public static void Absolute(ref JMatrix matrix, out JMatrix result) { result.M11 = Math.Abs(matrix.M11); result.M12 = Math.Abs(matrix.M12); result.M21 = Math.Abs(matrix.M21); result.M22 = Math.Abs(matrix.M22); }
public static bool ClosestPoints(ISupportMappable support1, ISupportMappable support2, ref JMatrix orientation1, ref JMatrix orientation2, ref JVector position1, ref JVector position2, out JVector p1, out JVector p2, out JVector normal) { VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); p1 = p2 = JVector.Zero; JVector r = position1 - position2; JVector w, v; JVector supVertexA; JVector rn, vn; rn = JVector.Negate(r); SupportMapTransformed(support1, ref orientation1, ref position1, ref rn, out supVertexA); JVector supVertexB; SupportMapTransformed(support2, ref orientation2, ref position2, ref r, out supVertexB); v = supVertexA - supVertexB; normal = JVector.Zero; int iter = 0; float distSq = v.LengthSquared(); float epsilon = 0.00001f; while ((distSq > epsilon) && (iter++ < MaxIterations)) { IterationsTaken = iter; vn = JVector.Negate(v); SupportMapTransformed(support1, ref orientation1, ref position1, ref vn, out supVertexA); SupportMapTransformed(support2, ref orientation2, ref position2, ref v, out supVertexB); w = supVertexA - supVertexB; if (!simplexSolver.InSimplex(w)) simplexSolver.AddVertex(w, supVertexA, supVertexB); if (simplexSolver.Closest(out v)) { distSq = v.LengthSquared(); normal = v; } else distSq = 0.0f; } simplexSolver.ComputePoints(out p1, out p2); if (normal.LengthSquared() > JMath.Epsilon * JMath.Epsilon) normal.Normalize(); simplexSolverPool.GiveBack(simplexSolver); return true; }
static JMatrix() { Zero = new JMatrix(); Identity = new JMatrix(); Identity.M11 = 1.0f; Identity.M22 = 1.0f; InternalIdentity = Identity; }
public static Matrix ToXNAMatrix(JMatrix matrix) { return new Matrix(matrix.M11, matrix.M12, matrix.M13, 0.0f, matrix.M21, matrix.M22, matrix.M23, 0.0f, matrix.M31, matrix.M32, matrix.M33, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); }
public static void SupportMapTransformed(ISupportMappable support, ref JMatrix orientation, ref JVector position, ref JVector direction, out JVector result) { // THIS IS *THE* HIGH FREQUENCY CODE OF THE COLLLISION PART OF THE ENGINE result.X = ((direction.X * orientation.M11) + (direction.Y * orientation.M12)); result.Y = ((direction.X * orientation.M21) + (direction.Y * orientation.M22)); support.SupportMapping(ref result, out result); float x = ((result.X * orientation.M11) + (result.Y * orientation.M21)); float y = ((result.X * orientation.M12) + (result.Y * orientation.M22)); result.X = position.X + x; result.Y = position.Y + y; }
/// <summary> /// Creates the transposed matrix. /// </summary> /// <param name="matrix">The matrix which should be transposed.</param> /// <param name="result">The transposed JMatrix.</param> public static void Transpose(ref JMatrix matrix, out JMatrix result) { result.M11 = matrix.M11; result.M12 = matrix.M21; result.M21 = matrix.M12; result.M22 = matrix.M22; }
/// <summary> /// Adds two matrices. /// </summary> /// <param name="value1">The first matrix.</param> /// <param name="value2">The second matrix.</param> /// <returns>The sum of both values.</returns> #region public static JMatrix operator +(JMatrix value1, JMatrix value2) public static JMatrix operator +(JMatrix value1, JMatrix value2) { JMatrix result; JMatrix.Add(ref value1, ref value2, out result); return(result); }
/// <summary> /// Transforms a vector by the transposed of the given Matrix. /// </summary> /// <param name="position">The vector to transform.</param> /// <param name="matrix">The transform matrix.</param> /// <param name="result">The transformed vector.</param> public static void TransposedTransform(ref JVector position, ref JMatrix matrix, out JVector result) { float num0 = ((position.X * matrix.M11) + (position.Y * matrix.M12)); float num1 = ((position.X * matrix.M21) + (position.Y * matrix.M22)); result.X = num0; result.Y = num1; }
public static JVector Transform(JVector position, JMatrix matrix) { JVector result; JVector.Transform(ref position, ref matrix, out result); return result; }
/// <summary> /// Transforms the bounding box into the space given by orientation and position. /// </summary> /// <param name="position"></param> /// <param name="orientation"></param> /// <param name="result"></param> internal void InverseTransform(ref JVector position, ref JMatrix orientation) { JVector.Subtract(ref Max, ref position, out Max); JVector.Subtract(ref Min, ref position, out Min); JVector center; JVector.Add(ref Max, ref Min, out center); center.X *= 0.5f; center.Y *= 0.5f; JVector halfExtents; JVector.Subtract(ref Max, ref Min, out halfExtents); halfExtents.X *= 0.5f; halfExtents.Y *= 0.5f; JVector.TransposedTransform(ref center, ref orientation, out center); JMatrix abs; JMath.Absolute(ref orientation, out abs); JVector.TransposedTransform(ref halfExtents, ref abs, out halfExtents); JVector.Add(ref center, ref halfExtents, out Max); JVector.Subtract(ref center, ref halfExtents, out Min); }
/// <summary> /// Gets up to two supports points if the given direction is within a tolerance of being parallel to the normal of the edge formed by the supports. Otherwise it just returns a single support. /// </summary> internal int FindSupportPoints(ref JVector direction, ref JVector PA, ref JMatrix OA, out JVector[] S) { // init S S = new JVector[2]; // transform the normal into object space JVector N = JVector.TransposedTransform(direction, OA); // find dots float a = this.GetCorner(0) * N; float b = this.GetCorner(1) * N; float c = this.GetCorner(2) * N; float d = this.GetCorner(3) * N; // find min float min = JMath.Min(a, b); min = JMath.Min(c, min); min = JMath.Min(d, min); // now min should be right int Snum = 0; const float threshold = 1.0E-3f; if (a < min + threshold) S[Snum++] = JVector.Transform(this.GetCorner(0), OA) + PA; if (b < min + threshold) S[Snum++] = JVector.Transform(this.GetCorner(1), OA) + PA; if (c < min + threshold) S[Snum++] = JVector.Transform(this.GetCorner(2), OA) + PA; if (d < min + threshold) S[Snum++] = JVector.Transform(this.GetCorner(3), OA) + PA; return Snum; }
/// <summary> /// Calculates the inverse of a give matrix. /// </summary> /// <param name="matrix">The matrix to invert.</param> /// <param name="result">The inverted JMatrix.</param> public static void Inverse(ref JMatrix matrix, out JMatrix result) { float det = matrix.M11 * matrix.M22 - matrix.M12 * matrix.M21; float determinantInverse = 1f / det; result.M11 = matrix.M22 * determinantInverse; result.M12 = -matrix.M12 * determinantInverse; result.M21 = matrix.M11 * determinantInverse; result.M22 = -matrix.M21 * determinantInverse; }
public static JMatrix Inverse(JMatrix matrix) { JMatrix result; JMatrix.Inverse(ref matrix, out result); return result; }
public static void CreateRotationZ(float radians, out JMatrix result) { float num2 = (float)Math.Cos((double)radians); float num = (float)Math.Sin((double)radians); result.M11 = num2; result.M12 = num; result.M21 = -num; result.M22 = num2; }
/// <summary> /// Matrices are added. /// </summary> /// <param name="matrix1">The first matrix.</param> /// <param name="matrix2">The second matrix.</param> /// <param name="result">The sum of both matrices.</param> public static void Add(ref JMatrix matrix1, ref JMatrix matrix2, out JMatrix result) { result.M11 = matrix1.M11 + matrix2.M11; result.M12 = matrix1.M12 + matrix2.M12; result.M21 = matrix1.M21 + matrix2.M21; result.M22 = matrix1.M22 + matrix2.M22; }
public static JMatrix Add(JMatrix matrix1, JMatrix matrix2) { JMatrix result; JMatrix.Add(ref matrix1, ref matrix2, out result); return result; }
public static float CalculateMassInertia(Shape shape, out JVector centerOfMass, out JMatrix inertia) { throw new NotImplementedException(); }
/// <summary> /// Should return true if the point is inside the shapes world space. /// </summary> /// <param name="point">The point.</param> /// <param name="position">World position of shape.</param> /// <param name="orientation">World orientation of shape.</param> /// <returns>True if the point is inside the shape.</returns> public abstract bool PointInsideWorld(JVector point, JVector position, JMatrix orientation);
/// <summary> /// Should return true if the point is inside the box's world space. /// </summary> /// <param name="point">The point.</param> /// <param name="position">World position of box.</param> /// <param name="orientation">World orientation of box.</param> /// <returns>True if the point is inside the shape.</returns> public override bool PointInsideWorld(JVector point, JVector position, JMatrix orientation) { // move point into local space throw new NotImplementedException(); }
internal static bool CircleBoxTest(ref CircleShape A, ref JVector PA, ref BoxShape B, ref JVector PB, ref JMatrix OB) { // find vertex closest to circles center // move circle into boxes space var pa = JVector.TransposedTransform(PA - PB, OB); // find normal from box to circles center var axis = pa; JVector closestVertex; // find closest vertex B.SupportMapping(ref axis, out closestVertex); // do a SAT test on that axis // axis to test JVector T = pa - closestVertex; float TL = Math.Abs(T * axis); float a = Math.Abs(pa * axis); float b = Math.Abs(closestVertex * axis); if (TL > (a + b + A.Radius)) return false; return true; }
public static void Invert(ref JMatrix matrix, out JMatrix result) { float determinantInverse = 1f / matrix.Determinant(); result.M11 = matrix.M22 * determinantInverse; result.M12 = -matrix.M12 * determinantInverse; result.M21 = matrix.M11 * determinantInverse; result.M22 = -matrix.M21 * determinantInverse; }
public void Transform(ref JMatrix orientation) { JVector halfExtents = 0.5f * (Max - Min); JVector center = 0.5f * (Max + Min); JVector.Transform(ref center, ref orientation, out center); JMatrix abs; JMath.Absolute(ref orientation, out abs); JVector.Transform(ref halfExtents, ref abs, out halfExtents); Max = center + halfExtents; Min = center - halfExtents; }
/// <summary> /// Checks two shapes for collisions. /// </summary> /// <param name="support1">The SupportMappable implementation of the first shape to test.</param> /// <param name="support2">The SupportMappable implementation of the seconds shape to test.</param> /// <param name="orientation1">The orientation of the first shape.</param> /// <param name="orientation2">The orientation of the second shape.</param> /// <param name="position1">The position of the first shape.</param> /// <param name="position2">The position of the second shape</param> /// <param name="point">The pointin world coordinates, where collision occur.</param> /// <param name="normal">The normal pointing from body2 to body1.</param> /// <param name="penetration">Estimated penetration depth of the collision.</param> /// <returns>Returns true if there is a collision, false otherwise.</returns> public static bool Detect(ISupportMappable support1, ISupportMappable support2, ref JMatrix orientation1, ref JMatrix orientation2, ref JVector position1, ref JVector position2, out JVector point, out JVector normal, out float penetration) { // Used variables JVector v01, v02, v0; JVector v11, v12, v1; JVector v21, v22, v2; JVector v31, v32, v3; JVector mn; // Initialization of the output point = normal = JVector.Zero; penetration = 0.0f; // Get the center of shape1 in world coordinates -> v01 support1.SupportCenter(out v01); JVector.Transform(ref v01, ref orientation1, out v01); JVector.Add(ref position1, ref v01, out v01); // Get the center of shape2 in world coordinates -> v02 support2.SupportCenter(out v02); JVector.Transform(ref v02, ref orientation2, out v02); JVector.Add(ref position2, ref v02, out v02); // v0 is the center of the minkowski difference JVector.Subtract(ref v02, ref v01, out v0); // Avoid case where centers overlap -- any direction is fine in this case if (v0.IsNearlyZero()) v0 = new JVector(0.00001f, 0); // v1 = support in direction of origin mn = v0; JVector.Negate(ref v0, out normal); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v11); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v12); JVector.Subtract(ref v12, ref v11, out v1); if (JVector.Dot(ref v1, ref normal) <= 0.0f) return false; // v2 = support perpendicular to v1,v0 normal = OutsidePortal(v1, v0); JVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v21); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v22); JVector.Subtract(ref v22, ref v21, out v2); //LD.Draw(Conversion.ToXNAVector2(v1), Conversion.ToXNAVector2(v0), Color.Blue); //LD.Draw(Conversion.ToXNAVector2(v2), Conversion.ToXNAVector2(v0), Color.Blue); if (JVector.Dot(ref v2, ref normal) <= 0.0f) return false; // phase two: portal refinement int maxIterations = 0; while (true) { // find normal direction if (!IntersectPortal(v0, v2, v1)) normal = InsidePortal(v2, v1); else // origin ray crosses the portal normal = OutsidePortal(v2, v1); // obtain the next support point JVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v31); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v32); JVector.Subtract(ref v32, ref v31, out v3); //LD.Draw(Conversion.ToXNAVector2(v3), Conversion.ToXNAVector2(v0), Color.Green); if (JVector.Dot(v3, normal) <= 0) { JVector ab = v3 - v2; float t = -(JVector.Dot(v2, ab)) / (JVector.Dot(ab, ab)); normal = (v2 + (t * ab)); return false; } // Portal lies on the outside edge of the Minkowski Hull. // Return contact information if (JVector.Dot((v3 - v2), normal) <= CollideEpsilon || ++maxIterations > MaximumIterations) { JVector ab = v2 - v1; float t = JVector.Dot(JVector.Negate(v1), ab); if (t <= 0.0f) { t = 0.0f; normal = v1; } else { float denom = JVector.Dot(ab, ab); if (t >= denom) { normal = v2; t = 1.0f; } else { t /= denom; normal = v1 + t * ab; } } float s = 1 - t; point = s * v11 + t * v21; var point2 = s * v12 + t * v22; // this causes a sq root = bad! penetration = normal.Length(); normal.Normalize(); return true; } // if origin is inside (v1, v0, v3), refine portal if (OriginInTriangle(v0, v1, v3)) { v2 = v3; v21 = v31; v22 = v32; continue; } // if origin is inside (v3, v0, v2), refine portal else if (OriginInTriangle(v0, v2, v3)) { v1 = v3; v11 = v31; v12 = v32; continue; } return false; } }
public static JMatrix Multiply(JMatrix matrix1, JMatrix matrix2) { JMatrix result; JMatrix.Multiply(ref matrix1, ref matrix2, out result); return result; }
/// <summary> /// Discrete Box vs Box test. Very fast. Generates contact info. NOTE: ensure UpdateAxes is called for each BoxShape prior. /// </summary> /// <param name="A">BoxShape A.</param> /// <param name="PA">BoxShape A's position.</param> /// <param name="OA">BoxShape A's orientation.</param> /// <param name="B">BoxShape B.</param> /// <param name="PB">BoxShape B's position.</param> /// <param name="OB">BoxShape B's orientation.</param> /// <param name="normal">Normal of collision.</param> /// <param name="t">Amount of penetration.</param> /// <param name="CA">Contacts found on BoxShape A.</param> /// <param name="CB">Contacts found on BoxShape B.</param> /// <param name="NumContacts">Number of contacts found.</param> /// <returns>True if collision exists.</returns> public static bool BoxBoxTestContact(ref BoxShape A, ref JVector PA, ref JMatrix OA, ref BoxShape B, ref JVector PB, ref JMatrix OB, out JVector normal, out float t, out JVector[] CA, out JVector[] CB, out int NumContacts) { float overlap = 0; normal = A.xAxis; t = 0.0f; // TODO in future to save a few bytes of garbage make these // SA1, SA2 and SB1, SB2 (no arrays) JVector[] SA = new JVector[2], SB = new JVector[2]; int NumSA = 0, NumSB = 0; CA = new JVector[2]; CB = new JVector[2]; NumContacts = 0; JVector T = PB - PA; // cache scaled local axes JVector Ax = A.halfSize.X * A.xAxis; JVector Ay = A.halfSize.Y * A.yAxis; JVector Bx = B.halfSize.X * B.xAxis; JVector By = B.halfSize.Y * B.yAxis; // axis to test JVector L = A.xAxis; float TL = Math.Abs(T * L); float a = Math.Abs((Ax) * L) + Math.Abs((Ay) * L); float b = Math.Abs((Bx) * L) + Math.Abs((By) * L); if (TL > (a + b)) return false; // cache overlap // just set first overlap overlap = TL - (b + a); // axis to test L = A.yAxis; TL = Math.Abs(T * L); a = Math.Abs((Ax) * L) + Math.Abs((Ay) * L); b = Math.Abs((Bx) * L) + Math.Abs((By) * L); if (TL > (a + b)) return false; // cache overlap var o = TL - (b + a); if (o > overlap) { overlap = o; normal = A.yAxis; } // axis to test L = B.xAxis; TL = Math.Abs(T * L); a = Math.Abs((Ax) * L) + Math.Abs((Ay) * L); b = Math.Abs((Bx) * L) + Math.Abs((By) * L); if (TL > (a + b)) return false; // cache overlap o = TL - (b + a); if (o > overlap) { overlap = o; normal = B.xAxis; } // axis to test L = B.yAxis; TL = Math.Abs(T * L); a = Math.Abs((Ax) * L) + Math.Abs((Ay) * L); b = Math.Abs((Bx) * L) + Math.Abs((By) * L); if (TL > (a + b)) return false; // cache overlap o = TL - (b + a); if (o > overlap) { overlap = o; normal = B.yAxis; } // make sure the polygons gets pushed away from each other. if (normal * T < 0.0f) normal = -normal; t = overlap; // now to find a contact point or edge! var mn = -normal; NumSA = A.FindSupportPoints(ref mn, ref PA, ref OA, out SA); NumSB = B.FindSupportPoints(ref normal, ref PB, ref OB, out SB); // now refine contact points from support points // edge/vertex case if (NumSA == 2 && NumSB == 1) { ProjectPointOnLine(ref SB[0], ref SA[0], ref SA[1], out CA[NumContacts]); CB[NumContacts] = SB[0]; NumContacts++; return true; } // vertex/edge case if (NumSA == 1 && NumSB == 2) { ProjectPointOnLine(ref SA[0], ref SB[0], ref SB[1], out CB[NumContacts]); CA[NumContacts] = SA[0]; NumContacts++; return true; } // edge/edge case if (NumSA == 2 && NumSB == 2) { // clip contacts JVector perp = new JVector(-normal.Y, normal.X); // project first 2 contacts to axis perpendicular to normal float min0 = SA[0] * perp; float max0 = min0; float min1 = SB[0] * perp; float max1 = min1; // project next point from A max0 = SA[1] * perp; if (max0 < min0) { JMath.Swapf(ref min0, ref max0); JVector.Swap(ref SA[0], ref SA[1]); } max1 = SB[1] * perp; if (max1 < min1) { JMath.Swapf(ref min1, ref max1); JVector.Swap(ref SB[0], ref SB[1]); } if (min0 > min1) { JVector Pseg; ProjectPointOnLine(ref SA[0], ref SB[0], ref SB[1], out Pseg); CA[NumContacts] = SA[0]; CB[NumContacts] = Pseg; NumContacts++; } else { JVector Pseg; ProjectPointOnLine(ref SB[0], ref SA[0], ref SA[1], out Pseg); CA[NumContacts] = Pseg; CB[NumContacts] = SB[0]; NumContacts++; } if (max0 < max1) { JVector Pseg; ProjectPointOnLine(ref SA[1], ref SB[0], ref SB[1], out Pseg); CA[NumContacts] = SA[1]; CB[NumContacts] = Pseg; NumContacts++; } else { JVector Pseg; ProjectPointOnLine(ref SB[1], ref SA[0], ref SA[1], out Pseg); CA[NumContacts] = Pseg; CB[NumContacts] = SB[1]; NumContacts++; } return true; } // if all axes overlap collision exists return true; }
/// <summary> /// Multiply two matrices. Notice: matrix multiplication is not commutative. /// </summary> /// <param name="matrix1">The first matrix.</param> /// <param name="matrix2">The second matrix.</param> /// <param name="result">The product of both matrices.</param> public static void Multiply(ref JMatrix matrix1, ref JMatrix matrix2, out JMatrix result) { float num0 = (matrix1.M11 * matrix2.M11) + (matrix1.M12 * matrix2.M21); float num1 = (matrix1.M11 * matrix2.M12) + (matrix1.M12 * matrix2.M22); float num3 = (matrix1.M21 * matrix2.M11) + (matrix1.M22 * matrix2.M21); float num4 = (matrix1.M21 * matrix2.M12) + (matrix1.M22 * matrix2.M22); result.M11 = num0; result.M12 = num1; result.M21 = num3; result.M22 = num4; }
/// <summary> /// Transforms a vector by the transposed of the given Matrix. /// </summary> /// <param name="position">The vector to transform.</param> /// <param name="matrix">The transform matrix.</param> /// <param name="result">The transformed vector.</param> public static JVector TransposedTransform(JVector position, JMatrix matrix) { JVector result; float num0 = ((position.X * matrix.M11) + (position.Y * matrix.M12)); float num1 = ((position.X * matrix.M21) + (position.Y * matrix.M22)); result.X = num0; result.Y = num1; return result; }
public static JMatrix Multiply(JMatrix matrix1, float scaleFactor) { JMatrix result; JMatrix.Multiply(ref matrix1, scaleFactor, out result); return result; }
/// <summary> /// Multiply a matrix by a scalefactor. /// </summary> /// <param name="matrix1">The matrix.</param> /// <param name="scaleFactor">The scale factor.</param> /// <param name="result">A JMatrix multiplied by the scale factor.</param> public static void Multiply(ref JMatrix matrix1, float scaleFactor, out JMatrix result) { float num = scaleFactor; result.M11 = matrix1.M11 * num; result.M12 = matrix1.M12 * num; result.M21 = matrix1.M21 * num; result.M22 = matrix1.M22 * num; }
public static JMatrix Transpose(JMatrix matrix) { JMatrix result; JMatrix.Transpose(ref matrix, out result); return result; }
void DrawPoly(List<JVector> poly, JVector pos, JMatrix o, Color color) { for (int i = 0; i < poly.Count - 1; i++) { JVector a = JVector.Transform(poly[i], o * JMatrix.CreateTranslation(pos)); JVector b = JVector.Transform(poly[i + 1], o * JMatrix.CreateTranslation(pos)); DebugDrawer.DrawLine(a, b, color); } JVector c = JVector.Transform(poly[0], o * JMatrix.CreateTranslation(pos)); JVector d = JVector.Transform(poly[poly.Count - 1], o * JMatrix.CreateTranslation(pos)); DebugDrawer.DrawLine(c, d, color); }
/// <summary> /// Multiplies two matrices. /// </summary> /// <param name="value1">The first matrix.</param> /// <param name="value2">The second matrix.</param> /// <returns>The product of both values.</returns> #region public static JMatrix operator *(JMatrix value1,JMatrix value2) public static JMatrix operator *(JMatrix value1, JMatrix value2) { JMatrix result; JMatrix.Multiply(ref value1, ref value2, out result); return(result); }