// Check if polygon A is going to collide with polygon B for the given velocity public SvgCollision.PolygonCollisionResult PolygonCollision(Polygon polygonA, Polygon polygonB, Vector velocity) { SvgCollision.PolygonCollisionResult result = new SvgCollision.PolygonCollisionResult(); result.IsIntersecting = true; result.WillIntersect = true; int edgeCountA = polygonA.Edges.Count; int edgeCountB = polygonB.Edges.Count; float minIntervalDistance = float.PositiveInfinity; Vector translationAxis = new Vector(); Vector edge; // Loop through all the edges of both polygons for (int edgeIndex = 0; edgeIndex < edgeCountA + edgeCountB; edgeIndex++) { if (edgeIndex < edgeCountA) { edge = polygonA.Edges[edgeIndex]; } else { edge = polygonB.Edges[edgeIndex - edgeCountA]; } // ===== 1. Find if the polygons are currently intersecting ===== // Find the axis perpendicular to the current edge Vector axis = new Vector(-edge.Y, edge.X); axis.Normalize(); // Find the projection of the polygon on the current axis float minA = 0; float minB = 0; float maxA = 0; float maxB = 0; ProjectPolygon(axis, polygonA, ref minA, ref maxA); ProjectPolygon(axis, polygonB, ref minB, ref maxB); // Check if the polygon projections are currentlty intersecting float intervalDistance = IntervalDistance(minA, maxA, minB, maxB); if (intervalDistance > 0) result.IsIntersecting = false; // ===== 2. Now find if the polygons *will* intersect ===== // Project the velocity on the current axis float velocityProjection = axis.DotProduct(velocity); // Get the projection of polygon A during the movement if (velocityProjection < 0) { minA += velocityProjection; } else { maxA += velocityProjection; } // Do the same test as above for the new projection intervalDistance = IntervalDistance(minA, maxA, minB, maxB); if (intervalDistance > 0) result.WillIntersect = false; // If the polygons are not intersecting and won't intersect, exit the loop if (!result.IsIntersecting && !result.WillIntersect) break; // Check if the current interval distance is the minimum one. If so store // the interval distance and the current distance. // This will be used to calculate the minimum translation vector intervalDistance = Math.Abs(intervalDistance); if (intervalDistance < minIntervalDistance) { minIntervalDistance = intervalDistance; translationAxis = axis; Vector d = polygonA.Center - polygonB.Center; if (d.DotProduct(translationAxis) < 0) translationAxis = -translationAxis; } } // The minimum translation vector can be used to push the polygons appart. // First moves the polygons by their velocity // then move polygonA by MinimumTranslationVector. if (result.WillIntersect) result.MinimumTranslationVector = translationAxis * minIntervalDistance; return result; }
private void textBox1_TextChanged(object sender, EventArgs e) { try { var t = new XmlDocument(); t.XmlResolver = null; // Don't verify the XML t.LoadXml(textBox1.Text.Substring(textBox1.Text.IndexOf("<svg"))); FSvgDoc = SvgDocument.Open(t); pictureBox1.Image = FSvgDoc.Draw(); IterateKids(FSvgDoc.Children); Vector velocity = new Vector(0, 20); DateTime dte1, dte2; List<SvgCollision.PolygonCollisionResult> collisions; //dte1 = DateTime.Now; //collisions = SvgCollision.checkForCollision(FSvgDoc.Children, SvgCollision.collisionCheckType.LineCollision, velocity); //dte2 = DateTime.Now; //Debug.WriteLine((dte2 - dte1).TotalMilliseconds.ToString()); //foreach (SvgCollision.PolygonCollisionResult col in collisions) //{ // //Debug.WriteLine(col.collidor.ToString() + " intersects with " + col.collidee.ToString() + "\tIsIntersecting=" + col.IsIntersecting + "\tWillIntersect=" + col.WillIntersect + "\tOnPath=" + col.OnPath); //} //dte1 = DateTime.Now; //collisions = SvgCollision.checkForCollision(FSvgDoc.Children, SvgCollision.collisionCheckType.SeparatingAxisTheorem, velocity); //dte2 = DateTime.Now; //Debug.WriteLine((dte2 - dte1).TotalMilliseconds.ToString()); //foreach (SvgCollision.PolygonCollisionResult col in collisions) //{ // //Debug.WriteLine(col.collidor.ToString() + " intersects with " + col.collidee.ToString() + "\tIsIntersecting=" + col.IsIntersecting + "\tWillIntersect=" + col.WillIntersect + "\tOnPath=" + col.OnPath); //} dte1 = DateTime.Now; collisions = SvgCollision.checkForCollision(FSvgDoc.Children, SvgCollision.collisionCheckType.Mixed,0, velocity); dte2 = DateTime.Now; Debug.WriteLine((dte2 - dte1).TotalMilliseconds.ToString() + "\t" + collisions.Count + " collisions found"); foreach (SvgCollision.PolygonCollisionResult col in collisions) { Debug.WriteLine(col.collidor.ToString() + " intersects with " + col.collidee.ToString() + "\tIsIntersecting=" + col.IsIntersecting + "\tWillIntersect=" + col.WillIntersect + "\tOnPath=" + col.OnPath + "\tRayCasting=" + col.rayCastingResult + "\tMinVector=" + col.MinimumTranslationVector.X + "," + col.MinimumTranslationVector.Y ); } } catch { } //drawCirclePath(FSvgDoc.Children); }
/// <summary> /// Test all visualelements in a SvgElementCollection for collisions and return the result as a list of PolygonCollisionResult /// </summary> /// <param name="elCol"></param> /// <param name="colCheckType">Optional</param> /// <param name="minimumArea">Optional, should only be used if a majority of objects should be excluded from collision detection as it otherwise can cause a large performance penalty</param> /// <param name="velocity">Optional to simulate movement of all objects in certain direction. Result stored in PolygonCollisionResult.WillIntersect.</param> /// <returns></returns> public static List<PolygonCollisionResult> checkForCollision(SvgElementCollection elCol, collisionCheckType colCheckType = collisionCheckType.Mixed, float minimumArea = 0, Vector velocity = default(Vector)) { _collisionResultList = new List<PolygonCollisionResult>(); _elCol = elCol; _velocity = velocity; _colCheckType = colCheckType; _minimumArea = minimumArea; iterate(elCol, elCol); return _collisionResultList; }
// Calculate the projection of a polygon on an axis and returns it as a [min, max] interval public void ProjectPolygon(Vector axis, Polygon polygon, ref float min, ref float max) { // To project a point on an axis use the dot product float d = axis.DotProduct(polygon.Points[0]); min = d; max = d; for (int i = 0; i < polygon.Points.Count; i++) { d = polygon.Points[i].DotProduct(axis); if (d < min) { min = d; } else { if (d > max) { max = d; } } } }
public static SvgCollision.PolygonCollisionResult PolygonCollision(PointF[] ptsA, PointF[] ptsB, Vector velocity) { Polygon polygonA, polygonB; polygonA = new Polygon(); polygonB = new Polygon(); foreach (PointF pts in ptsA) { polygonA.Points.Add(new Vector(pts.X, pts.Y)); } foreach (PointF pts in ptsB) { polygonB.Points.Add(new Vector(pts.X, pts.Y)); } polygonA.BuildEdges(); polygonB.BuildEdges(); SeparatingAxisTheorem svgCollision = new SeparatingAxisTheorem(); return svgCollision.PolygonCollision(polygonA, polygonB, velocity); }
public void Offset(float x, float y) { for (int i = 0; i < points.Count; i++) { Vector p = points[i]; points[i] = new Vector(p.X + x, p.Y + y); } }
public void Offset(Vector v) { Offset(v.X, v.Y); }
public bool Equals(Vector v) { return X == v.X && Y == v.Y; }
public float DotProduct(Vector vector) { return this.X * vector.X + this.Y * vector.Y; }
public float DistanceTo(Vector vector) { return (float)Math.Sqrt(Math.Pow(vector.X - this.X, 2) + Math.Pow(vector.Y - this.Y, 2)); }