#if ACAD24 using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Colors; using AcAp = Autodesk.AutoCAD.ApplicationServices; #elif BCAD using Bricscad.EditorInput; using Teigha.Geometry; using Teigha.DatabaseServices; using Teigha.Colors; #endif using System; using System.Collections.Generic; namespace Boprs { /// /// Type of the boolean operation. /// public enum BoprType { /// /// Union. /// UNITE, /// /// Intersection. /// INTERSECT, /// /// Difference. /// SUBTRACT, /// /// Exclusive or. /// EXCLUSIVE, } /// /// Boolean operation on two regions. /// public class BooleanOperation { /// /// Resulting region from the operation. /// public Region Result { get; private set; } /// /// Subdivide any intersecting edges such that there are no more edge intersections and tag their Type property. /// /// /// /// This method will empty the sortedVertices list. /// /// /// Lexico-graphically sorted vertices of the edges to subdivide. /// Processed edges. private List ProcessEdges(List sortedVertices) { // Sweepline to keep track of edges. SweepLine sweepLine = new SweepLine(); // Processed edges will be moved here. List processed = new List(); // Go through all the sorted vertices, test for intersections when appropriate and, // if needed, subdivide the edges. while (sortedVertices.Count != 0) { SweepVertex acVx = sortedVertices[0]; sortedVertices.RemoveAt(0); if (acVx.IsLeft()) { sweepLine.Add(acVx.Edge, true); SweepEdge prevEdge = sweepLine.PrevEdge(acVx.Edge); SweepEdge nextEdge = sweepLine.NextEdge(acVx.Edge); acVx.Edge.SetInsideOther(prevEdge); if (prevEdge != null) { List newVertices = acVx.Edge.TrySubdivideBy(prevEdge); foreach (SweepVertex vertex in newVertices) { Utils.InsertVertexSorted(sortedVertices, vertex); } } if (nextEdge != null) { List newVertices = acVx.Edge.TrySubdivideBy(nextEdge); foreach (SweepVertex vertex in newVertices) { Utils.InsertVertexSorted(sortedVertices, vertex); } } } else { SweepEdge prevEdge = sweepLine.PrevEdge(acVx.Edge); SweepEdge nextEdge = sweepLine.NextEdge(acVx.Edge); sweepLine.Remove(acVx.Edge); processed.Add(acVx.Edge); if (prevEdge != null && nextEdge != null) { List newVertices = prevEdge.TrySubdivideBy(nextEdge); foreach (SweepVertex vertex in newVertices) { Utils.InsertVertexSorted(sortedVertices, vertex); } } } } return processed; } /// /// Should a given edge be included in the result polygon? /// /// Edge to evaluate. /// Subject region of this operation. /// Type of the boolean operation. /// true if the edge should be included in the result, false if not. private bool IsInResult(SweepEdge edge, Region subject, BoprType boprType) { switch (edge.Type) { case EdgeType.NORMAL: switch (boprType) { case BoprType.UNITE: return !edge.InsideOther; case BoprType.INTERSECT: return edge.InsideOther; case BoprType.SUBTRACT: return (edge.ParentRegion == subject && !edge.InsideOther) || (edge.ParentRegion != subject && edge.InsideOther); case BoprType.EXCLUSIVE: return true; } break; case EdgeType.OVERLAP_SAME: return boprType == BoprType.INTERSECT || boprType == BoprType.UNITE; case EdgeType.OVERLAP_DIFFERENT: return boprType == BoprType.SUBTRACT; case EdgeType.OVERLAP_SILENT: return false; } return false; // Just to avoid compiler warning. } /// /// Build the result polygon from processed edges. /// /// Input edges. /// Subject region of this operation. /// Type of boolean operation. /// Built result region. private Region BuildResult(List edges, Region subject, BoprType boprType) { List chosenSegments = new List(); foreach(SweepEdge edge in edges) { if(IsInResult(edge, subject, boprType)) { chosenSegments.Add(new LineSegment2d(edge.LeftVertex.Point, edge.RightVertex.Point)); } } return Region.FromSegments(chosenSegments); } /// /// Compute a boolean operation on two regions. /// /// Subject region. /// Clip region. /// Boolean operation type. public BooleanOperation(Region subject, Region clip, BoprType type) { List sortedVerts = new List(); foreach (LineSegment2d seg in subject.GetSegments()) { SweepEdge edge = new SweepEdge(seg.StartPoint, seg.EndPoint); sortedVerts.Add(edge.LeftVertex); sortedVerts.Add(edge.RightVertex); } foreach (LineSegment2d seg in clip.GetSegments()) { SweepEdge edge = new SweepEdge(seg.StartPoint, seg.EndPoint); sortedVerts.Add(edge.LeftVertex); sortedVerts.Add(edge.RightVertex); } sortedVerts.Sort(); List processed = ProcessEdges(sortedVerts); Result = BuildResult(processed, subject, type); } } }