Compare commits
12 commits
Author | SHA1 | Date | |
---|---|---|---|
527abd16f4 | |||
37f4065919 | |||
b99de74993 | |||
22cd0105b7 | |||
2e57f41125 | |||
|
dff02947c8 | ||
|
75d12d6a5a | ||
|
6744f5e967 | ||
|
47d3f96b20 | ||
|
1a91a64b2d | ||
|
9719a7b549 | ||
|
157deccc57 |
10 changed files with 395 additions and 91 deletions
|
@ -191,17 +191,13 @@ namespace Boprs
|
|||
{
|
||||
List<SweepVertex> sortedVerts = new List<SweepVertex>();
|
||||
|
||||
foreach (LineSegment2d seg in subject.GetSegments())
|
||||
foreach (SweepEdge edge in subject.GetEdgeCopies())
|
||||
{
|
||||
SweepEdge edge = new SweepEdge(seg.StartPoint, seg.EndPoint);
|
||||
|
||||
sortedVerts.Add(edge.LeftVertex);
|
||||
sortedVerts.Add(edge.RightVertex);
|
||||
}
|
||||
foreach (LineSegment2d seg in clip.GetSegments())
|
||||
foreach (SweepEdge edge in clip.GetEdgeCopies())
|
||||
{
|
||||
SweepEdge edge = new SweepEdge(seg.StartPoint, seg.EndPoint);
|
||||
|
||||
sortedVerts.Add(edge.LeftVertex);
|
||||
sortedVerts.Add(edge.RightVertex);
|
||||
}
|
||||
|
|
10
Boprs.csproj
10
Boprs.csproj
|
@ -18,7 +18,7 @@
|
|||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;ACAD24</DefineConstants>
|
||||
<DefineConstants>TRACE;DEBUG;BCAD</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
@ -41,8 +41,11 @@
|
|||
<Reference Include="acmgd">
|
||||
<HintPath>..\..\..\..\..\Program Files\Autodesk\AutoCAD 2024\acmgd.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="BricscadExtensions">
|
||||
<HintPath>References\BricscadExtensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="BrxMgd">
|
||||
<HintPath>..\..\..\..\..\Program Files\Bricsys\BricsCAD V23 en_US\BrxMgd.dll</HintPath>
|
||||
<HintPath>..\..\..\..\..\Program Files\Bricsys\BricsCAD V24 en_US\BrxMgd.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
|
@ -53,12 +56,13 @@
|
|||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="TD_Mgd">
|
||||
<HintPath>..\..\..\..\..\Program Files\Bricsys\BricsCAD V23 en_US\TD_Mgd.dll</HintPath>
|
||||
<HintPath>..\..\..\..\..\Program Files\Bricsys\BricsCAD V24 en_US\TD_Mgd.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BooleanOperation.cs" />
|
||||
<Compile Include="Commands.cs" />
|
||||
<Compile Include="Contour.cs" />
|
||||
<Compile Include="Region.cs" />
|
||||
<Compile Include="SweepEdge.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
|
11
Commands.cs
11
Commands.cs
|
@ -55,6 +55,8 @@ namespace Boprs
|
|||
segs.Add(new LineSegment2d(asLine.StartPoint.To2d(), asLine.EndPoint.To2d()));
|
||||
}
|
||||
}
|
||||
|
||||
asPoly.Erase();
|
||||
}
|
||||
acTrans.Commit();
|
||||
}
|
||||
|
@ -109,7 +111,14 @@ namespace Boprs
|
|||
|
||||
BooleanOperation bopr = new BooleanOperation(subject, clip, type);
|
||||
|
||||
bopr.Result.Draw();
|
||||
List <Contour> contours = bopr.Result.GetContourCopies();
|
||||
|
||||
foreach (Contour contour in contours)
|
||||
{
|
||||
contour.Draw();
|
||||
}
|
||||
|
||||
acDoc.Editor.WriteMessage($"\nResult area: {bopr.Result.Area}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
124
Contour.cs
Normal file
124
Contour.cs
Normal file
|
@ -0,0 +1,124 @@
|
|||
#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;
|
||||
using AcAp = Bricscad.ApplicationServices;
|
||||
#endif
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Boprs
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple closed polygon.
|
||||
/// </summary>
|
||||
public class Contour : ICloneable
|
||||
{
|
||||
public object Clone()
|
||||
{
|
||||
return new Contour(new List<Point2d>(Vertices));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Vertices of the contour.
|
||||
/// </summary>
|
||||
private List<Point2d> Vertices { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Signed area of the contour.
|
||||
/// </summary>
|
||||
public double SignedArea { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Are the vertices of the contour arranged in clockwise manner?
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if the contour is clockwise, <c>false</c> if counter-clockwise.</returns>
|
||||
public bool IsClockwise { get => SignedArea < 0; }
|
||||
|
||||
/// <summary>
|
||||
/// Get a copy of the list of the vertices of this contour.
|
||||
/// </summary>
|
||||
/// <returns>List of vertices defining this region.</returns>
|
||||
public List<Point2d> GetVertexCopies()
|
||||
{
|
||||
return new List<Point2d>(Vertices);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the signed area of the contour
|
||||
/// </summary>
|
||||
private void ComputeArea()
|
||||
{
|
||||
double areaSum = 0;
|
||||
|
||||
// Go through all the vertices.
|
||||
for (int i = 0; i < Vertices.Count; i++)
|
||||
{
|
||||
// Get current vertex
|
||||
Point2d p0 = Vertices[i];
|
||||
|
||||
// Get the next vertex
|
||||
Point2d p1 = Vertices[(i + 1) % Vertices.Count];
|
||||
|
||||
// Compute the area under the trapezoid made by the current segment.
|
||||
// Note that this is actually double the proper value.
|
||||
areaSum += (p1.X - p0.X) * (p1.Y + p0.Y);
|
||||
}
|
||||
|
||||
// The above algorithm deems clockwise area to be positive,
|
||||
// however we consider ccw contours to be positive, so we flip the value.
|
||||
SignedArea = - areaSum / 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverse the orientation of the contour.
|
||||
/// </summary>
|
||||
internal void Reverse()
|
||||
{
|
||||
Vertices.Reverse();
|
||||
SignedArea *= -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public Contour(List<Point2d> vertices)
|
||||
{
|
||||
Vertices = vertices;
|
||||
ComputeArea();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
internal void Draw(Color color = null)
|
||||
{
|
||||
AcAp.Document acDoc = AcAp.Application.DocumentManager.MdiActiveDocument;
|
||||
Database acDb = acDoc.Database;
|
||||
|
||||
using (Transaction acTrans = acDb.TransactionManager.StartTransaction())
|
||||
{
|
||||
// Open the BlockTableRecord
|
||||
BlockTable acBlkTbl = (BlockTable)acTrans.GetObject(acDb.BlockTableId, OpenMode.ForRead);
|
||||
BlockTableRecord acBlkTblRec =
|
||||
(BlockTableRecord)acTrans.GetObject(acBlkTbl[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
|
||||
|
||||
for(int i = 0; i < Vertices.Count; i++)
|
||||
{
|
||||
Line asLine = new Line(Vertices[i].To3d(), Vertices[(i + 1) % Vertices.Count].To3d());
|
||||
asLine.Color = IsClockwise ? Color.FromRgb(255, 32, 32) : Color.FromRgb(32, 255, 32);
|
||||
acBlkTblRec.AppendEntity(asLine);
|
||||
acTrans.AddNewlyCreatedDBObject(asLine, true);
|
||||
}
|
||||
|
||||
acTrans.Commit();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -8,9 +8,9 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyTitle("Boprs")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("DEK")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Boprs")]
|
||||
[assembly: AssemblyCopyright("Copyright © DEK 2024")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: AssemblyVersion("1.1.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.1.0.0")]
|
||||
|
|
237
Region.cs
237
Region.cs
|
@ -21,34 +21,44 @@ namespace Boprs
|
|||
public class Region
|
||||
{
|
||||
/// <summary>
|
||||
/// Vertices belonging to this polygon.
|
||||
/// Edges belonging to this polygon.
|
||||
/// </summary>
|
||||
private List<SweepVertex> Vertices { get; }
|
||||
private List<SweepEdge> Edges { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contours making up the region.
|
||||
/// </summary>
|
||||
private List<Contour> Contours { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Area of the positive part of the region (holes subtracted).
|
||||
/// </summary>
|
||||
public double Area { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Subdivide my edges, set their inOut tags and validate their non-colinearity.
|
||||
/// </summary>
|
||||
private void ValidateEdges()
|
||||
private void SetEdges(List<SweepVertex> vertices)
|
||||
{
|
||||
// Lexico-graphically sort my vertices.
|
||||
Vertices.Sort();
|
||||
vertices.Sort();
|
||||
|
||||
// Sweepline to keep track of edges.
|
||||
SweepLine sweepLine = new SweepLine();
|
||||
|
||||
// Current number of vertices in the list.
|
||||
// Will be increased if subdivision occurs.
|
||||
int numVertices = Vertices.Count;
|
||||
// Processed edges will be moved here.
|
||||
List<SweepEdge> processed = new List<SweepEdge>();
|
||||
|
||||
// Go through all the sorted vertices, test for intersections when appropriate and,
|
||||
// if needed, subdivide the edges.
|
||||
for (int i = 0; i < numVertices; i++)
|
||||
while (vertices.Count != 0)
|
||||
{
|
||||
SweepVertex acVx = Vertices[i];
|
||||
SweepVertex acVx = vertices[0];
|
||||
vertices.RemoveAt(0);
|
||||
|
||||
if (acVx.IsLeft())
|
||||
{
|
||||
sweepLine.Add(acVx.Edge, false);
|
||||
sweepLine.Add(acVx.Edge, true);
|
||||
|
||||
SweepEdge prevEdge = sweepLine.PrevEdge(acVx.Edge);
|
||||
SweepEdge nextEdge = sweepLine.NextEdge(acVx.Edge);
|
||||
|
@ -61,8 +71,7 @@ namespace Boprs
|
|||
|
||||
foreach (SweepVertex vertex in newVertices)
|
||||
{
|
||||
Utils.InsertVertexSorted(Vertices, vertex);
|
||||
numVertices++;
|
||||
Utils.InsertVertexSorted(vertices, vertex);
|
||||
}
|
||||
}
|
||||
if (nextEdge != null)
|
||||
|
@ -71,8 +80,7 @@ namespace Boprs
|
|||
|
||||
foreach (SweepVertex vertex in newVertices)
|
||||
{
|
||||
Utils.InsertVertexSorted(Vertices, vertex);
|
||||
numVertices++;
|
||||
Utils.InsertVertexSorted(vertices, vertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -82,6 +90,7 @@ namespace Boprs
|
|||
SweepEdge nextEdge = sweepLine.NextEdge(acVx.Edge);
|
||||
|
||||
sweepLine.Remove(acVx.Edge);
|
||||
processed.Add(acVx.Edge);
|
||||
|
||||
if (prevEdge != null && nextEdge != null)
|
||||
{
|
||||
|
@ -89,32 +98,163 @@ namespace Boprs
|
|||
|
||||
foreach (SweepVertex vertex in newVertices)
|
||||
{
|
||||
Utils.InsertVertexSorted(Vertices, vertex);
|
||||
numVertices++;
|
||||
Utils.InsertVertexSorted(vertices, vertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Edges = processed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the index of an un-processed vertex with the same position as the one on specified index.
|
||||
/// </summary>
|
||||
/// <param name="pos">Index of the current vertex.</param>
|
||||
/// <param name="vertices">List of vertices.</param>
|
||||
/// <param name="processed">Mask for processed vertices.</param>
|
||||
/// <returns>Index of an unprocessed neighbour with the same position.</returns>
|
||||
private int NextPos(int pos, List<SweepVertex> vertices, bool[] processed)
|
||||
{
|
||||
int newPos = pos + 1;
|
||||
while(newPos < vertices.Count && Utils.PointEquals(vertices[pos].Point, vertices[newPos].Point))
|
||||
{
|
||||
if (!processed[newPos])
|
||||
{
|
||||
return newPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
newPos++;
|
||||
}
|
||||
}
|
||||
newPos = pos - 1;
|
||||
while (newPos >= 0 && Utils.PointEquals(vertices[pos].Point, vertices[newPos].Point))
|
||||
{
|
||||
if (!processed[newPos])
|
||||
{
|
||||
return newPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
newPos--;
|
||||
}
|
||||
}
|
||||
throw new Exception("Hit contour dead end (non-connected edge).");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute my closed contours.
|
||||
/// </summary>
|
||||
private void ComputeContours()
|
||||
{
|
||||
// Gather all vertices of the region.
|
||||
List<SweepVertex> vertices = new List<SweepVertex>();
|
||||
foreach (SweepEdge edge in Edges)
|
||||
{
|
||||
vertices.Add(edge.LeftVertex);
|
||||
vertices.Add(edge.RightVertex);
|
||||
}
|
||||
|
||||
// Lexico-graphically sort the vertices.
|
||||
vertices.Sort();
|
||||
|
||||
bool[] processed = new bool[vertices.Count];
|
||||
List<Contour> contours = new List<Contour>();
|
||||
|
||||
for(int i = 0; i < vertices.Count; i++)
|
||||
{
|
||||
// If we already traversed this vertex, skip it.
|
||||
if (processed[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise this is an edge on an indiscovered contour, create it.
|
||||
|
||||
// acVx should be guaranteed to be the lowest and leftest vertex of the new polygon.
|
||||
// Thus it cannot be vertical.
|
||||
// if it is transition inside, it is a positive contour and should wind counter-clockwise,
|
||||
// if it is transition outside, it is a negative contour and should wind clockwise.
|
||||
SweepVertex acVx = vertices[i];
|
||||
bool shouldBeCW = !acVx.Edge.TransitionInside;
|
||||
|
||||
// Traverse connected edges, and mark taversed vertices as processed,
|
||||
// until we loop back to the first discovered vertex on the contour.
|
||||
int pos = i;
|
||||
processed[i] = true;
|
||||
Point2d target = acVx.Point;
|
||||
List<Point2d> contourVertices = new List<Point2d>() { vertices[pos].Point };
|
||||
while (!Utils.PointEquals(vertices[pos].OtherVertex().Point, target))
|
||||
{
|
||||
int otherPos = vertices.IndexOf(vertices[pos].OtherVertex());
|
||||
pos = NextPos(otherPos, vertices, processed);
|
||||
|
||||
processed[pos] = true;
|
||||
processed[otherPos] = true;
|
||||
|
||||
contourVertices.Add(vertices[pos].Point);
|
||||
}
|
||||
processed[vertices.IndexOf(vertices[pos].OtherVertex())] = true;
|
||||
|
||||
// Instantiate the contour object from the found vertices.
|
||||
Contour contour = new Contour(contourVertices);
|
||||
contours.Add(contour);
|
||||
|
||||
// If the contour is a hole and winds ccw, or positive and winds cw, flip it.
|
||||
if (shouldBeCW != contour.IsClockwise)
|
||||
{
|
||||
contour.Reverse();
|
||||
}
|
||||
}
|
||||
Contours = contours;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the area of the region.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Requires contours to be computed.
|
||||
/// </remarks>
|
||||
private void ComputeArea()
|
||||
{
|
||||
Area = 0;
|
||||
foreach(Contour contour in Contours)
|
||||
{
|
||||
Area += contour.SignedArea;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a copy of the regions vertex list.
|
||||
/// Get a copy of the regions edges list.
|
||||
/// </summary>
|
||||
/// <returns>Copy of the regions vertex list.</returns>
|
||||
internal List<LineSegment2d> GetSegments()
|
||||
/// <returns>Copy of the regions edges list.</returns>
|
||||
internal List<SweepEdge> GetEdgeCopies()
|
||||
{
|
||||
List <LineSegment2d> segments = new List<LineSegment2d>();
|
||||
List<SweepEdge> copies = new List<SweepEdge>();
|
||||
|
||||
foreach(SweepVertex sweepVertex in Vertices)
|
||||
foreach (SweepEdge edge in Edges)
|
||||
{
|
||||
if (sweepVertex.IsLeft())
|
||||
{
|
||||
segments.Add(
|
||||
new LineSegment2d(sweepVertex.Edge.LeftVertex.Point, sweepVertex.Edge.RightVertex.Point));
|
||||
}
|
||||
copies.Add((SweepEdge)edge.Clone());
|
||||
}
|
||||
|
||||
return segments;
|
||||
return copies;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a copy of the contours of the polygon.
|
||||
/// </summary>
|
||||
/// <returns>List of copies of the regions contours.</returns>
|
||||
public List<Contour> GetContourCopies()
|
||||
{
|
||||
List<Contour> copies = new List<Contour>();
|
||||
|
||||
foreach (Contour contour in Contours)
|
||||
{
|
||||
copies.Add((Contour)contour.Clone());
|
||||
}
|
||||
|
||||
return copies;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -126,50 +266,21 @@ namespace Boprs
|
|||
{
|
||||
Region region = new Region();
|
||||
|
||||
List<SweepVertex> vertices = new List<SweepVertex>();
|
||||
|
||||
foreach(LineSegment2d segment in segments)
|
||||
{
|
||||
SweepEdge newEdge = new SweepEdge(segment.StartPoint, segment.EndPoint);
|
||||
region.Vertices.Add(newEdge.LeftVertex);
|
||||
region.Vertices.Add(newEdge.RightVertex);
|
||||
vertices.Add(newEdge.LeftVertex);
|
||||
vertices.Add(newEdge.RightVertex);
|
||||
newEdge.ParentRegion = region;
|
||||
}
|
||||
|
||||
region.ValidateEdges();
|
||||
region.SetEdges(vertices);
|
||||
region.ComputeContours();
|
||||
region.ComputeArea();
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
private Region()
|
||||
{
|
||||
Vertices = new List<SweepVertex>();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
internal void Draw()
|
||||
{
|
||||
Erase();
|
||||
|
||||
foreach (SweepVertex vert in Vertices)
|
||||
{
|
||||
if (vert.IsLeft())
|
||||
{
|
||||
vert.Edge.Draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
internal void Erase()
|
||||
{
|
||||
foreach (SweepVertex vert in Vertices)
|
||||
{
|
||||
if (vert.IsLeft())
|
||||
{
|
||||
vert.Edge.Erase();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
30
SweepEdge.cs
30
SweepEdge.cs
|
@ -44,7 +44,7 @@ namespace Boprs
|
|||
/// <summary>
|
||||
/// Line segment (edge) used while a sweep line is processing a boolean operation.
|
||||
/// </summary>
|
||||
internal class SweepEdge
|
||||
internal class SweepEdge : ICloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// String representation of the edge.
|
||||
|
@ -54,6 +54,20 @@ namespace Boprs
|
|||
return ($"({LeftVertex} -- {RightVertex})");
|
||||
}
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
SweepVertex left = (SweepVertex)LeftVertex.Clone();
|
||||
SweepVertex right = (SweepVertex)RightVertex.Clone();
|
||||
SweepEdge clone = new SweepEdge(LeftVertex, RightVertex)
|
||||
{
|
||||
TransitionInside = TransitionInside,
|
||||
InsideOther = InsideOther,
|
||||
Type = Type,
|
||||
ParentRegion = ParentRegion,
|
||||
};
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Comparison of edges.
|
||||
/// </summary>
|
||||
|
@ -221,13 +235,13 @@ namespace Boprs
|
|||
Point2d intPt = intersector.GetIntersectionPoint(0);
|
||||
|
||||
// If the point is inside of either edge (not on its end point), subdivide the edge.
|
||||
if (!(Utils.DoubleEquals(intPt.GetDistanceTo(LeftVertex.Point), 0) ||
|
||||
Utils.DoubleEquals(intPt.GetDistanceTo(RightVertex.Point), 0)))
|
||||
if (!(Utils.PointEquals(intPt, LeftVertex.Point) ||
|
||||
Utils.PointEquals(intPt, RightVertex.Point)))
|
||||
{
|
||||
newVertices.AddRange(SubdivideAt(intPt));
|
||||
}
|
||||
if (!(Utils.DoubleEquals(intPt.GetDistanceTo(otherEdge.LeftVertex.Point), 0) ||
|
||||
Utils.DoubleEquals(intPt.GetDistanceTo(otherEdge.RightVertex.Point), 0)))
|
||||
if (!(Utils.PointEquals(intPt, otherEdge.LeftVertex.Point) ||
|
||||
Utils.PointEquals(intPt, otherEdge.RightVertex.Point)))
|
||||
{
|
||||
newVertices.AddRange(otherEdge.SubdivideAt(intPt));
|
||||
}
|
||||
|
@ -242,14 +256,14 @@ namespace Boprs
|
|||
List<SweepVertex> newVertices = new List<SweepVertex>();
|
||||
|
||||
// The edges share the left vertex
|
||||
if (Utils.DoubleEquals(LeftVertex.Point.GetDistanceTo(otherEdge.LeftVertex.Point), 0))
|
||||
if (Utils.PointEquals(LeftVertex.Point, otherEdge.LeftVertex.Point))
|
||||
{
|
||||
EdgeType et = (TransitionInside == otherEdge.TransitionInside) ?
|
||||
EdgeType.OVERLAP_SAME : EdgeType.OVERLAP_DIFFERENT;
|
||||
|
||||
// The edges share the right vertex as well, set the edge type for both this and the other
|
||||
// edge and return an empty list.
|
||||
if (Utils.DoubleEquals(RightVertex.Point.GetDistanceTo(otherEdge.RightVertex.Point), 0))
|
||||
if (Utils.PointEquals(RightVertex.Point, otherEdge.RightVertex.Point))
|
||||
{
|
||||
Type = et;
|
||||
otherEdge.Type = EdgeType.OVERLAP_SILENT;
|
||||
|
@ -295,7 +309,7 @@ namespace Boprs
|
|||
/// <param name="pt2">EndPoint 2.</param>
|
||||
internal SweepEdge(Point2d pt1, Point2d pt2)
|
||||
{
|
||||
if (Utils.DoubleEquals(pt1.GetDistanceTo(pt2), 0))
|
||||
if (Utils.PointEquals(pt1, pt2))
|
||||
{
|
||||
throw new ArgumentException("Edge end points cannot be the same.");
|
||||
}
|
||||
|
|
21
SweepLine.cs
21
SweepLine.cs
|
@ -77,6 +77,27 @@ namespace Boprs
|
|||
IntersectingEdges.Remove(edge);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all edges on the sweepline below a given edge.
|
||||
/// </summary>
|
||||
/// <param name="curr">Current edge.</param>
|
||||
/// <returns>From lowest to highest.</returns>
|
||||
internal List<SweepEdge> AllBefore(SweepEdge curr)
|
||||
{
|
||||
List<SweepEdge> foundEdges = new List<SweepEdge>();
|
||||
|
||||
// Get the index of the current edge
|
||||
int currIdx = IntersectingEdges.IndexOf(curr);
|
||||
|
||||
// Add all the previous edges to the list
|
||||
for(int i = 0; i < currIdx; i++)
|
||||
{
|
||||
foundEdges.Add(IntersectingEdges[i]);
|
||||
}
|
||||
|
||||
return foundEdges;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the edge below curr, or null if curr is the lowest.
|
||||
/// </summary>
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace Boprs
|
|||
/// <summary>
|
||||
/// End point of an edge used while sweep line is processing a boolean operation.
|
||||
/// </summary>
|
||||
internal class SweepVertex : IComparable
|
||||
internal class SweepVertex : IComparable, ICloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// String representation of the vertex.
|
||||
|
@ -28,6 +28,11 @@ namespace Boprs
|
|||
return ($"({Point.X}, {Point.Y})");
|
||||
}
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return new SweepVertex(Point) { Edge = Edge };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Comparison of vertices.
|
||||
/// </summary>
|
||||
|
@ -114,6 +119,15 @@ namespace Boprs
|
|||
return this == Edge.LeftVertex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the other vertex associated with my edge.
|
||||
/// </summary>
|
||||
/// <returns>Other vertex of my edge.</returns>
|
||||
internal SweepVertex OtherVertex()
|
||||
{
|
||||
return IsLeft() ? Edge.RightVertex : Edge.LeftVertex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
|
|
11
Utils.cs
11
Utils.cs
|
@ -38,6 +38,17 @@ namespace Boprs
|
|||
return (pt1.X - pt3.X) * (pt2.Y - pt3.Y) - (pt2.X - pt3.X) * (pt1.Y - pt3.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Are the points at roughly the same position?
|
||||
/// </summary>
|
||||
/// <param name="p1">First point to compare.</param>
|
||||
/// <param name="p2">Second point to compare.</param>
|
||||
/// <returns><c>true</c> if the points represent the same position, <c>false</c> if not.</returns>
|
||||
internal static bool PointEquals(Point2d p1, Point2d p2)
|
||||
{
|
||||
return DoubleEquals(p1.X, p2.X) && DoubleEquals(p1.Y, p2.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Are the two doubles close enough to be almost equal?
|
||||
/// </summary>
|
||||
|
|
Loading…
Reference in a new issue