|
27 | 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
28 | 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
29 | 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | | - */ |
31 | | - |
32 | | -/// Changes from the Java version |
33 | | -/// attributification |
34 | | -/// Future possibilities |
35 | | -/// Flattening out the number of indirections |
36 | | -/// Replacing arrays of 3 with fixed-length arrays? |
37 | | -/// Replacing bool[3] with a bit array of some sort? |
38 | | -/// Bundling everything into an AoS mess? |
39 | | -/// Hardcode them all as ABC ? |
40 | | - |
41 | | -using System; |
42 | | -using System.Diagnostics; |
43 | | -using System.Collections.Generic; |
44 | | - |
45 | | -namespace Poly2Tri { |
46 | | -public class DelaunayTriangle { |
47 | | -public FixedArray3<TriangulationPoint> Points; |
48 | | -public FixedArray3<DelaunayTriangle > Neighbors; |
49 | | -public FixedBitArray3 EdgeIsConstrained, EdgeIsDelaunay; |
50 | | -public bool IsInterior { get; set; } |
51 | | - |
52 | | -public DelaunayTriangle(TriangulationPoint p1, TriangulationPoint p2, TriangulationPoint p3) { |
53 | | -Points[0] = p1; |
54 | | -Points[1] = p2; |
55 | | -Points[2] = p3; |
56 | | -} |
57 | | - |
58 | | -public int IndexOf(TriangulationPoint p) { |
59 | | -int i = Points.IndexOf(p); |
60 | | -if (i==-1) throw new Exception("Calling index with a point that doesn't exist in triangle"); |
61 | | -return i; |
62 | | -} |
63 | | - |
64 | | -public int IndexCWFrom (TriangulationPoint p) { return (IndexOf(p)+2)%3; } |
65 | | -public int IndexCCWFrom(TriangulationPoint p) { return (IndexOf(p)+1)%3; } |
66 | | - |
67 | | -public bool Contains(TriangulationPoint p) { return Points.Contains(p); } |
68 | | - |
69 | | -/// <summary> |
70 | | -/// Update neighbor pointers |
71 | | -/// </summary> |
72 | | -/// <param name="p1">Point 1 of the shared edge</param> |
73 | | -/// <param name="p2">Point 2 of the shared edge</param> |
74 | | -/// <param name="t">This triangle's new neighbor</param> |
75 | | -private void MarkNeighbor( TriangulationPoint p1, TriangulationPoint p2, DelaunayTriangle t ) { |
76 | | -int i = EdgeIndex(p1,p2); |
77 | | -if ( i==-1 ) throw new Exception( "Error marking neighbors -- t doesn't contain edge p1-p2!" ); |
78 | | -Neighbors[i] = t; |
79 | | -} |
80 | | - |
81 | | -/// <summary> |
82 | | -/// Exhaustive search to update neighbor pointers |
83 | | -/// </summary> |
84 | | -public void MarkNeighbor( DelaunayTriangle t ) { |
85 | | -// Points of this triangle also belonging to t |
86 | | -bool a = t.Contains(Points[0]); |
87 | | -bool b = t.Contains(Points[1]); |
88 | | -bool c = t.Contains(Points[2]); |
89 | | - |
90 | | -if (b&&c) { Neighbors[0]=t; t.MarkNeighbor(Points[1],Points[2],this); } |
91 | | -else if (a&&c) { Neighbors[1]=t; t.MarkNeighbor(Points[0],Points[2],this); } |
92 | | -else if (a&&b) { Neighbors[2]=t; t.MarkNeighbor(Points[0],Points[1],this); } |
93 | | -else throw new Exception( "Failed to mark neighbor, doesn't share an edge!"); |
94 | | -} |
95 | | - |
96 | | -/// <param name="t">Opposite triangle</param> |
97 | | -/// <param name="p">The point in t that isn't shared between the triangles</param> |
98 | | -public TriangulationPoint OppositePoint(DelaunayTriangle t, TriangulationPoint p) { |
99 | | -Debug.Assert(t != this, "self-pointer error"); |
100 | | -return PointCWFrom(t.PointCWFrom(p)); |
101 | | -} |
102 | | - |
103 | | -public DelaunayTriangle NeighborCWFrom (TriangulationPoint point) { return Neighbors[(Points.IndexOf(point)+1)%3]; } |
104 | | -public DelaunayTriangle NeighborCCWFrom (TriangulationPoint point) { return Neighbors[(Points.IndexOf(point)+2)%3]; } |
105 | | -public DelaunayTriangle NeighborAcrossFrom(TriangulationPoint point) { return Neighbors[ Points.IndexOf(point) ]; } |
106 | | - |
107 | | -public TriangulationPoint PointCCWFrom(TriangulationPoint point) { return Points[(IndexOf(point)+1)%3]; } |
108 | | -public TriangulationPoint PointCWFrom (TriangulationPoint point) { return Points[(IndexOf(point)+2)%3]; } |
109 | | - |
110 | | -private void RotateCW() { |
111 | | -var t = Points[2]; |
112 | | -Points[2] = Points[1]; |
113 | | -Points[1] = Points[0]; |
114 | | -Points[0] = t; |
115 | | -} |
116 | | - |
117 | | -/// <summary> |
118 | | -/// Legalize triangle by rotating clockwise around oPoint |
119 | | -/// </summary> |
120 | | -/// <param name="oPoint">The origin point to rotate around</param> |
121 | | -/// <param name="nPoint">???</param> |
122 | | -public void Legalize(TriangulationPoint oPoint, TriangulationPoint nPoint) { |
123 | | -RotateCW(); |
124 | | -Points[IndexCCWFrom(oPoint)] = nPoint; |
125 | | -} |
126 | | - |
127 | | -public override string ToString() { return Points[0] + "," + Points[1] + "," + Points[2]; } |
128 | | - |
129 | | -/// <summary> |
130 | | -/// Finalize edge marking |
131 | | -/// </summary> |
132 | | -public void MarkNeighborEdges() { |
133 | | -for (int i = 0; i < 3; i++) if ( EdgeIsConstrained[i] && Neighbors[i] != null ) { |
134 | | -Neighbors[i].MarkConstrainedEdge(Points[(i+1)%3], Points[(i+2)%3]); |
135 | | -} |
136 | | -} |
137 | | - |
138 | | -public void MarkEdge(DelaunayTriangle triangle) { |
139 | | -for (int i = 0; i < 3; i++) if ( EdgeIsConstrained[i] ) { |
140 | | -triangle.MarkConstrainedEdge(Points[(i+1)%3], Points[(i+2)%3]); |
141 | | -} |
142 | | -} |
143 | | - |
144 | | -public void MarkEdge(List<DelaunayTriangle> tList) { |
145 | | -foreach ( DelaunayTriangle t in tList ) |
146 | | -for ( int i = 0; i < 3; i++ ) |
147 | | -if ( t.EdgeIsConstrained[i] ) |
148 | | -{ |
149 | | -MarkConstrainedEdge( t.Points[(i+1)%3], t.Points[(i+2)%3] ); |
150 | | -} |
151 | | -} |
152 | | - |
153 | | -public void MarkConstrainedEdge(int index) { |
154 | | -EdgeIsConstrained[index] = true; |
155 | | -} |
156 | | - |
157 | | -public void MarkConstrainedEdge(DTSweepConstraint edge) { |
158 | | -MarkConstrainedEdge(edge.P, edge.Q); |
159 | | -} |
160 | | - |
161 | | -/// <summary> |
162 | | -/// Mark edge as constrained |
163 | | -/// </summary> |
164 | | -public void MarkConstrainedEdge(TriangulationPoint p, TriangulationPoint q) { |
165 | | -int i = EdgeIndex(p,q); |
166 | | -if ( i != -1 ) EdgeIsConstrained[i] = true; |
167 | | -} |
168 | | - |
169 | | -public double Area() { |
170 | | -double b = Points[0].X - Points[1].X; |
171 | | -double h = Points[2].Y - Points[1].Y; |
172 | | - |
173 | | -return Math.Abs((b * h * 0.5f)); |
174 | | -} |
175 | | - |
176 | | -public TriangulationPoint Centroid() { |
177 | | -double cx = (Points[0].X + Points[1].X + Points[2].X) / 3f; |
178 | | -double cy = (Points[0].Y + Points[1].Y + Points[2].Y) / 3f; |
179 | | -return new TriangulationPoint(cx, cy); |
180 | | -} |
181 | | - |
182 | | -/// <summary> |
183 | | -/// Get the index of the neighbor that shares this edge (or -1 if it isn't shared) |
184 | | -/// </summary> |
185 | | -/// <returns>index of the shared edge or -1 if edge isn't shared</returns> |
186 | | -public int EdgeIndex(TriangulationPoint p1, TriangulationPoint p2) { |
187 | | -int i1 = Points.IndexOf(p1); |
188 | | -int i2 = Points.IndexOf(p2); |
189 | | - |
190 | | -// Points of this triangle in the edge p1-p2 |
191 | | -bool a = (i1==0 || i2==0); |
192 | | -bool b = (i1==1 || i2==1); |
193 | | -bool c = (i1==2 || i2==2); |
194 | | - |
195 | | -if (b&&c) return 0; |
196 | | -if (a&&c) return 1; |
197 | | -if (a&&b) return 2; |
198 | | -return -1; |
199 | | -} |
200 | | - |
201 | | -public bool GetConstrainedEdgeCCW ( TriangulationPoint p ) { return EdgeIsConstrained[(IndexOf(p)+2)%3]; } |
202 | | -public bool GetConstrainedEdgeCW ( TriangulationPoint p ) { return EdgeIsConstrained[(IndexOf(p)+1)%3]; } |
203 | | -public bool GetConstrainedEdgeAcross( TriangulationPoint p ) { return EdgeIsConstrained[ IndexOf(p) ]; } |
204 | | -public void SetConstrainedEdgeCCW ( TriangulationPoint p, bool ce ) { EdgeIsConstrained[(IndexOf(p)+2)%3] = ce; } |
205 | | -public void SetConstrainedEdgeCW ( TriangulationPoint p, bool ce ) { EdgeIsConstrained[(IndexOf(p)+1)%3] = ce; } |
206 | | -public void SetConstrainedEdgeAcross( TriangulationPoint p, bool ce ) { EdgeIsConstrained[ IndexOf(p) ] = ce; } |
207 | | - |
208 | | -public bool GetDelaunayEdgeCCW ( TriangulationPoint p ) { return EdgeIsDelaunay[(IndexOf(p)+2)%3]; } |
209 | | -public bool GetDelaunayEdgeCW ( TriangulationPoint p ) { return EdgeIsDelaunay[(IndexOf(p)+1)%3]; } |
210 | | -public bool GetDelaunayEdgeAcross( TriangulationPoint p ) { return EdgeIsDelaunay[ IndexOf(p) ]; } |
211 | | -public void SetDelaunayEdgeCCW ( TriangulationPoint p, bool ce ) { EdgeIsDelaunay[(IndexOf(p)+2)%3] = ce; } |
212 | | -public void SetDelaunayEdgeCW ( TriangulationPoint p, bool ce ) { EdgeIsDelaunay[(IndexOf(p)+1)%3] = ce; } |
213 | | -public void SetDelaunayEdgeAcross( TriangulationPoint p, bool ce ) { EdgeIsDelaunay[ IndexOf(p) ] = ce; } |
214 | | -} |
215 | | -} |
| 30 | + */ |
| 31 | + |
| 32 | +/// Changes from the Java version |
| 33 | +/// attributification |
| 34 | +/// Future possibilities |
| 35 | +/// Flattening out the number of indirections |
| 36 | +/// Replacing arrays of 3 with fixed-length arrays? |
| 37 | +/// Replacing bool[3] with a bit array of some sort? |
| 38 | +/// Bundling everything into an AoS mess? |
| 39 | +/// Hardcode them all as ABC ? |
| 40 | + |
| 41 | +using System; |
| 42 | +using System.Diagnostics; |
| 43 | +using System.Collections.Generic; |
| 44 | + |
| 45 | +namespace Poly2Tri |
| 46 | +{ |
| 47 | + public class DelaunayTriangle |
| 48 | + { |
| 49 | + public FixedArray3<TriangulationPoint> Points; |
| 50 | + public FixedArray3<DelaunayTriangle> Neighbors; |
| 51 | + public FixedBitArray3 EdgeIsConstrained, EdgeIsDelaunay; |
| 52 | + public bool IsInterior { get; set; } |
| 53 | + public DelaunayTriangle(TriangulationPoint p1, TriangulationPoint p2, TriangulationPoint p3) |
| 54 | + { |
| 55 | + Points[0] = p1; |
| 56 | + Points[1] = p2; |
| 57 | + Points[2] = p3; |
| 58 | + } |
| 59 | + public int IndexOf(TriangulationPoint p) |
| 60 | + { |
| 61 | + int i = Points.IndexOf(p); |
| 62 | + if (i == -1) throw new Exception("Calling index with a point that doesn't exist in triangle"); |
| 63 | + return i; |
| 64 | + } |
| 65 | + |
| 66 | + public int IndexCWFrom(TriangulationPoint p) { return (IndexOf(p) + 2) % 3; } |
| 67 | + public int IndexCCWFrom(TriangulationPoint p) { return (IndexOf(p) + 1) % 3; } |
| 68 | + |
| 69 | + public bool Contains(TriangulationPoint p) { return Points.Contains(p); } |
| 70 | + |
| 71 | + /// <summary> |
| 72 | + /// Update neighbor pointers |
| 73 | + /// </summary> |
| 74 | + /// <param name="p1">Point 1 of the shared edge</param> |
| 75 | + /// <param name="p2">Point 2 of the shared edge</param> |
| 76 | + /// <param name="t">This triangle's new neighbor</param> |
| 77 | + private void MarkNeighbor(TriangulationPoint p1, TriangulationPoint p2, DelaunayTriangle t) |
| 78 | + { |
| 79 | + int i = EdgeIndex(p1, p2); |
| 80 | + if (i == -1) throw new Exception("Error marking neighbors -- t doesn't contain edge p1-p2!"); |
| 81 | + Neighbors[i] = t; |
| 82 | + } |
| 83 | + |
| 84 | + /// <summary> |
| 85 | + /// Exhaustive search to update neighbor pointers |
| 86 | + /// </summary> |
| 87 | + public void MarkNeighbor(DelaunayTriangle t) |
| 88 | + { |
| 89 | + // Points of this triangle also belonging to t |
| 90 | + bool a = t.Contains(Points[0]); |
| 91 | + bool b = t.Contains(Points[1]); |
| 92 | + bool c = t.Contains(Points[2]); |
| 93 | + |
| 94 | + if (b && c) { Neighbors[0] = t; t.MarkNeighbor(Points[1], Points[2], this); } |
| 95 | + else if (a && c) { Neighbors[1] = t; t.MarkNeighbor(Points[0], Points[2], this); } |
| 96 | + else if (a && b) { Neighbors[2] = t; t.MarkNeighbor(Points[0], Points[1], this); } |
| 97 | + else throw new Exception("Failed to mark neighbor, doesn't share an edge!"); |
| 98 | + } |
| 99 | + |
| 100 | + /// <param name="t">Opposite triangle</param> |
| 101 | + /// <param name="p">The point in t that isn't shared between the triangles</param> |
| 102 | + public TriangulationPoint OppositePoint(DelaunayTriangle t, TriangulationPoint p) |
| 103 | + { |
| 104 | + Debug.Assert(t != this, "self-pointer error"); |
| 105 | + return PointCWFrom(t.PointCWFrom(p)); |
| 106 | + } |
| 107 | + |
| 108 | + public DelaunayTriangle NeighborCWFrom(TriangulationPoint point) { return Neighbors[(Points.IndexOf(point) + 1) % 3]; } |
| 109 | + public DelaunayTriangle NeighborCCWFrom(TriangulationPoint point) { return Neighbors[(Points.IndexOf(point) + 2) % 3]; } |
| 110 | + public DelaunayTriangle NeighborAcrossFrom(TriangulationPoint point) { return Neighbors[Points.IndexOf(point)]; } |
| 111 | + |
| 112 | + public TriangulationPoint PointCCWFrom(TriangulationPoint point) { return Points[(IndexOf(point) + 1) % 3]; } |
| 113 | + public TriangulationPoint PointCWFrom(TriangulationPoint point) { return Points[(IndexOf(point) + 2) % 3]; } |
| 114 | + |
| 115 | + private void RotateCW() |
| 116 | + { |
| 117 | + var t = Points[2]; |
| 118 | + Points[2] = Points[1]; |
| 119 | + Points[1] = Points[0]; |
| 120 | + Points[0] = t; |
| 121 | + } |
| 122 | + |
| 123 | + /// <summary> |
| 124 | + /// Legalize triangle by rotating clockwise around oPoint |
| 125 | + /// </summary> |
| 126 | + /// <param name="oPoint">The origin point to rotate around</param> |
| 127 | + /// <param name="nPoint">???</param> |
| 128 | + public void Legalize(TriangulationPoint oPoint, TriangulationPoint nPoint) |
| 129 | + { |
| 130 | + RotateCW(); |
| 131 | + Points[IndexCCWFrom(oPoint)] = nPoint; |
| 132 | + } |
| 133 | + |
| 134 | + public override string ToString() { return Points[0] + "," + Points[1] + "," + Points[2]; } |
| 135 | + |
| 136 | + /// <summary> |
| 137 | + /// Finalize edge marking |
| 138 | + /// </summary> |
| 139 | + public void MarkNeighborEdges() |
| 140 | + { |
| 141 | + for (int i = 0; i < 3; i++) if (EdgeIsConstrained[i] && Neighbors[i] != null) |
| 142 | + { |
| 143 | + Neighbors[i].MarkConstrainedEdge(Points[(i + 1) % 3], Points[(i + 2) % 3]); |
| 144 | + } |
| 145 | + } |
| 146 | + |
| 147 | + public void MarkEdge(DelaunayTriangle triangle) |
| 148 | + { |
| 149 | + for (int i = 0; i < 3; i++) if (EdgeIsConstrained[i]) |
| 150 | + { |
| 151 | + triangle.MarkConstrainedEdge(Points[(i + 1) % 3], Points[(i + 2) % 3]); |
| 152 | + } |
| 153 | + } |
| 154 | + |
| 155 | + public void MarkEdge(List<DelaunayTriangle> tList) |
| 156 | + { |
| 157 | + foreach (DelaunayTriangle t in tList) |
| 158 | + for (int i = 0; i < 3; i++) |
| 159 | + if (t.EdgeIsConstrained[i]) |
| 160 | + { |
| 161 | + MarkConstrainedEdge(t.Points[(i + 1) % 3], t.Points[(i + 2) % 3]); |
| 162 | + } |
| 163 | + } |
| 164 | + |
| 165 | + public void MarkConstrainedEdge(int index) |
| 166 | + { |
| 167 | + EdgeIsConstrained[index] = true; |
| 168 | + } |
| 169 | + |
| 170 | + public void MarkConstrainedEdge(DTSweepConstraint edge) |
| 171 | + { |
| 172 | + MarkConstrainedEdge(edge.P, edge.Q); |
| 173 | + } |
| 174 | + |
| 175 | + /// <summary> |
| 176 | + /// Mark edge as constrained |
| 177 | + /// </summary> |
| 178 | + public void MarkConstrainedEdge(TriangulationPoint p, TriangulationPoint q) |
| 179 | + { |
| 180 | + int i = EdgeIndex(p, q); |
| 181 | + if (i != -1) EdgeIsConstrained[i] = true; |
| 182 | + } |
| 183 | + |
| 184 | + public double Area() |
| 185 | + { |
| 186 | + double b = Points[0].X - Points[1].X; |
| 187 | + double h = Points[2].Y - Points[1].Y; |
| 188 | + |
| 189 | + return Math.Abs((b * h * 0.5f)); |
| 190 | + } |
| 191 | + |
| 192 | + public TriangulationPoint Centroid() |
| 193 | + { |
| 194 | + double cx = (Points[0].X + Points[1].X + Points[2].X) / 3f; |
| 195 | + double cy = (Points[0].Y + Points[1].Y + Points[2].Y) / 3f; |
| 196 | + return new TriangulationPoint(cx, cy); |
| 197 | + } |
| 198 | + |
| 199 | + /// <summary> |
| 200 | + /// Get the index of the neighbor that shares this edge (or -1 if it isn't shared) |
| 201 | + /// </summary> |
| 202 | + /// <returns>index of the shared edge or -1 if edge isn't shared</returns> |
| 203 | + public int EdgeIndex(TriangulationPoint p1, TriangulationPoint p2) |
| 204 | + { |
| 205 | + int i1 = Points.IndexOf(p1); |
| 206 | + int i2 = Points.IndexOf(p2); |
| 207 | + |
| 208 | + // Points of this triangle in the edge p1-p2 |
| 209 | + bool a = (i1 == 0 || i2 == 0); |
| 210 | + bool b = (i1 == 1 || i2 == 1); |
| 211 | + bool c = (i1 == 2 || i2 == 2); |
| 212 | + |
| 213 | + if (b && c) return 0; |
| 214 | + if (a && c) return 1; |
| 215 | + if (a && b) return 2; |
| 216 | + return -1; |
| 217 | + } |
| 218 | + |
| 219 | + public bool GetConstrainedEdgeCCW(TriangulationPoint p) { return EdgeIsConstrained[(IndexOf(p) + 2) % 3]; } |
| 220 | + public bool GetConstrainedEdgeCW(TriangulationPoint p) { return EdgeIsConstrained[(IndexOf(p) + 1) % 3]; } |
| 221 | + public bool GetConstrainedEdgeAcross(TriangulationPoint p) { return EdgeIsConstrained[IndexOf(p)]; } |
| 222 | + public void SetConstrainedEdgeCCW(TriangulationPoint p, bool ce) { EdgeIsConstrained[(IndexOf(p) + 2) % 3] = ce; } |
| 223 | + public void SetConstrainedEdgeCW(TriangulationPoint p, bool ce) { EdgeIsConstrained[(IndexOf(p) + 1) % 3] = ce; } |
| 224 | + public void SetConstrainedEdgeAcross(TriangulationPoint p, bool ce) { EdgeIsConstrained[IndexOf(p)] = ce; } |
| 225 | + |
| 226 | + public bool GetDelaunayEdgeCCW(TriangulationPoint p) { return EdgeIsDelaunay[(IndexOf(p) + 2) % 3]; } |
| 227 | + public bool GetDelaunayEdgeCW(TriangulationPoint p) { return EdgeIsDelaunay[(IndexOf(p) + 1) % 3]; } |
| 228 | + public bool GetDelaunayEdgeAcross(TriangulationPoint p) { return EdgeIsDelaunay[IndexOf(p)]; } |
| 229 | + public void SetDelaunayEdgeCCW(TriangulationPoint p, bool ce) { EdgeIsDelaunay[(IndexOf(p) + 2) % 3] = ce; } |
| 230 | + public void SetDelaunayEdgeCW(TriangulationPoint p, bool ce) { EdgeIsDelaunay[(IndexOf(p) + 1) % 3] = ce; } |
| 231 | + public void SetDelaunayEdgeAcross(TriangulationPoint p, bool ce) { EdgeIsDelaunay[IndexOf(p)] = ce; } |
| 232 | + } |
| 233 | +} |
0 commit comments