public IsParallelAndTouching ( |
||
s2 | ||
intersectionPoint | Point | |
Результат | bool |
private static List<ContactPoint> GetContactPoints(Segment[] firstSegments, Segment[] secondSegments) { if (shouldEliminatePointOnEnd) { ShiftEndpointsToEliminatePointOnSegment(firstSegments, secondSegments); } Point intersectionPoint = new Point(); List<ContactPoint> contactPoints = new List<ContactPoint>(); Segment firstSegment = new Segment(); Segment secondSegment = new Segment(); const double allowedError = .0005; bool debug = false; #if !SILVERLIGHT && !MONOGAME && !XBOX360 && !WINDOWS_PHONE if (debug) { FlatRedBall.Content.Polygon.PolygonSaveList psl = new FlatRedBall.Content.Polygon.PolygonSaveList(); psl.PolygonSaves.Add( FlatRedBall.Content.Polygon.PolygonSave.FromPolygon( Polygon.FromSegments(firstSegments))); psl.PolygonSaves.Add( FlatRedBall.Content.Polygon.PolygonSave.FromPolygon( Polygon.FromSegments(secondSegments))); psl.Save(FlatRedBall.IO.FileManager.MyDocuments + "modifiedPolygons.plylstx"); } #endif #region Handle the two-parallel segment special case List<ContactPoint> parallelContactPoints = new List<ContactPoint>(); for (int firstIndex = 0; firstIndex < firstSegments.Length; firstIndex++) { firstSegment = firstSegments[firstIndex]; for (int secondIndex = 0; secondIndex < secondSegments.Length; secondIndex++) { secondSegment = secondSegments[secondIndex]; Point parallelIntersectionPoint; if (firstSegment.IsParallelAndTouching(secondSegment, out parallelIntersectionPoint)) { ContactPoint cp = new ContactPoint(); cp.ThisIndex = firstIndex; cp.OtherIndex = secondIndex; // Technically this is a point on segment intersection, // but we treat it like a segment intersection because we're // going to eliminate duplicates cp.ContactType = ContactType.SegmentIntersection; cp.Position = new Vector3((float)parallelIntersectionPoint.X, (float)parallelIntersectionPoint.Y, 0); parallelContactPoints.Add(cp); } } } #endregion #region else, do regular intersection tests List<int> indexesToRemove = new List<int>(); for (int firstSegmentIndex = 0; firstSegmentIndex < firstSegments.Length; firstSegmentIndex++) { firstSegment = firstSegments[firstSegmentIndex]; for (int secondSegmentIndex = 0; secondSegmentIndex < secondSegments.Length; secondSegmentIndex++) { secondSegment = secondSegments[secondSegmentIndex]; bool intersects = firstSegment.Intersects(secondSegment, out intersectionPoint); if ( intersects || firstSegment.IsParallelAndTouching(secondSegment, out intersectionPoint)) { ContactPoint cp = new ContactPoint(); cp.Position = new Vector3((float)intersectionPoint.X, (float)intersectionPoint.Y, 0); cp.ThisIndex = firstSegmentIndex; cp.OtherIndex = secondSegmentIndex; cp.ThisEndpoint = -1; cp.OtherEndpoint = -1; if(intersectionPoint.EqualdWithin(firstSegment.Point1, allowedError)) { cp.ThisEndpoint = firstSegmentIndex; } else if(intersectionPoint.EqualdWithin(firstSegment.Point2, allowedError)) { cp.ThisEndpoint = firstSegmentIndex + 1; } else if(intersectionPoint.EqualdWithin(secondSegment.Point1, allowedError)) { cp.OtherEndpoint = secondSegmentIndex; } else if(intersectionPoint.EqualdWithin(secondSegment.Point2, allowedError)) { cp.OtherEndpoint = secondSegmentIndex + 1; } if (!intersects || cp.ThisEndpoint != -1 || cp.OtherEndpoint != -1 ) { if (shouldEliminatePointOnEnd) { throw new Exception(); } cp.ContactType = ContactType.PointOnSegment; } else { cp.ContactType = ContactType.SegmentIntersection; } if (!intersects) { indexesToRemove.Add(contactPoints.Count); } contactPoints.Add(cp); } } } #if false // Not sure why this is here, but it causes warnings and we don't use it if (false && parallelContactPoints.Count == 2) { const float minimumLength = .01f; bool isParallelContactPoint = false; for (int i = 0; i < contactPoints.Count; i++) { float closestToPair = float.PositiveInfinity; Vector3 position = contactPoints[i].Position; for (int parallelIndex = 0; parallelIndex < parallelContactPoints.Count; parallelIndex++) { Segment segment1 = firstSegments[parallelContactPoints[parallelIndex].ThisIndex]; Segment segment2 = secondSegments[parallelContactPoints[parallelIndex].OtherIndex]; float firstDistance = segment1.DistanceTo(position.X, position.Y); float secondDistance = segment2.DistanceTo(position.X, position.Y); float furthestAway = System.Math.Max(firstDistance, secondDistance); closestToPair = System.Math.Min(furthestAway, closestToPair); } if (closestToPair > minimumLength) { isParallelContactPoint = true; break; } } if (!isParallelContactPoint) { return parallelContactPoints; } } #endif int numberKilled = 0; List<int> intersectionIndexes = new List<int>(); for (int i = 0; i < firstSegments.Length; i++) { intersectionIndexes.Clear(); for (int cpIndex = 0; cpIndex < contactPoints.Count; cpIndex++) { if (contactPoints[cpIndex].ThisIndex == i) { intersectionIndexes.Add(cpIndex); } } if (intersectionIndexes.Count > 2 && intersectionIndexes.Count % 2 == 1) { contactPoints.RemoveAt(intersectionIndexes[1]); } } for (int i = 0; i < secondSegments.Length; i++) { intersectionIndexes.Clear(); for (int cpIndex = 0; cpIndex < contactPoints.Count; cpIndex++) { if (contactPoints[cpIndex].OtherIndex == i) { intersectionIndexes.Add(cpIndex); } } if (intersectionIndexes.Count > 2 && intersectionIndexes.Count % 2 == 1) { contactPoints.RemoveAt(intersectionIndexes[1]); } } // See if any contact points are the same. If so, kill them for (int firstCP = 0; firstCP < contactPoints.Count - 1; firstCP++) { for (int secondCP = 1; secondCP < contactPoints.Count; secondCP++) { if (firstCP == secondCP) { continue; } float distanceApart = (contactPoints[firstCP].Position - contactPoints[secondCP].Position).Length(); if (distanceApart < .002) { contactPoints.RemoveAt(secondCP); firstCP = -1; // start over. numberKilled++; break; } } } if (contactPoints.Count == 1) { // Is this bad? What do we do? //int m = 3; } if (contactPoints.Count % 2 != 0 && contactPoints.Count > 1) { // Oh, no, an odd number of contact points? Let's kill the closest pair ReactToOddContactPointCount(contactPoints); } #endregion return contactPoints; }
private static List <ContactPoint> GetContactPoints(Segment[] firstSegments, Segment[] secondSegments) { if (shouldEliminatePointOnEnd) { ShiftEndpointsToEliminatePointOnSegment(firstSegments, secondSegments); } Point intersectionPoint = new Point(); List <ContactPoint> contactPoints = new List <ContactPoint>(); Segment firstSegment = new Segment(); Segment secondSegment = new Segment(); const double allowedError = .0005; bool debug = false; #if !SILVERLIGHT && !MONOGAME && !XBOX360 && !WINDOWS_PHONE if (debug) { FlatRedBall.Content.Polygon.PolygonSaveList psl = new FlatRedBall.Content.Polygon.PolygonSaveList(); psl.PolygonSaves.Add( FlatRedBall.Content.Polygon.PolygonSave.FromPolygon( Polygon.FromSegments(firstSegments))); psl.PolygonSaves.Add( FlatRedBall.Content.Polygon.PolygonSave.FromPolygon( Polygon.FromSegments(secondSegments))); psl.Save(FlatRedBall.IO.FileManager.MyDocuments + "modifiedPolygons.plylstx"); } #endif #region Handle the two-parallel segment special case List <ContactPoint> parallelContactPoints = new List <ContactPoint>(); for (int firstIndex = 0; firstIndex < firstSegments.Length; firstIndex++) { firstSegment = firstSegments[firstIndex]; for (int secondIndex = 0; secondIndex < secondSegments.Length; secondIndex++) { secondSegment = secondSegments[secondIndex]; Point parallelIntersectionPoint; if (firstSegment.IsParallelAndTouching(secondSegment, out parallelIntersectionPoint)) { ContactPoint cp = new ContactPoint(); cp.ThisIndex = firstIndex; cp.OtherIndex = secondIndex; // Technically this is a point on segment intersection, // but we treat it like a segment intersection because we're // going to eliminate duplicates cp.ContactType = ContactType.SegmentIntersection; cp.Position = new Vector3((float)parallelIntersectionPoint.X, (float)parallelIntersectionPoint.Y, 0); parallelContactPoints.Add(cp); } } } #endregion #region else, do regular intersection tests List <int> indexesToRemove = new List <int>(); for (int firstSegmentIndex = 0; firstSegmentIndex < firstSegments.Length; firstSegmentIndex++) { firstSegment = firstSegments[firstSegmentIndex]; for (int secondSegmentIndex = 0; secondSegmentIndex < secondSegments.Length; secondSegmentIndex++) { secondSegment = secondSegments[secondSegmentIndex]; bool intersects = firstSegment.Intersects(secondSegment, out intersectionPoint); if (intersects || firstSegment.IsParallelAndTouching(secondSegment, out intersectionPoint)) { ContactPoint cp = new ContactPoint(); cp.Position = new Vector3((float)intersectionPoint.X, (float)intersectionPoint.Y, 0); cp.ThisIndex = firstSegmentIndex; cp.OtherIndex = secondSegmentIndex; cp.ThisEndpoint = -1; cp.OtherEndpoint = -1; if (intersectionPoint.EqualdWithin(firstSegment.Point1, allowedError)) { cp.ThisEndpoint = firstSegmentIndex; } else if (intersectionPoint.EqualdWithin(firstSegment.Point2, allowedError)) { cp.ThisEndpoint = firstSegmentIndex + 1; } else if (intersectionPoint.EqualdWithin(secondSegment.Point1, allowedError)) { cp.OtherEndpoint = secondSegmentIndex; } else if (intersectionPoint.EqualdWithin(secondSegment.Point2, allowedError)) { cp.OtherEndpoint = secondSegmentIndex + 1; } if (!intersects || cp.ThisEndpoint != -1 || cp.OtherEndpoint != -1 ) { if (shouldEliminatePointOnEnd) { throw new Exception(); } cp.ContactType = ContactType.PointOnSegment; } else { cp.ContactType = ContactType.SegmentIntersection; } if (!intersects) { indexesToRemove.Add(contactPoints.Count); } contactPoints.Add(cp); } } } #if false // Not sure why this is here, but it causes warnings and we don't use it if (false && parallelContactPoints.Count == 2) { const float minimumLength = .01f; bool isParallelContactPoint = false; for (int i = 0; i < contactPoints.Count; i++) { float closestToPair = float.PositiveInfinity; Vector3 position = contactPoints[i].Position; for (int parallelIndex = 0; parallelIndex < parallelContactPoints.Count; parallelIndex++) { Segment segment1 = firstSegments[parallelContactPoints[parallelIndex].ThisIndex]; Segment segment2 = secondSegments[parallelContactPoints[parallelIndex].OtherIndex]; float firstDistance = segment1.DistanceTo(position.X, position.Y); float secondDistance = segment2.DistanceTo(position.X, position.Y); float furthestAway = System.Math.Max(firstDistance, secondDistance); closestToPair = System.Math.Min(furthestAway, closestToPair); } if (closestToPair > minimumLength) { isParallelContactPoint = true; break; } } if (!isParallelContactPoint) { return(parallelContactPoints); } } #endif int numberKilled = 0; List <int> intersectionIndexes = new List <int>(); for (int i = 0; i < firstSegments.Length; i++) { intersectionIndexes.Clear(); for (int cpIndex = 0; cpIndex < contactPoints.Count; cpIndex++) { if (contactPoints[cpIndex].ThisIndex == i) { intersectionIndexes.Add(cpIndex); } } if (intersectionIndexes.Count > 2 && intersectionIndexes.Count % 2 == 1) { contactPoints.RemoveAt(intersectionIndexes[1]); } } for (int i = 0; i < secondSegments.Length; i++) { intersectionIndexes.Clear(); for (int cpIndex = 0; cpIndex < contactPoints.Count; cpIndex++) { if (contactPoints[cpIndex].OtherIndex == i) { intersectionIndexes.Add(cpIndex); } } if (intersectionIndexes.Count > 2 && intersectionIndexes.Count % 2 == 1) { contactPoints.RemoveAt(intersectionIndexes[1]); } } // See if any contact points are the same. If so, kill them for (int firstCP = 0; firstCP < contactPoints.Count - 1; firstCP++) { for (int secondCP = 1; secondCP < contactPoints.Count; secondCP++) { if (firstCP == secondCP) { continue; } float distanceApart = (contactPoints[firstCP].Position - contactPoints[secondCP].Position).Length(); if (distanceApart < .002) { contactPoints.RemoveAt(secondCP); firstCP = -1; // start over. numberKilled++; break; } } } if (contactPoints.Count == 1) { // Is this bad? What do we do? //int m = 3; } if (contactPoints.Count % 2 != 0 && contactPoints.Count > 1) { // Oh, no, an odd number of contact points? Let's kill the closest pair ReactToOddContactPointCount(contactPoints); } #endregion return(contactPoints); }