#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);
}
}
}