/// <summary> /// Runs the specified polygon. /// </summary> /// <param name="polygon">The polygon.</param> /// <param name="intersections">The intersections.</param> /// <param name="makeHolesPositive">if set to <c>true</c> [make holes positive].</param> /// <param name="tolerance">The tolerance.</param> /// <param name="strayHoles">The stray holes.</param> /// <returns>List<Polygon>.</returns> internal List <Polygon> Run(Polygon polygon, List <SegmentIntersection> intersections, ResultType resultType, double tolerance, List <bool> knownWrongPoints, int maxNumberOfPolygons) { var minAllowableArea = tolerance * tolerance / Constants.BaseTolerance; var interaction = new PolygonInteractionRecord(polygon, null); interaction.IntersectionData.AddRange(intersections); var delimiters = NumberVerticesAndGetPolygonVertexDelimiter(polygon); var intersectionLookup = interaction.MakeIntersectionLookupList(delimiters[^ 1]);
/// <summary> /// All of the previous boolean operations are accomplished by this function. Note that the function RemoveSelfIntersections is also /// very simliar to this function. /// </summary> /// <param name="polygonA">The polygon a.</param> /// <param name="polygonB">The polygon b.</param> /// <param name="intersections">The intersections.</param> /// <param name="isSubtract">The switch direction.</param> /// <param name="crossProductSign">The cross product sign.</param> /// <param name="tolerance">The minimum allowable area.</param> /// <returns>System.Collections.Generic.List<TVGL.TwoDimensional.Polygon>.</returns> internal List <Polygon> Run(Polygon polygonA, Polygon polygonB, PolygonInteractionRecord interaction, PolygonCollection polygonCollection, double tolerance = double.NaN) { double areaTolerance; if (double.IsNaN(tolerance)) { var minDimension = Math.Min(polygonA.MaxX - polygonA.MinX, Math.Min(polygonA.MaxY - polygonA.MinY, Math.Min(polygonB.MaxX - polygonB.MinX, polygonB.MaxY - polygonB.MinY))); tolerance = Constants.BaseTolerance * minDimension; areaTolerance = tolerance * minDimension; } else { areaTolerance = tolerance * tolerance / Constants.BaseTolerance; // why change the input tolerance? here, we are using it as a } // limit on the minimum allowable area only (about 12 lines down), so in order to change it from units of length to length-squared // we need to find the characteristic length that was multiplied by the base tolerance to obtain the linear tolerance. var delimiters = NumberVerticesAndGetPolygonVertexDelimiter(polygonA); delimiters = NumberVerticesAndGetPolygonVertexDelimiter(polygonB, delimiters[^ 1]);
/// <summary> /// Returns the list of polygons that exist in either A OR B.By providing the intersections /// between the two polygons, the operation will be performed with less time and memory. /// </summary> /// <param name="polygonA">The polygon a.</param> /// <param name="polygonB">The polygon b.</param> /// <param name="polygonInteraction">The polygon relationship.</param> /// <param name="outputAsCollectionType">Type of the output as collection.</param> /// <param name="tolerance">The minimum allowable area.</param> /// <returns>System.Collections.Generic.List<TVGL.TwoDimensional.Polygon>.</returns> /// <exception cref="ArgumentException">A negative polygon (i.e. hole) is provided to Union which results in infinite shape. - polygonA</exception> /// <exception cref="ArgumentException">A negative polygon (i.e. hole) is provided to Union which results in infinite shape. - polygonB</exception> public static List <Polygon> Union(this Polygon polygonA, Polygon polygonB, PolygonInteractionRecord polygonInteraction, PolygonCollection outputAsCollectionType = PolygonCollection.PolygonWithHoles, double tolerance = double.NaN) { if (!polygonA.IsPositive) { throw new ArgumentException("A negative polygon (i.e. hole) is provided to Union which results in infinite shape.", nameof(polygonA)); } if (!polygonB.IsPositive) { throw new ArgumentException("A negative polygon (i.e. hole) is provided to Union which results in infinite shape.", nameof(polygonB)); } if (!polygonInteraction.CoincidentEdges && (polygonInteraction.Relationship == PolygonRelationship.Separated || polygonInteraction.Relationship == PolygonRelationship.AIsInsideHoleOfB || polygonInteraction.Relationship == PolygonRelationship.BIsInsideHoleOfA)) { return new List <Polygon> { polygonA.Copy(true, false), polygonB.Copy(true, false) } } ; if (polygonInteraction.Relationship == PolygonRelationship.BInsideA || polygonInteraction.Relationship == PolygonRelationship.Equal) { return new List <Polygon> { polygonA.Copy(true, false) } } ; if (polygonInteraction.Relationship == PolygonRelationship.AInsideB) { return new List <Polygon> { polygonB.Copy(true, false) } } ; polygonUnion ??= new PolygonUnion(); return(polygonUnion.Run(polygonA, polygonB, polygonInteraction, outputAsCollectionType, tolerance)); }
/// <summary> /// Returns the list of polygons that are the Exclusive-OR of the two input polygons. Exclusive-OR are the regions where one polgyon /// resides but not both. By providing the intersections between the two polygons, the operation will be performed with less time and memory. /// </summary> /// <param name="polygonA">The polygon a.</param> /// <param name="polygonB">The polygon b.</param> /// <param name="interactionRecord">The interaction record.</param> /// <param name="outputAsCollectionType">Type of the output as collection.</param> /// <param name="tolerance">The tolerance.</param> /// <returns>System.Collections.Generic.List<TVGL.TwoDimensional.Polygon>.</returns> public static List <Polygon> ExclusiveOr(this Polygon polygonA, Polygon polygonB, PolygonInteractionRecord interactionRecord, PolygonCollection outputAsCollectionType = PolygonCollection.PolygonWithHoles, double tolerance = double.NaN) { if (interactionRecord.IntersectionWillBeEmpty()) { return new List <Polygon> { polygonA.Copy(true, false), polygonB.Copy(true, false) } } ; else if (interactionRecord.Relationship == PolygonRelationship.BInsideA && !interactionRecord.CoincidentEdges && !interactionRecord.CoincidentVertices) { var polygonACopy1 = polygonA.Copy(true, false); polygonACopy1.AddInnerPolygon(polygonB.Copy(true, true)); return(new List <Polygon> { polygonACopy1 }); } else if (interactionRecord.Relationship == PolygonRelationship.AInsideB && !interactionRecord.CoincidentEdges && !interactionRecord.CoincidentVertices) { var polygonBCopy2 = polygonB.Copy(true, false); polygonBCopy2.AddInnerPolygon(polygonA.Copy(true, true)); return(new List <Polygon> { polygonBCopy2 }); } else { var result = polygonA.Subtract(polygonB, interactionRecord, outputAsCollectionType, tolerance); result.AddRange(polygonB.Subtract(polygonA, interactionRecord, outputAsCollectionType, tolerance)); return(result); } }
/// <summary> /// Returns the list of polygons that result from A-B (subtracting polygon B from polygon A). By providing the intersections /// between the two polygons, the operation will be performed with less time and memory. /// </summary> /// <param name="minuend">The polygon a.</param> /// <param name="subtrahend">The polygon b.</param> /// <param name="interaction">The polygon relationship.</param> /// <param name="outputAsCollectionType">Type of the output as collection.</param> /// <param name="tolerance">The tolerance.</param> /// <returns>System.Collections.Generic.List<TVGL.TwoDimensional.Polygon>.</returns> /// <exception cref="ArgumentException">The minuend is already a negative polygon (i.e. hole). Consider another operation" /// +" to accomplish this function, like Intersect. - polygonA</exception> public static List <Polygon> Subtract(this Polygon minuend, Polygon subtrahend, PolygonInteractionRecord interaction, PolygonCollection outputAsCollectionType = PolygonCollection.PolygonWithHoles, double tolerance = double.NaN) { interaction = interaction.InvertPolygonInRecord(subtrahend, out var invertedPolygonB); return(Intersect(minuend, invertedPolygonB, interaction, outputAsCollectionType, tolerance)); }
/// <summary> /// Returns the list of polygons that result from the subshapes common to both A and B. By providing the intersections /// between the two polygons, the operation will be performed with less time and memory. /// </summary> /// <param name="polygonA">The polygon a.</param> /// <param name="polygonB">The polygon b.</param> /// <param name="interaction">The interaction.</param> /// <param name="outputAsCollectionType">Type of the output as collection.</param> /// <param name="tolerance">The minimum allowable area.</param> /// <returns>System.Collections.Generic.List<TVGL.TwoDimensional.Polygon>.</returns> public static List <Polygon> Intersect(this Polygon polygonA, Polygon polygonB, PolygonInteractionRecord interaction, PolygonCollection outputAsCollectionType = PolygonCollection.PolygonWithHoles, double tolerance = double.NaN) { if (interaction.IntersectionWillBeEmpty()) { if (polygonB.IsPositive) { return(new List <Polygon>()); } else { return new List <Polygon> { polygonA.Copy(true, false) } }; } else { polygonIntersection ??= new PolygonIntersection(); return(polygonIntersection.Run(polygonA, polygonB, interaction, outputAsCollectionType, tolerance)); } }