private void OnDrawGizmos() { Polygon2 pol0 = CreatePolygon2(Points0); Polygon2 pol1 = CreatePolygon2(Points1); Orientations orientation0; bool pol0Convex = pol0.IsConvex(out orientation0); Orientations orientation1; bool pol1Convex = pol1.IsConvex(out orientation1); FiguresColor(); DrawPolygon(pol0); DrawPolygon(pol1); if (pol0Convex && pol1Convex && orientation0 == Orientations.CCW && orientation1 == Orientations.CCW) { bool test = Intersection.TestConvexPolygon2ConvexPolygon2(pol0, pol1); Logger.LogInfo("Intersection: " + test); } else { Logger.LogError("Polygons are incorrect." + " Pol0Convex: " + pol0Convex + " Pol0Ori: " + orientation0 + " Pol1Convex: " + pol1Convex + " Pol1Ori: " + orientation1); } }
List <Polygon2> TileColliderDataToPolygons(TileColliderData tileColliderData, Vector2 scale) { List <Polygon2> polygons = new List <Polygon2>(); if (tileColliderData.vertices.Length > 0) { Polygon2 polygon = new Polygon2(tileColliderData.vertices.Length); for (int i = 0; i < tileColliderData.vertices.Length; i++) { Vector2 v = tileColliderData.vertices[i]; polygon.points[i] = v; } if (scale != Vector2.one) { polygon.ToScaleSelf(scale); } polygons.Add(polygon); } return(polygons); }
/// <summary> /// Checks what entities if any intersect any of the specified traces /// </summary> /// <param name="traces">The set of traces to check</param> /// <param name="from">Where the traces start at</param> /// <param name="excludeIds">The set of collidable ids which are excluded from this search</param> /// <param name="excludeFlags">Collidables with any of these flags are excluded</param> /// <returns>A list of all collidables inside any of the specified traces</returns> public List <T> TraceExhaust(List <Polygon2> traces, Vector2 from, HashSet <int> excludeIds, long excludeFlags) { List <T> result = new List <T>(); int tracesLen = traces.Count; for (int i = 0, len = Collidables.Count; i < len; i++) { T collidable = Collidables[i]; if (excludeIds.Contains(collidable.ID)) { continue; } if ((collidable.Flags & excludeFlags) != 0) { continue; } for (int j = 0; j < tracesLen; j++) { if (Polygon2.Intersects(collidable.Bounds, traces[j], collidable.Position, from, true)) { result.Add(collidable); break; } } } return(result); }
/// <summary> /// Checks if there are any entities intersecting any of the given polygons which do not have an ID /// in excludeIds and do not have any of the exclude flags. /// /// Returns true if there are no intersecting entities, returns false if there are intersecting entities /// </summary> /// <param name="traces">The polygons to check if any entities intersect</param> /// <param name="from">The offset for the traces</param> /// <param name="excludeIds">Ids of collidables which will be excluded in this check</param> /// <param name="excludeFlags">Any collibable which has any of these flags is excluded from this check</param> /// <returns>True if there are entities in traces located at from, False otherwise</returns> public bool Trace(List <Polygon2> traces, Vector2 from, HashSet <int> excludeIds, long excludeFlags) { int tracesLen = traces.Count; for (int i = 0, len = Collidables.Count; i < len; i++) { T collidable = Collidables[i]; if (excludeIds.Contains(collidable.ID)) { continue; } if ((collidable.Flags & excludeFlags) != 0) { continue; } for (int j = 0; j < tracesLen; j++) { if (Polygon2.Intersects(collidable.Bounds, traces[j], collidable.Position, from, true)) { return(false); } } } return(true); }
public static List <Polygon2> CreateFromCompositeCollider(CompositeCollider2D compositeCollider) { List <Polygon2> list = new List <Polygon2>(); if (compositeCollider != null) { int pathCount = compositeCollider.pathCount; for (int i = 0; i < pathCount; i++) { int pointCount = compositeCollider.GetPathPointCount(i); Vector2[] pointsInPath = new Vector2[pointCount]; compositeCollider.GetPath(i, pointsInPath); Polygon2 polygon = new Polygon2(pointsInPath); polygon.Normalize(); list.Add(polygon); } } return(list); }
public void InitializeColliders() { localColliders.Clear(); worldColliders.Clear(); colliderTransform.Clear(); foreach (Transform transform in gameObject.transform) { EdgeCollider2D[] edgeColliders = transform.GetComponents <EdgeCollider2D>(); PolygonCollider2D[] polygonColliders = transform.GetComponents <PolygonCollider2D>(); if (edgeColliders.Length > 0) { foreach (EdgeCollider2D collider in edgeColliders) { Polygon2 poly = Polygon2ListCollider2D.CreateFromEdgeCollider(collider); localColliders.Add(poly); colliderTransform.Add(transform); } } if (polygonColliders.Length > 0) { foreach (PolygonCollider2D collider in polygonColliders) { Polygon2 poly = Polygon2ListCollider2D.CreateFromPolygonColliderToLocalSpace(collider)[0]; localColliders.Add(poly); colliderTransform.Add(transform); } } } }
static private void ShadowForVertex(Polygon2 polygon, Vector2 position) { Vector2[] pointsList = polygon.points; int pointsCount = pointsList.Length; for (int x = 0; x < pointsCount; x++) { pair.A.x = pointsList[(x) % pointsCount].x + position.x; pair.A.y = pointsList[(x) % pointsCount].y + position.y; pair.B.x = pointsList[(x + 2) % pointsCount].x + position.x; pair.B.y = pointsList[(x + 2) % pointsCount].y + position.y; Pair2D edge_world = pair; Vector2 edgePosition; edgePosition.x = (float)(pair.A.x + pair.B.x) / 2; edgePosition.y = (float)(pair.A.y + pair.B.y) / 2; float edgeRotation = (float)Math.Atan2(pair.B.y - pair.A.y, pair.B.x - pair.A.x); float edgeSize = (float)Vector2D.Distance(pair.A, pair.B) / 2; pass.edgePosition = edgePosition; pass.edgeRotation = edgeRotation; pass.edgeSize = edgeSize; pass.coreSize = ShadowEngine.light.coreSize; pass.Generate(); pass.SetVars(); pass.Draw(); } }
public static void Main(string[] args) { // var canvas = host.CreateAndAddCanvas(0); // var smp = SectorMetadataPresets.Blank2D; // var punchResult = PolygonOperations.Punch() // .Include(smp.LocalIncludedContours) //// .Exclude(smp.LocalExcludedContours) // .Exclude(Polygon2.CreateRect(-10000, -10000, 20000, 20000)) // .Exclude(new []{(Polygon2.CreateRect(-8000, -8000, 16000, 16000), true)}) // .Execute(); // // canvas.Transform = Matrix4x4.CreateScale(500 / 60000.0f) * Matrix4x4.CreateTranslation(500, 300, 0); // canvas.DrawPolyNode(punchResult); // return; //var subjectPolygon = Polygon2.CreateCircle(0, 0, 100, 16); var n = 128; var random = new Random(0); var subjectPolygon = new Polygon2( Util.Generate( n, i => DoubleVector2.FromRadiusAngle(random.Next(10, 150), -i * Math.PI * 2 / n).LossyToIntVector2()) .ToList()); var clipPolygon = Polygon2.CreateRect(-80, -80, 160, 160); RenderSomething(0, subjectPolygon, clipPolygon); var offsetSubjectPolygon = new Polygon2(subjectPolygon.Points.Map(p => new IntVector2(0, 240) + p).ToList()); RenderSomething(1, offsetSubjectPolygon, clipPolygon); }
public PolyPairTestData(string name, Polygon2 a, Polygon2 b, Polygon2 r) { Name = name; A = a; B = b; R = r; }
void TryCastHealingStrike(JToken parsed) { if (Entity.SpellCooldowns.ContainsKey(SpellFactory.HEALING_STRIKE_INDEX)) { return; } var currWorld = Program.State.World; var currEnt = currWorld.GetByID(Entity.ID); if (!ManaCheck(currEnt, SpellFactory.HEALING_STRIKE_MANA)) { return; } Vector2 target = new Vector2((float)parsed[2]["x"], (float)parsed[2]["y"]); var mind = Polygon2.MinDistance(currEnt.Attributes.Bounds, currEnt.Location, target); if (mind != null && mind.Item2 > SpellFactory.HEALING_STRIKE_RANGE) { return; } var mut = new EntityCastSpellMutation(Entity.ID, SpellFactory.CreateHealingStrike(target)); Program.QueuedMutations[mut.Time].Enqueue(mut); _CastingSpell = true; UpdateVelocity(); }
static void Main(string[] args) { Console.WriteLine("Fact: " + (GeometryFactory2Double.Instance != null)); GeometryFactory2Base <double> factory = GeometryFactory2Double.Instance; Console.WriteLine("Factory is " + (factory == null ? "null" : "not null")); if (factory != null) { Point2 <double> pt = factory.ConstructPoint(43, 22); Console.WriteLine("Created point: " + pt.ToString()); Ring2 <double> rg = factory.ConstructRing(new Point2 <double>[] { factory.ConstructPoint(22.45, 33.33), factory.ConstructPoint(23.45, 33.33), factory.ConstructPoint(22.45, 35.33) }); Polygon2 <double> pl = factory.ConstructPolygon(rg); if (rg != null) { Console.WriteLine("Created ring: " + rg.ToString()); object o = Osrs.Numerics.Spatial.Postgres.NpgSpatialUtils.ToPGis(rg); Console.WriteLine("Created PG Geometry: " + (o != null).ToString()); } if (pl != null) { Console.WriteLine(GeoJsonUtils.ToGeoJson(pl).ToString()); } } Console.WriteLine("ALL DONE"); Console.ReadLine(); }
private Polygon2 FindUntouchedRingsB() { Contract.Ensures(Contract.Result <IEnumerable <Ring2> >() != null); if (VisitedCrossingsRingIndicesB.Count == 0) { return(B); } var missingCount = B.Count - VisitedCrossingsRingIndicesB.Count; var results = new Polygon2(missingCount); if (missingCount == 0) { return(results); } for (int i = 0; i < B.Count; i++) { if (!VisitedCrossingsRingIndicesB.Contains(i)) { results.Add(B[i]); } } return(results); }
private IntersectionResults BuildFinalResults(Polygon2 intersectedPolygon) { Contract.Requires(intersectedPolygon != null); Contract.Ensures(Contract.Result <IntersectionResults>() != null); Contract.Ensures(intersectedPolygon.Count >= Contract.OldValue(intersectedPolygon).Count); if (intersectedPolygon.Count == 0) { var untouchedA = FindUntouchedRingsA(); var untouchedB = FindUntouchedRingsB(); intersectedPolygon.AddRange(QualifyRings(untouchedA, untouchedB, true)); intersectedPolygon.AddRange(QualifyRings(untouchedB, untouchedA, false)); } else { var intersectedResultTree = new RingBoundaryTree(intersectedPolygon); intersectedPolygon.AddRange( FilterQualifiedRingsToBoundaryTree( QualifyRings(FindUntouchedRingsA(), B, true), intersectedResultTree ) ); intersectedPolygon.AddRange( FilterQualifiedRingsToBoundaryTree( QualifyRings(FindUntouchedRingsB(), A, false), intersectedResultTree ) ); } return(new IntersectionResults { Polygon = intersectedPolygon }); }
private void OnDrawGizmos() { List <Vector2> pointsList = new List <Vector2>(); foreach (Transform tr in Points) { if (tr != null) { pointsList.Add(tr.position); } } Polygon2 pol = new Polygon2(pointsList.ToArray()); Gizmos.color = Color.gray; for (int i0 = 0, i1 = pol.VertexCount - 1; i0 < pol.VertexCount; i1 = i0, i0++) { Gizmos.DrawLine(pol[i0], pol[i1]); } Orientations or; bool convex = pol.IsConvex(out or); bool hasDegen = pol.HasZeroCorners(); Logger.LogInfo("Area: " + pol.CalcArea() + " Per: " + pol.CalcPerimeter() + " Convex: " + convex + " Orient: " + or + " ZeroCorners: " + hasDegen); }
static public List <Polygon2> CreateFromPolygonColliderToLocalSpace(PolygonCollider2D collider) { List <Polygon2> result = new List <Polygon2>(); if (collider != null && collider.pathCount > 0) { Vector2[] array = collider.GetPath(0); Polygon2 newPolygon = new Polygon2(array.Length); for (int i = 0; i < array.Length; i++) { Vector2 p = array[i]; newPolygon.points[i] = (p + collider.offset); } result.Add(newPolygon); for (int i = 1; i < collider.pathCount; i++) { Vector2[] arrayHole = collider.GetPath(i); Polygon2 hole = new Polygon2(arrayHole.Length); for (int x = 0; x < arrayHole.Length; x++) { hole.points[i] = arrayHole[x] + collider.offset; } result.Add(hole); } } return(result); }
private static List <Ring2> QualifyRings( Polygon2 untouchedRings, Polygon2 polygon, bool qualifyEqual ) { Contract.Requires(untouchedRings != null); Contract.Requires(polygon != null); Contract.Ensures(Contract.Result <List <Ring2> >() != null); Contract.Ensures(Contract.ForAll(Contract.Result <List <Ring2> >(), x => null != x)); var result = new List <Ring2>(); var ringTree = new RingBoundaryTree(polygon); foreach (var ring in untouchedRings) { Contract.Assume(ring != null); // TODO: speed this up through some kind of magic, like RingBoundaryTree or something // TODO: var eq = new SpatialEqualityComparerThing(ringA); var stuff = otherRings.Where(r = > eq.SpatiallyEqual(r)); if (polygon.Any(r => ring.SpatiallyEqual(r))) { if (qualifyEqual) { result.Add(ring.Clone()); } } else if (ringTree.NonIntersectingContains(ring)) { result.Add(ring.Clone()); } } Contract.Assume(Contract.ForAll(result, x => null != x)); return(result); }
/// <summary> /// Find a smallest bounding rectangle. /// </summary> /// <returns></returns> public Vector2[] FindBounds(Polygon2 polygon) { if (polygon == null) { throw new ArgumentNullException("polygon"); } var minified = new Polygon2(polygon.ToVertices().Distinct()); minified.OrientCounterClockwise(); var vertices = minified.ToVertices().ToArray(); if (vertices.Count() == 0) { return(new Vector2[0]); } // This algorithm assumes the polygon is oriented counter-clockwise. // Get ready; ResetBoundingRect(vertices); // Check all possible bounding rectangles. for (int i = 0; i < vertices.Count(); i++) { CheckNextBoundingRectangle(vertices); } // Return the best result. return(_bestRectangle); }
/// <summary> /// Load existing collision /// </summary> /// <param name="buffer"></param> public void Load(byte[] buffer) { try { using (BinaryReader b = new BinaryReader(new MemoryStream(buffer))) { var polygonCount = b.ReadInt32(); for (int i = 0; i < polygonCount; i++) { var polygon = new Polygon2(); var pointNum = b.ReadInt32(); for (int p = 0; p < pointNum; p++) { var point = new K2DPosition(); point.X = b.ReadInt32(); point.Y = b.ReadInt32(); polygon.Points.Add(point); } Polygons.Add(polygon); } } XLog.WriteLine(Levels.Good, "Ok"); } catch (Exception exception) { Blank(); XLog.WriteLine(Levels.Error, "Failed"); XLog.WriteLine(Levels.Fatal, "NfaManager::Load<Exception> -> {0}", exception); } }
static public List <Polygon2> CreateFromMeshCollider(MeshCollider meshCollider) { List <Polygon2> newPolygons = new List <Polygon2>(); Vector2 size = new Vector2(1, 1); Vector2 offset = Vector2.zero; Mesh mesh = meshCollider.sharedMesh; int length = mesh.triangles.GetLength(0); for (int i = 0; i < length; i = i + 3) { Vector2 vecA = mesh.vertices [mesh.triangles [i]]; Vector2 vecB = mesh.vertices [mesh.triangles [i + 1]]; Vector2 vecC = mesh.vertices [mesh.triangles [i + 2]]; Polygon2 poly = new Polygon2(3); poly.points[0] = vecA; poly.points[1] = vecB; poly.points[2] = vecC; newPolygons.Add(poly); } return(newPolygons); }
protected void DrawPolygon(Polygon2 polygon) { for (int i0 = 0, i1 = polygon.VertexCount - 1; i0 < polygon.VertexCount; i1 = i0, ++i0) { Gizmos.DrawLine(polygon[i0], polygon[i1]); } }
private void OnDrawGizmos() { Ray2 ray = CreateRay2(Ray); Polygon2 polygon = CreatePolygon2(Polygon); Ray2Polygon2Intr info; bool find = Intersection.FindRay2Polygon2(ref ray, polygon, out info); FiguresColor(); DrawRay(ref ray); DrawPolygon(polygon); if (find) { ResultsColor(); if (info.IntersectionType == IntersectionTypes.Point) { DrawPoint(info.Point0); } else if (info.IntersectionType == IntersectionTypes.Segment) { DrawSegment(info.Point0, info.Point1); DrawPoint(info.Point0); DrawPoint(info.Point1); } } LogInfo(info.IntersectionType); }
public static void DrawPolygonContour(this IDebugCanvas canvas, Polygon2 poly, StrokeStyle strokeStyle) { for (var i = 0; i < poly.Points.Count - 1; i++) { canvas.DrawLineStrip(poly.Points.Map(ToDV3), strokeStyle); } }
public PolyPairTestData(RingPairTestData data, Polygon2 result) { Name = data.Name; A = new Polygon2(data.A); B = new Polygon2(data.B); R = null == result ? null : new Polygon2(result); CrossingPoints = (data.CrossingPoints ?? Enumerable.Empty<Point2>()).ToList(); }
private Polygon2 GetRectPolygon() { if (rectPolygon == null) { rectPolygon = new Polygon2(4); } return(rectPolygon); }
public List <Polygon2> GetWorldPolygons(LightTilemapCollider.Base tilemap) { if (worldPolygons == null) { List <Polygon2> localPolygons = GetLocalPolygons(tilemap); if (worldPolygonsCache == null) { worldPolygons = new List <Polygon2>(); worldPolygonsCache = worldPolygons; UpdateTransform(tilemap); foreach (Polygon2 polygon in localPolygons) { Polygon2 worldPolygon = polygon.Copy(); if (scale != Vector2.one) { worldPolygon.ToScaleSelf(scale); } worldPolygon.ToScaleSelf(worldScale); worldPolygon.ToRotationSelf((tilemap.transform.eulerAngles.z + rotation) * Mathf.Deg2Rad); worldPolygon.ToOffsetSelf(worldPosition.Value); worldPolygons.Add(worldPolygon); } } else { worldPolygons = worldPolygonsCache; UpdateTransform(tilemap); for (int i = 0; i < localPolygons.Count; i++) { Polygon2 polygon = localPolygons[i]; Polygon2 worldPolygon = worldPolygons[i]; for (int j = 0; j < polygon.points.Length; j++) { worldPolygon.points[j].x = polygon.points[j].x; worldPolygon.points[j].y = polygon.points[j].y; } if (scale != Vector2.one) { worldPolygon.ToScaleSelf(scale); } worldPolygon.ToScaleSelf(worldScale); worldPolygon.ToRotationSelf(tilemap.transform.eulerAngles.z * Mathf.Deg2Rad); worldPolygon.ToOffsetSelf(worldPosition.Value); } } } return(worldPolygons); }
public static VisualPolygon Create(Polygon2 poly, Pen pen = null, Brush brush = null) { return(new VisualPolygon(poly) { Pen = pen, FillBrush = brush }); }
internal override bool Overlaps(OverlapShape otherShape) { if (otherShape is OverlapBox b) { return(Polygon2.Intersects(b.Poly, Poly, b.Pos, Pos, b.Rot, Rot, false)); } return(false); }
public PolyPairTestData(RingPairTestData data, Polygon2 result) { Name = data.Name; A = new Polygon2(data.A); B = new Polygon2(data.B); R = null == result ? null : new Polygon2(result); CrossingPoints = (data.CrossingPoints ?? Enumerable.Empty <Point2>()).ToList(); }
private static Polygon2 ReverseWinding(Polygon2 p) { if (null == p) { return(null); } return(new Polygon2(p.Select(ReverseWinding))); }
public static PostgisPolygon ToPGis(Polygon2 <double> geom) { if (geom != null) { return(new PostgisPolygon(Points(geom))); } return(null); }
public Polygon2 ToWorldSpace(Transform transform) { Polygon2 newPolygon = this.Copy(); newPolygon.ToWorldSpaceSelf(transform); return(newPolygon); }
private static string PolygonToString(Polygon2 poly) { var sb = new StringBuilder(); for (int index = 0; index < poly.Count; index++) { var ring = poly[index]; sb.AppendFormat("Ring {0}:\n", index); sb.AppendLine(RingToString(ring)); } return sb.ToString(); }
/// <summary> /// Calculates the resulting union of two polygon geometries. /// </summary> /// <param name="a">A polygon.</param> /// <param name="b">A polygon.</param> /// <returns>The union of <paramref name="a"/> and <paramref name="b"/>.</returns> public IPlanarGeometry Union(Polygon2 a, Polygon2 b) { Contract.Ensures((a != null || b != null) || Contract.Result<IPlanarGeometry>() == null); if (null == a) return b; if (null == b) return a; var result = InverseIntersectionOperation.Intersect(a, b) as Polygon2; return result; }
/// <summary> /// Calculates the symmetric difference between two polygons. /// </summary> /// <param name="a">A polygon.</param> /// <param name="b">A polygon.</param> /// <returns>The symmetric difference of <paramref name="a"/> and <paramref name="b"/>.</returns> public IPlanarGeometry Xor(Polygon2 a, Polygon2 b) { if (null == a) return b; if (null == b) return a; var removedFromA = _differenceOperation.Difference(a, b) as Polygon2; var removedFromB = _differenceOperation.Difference(b, a) as Polygon2; var unionedLeftovers = _unionOperation.Union(removedFromA, removedFromB); return unionedLeftovers; }
public void TestPolygon() { Polygon2 poly = new Polygon2() { vertices = new Vector2[]{ new Vector2(1, 1), new Vector2(2, 1), new Vector2(1, 2) } }; Assert.IsTrue(poly.Contains(new Vector2(1.1f, 1.1f))); Assert.IsTrue(poly.Contains(new Vector2(1.1f, 1.8f))); Assert.IsTrue(poly.Contains(new Vector2(1.49f, 1.49f))); Assert.IsFalse(poly.Contains(new Vector2(1.51f, 1.51f))); Assert.IsFalse(poly.Contains(new Vector2(0f, 0f))); Assert.IsTrue(poly.Contains(new Vector2(1f, 1f))); }
private static Polygon2 ReverseWinding(Polygon2 p) { if (null == p) return null; return new Polygon2(p.Select(ReverseWinding)); }
/// <summary> /// Builds required crossing data. /// </summary> /// <param name="crossings">The crossings to calculate. (Note: collection is modified)</param> /// <param name="a">The left hand polygon.</param> /// <param name="b">The right hand polygon.</param> private PolygonCrossingsAlgorithmKernel CreateIntersectionKernelFromCrossings(List<PolygonCrossing> crossings, Polygon2 a, Polygon2 b) { Contract.Requires(crossings != null); Contract.Requires(a != null); Contract.Requires(b != null); Contract.Ensures(Contract.Result<PolygonCrossingsAlgorithmKernel>() != null); var kernel = new PolygonCrossingsAlgorithmKernel(a, b, crossings); if (crossings.Count == 0) return kernel; foreach (var currentCrossing in crossings) { var ringIndexA = currentCrossing.LocationA.RingIndex; Contract.Assume(ringIndexA < a.Count); var ringA = a[ringIndexA]; Contract.Assume(ringA != null); var crossingsOnRingA = kernel.RingCrossingsA.Get(ringIndexA); var priorPointA = FindPreviousRingPoint(currentCrossing, crossingsOnRingA, ringA, GetLocationA, PolygonCrossing.LocationAComparer.Default); var nextPointA = FindNextRingPoint(currentCrossing, crossingsOnRingA, ringA, GetLocationA, PolygonCrossing.LocationAComparer.Default); var ringIndexB = currentCrossing.LocationB.RingIndex; Contract.Assume(ringIndexB < b.Count); var ringB = b[ringIndexB]; Contract.Assume(ringB != null); var crossingsOnRingB = kernel.RingCrossingsB.Get(ringIndexB); var priorPointB = FindPreviousRingPoint(currentCrossing, crossingsOnRingB, ringB, GetLocationB, PolygonCrossing.LocationBComparer.Default); var nextPointB = FindNextRingPoint(currentCrossing, crossingsOnRingB, ringB, GetLocationB, PolygonCrossing.LocationBComparer.Default); // based on the vectors, need to classify the crossing type currentCrossing.CrossType = PolygonCrossing.DetermineCrossingType( (nextPointA - currentCrossing.Point).GetNormalized(), (priorPointA - currentCrossing.Point).GetNormalized(), (nextPointB - currentCrossing.Point).GetNormalized(), (priorPointB - currentCrossing.Point).GetNormalized() ); } foreach (var ringCrossings in kernel.RingCrossingsA.RingCrossings) { Contract.Assume(ringCrossings.Key >= 0 && ringCrossings.Key < a.Count); if (a[ringCrossings.Key].FillSide == RelativeDirectionType.Right) { foreach (var crossing in ringCrossings.Value) { Contract.Assume(crossing != null); var crossLegType = crossing.CrossType & CrossingType.Parallel; if (crossLegType == CrossingType.CrossToRight || crossLegType == CrossingType.DivergeRight) kernel.Entrances.Add(crossing); else if (crossLegType == CrossingType.CrossToLeft || crossLegType == CrossingType.ConvergeRight) kernel.Exits.Add(crossing); } } else { foreach (var crossing in ringCrossings.Value) { Contract.Assume(crossing != null); var crossLegType = crossing.CrossType & CrossingType.Parallel; if (crossLegType == CrossingType.CrossToLeft || crossLegType == CrossingType.DivergeLeft) kernel.Entrances.Add(crossing); else if (crossLegType == CrossingType.CrossToRight || crossLegType == CrossingType.ConvergeLeft) kernel.Exits.Add(crossing); } } } var sortedEntrances = kernel.Entrances.ToArray(); Array.Sort(sortedEntrances, PolygonCrossing.LocationAComparer.CompareNonNull); Contract.Assume(kernel.Exits != null); var sortedExits = kernel.Exits.ToArray(); Array.Sort(sortedExits, PolygonCrossing.LocationBComparer.CompareNonNull); for (int i = 0; i < sortedExits.Length; i++) { var exit = sortedExits[i]; var locationIndex = Array.BinarySearch(sortedEntrances, exit, PolygonCrossing.LocationAComparer.Default); if(locationIndex >= 0) kernel.ExitHops.Add(exit, sortedEntrances[locationIndex]); } for (int i = 0; i < sortedEntrances.Length; i++) { var entrance = sortedEntrances[i]; var locationIndex = Array.BinarySearch(sortedExits, entrance, PolygonCrossing.LocationBComparer.Default); if(locationIndex >= 0) kernel.EntranceHops.Add(entrance, sortedExits[locationIndex]); } return kernel; }
/// <summary> /// Inverts a polygon. /// </summary> /// <param name="polygon">The polygon to get the inverse of.</param> /// <returns>An inverted polygon.</returns> public static Polygon2 Invert(Polygon2 polygon) { Contract.Ensures(polygon == null ? Contract.Result<Polygon2>() == null : Contract.Result<Polygon2>() != null); return null == polygon ? null : new Polygon2(polygon.Select(Invert)); }
/// <summary> /// Determines the points that would need to be inserted into the resulting /// intersection geometry between the two given polygons, at the location where /// their boundaries cross. /// </summary> /// <param name="a">The first polygon to test.</param> /// <param name="b">The second polygon to test.</param> public List<PolygonCrossing> FindPointCrossings(Polygon2 a, Polygon2 b) { Contract.Ensures(Contract.Result<List<PolygonCrossing>>() != null); if (null == a || null == b) return new List<PolygonCrossing>(0); var crossingGenerator = new PolygonPointCrossingGenerator(a, b); var allCrossings = crossingGenerator.GenerateCrossings(); return allCrossings; }
public static void can_perform_box_and_donut_intersection_without_exception() { var donut = new Polygon2 { // outer boundary new Ring2( Enumerable.Range(0,8) .Select(i => i * 45 / 180.0 * Math.PI) .Select(t => new Point2(Math.Cos(t),Math.Sin(t))) ){Hole = false}, // inner hole new Ring2( Enumerable.Range(0,8) .Reverse() .Select(i => i * 45/ 180.0 * Math.PI) .Select(t => new Point2(Math.Cos(t)*0.5,Math.Sin(t)*0.5)) ) {Hole = true} }; var box = new Polygon2(new Ring2(new[]{ new Point2(0,0), new Point2(1,0), new Point2(1,1), new Point2(0,1) }) { Hole = false }); var intersectionOperation = new PolygonIntersectionOperation(); var result = intersectionOperation.Intersect(box, donut); }
/// <summary> /// Calculates the resulting difference of polygon <paramref name="b"/> subtracted from polygon <paramref name="a"/>. /// </summary> /// <param name="a">The polygon to be subtracted from.</param> /// <param name="b">The polygon used to subtract from a.</param> /// <returns>The difference resulting from subtracting <paramref name="b"/> from <paramref name="a"/>.</returns> public IPlanarGeometry Difference(Polygon2 a, Polygon2 b) { var result = RightInverseIntersectionOperation.Intersect(a, b); return result; }
public static void boxes_overlapping_top_half_holes() { var sourceData = _polyPairData["Boxes Overlapping: top half"]; var inverseA = new Polygon2(sourceData.A[0].Reverse(), true); var inverseB = new Polygon2(sourceData.B[0].Reverse(), true); var expectedResult = inverseA; var result = _intersectionOperation.Intersect(inverseA, inverseB) as Polygon2; Assert.True(result.SpatiallyEqual(expectedResult)); result = _intersectionOperation.Intersect(inverseB, inverseA) as Polygon2; Assert.True(result.SpatiallyEqual(expectedResult)); }
private static List<Ring2> QualifyRings( Polygon2 untouchedRings, Polygon2 polygon, bool qualifyEqual ) { Contract.Requires(untouchedRings != null); Contract.Requires(polygon != null); Contract.Ensures(Contract.Result<List<Ring2>>() != null); Contract.Ensures(Contract.ForAll(Contract.Result<List<Ring2>>(), x => null != x)); var result = new List<Ring2>(); var ringTree = new RingBoundaryTree(polygon); foreach (var ring in untouchedRings) { Contract.Assume(ring != null); // TODO: speed this up through some kind of magic, like RingBoundaryTree or something // TODO: var eq = new SpatialEqualityComparerThing(ringA); var stuff = otherRings.Where(r = > eq.SpatiallyEqual(r)); if (polygon.Any(r => ring.SpatiallyEqual(r))) { if (qualifyEqual) result.Add(ring.Clone()); } else if (ringTree.NonIntersectingContains(ring)) result.Add(ring.Clone()); } Contract.Assume(Contract.ForAll(result, x => null != x)); return result; }
public abstract void DrawPolygon(FillMode fill, Polygon2 polygon);
private PolygonCrossingsAlgorithmKernel CreateIntersectionKernel(Polygon2 a, Polygon2 b) { Contract.Requires(a != null); Contract.Requires(b != null); Contract.Ensures(Contract.Result<PolygonCrossingsAlgorithmKernel>() != null); var allCrossings = FindPointCrossings(a,b); return CreateIntersectionKernelFromCrossings(allCrossings, a, b); }
public IntersectionResults Turtle(PointWinding fillWinding) { Contract.Ensures(Contract.Result<IntersectionResults>() != null); // now that it is all sorted the turtle starts scooting around, making new rings: // // --== .-----. | ~ard // --== / \ | // A --== <_______(`~`) B | D E // ---*---------//-----//------*-------------*---*---------*--- // C | // | // // please wait while SPEED TURTLE!!! assembles your new rings var rings = new Polygon2(); PolygonCrossing startEntrance; while ((startEntrance = FindNextStartableEntrance()) != null) { var buildingRing = new List<Point2>(); var entrance = startEntrance; do { var exit = TraverseBSide(entrance, buildingRing); if (exit == null) { VisitEntrance(startEntrance); // may need to do this to be safe break; // unmatched entrance } VisitExit(exit); entrance = TraverseASide(exit, buildingRing); if (entrance == null) { break; // unmatched exit } VisitEntrance(entrance); } while (entrance != startEntrance); if (buildingRing.Count >= 3) rings.Add(new Ring2(buildingRing)); // here is a new ring } if (fillWinding != PointWinding.Unknown) rings.ForceFillWinding(fillWinding); return BuildFinalResults(rings); }
[ContractVerification(false)] // TODO: remove when CC bugs are fixed public PolygonCrossingsAlgorithmKernel(Polygon2 a, Polygon2 b, List<PolygonCrossing> crossings) { Contract.Requires(a != null); Contract.Requires(b != null); Contract.Requires(crossings != null); Contract.Requires(Contract.ForAll(crossings, x => x != null)); A = a; B = b; var ringCrossingsABuilder = new Dictionary<int, List<PolygonCrossing>>(a.Count); var ringCrossingsBBuilder = new Dictionary<int, List<PolygonCrossing>>(b.Count); foreach (var crossing in crossings) { List<PolygonCrossing> list; if (!ringCrossingsABuilder.TryGetValue(crossing.LocationA.RingIndex, out list)) { list = new List<PolygonCrossing>(); ringCrossingsABuilder.Add(crossing.LocationA.RingIndex, list); } Contract.Assume(list != null); list.Add(crossing); Contract.Assume(crossing.LocationB != null); if (!ringCrossingsBBuilder.TryGetValue(crossing.LocationB.RingIndex, out list)) { Contract.Assume(crossing.LocationB != null); list = new List<PolygonCrossing>(); ringCrossingsBBuilder.Add(crossing.LocationB.RingIndex, list); } Contract.Assume(list != null); list.Add(crossing); } RingCrossingsA = PolygonRingCrossingLookup.Build(ringCrossingsABuilder, PolygonCrossing.LocationAComparer.CompareNonNull); RingCrossingsB = PolygonRingCrossingLookup.Build(ringCrossingsBBuilder, PolygonCrossing.LocationBComparer.CompareNonNull); Entrances = new HashSet<PolygonCrossing>(); Exits = new HashSet<PolygonCrossing>(); EntranceHops = new Dictionary<PolygonCrossing, PolygonCrossing>(); ExitHops = new Dictionary<PolygonCrossing, PolygonCrossing>(); VisitedCrossings = new List<PolygonCrossing>(); VisitedCrossingsRingIndicesA = new HashSet<int>(); VisitedCrossingsRingIndicesB = new HashSet<int>(); }
/// <summary> /// Calculates the intersection between two polygons. /// </summary> /// <param name="a">A polygon.</param> /// <param name="b">A polygon.</param> /// <returns>The intersection result, which may be a geometry collection containing points, segments, and polygons.</returns> public IPlanarGeometry Intersect(Polygon2 a, Polygon2 b) { if (null == a || a.Count == 0 || null == b || b.Count == 0) return null; if (ReferenceEquals(a, b)) return a.Clone(); if (Options.InvertLeftHandSide) a = PolygonInverseOperation.Invert(a); if (Options.InvertRightHandSide) b = PolygonInverseOperation.Invert(b); // find all the crossings var fillWinding = DetermineFillWinding(a.Concat(b)); var kernel = CreateIntersectionKernel(a, b); // traverse the rings var results = kernel.Turtle(fillWinding); if (null == results.Polygon) return null; // TODO: this stuff is not so great results.Polygon = (results.Polygon.Count == 0 ? null : results.Polygon); if (null != results.Polygon) { if (fillWinding != PointWinding.Unknown) results.Polygon.ForceFillWinding(fillWinding); } if (Options.InvertResult) results.Polygon = PolygonInverseOperation.Invert(results.Polygon); return results.Polygon; }
private IntersectionResults BuildFinalResults(Polygon2 intersectedPolygon) { Contract.Requires(intersectedPolygon != null); Contract.Ensures(Contract.Result<IntersectionResults>() != null); Contract.Ensures(intersectedPolygon.Count >= Contract.OldValue(intersectedPolygon).Count); if (intersectedPolygon.Count == 0) { var untouchedA = FindUntouchedRingsA(); var untouchedB = FindUntouchedRingsB(); intersectedPolygon.AddRange(QualifyRings(untouchedA, untouchedB, true)); intersectedPolygon.AddRange(QualifyRings(untouchedB, untouchedA, false)); } else { var intersectedResultTree = new RingBoundaryTree(intersectedPolygon); intersectedPolygon.AddRange( FilterQualifiedRingsToBoundaryTree( QualifyRings(FindUntouchedRingsA(), B, true), intersectedResultTree ) ); intersectedPolygon.AddRange( FilterQualifiedRingsToBoundaryTree( QualifyRings(FindUntouchedRingsB(), A, false), intersectedResultTree ) ); } return new IntersectionResults { Polygon = intersectedPolygon }; }
public Polygon2 ToPolygon(int offset = 0, float overrideWidth = -1) { var result = new Polygon2(); var outRadius = (overrideWidth > 0 ? overrideWidth : (offset + this.Radius) / (float)Math.Cos(2 * Math.PI / MaxLineSegmentN)); for (var i = MaxLineSegmentN; i >= CurrentLineSegmentN; i--) { var angle = i * 2 * Math.PI / MaxLineSegmentN; var point = new Vector2(this.Center.X + outRadius * (float)Math.Cos(angle), this.Center.Y + outRadius * (float)Math.Sin(angle)); result.Add(point); } return result; }
private Polygon2 FindUntouchedRingsB() { Contract.Ensures(Contract.Result<IEnumerable<Ring2>>() != null); if (VisitedCrossingsRingIndicesB.Count == 0) return B; var missingCount = B.Count - VisitedCrossingsRingIndicesB.Count; var results = new Polygon2(missingCount); if (missingCount == 0) return results; for (int i = 0; i < B.Count; i++) { if (!VisitedCrossingsRingIndicesB.Contains(i)) results.Add(B[i]); } return results; }