├── .gitignore ├── LICENSE ├── Poly2Tri.Test ├── Poly2Tri.Test.csproj └── Properties │ └── AssemblyInfo.cs ├── Poly2Tri.sln ├── Poly2Tri ├── P2T.cs ├── Poly2Tri.csproj ├── Poly2Tri.nuspec ├── Properties │ └── AssemblyInfo.cs ├── Triangulation │ ├── Delaunay │ │ ├── DelaunayTriangle.cs │ │ └── Sweep │ │ │ ├── AdvancingFront.cs │ │ │ ├── AdvancingFrontNode.cs │ │ │ ├── DTSweep.cs │ │ │ ├── DTSweepBasin.cs │ │ │ ├── DTSweepConstraint.cs │ │ │ ├── DTSweepContext.cs │ │ │ ├── DTSweepDebugContext.cs │ │ │ ├── DTSweepEdgeEvent.cs │ │ │ ├── DTSweepPointComparator.cs │ │ │ └── PointOnEdgeException.cs │ ├── ITriangulatable.cs │ ├── Orientation.cs │ ├── Polygon │ │ ├── Contour.cs │ │ ├── Polygon.cs │ │ ├── PolygonPoint.cs │ │ └── PolygonUtil.cs │ ├── Sets │ │ ├── ConstrainedPointSet.cs │ │ └── PointSet.cs │ ├── TriangulationAlgorithm.cs │ ├── TriangulationConstraint.cs │ ├── TriangulationContext.cs │ ├── TriangulationDebugContext.cs │ ├── TriangulationMode.cs │ ├── TriangulationPoint.cs │ └── Util │ │ ├── PointGenerator.cs │ │ ├── PolygonGenerator.cs │ │ └── TriangulationUtil.cs └── Utility │ ├── FixedArray3.cs │ ├── MathUtil.cs │ ├── Point2D.cs │ ├── Point2DList.cs │ └── Rect2D.cs ├── push-all.ps1 └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.user 2 | *.suo 3 | *.ncrunchsolution 4 | *.ncrunchproject 5 | *.cache 6 | _Resharper.Caches 7 | _Resharper.Poly2Tri 8 | 9 | Poly2Tri/bin 10 | Poly2Tri/obj 11 | 12 | Poly2Tri.Test/bin 13 | Poly2Tri.Test/obj -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors 2 | 3 | All rights reserved. 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | * Neither the name of Poly2Tri nor the names of its contributors may be 13 | used to endorse or promote products derived from this software without specific 14 | prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /Poly2Tri.Test/Poly2Tri.Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {F5BF959A-8FBF-4336-BDBD-F76E281AFACA} 7 | Library 8 | Properties 9 | Poly2Tri.Test 10 | Poly2Tri.Test 11 | v4.5.2 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | {a21a4d0a-f045-4736-96a7-0053bea98410} 58 | Poly2Tri 59 | 60 | 61 | 62 | 63 | 64 | 65 | False 66 | 67 | 68 | False 69 | 70 | 71 | False 72 | 73 | 74 | False 75 | 76 | 77 | 78 | 79 | 80 | 81 | 88 | -------------------------------------------------------------------------------- /Poly2Tri.Test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Poly2Tri.Test")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Poly2Tri.Test")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("f5bf959a-8fbf-4336-bdbd-f76e281afaca")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Poly2Tri.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Poly2Tri", "Poly2Tri\Poly2Tri.csproj", "{A21A4D0A-F045-4736-96A7-0053BEA98410}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Poly2Tri.Test", "Poly2Tri.Test\Poly2Tri.Test.csproj", "{F5BF959A-8FBF-4336-BDBD-F76E281AFACA}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {A21A4D0A-F045-4736-96A7-0053BEA98410}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {A21A4D0A-F045-4736-96A7-0053BEA98410}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {A21A4D0A-F045-4736-96A7-0053BEA98410}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {A21A4D0A-F045-4736-96A7-0053BEA98410}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {F5BF959A-8FBF-4336-BDBD-F76E281AFACA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {F5BF959A-8FBF-4336-BDBD-F76E281AFACA}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {F5BF959A-8FBF-4336-BDBD-F76E281AFACA}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {F5BF959A-8FBF-4336-BDBD-F76E281AFACA}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /Poly2Tri/P2T.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using System.Collections.Generic; 33 | using Poly2Tri.Triangulation; 34 | using Poly2Tri.Triangulation.Delaunay.Sweep; 35 | using Poly2Tri.Triangulation.Polygon; 36 | 37 | namespace Poly2Tri 38 | { 39 | public static class P2T 40 | { 41 | private const TriangulationAlgorithm DEFAULT_ALGORITHM = TriangulationAlgorithm.DTSweep; 42 | 43 | public static void Triangulate(IEnumerable polygons) 44 | { 45 | foreach (var p in polygons) 46 | Triangulate(p); 47 | } 48 | 49 | private static TriangulationContext CreateContext(TriangulationAlgorithm algorithm) 50 | { 51 | switch (algorithm) 52 | { 53 | default: 54 | return new DTSweepContext(); 55 | } 56 | } 57 | 58 | public static void Triangulate(ITriangulatable t, TriangulationAlgorithm algorithm = DEFAULT_ALGORITHM) 59 | { 60 | TriangulationContext tcx = CreateContext(algorithm); 61 | tcx.PrepareTriangulation(t); 62 | Triangulate(tcx); 63 | } 64 | 65 | private static void Triangulate(TriangulationContext tcx) 66 | { 67 | switch (tcx.Algorithm) 68 | { 69 | default: 70 | DTSweep.Triangulate((DTSweepContext)tcx); 71 | break; 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Poly2Tri/Poly2Tri.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {A21A4D0A-F045-4736-96A7-0053BEA98410} 8 | Library 9 | Properties 10 | Poly2Tri 11 | Poly2Tri 12 | v3.5 13 | 512 14 | Client 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 88 | -------------------------------------------------------------------------------- /Poly2Tri/Poly2Tri.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $id$ 5 | $version$ 6 | https://code.google.com/p/poly2tri/people/list 7 | https://code.google.com/p/poly2tri/people/detail?u=113158675721513411716 8 | http://opensource.org/licenses/BSD-3-Clause 9 | https://code.google.com/p/poly2tri/ 10 | false 11 | $description$ 12 | 13 | 14 | -------------------------------------------------------------------------------- /Poly2Tri/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("Poly2Tri")] 8 | [assembly: AssemblyDescription("A 2D constrained Delaunay triangulation library")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("Poly2Tri")] 12 | [assembly: AssemblyCopyright("Copyright © 2015")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("efc06da6-3d71-48ea-8abf-f310499f4d51")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.1")] 35 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Delaunay/DelaunayTriangle.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 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 Poly2Tri.Triangulation.Delaunay.Sweep; 42 | using Poly2Tri.Utility; 43 | using System; 44 | using System.Collections.Generic; 45 | 46 | namespace Poly2Tri.Triangulation.Delaunay 47 | { 48 | public class DelaunayTriangle 49 | : IEquatable 50 | { 51 | 52 | public FixedArray3 Points; 53 | public FixedArray3 Neighbors; 54 | private FixedArray3 _edgeIsConstrained; 55 | public FixedArray3 EdgeIsConstrained { get { return _edgeIsConstrained; } } 56 | public FixedArray3 EdgeIsDelaunay; 57 | public bool IsInterior { get; set; } 58 | 59 | public DelaunayTriangle(TriangulationPoint p1, TriangulationPoint p2, TriangulationPoint p3) 60 | { 61 | Points[0] = p1; 62 | Points[1] = p2; 63 | Points[2] = p3; 64 | } 65 | 66 | 67 | public int IndexOf(TriangulationPoint p) 68 | { 69 | int i = Points.IndexOf(p); 70 | if (i == -1) 71 | { 72 | throw new Exception("Calling index with a point that doesn't exist in triangle"); 73 | } 74 | 75 | return i; 76 | } 77 | 78 | internal void CircumCircleCenter(out double x, out double y) 79 | { 80 | var a = Points.Item0; 81 | var b = Points.Item1; 82 | var c = Points.Item2; 83 | 84 | var tx = (a.X + c.X) / 2; 85 | var ty = (a.Y + c.Y) / 2; 86 | 87 | var vx = (b.X + c.X) / 2; 88 | var vy = (b.Y + c.Y) / 2; 89 | 90 | double ux, uy, wx, wy; 91 | 92 | if (a.X == c.X) 93 | { 94 | ux = 1; 95 | uy = 0; 96 | } 97 | else 98 | { 99 | ux = (c.Y - a.Y) / (a.X - c.X); 100 | uy = 1; 101 | } 102 | 103 | if (b.X == c.X) 104 | { 105 | wx = -1; 106 | wy = 0; 107 | } 108 | else 109 | { 110 | wx = (b.Y - c.Y) / (b.X - c.X); 111 | wy = -1; 112 | } 113 | 114 | var alpha = (wy * (vx - tx) - wx * (vy - ty)) / (ux * wy - wx * uy); 115 | 116 | x = tx + alpha * ux; 117 | y = ty + alpha * uy; 118 | } 119 | 120 | public int IndexCWFrom(TriangulationPoint p) 121 | { 122 | return (IndexOf(p) + 2) % 3; 123 | } 124 | 125 | private int IndexCCWFrom(TriangulationPoint p) 126 | { 127 | return (IndexOf(p) + 1) % 3; 128 | } 129 | 130 | 131 | public bool Contains(TriangulationPoint p) 132 | { 133 | return Points.Contains(p); 134 | } 135 | 136 | 137 | /// 138 | /// Update neighbor pointers 139 | /// 140 | /// Point 1 of the shared edge 141 | /// Point 2 of the shared edge 142 | /// This triangle's new neighbor 143 | private void MarkNeighbor(TriangulationPoint p1, TriangulationPoint p2, DelaunayTriangle t) 144 | { 145 | int i = EdgeIndex(p1, p2); 146 | if (i == -1) 147 | { 148 | throw new Exception("Error marking neighbors -- t doesn't contain edge p1-p2!"); 149 | } 150 | Neighbors[i] = t; 151 | } 152 | 153 | 154 | /// 155 | /// Exhaustive search to update neighbor pointers 156 | /// 157 | public void MarkNeighbor(DelaunayTriangle t) 158 | { 159 | // Points of this triangle also belonging to t 160 | bool a = t.Contains(Points[0]); 161 | bool b = t.Contains(Points[1]); 162 | bool c = t.Contains(Points[2]); 163 | 164 | if (b && c) 165 | { 166 | Neighbors[0] = t; 167 | t.MarkNeighbor(Points[1], Points[2], this); 168 | } 169 | else if (a && c) 170 | { 171 | Neighbors[1] = t; 172 | t.MarkNeighbor(Points[0], Points[2], this); 173 | } 174 | else if (a && b) 175 | { 176 | Neighbors[2] = t; 177 | t.MarkNeighbor(Points[0], Points[1], this); 178 | } 179 | else 180 | { 181 | throw new Exception("Failed to mark neighbor, doesn't share an edge!"); 182 | } 183 | } 184 | 185 | private void ClearNeighbors() 186 | { 187 | Neighbors[0] = Neighbors[1] = Neighbors[2] = null; 188 | } 189 | 190 | private void ClearNeighbor(DelaunayTriangle triangle) 191 | { 192 | if (Neighbors[0] == triangle) 193 | { 194 | Neighbors[0] = null; 195 | } 196 | else if (Neighbors[1] == triangle) 197 | { 198 | Neighbors[1] = null; 199 | } 200 | else if( Neighbors[2] == triangle) 201 | { 202 | Neighbors[2] = null; 203 | } 204 | } 205 | 206 | /// 207 | /// Clears all references to all other triangles and points 208 | /// 209 | public void Clear() 210 | { 211 | for (int i = 0; i < 3; i++) 212 | { 213 | DelaunayTriangle t = Neighbors[i]; 214 | if (t != null) 215 | { 216 | t.ClearNeighbor(this); 217 | } 218 | } 219 | ClearNeighbors(); 220 | Points[0] = Points[1] = Points[2] = null; 221 | } 222 | 223 | /// Opposite triangle 224 | /// The point in t that isn't shared between the triangles 225 | public TriangulationPoint OppositePoint(DelaunayTriangle t, TriangulationPoint p) 226 | { 227 | return PointCWFrom(t.PointCWFrom(p)); 228 | } 229 | 230 | 231 | public DelaunayTriangle NeighborCWFrom(TriangulationPoint point) 232 | { 233 | return Neighbors[(Points.IndexOf(point) + 1) % 3]; 234 | } 235 | 236 | 237 | public DelaunayTriangle NeighborCCWFrom(TriangulationPoint point) 238 | { 239 | return Neighbors[(Points.IndexOf(point) + 2) % 3]; 240 | } 241 | 242 | 243 | public DelaunayTriangle NeighborAcrossFrom(TriangulationPoint point) 244 | { 245 | return Neighbors[Points.IndexOf(point)]; 246 | } 247 | 248 | 249 | public TriangulationPoint PointCCWFrom(TriangulationPoint point) 250 | { 251 | return Points[(IndexOf(point) + 1) % 3]; 252 | } 253 | 254 | 255 | public TriangulationPoint PointCWFrom(TriangulationPoint point) 256 | { 257 | return Points[(IndexOf(point) + 2) % 3]; 258 | } 259 | 260 | 261 | private void RotateCW() 262 | { 263 | var t = Points[2]; 264 | Points[2] = Points[1]; 265 | Points[1] = Points[0]; 266 | Points[0] = t; 267 | } 268 | 269 | 270 | /// 271 | /// Legalize triangle by rotating clockwise around oPoint 272 | /// 273 | /// The origin point to rotate around 274 | /// ??? 275 | public void Legalize(TriangulationPoint oPoint, TriangulationPoint nPoint) 276 | { 277 | RotateCW(); 278 | Points[IndexCCWFrom(oPoint)] = nPoint; 279 | } 280 | 281 | 282 | public override string ToString() 283 | { 284 | return Points[0] + "," + Points[1] + "," + Points[2]; 285 | } 286 | 287 | 288 | /// 289 | /// Finalize edge marking 290 | /// 291 | public void MarkNeighborEdges() 292 | { 293 | for (int i = 0; i < 3; i++) 294 | { 295 | if (EdgeIsConstrained[i] && Neighbors[i] != null) 296 | { 297 | Neighbors[i].MarkConstrainedEdge(Points[(i + 1) % 3], Points[(i + 2) % 3]); 298 | } 299 | } 300 | } 301 | 302 | 303 | public void MarkEdge(DelaunayTriangle triangle) 304 | { 305 | for (int i = 0; i < 3; i++) if (EdgeIsConstrained[i]) 306 | { 307 | triangle.MarkConstrainedEdge(Points[(i + 1) % 3], Points[(i + 2) % 3]); 308 | } 309 | } 310 | 311 | public void MarkEdge(IEnumerable tList) 312 | { 313 | foreach (DelaunayTriangle t in tList) 314 | { 315 | for (int i = 0; i < 3; i++) 316 | { 317 | if (t.EdgeIsConstrained[i]) 318 | { 319 | MarkConstrainedEdge(t.Points[(i + 1) % 3], t.Points[(i + 2) % 3]); 320 | } 321 | } 322 | } 323 | } 324 | 325 | 326 | public void MarkConstrainedEdge(int index) 327 | { 328 | _edgeIsConstrained[index] = true; 329 | } 330 | 331 | 332 | public void MarkConstrainedEdge(DTSweepConstraint edge) 333 | { 334 | MarkConstrainedEdge(edge.P, edge.Q); 335 | } 336 | 337 | 338 | /// 339 | /// Mark edge as constrained 340 | /// 341 | public void MarkConstrainedEdge(TriangulationPoint p, TriangulationPoint q) 342 | { 343 | int i = EdgeIndex(p, q); 344 | if (i != -1) 345 | { 346 | _edgeIsConstrained[i] = true; 347 | } 348 | } 349 | 350 | 351 | public double Area() 352 | { 353 | double b = Points[0].X - Points[1].X; 354 | double h = Points[2].Y - Points[1].Y; 355 | 356 | return Math.Abs((b * h * 0.5f)); 357 | } 358 | 359 | public TriangulationPoint Centroid() 360 | { 361 | double cx = (Points[0].X + Points[1].X + Points[2].X) / 3f; 362 | double cy = (Points[0].Y + Points[1].Y + Points[2].Y) / 3f; 363 | return new TriangulationPoint(cx, cy); 364 | } 365 | 366 | 367 | /// 368 | /// Get the index of the neighbor that shares this edge (or -1 if it isn't shared) 369 | /// 370 | /// index of the shared edge or -1 if edge isn't shared 371 | public int EdgeIndex(TriangulationPoint p1, TriangulationPoint p2) 372 | { 373 | int i1 = Points.IndexOf(p1); 374 | int i2 = Points.IndexOf(p2); 375 | 376 | // Points of this triangle in the edge p1-p2 377 | bool a = (i1 == 0 || i2 == 0); 378 | bool b = (i1 == 1 || i2 == 1); 379 | bool c = (i1 == 2 || i2 == 2); 380 | 381 | if (b && c) 382 | { 383 | return 0; 384 | } 385 | if (a && c) 386 | { 387 | return 1; 388 | } 389 | if (a && b) 390 | { 391 | return 2; 392 | } 393 | 394 | return -1; 395 | } 396 | 397 | 398 | public bool GetConstrainedEdgeCCW(TriangulationPoint p) { return EdgeIsConstrained[(IndexOf(p) + 2) % 3]; } 399 | public bool GetConstrainedEdgeCW(TriangulationPoint p) { return EdgeIsConstrained[(IndexOf(p) + 1) % 3]; } 400 | public bool GetConstrainedEdgeAcross(TriangulationPoint p) { return EdgeIsConstrained[IndexOf(p)]; } 401 | 402 | private void SetConstrainedEdge(int idx, bool ce) 403 | { 404 | //if (ce == false && EdgeIsConstrained[idx]) 405 | //{ 406 | // DTSweepConstraint edge = null; 407 | // if (GetEdge(idx, out edge)) 408 | // { 409 | // Console.WriteLine("Removing pre-defined constraint from edge " + edge.ToString()); 410 | // } 411 | //} 412 | _edgeIsConstrained[idx] = ce; 413 | } 414 | public void SetConstrainedEdgeCCW(TriangulationPoint p, bool ce) 415 | { 416 | int idx = (IndexOf(p) + 2) % 3; 417 | SetConstrainedEdge(idx, ce); 418 | } 419 | public void SetConstrainedEdgeCW(TriangulationPoint p, bool ce) 420 | { 421 | int idx = (IndexOf(p) + 1) % 3; 422 | SetConstrainedEdge(idx, ce); 423 | } 424 | public void SetConstrainedEdgeAcross(TriangulationPoint p, bool ce) 425 | { 426 | int idx = IndexOf(p); 427 | SetConstrainedEdge(idx, ce); 428 | } 429 | 430 | public bool GetDelaunayEdgeCCW(TriangulationPoint p) { return EdgeIsDelaunay[(IndexOf(p) + 2) % 3]; } 431 | public bool GetDelaunayEdgeCW(TriangulationPoint p) { return EdgeIsDelaunay[(IndexOf(p) + 1) % 3]; } 432 | public bool GetDelaunayEdgeAcross(TriangulationPoint p) { return EdgeIsDelaunay[IndexOf(p)]; } 433 | public void SetDelaunayEdgeCCW(TriangulationPoint p, bool ce) { EdgeIsDelaunay[(IndexOf(p) + 2) % 3] = ce; } 434 | public void SetDelaunayEdgeCW(TriangulationPoint p, bool ce) { EdgeIsDelaunay[(IndexOf(p) + 1) % 3] = ce; } 435 | public void SetDelaunayEdgeAcross(TriangulationPoint p, bool ce) { EdgeIsDelaunay[IndexOf(p)] = ce; } 436 | 437 | private bool GetEdge(int idx, out DTSweepConstraint edge) 438 | { 439 | edge = null; 440 | if (idx < 0 || idx > 2) 441 | { 442 | return false; 443 | } 444 | TriangulationPoint p1 = Points[(idx + 1) % 3]; 445 | TriangulationPoint p2 = Points[(idx + 2) % 3]; 446 | if (p1.GetEdge(p2, out edge)) 447 | { 448 | return true; 449 | } 450 | else if (p2.GetEdge(p1, out edge)) 451 | { 452 | return true; 453 | } 454 | 455 | return false; 456 | } 457 | 458 | 459 | public bool GetEdgeCCW(TriangulationPoint p, out DTSweepConstraint edge) 460 | { 461 | int pointIndex = IndexOf(p); 462 | int edgeIdx = (pointIndex + 2)%3; 463 | 464 | return GetEdge(edgeIdx, out edge); 465 | } 466 | 467 | public bool GetEdgeCW(TriangulationPoint p, out DTSweepConstraint edge) 468 | { 469 | int pointIndex = IndexOf(p); 470 | int edgeIdx = (pointIndex + 1) % 3; 471 | 472 | return GetEdge(edgeIdx, out edge); 473 | } 474 | 475 | public bool GetEdgeAcross(TriangulationPoint p, out DTSweepConstraint edge) 476 | { 477 | int pointIndex = IndexOf(p); 478 | int edgeIdx = pointIndex; 479 | 480 | return GetEdge(edgeIdx, out edge); 481 | } 482 | 483 | public bool Equals(DelaunayTriangle other) 484 | { 485 | return ReferenceEquals(this, other); 486 | } 487 | } 488 | } 489 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Delaunay/Sweep/AdvancingFront.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | // Changes from the Java version 33 | // Removed BST code, but not all artifacts of it 34 | // Future possibilities 35 | // Eliminate Add/RemoveNode ? 36 | // Comments comments and more comments! 37 | 38 | using System; 39 | using System.Text; 40 | 41 | namespace Poly2Tri.Triangulation.Delaunay.Sweep 42 | { 43 | /** 44 | * @author Thomas Åhlen (thahlen@gmail.com) 45 | */ 46 | public class AdvancingFront 47 | { 48 | public AdvancingFrontNode Head; 49 | public AdvancingFrontNode Tail; 50 | private AdvancingFrontNode _search; 51 | 52 | public AdvancingFront(AdvancingFrontNode head, AdvancingFrontNode tail) 53 | { 54 | Head = head; 55 | Tail = tail; 56 | _search = head; 57 | } 58 | 59 | public override string ToString() 60 | { 61 | StringBuilder sb = new StringBuilder(); 62 | AdvancingFrontNode node = Head; 63 | while (node != Tail) 64 | { 65 | sb.Append(node.Point.X).Append("->"); 66 | node = node.Next; 67 | } 68 | sb.Append(Tail.Point.X); 69 | return sb.ToString(); 70 | } 71 | 72 | /// 73 | /// We use a balancing tree to locate a node smaller or equal to given key value (in theory) 74 | /// 75 | public AdvancingFrontNode LocateNode(TriangulationPoint point) 76 | { 77 | return LocateNode(point.X); 78 | } 79 | 80 | private AdvancingFrontNode LocateNode(double x) 81 | { 82 | AdvancingFrontNode node = _search; 83 | if (x < node.Value) 84 | { 85 | while ((node = node.Prev) != null) 86 | { 87 | if (x >= node.Value) 88 | { 89 | _search = node; 90 | return node; 91 | } 92 | } 93 | } 94 | else 95 | { 96 | while ((node = node.Next) != null) 97 | { 98 | if (x < node.Value) 99 | { 100 | _search = node.Prev; 101 | return node.Prev; 102 | } 103 | } 104 | } 105 | 106 | return null; 107 | } 108 | 109 | 110 | /// 111 | /// This implementation will use simple node traversal algorithm to find a point on the front 112 | /// 113 | public AdvancingFrontNode LocatePoint(TriangulationPoint point) 114 | { 115 | double px = point.X; 116 | AdvancingFrontNode node = _search; 117 | double nx = node.Point.X; 118 | 119 | // ReSharper disable CompareOfFloatsByEqualityOperator 120 | if (px == nx) 121 | // ReSharper restore CompareOfFloatsByEqualityOperator 122 | { 123 | if (!point.Equals(node.Point)) 124 | { 125 | // We might have two nodes with same x value for a short time 126 | if (point.Equals(node.Prev.Point)) 127 | { 128 | node = node.Prev; 129 | } 130 | else if (point.Equals(node.Next.Point)) 131 | { 132 | node = node.Next; 133 | } 134 | else 135 | { 136 | throw new Exception("Failed to find Node for given afront point"); 137 | } 138 | } 139 | } 140 | else if (px < nx) 141 | { 142 | while ((node = node.Prev) != null) 143 | { 144 | if (point.Equals(node.Point)) 145 | { 146 | break; 147 | } 148 | } 149 | } 150 | else 151 | { 152 | while ((node = node.Next) != null) 153 | { 154 | if (point.Equals(node.Point)) 155 | { 156 | break; 157 | } 158 | } 159 | } 160 | _search = node; 161 | 162 | return node; 163 | } 164 | } 165 | } -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Delaunay/Sweep/AdvancingFrontNode.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | // Changes from the Java version 33 | // Removed getters 34 | // Has* turned into attributes 35 | // Future possibilities 36 | // Comments! 37 | 38 | namespace Poly2Tri.Triangulation.Delaunay.Sweep 39 | { 40 | public class AdvancingFrontNode 41 | { 42 | public AdvancingFrontNode Next; 43 | public AdvancingFrontNode Prev; 44 | public readonly double Value; 45 | public readonly TriangulationPoint Point; 46 | public DelaunayTriangle Triangle; 47 | 48 | public AdvancingFrontNode(TriangulationPoint point) 49 | { 50 | Point = point; 51 | Value = point.X; 52 | } 53 | 54 | public bool HasNext { get { return Next != null; } } 55 | public bool HasPrev { get { return Prev != null; } } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Delaunay/Sweep/DTSweepBasin.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | namespace Poly2Tri.Triangulation.Delaunay.Sweep 33 | { 34 | public class DTSweepBasin 35 | { 36 | public AdvancingFrontNode LeftNode; 37 | public AdvancingFrontNode BottomNode; 38 | public AdvancingFrontNode RightNode; 39 | public double Width; 40 | public bool LeftHighest; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Delaunay/Sweep/DTSweepConstraint.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using Poly2Tri.Utility; 33 | 34 | namespace Poly2Tri.Triangulation.Delaunay.Sweep 35 | { 36 | public class DTSweepConstraint : TriangulationConstraint 37 | { 38 | /// 39 | /// Give two points in any order. Will always be ordered so 40 | /// that q.y > p.y and q.x > p.x if same y value 41 | /// 42 | public DTSweepConstraint(Point2D p1, Point2D p2) 43 | : base(p1, p2) 44 | { 45 | Q.AddEdge(this); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Delaunay/Sweep/DTSweepContext.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | namespace Poly2Tri.Triangulation.Delaunay.Sweep 33 | { 34 | /** 35 | * 36 | * @author Thomas Åhlén, thahlen@gmail.com 37 | * 38 | */ 39 | public class DTSweepContext : TriangulationContext 40 | { 41 | // Inital triangle factor, seed triangle will extend 30% of 42 | // PointSet width to both left and right. 43 | private const float ALPHA = 0.3f; 44 | 45 | public AdvancingFront Front; 46 | private TriangulationPoint Head { get; set; } 47 | private TriangulationPoint Tail { get; set; } 48 | 49 | public readonly DTSweepBasin Basin = new DTSweepBasin(); 50 | public readonly DTSweepEdgeEvent EdgeEvent = new DTSweepEdgeEvent(); 51 | 52 | private readonly DTSweepPointComparator _comparator = new DTSweepPointComparator(); 53 | 54 | public override TriangulationAlgorithm Algorithm { get { return TriangulationAlgorithm.DTSweep; } } 55 | 56 | 57 | 58 | public DTSweepContext() 59 | : base(new DTSweepDebugContext()) 60 | { 61 | } 62 | 63 | public new DTSweepDebugContext DebugContext 64 | { 65 | get 66 | { 67 | return (DTSweepDebugContext)base.DebugContext; 68 | } 69 | } 70 | 71 | public void RemoveFromList(DelaunayTriangle triangle) 72 | { 73 | Triangles.Remove(triangle); 74 | // TODO: remove all neighbor pointers to this triangle 75 | // for( int i=0; i<3; i++ ) 76 | // { 77 | // if( triangle.neighbors[i] != null ) 78 | // { 79 | // triangle.neighbors[i].clearNeighbor( triangle ); 80 | // } 81 | // } 82 | // triangle.clearNeighbors(); 83 | } 84 | 85 | 86 | public void MeshClean(DelaunayTriangle triangle) 87 | { 88 | MeshCleanReq(triangle); 89 | } 90 | 91 | 92 | private void MeshCleanReq(DelaunayTriangle triangle) 93 | { 94 | if (triangle != null && !triangle.IsInterior) 95 | { 96 | triangle.IsInterior = true; 97 | Triangulatable.AddTriangle(triangle); 98 | 99 | for (int i = 0; i < 3; i++) 100 | { 101 | if (!triangle.EdgeIsConstrained[i]) 102 | { 103 | MeshCleanReq(triangle.Neighbors[i]); 104 | } 105 | } 106 | } 107 | } 108 | 109 | public AdvancingFrontNode LocateNode(TriangulationPoint point) 110 | { 111 | return Front.LocateNode(point); 112 | } 113 | 114 | 115 | public void CreateAdvancingFront() 116 | { 117 | // Initial triangle 118 | DelaunayTriangle iTriangle = new DelaunayTriangle(Points[0], Tail, Head); 119 | Triangles.Add(iTriangle); 120 | 121 | AdvancingFrontNode head = new AdvancingFrontNode(iTriangle.Points[1]) { 122 | Triangle = iTriangle 123 | }; 124 | AdvancingFrontNode middle = new AdvancingFrontNode(iTriangle.Points[0]) { 125 | Triangle = iTriangle 126 | }; 127 | AdvancingFrontNode tail = new AdvancingFrontNode(iTriangle.Points[2]); 128 | 129 | Front = new AdvancingFront(head, tail) { 130 | Head = { 131 | Next = middle 132 | } 133 | }; 134 | 135 | // TODO: I think it would be more intuitive if head is middles next and not previous 136 | // so swap head and tail 137 | middle.Next = Front.Tail; 138 | middle.Prev = Front.Head; 139 | Front.Tail.Prev = middle; 140 | } 141 | 142 | 143 | /// 144 | /// Try to map a node to all sides of this triangle that don't have 145 | /// a neighbor. 146 | /// 147 | public void MapTriangleToNodes(DelaunayTriangle t) 148 | { 149 | for (int i = 0; i < 3; i++) 150 | { 151 | if (t.Neighbors[i] == null) 152 | { 153 | AdvancingFrontNode n = Front.LocatePoint(t.PointCWFrom(t.Points[i])); 154 | if (n != null) 155 | { 156 | n.Triangle = t; 157 | } 158 | } 159 | } 160 | } 161 | 162 | 163 | public override void PrepareTriangulation(ITriangulatable t) 164 | { 165 | base.PrepareTriangulation(t); 166 | 167 | double xmin; 168 | double ymin; 169 | 170 | double xmax = xmin = Points[0].X; 171 | double ymax = ymin = Points[0].Y; 172 | 173 | // Calculate bounds. Should be combined with the sorting 174 | foreach (TriangulationPoint p in Points) 175 | { 176 | if (p.X > xmax) 177 | { 178 | xmax = p.X; 179 | } 180 | if (p.X < xmin) 181 | { 182 | xmin = p.X; 183 | } 184 | if (p.Y > ymax) 185 | { 186 | ymax = p.Y; 187 | } 188 | if (p.Y < ymin) 189 | { 190 | ymin = p.Y; 191 | } 192 | } 193 | 194 | double deltaX = ALPHA * (xmax - xmin); 195 | double deltaY = ALPHA * (ymax - ymin); 196 | TriangulationPoint p1 = new TriangulationPoint(xmax + deltaX, ymin - deltaY); 197 | TriangulationPoint p2 = new TriangulationPoint(xmin - deltaX, ymin - deltaY); 198 | 199 | Head = p1; 200 | Tail = p2; 201 | 202 | // long time = System.nanoTime(); 203 | // Sort the points along y-axis 204 | Points.Sort(_comparator); 205 | // logger.info( "Triangulation setup [{}ms]", ( System.nanoTime() - time ) / 1e6 ); 206 | } 207 | 208 | 209 | public void FinalizeTriangulation() 210 | { 211 | Triangulatable.AddTriangles(Triangles); 212 | Triangles.Clear(); 213 | } 214 | 215 | 216 | public override DTSweepConstraint NewConstraint(TriangulationPoint a, TriangulationPoint b) 217 | { 218 | return new DTSweepConstraint(a, b); 219 | } 220 | 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Delaunay/Sweep/DTSweepDebugContext.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | namespace Poly2Tri.Triangulation.Delaunay.Sweep 33 | { 34 | public class DTSweepDebugContext : TriangulationDebugContext 35 | { 36 | public DelaunayTriangle PrimaryTriangle { get; set; } 37 | public DelaunayTriangle SecondaryTriangle { get; set; } 38 | public TriangulationPoint ActivePoint { get; set; } 39 | public AdvancingFrontNode ActiveNode { get; set; } 40 | public DTSweepConstraint ActiveConstraint { get; set; } 41 | 42 | public bool IsDebugContext { get { return true; } } 43 | 44 | public override void Clear() 45 | { 46 | PrimaryTriangle = null; 47 | SecondaryTriangle = null; 48 | ActivePoint = null; 49 | ActiveNode = null; 50 | ActiveConstraint = null; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Delaunay/Sweep/DTSweepEdgeEvent.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | // Changes from the Java version 33 | // Turned DTSweepEdgeEvent into a value type 34 | 35 | namespace Poly2Tri.Triangulation.Delaunay.Sweep 36 | { 37 | public class DTSweepEdgeEvent 38 | { 39 | public DTSweepConstraint ConstrainedEdge; 40 | public bool Right; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Delaunay/Sweep/DTSweepPointComparator.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using System.Collections.Generic; 33 | 34 | namespace Poly2Tri.Triangulation.Delaunay.Sweep 35 | { 36 | public class DTSweepPointComparator : IComparer 37 | { 38 | public int Compare(TriangulationPoint p1, TriangulationPoint p2) 39 | { 40 | if (p1.Y < p2.Y) 41 | { 42 | return -1; 43 | } 44 | else if (p1.Y > p2.Y) 45 | { 46 | return 1; 47 | } 48 | else 49 | { 50 | if (p1.X < p2.X) 51 | { 52 | return -1; 53 | } 54 | else if (p1.X > p2.X) 55 | { 56 | return 1; 57 | } 58 | else 59 | { 60 | return 0; 61 | } 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Delaunay/Sweep/PointOnEdgeException.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using System; 33 | 34 | namespace Poly2Tri.Triangulation.Delaunay.Sweep 35 | { 36 | public class PointOnEdgeException : NotImplementedException 37 | { 38 | public TriangulationPoint A { get; set; } 39 | public TriangulationPoint B { get; set; } 40 | public TriangulationPoint C { get; set; } 41 | 42 | public PointOnEdgeException(string message, TriangulationPoint a, TriangulationPoint b, TriangulationPoint c) 43 | : base(message) 44 | { 45 | A = a; 46 | B = b; 47 | C = c; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/ITriangulatable.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using System.Collections.Generic; 33 | using Poly2Tri.Triangulation.Delaunay; 34 | using Poly2Tri.Utility; 35 | 36 | namespace Poly2Tri.Triangulation 37 | { 38 | public interface ITriangulatable 39 | { 40 | //IList Points { get; } // MM: Neither of these are used via interface (yet?) 41 | IList Triangles { get; } 42 | TriangulationMode TriangulationMode { get; } 43 | bool DisplayFlipX { get; set; } 44 | bool DisplayFlipY { get; set; } 45 | float DisplayRotate { get; set; } 46 | double Precision { get; set; } 47 | double MinX { get; } 48 | double MaxX { get; } 49 | double MinY { get; } 50 | double MaxY { get; } 51 | Rect2D Bounds { get; } 52 | 53 | void Prepare(TriangulationContext tcx); 54 | void AddTriangle(DelaunayTriangle t); 55 | void AddTriangles(IEnumerable list); 56 | void ClearTriangles(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Orientation.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | namespace Poly2Tri.Triangulation 33 | { 34 | public enum Orientation 35 | { 36 | Clockwise, 37 | AntiClockwise, 38 | Collinear 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Polygon/Contour.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using System; 33 | using System.Collections.Generic; 34 | using System.Linq; 35 | using Poly2Tri.Triangulation.Delaunay; 36 | using Poly2Tri.Triangulation.Sets; 37 | using Poly2Tri.Utility; 38 | 39 | namespace Poly2Tri.Triangulation.Polygon 40 | { 41 | 42 | /// 43 | /// This is basically a light-weight version of the Polygon class, but with limited functionality and 44 | /// used for different purposes. Nonetheless, for all intents and purposes, this should actually be 45 | /// a polygon (though not a Polygon..) 46 | /// 47 | public class Contour : Point2DList, ITriangulatable, IEnumerable, IList 48 | { 49 | private readonly List _holes = new List(); 50 | private ITriangulatable _parent = null; 51 | 52 | public new TriangulationPoint this[int index] 53 | { 54 | get { return MPoints[index] as TriangulationPoint; } 55 | set { MPoints[index] = value; } 56 | } 57 | 58 | public IList Triangles 59 | { 60 | get 61 | { 62 | throw new NotImplementedException("PolyHole.Triangles should never get called"); 63 | } 64 | } 65 | 66 | public TriangulationMode TriangulationMode { get { return _parent.TriangulationMode; } } 67 | public bool DisplayFlipX { get { return _parent.DisplayFlipX; } set { } } 68 | public bool DisplayFlipY { get { return _parent.DisplayFlipY; } set { } } 69 | public float DisplayRotate { get { return _parent.DisplayRotate; } set { } } 70 | public double Precision { get { return _parent.Precision; } set { } } 71 | public double MinX { get { return BoundingBox.MinX; } } 72 | public double MaxX { get { return BoundingBox.MaxX; } } 73 | public double MinY { get { return BoundingBox.MinY; } } 74 | public double MaxY { get { return BoundingBox.MaxY; } } 75 | public Rect2D Bounds { get { return BoundingBox; } } 76 | 77 | 78 | public Contour(ITriangulatable parent) 79 | { 80 | _parent = parent; 81 | } 82 | 83 | 84 | public Contour(ITriangulatable parent, IList points, WindingOrderType windingOrder) 85 | { 86 | // Currently assumes that input is pre-checked for validity 87 | _parent = parent; 88 | AddRange(points, windingOrder); 89 | } 90 | 91 | IEnumerator IEnumerable.GetEnumerator() 92 | { 93 | return MPoints.Cast().GetEnumerator(); 94 | } 95 | 96 | 97 | public int IndexOf(TriangulationPoint p) 98 | { 99 | return MPoints.IndexOf(p); 100 | } 101 | 102 | 103 | public void Add(TriangulationPoint p) 104 | { 105 | Add(p, -1, true); 106 | } 107 | 108 | 109 | protected override void Add(Point2D p, int idx, bool bCalcWindingOrderAndEpsilon) 110 | { 111 | TriangulationPoint pt; 112 | if (p is TriangulationPoint) 113 | { 114 | pt = p as TriangulationPoint; 115 | } 116 | else 117 | { 118 | pt = new TriangulationPoint(p.X, p.Y); 119 | } 120 | if (idx < 0) 121 | { 122 | MPoints.Add(pt); 123 | } 124 | else 125 | { 126 | MPoints.Insert(idx, pt); 127 | } 128 | BoundingBox = BoundingBox.AddPoint(pt); 129 | if (bCalcWindingOrderAndEpsilon) 130 | { 131 | if (WindingOrder == WindingOrderType.Unknown) 132 | { 133 | WindingOrder = CalculateWindingOrder(); 134 | } 135 | Epsilon = CalculateEpsilon(); 136 | } 137 | } 138 | 139 | protected override void AddRange(IEnumerator iter, WindingOrderType windingOrder) 140 | { 141 | if (iter == null) 142 | { 143 | return; 144 | } 145 | 146 | if (WindingOrder == WindingOrderType.Unknown && Count == 0) 147 | { 148 | WindingOrder = windingOrder; 149 | } 150 | bool bReverseReadOrder = (WindingOrder != WindingOrderType.Unknown) && (windingOrder != WindingOrderType.Unknown) && (WindingOrder != windingOrder); 151 | bool bAddedFirst = true; 152 | int startCount = MPoints.Count; 153 | iter.Reset(); 154 | while (iter.MoveNext()) 155 | { 156 | TriangulationPoint pt; 157 | if (iter.Current is TriangulationPoint) 158 | { 159 | pt = iter.Current as TriangulationPoint; 160 | } 161 | else 162 | { 163 | pt = new TriangulationPoint(iter.Current.X, iter.Current.Y); 164 | } 165 | if (!bAddedFirst) 166 | { 167 | bAddedFirst = true; 168 | MPoints.Add(pt); 169 | } 170 | else if (bReverseReadOrder) 171 | { 172 | MPoints.Insert(startCount, pt); 173 | } 174 | else 175 | { 176 | MPoints.Add(pt); 177 | } 178 | BoundingBox = BoundingBox.AddPoint(iter.Current); 179 | } 180 | if (WindingOrder == WindingOrderType.Unknown && windingOrder == WindingOrderType.Unknown) 181 | { 182 | WindingOrder = CalculateWindingOrder(); 183 | } 184 | Epsilon = CalculateEpsilon(); 185 | } 186 | 187 | private void AddRange(IList points, WindingOrderType windingOrder) 188 | { 189 | if (points == null || points.Count < 1) 190 | { 191 | return; 192 | } 193 | 194 | if (WindingOrder == WindingOrderType.Unknown && Count == 0) 195 | { 196 | WindingOrder = windingOrder; 197 | } 198 | 199 | int numPoints = points.Count; 200 | bool bReverseReadOrder = (WindingOrder != WindingOrderType.Unknown) && (windingOrder != WindingOrderType.Unknown) && (WindingOrder != windingOrder); 201 | for (int i = 0; i < numPoints; ++i) 202 | { 203 | int idx = i; 204 | if (bReverseReadOrder) 205 | { 206 | idx = points.Count - i - 1; 207 | } 208 | Add(points[idx], -1, false); 209 | } 210 | if (WindingOrder == WindingOrderType.Unknown) 211 | { 212 | WindingOrder = CalculateWindingOrder(); 213 | } 214 | Epsilon = CalculateEpsilon(); 215 | } 216 | 217 | 218 | public void Insert(int idx, TriangulationPoint p) 219 | { 220 | Add(p, idx, true); 221 | } 222 | 223 | 224 | public bool Remove(TriangulationPoint p) 225 | { 226 | return Remove(p as Point2D); 227 | } 228 | 229 | 230 | public bool Contains(TriangulationPoint p) 231 | { 232 | return MPoints.Contains(p); 233 | } 234 | 235 | 236 | public void CopyTo(TriangulationPoint[] array, int arrayIndex) 237 | { 238 | int numElementsToCopy = Math.Min(Count, array.Length - arrayIndex); 239 | for (int i = 0; i < numElementsToCopy; ++i) 240 | { 241 | array[arrayIndex + i] = MPoints[i] as TriangulationPoint; 242 | } 243 | } 244 | 245 | private void AddHole(Contour c) 246 | { 247 | // no checking is done here as we rely on InitializeHoles for that 248 | c._parent = this; 249 | _holes.Add(c); 250 | } 251 | 252 | 253 | /// 254 | /// returns number of holes that are actually holes, including all children of children, etc. Does NOT 255 | /// include holes that are not actually holes. For example, if the parent is not a hole and this contour has 256 | /// a hole that contains a hole, then the number of holes returned would be 2 - one for the current hole (because 257 | /// the parent is NOT a hole and thus this hole IS a hole), and 1 for the child of the child. 258 | /// 259 | /// 260 | /// 261 | public int GetNumHoles(bool parentIsHole) 262 | { 263 | return (parentIsHole ? 0 : 1) + _holes.Sum(c => c.GetNumHoles(!parentIsHole)); 264 | } 265 | 266 | /// 267 | /// returns the basic number of child holes of THIS contour, not including any children of children, etc nor 268 | /// examining whether any children are actual holes. 269 | /// 270 | /// 271 | private int GetNumHoles() 272 | { 273 | return _holes.Count; 274 | } 275 | 276 | private Contour GetHole(int idx) 277 | { 278 | if (idx < 0 || idx >= _holes.Count) 279 | { 280 | return null; 281 | } 282 | 283 | return _holes[idx]; 284 | } 285 | 286 | 287 | public void GetActualHoles(bool parentIsHole, ref List holes) 288 | { 289 | if (parentIsHole) 290 | { 291 | holes.Add(this); 292 | } 293 | 294 | foreach (Contour c in _holes) 295 | { 296 | c.GetActualHoles(!parentIsHole, ref holes); 297 | } 298 | } 299 | 300 | 301 | public List.Enumerator GetHoleEnumerator() 302 | { 303 | return _holes.GetEnumerator(); 304 | } 305 | 306 | 307 | public void InitializeHoles(ConstrainedPointSet cps) 308 | { 309 | InitializeHoles(_holes, this, cps); 310 | foreach (Contour c in _holes) 311 | { 312 | c.InitializeHoles(cps); 313 | } 314 | } 315 | 316 | 317 | public static void InitializeHoles(List holes, ITriangulatable parent, ConstrainedPointSet cps) 318 | { 319 | int numHoles = holes.Count; 320 | int holeIdx = 0; 321 | 322 | // pass 1 - remove duplicates 323 | while (holeIdx < numHoles) 324 | { 325 | int hole2Idx = holeIdx + 1; 326 | while (hole2Idx < numHoles) 327 | { 328 | bool bSamePolygon = PolygonUtil.PolygonsAreSame2D(holes[holeIdx], holes[hole2Idx]); 329 | if (bSamePolygon) 330 | { 331 | // remove one of them 332 | holes.RemoveAt(hole2Idx); 333 | --numHoles; 334 | } 335 | else 336 | { 337 | ++hole2Idx; 338 | } 339 | } 340 | ++holeIdx; 341 | } 342 | 343 | // pass 2: Intersections and Containment 344 | holeIdx = 0; 345 | while (holeIdx < numHoles) 346 | { 347 | bool bIncrementHoleIdx = true; 348 | int hole2Idx = holeIdx + 1; 349 | while (hole2Idx < numHoles) 350 | { 351 | if (PolygonUtil.PolygonContainsPolygon(holes[holeIdx], holes[holeIdx].Bounds, holes[hole2Idx], holes[hole2Idx].Bounds, false)) 352 | { 353 | holes[holeIdx].AddHole(holes[hole2Idx]); 354 | holes.RemoveAt(hole2Idx); 355 | --numHoles; 356 | } 357 | else if (PolygonUtil.PolygonContainsPolygon(holes[hole2Idx], holes[hole2Idx].Bounds, holes[holeIdx], holes[holeIdx].Bounds, false)) 358 | { 359 | holes[hole2Idx].AddHole(holes[holeIdx]); 360 | holes.RemoveAt(holeIdx); 361 | --numHoles; 362 | bIncrementHoleIdx = false; 363 | break; 364 | } 365 | else 366 | { 367 | bool bIntersect = PolygonUtil.PolygonsIntersect2D(holes[holeIdx], holes[holeIdx].Bounds, holes[hole2Idx], holes[hole2Idx].Bounds); 368 | if (bIntersect) 369 | { 370 | // this is actually an error condition 371 | // fix by merging hole1 and hole2 into hole1 (including the holes inside hole2!) and delete hole2 372 | // Then, because hole1 is now changed, restart it's check. 373 | PolygonOperationContext ctx = new PolygonOperationContext(); 374 | if (!ctx.Init(PolygonUtil.PolyOperation.Union | PolygonUtil.PolyOperation.Intersect, holes[holeIdx], holes[hole2Idx])) 375 | { 376 | if (ctx.Error == PolygonUtil.PolyUnionError.Poly1InsidePoly2) 377 | { 378 | holes[hole2Idx].AddHole(holes[holeIdx]); 379 | holes.RemoveAt(holeIdx); 380 | --numHoles; 381 | bIncrementHoleIdx = false; 382 | break; 383 | } 384 | else 385 | { 386 | throw new Exception("PolygonOperationContext.Init had an error during initialization"); 387 | } 388 | } 389 | PolygonUtil.PolyUnionError pue = PolygonUtil.PolygonOperation(ctx); 390 | if (pue == PolygonUtil.PolyUnionError.None) 391 | { 392 | Point2DList union = ctx.Union; 393 | Point2DList intersection = ctx.Intersect; 394 | 395 | // create a new contour for the union 396 | Contour c = new Contour(parent); 397 | c.AddRange(union); 398 | c.WindingOrder = WindingOrderType.Default; 399 | 400 | // add children from both of the merged contours 401 | int numChildHoles = holes[holeIdx].GetNumHoles(); 402 | for(int i = 0; i < numChildHoles; ++i) 403 | { 404 | c.AddHole(holes[holeIdx].GetHole(i)); 405 | } 406 | numChildHoles = holes[hole2Idx].GetNumHoles(); 407 | for (int i = 0; i < numChildHoles; ++i) 408 | { 409 | c.AddHole(holes[hole2Idx].GetHole(i)); 410 | } 411 | 412 | // make sure we preserve the contours of the intersection 413 | Contour cInt = new Contour(c); 414 | cInt.AddRange(intersection); 415 | cInt.WindingOrder = WindingOrderType.Default; 416 | c.AddHole(cInt); 417 | 418 | // replace the current contour with the merged contour 419 | holes[holeIdx] = c; 420 | 421 | // toss the second contour 422 | holes.RemoveAt(hole2Idx); 423 | --numHoles; 424 | 425 | // current hole is "examined", so move to the next one 426 | hole2Idx = holeIdx + 1; 427 | } 428 | else 429 | { 430 | throw new Exception("PolygonOperation had an error!"); 431 | } 432 | } 433 | else 434 | { 435 | ++hole2Idx; 436 | } 437 | } 438 | } 439 | if (bIncrementHoleIdx) 440 | { 441 | ++holeIdx; 442 | } 443 | } 444 | 445 | numHoles = holes.Count; 446 | holeIdx = 0; 447 | while (holeIdx < numHoles) 448 | { 449 | int numPoints = holes[holeIdx].Count; 450 | for (int i = 0; i < numPoints; ++i) 451 | { 452 | int j = holes[holeIdx].NextIndex(i); 453 | uint constraintCode = TriangulationConstraint.CalculateContraintCode(holes[holeIdx][i], holes[holeIdx][j]); 454 | TriangulationConstraint tc; 455 | if (!cps.TryGetConstraint(constraintCode, out tc)) 456 | { 457 | tc = new TriangulationConstraint(holes[holeIdx][i], holes[holeIdx][j]); 458 | cps.AddConstraint(tc); 459 | } 460 | 461 | // replace the points in the holes with valid points 462 | if (holes[holeIdx][i].VertexCode == tc.P.VertexCode) 463 | { 464 | holes[holeIdx][i] = tc.P; 465 | } 466 | else if (holes[holeIdx][j].VertexCode == tc.P.VertexCode) 467 | { 468 | holes[holeIdx][j] = tc.P; 469 | } 470 | if (holes[holeIdx][i].VertexCode == tc.Q.VertexCode) 471 | { 472 | holes[holeIdx][i] = tc.Q; 473 | } 474 | else if (holes[holeIdx][j].VertexCode == tc.Q.VertexCode) 475 | { 476 | holes[holeIdx][j] = tc.Q; 477 | } 478 | } 479 | ++holeIdx; 480 | } 481 | } 482 | 483 | 484 | public void Prepare(TriangulationContext tcx) 485 | { 486 | throw new NotImplementedException("PolyHole.Prepare should never get called"); 487 | } 488 | 489 | 490 | public void AddTriangle(DelaunayTriangle t) 491 | { 492 | throw new NotImplementedException("PolyHole.AddTriangle should never get called"); 493 | } 494 | 495 | 496 | public void AddTriangles(IEnumerable list) 497 | { 498 | throw new NotImplementedException("PolyHole.AddTriangles should never get called"); 499 | } 500 | 501 | 502 | public void ClearTriangles() 503 | { 504 | throw new NotImplementedException("PolyHole.ClearTriangles should never get called"); 505 | } 506 | 507 | 508 | public Point2D FindPointInContour() 509 | { 510 | if (Count < 3) 511 | { 512 | return null; 513 | } 514 | 515 | // first try the simple approach: 516 | Point2D p = GetCentroid(); 517 | if (IsPointInsideContour(p)) 518 | { 519 | return p; 520 | } 521 | 522 | // brute force it... 523 | Random random = new Random(); 524 | while (true) 525 | { 526 | p.X = (random.NextDouble() * (MaxX - MinX)) + MinX; 527 | p.Y = (random.NextDouble() * (MaxY - MinY)) + MinY; 528 | if (IsPointInsideContour(p)) 529 | { 530 | return p; 531 | } 532 | } 533 | } 534 | 535 | private bool IsPointInsideContour(Point2D p) 536 | { 537 | if (PolygonUtil.PointInPolygon2D(this, p)) 538 | return _holes.All(c => !c.IsPointInsideContour(p)); 539 | 540 | return false; 541 | } 542 | 543 | } 544 | } 545 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Polygon/Polygon.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | // Changes from the Java version 33 | // Polygon constructors sprused up, checks for 3+ polys 34 | // Naming of everything 35 | // getTriangulationMode() -> TriangulationMode { get; } 36 | // Exceptions replaced 37 | // Future possibilities 38 | // We have a lot of Add/Clear methods -- we may prefer to just expose the container 39 | // Some self-explanatory methods may deserve commenting anyways 40 | 41 | using System; 42 | using System.Collections.Generic; 43 | using System.Linq; 44 | using Poly2Tri.Triangulation.Delaunay; 45 | using Poly2Tri.Utility; 46 | 47 | namespace Poly2Tri.Triangulation.Polygon 48 | { 49 | public class Polygon : Point2DList, ITriangulatable, IEnumerable, IList 50 | { 51 | // ITriangulatable Implementation 52 | private readonly Dictionary _pointMap = new Dictionary(); 53 | public IList Points { get { return this; } } 54 | private List _triangles; 55 | public IList Triangles { get { return _triangles; } } 56 | public TriangulationMode TriangulationMode { get { return TriangulationMode.Polygon; } } 57 | public string FileName { get; set; } 58 | public bool DisplayFlipX { get; set; } 59 | public bool DisplayFlipY { get; set; } 60 | public float DisplayRotate { get; set; } 61 | private double _precision = TriangulationPoint.VERTEX_CODE_DEFAULT_PRECISION; 62 | public double Precision { get { return _precision; } set { _precision = value; } } 63 | public double MinX { get { return BoundingBox.MinX; } } 64 | public double MaxX { get { return BoundingBox.MaxX; } } 65 | public double MinY { get { return BoundingBox.MinY; } } 66 | public double MaxY { get { return BoundingBox.MaxY; } } 67 | public Rect2D Bounds { get { return BoundingBox; } } 68 | 69 | // Point2DList overrides 70 | public new TriangulationPoint this[int index] 71 | { 72 | get { return MPoints[index] as TriangulationPoint; } 73 | set { MPoints[index] = value; } 74 | } 75 | 76 | // Polygon Implementation 77 | private List Holes { get; set; } 78 | private PolygonPoint _last; 79 | 80 | 81 | 82 | /// 83 | /// Create a polygon from a list of at least 3 points with no duplicates. 84 | /// 85 | /// A list of unique points 86 | private Polygon(IList points) 87 | { 88 | if (points.Count < 3) 89 | { 90 | throw new ArgumentException("List has fewer than 3 points", "points"); 91 | } 92 | 93 | AddRange(points, WindingOrderType.Unknown); 94 | } 95 | 96 | 97 | /// 98 | /// Create a polygon from a list of at least 3 points with no duplicates. 99 | /// 100 | /// A list of unique points. 101 | public Polygon(IEnumerable points) 102 | : this((points as IList) ?? points.ToArray()) 103 | {} 104 | 105 | 106 | /// 107 | /// Create a polygon from a list of at least 3 points with no duplicates. 108 | /// 109 | /// A list of unique points. 110 | public Polygon(params PolygonPoint[] points) 111 | : this((IList)points) 112 | {} 113 | 114 | 115 | IEnumerator IEnumerable.GetEnumerator() 116 | { 117 | return MPoints.Cast().GetEnumerator(); 118 | } 119 | 120 | 121 | public int IndexOf(TriangulationPoint p) 122 | { 123 | return MPoints.IndexOf(p); 124 | } 125 | 126 | 127 | public override void Add(Point2D p) 128 | { 129 | Add(p, -1, true); 130 | } 131 | 132 | 133 | public void Add(TriangulationPoint p) 134 | { 135 | Add(p, -1, true); 136 | } 137 | 138 | 139 | public void Add(PolygonPoint p) 140 | { 141 | Add(p, -1, true); 142 | } 143 | 144 | 145 | protected override void Add(Point2D p, int idx, bool bCalcWindingOrderAndEpsilon) 146 | { 147 | TriangulationPoint pt = p as TriangulationPoint; 148 | if (pt == null) 149 | { 150 | // we only store TriangulationPoints and PolygonPoints in this class 151 | return; 152 | } 153 | 154 | // do not insert duplicate points 155 | if (_pointMap.ContainsKey(pt.VertexCode)) 156 | { 157 | return; 158 | } 159 | _pointMap.Add(pt.VertexCode, pt); 160 | 161 | base.Add(p, idx, bCalcWindingOrderAndEpsilon); 162 | 163 | PolygonPoint pp = p as PolygonPoint; 164 | if (pp != null) 165 | { 166 | pp.Previous = _last; 167 | if (_last != null) 168 | { 169 | pp.Next = _last.Next; 170 | _last.Next = pp; 171 | } 172 | _last = pp; 173 | } 174 | } 175 | 176 | private void AddRange(IList points, WindingOrderType windingOrder) 177 | { 178 | if (points == null || points.Count < 1) 179 | return; 180 | 181 | if (WindingOrder == WindingOrderType.Unknown && Count == 0) 182 | WindingOrder = windingOrder; 183 | 184 | int numPoints = points.Count; 185 | bool bReverseReadOrder = (WindingOrder != WindingOrderType.Unknown) && (windingOrder != WindingOrderType.Unknown) && (WindingOrder != windingOrder); 186 | for (int i = 0; i < numPoints; ++i) 187 | { 188 | int idx = i; 189 | if (bReverseReadOrder) 190 | { 191 | idx = points.Count - i - 1; 192 | } 193 | Add(points[idx], -1, false); 194 | } 195 | if (WindingOrder == WindingOrderType.Unknown) 196 | { 197 | WindingOrder = CalculateWindingOrder(); 198 | } 199 | Epsilon = CalculateEpsilon(); 200 | } 201 | 202 | 203 | public void AddRange(IList points, WindingOrderType windingOrder) 204 | { 205 | if (points == null || points.Count < 1) 206 | { 207 | return; 208 | } 209 | 210 | if (WindingOrder == WindingOrderType.Unknown && Count == 0) 211 | WindingOrder = windingOrder; 212 | 213 | int numPoints = points.Count; 214 | bool bReverseReadOrder = (WindingOrder != WindingOrderType.Unknown) && (windingOrder != WindingOrderType.Unknown) && (WindingOrder != windingOrder); 215 | for (int i = 0; i < numPoints; ++i) 216 | { 217 | int idx = i; 218 | if (bReverseReadOrder) 219 | { 220 | idx = points.Count - i - 1; 221 | } 222 | Add(points[idx], -1, false); 223 | } 224 | if (WindingOrder == WindingOrderType.Unknown) 225 | WindingOrder = CalculateWindingOrder(); 226 | 227 | Epsilon = CalculateEpsilon(); 228 | } 229 | 230 | 231 | public void Insert(int idx, TriangulationPoint p) 232 | { 233 | Add(p, idx, true); 234 | } 235 | 236 | 237 | public bool Remove(TriangulationPoint p) 238 | { 239 | return base.Remove(p); 240 | } 241 | 242 | 243 | /// 244 | /// Removes a point from the polygon. Note this can be a somewhat expensive operation 245 | /// as it must recalculate the bounding area from scratch. 246 | /// 247 | /// 248 | public void RemovePoint(PolygonPoint p) 249 | { 250 | PolygonPoint next = p.Next; 251 | PolygonPoint prev = p.Previous; 252 | prev.Next = next; 253 | next.Previous = prev; 254 | MPoints.Remove(p); 255 | 256 | BoundingBox = new Rect2D(); 257 | foreach (var point2D in MPoints) 258 | BoundingBox = BoundingBox.AddPoint(point2D); 259 | } 260 | 261 | 262 | 263 | public bool Contains(TriangulationPoint p) 264 | { 265 | return MPoints.Contains(p); 266 | } 267 | 268 | 269 | public void CopyTo(TriangulationPoint[] array, int arrayIndex) 270 | { 271 | int numElementsToCopy = Math.Min(Count, array.Length - arrayIndex); 272 | for (int i = 0; i < numElementsToCopy; ++i) 273 | { 274 | array[arrayIndex + i] = MPoints[i] as TriangulationPoint; 275 | } 276 | } 277 | 278 | /// 279 | /// Add a hole to the polygon. 280 | /// 281 | /// A subtraction polygon fully contained inside this polygon. 282 | public void AddHole(Polygon poly) 283 | { 284 | if (Holes == null) 285 | { 286 | Holes = new List(); 287 | } 288 | Holes.Add(poly); 289 | // XXX: tests could be made here to be sure it is fully inside 290 | // addSubtraction( poly.getPoints() ); 291 | } 292 | 293 | 294 | public void AddTriangle(DelaunayTriangle t) 295 | { 296 | _triangles.Add(t); 297 | } 298 | 299 | 300 | public void AddTriangles(IEnumerable list) 301 | { 302 | _triangles.AddRange(list); 303 | } 304 | 305 | 306 | public void ClearTriangles() 307 | { 308 | if (_triangles != null) 309 | { 310 | _triangles.Clear(); 311 | } 312 | } 313 | 314 | 315 | public bool IsPointInside(TriangulationPoint p) 316 | { 317 | return PolygonUtil.PointInPolygon2D(this, p); 318 | } 319 | 320 | 321 | /// 322 | /// Creates constraints and populates the context with points 323 | /// 324 | /// The context 325 | public void Prepare(TriangulationContext tcx) 326 | { 327 | if (_triangles == null) 328 | { 329 | _triangles = new List(MPoints.Count); 330 | } 331 | else 332 | { 333 | _triangles.Clear(); 334 | } 335 | 336 | // Outer constraints 337 | for (int i = 0; i < MPoints.Count - 1; i++) 338 | { 339 | //tcx.NewConstraint(mPoints[i], mPoints[i + 1]); 340 | tcx.NewConstraint(this[i], this[i + 1]); 341 | } 342 | tcx.NewConstraint(this[0], this[Count - 1]); 343 | tcx.Points.AddRange(this); 344 | 345 | // Hole constraints 346 | if (Holes != null) 347 | { 348 | foreach (Polygon p in Holes) 349 | { 350 | for (int i = 0; i < p.MPoints.Count - 1; i++) 351 | { 352 | tcx.NewConstraint(p[i], p[i + 1]); 353 | } 354 | tcx.NewConstraint(p[0], p[p.Count - 1]); 355 | tcx.Points.AddRange(p); 356 | } 357 | } 358 | } 359 | } 360 | } 361 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Polygon/PolygonPoint.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | // Changes from the Java version 33 | // Replaced get/set Next/Previous with attributes 34 | // Future possibilities 35 | // Documentation! 36 | 37 | 38 | namespace Poly2Tri.Triangulation.Polygon 39 | { 40 | public class PolygonPoint : TriangulationPoint 41 | { 42 | public PolygonPoint(double x, double y) : base(x, y) { } 43 | 44 | public PolygonPoint Next { get; set; } 45 | public PolygonPoint Previous { get; set; } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Sets/ConstrainedPointSet.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using System.Collections.Generic; 33 | using System.Linq; 34 | using Poly2Tri.Triangulation.Delaunay; 35 | using Poly2Tri.Triangulation.Polygon; 36 | using Poly2Tri.Utility; 37 | 38 | namespace Poly2Tri.Triangulation.Sets 39 | { 40 | /* 41 | * Extends the PointSet by adding some Constraints on how it will be triangulated 42 | * A constraint defines an edge between two points in the set, these edges can not 43 | * be crossed. They will be enforced triangle edges after a triangulation. 44 | * 45 | * 46 | * @author Thomas Åhlén, thahlen@gmail.com 47 | * @author Lee Wilson, lwilson@ea.com 48 | */ 49 | public class ConstrainedPointSet : PointSet 50 | { 51 | private readonly Dictionary _constraintMap = new Dictionary(); 52 | private readonly List _holes = new List(); 53 | 54 | public override TriangulationMode TriangulationMode { get { return TriangulationMode.Constrained; } } 55 | 56 | 57 | public ConstrainedPointSet(IEnumerable bounds) 58 | : base(bounds) 59 | { 60 | AddBoundaryConstraints(); 61 | } 62 | 63 | public ConstrainedPointSet(IEnumerable bounds, IEnumerable constraints) 64 | : base(bounds) 65 | { 66 | AddBoundaryConstraints(); 67 | AddConstraints(constraints); 68 | } 69 | 70 | public ConstrainedPointSet(IList bounds, ICollection indices) 71 | : base(bounds) 72 | { 73 | AddBoundaryConstraints(); 74 | List l = new List(); 75 | for (int i = 0; i < indices.Count; i += 2) 76 | { 77 | TriangulationConstraint tc = new TriangulationConstraint(bounds[i], bounds[i + 1]); 78 | l.Add(tc); 79 | } 80 | AddConstraints(l); 81 | } 82 | 83 | private void AddBoundaryConstraints() 84 | { 85 | TriangulationPoint ptLL; 86 | TriangulationPoint ptLR; 87 | TriangulationPoint ptUR; 88 | TriangulationPoint ptUL; 89 | if (!TryGetPoint(MinX, MinY, out ptLL)) 90 | { 91 | ptLL = new TriangulationPoint(MinX, MinY); 92 | Add(ptLL); 93 | } 94 | if (!TryGetPoint(MaxX, MinY, out ptLR)) 95 | { 96 | ptLR = new TriangulationPoint(MaxX, MinY); 97 | Add(ptLR); 98 | } 99 | if (!TryGetPoint(MaxX, MaxY, out ptUR)) 100 | { 101 | ptUR = new TriangulationPoint(MaxX, MaxY); 102 | Add(ptUR); 103 | } 104 | if (!TryGetPoint(MinX, MaxY, out ptUL)) 105 | { 106 | ptUL = new TriangulationPoint(MinX, MaxY); 107 | Add(ptUL); 108 | } 109 | TriangulationConstraint tcLLtoLR = new TriangulationConstraint(ptLL, ptLR); 110 | AddConstraint(tcLLtoLR); 111 | TriangulationConstraint tcLRtoUR = new TriangulationConstraint(ptLR, ptUR); 112 | AddConstraint(tcLRtoUR); 113 | TriangulationConstraint tcURtoUL = new TriangulationConstraint(ptUR, ptUL); 114 | AddConstraint(tcURtoUL); 115 | TriangulationConstraint tcULtoLL = new TriangulationConstraint(ptUL, ptLL); 116 | AddConstraint(tcULtoLL); 117 | } 118 | 119 | 120 | public override void Add(Point2D p) 121 | { 122 | Add(p as TriangulationPoint, -1, true); 123 | } 124 | 125 | 126 | public override void Add(TriangulationPoint p) 127 | { 128 | Add(p, -1, true); 129 | } 130 | 131 | 132 | public override bool AddRange(IEnumerable points) 133 | { 134 | bool bOk = true; 135 | foreach (TriangulationPoint p in points) 136 | { 137 | bOk = Add(p, -1, true) && bOk; 138 | } 139 | 140 | return bOk; 141 | } 142 | 143 | 144 | // Assumes that points being passed in the list are connected and form a polygon. 145 | // Note that some error checking is done for robustness, but for the most part, 146 | // we have to rely on the user to feed us "correct" data 147 | public bool AddHole(List points) 148 | { 149 | if (points == null) 150 | { 151 | return false; 152 | } 153 | 154 | //// split our self-intersection sections into their own lists 155 | List pts = new List(); 156 | int listIdx = 0; 157 | { 158 | Contour c = new Contour(this, points, WindingOrderType.Unknown); 159 | pts.Add(c); 160 | 161 | // only constrain the points if we actually HAVE a bounding rect 162 | if (MPoints.Count > 1) 163 | { 164 | // constrain the points to bounding rect 165 | int numPoints = pts[listIdx].Count; 166 | for (int i = 0; i < numPoints; ++i) 167 | { 168 | ConstrainPointToBounds(pts[listIdx][i]); 169 | } 170 | } 171 | } 172 | 173 | while (listIdx < pts.Count) 174 | { 175 | // simple sanity checking - remove duplicate coincident points before 176 | // we check the polygon: fast, simple algorithm that eliminate lots of problems 177 | // that only more expensive checks will find 178 | pts[listIdx].RemoveDuplicateNeighborPoints(); 179 | pts[listIdx].WindingOrder = WindingOrderType.Default; 180 | 181 | bool bListOk = true; 182 | PolygonError err = pts[listIdx].CheckPolygon(); 183 | while (bListOk && err != PolygonError.None) 184 | { 185 | if ((err & PolygonError.NotEnoughVertices) == PolygonError.NotEnoughVertices) 186 | { 187 | bListOk = false; 188 | continue; 189 | } 190 | if ((err & PolygonError.NotSimple) == PolygonError.NotSimple) 191 | { 192 | // split the polygons, remove the current list and add the resulting list to the end 193 | //List l = TriangulationUtil.SplitSelfIntersectingPolygon(pts[listIdx], pts[listIdx].Epsilon); 194 | IEnumerable l = PolygonUtil.SplitComplexPolygon(pts[listIdx], pts[listIdx].Epsilon); 195 | pts.RemoveAt(listIdx); 196 | foreach (Point2DList newList in l) 197 | { 198 | Contour c = new Contour(this); 199 | c.AddRange(newList); 200 | pts.Add(c); 201 | } 202 | err = pts[listIdx].CheckPolygon(); 203 | continue; 204 | } 205 | if ((err & PolygonError.Degenerate) == PolygonError.Degenerate) 206 | { 207 | pts[listIdx].Simplify(Epsilon); 208 | err = pts[listIdx].CheckPolygon(); 209 | continue; 210 | //err &= ~(PolygonError.Degenerate); 211 | //if (pts[listIdx].Count < 3) 212 | //{ 213 | // err |= PolygonError.NotEnoughVertices; 214 | // bListOK = false; 215 | // continue; 216 | //} 217 | } 218 | if ((err & PolygonError.AreaTooSmall) == PolygonError.AreaTooSmall || 219 | (err & PolygonError.SidesTooCloseToParallel) == PolygonError.SidesTooCloseToParallel || 220 | (err & PolygonError.TooThin) == PolygonError.TooThin || 221 | (err & PolygonError.Unknown) == PolygonError.Unknown) 222 | { 223 | bListOk = false; 224 | } 225 | // non-convex polygons are ok 226 | //if ((err & PolygonError.NotConvex) == PolygonError.NotConvex) 227 | //{ 228 | //} 229 | } 230 | if (!bListOk && pts[listIdx].Count != 2) 231 | { 232 | pts.RemoveAt(listIdx); 233 | } 234 | else 235 | { 236 | ++listIdx; 237 | } 238 | } 239 | 240 | bool bOk = true; 241 | listIdx = 0; 242 | while (listIdx < pts.Count) 243 | { 244 | int numPoints = pts[listIdx].Count; 245 | if (numPoints < 2) 246 | { 247 | // should not be possible by this point... 248 | ++listIdx; 249 | bOk = false; 250 | continue; 251 | } 252 | else if (numPoints == 2) 253 | { 254 | uint constraintCode = TriangulationConstraint.CalculateContraintCode(pts[listIdx][0], pts[listIdx][1]); 255 | TriangulationConstraint tc; 256 | if (!_constraintMap.TryGetValue(constraintCode, out tc)) 257 | { 258 | tc = new TriangulationConstraint(pts[listIdx][0], pts[listIdx][1]); 259 | AddConstraint(tc); 260 | } 261 | } 262 | else 263 | { 264 | Contour ph = new Contour(this, pts[listIdx], WindingOrderType.Unknown) { 265 | WindingOrder = WindingOrderType.Default, 266 | }; 267 | _holes.Add(ph); 268 | } 269 | ++listIdx; 270 | } 271 | 272 | return bOk; 273 | } 274 | 275 | 276 | // this method adds constraints singly and does not assume that they form a contour 277 | // If you are trying to add a "series" or edges (or "contour"), use AddHole instead. 278 | private void AddConstraints(IEnumerable constraints) 279 | { 280 | if (constraints == null) 281 | return; 282 | 283 | foreach (TriangulationConstraint tc in constraints) 284 | { 285 | if (ConstrainPointToBounds(tc.P) || ConstrainPointToBounds(tc.Q)) 286 | { 287 | tc.CalculateContraintCode(); 288 | } 289 | 290 | TriangulationConstraint tcTmp; 291 | if (!_constraintMap.TryGetValue(tc.ConstraintCode, out tcTmp)) 292 | { 293 | tcTmp = tc; 294 | AddConstraint(tcTmp); 295 | } 296 | } 297 | } 298 | 299 | 300 | public void AddConstraint(TriangulationConstraint tc) 301 | { 302 | if (tc == null || tc.P == null || tc.Q == null) 303 | { 304 | return; 305 | } 306 | 307 | // If we already have this constraint, then there's nothing to do. Since we already have 308 | // a valid constraint in the map with the same ConstraintCode, then we're guaranteed that 309 | // the points are also valid (and have the same coordinates as the ones being passed in with 310 | // this constrain). Return true to indicate that we successfully "added" the constraint 311 | if (_constraintMap.ContainsKey(tc.ConstraintCode)) 312 | { 313 | return; 314 | } 315 | 316 | // Make sure the constraint is not using points that are duplicates of ones already stored 317 | // If it is, replace the Constraint Points with the points already stored. 318 | TriangulationPoint p; 319 | if (TryGetPoint(tc.P.X, tc.P.Y, out p)) 320 | { 321 | tc.P = p; 322 | } 323 | else 324 | { 325 | Add(tc.P); 326 | } 327 | 328 | if (TryGetPoint(tc.Q.X, tc.Q.Y, out p)) 329 | { 330 | tc.Q = p; 331 | } 332 | else 333 | { 334 | Add(tc.Q); 335 | } 336 | 337 | _constraintMap.Add(tc.ConstraintCode, tc); 338 | } 339 | 340 | 341 | public bool TryGetConstraint(uint constraintCode, out TriangulationConstraint tc) 342 | { 343 | return _constraintMap.TryGetValue(constraintCode, out tc); 344 | } 345 | 346 | 347 | public int GetNumConstraints() 348 | { 349 | return _constraintMap.Count; 350 | } 351 | 352 | 353 | public Dictionary.Enumerator GetConstraintEnumerator() 354 | { 355 | return _constraintMap.GetEnumerator(); 356 | } 357 | 358 | 359 | public int GetNumHoles() 360 | { 361 | return _holes.Sum(c => c.GetNumHoles(false)); 362 | } 363 | 364 | public Contour GetHole(int idx) 365 | { 366 | if (idx < 0 || idx >= _holes.Count) 367 | { 368 | return null; 369 | } 370 | 371 | return _holes[idx]; 372 | } 373 | 374 | 375 | public int GetActualHoles(out List holes) 376 | { 377 | holes = new List(); 378 | foreach (Contour c in _holes) 379 | { 380 | c.GetActualHoles(false, ref holes); 381 | } 382 | 383 | return holes.Count; 384 | } 385 | 386 | private void InitializeHoles() 387 | { 388 | Contour.InitializeHoles(_holes, this, this); 389 | foreach (Contour c in _holes) 390 | { 391 | c.InitializeHoles(this); 392 | } 393 | } 394 | 395 | protected override bool Initialize() 396 | { 397 | InitializeHoles(); 398 | return base.Initialize(); 399 | } 400 | 401 | 402 | public override void Prepare(TriangulationContext tcx) 403 | { 404 | if (!Initialize()) 405 | { 406 | return; 407 | } 408 | 409 | base.Prepare(tcx); 410 | 411 | Dictionary.Enumerator it = _constraintMap.GetEnumerator(); 412 | while (it.MoveNext()) 413 | { 414 | TriangulationConstraint tc = it.Current.Value; 415 | tcx.NewConstraint(tc.P, tc.Q); 416 | } 417 | } 418 | 419 | 420 | public override void AddTriangle(DelaunayTriangle t) 421 | { 422 | Triangles.Add(t); 423 | } 424 | 425 | } 426 | } 427 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Sets/PointSet.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using System; 33 | using System.Collections.Generic; 34 | using System.Linq; 35 | using Poly2Tri.Triangulation.Delaunay; 36 | using Poly2Tri.Utility; 37 | 38 | namespace Poly2Tri.Triangulation.Sets 39 | { 40 | public class PointSet : Point2DList, ITriangulatable, IEnumerable, IList 41 | { 42 | private readonly Dictionary _pointMap = new Dictionary(); 43 | public IList Triangles { get; private set; } 44 | 45 | public string FileName { get; set; } 46 | public bool DisplayFlipX { get; set; } 47 | public bool DisplayFlipY { get; set; } 48 | public float DisplayRotate { get; set; } 49 | 50 | private double _precision = TriangulationPoint.VERTEX_CODE_DEFAULT_PRECISION; 51 | public double Precision { get { return _precision; } set { _precision = value; } } 52 | 53 | public double MinX { get { return BoundingBox.MinX; } } 54 | public double MaxX { get { return BoundingBox.MaxX; } } 55 | public double MinY { get { return BoundingBox.MinY; } } 56 | public double MaxY { get { return BoundingBox.MaxY; } } 57 | public Rect2D Bounds { get { return BoundingBox; } } 58 | 59 | public virtual TriangulationMode TriangulationMode { get { return TriangulationMode.Unconstrained; } } 60 | 61 | public new TriangulationPoint this[int index] 62 | { 63 | get { return MPoints[index] as TriangulationPoint; } 64 | set { MPoints[index] = value; } 65 | } 66 | 67 | protected PointSet(IEnumerable bounds) 68 | { 69 | //Points = new List(); 70 | foreach (TriangulationPoint p in bounds) 71 | { 72 | Add(p, -1, false); 73 | 74 | // Only the initial points are counted toward min/max x/y as they 75 | // are considered to be the boundaries of the point-set 76 | BoundingBox = BoundingBox.AddPoint(p); 77 | } 78 | Epsilon = CalculateEpsilon(); 79 | WindingOrder = WindingOrderType.Unknown; // not valid for a point-set 80 | } 81 | 82 | 83 | IEnumerator IEnumerable.GetEnumerator() 84 | { 85 | return MPoints.Cast().GetEnumerator(); 86 | } 87 | 88 | 89 | public int IndexOf(TriangulationPoint p) 90 | { 91 | return MPoints.IndexOf(p); 92 | } 93 | 94 | 95 | public override void Add(Point2D p) 96 | { 97 | Add(p as TriangulationPoint, -1, false); 98 | } 99 | 100 | public virtual void Add(TriangulationPoint p) 101 | { 102 | Add(p, -1, false); 103 | } 104 | 105 | 106 | protected override void Add(Point2D p, int idx, bool constrainToBounds) 107 | { 108 | Add(p as TriangulationPoint, idx, constrainToBounds); 109 | } 110 | 111 | 112 | protected bool Add(TriangulationPoint p, int idx, bool constrainToBounds) 113 | { 114 | if (p == null) 115 | { 116 | return false; 117 | } 118 | 119 | if (constrainToBounds) 120 | { 121 | ConstrainPointToBounds(p); 122 | } 123 | 124 | // if we already have an instance of the point, then don't bother inserting it again as duplicate points 125 | // will actually cause some real problems later on. Still return true though to indicate that the point 126 | // is successfully "added" 127 | if (_pointMap.ContainsKey(p.VertexCode)) 128 | { 129 | return true; 130 | } 131 | _pointMap.Add(p.VertexCode, p); 132 | 133 | if (idx < 0) 134 | { 135 | MPoints.Add(p); 136 | } 137 | else 138 | { 139 | MPoints.Insert(idx, p); 140 | } 141 | 142 | return true; 143 | } 144 | 145 | protected override void AddRange(IEnumerator iter, WindingOrderType windingOrder) 146 | { 147 | if (iter == null) 148 | { 149 | return; 150 | } 151 | 152 | iter.Reset(); 153 | while (iter.MoveNext()) 154 | { 155 | Add(iter.Current); 156 | } 157 | } 158 | 159 | 160 | public virtual bool AddRange(IEnumerable points) 161 | { 162 | bool bOk = true; 163 | foreach (TriangulationPoint p in points) 164 | { 165 | bOk = Add(p, -1, false) && bOk; 166 | } 167 | 168 | return bOk; 169 | } 170 | 171 | protected bool TryGetPoint(double x, double y, out TriangulationPoint p) 172 | { 173 | uint vc = TriangulationPoint.CreateVertexCode(x, y, Precision); 174 | if (_pointMap.TryGetValue(vc, out p)) 175 | { 176 | return true; 177 | } 178 | 179 | return false; 180 | } 181 | 182 | public void Insert(int idx, TriangulationPoint item) 183 | { 184 | MPoints.Insert(idx, item); 185 | } 186 | 187 | 188 | public override bool Remove(Point2D p) 189 | { 190 | return MPoints.Remove(p); 191 | } 192 | 193 | 194 | public bool Remove(TriangulationPoint p) 195 | { 196 | return MPoints.Remove(p); 197 | } 198 | 199 | 200 | public override void RemoveAt(int idx) 201 | { 202 | if (idx < 0 || idx >= Count) 203 | { 204 | return; 205 | } 206 | MPoints.RemoveAt(idx); 207 | } 208 | 209 | 210 | public bool Contains(TriangulationPoint p) 211 | { 212 | return MPoints.Contains(p); 213 | } 214 | 215 | 216 | public void CopyTo(TriangulationPoint[] array, int arrayIndex) 217 | { 218 | int numElementsToCopy = Math.Min(Count, array.Length - arrayIndex); 219 | for (int i = 0; i < numElementsToCopy; ++i) 220 | { 221 | array[arrayIndex + i] = MPoints[i] as TriangulationPoint; 222 | } 223 | } 224 | 225 | 226 | // returns true if the point is changed, false if the point is unchanged 227 | protected bool ConstrainPointToBounds(Point2D p) 228 | { 229 | double oldX = p.X; 230 | double oldY = p.Y; 231 | p.X = Math.Max(MinX, p.X); 232 | p.X = Math.Min(MaxX, p.X); 233 | p.Y = Math.Max(MinY, p.Y); 234 | p.Y = Math.Min(MaxY, p.Y); 235 | 236 | // ReSharper disable CompareOfFloatsByEqualityOperator 237 | return (p.X != oldX) || (p.Y != oldY); 238 | // ReSharper restore CompareOfFloatsByEqualityOperator 239 | } 240 | 241 | 242 | protected bool ConstrainPointToBounds(TriangulationPoint p) 243 | { 244 | double oldX = p.X; 245 | double oldY = p.Y; 246 | p.X = Math.Max(MinX, p.X); 247 | p.X = Math.Min(MaxX, p.X); 248 | p.Y = Math.Max(MinY, p.Y); 249 | p.Y = Math.Min(MaxY, p.Y); 250 | 251 | // ReSharper disable CompareOfFloatsByEqualityOperator 252 | return (p.X != oldX) || (p.Y != oldY); 253 | // ReSharper restore CompareOfFloatsByEqualityOperator 254 | } 255 | 256 | 257 | public virtual void AddTriangle(DelaunayTriangle t) 258 | { 259 | Triangles.Add(t); 260 | } 261 | 262 | 263 | public void AddTriangles(IEnumerable list) 264 | { 265 | foreach (var tri in list) 266 | { 267 | AddTriangle(tri); 268 | } 269 | } 270 | 271 | 272 | public void ClearTriangles() 273 | { 274 | Triangles.Clear(); 275 | } 276 | 277 | protected virtual bool Initialize() 278 | { 279 | return true; 280 | } 281 | 282 | 283 | public virtual void Prepare(TriangulationContext tcx) 284 | { 285 | if (Triangles == null) 286 | { 287 | Triangles = new List(Count); 288 | } 289 | else 290 | { 291 | Triangles.Clear(); 292 | } 293 | tcx.Points.AddRange(this); 294 | } 295 | } 296 | } 297 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/TriangulationAlgorithm.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | namespace Poly2Tri.Triangulation 33 | { 34 | public enum TriangulationAlgorithm 35 | { 36 | DTSweep 37 | } 38 | } -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/TriangulationConstraint.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | /** 32 | * Forces a triangle edge between two points p and q 33 | * when triangulating. For example used to enforce 34 | * Polygon Edges during a polygon triangulation. 35 | * 36 | * @author Thomas Åhlén, thahlen@gmail.com 37 | */ 38 | 39 | using System; 40 | using Poly2Tri.Utility; 41 | 42 | namespace Poly2Tri.Triangulation 43 | { 44 | public class Edge 45 | { 46 | public Point2D EdgeStart { get; set; } 47 | public Point2D EdgeEnd { get; set; } 48 | 49 | public Edge() { EdgeStart = null; EdgeEnd = null; } 50 | public Edge(Point2D edgeStart, Point2D edgeEnd) 51 | { 52 | EdgeStart = edgeStart; 53 | EdgeEnd = edgeEnd; 54 | } 55 | } 56 | 57 | 58 | public class TriangulationConstraint : Edge 59 | { 60 | public TriangulationPoint P 61 | { 62 | get { return EdgeStart as TriangulationPoint; } 63 | set 64 | { 65 | if (value != null && !value.Equals(EdgeStart)) 66 | { 67 | EdgeStart = value; 68 | CalculateContraintCode(); 69 | } 70 | } 71 | } 72 | public TriangulationPoint Q 73 | { 74 | get { return EdgeEnd as TriangulationPoint; } 75 | set 76 | { 77 | // Note: intentionally use != instead of !Equals() because we 78 | // WANT to compare pointer values here rather than VertexCode values 79 | if (value != null && !value.Equals(EdgeEnd)) 80 | { 81 | EdgeEnd = value; 82 | CalculateContraintCode(); 83 | } 84 | } 85 | } 86 | 87 | public uint ConstraintCode { get; private set; } 88 | 89 | /// 90 | /// Give two points in any order. Will always be ordered so 91 | /// that q.y > p.y and q.x > p.x if same y value 92 | /// 93 | public TriangulationConstraint(Point2D p1, Point2D p2) 94 | { 95 | ConstraintCode = 0; 96 | EdgeStart = p1; 97 | EdgeEnd = p2; 98 | if (p1.Y > p2.Y) 99 | { 100 | EdgeEnd = p1; 101 | EdgeStart = p2; 102 | } 103 | else if (p1.Y == p2.Y) 104 | { 105 | if (p1.X > p2.X) 106 | { 107 | EdgeEnd = p1; 108 | EdgeStart = p2; 109 | } 110 | else if (p1.X == p2.X) 111 | { 112 | // logger.info( "Failed to create constraint {}={}", p1, p2 ); 113 | // throw new DuplicatePointException( p1 + "=" + p2 ); 114 | // return; 115 | } 116 | } 117 | CalculateContraintCode(); 118 | } 119 | 120 | 121 | public override string ToString() 122 | { 123 | return string.Format("[P={0}, Q={1} : {{{2}}}]", P, Q, ConstraintCode); 124 | } 125 | 126 | 127 | public void CalculateContraintCode() 128 | { 129 | ConstraintCode = CalculateContraintCode(P, Q); 130 | } 131 | 132 | 133 | public static uint CalculateContraintCode(TriangulationPoint p, TriangulationPoint q) 134 | { 135 | if (p == null || p == null) 136 | { 137 | throw new ArgumentNullException(); 138 | } 139 | 140 | uint constraintCode = MathUtil.Jenkins32Hash(BitConverter.GetBytes(p.VertexCode), 0); 141 | constraintCode = MathUtil.Jenkins32Hash(BitConverter.GetBytes(q.VertexCode), constraintCode); 142 | 143 | return constraintCode; 144 | } 145 | 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/TriangulationContext.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using System.Collections.Generic; 33 | using Poly2Tri.Triangulation.Delaunay; 34 | using Poly2Tri.Triangulation.Delaunay.Sweep; 35 | 36 | namespace Poly2Tri.Triangulation 37 | { 38 | public abstract class TriangulationContext 39 | { 40 | protected TriangulationDebugContext DebugContext { get; private set; } 41 | public bool IsDebugEnabled { get; protected set; } 42 | 43 | public readonly List Triangles = new List(); 44 | public readonly List Points = new List(200); 45 | public TriangulationMode TriangulationMode { get; private set; } 46 | public ITriangulatable Triangulatable { get; private set; } 47 | 48 | public abstract TriangulationAlgorithm Algorithm { get; } 49 | 50 | protected TriangulationContext(TriangulationDebugContext debug) 51 | { 52 | DebugContext = debug; 53 | } 54 | 55 | public virtual void PrepareTriangulation(ITriangulatable t) 56 | { 57 | Triangulatable = t; 58 | TriangulationMode = t.TriangulationMode; 59 | t.Prepare(this); 60 | 61 | //List constraints = new List(); 62 | 63 | //Console.WriteLine("Points for " + t.FileName + ":"); 64 | //Console.WriteLine("Idx,X,Y,VC,Edges"); 65 | //int numPoints = Points.Count; 66 | //for (int i = 0; i < numPoints; ++i) 67 | //{ 68 | // StringBuilder sb = new StringBuilder(128); 69 | // sb.Append(i.ToString()); 70 | // sb.Append(","); 71 | // sb.Append(Points[i].X.ToString()); 72 | // sb.Append(","); 73 | // sb.Append(Points[i].Y.ToString()); 74 | // sb.Append(","); 75 | // sb.Append(Points[i].VertexCode.ToString()); 76 | // int numEdges = (Points[i].Edges != null) ? Points[i].Edges.Count : 0; 77 | // for (int j = 0; j < numEdges; ++j) 78 | // { 79 | // TriangulationConstraint tc = Points[i].Edges[j]; 80 | // sb.Append(","); 81 | // sb.Append(tc.ConstraintCode.ToString()); 82 | // constraints.Add(tc); 83 | // } 84 | // Console.WriteLine(sb.ToString()); 85 | //} 86 | 87 | //int idx = 0; 88 | //Console.WriteLine("Constraints " + t.FileName + ":"); 89 | //Console.WriteLine("EdgeIdx,Px,Py,PVC,Qx,Qy,QVC,ConstraintCode,Owner"); 90 | //foreach (TriangulationConstraint tc in constraints) 91 | //{ 92 | // StringBuilder sb = new StringBuilder(128); 93 | 94 | // sb.Append(idx.ToString()); 95 | // sb.Append(","); 96 | // sb.Append(tc.P.X.ToString()); 97 | // sb.Append(","); 98 | // sb.Append(tc.P.Y.ToString()); 99 | // sb.Append(","); 100 | // sb.Append(tc.P.VertexCode.ToString()); 101 | // sb.Append(","); 102 | // sb.Append(tc.Q.X.ToString()); 103 | // sb.Append(","); 104 | // sb.Append(tc.Q.Y.ToString()); 105 | // sb.Append(","); 106 | // sb.Append(tc.Q.VertexCode.ToString()); 107 | // sb.Append(","); 108 | // sb.Append(tc.ConstraintCode.ToString()); 109 | // sb.Append(","); 110 | // if (tc.Q.HasEdge(tc.P)) 111 | // { 112 | // sb.Append("Q"); 113 | // } 114 | // else 115 | // { 116 | // sb.Append("P"); 117 | // } 118 | // Console.WriteLine(sb.ToString()); 119 | 120 | // ++idx; 121 | //} 122 | } 123 | 124 | 125 | // ReSharper disable UnusedMethodReturnValue.Global 126 | public abstract DTSweepConstraint NewConstraint(TriangulationPoint a, TriangulationPoint b); 127 | // ReSharper restore UnusedMethodReturnValue.Global 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/TriangulationDebugContext.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | namespace Poly2Tri.Triangulation 33 | { 34 | public abstract class TriangulationDebugContext 35 | { 36 | public abstract void Clear(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/TriangulationMode.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | namespace Poly2Tri.Triangulation 33 | { 34 | public enum TriangulationMode 35 | { 36 | Unconstrained, 37 | Constrained, 38 | Polygon 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/TriangulationPoint.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using System; 33 | using System.Collections.Generic; 34 | using System.Linq; 35 | using Poly2Tri.Triangulation.Delaunay.Sweep; 36 | using Poly2Tri.Utility; 37 | 38 | namespace Poly2Tri.Triangulation 39 | { 40 | 41 | public class TriangulationPoint : Point2D, IEquatable 42 | { 43 | public const double VERTEX_CODE_DEFAULT_PRECISION = 3.0; 44 | 45 | public override double X 46 | { 47 | get { return base.X; } 48 | set 49 | { 50 | // ReSharper disable CompareOfFloatsByEqualityOperator 51 | if (value != base.X) 52 | // ReSharper restore CompareOfFloatsByEqualityOperator 53 | { 54 | base.X = value; 55 | VertexCode = CreateVertexCode(base.X, base.Y, VERTEX_CODE_DEFAULT_PRECISION); 56 | 57 | // Technically, we should change the ConstraintCodes of any edges that contain this point. 58 | // We don't for 2 reasons: 59 | // 1) Currently the only time we care about Vertex/Constraint Codes is when entering data in the point-set. 60 | // Once the data is being used by the algorithm, the point locations are (currently) not modified. 61 | // 2) Since this Point's Edge list will only contain SOME of the edges that this point is a part of, 62 | // there currently isn't a way to (easily) get any edges that contain this point but are not in this 63 | // point's edge list. 64 | } 65 | } 66 | } 67 | public override double Y 68 | { 69 | get { return base.Y; } 70 | set 71 | { 72 | // ReSharper disable CompareOfFloatsByEqualityOperator 73 | if (value != base.Y) 74 | // ReSharper restore CompareOfFloatsByEqualityOperator 75 | { 76 | base.Y = value; 77 | VertexCode = CreateVertexCode(base.X, base.Y, VERTEX_CODE_DEFAULT_PRECISION); 78 | 79 | // Technically, we should change the ConstraintCodes of any edges that contain this point. 80 | // We don't for 2 reasons: 81 | // 1) Currently the only time we care about Vertex/Constraint Codes is when entering data in the point-set. 82 | // Once the data is being used by the algorithm, the point locations are (currently) not modified. 83 | // 2) Since this Point's Edge list will only contain SOME of the edges that this point is a part of, 84 | // there currently isn't a way to (easily) get any edges that contain this point but are not in this 85 | // point's edge list. 86 | } 87 | } 88 | } 89 | 90 | public uint VertexCode { get; private set; } 91 | 92 | // List of edges this point constitutes an upper ending point (CDT) 93 | public List Edges { get; private set; } 94 | public bool HasEdges { get { return Edges != null; } } 95 | 96 | public TriangulationPoint(double x, double y, double precision = VERTEX_CODE_DEFAULT_PRECISION) 97 | : base(x,y) 98 | { 99 | VertexCode = CreateVertexCode(x, y, precision); 100 | } 101 | 102 | 103 | public override string ToString() 104 | { 105 | return base.ToString() + ":{" + VertexCode + "}"; 106 | } 107 | 108 | 109 | public override int GetHashCode() 110 | { 111 | return (int)VertexCode; 112 | } 113 | 114 | 115 | public override bool Equals(object obj) 116 | { 117 | return Equals(obj as TriangulationPoint); 118 | } 119 | 120 | public bool Equals(TriangulationPoint other) 121 | { 122 | if (other == null) 123 | return false; 124 | 125 | return VertexCode == other.VertexCode && base.Equals(other); 126 | } 127 | 128 | 129 | public override void Set(double x, double y) 130 | { 131 | X = x; 132 | Y = y; 133 | } 134 | 135 | 136 | public static uint CreateVertexCode(double x, double y, double precision) 137 | { 138 | float fx = (float)MathUtil.RoundWithPrecision(x, precision); 139 | float fy = (float)MathUtil.RoundWithPrecision(y, precision); 140 | uint vc = MathUtil.Jenkins32Hash(BitConverter.GetBytes(fx), 0); 141 | vc = MathUtil.Jenkins32Hash(BitConverter.GetBytes(fy), vc); 142 | 143 | return vc; 144 | } 145 | 146 | 147 | public void AddEdge(DTSweepConstraint e) 148 | { 149 | if (Edges == null) 150 | { 151 | Edges = new List(); 152 | } 153 | Edges.Add(e); 154 | } 155 | 156 | 157 | public bool HasEdge(TriangulationPoint p) 158 | { 159 | DTSweepConstraint tmp; 160 | return GetEdge(p, out tmp); 161 | } 162 | 163 | 164 | public bool GetEdge(TriangulationPoint p, out DTSweepConstraint edge) 165 | { 166 | edge = null; 167 | if (Edges == null || Edges.Count < 1 || p == null || p.Equals(this)) 168 | { 169 | return false; 170 | } 171 | 172 | foreach (DTSweepConstraint sc in Edges.Where(sc => (sc.P.Equals(this) && sc.Q.Equals(p)) || (sc.P.Equals(p) && sc.Q.Equals(this)))) 173 | { 174 | edge = sc; 175 | return true; 176 | } 177 | 178 | return false; 179 | } 180 | 181 | } 182 | } -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Util/PointGenerator.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using System; 33 | using System.Collections.Generic; 34 | 35 | namespace Poly2Tri.Triangulation.Util 36 | { 37 | public class PointGenerator 38 | { 39 | static readonly Random _rng = new Random(); 40 | 41 | 42 | public static List UniformDistribution(int n, double scale) 43 | { 44 | List points = new List(); 45 | for (int i = 0; i < n; i++) 46 | { 47 | points.Add(new TriangulationPoint(scale * (0.5 - _rng.NextDouble()), scale * (0.5 - _rng.NextDouble()))); 48 | } 49 | 50 | return points; 51 | } 52 | 53 | 54 | public static List UniformGrid(int n, double scale) 55 | { 56 | double size = scale / n; 57 | double halfScale = 0.5 * scale; 58 | 59 | List points = new List(); 60 | for (int i = 0; i < n + 1; i++) 61 | { 62 | double x = halfScale - i * size; 63 | for (int j = 0; j < n + 1; j++) 64 | { 65 | points.Add(new TriangulationPoint(x, halfScale - j * size)); 66 | } 67 | } 68 | 69 | return points; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Util/PolygonGenerator.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using System; 33 | using Poly2Tri.Triangulation.Polygon; 34 | 35 | namespace Poly2Tri.Triangulation.Util 36 | { 37 | public class PolygonGenerator 38 | { 39 | static readonly Random _rng = new Random(); 40 | 41 | private const double PI_2 = 2.0 * Math.PI; 42 | 43 | public static Polygon.Polygon RandomCircleSweep(double scale, int vertexCount) 44 | { 45 | double radius = scale / 4; 46 | 47 | PolygonPoint[] points = new PolygonPoint[vertexCount]; 48 | for (int i = 0; i < vertexCount; i++) 49 | { 50 | do 51 | { 52 | if (i % 250 == 0) 53 | { 54 | radius += scale / 2 * (0.5 - _rng.NextDouble()); 55 | } 56 | else if (i % 50 == 0) 57 | { 58 | radius += scale / 5 * (0.5 - _rng.NextDouble()); 59 | } 60 | else 61 | { 62 | radius += 25 * scale / vertexCount * (0.5 - _rng.NextDouble()); 63 | } 64 | radius = radius > scale / 2 ? scale / 2 : radius; 65 | radius = radius < scale / 10 ? scale / 10 : radius; 66 | } while (radius < scale / 10 || radius > scale / 2); 67 | PolygonPoint point = new PolygonPoint(radius * Math.Cos((PI_2 * i) / vertexCount), radius * Math.Sin((PI_2 * i) / vertexCount)); 68 | points[i] = point; 69 | } 70 | return new Polygon.Polygon(points); 71 | } 72 | 73 | public static Polygon.Polygon RandomCircleSweep2(double scale, int vertexCount) 74 | { 75 | double radius = scale / 4; 76 | 77 | PolygonPoint[] points = new PolygonPoint[vertexCount]; 78 | for (int i = 0; i < vertexCount; i++) 79 | { 80 | do 81 | { 82 | radius += scale / 5 * (0.5 - _rng.NextDouble()); 83 | radius = radius > scale / 2 ? scale / 2 : radius; 84 | radius = radius < scale / 10 ? scale / 10 : radius; 85 | } while (radius < scale / 10 || radius > scale / 2); 86 | PolygonPoint point = new PolygonPoint(radius * Math.Cos((PI_2 * i) / vertexCount), radius * Math.Sin((PI_2 * i) / vertexCount)); 87 | points[i] = point; 88 | } 89 | return new Polygon.Polygon(points); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Poly2Tri/Triangulation/Util/TriangulationUtil.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using System; 33 | using Poly2Tri.Utility; 34 | 35 | namespace Poly2Tri.Triangulation.Util 36 | { 37 | /** 38 | * @author Thomas Åhlén, thahlen@gmail.com 39 | */ 40 | public class TriangulationUtil 41 | { 42 | /// 43 | /// Requirements: 44 | /// 1. a,b and c form a triangle. 45 | /// 2. a and d is know to be on opposite side of bc 46 | /// 47 | /// a 48 | /// + 49 | /// / \ 50 | /// / \ 51 | /// b/ \c 52 | /// +-------+ 53 | /// / B \ 54 | /// / \ 55 | /// 56 | /// Facts: 57 | /// d has to be in area B to have a chance to be inside the circle formed by a,b and c 58 | /// d is outside B if orient2d(a,b,d) or orient2d(c,a,d) is CW 59 | /// This preknowledge gives us a way to optimize the incircle test 60 | /// 61 | /// triangle point, opposite d 62 | /// triangle point 63 | /// triangle point 64 | /// point opposite a 65 | /// true if d is inside circle, false if on circle edge 66 | public static bool SmartIncircle(Point2D pa, Point2D pb, Point2D pc, Point2D pd) 67 | { 68 | double pdx = pd.X; 69 | double pdy = pd.Y; 70 | double adx = pa.X - pdx; 71 | double ady = pa.Y - pdy; 72 | double bdx = pb.X - pdx; 73 | double bdy = pb.Y - pdy; 74 | 75 | double adxbdy = adx * bdy; 76 | double bdxady = bdx * ady; 77 | double oabd = adxbdy - bdxady; 78 | // oabd = orient2d(pa,pb,pd); 79 | if (oabd <= 0) 80 | { 81 | return false; 82 | } 83 | 84 | double cdx = pc.X - pdx; 85 | double cdy = pc.Y - pdy; 86 | 87 | double cdxady = cdx * ady; 88 | double adxcdy = adx * cdy; 89 | double ocad = cdxady - adxcdy; 90 | // ocad = orient2d(pc,pa,pd); 91 | if (ocad <= 0) 92 | { 93 | return false; 94 | } 95 | 96 | double bdxcdy = bdx * cdy; 97 | double cdxbdy = cdx * bdy; 98 | 99 | double alift = adx * adx + ady * ady; 100 | double blift = bdx * bdx + bdy * bdy; 101 | double clift = cdx * cdx + cdy * cdy; 102 | 103 | double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd; 104 | 105 | return det > 0; 106 | } 107 | 108 | 109 | public static bool InScanArea(Point2D pa, Point2D pb, Point2D pc, Point2D pd) 110 | { 111 | double pdx = pd.X; 112 | double pdy = pd.Y; 113 | double adx = pa.X - pdx; 114 | double ady = pa.Y - pdy; 115 | double bdx = pb.X - pdx; 116 | double bdy = pb.Y - pdy; 117 | 118 | double adxbdy = adx * bdy; 119 | double bdxady = bdx * ady; 120 | double oabd = adxbdy - bdxady; 121 | // oabd = orient2d(pa,pb,pd); 122 | if (oabd <= 0) 123 | { 124 | return false; 125 | } 126 | 127 | double cdx = pc.X - pdx; 128 | double cdy = pc.Y - pdy; 129 | 130 | double cdxady = cdx * ady; 131 | double adxcdy = adx * cdy; 132 | double ocad = cdxady - adxcdy; 133 | // ocad = orient2d(pc,pa,pd); 134 | if (ocad <= 0) 135 | { 136 | return false; 137 | } 138 | return true; 139 | } 140 | 141 | 142 | /// Forumla to calculate signed area 143 | /// Positive if CCW 144 | /// Negative if CW 145 | /// 0 if collinear 146 | /// A[P1,P2,P3] = (x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y1 - y3*x1) 147 | /// = (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3) 148 | public static Orientation Orient2d(Point2D pa, Point2D pb, Point2D pc) 149 | { 150 | double detleft = (pa.X - pc.X) * (pb.Y - pc.Y); 151 | double detright = (pa.Y - pc.Y) * (pb.X - pc.X); 152 | double val = detleft - detright; 153 | if (val > -MathUtil.EPSILON && val < MathUtil.EPSILON) 154 | { 155 | return Orientation.Collinear; 156 | } 157 | else if (val > 0) 158 | { 159 | return Orientation.AntiClockwise; 160 | } 161 | return Orientation.Clockwise; 162 | } 163 | 164 | 165 | /////////////////////////////////////////////////////////////////////////////// 166 | // PointRelativeToLine2D 167 | // 168 | // Returns -1 if point is on left of line, 0 if point is on line, and 1 if 169 | // the point is to the right of the line. This assumes a coordinate system 170 | // whereby the y axis goes upward when the x axis goes rightward. This is how 171 | // 3D systems (both right and left-handed) and PostScript works, but is not 172 | // how the Win32 GUI works. If you are using a 'y goes downward' coordinate 173 | // system, simply negate the return value from this function. 174 | // 175 | // Given a point (a,b) and a line from (x1,y1) to (x2,y2), we calculate the 176 | // following equation: 177 | // (y2-y1)*(a-x1)-(x2-x1)*(b-y1) (left) 178 | // If the result is > 0, the point is on 1 --------------> 2 179 | // the right, else left. (right) 180 | // 181 | // For example, with a point at (1,1) and a 182 | // line going from (0,0) to (2,0), we get: 183 | // (0-0)*(1-0)-(2-0)*(1-0) 184 | // which equals: 185 | // -2 186 | // Which indicates the point is (correctly) 187 | // on the left of the directed line. 188 | // 189 | // This function has been checked to a good degree. 190 | // 191 | ///////////////////////////////////////////////////////////////////////////// 192 | //public static double PointRelativeToLine2D(Point2D ptPoint, Point2D ptLineBegin, Point2D ptLineEnd) 193 | //{ 194 | // return (ptLineEnd.Y - ptLineBegin.Y) * (ptPoint.X - ptLineBegin.X) - (ptLineEnd.X - ptLineBegin.X) * (ptPoint.Y - ptLineBegin.Y); 195 | //} 196 | 197 | 198 | /////////////////////////////////////////////////////////////////////////// 199 | // PointInBoundingBox - checks if a point is completely inside an 200 | // axis-aligned bounding box defined by xmin, xmax, ymin, and ymax. 201 | // Note that the point must be fully inside for this method to return 202 | // true - it cannot lie on the border of the bounding box. 203 | /////////////////////////////////////////////////////////////////////////// 204 | public static bool PointInBoundingBox(double xmin, double xmax, double ymin, double ymax, Point2D p) 205 | { 206 | return (p.X > xmin && p.X < xmax && p.Y > ymin && p.Y < ymax); 207 | } 208 | 209 | 210 | public static bool PointOnLineSegment2D(Point2D lineStart, Point2D lineEnd, Point2D p, double epsilon) 211 | { 212 | return PointOnLineSegment2D(lineStart.X, lineStart.Y, lineEnd.X, lineEnd.Y, p.X, p.Y, epsilon); 213 | } 214 | 215 | private static bool PointOnLineSegment2D(double x1, double y1, double x2, double y2, double x, double y, double epsilon) 216 | { 217 | // First checking if (x, z) is in the range of the line segment's end points. 218 | if (MathUtil.IsValueBetween(x, x1, x2, epsilon) && MathUtil.IsValueBetween(y, y1, y2, epsilon)) 219 | { 220 | if (MathUtil.AreValuesEqual(x2 - x1, 0.0f, epsilon)) 221 | { 222 | // Vertical line. 223 | return true; 224 | } 225 | 226 | double slope = (y2 - y1) / (x2 - x1); 227 | double yIntercept = -(slope * x1) + y1; 228 | 229 | // Checking if (x, y) is on the line passing through the end points. 230 | double t = y - ((slope * x) + yIntercept); 231 | 232 | return MathUtil.AreValuesEqual(t, 0.0f, epsilon); 233 | } 234 | 235 | return false; 236 | } 237 | 238 | 239 | public static bool RectsIntersect(Rect2D r1, Rect2D r2) 240 | { 241 | return (r1.Right > r2.Left) && 242 | (r1.Left < r2.Right) && 243 | (r1.Bottom > r2.Top) && 244 | (r1.Top < r2.Bottom); 245 | } 246 | 247 | /// 248 | /// This method detects if two line segments (or lines) intersect, 249 | /// and, if so, the point of intersection. Use the and 250 | /// parameters to set whether the intersection point 251 | /// must be on the first and second line segments. Setting these 252 | /// both to true means you are doing a line-segment to line-segment 253 | /// intersection. Setting one of them to true means you are doing a 254 | /// line to line-segment intersection test, and so on. 255 | /// Note: If two line segments are coincident, then 256 | /// no intersection is detected (there are actually 257 | /// infinite intersection points). 258 | /// 259 | /// The first point of the first line segment. 260 | /// The second point of the first line segment. 261 | /// The first point of the second line segment. 262 | /// The second point of the second line segment. 263 | /// Set this to true to require that the 264 | /// intersection point be on the first line segment. 265 | /// Set this to true to require that the 266 | /// intersection point be on the second line segment. 267 | /// Set this to true to enable collisions if the line segments share 268 | /// an endpoint 269 | /// This is set to the intersection 270 | /// point if an intersection is detected. 271 | /// 272 | /// True if an intersection is detected, false otherwise. 273 | public static bool LinesIntersect2D( Point2D ptStart0, Point2D ptEnd0, 274 | Point2D ptStart1, Point2D ptEnd1, 275 | bool firstIsSegment, bool secondIsSegment, bool coincidentEndPointCollisions, 276 | ref Point2D pIntersectionPt, 277 | double epsilon) 278 | { 279 | double d = (ptEnd0.X - ptStart0.X) * (ptStart1.Y - ptEnd1.Y) - (ptStart1.X - ptEnd1.X) * (ptEnd0.Y - ptStart0.Y); 280 | if (Math.Abs(d) < epsilon) 281 | { 282 | //The lines are parallel. 283 | return false; 284 | } 285 | 286 | double d0 = (ptStart1.X - ptStart0.X) * (ptStart1.Y - ptEnd1.Y) - (ptStart1.X - ptEnd1.X) * (ptStart1.Y - ptStart0.Y); 287 | double d1 = (ptEnd0.X - ptStart0.X) * (ptStart1.Y - ptStart0.Y) - (ptStart1.X - ptStart0.X) * (ptEnd0.Y - ptStart0.Y); 288 | double kOneOverD = 1 / d; 289 | double t0 = d0 * kOneOverD; 290 | double t1 = d1 * kOneOverD; 291 | 292 | if ((!firstIsSegment || ((t0 >= 0.0) && (t0 <= 1.0))) && 293 | (!secondIsSegment || ((t1 >= 0.0) && (t1 <= 1.0))) && 294 | (coincidentEndPointCollisions || (!MathUtil.AreValuesEqual(0.0, t0, epsilon) && !MathUtil.AreValuesEqual(0.0, t1, epsilon)))) 295 | { 296 | if (pIntersectionPt != null) 297 | { 298 | pIntersectionPt.X = ptStart0.X + t0 * (ptEnd0.X - ptStart0.X); 299 | pIntersectionPt.Y = ptStart0.Y + t0 * (ptEnd0.Y - ptStart0.Y); 300 | } 301 | 302 | return true; 303 | } 304 | 305 | return false; 306 | } 307 | 308 | 309 | public static bool LinesIntersect2D( Point2D ptStart0, Point2D ptEnd0, 310 | Point2D ptStart1, Point2D ptEnd1, 311 | ref Point2D pIntersectionPt, 312 | double epsilon) 313 | { 314 | return LinesIntersect2D(ptStart0, ptEnd0, ptStart1, ptEnd1, true, true, false, ref pIntersectionPt, epsilon); 315 | } 316 | 317 | 318 | /////////////////////////////////////////////////////////////////////////// 319 | // RaysIntersect2D 320 | // 321 | // Given two lines defined by (sorry about the lame notation): 322 | // x0 = x00 + vector_x0*s; 323 | // y0 = y00 + vector_y0*s; 324 | // 325 | // x1 = x10 + vector_x1*t; 326 | // y1 = y10 + vector_y1*t; 327 | // 328 | // This function determines the intersection between them, if there is any. 329 | // 330 | // This function assumes the lines to have no endpoints and will intersect 331 | // them anywhere in 2D space. 332 | // 333 | // This algorithm taken from "Realtime-Rendering" section 10.12. 334 | // 335 | // This function has been checked to a good degree. 336 | // 337 | /////////////////////////////////////////////////////////////////////////// 338 | private static double LI2DDotProduct(Point2D v0, Point2D v1) 339 | { 340 | return ((v0.X * v1.X) + (v0.Y * v1.Y)); 341 | } 342 | 343 | 344 | public static bool RaysIntersect2D( Point2D ptRayOrigin0, Point2D ptRayVector0, 345 | Point2D ptRayOrigin1, Point2D ptRayVector1, 346 | ref Point2D ptIntersection) 347 | { 348 | const double K_EPSILON = 0.01; 349 | 350 | if (ptIntersection != null) 351 | { 352 | //If the user wants an actual intersection result... 353 | 354 | //This is a vector from pLineOrigin0 to ptLineOrigin1. 355 | Point2D ptTemp1 = new Point2D(ptRayOrigin1.X - ptRayOrigin0.X, ptRayOrigin1.Y - ptRayOrigin0.Y); 356 | 357 | //This is a vector perpendicular to ptVector1. 358 | Point2D ptTemp2 = new Point2D(-ptRayVector1.Y, ptRayVector1.X); 359 | 360 | double fDot1 = LI2DDotProduct(ptRayVector0, ptTemp2); 361 | 362 | if (Math.Abs(fDot1) < K_EPSILON) 363 | { 364 | return false; //The lines are essentially parallel. 365 | } 366 | 367 | double fDot2 = LI2DDotProduct(ptTemp1, ptTemp2); 368 | double s = fDot2 / fDot1; 369 | ptIntersection.X = ptRayOrigin0.X + ptRayVector0.X * s; 370 | ptIntersection.Y = ptRayOrigin0.Y + ptRayVector0.Y * s; 371 | return true; 372 | } 373 | 374 | //Else the user just wants to know if there is an intersection... 375 | //In this case we need only compare the slopes of the lines. 376 | double delta = ptRayVector1.X - ptRayVector0.X; 377 | if (Math.Abs(delta) > K_EPSILON) 378 | { 379 | delta = ptRayVector1.Y - ptRayVector0.Y; 380 | if (Math.Abs(delta) > K_EPSILON) 381 | { 382 | return true; //The lines are not parallel. 383 | } 384 | } 385 | 386 | return false; 387 | } 388 | 389 | } 390 | 391 | 392 | } 393 | -------------------------------------------------------------------------------- /Poly2Tri/Utility/FixedArray3.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using System; 33 | using System.Collections; 34 | using System.Collections.Generic; 35 | 36 | namespace Poly2Tri.Utility 37 | { 38 | public struct FixedArray3 : IEnumerable where T : IEquatable 39 | { 40 | public T Item0; 41 | public T Item1; 42 | public T Item2; 43 | 44 | public T this[int index] 45 | { 46 | get 47 | { 48 | switch (index) 49 | { 50 | case 0: 51 | return Item0; 52 | case 1: 53 | return Item1; 54 | case 2: 55 | return Item2; 56 | default: 57 | throw new IndexOutOfRangeException(); 58 | } 59 | } 60 | set 61 | { 62 | switch (index) 63 | { 64 | case 0: 65 | Item0 = value; 66 | break; 67 | case 1: 68 | Item1 = value; 69 | break; 70 | case 2: 71 | Item2 = value; 72 | break; 73 | default: 74 | throw new IndexOutOfRangeException(); 75 | } 76 | } 77 | } 78 | 79 | 80 | public bool Contains(T value) 81 | { 82 | return IndexOf(value) != -1; 83 | } 84 | 85 | 86 | public int IndexOf(T value) 87 | { 88 | for (int i = 0; i < 3; ++i) 89 | { 90 | if (!this[i].Equals(default(T)) && this[i].Equals(value)) 91 | { 92 | return i; 93 | } 94 | } 95 | 96 | return -1; 97 | } 98 | 99 | 100 | public void Clear() 101 | { 102 | Item0 = Item1 = Item2 = default(T); 103 | } 104 | 105 | 106 | public void Clear(T value) 107 | { 108 | for (int i = 0; i < 3; ++i) 109 | { 110 | if (this[i].Equals(default(T)) && this[i].Equals(value)) 111 | { 112 | this[i] = default(T); 113 | } 114 | } 115 | } 116 | 117 | 118 | private IEnumerable Enumerate() 119 | { 120 | for (int i = 0; i < 3; ++i) 121 | { 122 | yield return this[i]; 123 | } 124 | } 125 | 126 | 127 | public IEnumerator GetEnumerator() { return Enumerate().GetEnumerator(); } 128 | 129 | 130 | IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /Poly2Tri/Utility/MathUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Poly2Tri.Utility 5 | { 6 | public class MathUtil 7 | { 8 | public const double EPSILON = 1e-12; 9 | 10 | public static bool AreValuesEqual(double val1, double val2, double tolerance = EPSILON) 11 | { 12 | if (val1 >= (val2 - tolerance) && val1 <= (val2 + tolerance)) 13 | { 14 | return true; 15 | } 16 | 17 | return false; 18 | } 19 | 20 | 21 | public static bool IsValueBetween(double val, double min, double max, double tolerance) 22 | { 23 | if (min > max) 24 | { 25 | double tmp = min; 26 | min = max; 27 | max = tmp; 28 | } 29 | if ((val + tolerance) >= min && (val - tolerance) <= max) 30 | { 31 | return true; 32 | } 33 | 34 | return false; 35 | } 36 | 37 | 38 | public static double RoundWithPrecision(double f, double precision) 39 | { 40 | if (precision < 0.0) 41 | { 42 | return f; 43 | } 44 | 45 | double mul = Math.Pow(10.0, precision); 46 | double fTemp = Math.Floor(f * mul) / mul; 47 | 48 | return fTemp; 49 | } 50 | 51 | 52 | public static double Clamp(double a, double low, double high) 53 | { 54 | return Math.Max(low, Math.Min(a, high)); 55 | } 56 | 57 | 58 | public static void Swap(ref T a, ref T b) 59 | { 60 | T tmp = a; 61 | a = b; 62 | b = tmp; 63 | } 64 | 65 | 66 | public static uint Jenkins32Hash(IEnumerable data, uint nInitialValue) 67 | { 68 | foreach (byte b in data) 69 | { 70 | nInitialValue += b; 71 | nInitialValue += (nInitialValue << 10); 72 | nInitialValue += (nInitialValue >> 6); 73 | } 74 | 75 | nInitialValue += (nInitialValue << 3); 76 | nInitialValue ^= (nInitialValue >> 11); 77 | nInitialValue += (nInitialValue << 15); 78 | 79 | return nInitialValue; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Poly2Tri/Utility/Point2D.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using System; 33 | 34 | namespace Poly2Tri.Utility 35 | { 36 | public class Point2D : IComparable 37 | { 38 | private double _x; 39 | public virtual double X { get { return _x; } set { _x = value; } } 40 | private double _y; 41 | public virtual double Y { get { return _y; } set { _y = value; } } 42 | 43 | public float Xf { get { return (float)X; } } 44 | public float Yf { get { return (float)Y; } } 45 | 46 | 47 | public Point2D() 48 | { 49 | _x = 0.0; 50 | _y = 0.0; 51 | } 52 | 53 | 54 | public Point2D(double x, double y) 55 | { 56 | _x = x; 57 | _y = y; 58 | } 59 | 60 | public override string ToString() 61 | { 62 | return string.Format("[{0},{1}]", X, Y); 63 | } 64 | 65 | 66 | public override int GetHashCode() 67 | { 68 | unchecked 69 | { 70 | return 378163771 * _x.GetHashCode() 71 | + 113137337 * _y.GetHashCode(); 72 | } 73 | } 74 | 75 | 76 | public override bool Equals(Object obj) 77 | { 78 | Point2D p = obj as Point2D; 79 | if (p != null) 80 | return Equals(p); 81 | 82 | return false; 83 | } 84 | 85 | public bool Equals(Point2D p, double epsilon = 0.0) 86 | { 87 | if (p == null || !MathUtil.AreValuesEqual(X, p.X, epsilon) || !MathUtil.AreValuesEqual(Y, p.Y, epsilon)) 88 | return false; 89 | 90 | return true; 91 | } 92 | 93 | 94 | public int CompareTo(Point2D other) 95 | { 96 | if (Y < other.Y) 97 | { 98 | return -1; 99 | } 100 | else if (Y > other.Y) 101 | { 102 | return 1; 103 | } 104 | else 105 | { 106 | if (X < other.X) 107 | { 108 | return -1; 109 | } 110 | else if (X > other.X) 111 | { 112 | return 1; 113 | } 114 | } 115 | 116 | return 0; 117 | } 118 | 119 | 120 | public virtual void Set(double x, double y) { X = x; Y = y; } 121 | 122 | public void Subtract(Point2D p) { X -= p.X; Y -= p.Y; } 123 | private void Multiply(double scalar) { X *= scalar; Y *= scalar; } 124 | public double Magnitude() { return Math.Sqrt(MagnitudeSquared()); } 125 | public double MagnitudeSquared() { return (X * X) + (Y * Y); } 126 | private double MagnitudeReciprocal() { return 1.0 / Magnitude(); } 127 | public void Normalize() { Multiply(MagnitudeReciprocal()); } 128 | public double Dot(Point2D p) { return (X * p.X) + (Y * p.Y); } 129 | public double Cross(Point2D p) { return (X * p.Y) - (Y * p.X); } 130 | 131 | public static double Dot(Point2D lhs, Point2D rhs) { return (lhs.X * rhs.X) + (lhs.Y * rhs.Y); } 132 | public static double Cross(Point2D lhs, Point2D rhs) { return (lhs.X * rhs.Y) - (lhs.Y * rhs.X); } 133 | 134 | // returns a scaled perpendicular vector. Which direction it goes depends on the order in which the arguments are passed 135 | public static Point2D Perpendicular(Point2D lhs, double scalar) { Point2D p = new Point2D(lhs.Y * scalar, lhs.X * -scalar); return p; } 136 | public static Point2D Perpendicular(double scalar, Point2D rhs) { Point2D p = new Point2D(-scalar * rhs.Y, scalar * rhs.X); return p; } 137 | 138 | 139 | // 140 | // operator overloading 141 | // 142 | 143 | // Binary Operators 144 | // Note that in C#, when a binary operator is overloaded, its corresponding compound assignment operator is also automatically 145 | // overloaded. So, for example, overloading operator + implicitly overloads += as well 146 | public static Point2D operator +(Point2D lhs, Point2D rhs) { return new Point2D(lhs.X + rhs.X, lhs.Y + rhs.Y); } 147 | public static Point2D operator +(Point2D lhs, double scalar) { return new Point2D(lhs.X + scalar, lhs.Y + scalar); } 148 | public static Point2D operator -(Point2D lhs, Point2D rhs) { return new Point2D(lhs.X - rhs.X, lhs.Y - rhs.Y); } 149 | public static Point2D operator -(Point2D lhs, double scalar) { return new Point2D(lhs.X - scalar, lhs.Y - scalar); } 150 | public static Point2D operator *(Point2D lhs, Point2D rhs) { return new Point2D(lhs.X * rhs.X, lhs.Y * rhs.Y); } 151 | public static Point2D operator *(Point2D lhs, double scalar) { return new Point2D(lhs.X * scalar, lhs.Y * scalar); } 152 | public static Point2D operator *(double scalar, Point2D rhs) { return rhs * scalar; } 153 | public static Point2D operator /(Point2D lhs, Point2D rhs) { return new Point2D(lhs.X / rhs.X, lhs.Y / rhs.Y); } 154 | public static Point2D operator /(Point2D lhs, double scalar) { return new Point2D(lhs.X / scalar, lhs.Y / scalar); } 155 | 156 | // Unary Operators 157 | public static Point2D operator -(Point2D p) { return new Point2D(-p.X, -p.Y); } 158 | 159 | // Relational Operators 160 | //public static bool operator ==(Point2D lhs, Point2D rhs) { if ((object)lhs != null) { return lhs.Equals(rhs, 0.0); } if ((object)rhs == null) { return true; } else { return false; } } 161 | //public static bool operator !=(Point2D lhs, Point2D rhs) { if ((object)lhs != null) { return !lhs.Equals(rhs, 0.0); } if ((object)rhs == null) { return false; } else { return true; } } 162 | public static bool operator <(Point2D lhs, Point2D rhs) { return (lhs.CompareTo(rhs) == -1); } 163 | public static bool operator >(Point2D lhs, Point2D rhs) { return (lhs.CompareTo(rhs) == 1); } 164 | public static bool operator <=(Point2D lhs, Point2D rhs) { return (lhs.CompareTo(rhs) <= 0); } 165 | public static bool operator >=(Point2D lhs, Point2D rhs) { return (lhs.CompareTo(rhs) >= 0); } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /Poly2Tri/Utility/Rect2D.cs: -------------------------------------------------------------------------------- 1 | /* Poly2Tri 2 | * Copyright (c) 2009-2010, Poly2Tri Contributors 3 | * http://code.google.com/p/poly2tri/ 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * * Neither the name of Poly2Tri nor the names of its contributors may be 16 | * used to endorse or promote products derived from this software without specific 17 | * prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | using System; 33 | 34 | namespace Poly2Tri.Utility 35 | { 36 | public struct Rect2D 37 | { 38 | private readonly double _minX; 39 | private readonly double _maxX; 40 | private readonly double _minY; 41 | private readonly double _maxY; 42 | 43 | public double MinX { get { return _minX; } } 44 | public double MaxX { get { return _maxX; } } 45 | public double MinY { get { return _minY; } } 46 | public double MaxY { get { return _maxY; } } 47 | public double Left { get { return _minX; } } 48 | public double Right { get { return _maxX; } } 49 | public double Top { get { return _maxY; } } 50 | public double Bottom { get { return _minY; } } 51 | 52 | public double Width { get { return (Right - Left); } } 53 | public double Height { get { return (Top - Bottom); } } 54 | 55 | public bool IsEmpty 56 | { 57 | get 58 | { 59 | return Math.Abs(Width) < float.Epsilon || Math.Abs(Height) < float.Epsilon; 60 | } 61 | } 62 | 63 | private Rect2D(double minX, double maxX, double minY, double maxY) 64 | { 65 | _minX = minX; 66 | _maxX = maxX; 67 | _minY = minY; 68 | _maxY = maxY; 69 | } 70 | 71 | public override int GetHashCode() 72 | { 73 | unchecked 74 | { 75 | // ReSharper disable ImpureMethodCallOnReadonlyValueField 76 | return 54734431 * _minX.GetHashCode() 77 | + 1122547711 * _minY.GetHashCode() 78 | + 1097393683 * _maxX.GetHashCode() 79 | + 1198754321 * _maxY.GetHashCode(); 80 | // ReSharper restore ImpureMethodCallOnReadonlyValueField 81 | } 82 | 83 | } 84 | 85 | public override bool Equals(Object obj) 86 | { 87 | return obj is Rect2D && Equals((Rect2D)obj); 88 | } 89 | 90 | private bool Equals(Rect2D r, double epsilon = MathUtil.EPSILON) 91 | { 92 | return MathUtil.AreValuesEqual(MinX, r.MinX, epsilon) 93 | && MathUtil.AreValuesEqual(MaxX, r.MaxX, epsilon) 94 | && MathUtil.AreValuesEqual(MinY, r.MinY, epsilon) 95 | && MathUtil.AreValuesEqual(MaxY, r.MaxY, epsilon); 96 | } 97 | 98 | public bool Intersects(Rect2D r) 99 | { 100 | return (Right > r.Left) && 101 | (Left < r.Right) && 102 | (Bottom < r.Top) && 103 | (Top > r.Bottom); 104 | } 105 | 106 | public Rect2D AddPoint(Point2D p) 107 | { 108 | return new Rect2D( 109 | Math.Min(MinX, p.X), 110 | Math.Max(MaxX, p.X), 111 | Math.Min(MinY, p.Y), 112 | Math.Max(MaxY, p.Y) 113 | ); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /push-all.ps1: -------------------------------------------------------------------------------- 1 | function Push-Nuget($path, $csproj) { 2 | $fullPathToCsprog = Join-Path -Path $path -ChildPath $csproj -resolve; 3 | 4 | nuget pack $fullPathToCsprog -Prop Configuration=Release -IncludeReferencedProjects -Symbols 5 | 6 | get-childitem -Filter *.nupkg -name | foreach ($_) { 7 | Write-Host "Pushing " $_ -backgroundcolor darkgreen -foregroundcolor white; 8 | 9 | nuget push $_ 10 | Remove-Item $_ 11 | 12 | Write-Host "Done " $_ -backgroundcolor darkgreen -foregroundcolor white; 13 | } 14 | } 15 | 16 | Push-Nuget "Poly2Tri" "Poly2Tri.csproj" -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | This is a fork of the C# version of [poly2tri](https://code.google.com/p/poly2tri/). Changes to the code are just to bring things in line with C# style. 2 | 3 | This is the code behind the poly2tri [nuget package](https://www.nuget.org/packages/Poly2Tri/). --------------------------------------------------------------------------------