public static bool IsInLineOfSight(Vector3 position1, Vector3 position2, float collisionThreshold, ShapeCollection shapeCollection) { Segment segment = new Segment(new FlatRedBall.Math.Geometry.Point(ref position1), new FlatRedBall.Math.Geometry.Point(ref position2)); for(int i = 0; i < shapeCollection.Polygons.Count; i++) { Polygon polygon = shapeCollection.Polygons[i]; if (polygon.CollideAgainst(segment) || (collisionThreshold > 0 && segment.DistanceTo(polygon) < collisionThreshold)) { return false; } } for (int i = 0; i < shapeCollection.AxisAlignedRectangles.Count; i++) { AxisAlignedRectangle rectangle = shapeCollection.AxisAlignedRectangles[i]; FlatRedBall.Math.Geometry.Point throwaway; if (rectangle.Intersects(segment, out throwaway) || (collisionThreshold > 0 && segment.DistanceTo(rectangle) < collisionThreshold)) { return false; } } for (int i = 0; i < shapeCollection.Circles.Count; i++) { Circle circle = shapeCollection.Circles[i]; if (segment.DistanceTo(circle) < collisionThreshold) { return false; } } #if DEBUG if (shapeCollection.Capsule2Ds.Count != 0) { throw new Exception("IsInLineOfSight does not support ShapeCollections with Capsule2Ds"); } #endif for (int i = 0; i < shapeCollection.Lines.Count; i++) { Line line = shapeCollection.Lines[i]; if (segment.DistanceTo(line.AsSegment()) < collisionThreshold) { return false; } } return true; }
/// <summary> /// Tests if two vector positions are within line of sight given a collision map. /// </summary> /// <param name="position1">The first world-coordinate position.</param> /// <param name="position2">The second world-coordinate position.</param> /// <param name="collisionThreshold">Distance from position2 to the polygon it's colliding against. /// If a polygon is within this threshold, this will return false.</param> /// <param name="collisionMap">The list of polygons used to test if the two positions are within line of sight.</param> /// <returns></returns> #endregion public static bool IsInLineOfSight(Vector3 position1, Vector3 position2, float collisionThreshold, PositionedObjectList<Polygon> collisionMap) { Segment segment = new Segment(new FlatRedBall.Math.Geometry.Point(ref position1), new FlatRedBall.Math.Geometry.Point(ref position2)); foreach (Polygon polygon in collisionMap) { if (polygon.CollideAgainst(segment) || (collisionThreshold > 0 && segment.DistanceTo(polygon) < collisionThreshold)) { return false; } } return true; }
private void GetLinkOver(ref Link linkOver, ref PositionedNode linkOverParent) { Cursor cursor = GuiManager.Cursor; float worldX; float worldY; if (EditorData.NodeNetwork.Nodes.Count != 0) { float tolerance = 5 / SpriteManager.Camera.PixelsPerUnitAt(0); for (int i = 0; i < EditorData.NodeNetwork.Nodes.Count; i++) { PositionedNode node = EditorData.NodeNetwork.Nodes[i]; worldX = cursor.WorldXAt(node.Z); worldY = cursor.WorldYAt(node.Z); for (int linkIndex = 0; linkIndex < node.Links.Count; linkIndex++) { Segment segment = new Segment( node.Position, node.Links[linkIndex].NodeLinkingTo.Position); float distance = segment.DistanceTo(worldX, worldY); if (distance < tolerance) { linkOverParent = node; linkOver = node.Links[linkIndex]; return; } } } } linkOverParent = null; linkOver = null; }
/// <summary> /// Returns the point where this segment intersects the argument segment. /// </summary> /// <param name="s2">The segment to test for intersection.</param> /// <returns>The point where this segment intersects the /// argument segment. If the two segments do not touch, the point /// will have both values be double.NAN. /// </returns> #endregion public void IntersectionPoint(ref Segment s2, out Point intersectionPoint) { // code borrowed from // http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=geometry2 double A1 = Point2.Y - Point1.Y; double B1 = Point1.X - Point2.X; double C1 = A1 * Point1.X + B1 * Point1.Y; double A2 = s2.Point2.Y - s2.Point1.Y; double B2 = s2.Point1.X - s2.Point2.X; double C2 = A2 * s2.Point1.X + B2 * s2.Point1.Y; double det = A1 * B2 - A2 * B1; if (det == 0) { //Lines are parallel intersectionPoint.X = double.NaN; intersectionPoint.Y = double.NaN; } else { intersectionPoint.X = (B2 * C1 - B1 * C2) / det; intersectionPoint.Y = (A1 * C2 - A2 * C1) / det; if (!this.IsClosestPointOnEndpoint(ref intersectionPoint) && !s2.IsClosestPointOnEndpoint(ref intersectionPoint)) { // do nothing ; } else { // The closest point is on an endpoint, but we may have a situation where // one segment is touching another one like a T. If that's the case, // let's still consider it an intersection. double distanceFromThis = this.DistanceTo(intersectionPoint); double distanceFromOther = s2.DistanceTo(intersectionPoint); if (distanceFromOther > .000000001 || distanceFromThis > .000000001) { intersectionPoint.X = float.NaN; intersectionPoint.Y = float.NaN; } } } }
public bool IsParallelAndTouching(Segment s2, out Point intersectionPoint) { double thisAngle = this.Angle; double otherAngle = s2.Angle; double distance = this.DistanceTo(s2); const float maximumAngleVariation = .00001f; const double maximumDistance = .00001f; intersectionPoint = new Point(double.NaN, double.NaN); if (System.Math.Abs(thisAngle - otherAngle) < maximumAngleVariation && distance < maximumDistance) { if (s2.DistanceTo(this.Point1) < maximumDistance) { intersectionPoint = Point1; } else if (s2.DistanceTo(this.Point2) < maximumDistance) { intersectionPoint = Point2; } else if (this.DistanceTo(s2.Point1) < maximumDistance) { intersectionPoint = s2.Point1; } else// if (this.DistanceTo(s2.Point2) < maximumDistance) { intersectionPoint = s2.Point2; } // They're parallel and touching return true; } return false; }
public float DistanceTo(Segment otherSegment) { if (otherSegment.Intersects(this)) { return 0; } else { float minDistance = float.PositiveInfinity; minDistance = System.Math.Min(minDistance, this.DistanceTo(otherSegment.Point1)); minDistance = System.Math.Min(minDistance, this.DistanceTo(otherSegment.Point2)); minDistance = System.Math.Min(minDistance, otherSegment.DistanceTo(this.Point1)); minDistance = System.Math.Min(minDistance, otherSegment.DistanceTo(this.Point2)); return minDistance; } }
public bool CollideAgainst(Capsule2D otherCapsule) { this.UpdateDependencies(TimeManager.CurrentTime); otherCapsule.UpdateDependencies(TimeManager.CurrentTime); #region Create some initial variables which will be used below Vector3 thisEndpoint1 = this.Endpoint1Position; Vector3 thisEndpoint2 = this.Endpoint2Position; Vector3 otherEndpoint1 = otherCapsule.Endpoint1Position; Vector3 otherEndpoint2 = otherCapsule.Endpoint2Position; #endregion #region Point vs. Point (circle collision) float radiiCombinedSquared = (mEndpointRadius + otherCapsule.mEndpointRadius) * (mEndpointRadius + otherCapsule.mEndpointRadius); Vector3 difference1 = thisEndpoint1 - otherEndpoint1; Vector3 difference2 = thisEndpoint1 - otherEndpoint2; Vector3 difference3 = thisEndpoint2 - otherEndpoint1; Vector3 difference4 = thisEndpoint2 - otherEndpoint2; if ( #if FRB_MDX difference1.LengthSq() < radiiCombinedSquared || difference2.LengthSq() < radiiCombinedSquared || difference3.LengthSq() < radiiCombinedSquared || difference4.LengthSq() < radiiCombinedSquared) #else //if FRB_XNA || SILVERLIGHT || WINDOWS_PHONE difference1.LengthSquared() < radiiCombinedSquared || difference2.LengthSquared() < radiiCombinedSquared || difference3.LengthSquared() < radiiCombinedSquared || difference4.LengthSquared() < radiiCombinedSquared) #endif { return(true); } #endregion #region Segment vs. Segment (bandaid collision) Segment thisTopSegment = this.TopSegment; Segment thisBottomSegment = this.BottomSegment; Segment otherTopSegment = otherCapsule.TopSegment; Segment otherBottomSegment = otherCapsule.BottomSegment; if ( thisTopSegment.Intersects(otherTopSegment) || thisTopSegment.Intersects(otherBottomSegment) || thisBottomSegment.Intersects(otherTopSegment) || thisBottomSegment.Intersects(otherBottomSegment)) { return(true); } #endregion #region Point vs. Segment (T collision) if ( thisTopSegment.DistanceTo(otherEndpoint1.X, otherEndpoint1.Y) < otherCapsule.mEndpointRadius || thisTopSegment.DistanceTo(otherEndpoint2.X, otherEndpoint2.Y) < otherCapsule.mEndpointRadius || thisBottomSegment.DistanceTo(otherEndpoint1.X, otherEndpoint1.Y) < otherCapsule.mEndpointRadius || thisBottomSegment.DistanceTo(otherEndpoint2.X, otherEndpoint2.Y) < otherCapsule.mEndpointRadius) { return(true); } if ( otherTopSegment.DistanceTo(thisEndpoint1.X, thisEndpoint1.Y) < this.mEndpointRadius || otherTopSegment.DistanceTo(thisEndpoint2.X, thisEndpoint2.Y) < this.mEndpointRadius || otherBottomSegment.DistanceTo(thisEndpoint1.X, thisEndpoint1.Y) < this.mEndpointRadius || otherBottomSegment.DistanceTo(thisEndpoint2.X, thisEndpoint2.Y) < this.mEndpointRadius) { return(true); } #endregion #region Endpoint inside Shape (Fully contained collision) Point thisEndpoint1Point = new Point(ref thisEndpoint1); Point thisEndpoint2Point = new Point(ref thisEndpoint2); Point otherEndpoint1Point = new Point(ref otherEndpoint1); Point otherEndpoint2Point = new Point(ref otherEndpoint2); if ( MathFunctions.IsPointInsideRectangle(thisEndpoint1Point, otherTopSegment.Point1, otherTopSegment.Point2, otherBottomSegment.Point2, otherBottomSegment.Point1) || MathFunctions.IsPointInsideRectangle(thisEndpoint2Point, otherTopSegment.Point1, otherTopSegment.Point2, otherBottomSegment.Point2, otherBottomSegment.Point1) || MathFunctions.IsPointInsideRectangle(otherEndpoint1Point, thisTopSegment.Point1, thisTopSegment.Point2, thisBottomSegment.Point2, thisBottomSegment.Point1) || MathFunctions.IsPointInsideRectangle(otherEndpoint2Point, thisTopSegment.Point1, thisTopSegment.Point2, thisBottomSegment.Point2, thisBottomSegment.Point1) ) { return(true); } #endregion // If we got here then the two do not touch. return(false); }
public bool CollideAgainst(AxisAlignedRectangle rectangle) { if (mLastDependencyUpdate != TimeManager.CurrentTime) { UpdateDependencies(TimeManager.CurrentTime); } if (rectangle.LastDependencyUpdate != TimeManager.CurrentTime) { rectangle.UpdateDependencies(TimeManager.CurrentTime); } // first perform a quick test to see if the Circle is too far // away from the rectangle if ((Position.X + Radius < rectangle.X - rectangle.mScaleX || Position.X - Radius > rectangle.X + rectangle.mScaleX || Position.Y + Radius < rectangle.Y - rectangle.mScaleY || Position.Y - Radius > rectangle.Y + rectangle.mScaleY)) { return(false); } // The simple bounding box test from above will eliminate most // cases. If we get this far, then it is likely that we have a collision // and a more in-depth test can be performed. // quick test to see if the circle is inside of the rectangle if (rectangle.IsPointInside(Position.X, Position.Y)) { mLastCollisionTangent.X = -(Position.Y - rectangle.Position.Y); mLastCollisionTangent.Y = (Position.X - rectangle.Position.X); return(true); } // if we got this far, the bounding box of the circle touches the rectangle // and the center of the circle is not inside of the rectangle. Perform // the most expensive checks now. Point centerPoint = new Point(Position.X, Position.Y); Segment connectingSegment = new Segment(); int numberOfEndpointsClosestTo = 0; // top segment Segment segment = new Segment( new Point(rectangle.Left, rectangle.Top), new Point(rectangle.Right, rectangle.Top)); if (segment.DistanceTo(centerPoint, out connectingSegment) < Radius) { if (segment.IsClosestPointOnEndpoint(ref centerPoint)) { mLastCollisionTangent.X = -(connectingSegment.Point2.Y - Y); mLastCollisionTangent.Y = (connectingSegment.Point2.X - X); numberOfEndpointsClosestTo++; } else { mLastCollisionTangent.X = 1; mLastCollisionTangent.Y = 0; return(true); } } // bottom segment segment = new Segment( new Point(rectangle.Left, rectangle.Bottom), new Point(rectangle.Right, rectangle.Bottom)); if (segment.DistanceTo(centerPoint, out connectingSegment) < Radius) { if (segment.IsClosestPointOnEndpoint(ref centerPoint)) { mLastCollisionTangent.X = -(connectingSegment.Point2.Y - Position.Y); mLastCollisionTangent.Y = (connectingSegment.Point2.X - Position.X); numberOfEndpointsClosestTo++; } else { mLastCollisionTangent.X = 1; mLastCollisionTangent.Y = 0; return(true); } } // left segment segment = new Segment( new Point(rectangle.Left, rectangle.Top), new Point(rectangle.Left, rectangle.Bottom)); if (segment.DistanceTo(centerPoint, out connectingSegment) < Radius) { if (segment.IsClosestPointOnEndpoint(ref centerPoint)) { mLastCollisionTangent.X = -(connectingSegment.Point2.Y - Position.Y); mLastCollisionTangent.Y = (connectingSegment.Point2.X - Position.X); numberOfEndpointsClosestTo++; } else { mLastCollisionTangent.X = 0; mLastCollisionTangent.Y = 1; return(true); } } // right segment segment = new Segment( new Point(rectangle.Right, rectangle.Top), new Point(rectangle.Right, rectangle.Bottom)); if (segment.DistanceTo(centerPoint, out connectingSegment) < Radius) { if (segment.IsClosestPointOnEndpoint(ref centerPoint)) { mLastCollisionTangent.X = -(connectingSegment.Point2.Y - Position.Y); mLastCollisionTangent.Y = (connectingSegment.Point2.X - Position.X); numberOfEndpointsClosestTo++; } else { mLastCollisionTangent.X = 0; mLastCollisionTangent.Y = 1; return(true); } } if (numberOfEndpointsClosestTo > 0) { return(true); } else // well, this is rare, but it can happen. Collision failed! { return(false); } }