From f67a8ba82b8df2d1260201a010f85342ae1a96a5 Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Thu, 20 Jan 2022 16:31:08 +0100 Subject: [PATCH 01/19] investigating #70 --- .../Issue70Fixture.cs | 40 ++++++++++++++++++ .../Issue79Fixture.cs | 5 ++- .../TestShapefiles/shell_bad_ccw.dbf | Bin 0 -> 70 bytes .../TestShapefiles/shell_bad_ccw.prj | 1 + .../TestShapefiles/shell_bad_ccw.shp | Bin 0 -> 816 bytes .../TestShapefiles/shell_bad_ccw.shx | Bin 0 -> 108 bytes 6 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs create mode 100644 test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.dbf create mode 100644 test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.prj create mode 100644 test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.shp create mode 100644 test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.shx diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs new file mode 100644 index 0000000..7871dee --- /dev/null +++ b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs @@ -0,0 +1,40 @@ +using NUnit.Framework; +using System.IO; +using NetTopologySuite.Geometries; +using System; + +namespace NetTopologySuite.IO.ShapeFile.Test +{ + [TestFixture] + [ShapeFileIssueNumber(70)] + public class Issue70Fixture + { + /// + /// + /// + [Test] + public void TestReadPolygonWithWrongShellOrientation() + { + string filePath = Path.Combine( + CommonHelpers.TestShapefilesDirectory, + "shell_bad_ccw.shp"); + Assert.That(File.Exists(filePath), Is.True); + string filePathWoExt = Path.Combine( + Path.GetDirectoryName(filePath), + Path.GetFileNameWithoutExtension(filePath)); + using var shpReader = new ShapefileDataReader( + filePathWoExt, + GeometryFactory.Default); + bool success = shpReader.Read(); + Assert.That(success, Is.True); + var geom = shpReader.Geometry; + Assert.That(geom, Is.Not.Null); + Console.WriteLine(geom.AsText()); + Assert.That(geom, Is.InstanceOf()); + var poly = (Polygon)geom; + Assert.That(poly.Shell, Is.Not.Null); + Assert.That(poly.Holes, Is.Not.Null); + Assert.That(poly.Holes.Length, Is.EqualTo(1)); + } + } +} diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/Issue79Fixture.cs b/test/NetTopologySuite.IO.ShapeFile.Test/Issue79Fixture.cs index d85c452..723fa7d 100644 --- a/test/NetTopologySuite.IO.ShapeFile.Test/Issue79Fixture.cs +++ b/test/NetTopologySuite.IO.ShapeFile.Test/Issue79Fixture.cs @@ -18,8 +18,11 @@ public void TestReadEmptyShapefile() CommonHelpers.TestShapefilesDirectory, "__emptyShapefile.shp"); Assert.That(File.Exists(filePath), Is.True); + string filePathWoExt = Path.Combine( + Path.GetDirectoryName(filePath), + Path.GetFileNameWithoutExtension(filePath)); using var shpReader = new ShapefileDataReader( - Path.GetFileNameWithoutExtension(filePath), + filePathWoExt, GeometryFactory.Default); bool success = shpReader.Read(); Assert.That(success, Is.False); diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.dbf b/test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.dbf new file mode 100644 index 0000000000000000000000000000000000000000..ee26ecad0c4009bb98a60ed996b8e60909f70da2 GIT binary patch literal 70 ocmZRsViaLyU|?`$U;&btz|GSo-Vh?}2cnqKl<+E;SQttH0CmU%aR2}S literal 0 HcmV?d00001 diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.prj b/test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.prj new file mode 100644 index 0000000..8159721 --- /dev/null +++ b/test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.prj @@ -0,0 +1 @@ +PROJCS["WGS_1984_UTM_Zone_35N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",27.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.shp b/test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.shp new file mode 100644 index 0000000000000000000000000000000000000000..5809d371aedafe686c40daf576c6a2e69a4ad962 GIT binary patch literal 816 zcma*lUr1AN6bJA-&4o*|DK*wErmz%kW~ewcUHzuBzxp6aZMcOti&@JuiyjKW44X20 zSivA2w5hq=d?-toODSBK8G^$W;?ly(MEmEQ7%}?}+C$<)_vP~WoqK-gchC7zR6L7X z^I_;`f+;ElF>TL4-|}6W{Pc2*hBSp_yivOCyOk!%zdo=M16Y9>PcD_KgyaZqGPd;1@vzr7xHaIeiBR&pa zjpuk(a9d5{j$*hzVsOmYMw86WSkE!I>FK7I4`A_Y=H8?5O;L=c6nLTqc@? z_rCX@hR;S%s0-lySB9|)*pXxi=feE1Zl%AMalA|!2M+YsC{n~9G}0t{d$X&e#2r2QRV1%F^Kj z6D!>Y)SLfm8%c#nbwRR0oWHd)uSEzi>Rh}jn6EH$1+cx={<))_CbQg9Jqtcm$KH@- zriozG7|VqBU4CxLfi)=_X9!$ucaOxuNfPN6FXlJaU>)VdoTwkVMYy+i&xJf#`%Avr z@0lv5;0!F=Z+YZ_7b{Iz52?~bDgXcg literal 0 HcmV?d00001 diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.shx b/test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.shx new file mode 100644 index 0000000000000000000000000000000000000000..1e00e988022c9a9b3d0141638ed36796119329e1 GIT binary patch literal 108 zcmZQzQ0HR64$NLKGcd3M<$8A<+4pmyjN_+olA)(MgB)-5Maq9zE90nt%dE7pE65SM Mb`((~1_s6?02?V10{{R3 literal 0 HcmV?d00001 From fbdc1bf41fc6b389f659ff1f50f5ebf6dc6c0cb8 Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Fri, 21 Jan 2022 08:44:49 +0100 Subject: [PATCH 02/19] #70 update PolygonHandler to handle "unassigned" holes - i.e: holes that are not inside any shell, due mainly to invalid inputs with shell and holes not correctly oriented - as separate shells --- .../Handlers/PolygonHandler.cs | 38 +++++++++++++++---- .../Issue70Fixture.cs | 21 +++++++--- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs index b8b372a..f32945f 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using NetTopologySuite.Algorithm; using NetTopologySuite.Geometries; @@ -28,6 +29,8 @@ public PolygonHandler(ShapeGeometryType type) /// Total length of the record we are about to read /// The geometry factory to use when making the object. /// The Geometry object that represents the shape file record. + /// + /// public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, GeometryFactory factory) { int totalRead = 0; @@ -118,9 +121,12 @@ public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, //Sort shells by area, rings should only be added to the smallest shell, that contains the ring shells.Sort(ProbeLinearRing); + //mark all the holes assigned to a shell + bool[] holesAssigned = new bool[holes.Count]; // Find holes - foreach (var testHole in holes) + for (int i = 0; i < holes.Count; i++) { + var testHole = holes[i]; var testEnv = testHole.EnvelopeInternal; var testPt = testHole.GetCoordinateN(0); @@ -140,6 +146,12 @@ public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, var holesForThisShell = holesForShells[j]; holesForThisShell.Add(testHole); + if (holesAssigned[i]) + { + throw new InvalidOperationException($"Hole {i} already assigned to a shell!"); + } + holesAssigned[i] = true; // mark the hole as "assigned" to a shell + //Suggested by Bruno.Labrecque //A LinearRing should only be added to one outer shell break; @@ -149,7 +161,19 @@ public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, var polygons = new Polygon[shells.Count]; for (int i = 0; i < shells.Count; i++) - polygons[i] = (factory.CreatePolygon(shells[i], holesForShells[i].ToArray())); + polygons[i] = factory.CreatePolygon(shells[i], holesForShells[i].ToArray()); + + if (!Array.TrueForAll(holesAssigned, b => b)) + { + var list = new List(polygons); + // found some holes not assigned to a shell + for (int i = 0; i < holesAssigned.Length; i++) + { + if (!holesAssigned[i]) + list.Add(factory.CreatePolygon(holes[i])); + } + polygons = list.ToArray(); + } if (polygons.Length == 0) geom = factory.CreatePolygon(); @@ -192,10 +216,10 @@ public override void Write(Geometry geometry, BinaryWriter writer, GeometryFacto } // Write the shape type - writer.Write((int) ShapeType); + writer.Write((int)ShapeType); var box = multi.EnvelopeInternal; - var bounds = GetEnvelopeExternal(factory.PrecisionModel, box); + var bounds = GetEnvelopeExternal(factory.PrecisionModel, box); writer.Write(bounds.MinX); writer.Write(bounds.MinY); writer.Write(bounds.MaxX); @@ -211,7 +235,7 @@ public override void Write(Geometry geometry, BinaryWriter writer, GeometryFacto for (int part = 0; part < multi.NumGeometries; part++) { // offset to the shell points - var polygon = (Polygon) multi.Geometries[part]; + var polygon = (Polygon)multi.Geometries[part]; writer.Write(offset); offset = offset + polygon.ExteriorRing.NumPoints; @@ -229,7 +253,7 @@ public override void Write(Geometry geometry, BinaryWriter writer, GeometryFacto // write the points for (int part = 0; part < multi.NumGeometries; part++) { - var poly = (Polygon) multi.Geometries[part]; + var poly = (Polygon)multi.Geometries[part]; var shell = (LinearRing)poly.ExteriorRing; // shells in polygons are written clockwise var points = !shell.IsCCW @@ -237,7 +261,7 @@ public override void Write(Geometry geometry, BinaryWriter writer, GeometryFacto : shell.CoordinateSequence.Reversed(); WriteCoords(points, writer, zList, mList); - foreach(LinearRing hole in poly.InteriorRings) + foreach (LinearRing hole in poly.InteriorRings) { // holes in polygons are written counter-clockwise points = hole.IsCCW diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs index 7871dee..a55da7d 100644 --- a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs +++ b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs @@ -2,6 +2,7 @@ using System.IO; using NetTopologySuite.Geometries; using System; +using System.Linq; namespace NetTopologySuite.IO.ShapeFile.Test { @@ -15,6 +16,14 @@ public class Issue70Fixture [Test] public void TestReadPolygonWithWrongShellOrientation() { + /* + * The shell_bad_ccw.shp contains a single polygon, with: + * - a shell CCW-oriented (like a hole from ESRI specs + * - a hole CW-oriented (like a shell from ESRI specs) + * + * ShapefileReader reads this kind of data as two + * separate shells, added to a multipolygon. + */ string filePath = Path.Combine( CommonHelpers.TestShapefilesDirectory, "shell_bad_ccw.shp"); @@ -30,11 +39,13 @@ public void TestReadPolygonWithWrongShellOrientation() var geom = shpReader.Geometry; Assert.That(geom, Is.Not.Null); Console.WriteLine(geom.AsText()); - Assert.That(geom, Is.InstanceOf()); - var poly = (Polygon)geom; - Assert.That(poly.Shell, Is.Not.Null); - Assert.That(poly.Holes, Is.Not.Null); - Assert.That(poly.Holes.Length, Is.EqualTo(1)); + Assert.That(geom, Is.InstanceOf()); + var mpoly = (MultiPolygon)geom; + Assert.That(mpoly.NumGeometries, Is.EqualTo(2)); + var polys = mpoly.Geometries.Cast(); + CollectionAssert.AllItemsAreNotNull(polys.Select(p => p.Shell)); + CollectionAssert.AllItemsAreNotNull(polys.Select(p => p.Holes)); + Assert.AreEqual(0, polys.Sum(p => p.Holes.Length)); } } } From 01ccb8d85a49f1a8aed59d6d5d3f2685b1e20009 Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Fri, 21 Jan 2022 13:57:25 +0100 Subject: [PATCH 03/19] #70 made explicit that the readed geometry is not valid --- test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs index a55da7d..ff12750 100644 --- a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs +++ b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs @@ -38,7 +38,7 @@ public void TestReadPolygonWithWrongShellOrientation() Assert.That(success, Is.True); var geom = shpReader.Geometry; Assert.That(geom, Is.Not.Null); - Console.WriteLine(geom.AsText()); + Assert.That(geom.IsValid, Is.False); Assert.That(geom, Is.InstanceOf()); var mpoly = (MultiPolygon)geom; Assert.That(mpoly.NumGeometries, Is.EqualTo(2)); From 3af1eac87e62dca79bcaa08b7213aaf4e9fdc8e4 Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Fri, 21 Jan 2022 17:25:07 +0100 Subject: [PATCH 04/19] #70 polygon creation based on area, ignoring shell/holes orientation --- .../Handlers/PolygonHandler.cs | 108 +++++++++--------- .../Handlers/ProbeLinearRing.cs | 2 + .../Issue70Fixture.cs | 18 ++- 3 files changed, 60 insertions(+), 68 deletions(-) diff --git a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs index f32945f..47da7ca 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; +using System.Linq; using NetTopologySuite.Algorithm; using NetTopologySuite.Geometries; @@ -12,9 +12,6 @@ namespace NetTopologySuite.IO.Handlers /// public class PolygonHandler : ShapeHandler { - //Thanks to Bruno.Labrecque - private static readonly ProbeLinearRing ProbeLinearRing = new ProbeLinearRing(); - public PolygonHandler() : base(ShapeGeometryType.Polygon) { } @@ -89,8 +86,8 @@ public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, // Get the resulting sequences var sequences = buffer.ToSequences(factory.CoordinateSequenceFactory); - var shells = new List(); - var holes = new List(); + // Read all rings + var rings = new List(); for (int i = 0; i < sequences.Length; i++) { //Skip garbage input data with 0 points @@ -99,92 +96,89 @@ public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, var tmp = EnsureClosedSequence(sequences[i], factory.CoordinateSequenceFactory); if (tmp == null) continue; var ring = factory.CreateLinearRing(tmp); - if (ring.IsCCW) - holes.Add(ring); - else - shells.Add(ring); + rings.Add(ring); } + //Sort rings by area, from bigger to smaller + rings = rings.OrderByDescending(r => r.Factory.CreatePolygon(r).Area).ToList(); - // Ensure the ring is encoded right - if (shells.Count == 0 && holes.Count == 1) + // considering all rings as a potential shell, search the valid holes for any shell + // NOTE: rings order explained: https://gis.stackexchange.com/a/147971/26684 + var data = new List<(LinearRing shell, List holes)>(); + for (int i = 0; i < rings.Count; i++) { - shells.Add(factory.CreateLinearRing(holes[0].CoordinateSequence.Reversed())); - holes.Clear(); - } - - // Now we have lists of all shells and all holes - var holesForShells = new List>(shells.Count); - for (int i = 0; i < shells.Count; i++) - holesForShells.Add(new List()); - - //Thanks to Bruno.Labrecque - //Sort shells by area, rings should only be added to the smallest shell, that contains the ring - shells.Sort(ProbeLinearRing); + var ring = rings[i]; + if (i == 0) + { + data.Add(( + EnsureOrientation(ring, true), + new List())); + continue; + } - //mark all the holes assigned to a shell - bool[] holesAssigned = new bool[holes.Count]; - // Find holes - for (int i = 0; i < holes.Count; i++) - { - var testHole = holes[i]; + var testHole = ring; var testEnv = testHole.EnvelopeInternal; var testPt = testHole.GetCoordinateN(0); - //We have the shells sorted - for (int j = 0; j < shells.Count; j++) + bool isHoleForShell = false; + foreach (var (shell, holes) in data) { - var tryShell = shells[j]; + var tryShell = shell; var tryEnv = tryShell.EnvelopeInternal; - bool isContained = tryEnv.Contains(testEnv) && PointLocation.IsInRing(testPt, tryShell.Coordinates); + bool isContained = tryEnv.Contains(testEnv) && PointLocation.IsInRing(testPt, tryShell.Coordinates); // Check if this new containing ring is smaller than the current minimum ring if (isContained) { // Suggested by Brian Macomber and added 3/28/2006: // holes were being found but never added to the holesForShells array // so when converted to geometry by the factory, the inner rings were never created. - var holesForThisShell = holesForShells[j]; - holesForThisShell.Add(testHole); - - if (holesAssigned[i]) - { - throw new InvalidOperationException($"Hole {i} already assigned to a shell!"); - } - holesAssigned[i] = true; // mark the hole as "assigned" to a shell + var holesForThisShell = holes; + holesForThisShell.Add(EnsureOrientation(testHole, false)); + isHoleForShell = true; //Suggested by Bruno.Labrecque //A LinearRing should only be added to one outer shell break; } } - } - - var polygons = new Polygon[shells.Count]; - for (int i = 0; i < shells.Count; i++) - polygons[i] = factory.CreatePolygon(shells[i], holesForShells[i].ToArray()); - - if (!Array.TrueForAll(holesAssigned, b => b)) - { - var list = new List(polygons); - // found some holes not assigned to a shell - for (int i = 0; i < holesAssigned.Length; i++) + if (!isHoleForShell) { - if (!holesAssigned[i]) - list.Add(factory.CreatePolygon(holes[i])); + data.Add(( + EnsureOrientation(ring, true), + new List())); } - polygons = list.ToArray(); } + var polygons = data.Select(t => factory.CreatePolygon( + t.shell, t.holes.ToArray())).ToArray(); if (polygons.Length == 0) geom = factory.CreatePolygon(); else if (polygons.Length == 1) geom = polygons[0]; else geom = factory.CreateMultiPolygon(polygons); - return geom; } + + private LinearRing EnsureOrientation(LinearRing ring, bool asShell) + { + if (ring == null) + throw new ArgumentNullException(nameof(ring)); + + if (ring.IsCCW) + return asShell + ? ring.Factory.CreateLinearRing( + ring.CoordinateSequence.Reversed()) + : ring; + + return !asShell + ? ring.Factory.CreateLinearRing( + ring.CoordinateSequence.Reversed()) + : ring; + + } + /// /// Writes a Geometry to the given binary wirter. /// diff --git a/src/NetTopologySuite.IO.ShapeFile/Handlers/ProbeLinearRing.cs b/src/NetTopologySuite.IO.ShapeFile/Handlers/ProbeLinearRing.cs index 3718f81..594fa37 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Handlers/ProbeLinearRing.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Handlers/ProbeLinearRing.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using NetTopologySuite.Geometries; @@ -7,6 +8,7 @@ namespace NetTopologySuite.IO.Handlers /// Serves to probe linear rings /// /// Bruno.Labrecque@mddep.gouv.qc.ca + [Obsolete("unused", true)] internal class ProbeLinearRing : IComparer { diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs index ff12750..2166cd2 100644 --- a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs +++ b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs @@ -20,9 +20,6 @@ public void TestReadPolygonWithWrongShellOrientation() * The shell_bad_ccw.shp contains a single polygon, with: * - a shell CCW-oriented (like a hole from ESRI specs * - a hole CW-oriented (like a shell from ESRI specs) - * - * ShapefileReader reads this kind of data as two - * separate shells, added to a multipolygon. */ string filePath = Path.Combine( CommonHelpers.TestShapefilesDirectory, @@ -38,14 +35,13 @@ public void TestReadPolygonWithWrongShellOrientation() Assert.That(success, Is.True); var geom = shpReader.Geometry; Assert.That(geom, Is.Not.Null); - Assert.That(geom.IsValid, Is.False); - Assert.That(geom, Is.InstanceOf()); - var mpoly = (MultiPolygon)geom; - Assert.That(mpoly.NumGeometries, Is.EqualTo(2)); - var polys = mpoly.Geometries.Cast(); - CollectionAssert.AllItemsAreNotNull(polys.Select(p => p.Shell)); - CollectionAssert.AllItemsAreNotNull(polys.Select(p => p.Holes)); - Assert.AreEqual(0, polys.Sum(p => p.Holes.Length)); + Assert.That(geom.IsValid, Is.True); + Assert.That(geom.NumGeometries, Is.EqualTo(1)); + Assert.That(geom, Is.InstanceOf()); + var poly = (Polygon)geom.GetGeometryN(0); + Assert.That(poly.Shell, Is.Not.Null); + Assert.That(poly.Holes, Is.Not.Null); + Assert.That(poly.Holes.Length, Is.EqualTo(1)); } } } From 15499f6ace263c4773ec1f196a772a37db786ae1 Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Mon, 24 Jan 2022 09:11:47 +0100 Subject: [PATCH 05/19] added a test that fails --- .../Issue70Fixture.cs | 12 ++++++++++++ .../ShapeFileDataWriterTest.cs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs index 2166cd2..6bb0be7 100644 --- a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs +++ b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs @@ -43,5 +43,17 @@ public void TestReadPolygonWithWrongShellOrientation() Assert.That(poly.Holes, Is.Not.Null); Assert.That(poly.Holes.Length, Is.EqualTo(1)); } + + [Test] + public void TestValidMultiPolygonIsWrittenAndReadAsSameGeometry() + { + const string wkt = @"MULTIPOLYGON (((-124.134 -79.199, -124.141 -79.316, -124.164 -79.431, -124.202 -79.542, -124.254 -79.647, -124.319 -79.745, -124.396 -79.833, -124.484 -79.91, -124.582 -79.975, -124.687 -80.027, -124.798 -80.065, -124.913 -80.088, -125.03 -80.095, -125.147 -80.088, -125.262 -80.065, -125.373 -80.027, -125.478 -79.975, -125.576 -79.91, -125.664 -79.833, -125.741 -79.745, -125.806 -79.647, -125.858 -79.542, -125.896 -79.431, -125.919 -79.316, -125.926 -79.199, -125.919 -79.082, -125.896 -78.967, -125.858 -78.856, -125.806 -78.751, -125.741 -78.653, -125.664 -78.565, -125.576 -78.488, -125.478 -78.423, -125.373 -78.371, -125.262 -78.333, -125.147 -78.31, -125.03 -78.303, -124.913 -78.31, -124.798 -78.333, -124.687 -78.371, -124.582 -78.423, -124.484 -78.488, -124.396 -78.565, -124.319 -78.653, -124.254 -78.751, -124.202 -78.856, -124.164 -78.967, -124.141 -79.082, -124.134 -79.199),(-124.438 -79.199, -124.443 -79.122, -124.459 -79.046, -124.483 -78.973, -124.518 -78.903, -124.561 -78.839, -124.612 -78.781, -124.67 -78.73, -124.734 -78.687, -124.804 -78.652, -124.877 -78.628, -124.953 -78.612, -125.03 -78.607, -125.107 -78.612, -125.183 -78.628, -125.256 -78.652, -125.326 -78.687, -125.39 -78.73, -125.448 -78.781, -125.499 -78.839, -125.542 -78.903, -125.577 -78.973, -125.601 -79.046, -125.617 -79.122, -125.622 -79.199, -125.617 -79.276, -125.601 -79.352, -125.577 -79.425, -125.542 -79.495, -125.499 -79.559, -125.448 -79.617, -125.39 -79.668, -125.326 -79.711, -125.256 -79.746, -125.183 -79.77, -125.107 -79.786, -125.03 -79.791, -124.953 -79.786, -124.877 -79.77, -124.804 -79.746, -124.734 -79.711, -124.67 -79.668, -124.612 -79.617, -124.561 -79.559, -124.518 -79.495, -124.483 -79.425, -124.459 -79.352, -124.443 -79.276, -124.438 -79.199)),((-124.582 -79.199, -124.586 -79.257, -124.597 -79.315, -124.616 -79.371, -124.642 -79.423, -124.674 -79.472, -124.713 -79.516, -124.757 -79.555, -124.806 -79.587, -124.858 -79.613, -124.914 -79.632, -124.972 -79.643, -125.03 -79.647, -125.088 -79.643, -125.146 -79.632, -125.202 -79.613, -125.254 -79.587, -125.303 -79.555, -125.347 -79.516, -125.386 -79.472, -125.418 -79.423, -125.444 -79.371, -125.463 -79.315, -125.474 -79.257, -125.478 -79.199, -125.474 -79.141, -125.463 -79.083, -125.444 -79.027, -125.418 -78.975, -125.386 -78.926, -125.347 -78.882, -125.303 -78.843, -125.254 -78.811, -125.202 -78.785, -125.146 -78.766, -125.088 -78.755, -125.03 -78.751, -124.972 -78.755, -124.914 -78.766, -124.858 -78.785, -124.806 -78.811, -124.757 -78.843, -124.713 -78.882, -124.674 -78.926, -124.642 -78.975, -124.616 -79.027, -124.597 -79.083, -124.586 -79.141, -124.582 -79.199),(-124.896 -79.199, -124.897 -79.181, -124.9 -79.164, -124.906 -79.148, -124.914 -79.132, -124.923 -79.117, -124.935 -79.104, -124.948 -79.092, -124.963 -79.083, -124.979 -79.075, -124.995 -79.069, -125.012 -79.066, -125.03 -79.065, -125.048 -79.066, -125.065 -79.069, -125.081 -79.075, -125.097 -79.083, -125.112 -79.092, -125.125 -79.104, -125.137 -79.117, -125.146 -79.132, -125.154 -79.148, -125.16 -79.164, -125.163 -79.181, -125.164 -79.199, -125.163 -79.217, -125.16 -79.234, -125.154 -79.25, -125.146 -79.266, -125.137 -79.281, -125.125 -79.294, -125.112 -79.306, -125.097 -79.315, -125.081 -79.323, -125.065 -79.329, -125.048 -79.332, -125.03 -79.333, -125.012 -79.332, -124.995 -79.329, -124.979 -79.323, -124.963 -79.315, -124.948 -79.306, -124.935 -79.294, -124.923 -79.281, -124.914 -79.266, -124.906 -79.25, -124.9 -79.234, -124.897 -79.217, -124.896 -79.199))) +"; + var fac = GeometryFactory.Default; + var geom = new WKTReader(fac).Read(wkt); + Assert.That(geom.IsValid, Is.True); + var coll = fac.CreateGeometryCollection(new[] { geom }); + ShapeFileDataWriterTest.DoTest(coll, Ordinates.XY); + } } } diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/ShapeFileDataWriterTest.cs b/test/NetTopologySuite.IO.ShapeFile.Test/ShapeFileDataWriterTest.cs index df6336e..8ea76fa 100644 --- a/test/NetTopologySuite.IO.ShapeFile.Test/ShapeFileDataWriterTest.cs +++ b/test/NetTopologySuite.IO.ShapeFile.Test/ShapeFileDataWriterTest.cs @@ -181,7 +181,7 @@ public void TestReadWritePolygonal() DoTest(geomsWrite, Ordinates.XYZM, false); } - private static void DoTest(GeometryCollection geomsWrite, Ordinates ordinates, bool testGetOrdinate = true) + internal static void DoTest(GeometryCollection geomsWrite, Ordinates ordinates, bool testGetOrdinate = true) { string fileName = string.Empty; From 603a9c1d2a11133aaa76483c34905471ea6c482d Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Tue, 25 Jan 2022 10:43:15 +0100 Subject: [PATCH 06/19] modified the polygon builder logic when a potential hole of a shell is found, we check also the shell holes, to see if any hole contains potential hole. If so, the potential hole can not be considered a hole for the shell, but a separate geometry. --- .../Handlers/PolygonHandler.cs | 60 +++++++++++-------- .../Issue70Fixture.cs | 51 +++++++++++++++- 2 files changed, 83 insertions(+), 28 deletions(-) diff --git a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs index 47da7ca..8d49aca 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs @@ -19,6 +19,7 @@ public PolygonHandler(ShapeGeometryType type) : base(type) { } + /// /// Reads a stream and converts the shapefile record to an equilivent geometry object. /// @@ -90,7 +91,7 @@ public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, var rings = new List(); for (int i = 0; i < sequences.Length; i++) { - //Skip garbage input data with 0 points + // Skip garbage input data with 0 points if (sequences[i].Count < 1) continue; var tmp = EnsureClosedSequence(sequences[i], factory.CoordinateSequenceFactory); @@ -98,52 +99,61 @@ public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, var ring = factory.CreateLinearRing(tmp); rings.Add(ring); } - //Sort rings by area, from bigger to smaller + + // Sort rings by area, from bigger to smaller rings = rings.OrderByDescending(r => r.Factory.CreatePolygon(r).Area).ToList(); - // considering all rings as a potential shell, search the valid holes for any shell + // Considering all rings as a potential shell, search the valid holes for any shell // NOTE: rings order explained: https://gis.stackexchange.com/a/147971/26684 - var data = new List<(LinearRing shell, List holes)>(); + var data = new Stack<(LinearRing shell, List holes)>(); // LIFO for (int i = 0; i < rings.Count; i++) { var ring = rings[i]; if (i == 0) { - data.Add(( + // First ring is "by design" a shell + data.Push(( EnsureOrientation(ring, true), new List())); continue; } var testHole = ring; - var testEnv = testHole.EnvelopeInternal; - var testPt = testHole.GetCoordinateN(0); + var testHoleEnv = testHole.EnvelopeInternal; + var testHolePt = testHole.GetCoordinateN(0); bool isHoleForShell = false; - foreach (var (shell, holes) in data) + foreach (var (tryShell, tryHoles) in data) { - var tryShell = shell; - var tryEnv = tryShell.EnvelopeInternal; - - bool isContained = tryEnv.Contains(testEnv) && PointLocation.IsInRing(testPt, tryShell.Coordinates); - // Check if this new containing ring is smaller than the current minimum ring - if (isContained) + var tryShellEnv = tryShell.EnvelopeInternal; + // Check if the ring is inside any shell: if true, + // it can be considered a potential hole for the shell + bool isTestHoleContainedInTryShell = tryShellEnv.Contains(testHoleEnv) + && PointLocation.IsInRing(testHolePt, tryShell.Coordinates); + if (isTestHoleContainedInTryShell) { - // Suggested by Brian Macomber and added 3/28/2006: - // holes were being found but never added to the holesForShells array - // so when converted to geometry by the factory, the inner rings were never created. - var holesForThisShell = holes; - holesForThisShell.Add(EnsureOrientation(testHole, false)); - - isHoleForShell = true; - //Suggested by Bruno.Labrecque - //A LinearRing should only be added to one outer shell - break; + // Check if the ring is inside any hole of the shell: + // if true, this means that is actually a shell of a distinct + // geometry,and NOT a valid hole for the shell; a hole + // inside another hole is not allowed + bool isTestHoleContainedInAlreadyExistingTryShellHole = false; + foreach (var tryHole in tryHoles) + { + var tryHoleEnv = tryHole.EnvelopeInternal; + isTestHoleContainedInAlreadyExistingTryShellHole = tryHoleEnv.Contains(testHoleEnv) + && PointLocation.IsInRing(testHolePt, tryHole.Coordinates); + } + if (!isTestHoleContainedInAlreadyExistingTryShellHole) + { + tryHoles.Add(EnsureOrientation(testHole, false)); + isHoleForShell = true; + break; + } } } if (!isHoleForShell) { - data.Add(( + data.Push(( EnsureOrientation(ring, true), new List())); } diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs index 6bb0be7..db0301c 100644 --- a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs +++ b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs @@ -3,6 +3,7 @@ using NetTopologySuite.Geometries; using System; using System.Linq; +using System.Collections.Generic; namespace NetTopologySuite.IO.ShapeFile.Test { @@ -44,16 +45,60 @@ public void TestReadPolygonWithWrongShellOrientation() Assert.That(poly.Holes.Length, Is.EqualTo(1)); } + private const string WktMultiPoly = @" +MULTIPOLYGON (((-124.134 -79.199, -124.141 -79.316, -124.164 -79.431, -124.202 -79.542, -124.254 -79.647, -124.319 -79.745, -124.396 -79.833, -124.484 -79.91, -124.582 -79.975, -124.687 -80.027, -124.798 -80.065, -124.913 -80.088, -125.03 -80.095, -125.147 -80.088, -125.262 -80.065, -125.373 -80.027, -125.478 -79.975, -125.576 -79.91, -125.664 -79.833, -125.741 -79.745, -125.806 -79.647, -125.858 -79.542, -125.896 -79.431, -125.919 -79.316, -125.926 -79.199, -125.919 -79.082, -125.896 -78.967, -125.858 -78.856, -125.806 -78.751, -125.741 -78.653, -125.664 -78.565, -125.576 -78.488, -125.478 -78.423, -125.373 -78.371, -125.262 -78.333, -125.147 -78.31, -125.03 -78.303, -124.913 -78.31, -124.798 -78.333, -124.687 -78.371, -124.582 -78.423, -124.484 -78.488, -124.396 -78.565, -124.319 -78.653, -124.254 -78.751, -124.202 -78.856, -124.164 -78.967, -124.141 -79.082, -124.134 -79.199),(-124.438 -79.199, -124.443 -79.122, -124.459 -79.046, -124.483 -78.973, -124.518 -78.903, -124.561 -78.839, -124.612 -78.781, -124.67 -78.73, -124.734 -78.687, -124.804 -78.652, -124.877 -78.628, -124.953 -78.612, -125.03 -78.607, -125.107 -78.612, -125.183 -78.628, -125.256 -78.652, -125.326 -78.687, -125.39 -78.73, -125.448 -78.781, -125.499 -78.839, -125.542 -78.903, -125.577 -78.973, -125.601 -79.046, -125.617 -79.122, -125.622 -79.199, -125.617 -79.276, -125.601 -79.352, -125.577 -79.425, -125.542 -79.495, -125.499 -79.559, -125.448 -79.617, -125.39 -79.668, -125.326 -79.711, -125.256 -79.746, -125.183 -79.77, -125.107 -79.786, -125.03 -79.791, -124.953 -79.786, -124.877 -79.77, -124.804 -79.746, -124.734 -79.711, -124.67 -79.668, -124.612 -79.617, -124.561 -79.559, -124.518 -79.495, -124.483 -79.425, -124.459 -79.352, -124.443 -79.276, -124.438 -79.199)),((-124.582 -79.199, -124.586 -79.257, -124.597 -79.315, -124.616 -79.371, -124.642 -79.423, -124.674 -79.472, -124.713 -79.516, -124.757 -79.555, -124.806 -79.587, -124.858 -79.613, -124.914 -79.632, -124.972 -79.643, -125.03 -79.647, -125.088 -79.643, -125.146 -79.632, -125.202 -79.613, -125.254 -79.587, -125.303 -79.555, -125.347 -79.516, -125.386 -79.472, -125.418 -79.423, -125.444 -79.371, -125.463 -79.315, -125.474 -79.257, -125.478 -79.199, -125.474 -79.141, -125.463 -79.083, -125.444 -79.027, -125.418 -78.975, -125.386 -78.926, -125.347 -78.882, -125.303 -78.843, -125.254 -78.811, -125.202 -78.785, -125.146 -78.766, -125.088 -78.755, -125.03 -78.751, -124.972 -78.755, -124.914 -78.766, -124.858 -78.785, -124.806 -78.811, -124.757 -78.843, -124.713 -78.882, -124.674 -78.926, -124.642 -78.975, -124.616 -79.027, -124.597 -79.083, -124.586 -79.141, -124.582 -79.199),(-124.896 -79.199, -124.897 -79.181, -124.9 -79.164, -124.906 -79.148, -124.914 -79.132, -124.923 -79.117, -124.935 -79.104, -124.948 -79.092, -124.963 -79.083, -124.979 -79.075, -124.995 -79.069, -125.012 -79.066, -125.03 -79.065, -125.048 -79.066, -125.065 -79.069, -125.081 -79.075, -125.097 -79.083, -125.112 -79.092, -125.125 -79.104, -125.137 -79.117, -125.146 -79.132, -125.154 -79.148, -125.16 -79.164, -125.163 -79.181, -125.164 -79.199, -125.163 -79.217, -125.16 -79.234, -125.154 -79.25, -125.146 -79.266, -125.137 -79.281, -125.125 -79.294, -125.112 -79.306, -125.097 -79.315, -125.081 -79.323, -125.065 -79.329, -125.048 -79.332, -125.03 -79.333, -125.012 -79.332, -124.995 -79.329, -124.979 -79.323, -124.963 -79.315, -124.948 -79.306, -124.935 -79.294, -124.923 -79.281, -124.914 -79.266, -124.906 -79.25, -124.9 -79.234, -124.897 -79.217, -124.896 -79.199))) +"; + [Test] public void TestValidMultiPolygonIsWrittenAndReadAsSameGeometry() { - const string wkt = @"MULTIPOLYGON (((-124.134 -79.199, -124.141 -79.316, -124.164 -79.431, -124.202 -79.542, -124.254 -79.647, -124.319 -79.745, -124.396 -79.833, -124.484 -79.91, -124.582 -79.975, -124.687 -80.027, -124.798 -80.065, -124.913 -80.088, -125.03 -80.095, -125.147 -80.088, -125.262 -80.065, -125.373 -80.027, -125.478 -79.975, -125.576 -79.91, -125.664 -79.833, -125.741 -79.745, -125.806 -79.647, -125.858 -79.542, -125.896 -79.431, -125.919 -79.316, -125.926 -79.199, -125.919 -79.082, -125.896 -78.967, -125.858 -78.856, -125.806 -78.751, -125.741 -78.653, -125.664 -78.565, -125.576 -78.488, -125.478 -78.423, -125.373 -78.371, -125.262 -78.333, -125.147 -78.31, -125.03 -78.303, -124.913 -78.31, -124.798 -78.333, -124.687 -78.371, -124.582 -78.423, -124.484 -78.488, -124.396 -78.565, -124.319 -78.653, -124.254 -78.751, -124.202 -78.856, -124.164 -78.967, -124.141 -79.082, -124.134 -79.199),(-124.438 -79.199, -124.443 -79.122, -124.459 -79.046, -124.483 -78.973, -124.518 -78.903, -124.561 -78.839, -124.612 -78.781, -124.67 -78.73, -124.734 -78.687, -124.804 -78.652, -124.877 -78.628, -124.953 -78.612, -125.03 -78.607, -125.107 -78.612, -125.183 -78.628, -125.256 -78.652, -125.326 -78.687, -125.39 -78.73, -125.448 -78.781, -125.499 -78.839, -125.542 -78.903, -125.577 -78.973, -125.601 -79.046, -125.617 -79.122, -125.622 -79.199, -125.617 -79.276, -125.601 -79.352, -125.577 -79.425, -125.542 -79.495, -125.499 -79.559, -125.448 -79.617, -125.39 -79.668, -125.326 -79.711, -125.256 -79.746, -125.183 -79.77, -125.107 -79.786, -125.03 -79.791, -124.953 -79.786, -124.877 -79.77, -124.804 -79.746, -124.734 -79.711, -124.67 -79.668, -124.612 -79.617, -124.561 -79.559, -124.518 -79.495, -124.483 -79.425, -124.459 -79.352, -124.443 -79.276, -124.438 -79.199)),((-124.582 -79.199, -124.586 -79.257, -124.597 -79.315, -124.616 -79.371, -124.642 -79.423, -124.674 -79.472, -124.713 -79.516, -124.757 -79.555, -124.806 -79.587, -124.858 -79.613, -124.914 -79.632, -124.972 -79.643, -125.03 -79.647, -125.088 -79.643, -125.146 -79.632, -125.202 -79.613, -125.254 -79.587, -125.303 -79.555, -125.347 -79.516, -125.386 -79.472, -125.418 -79.423, -125.444 -79.371, -125.463 -79.315, -125.474 -79.257, -125.478 -79.199, -125.474 -79.141, -125.463 -79.083, -125.444 -79.027, -125.418 -78.975, -125.386 -78.926, -125.347 -78.882, -125.303 -78.843, -125.254 -78.811, -125.202 -78.785, -125.146 -78.766, -125.088 -78.755, -125.03 -78.751, -124.972 -78.755, -124.914 -78.766, -124.858 -78.785, -124.806 -78.811, -124.757 -78.843, -124.713 -78.882, -124.674 -78.926, -124.642 -78.975, -124.616 -79.027, -124.597 -79.083, -124.586 -79.141, -124.582 -79.199),(-124.896 -79.199, -124.897 -79.181, -124.9 -79.164, -124.906 -79.148, -124.914 -79.132, -124.923 -79.117, -124.935 -79.104, -124.948 -79.092, -124.963 -79.083, -124.979 -79.075, -124.995 -79.069, -125.012 -79.066, -125.03 -79.065, -125.048 -79.066, -125.065 -79.069, -125.081 -79.075, -125.097 -79.083, -125.112 -79.092, -125.125 -79.104, -125.137 -79.117, -125.146 -79.132, -125.154 -79.148, -125.16 -79.164, -125.163 -79.181, -125.164 -79.199, -125.163 -79.217, -125.16 -79.234, -125.154 -79.25, -125.146 -79.266, -125.137 -79.281, -125.125 -79.294, -125.112 -79.306, -125.097 -79.315, -125.081 -79.323, -125.065 -79.329, -125.048 -79.332, -125.03 -79.333, -125.012 -79.332, -124.995 -79.329, -124.979 -79.323, -124.963 -79.315, -124.948 -79.306, -124.935 -79.294, -124.923 -79.281, -124.914 -79.266, -124.906 -79.25, -124.9 -79.234, -124.897 -79.217, -124.896 -79.199))) -"; var fac = GeometryFactory.Default; - var geom = new WKTReader(fac).Read(wkt); + var geom = new WKTReader(fac).Read(WktMultiPoly); Assert.That(geom.IsValid, Is.True); var coll = fac.CreateGeometryCollection(new[] { geom }); ShapeFileDataWriterTest.DoTest(coll, Ordinates.XY); } + + [Test] + public void TestPolygonWithHoleInsideAnotherHoleIsNotValid() + { + var fac = GeometryFactory.Default; + var geom = new WKTReader(fac).Read(WktMultiPoly); + Assert.That(geom.IsValid, Is.True); + Assert.That(geom, Is.InstanceOf()); + var mpoly = (MultiPolygon)geom; + + var rings = CollectRings() + .OrderByDescending(p => fac.CreatePolygon(p).Area) + .ToList(); + IEnumerable CollectRings() + { + foreach (Polygon poly in mpoly.Geometries) + { + yield return poly.Shell; + foreach (var hole in poly.Holes) + yield return hole; + } + } + Assert.That(rings.Count, Is.EqualTo(4)); + for (int i = 1; i < rings.Count; i++) + { + var prev = rings[i - 1]; + var curr = rings[i]; + Assert.That(prev.EnvelopeInternal + .Contains(curr.EnvelopeInternal), Is.True); + } + + var testPoly = fac.CreatePolygon(rings[0], rings.Skip(1).ToArray()); + Assert.That(testPoly.IsValid, Is.False); + Assert.That(testPoly.Holes.Count, Is.EqualTo(3)); + for (int i = 0; i < testPoly.Holes.Length; i++) + { + var prev = i == 0 ? testPoly.Shell : testPoly.Holes[i - 1]; + var curr = testPoly.Holes[i]; + Assert.That(prev.EnvelopeInternal + .Contains(curr.EnvelopeInternal), Is.True); + } + } } } From 6dd104a97d98a3b3fb82f9751388da8d1eab3fea Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Tue, 25 Jan 2022 12:23:04 +0100 Subject: [PATCH 07/19] minor changes to read the code a bit more readable --- .../Handlers/PolygonHandler.cs | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs index 8d49aca..a3c1e64 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs @@ -100,6 +100,11 @@ public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, rings.Add(ring); } + // Utility function to test if a ring is a potential hole for a shell + bool IsHoleContainedInShell(LinearRing shell, LinearRing hole) => + shell.EnvelopeInternal.Contains(hole.EnvelopeInternal) + && PointLocation.IsInRing(hole.GetCoordinateN(0), shell.Coordinates); + // Sort rings by area, from bigger to smaller rings = rings.OrderByDescending(r => r.Factory.CreatePolygon(r).Area).ToList(); @@ -118,34 +123,20 @@ public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, continue; } - var testHole = ring; - var testHoleEnv = testHole.EnvelopeInternal; - var testHolePt = testHole.GetCoordinateN(0); - bool isHoleForShell = false; foreach (var (tryShell, tryHoles) in data) { - var tryShellEnv = tryShell.EnvelopeInternal; // Check if the ring is inside any shell: if true, // it can be considered a potential hole for the shell - bool isTestHoleContainedInTryShell = tryShellEnv.Contains(testHoleEnv) - && PointLocation.IsInRing(testHolePt, tryShell.Coordinates); - if (isTestHoleContainedInTryShell) + if (IsHoleContainedInShell(tryShell, ring)) { // Check if the ring is inside any hole of the shell: // if true, this means that is actually a shell of a distinct // geometry,and NOT a valid hole for the shell; a hole // inside another hole is not allowed - bool isTestHoleContainedInAlreadyExistingTryShellHole = false; - foreach (var tryHole in tryHoles) - { - var tryHoleEnv = tryHole.EnvelopeInternal; - isTestHoleContainedInAlreadyExistingTryShellHole = tryHoleEnv.Contains(testHoleEnv) - && PointLocation.IsInRing(testHolePt, tryHole.Coordinates); - } - if (!isTestHoleContainedInAlreadyExistingTryShellHole) + if (!tryHoles.Any(tryHole => IsHoleContainedInShell(tryHole, ring))) { - tryHoles.Add(EnsureOrientation(testHole, false)); + tryHoles.Add(EnsureOrientation(ring, false)); isHoleForShell = true; break; } From 2d9b34cbc9bc1b614f9e549f573bbae87e54c49f Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Mon, 7 Feb 2022 10:36:16 +0100 Subject: [PATCH 08/19] introduced conditional flag to handle new polygon builder logic TODO: flag needs to be handled differently, suggestions well accepted --- .../Handlers/PolygonHandler.cs | 130 ++++++++++++++---- .../Handlers/ProbeLinearRing.cs | 4 +- .../Issue70Fixture.cs | 47 +++++-- 3 files changed, 135 insertions(+), 46 deletions(-) diff --git a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs index a3c1e64..6c2165b 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs @@ -12,6 +12,11 @@ namespace NetTopologySuite.IO.Handlers /// public class PolygonHandler : ShapeHandler { + public static bool ExperimentalPolygonBuilderEnabled { get; set; } + + //Thanks to Bruno.Labrecque + private static readonly ProbeLinearRing ProbeLinearRing = new ProbeLinearRing(); + public PolygonHandler() : base(ShapeGeometryType.Polygon) { } @@ -27,8 +32,6 @@ public PolygonHandler(ShapeGeometryType type) /// Total length of the record we are about to read /// The geometry factory to use when making the object. /// The Geometry object that represents the shape file record. - /// - /// public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, GeometryFactory factory) { int totalRead = 0; @@ -85,6 +88,92 @@ public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, // Geometries via CoordinateSequence further down. GetZMValues(file, totalRecordLength, ref totalRead, buffer, skippedList); + var polys = !ExperimentalPolygonBuilderEnabled + ? InternalBuildPolygons(factory, buffer) + : InternalBuildPolygonsExperimental(factory, buffer); + + if (polys.Length == 0) + geom = factory.CreatePolygon(); + else if (polys.Length == 1) + geom = polys[0]; + else + geom = factory.CreateMultiPolygon(polys); + return geom; + } + + private static Polygon[] InternalBuildPolygons(GeometryFactory factory, CoordinateBuffer buffer) + { + // Get the resulting sequences + var sequences = buffer.ToSequences(factory.CoordinateSequenceFactory); + var shells = new List(); + var holes = new List(); + for (int i = 0; i < sequences.Length; i++) + { + //Skip garbage input data with 0 points + if (sequences[i].Count < 1) continue; + + var tmp = EnsureClosedSequence(sequences[i], factory.CoordinateSequenceFactory); + if (tmp == null) continue; + var ring = factory.CreateLinearRing(tmp); + if (ring.IsCCW) + holes.Add(ring); + else + shells.Add(ring); + } + + // Ensure the ring is encoded right + if (shells.Count == 0 && holes.Count == 1) + { + shells.Add(factory.CreateLinearRing(holes[0].CoordinateSequence.Reversed())); + holes.Clear(); + } + + // Now we have lists of all shells and all holes + var holesForShells = new List>(shells.Count); + for (int i = 0; i < shells.Count; i++) + holesForShells.Add(new List()); + + //Thanks to Bruno.Labrecque + //Sort shells by area, rings should only be added to the smallest shell, that contains the ring + shells.Sort(ProbeLinearRing); + + // Find holes + foreach (var testHole in holes) + { + var testEnv = testHole.EnvelopeInternal; + var testPt = testHole.GetCoordinateN(0); + + //We have the shells sorted + for (int j = 0; j < shells.Count; j++) + { + var tryShell = shells[j]; + var tryEnv = tryShell.EnvelopeInternal; + bool isContained = tryEnv.Contains(testEnv) && PointLocation.IsInRing(testPt, tryShell.Coordinates); + + // Check if this new containing ring is smaller than the current minimum ring + if (isContained) + { + // Suggested by Brian Macomber and added 3/28/2006: + // holes were being found but never added to the holesForShells array + // so when converted to geometry by the factory, the inner rings were never created. + var holesForThisShell = holesForShells[j]; + holesForThisShell.Add(testHole); + + //Suggested by Bruno.Labrecque + //A LinearRing should only be added to one outer shell + break; + } + } + } + + var polygons = new Polygon[shells.Count]; + for (int i = 0; i < shells.Count; i++) + polygons[i] = factory.CreatePolygon(shells[i], holesForShells[i].ToArray()); + return polygons; + } + + private static Polygon[] InternalBuildPolygonsExperimental(GeometryFactory factory, CoordinateBuffer buffer) + { // Get the resulting sequences var sequences = buffer.ToSequences(factory.CoordinateSequenceFactory); // Read all rings @@ -105,6 +194,12 @@ bool IsHoleContainedInShell(LinearRing shell, LinearRing hole) => shell.EnvelopeInternal.Contains(hole.EnvelopeInternal) && PointLocation.IsInRing(hole.GetCoordinateN(0), shell.Coordinates); + // Utility function to ensure that shell and holes are correctly oriented + LinearRing EnsureOrientation(LinearRing ring, bool asShell) => + ring.IsCCW + ? !asShell ? ring : ring.Factory.CreateLinearRing(ring.CoordinateSequence.Reversed()) + : asShell ? ring : ring.Factory.CreateLinearRing(ring.CoordinateSequence.Reversed()); + // Sort rings by area, from bigger to smaller rings = rings.OrderByDescending(r => r.Factory.CreatePolygon(r).Area).ToList(); @@ -150,34 +245,9 @@ bool IsHoleContainedInShell(LinearRing shell, LinearRing hole) => } } - var polygons = data.Select(t => factory.CreatePolygon( - t.shell, t.holes.ToArray())).ToArray(); - if (polygons.Length == 0) - geom = factory.CreatePolygon(); - else if (polygons.Length == 1) - geom = polygons[0]; - else - geom = factory.CreateMultiPolygon(polygons); - return geom; - } - - - private LinearRing EnsureOrientation(LinearRing ring, bool asShell) - { - if (ring == null) - throw new ArgumentNullException(nameof(ring)); - - if (ring.IsCCW) - return asShell - ? ring.Factory.CreateLinearRing( - ring.CoordinateSequence.Reversed()) - : ring; - - return !asShell - ? ring.Factory.CreateLinearRing( - ring.CoordinateSequence.Reversed()) - : ring; - + return data + .Select(t => factory.CreatePolygon(t.shell, t.holes.ToArray())) + .ToArray(); } /// diff --git a/src/NetTopologySuite.IO.ShapeFile/Handlers/ProbeLinearRing.cs b/src/NetTopologySuite.IO.ShapeFile/Handlers/ProbeLinearRing.cs index 594fa37..085a942 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Handlers/ProbeLinearRing.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Handlers/ProbeLinearRing.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using NetTopologySuite.Geometries; @@ -8,7 +7,6 @@ namespace NetTopologySuite.IO.Handlers /// Serves to probe linear rings /// /// Bruno.Labrecque@mddep.gouv.qc.ca - [Obsolete("unused", true)] internal class ProbeLinearRing : IComparer { @@ -19,7 +17,7 @@ internal enum Order } internal ProbeLinearRing() - :this(Order.Descending) + : this(Order.Descending) { } diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs index db0301c..e1bdf33 100644 --- a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs +++ b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs @@ -1,9 +1,10 @@ using NUnit.Framework; using System.IO; using NetTopologySuite.Geometries; -using System; using System.Linq; using System.Collections.Generic; +using NetTopologySuite.IO.Handlers; +using System; namespace NetTopologySuite.IO.ShapeFile.Test { @@ -11,17 +12,20 @@ namespace NetTopologySuite.IO.ShapeFile.Test [ShapeFileIssueNumber(70)] public class Issue70Fixture { + [TearDown] + public void AfterEachTestExecution() + { + Console.WriteLine("disabled"); + PolygonHandler.ExperimentalPolygonBuilderEnabled = false; + } + /// - /// + /// The shell_bad_ccw.shp contains a single polygon, with: + /// - a *shell* CCW-oriented(like a hole from ESRI specs + /// - a *hole* CW-oriented (like a shell from ESRI specs) /// - [Test] - public void TestReadPolygonWithWrongShellOrientation() + private static Polygon ReadPolyBadlyOriented() { - /* - * The shell_bad_ccw.shp contains a single polygon, with: - * - a shell CCW-oriented (like a hole from ESRI specs - * - a hole CW-oriented (like a shell from ESRI specs) - */ string filePath = Path.Combine( CommonHelpers.TestShapefilesDirectory, "shell_bad_ccw.shp"); @@ -29,9 +33,7 @@ public void TestReadPolygonWithWrongShellOrientation() string filePathWoExt = Path.Combine( Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath)); - using var shpReader = new ShapefileDataReader( - filePathWoExt, - GeometryFactory.Default); + var shpReader = Shapefile.CreateDataReader(filePathWoExt, GeometryFactory.Default); bool success = shpReader.Read(); Assert.That(success, Is.True); var geom = shpReader.Geometry; @@ -39,12 +41,31 @@ public void TestReadPolygonWithWrongShellOrientation() Assert.That(geom.IsValid, Is.True); Assert.That(geom.NumGeometries, Is.EqualTo(1)); Assert.That(geom, Is.InstanceOf()); - var poly = (Polygon)geom.GetGeometryN(0); + return (Polygon)geom.GetGeometryN(0); + } + + /// + /// + /// + [Test] + public void TestReadPolygonWithWrongShellOrientationReadsHoleWithFlagEnabled() + { + PolygonHandler.ExperimentalPolygonBuilderEnabled = true; + var poly = ReadPolyBadlyOriented(); Assert.That(poly.Shell, Is.Not.Null); Assert.That(poly.Holes, Is.Not.Null); Assert.That(poly.Holes.Length, Is.EqualTo(1)); } + [Test] + public void TestReadPolygonWithWrongShellOrientationDoesntReadHoleWithFlagDisabled() + { + var poly = ReadPolyBadlyOriented(); + Assert.That(poly.Shell, Is.Not.Null); + Assert.That(poly.Holes, Is.Not.Null); + Assert.That(poly.Holes.Length, Is.EqualTo(0)); + } + private const string WktMultiPoly = @" MULTIPOLYGON (((-124.134 -79.199, -124.141 -79.316, -124.164 -79.431, -124.202 -79.542, -124.254 -79.647, -124.319 -79.745, -124.396 -79.833, -124.484 -79.91, -124.582 -79.975, -124.687 -80.027, -124.798 -80.065, -124.913 -80.088, -125.03 -80.095, -125.147 -80.088, -125.262 -80.065, -125.373 -80.027, -125.478 -79.975, -125.576 -79.91, -125.664 -79.833, -125.741 -79.745, -125.806 -79.647, -125.858 -79.542, -125.896 -79.431, -125.919 -79.316, -125.926 -79.199, -125.919 -79.082, -125.896 -78.967, -125.858 -78.856, -125.806 -78.751, -125.741 -78.653, -125.664 -78.565, -125.576 -78.488, -125.478 -78.423, -125.373 -78.371, -125.262 -78.333, -125.147 -78.31, -125.03 -78.303, -124.913 -78.31, -124.798 -78.333, -124.687 -78.371, -124.582 -78.423, -124.484 -78.488, -124.396 -78.565, -124.319 -78.653, -124.254 -78.751, -124.202 -78.856, -124.164 -78.967, -124.141 -79.082, -124.134 -79.199),(-124.438 -79.199, -124.443 -79.122, -124.459 -79.046, -124.483 -78.973, -124.518 -78.903, -124.561 -78.839, -124.612 -78.781, -124.67 -78.73, -124.734 -78.687, -124.804 -78.652, -124.877 -78.628, -124.953 -78.612, -125.03 -78.607, -125.107 -78.612, -125.183 -78.628, -125.256 -78.652, -125.326 -78.687, -125.39 -78.73, -125.448 -78.781, -125.499 -78.839, -125.542 -78.903, -125.577 -78.973, -125.601 -79.046, -125.617 -79.122, -125.622 -79.199, -125.617 -79.276, -125.601 -79.352, -125.577 -79.425, -125.542 -79.495, -125.499 -79.559, -125.448 -79.617, -125.39 -79.668, -125.326 -79.711, -125.256 -79.746, -125.183 -79.77, -125.107 -79.786, -125.03 -79.791, -124.953 -79.786, -124.877 -79.77, -124.804 -79.746, -124.734 -79.711, -124.67 -79.668, -124.612 -79.617, -124.561 -79.559, -124.518 -79.495, -124.483 -79.425, -124.459 -79.352, -124.443 -79.276, -124.438 -79.199)),((-124.582 -79.199, -124.586 -79.257, -124.597 -79.315, -124.616 -79.371, -124.642 -79.423, -124.674 -79.472, -124.713 -79.516, -124.757 -79.555, -124.806 -79.587, -124.858 -79.613, -124.914 -79.632, -124.972 -79.643, -125.03 -79.647, -125.088 -79.643, -125.146 -79.632, -125.202 -79.613, -125.254 -79.587, -125.303 -79.555, -125.347 -79.516, -125.386 -79.472, -125.418 -79.423, -125.444 -79.371, -125.463 -79.315, -125.474 -79.257, -125.478 -79.199, -125.474 -79.141, -125.463 -79.083, -125.444 -79.027, -125.418 -78.975, -125.386 -78.926, -125.347 -78.882, -125.303 -78.843, -125.254 -78.811, -125.202 -78.785, -125.146 -78.766, -125.088 -78.755, -125.03 -78.751, -124.972 -78.755, -124.914 -78.766, -124.858 -78.785, -124.806 -78.811, -124.757 -78.843, -124.713 -78.882, -124.674 -78.926, -124.642 -78.975, -124.616 -79.027, -124.597 -79.083, -124.586 -79.141, -124.582 -79.199),(-124.896 -79.199, -124.897 -79.181, -124.9 -79.164, -124.906 -79.148, -124.914 -79.132, -124.923 -79.117, -124.935 -79.104, -124.948 -79.092, -124.963 -79.083, -124.979 -79.075, -124.995 -79.069, -125.012 -79.066, -125.03 -79.065, -125.048 -79.066, -125.065 -79.069, -125.081 -79.075, -125.097 -79.083, -125.112 -79.092, -125.125 -79.104, -125.137 -79.117, -125.146 -79.132, -125.154 -79.148, -125.16 -79.164, -125.163 -79.181, -125.164 -79.199, -125.163 -79.217, -125.16 -79.234, -125.154 -79.25, -125.146 -79.266, -125.137 -79.281, -125.125 -79.294, -125.112 -79.306, -125.097 -79.315, -125.081 -79.323, -125.065 -79.329, -125.048 -79.332, -125.03 -79.333, -125.012 -79.332, -124.995 -79.329, -124.979 -79.323, -124.963 -79.315, -124.948 -79.306, -124.935 -79.294, -124.923 -79.281, -124.914 -79.266, -124.906 -79.25, -124.9 -79.234, -124.897 -79.217, -124.896 -79.199))) "; From 2739c7e634f64b389bf4f719bdb3c515c3726ded Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Wed, 9 Feb 2022 15:33:35 +0100 Subject: [PATCH 09/19] added tests for ShapeDataReader (too many readers!) and some performance checks (not good vibes...) --- .../Issue70Fixture.cs | 144 +++++++++++++++++- 1 file changed, 136 insertions(+), 8 deletions(-) diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs index e1bdf33..c29d603 100644 --- a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs +++ b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs @@ -3,11 +3,20 @@ using NetTopologySuite.Geometries; using System.Linq; using System.Collections.Generic; +using NetTopologySuite.IO.ShapeFile.Extended; using NetTopologySuite.IO.Handlers; +using NetTopologySuite.Features; using System; +using System.Diagnostics; namespace NetTopologySuite.IO.ShapeFile.Test { + /// + /// The shell_bad_ccw.shp contains a single polygon, with: + /// - a *shell* CCW-oriented(like a hole from ESRI specs + /// - a *hole* CW-oriented (like a shell from ESRI specs) + /// + /// [TestFixture] [ShapeFileIssueNumber(70)] public class Issue70Fixture @@ -15,24 +24,23 @@ public class Issue70Fixture [TearDown] public void AfterEachTestExecution() { - Console.WriteLine("disabled"); PolygonHandler.ExperimentalPolygonBuilderEnabled = false; } - /// - /// The shell_bad_ccw.shp contains a single polygon, with: - /// - a *shell* CCW-oriented(like a hole from ESRI specs - /// - a *hole* CW-oriented (like a shell from ESRI specs) - /// - private static Polygon ReadPolyBadlyOriented() + private static string GetShapefilePath() { string filePath = Path.Combine( CommonHelpers.TestShapefilesDirectory, "shell_bad_ccw.shp"); Assert.That(File.Exists(filePath), Is.True); - string filePathWoExt = Path.Combine( + return Path.Combine( Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath)); + } + + private static Polygon ReadPolyBadlyOriented() + { + string filePathWoExt = GetShapefilePath(); var shpReader = Shapefile.CreateDataReader(filePathWoExt, GeometryFactory.Default); bool success = shpReader.Read(); Assert.That(success, Is.True); @@ -44,6 +52,14 @@ private static Polygon ReadPolyBadlyOriented() return (Polygon)geom.GetGeometryN(0); } + private static Polygon ReadPolyBadlyOrientedUsingShapeDataReader() + { + string filePathWoExt = GetShapefilePath(); + using var shpReader = new ShapeDataReader(filePathWoExt); + var features = shpReader.ReadByMBRFilter(shpReader.ShapefileBounds); + return (Polygon)features.Single().Geometry; + } + /// /// /// @@ -66,6 +82,25 @@ public void TestReadPolygonWithWrongShellOrientationDoesntReadHoleWithFlagDisabl Assert.That(poly.Holes.Length, Is.EqualTo(0)); } + [Test] + public void TestReadPolygonWithWrongShellOrientationReadsHoleWithFlagEnabledUsingShapeDataReader() + { + PolygonHandler.ExperimentalPolygonBuilderEnabled = true; + var poly = ReadPolyBadlyOrientedUsingShapeDataReader(); + Assert.That(poly.Shell, Is.Not.Null); + Assert.That(poly.Holes, Is.Not.Null); + Assert.That(poly.Holes.Length, Is.EqualTo(1)); + } + + [Test] + public void TestReadPolygonWithWrongShellOrientationDoesntReadHoleWithFlagDisabledUsingShapeDataReader() + { + var poly = ReadPolyBadlyOrientedUsingShapeDataReader(); + Assert.That(poly.Shell, Is.Not.Null); + Assert.That(poly.Holes, Is.Not.Null); + Assert.That(poly.Holes.Length, Is.EqualTo(0)); + } + private const string WktMultiPoly = @" MULTIPOLYGON (((-124.134 -79.199, -124.141 -79.316, -124.164 -79.431, -124.202 -79.542, -124.254 -79.647, -124.319 -79.745, -124.396 -79.833, -124.484 -79.91, -124.582 -79.975, -124.687 -80.027, -124.798 -80.065, -124.913 -80.088, -125.03 -80.095, -125.147 -80.088, -125.262 -80.065, -125.373 -80.027, -125.478 -79.975, -125.576 -79.91, -125.664 -79.833, -125.741 -79.745, -125.806 -79.647, -125.858 -79.542, -125.896 -79.431, -125.919 -79.316, -125.926 -79.199, -125.919 -79.082, -125.896 -78.967, -125.858 -78.856, -125.806 -78.751, -125.741 -78.653, -125.664 -78.565, -125.576 -78.488, -125.478 -78.423, -125.373 -78.371, -125.262 -78.333, -125.147 -78.31, -125.03 -78.303, -124.913 -78.31, -124.798 -78.333, -124.687 -78.371, -124.582 -78.423, -124.484 -78.488, -124.396 -78.565, -124.319 -78.653, -124.254 -78.751, -124.202 -78.856, -124.164 -78.967, -124.141 -79.082, -124.134 -79.199),(-124.438 -79.199, -124.443 -79.122, -124.459 -79.046, -124.483 -78.973, -124.518 -78.903, -124.561 -78.839, -124.612 -78.781, -124.67 -78.73, -124.734 -78.687, -124.804 -78.652, -124.877 -78.628, -124.953 -78.612, -125.03 -78.607, -125.107 -78.612, -125.183 -78.628, -125.256 -78.652, -125.326 -78.687, -125.39 -78.73, -125.448 -78.781, -125.499 -78.839, -125.542 -78.903, -125.577 -78.973, -125.601 -79.046, -125.617 -79.122, -125.622 -79.199, -125.617 -79.276, -125.601 -79.352, -125.577 -79.425, -125.542 -79.495, -125.499 -79.559, -125.448 -79.617, -125.39 -79.668, -125.326 -79.711, -125.256 -79.746, -125.183 -79.77, -125.107 -79.786, -125.03 -79.791, -124.953 -79.786, -124.877 -79.77, -124.804 -79.746, -124.734 -79.711, -124.67 -79.668, -124.612 -79.617, -124.561 -79.559, -124.518 -79.495, -124.483 -79.425, -124.459 -79.352, -124.443 -79.276, -124.438 -79.199)),((-124.582 -79.199, -124.586 -79.257, -124.597 -79.315, -124.616 -79.371, -124.642 -79.423, -124.674 -79.472, -124.713 -79.516, -124.757 -79.555, -124.806 -79.587, -124.858 -79.613, -124.914 -79.632, -124.972 -79.643, -125.03 -79.647, -125.088 -79.643, -125.146 -79.632, -125.202 -79.613, -125.254 -79.587, -125.303 -79.555, -125.347 -79.516, -125.386 -79.472, -125.418 -79.423, -125.444 -79.371, -125.463 -79.315, -125.474 -79.257, -125.478 -79.199, -125.474 -79.141, -125.463 -79.083, -125.444 -79.027, -125.418 -78.975, -125.386 -78.926, -125.347 -78.882, -125.303 -78.843, -125.254 -78.811, -125.202 -78.785, -125.146 -78.766, -125.088 -78.755, -125.03 -78.751, -124.972 -78.755, -124.914 -78.766, -124.858 -78.785, -124.806 -78.811, -124.757 -78.843, -124.713 -78.882, -124.674 -78.926, -124.642 -78.975, -124.616 -79.027, -124.597 -79.083, -124.586 -79.141, -124.582 -79.199),(-124.896 -79.199, -124.897 -79.181, -124.9 -79.164, -124.906 -79.148, -124.914 -79.132, -124.923 -79.117, -124.935 -79.104, -124.948 -79.092, -124.963 -79.083, -124.979 -79.075, -124.995 -79.069, -125.012 -79.066, -125.03 -79.065, -125.048 -79.066, -125.065 -79.069, -125.081 -79.075, -125.097 -79.083, -125.112 -79.092, -125.125 -79.104, -125.137 -79.117, -125.146 -79.132, -125.154 -79.148, -125.16 -79.164, -125.163 -79.181, -125.164 -79.199, -125.163 -79.217, -125.16 -79.234, -125.154 -79.25, -125.146 -79.266, -125.137 -79.281, -125.125 -79.294, -125.112 -79.306, -125.097 -79.315, -125.081 -79.323, -125.065 -79.329, -125.048 -79.332, -125.03 -79.333, -125.012 -79.332, -124.995 -79.329, -124.979 -79.323, -124.963 -79.315, -124.948 -79.306, -124.935 -79.294, -124.923 -79.281, -124.914 -79.266, -124.906 -79.25, -124.9 -79.234, -124.897 -79.217, -124.896 -79.199))) "; @@ -121,5 +156,98 @@ IEnumerable CollectRings() .Contains(curr.EnvelopeInternal), Is.True); } } + + [Test] + public void TestPerformancesWithFlagEnabled() + { + var fac = GeometryFactory.Default; + + var features = CreateFeatures(fac, 2345).ToList(); + string fname = Path.ChangeExtension(Path.GetTempFileName(), ".shp"); + var header = ShapefileDataWriter.GetHeader(features[0], features.Count); + var w = Stopwatch.StartNew(); + var writer = new ShapefileDataWriter(fname) { Header = header }; + writer.Write(features); + w.Stop(); + Assert.That(File.Exists(fname), Is.True); + Console.WriteLine($"WRITE => elapsed: '{w.Elapsed}'"); + + string fnameWoExt = Path.Combine( + Path.GetDirectoryName(fname), + Path.GetFileNameWithoutExtension(fname)); + Assert.That(PolygonHandler.ExperimentalPolygonBuilderEnabled, Is.False); + + w.Restart(); + Assert.That(ReadData(fnameWoExt, fac), Is.EqualTo(features.Count)); + w.Stop(); + Console.WriteLine($"flag DISABLED => elapsed: '{w.Elapsed}'"); + + PolygonHandler.ExperimentalPolygonBuilderEnabled = true; + Assert.That(PolygonHandler.ExperimentalPolygonBuilderEnabled, Is.True); + w.Restart(); + Assert.That(ReadData(fnameWoExt, fac), Is.EqualTo(features.Count)); + w.Stop(); + Console.WriteLine($"flag ENABLED => elapsed: '{w.Elapsed}'"); + } + + private static int ReadData(string fname, GeometryFactory fac) + { + int i = 0; + var reader = Shapefile.CreateDataReader(fname, fac); + while (reader.Read()) + { + var geom = reader.Geometry; + Debug.WriteLine($"geom {i}: {geom.NumGeometries}"); + i++; + } + return i; + } + + private static IEnumerable CreateFeatures(GeometryFactory fac, uint count) + { + var list = new List(); + int counter = 0; + int indexer = 0; + for (int i = 1; i < count * 10; i += 10) + { + var shell = fac.CreateLinearRing(new Coordinate[] + { + new Coordinate(1 * i, 1 * i), + new Coordinate(9 * i, 1 * i), + new Coordinate(9 * i, 9* i), + new Coordinate(1 * i, 9* i), + new Coordinate(1 * i, 1* i), + }); + var hole1 = fac.CreateLinearRing(new Coordinate[] + { + new Coordinate(2* i, 2* i), + new Coordinate(3* i, 3* i), + new Coordinate(4* i, 2* i), + new Coordinate(2* i, 2* i), + }); + var hole2 = fac.CreateLinearRing(new Coordinate[] + { + new Coordinate(6* i, 6* i), + new Coordinate(8* i, 8* i), + new Coordinate(7* i, 6* i), + new Coordinate(6* i, 6* i), + }); + var poly = fac.CreatePolygon(shell, new[] { hole1, hole2 }); + list.Add(poly); + if (++counter >= 100) + { + var mpoly = fac.CreateMultiPolygon(list.ToArray()); + var attrs = new AttributesTable { { "id", ++indexer } }; + yield return new Feature(mpoly, attrs); + + list.Clear(); + counter = 0; + } + } + + var mpoly1 = fac.CreateMultiPolygon(list.ToArray()); + var attrs1 = new AttributesTable { { "id", ++indexer } }; + yield return new Feature(mpoly1, attrs1); + } } } From faf29de5ef67657842dd799e22620a504bd6d52d Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Thu, 10 Feb 2022 09:04:35 +0100 Subject: [PATCH 10/19] Update Issue70Fixture.cs --- .../Issue70Fixture.cs | 56 +++++++++++++------ 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs index c29d603..d4dc9e8 100644 --- a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs +++ b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs @@ -158,11 +158,10 @@ IEnumerable CollectRings() } [Test] - public void TestPerformancesWithFlagEnabled() + [Ignore("PerformancesTest")] + public void TestPerformances() { - var fac = GeometryFactory.Default; - - var features = CreateFeatures(fac, 2345).ToList(); + var features = CreateFeatures(GeometryFactory.Default, 50000).ToList(); string fname = Path.ChangeExtension(Path.GetTempFileName(), ".shp"); var header = ShapefileDataWriter.GetHeader(features[0], features.Count); var w = Stopwatch.StartNew(); @@ -172,37 +171,56 @@ public void TestPerformancesWithFlagEnabled() Assert.That(File.Exists(fname), Is.True); Console.WriteLine($"WRITE => elapsed: '{w.Elapsed}'"); + TestReaderPerformances(fname, false, features.Count); + TestReaderPerformances(fname, true, features.Count); + } + + private static void TestReaderPerformances(string fname, + bool shapeReader, int featuresCount) + { string fnameWoExt = Path.Combine( Path.GetDirectoryName(fname), Path.GetFileNameWithoutExtension(fname)); - Assert.That(PolygonHandler.ExperimentalPolygonBuilderEnabled, Is.False); + Console.WriteLine(shapeReader ? "ShapeReader" : "ShapeFileDataReader"); - w.Restart(); - Assert.That(ReadData(fnameWoExt, fac), Is.EqualTo(features.Count)); + PolygonHandler.ExperimentalPolygonBuilderEnabled = false; + Assert.That(PolygonHandler.ExperimentalPolygonBuilderEnabled, Is.False); + var w = Stopwatch.StartNew(); + int readDisabled = shapeReader + ? ReadDataUsingShapeDataReader(fnameWoExt) + : ReadDataUsingShapeFileDataReader(fnameWoExt); w.Stop(); Console.WriteLine($"flag DISABLED => elapsed: '{w.Elapsed}'"); + Assert.That(readDisabled, Is.EqualTo(featuresCount)); PolygonHandler.ExperimentalPolygonBuilderEnabled = true; Assert.That(PolygonHandler.ExperimentalPolygonBuilderEnabled, Is.True); w.Restart(); - Assert.That(ReadData(fnameWoExt, fac), Is.EqualTo(features.Count)); + int readEnabled = shapeReader + ? ReadDataUsingShapeDataReader(fnameWoExt) + : ReadDataUsingShapeFileDataReader(fnameWoExt); w.Stop(); Console.WriteLine($"flag ENABLED => elapsed: '{w.Elapsed}'"); + Assert.That(readEnabled, Is.EqualTo(featuresCount)); } - private static int ReadData(string fname, GeometryFactory fac) + private static int ReadDataUsingShapeFileDataReader(string fname) { int i = 0; - var reader = Shapefile.CreateDataReader(fname, fac); + var reader = Shapefile.CreateDataReader(fname, GeometryFactory.Default); while (reader.Read()) - { - var geom = reader.Geometry; - Debug.WriteLine($"geom {i}: {geom.NumGeometries}"); i++; - } return i; } + private static int ReadDataUsingShapeDataReader(string fname) + { + using var reader = new ShapeDataReader(fname); + var bounds = reader.ShapefileBounds; + var features = reader.ReadByMBRFilter(bounds); + return features.Count(); + } + private static IEnumerable CreateFeatures(GeometryFactory fac, uint count) { var list = new List(); @@ -244,10 +262,12 @@ private static IEnumerable CreateFeatures(GeometryFactory fac, uint co counter = 0; } } - - var mpoly1 = fac.CreateMultiPolygon(list.ToArray()); - var attrs1 = new AttributesTable { { "id", ++indexer } }; - yield return new Feature(mpoly1, attrs1); + if (list.Count != 0) + { + var mpoly1 = fac.CreateMultiPolygon(list.ToArray()); + var attrs1 = new AttributesTable { { "id", ++indexer } }; + yield return new Feature(mpoly1, attrs1); + } } } } From b4c48142efdfd8fb007fda60348c352d77ff197e Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Fri, 11 Feb 2022 09:17:27 +0100 Subject: [PATCH 11/19] moved flag to a static class, and added some docs --- .../Handlers/PolygonHandler.cs | 4 +--- .../Shapefile.FullFat.cs | 3 +-- .../Shapefile.cs | 23 +++++++++++++++++-- .../Issue70Fixture.cs | 21 ++++++++--------- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs index 6c2165b..26dd4df 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs @@ -12,8 +12,6 @@ namespace NetTopologySuite.IO.Handlers /// public class PolygonHandler : ShapeHandler { - public static bool ExperimentalPolygonBuilderEnabled { get; set; } - //Thanks to Bruno.Labrecque private static readonly ProbeLinearRing ProbeLinearRing = new ProbeLinearRing(); @@ -88,7 +86,7 @@ public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, // Geometries via CoordinateSequence further down. GetZMValues(file, totalRecordLength, ref totalRead, buffer, skippedList); - var polys = !ExperimentalPolygonBuilderEnabled + var polys = !Shapefile.ExperimentalPolygonBuilderEnabled ? InternalBuildPolygons(factory, buffer) : InternalBuildPolygonsExperimental(factory, buffer); diff --git a/src/NetTopologySuite.IO.ShapeFile/Shapefile.FullFat.cs b/src/NetTopologySuite.IO.ShapeFile/Shapefile.FullFat.cs index 607548b..7d51b17 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Shapefile.FullFat.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Shapefile.FullFat.cs @@ -6,7 +6,7 @@ namespace NetTopologySuite.IO { - public partial class Shapefile + public static partial class Shapefile { /// /// Creates a DataTable representing the information in a shape file. @@ -63,6 +63,5 @@ public static DataTable CreateDataTable(string filename, string tableName, Geome return table; } - } } diff --git a/src/NetTopologySuite.IO.ShapeFile/Shapefile.cs b/src/NetTopologySuite.IO.ShapeFile/Shapefile.cs index 1c4b2cb..7422eca 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Shapefile.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Shapefile.cs @@ -8,11 +8,30 @@ namespace NetTopologySuite.IO /// /// This class is used to read and write ESRI Shapefiles. /// - public partial class Shapefile + public static partial class Shapefile { internal const int ShapefileId = 9994; internal const int Version = 1000; + /// + /// Here's the logic applied when the flag is enabled: + /// 1. Considering all rings as a potential shell, + /// search the valid holes for any possible shell. + /// 2. Check if the ring is inside any shell: if true, + /// it can be considered a potential hole for the shell. + /// 3. Check if the ring is inside any hole of the shell: if true, + /// this means that is actually a shell of a distinct geometry, + /// and NOT a valid hole for the shell; a hole inside + /// another hole is not allowed. + /// + /// + /// Note that the experimental polygon builder is considerably slower + /// - three to four times slower, in fact - than the standard polygon builder, + /// especially for complex polygons(i.e.: polygons with a large number of holes). + /// + /// Rings order explained. + public static bool ExperimentalPolygonBuilderEnabled { get; set; } + /// /// Given a geomtery object, returns the equivalent shape file type. /// @@ -98,7 +117,7 @@ public static ShapeGeometryType GetShapeType(Geometry geom) /// The itself if not-empty AND not a collection, /// or the first not-empty child if is /// a collection,or null. - /// + /// private static Geometry TryGetNonEmptyGeometry(Geometry geom) { if (geom == null || geom.IsEmpty) diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs index d4dc9e8..0416816 100644 --- a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs +++ b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Collections.Generic; using NetTopologySuite.IO.ShapeFile.Extended; -using NetTopologySuite.IO.Handlers; using NetTopologySuite.Features; using System; using System.Diagnostics; @@ -24,7 +23,7 @@ public class Issue70Fixture [TearDown] public void AfterEachTestExecution() { - PolygonHandler.ExperimentalPolygonBuilderEnabled = false; + Shapefile.ExperimentalPolygonBuilderEnabled = false; } private static string GetShapefilePath() @@ -66,7 +65,7 @@ private static Polygon ReadPolyBadlyOrientedUsingShapeDataReader() [Test] public void TestReadPolygonWithWrongShellOrientationReadsHoleWithFlagEnabled() { - PolygonHandler.ExperimentalPolygonBuilderEnabled = true; + Shapefile.ExperimentalPolygonBuilderEnabled = true; var poly = ReadPolyBadlyOriented(); Assert.That(poly.Shell, Is.Not.Null); Assert.That(poly.Holes, Is.Not.Null); @@ -85,7 +84,7 @@ public void TestReadPolygonWithWrongShellOrientationDoesntReadHoleWithFlagDisabl [Test] public void TestReadPolygonWithWrongShellOrientationReadsHoleWithFlagEnabledUsingShapeDataReader() { - PolygonHandler.ExperimentalPolygonBuilderEnabled = true; + Shapefile.ExperimentalPolygonBuilderEnabled = true; var poly = ReadPolyBadlyOrientedUsingShapeDataReader(); Assert.That(poly.Shell, Is.Not.Null); Assert.That(poly.Holes, Is.Not.Null); @@ -161,7 +160,7 @@ IEnumerable CollectRings() [Ignore("PerformancesTest")] public void TestPerformances() { - var features = CreateFeatures(GeometryFactory.Default, 50000).ToList(); + var features = CreateFeatures(GeometryFactory.Default, 500000, 5).ToList(); string fname = Path.ChangeExtension(Path.GetTempFileName(), ".shp"); var header = ShapefileDataWriter.GetHeader(features[0], features.Count); var w = Stopwatch.StartNew(); @@ -183,8 +182,8 @@ private static void TestReaderPerformances(string fname, Path.GetFileNameWithoutExtension(fname)); Console.WriteLine(shapeReader ? "ShapeReader" : "ShapeFileDataReader"); - PolygonHandler.ExperimentalPolygonBuilderEnabled = false; - Assert.That(PolygonHandler.ExperimentalPolygonBuilderEnabled, Is.False); + Shapefile.ExperimentalPolygonBuilderEnabled = false; + Assert.That(Shapefile.ExperimentalPolygonBuilderEnabled, Is.False); var w = Stopwatch.StartNew(); int readDisabled = shapeReader ? ReadDataUsingShapeDataReader(fnameWoExt) @@ -193,8 +192,8 @@ private static void TestReaderPerformances(string fname, Console.WriteLine($"flag DISABLED => elapsed: '{w.Elapsed}'"); Assert.That(readDisabled, Is.EqualTo(featuresCount)); - PolygonHandler.ExperimentalPolygonBuilderEnabled = true; - Assert.That(PolygonHandler.ExperimentalPolygonBuilderEnabled, Is.True); + Shapefile.ExperimentalPolygonBuilderEnabled = true; + Assert.That(Shapefile.ExperimentalPolygonBuilderEnabled, Is.True); w.Restart(); int readEnabled = shapeReader ? ReadDataUsingShapeDataReader(fnameWoExt) @@ -221,12 +220,12 @@ private static int ReadDataUsingShapeDataReader(string fname) return features.Count(); } - private static IEnumerable CreateFeatures(GeometryFactory fac, uint count) + private static IEnumerable CreateFeatures(GeometryFactory fac, uint count, uint step) { var list = new List(); int counter = 0; int indexer = 0; - for (int i = 1; i < count * 10; i += 10) + for (uint i = 1; i < count * 10; i += step) { var shell = fac.CreateLinearRing(new Coordinate[] { From 90ff2a1676e78d72cb91641ff1258c5532dbe2d9 Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Fri, 11 Feb 2022 09:26:48 +0100 Subject: [PATCH 12/19] Delete shell_bad_ccw.prj --- .../TestShapefiles/shell_bad_ccw.prj | 1 - 1 file changed, 1 deletion(-) delete mode 100644 test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.prj diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.prj b/test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.prj deleted file mode 100644 index 8159721..0000000 --- a/test/NetTopologySuite.IO.ShapeFile.Test/TestShapefiles/shell_bad_ccw.prj +++ /dev/null @@ -1 +0,0 @@ -PROJCS["WGS_1984_UTM_Zone_35N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",27.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file From 398140abe4b27082a66a90da388ae92a0721fbd2 Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Tue, 15 Feb 2022 12:04:58 +0100 Subject: [PATCH 13/19] added some performance tests --- .../Issue70Fixture.cs | 149 ++++++++++++------ 1 file changed, 97 insertions(+), 52 deletions(-) diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs index 0416816..e6a21a1 100644 --- a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs +++ b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs @@ -156,11 +156,59 @@ IEnumerable CollectRings() } } - [Test] - [Ignore("PerformancesTest")] - public void TestPerformances() + private static IEnumerable CreateFeatures(GeometryFactory fac, uint count, uint step) + { + var list = new List(); + int counter = 0; + int indexer = 0; + for (uint i = 1; i < count * 10; i += step) + { + var shell = fac.CreateLinearRing(new Coordinate[] + { + new Coordinate(1 * i, 1 * i), + new Coordinate(9 * i, 1 * i), + new Coordinate(9 * i, 9* i), + new Coordinate(1 * i, 9* i), + new Coordinate(1 * i, 1* i), + }); + var hole1 = fac.CreateLinearRing(new Coordinate[] + { + new Coordinate(2* i, 2* i), + new Coordinate(3* i, 3* i), + new Coordinate(4* i, 2* i), + new Coordinate(2* i, 2* i), + }); + var hole2 = fac.CreateLinearRing(new Coordinate[] + { + new Coordinate(6* i, 6* i), + new Coordinate(8* i, 8* i), + new Coordinate(7* i, 6* i), + new Coordinate(6* i, 6* i), + }); + var poly = fac.CreatePolygon(shell, new[] { hole1, hole2 }); + list.Add(poly); + if (++counter >= 100) + { + var mpoly = fac.CreateMultiPolygon(list.ToArray()); + var attrs = new AttributesTable { { "id", ++indexer } }; + yield return new Feature(mpoly, attrs); + + list.Clear(); + counter = 0; + } + } + if (list.Count != 0) + { + var mpoly1 = fac.CreateMultiPolygon(list.ToArray()); + var attrs1 = new AttributesTable { { "id", ++indexer } }; + yield return new Feature(mpoly1, attrs1); + } + } + + private static string WriteFeatures(out int featuresCount) { - var features = CreateFeatures(GeometryFactory.Default, 500000, 5).ToList(); + var features = CreateFeatures(GeometryFactory.Default, 500000, 50).ToList(); + featuresCount = features.Count; string fname = Path.ChangeExtension(Path.GetTempFileName(), ".shp"); var header = ShapefileDataWriter.GetHeader(features[0], features.Count); var w = Stopwatch.StartNew(); @@ -169,9 +217,7 @@ public void TestPerformances() w.Stop(); Assert.That(File.Exists(fname), Is.True); Console.WriteLine($"WRITE => elapsed: '{w.Elapsed}'"); - - TestReaderPerformances(fname, false, features.Count); - TestReaderPerformances(fname, true, features.Count); + return fname; } private static void TestReaderPerformances(string fname, @@ -220,53 +266,52 @@ private static int ReadDataUsingShapeDataReader(string fname) return features.Count(); } - private static IEnumerable CreateFeatures(GeometryFactory fac, uint count, uint step) + [Test] + [Ignore("PerformancesTest")] + public void TestPerformances() { - var list = new List(); - int counter = 0; - int indexer = 0; - for (uint i = 1; i < count * 10; i += step) - { - var shell = fac.CreateLinearRing(new Coordinate[] - { - new Coordinate(1 * i, 1 * i), - new Coordinate(9 * i, 1 * i), - new Coordinate(9 * i, 9* i), - new Coordinate(1 * i, 9* i), - new Coordinate(1 * i, 1* i), - }); - var hole1 = fac.CreateLinearRing(new Coordinate[] - { - new Coordinate(2* i, 2* i), - new Coordinate(3* i, 3* i), - new Coordinate(4* i, 2* i), - new Coordinate(2* i, 2* i), - }); - var hole2 = fac.CreateLinearRing(new Coordinate[] - { - new Coordinate(6* i, 6* i), - new Coordinate(8* i, 8* i), - new Coordinate(7* i, 6* i), - new Coordinate(6* i, 6* i), - }); - var poly = fac.CreatePolygon(shell, new[] { hole1, hole2 }); - list.Add(poly); - if (++counter >= 100) - { - var mpoly = fac.CreateMultiPolygon(list.ToArray()); - var attrs = new AttributesTable { { "id", ++indexer } }; - yield return new Feature(mpoly, attrs); + string fname = WriteFeatures(out int featuresCount); + TestReaderPerformances(fname, false, featuresCount); + TestReaderPerformances(fname, true, featuresCount); + } - list.Clear(); - counter = 0; - } - } - if (list.Count != 0) - { - var mpoly1 = fac.CreateMultiPolygon(list.ToArray()); - var attrs1 = new AttributesTable { { "id", ++indexer } }; - yield return new Feature(mpoly1, attrs1); - } + private static TimeSpan TestReaderPerformancesSimple(string fname) + { + string fnameWoExt = Path.Combine( + Path.GetDirectoryName(fname), + Path.GetFileNameWithoutExtension(fname)); + var w = Stopwatch.StartNew(); + ReadDataUsingShapeDataReader(fnameWoExt); + w.Stop(); + return w.Elapsed; + } + + private const int PerfTestNum = 20; + + [Test] + [Ignore("PerformancesTest")] + public void TestPerformancesAvgWithFlagDisabled() + { + string fname = WriteFeatures(out int _); + Shapefile.ExperimentalPolygonBuilderEnabled = false; + Assert.That(Shapefile.ExperimentalPolygonBuilderEnabled, Is.False); + double avg = Enumerable.Range(0, PerfTestNum) + .Select(_ => TestReaderPerformancesSimple(fname)) + .Average(ts => ts.TotalMilliseconds); + Console.WriteLine($"flag DISABLED: n='{PerfTestNum}' => ms='{avg}'"); + } + + [Test] + [Ignore("PerformancesTest")] + public void TestPerformancesAvgWithFlagEnabled() + { + string fname = WriteFeatures(out int _); + Shapefile.ExperimentalPolygonBuilderEnabled = true; + Assert.That(Shapefile.ExperimentalPolygonBuilderEnabled, Is.True); + double avg = Enumerable.Range(0, PerfTestNum) + .Select(_ => TestReaderPerformancesSimple(fname)) + .Average(ts => ts.TotalMilliseconds); + Console.WriteLine($"flag ENABLED: n='{PerfTestNum}' => ms='{avg}'"); } } } From 389593baf31437d299d18ff14381396817f42188 Mon Sep 17 00:00:00 2001 From: Felix Obermaier Date: Tue, 15 Feb 2022 14:08:11 +0100 Subject: [PATCH 14/19] Do sort on Polygon --- .../Handlers/PolygonHandler.cs | 33 ++++++++++--------- .../Handlers/ProbeLinearRing.cs | 16 +++++++-- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs index 26dd4df..4e8952e 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs @@ -35,7 +35,7 @@ public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, int totalRead = 0; var type = (ShapeGeometryType)ReadInt32(file, totalRecordLength, ref totalRead); if (type == ShapeGeometryType.NullShape) - return factory.CreatePolygon(null, null); + return factory.CreatePolygon(); if (type != ShapeType) throw new ShapefileException(string.Format("Encountered a '{0}' instead of a '{1}'", type, ShapeType)); @@ -103,8 +103,8 @@ private static Polygon[] InternalBuildPolygons(GeometryFactory factory, Coordina { // Get the resulting sequences var sequences = buffer.ToSequences(factory.CoordinateSequenceFactory); - var shells = new List(); - var holes = new List(); + var shells = new List(); + var holes = new List(); for (int i = 0; i < sequences.Length; i++) { //Skip garbage input data with 0 points @@ -114,16 +114,19 @@ private static Polygon[] InternalBuildPolygons(GeometryFactory factory, Coordina if (tmp == null) continue; var ring = factory.CreateLinearRing(tmp); if (ring.IsCCW) - holes.Add(ring); + holes.Add(factory.CreatePolygon(ring)); else - shells.Add(ring); + shells.Add(factory.CreatePolygon(ring)); } // Ensure the ring is encoded right if (shells.Count == 0 && holes.Count == 1) { - shells.Add(factory.CreateLinearRing(holes[0].CoordinateSequence.Reversed())); + shells.Add((Polygon)((Geometry)holes[0]).Reverse()); holes.Clear(); + + // We have one polygon, we don't have to do anything else + return shells.ToArray(); } // Now we have lists of all shells and all holes @@ -139,7 +142,7 @@ private static Polygon[] InternalBuildPolygons(GeometryFactory factory, Coordina foreach (var testHole in holes) { var testEnv = testHole.EnvelopeInternal; - var testPt = testHole.GetCoordinateN(0); + var testPt = testHole.ExteriorRing.GetCoordinateN(0); //We have the shells sorted for (int j = 0; j < shells.Count; j++) @@ -155,7 +158,7 @@ private static Polygon[] InternalBuildPolygons(GeometryFactory factory, Coordina // holes were being found but never added to the holesForShells array // so when converted to geometry by the factory, the inner rings were never created. var holesForThisShell = holesForShells[j]; - holesForThisShell.Add(testHole); + holesForThisShell.Add((LinearRing)testHole.ExteriorRing); //Suggested by Bruno.Labrecque //A LinearRing should only be added to one outer shell @@ -166,7 +169,7 @@ private static Polygon[] InternalBuildPolygons(GeometryFactory factory, Coordina var polygons = new Polygon[shells.Count]; for (int i = 0; i < shells.Count; i++) - polygons[i] = factory.CreatePolygon(shells[i], holesForShells[i].ToArray()); + polygons[i] = factory.CreatePolygon((LinearRing)shells[i].ExteriorRing, holesForShells[i].ToArray()); return polygons; } @@ -175,7 +178,7 @@ private static Polygon[] InternalBuildPolygonsExperimental(GeometryFactory facto // Get the resulting sequences var sequences = buffer.ToSequences(factory.CoordinateSequenceFactory); // Read all rings - var rings = new List(); + var rings = new List(); for (int i = 0; i < sequences.Length; i++) { // Skip garbage input data with 0 points @@ -184,7 +187,7 @@ private static Polygon[] InternalBuildPolygonsExperimental(GeometryFactory facto var tmp = EnsureClosedSequence(sequences[i], factory.CoordinateSequenceFactory); if (tmp == null) continue; var ring = factory.CreateLinearRing(tmp); - rings.Add(ring); + rings.Add(factory.CreatePolygon(ring)); } // Utility function to test if a ring is a potential hole for a shell @@ -195,18 +198,18 @@ bool IsHoleContainedInShell(LinearRing shell, LinearRing hole) => // Utility function to ensure that shell and holes are correctly oriented LinearRing EnsureOrientation(LinearRing ring, bool asShell) => ring.IsCCW - ? !asShell ? ring : ring.Factory.CreateLinearRing(ring.CoordinateSequence.Reversed()) - : asShell ? ring : ring.Factory.CreateLinearRing(ring.CoordinateSequence.Reversed()); + ? !asShell ? ring : (LinearRing)((Geometry)ring).Reverse() + : asShell ? ring : (LinearRing)((Geometry)ring).Reverse(); // Sort rings by area, from bigger to smaller - rings = rings.OrderByDescending(r => r.Factory.CreatePolygon(r).Area).ToList(); + rings = rings.OrderByDescending(r => r.Area).ToList(); // Considering all rings as a potential shell, search the valid holes for any shell // NOTE: rings order explained: https://gis.stackexchange.com/a/147971/26684 var data = new Stack<(LinearRing shell, List holes)>(); // LIFO for (int i = 0; i < rings.Count; i++) { - var ring = rings[i]; + var ring = (LinearRing)rings[i].ExteriorRing; if (i == 0) { // First ring is "by design" a shell diff --git a/src/NetTopologySuite.IO.ShapeFile/Handlers/ProbeLinearRing.cs b/src/NetTopologySuite.IO.ShapeFile/Handlers/ProbeLinearRing.cs index 085a942..93fc5a8 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Handlers/ProbeLinearRing.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Handlers/ProbeLinearRing.cs @@ -7,7 +7,7 @@ namespace NetTopologySuite.IO.Handlers /// Serves to probe linear rings /// /// Bruno.Labrecque@mddep.gouv.qc.ca - internal class ProbeLinearRing : IComparer + internal class ProbeLinearRing : IComparer, IComparer { internal enum Order @@ -40,16 +40,28 @@ internal ProbeLinearRing(Order order) private readonly int _r2; + [System.Obsolete()] public int Compare(LinearRing x, LinearRing y) { var pm = PrecisionModel.MostPrecise(x.PrecisionModel, y.PrecisionModel); - var geometryFactory = new GeometryFactory(pm); + var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(pm, x.SRID); + // If we keep creating new polygons for each comparison + // we can't cache values like Area or Length var p1 = geometryFactory.CreatePolygon(x, null); var p2 = geometryFactory.CreatePolygon(y, null); ; + Compare(p1, p2); + if (p1.Area < p2.Area) return _r1; return p1.Area > p2.Area ? _r2 : 0; } + + public int Compare(Polygon x, Polygon y) + { + if (x.Area < y.Area) + return _r1; + return x.Area > y.Area ? _r2 : 0; + } } } From 0e2db23dc7e6878ad21cde22215059b026877249 Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Tue, 15 Feb 2022 15:08:23 +0100 Subject: [PATCH 15/19] removed unnecessary (and, actually, broken) check --- .../Handlers/PolygonHandler.cs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs index 4e8952e..4c2439b 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs @@ -195,12 +195,6 @@ bool IsHoleContainedInShell(LinearRing shell, LinearRing hole) => shell.EnvelopeInternal.Contains(hole.EnvelopeInternal) && PointLocation.IsInRing(hole.GetCoordinateN(0), shell.Coordinates); - // Utility function to ensure that shell and holes are correctly oriented - LinearRing EnsureOrientation(LinearRing ring, bool asShell) => - ring.IsCCW - ? !asShell ? ring : (LinearRing)((Geometry)ring).Reverse() - : asShell ? ring : (LinearRing)((Geometry)ring).Reverse(); - // Sort rings by area, from bigger to smaller rings = rings.OrderByDescending(r => r.Area).ToList(); @@ -213,9 +207,7 @@ LinearRing EnsureOrientation(LinearRing ring, bool asShell) => if (i == 0) { // First ring is "by design" a shell - data.Push(( - EnsureOrientation(ring, true), - new List())); + data.Push((ring, new List())); continue; } @@ -232,7 +224,7 @@ LinearRing EnsureOrientation(LinearRing ring, bool asShell) => // inside another hole is not allowed if (!tryHoles.Any(tryHole => IsHoleContainedInShell(tryHole, ring))) { - tryHoles.Add(EnsureOrientation(ring, false)); + tryHoles.Add(ring); isHoleForShell = true; break; } @@ -240,9 +232,7 @@ LinearRing EnsureOrientation(LinearRing ring, bool asShell) => } if (!isHoleForShell) { - data.Push(( - EnsureOrientation(ring, true), - new List())); + data.Push((ring, new List())); } } From f36409a9a84a638dcb4ec7496d883d77efd2aa26 Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Wed, 16 Feb 2022 10:05:03 +0100 Subject: [PATCH 16/19] added perftest stub --- NetTopologySuite.IO.ShapeFile.sln | 10 +- PerfApp/Perf.cs | 46 + PerfApp/PerfApp.csproj | 27 + PerfApp/Program.cs | 12 + PerfApp/Utils.cs | 71 + .../nts_develop/NetTopologySuite.deps.json | 152 + PerfApp/nts_develop/NetTopologySuite.dll | Bin 0 -> 759296 bytes PerfApp/nts_develop/NetTopologySuite.xml | 47789 +++++++++++++++ .../nts_patch_595/NetTopologySuite.deps.json | 152 + PerfApp/nts_patch_595/NetTopologySuite.dll | Bin 0 -> 759808 bytes PerfApp/nts_patch_595/NetTopologySuite.xml | 47799 ++++++++++++++++ 11 files changed, 96056 insertions(+), 2 deletions(-) create mode 100644 PerfApp/Perf.cs create mode 100644 PerfApp/PerfApp.csproj create mode 100644 PerfApp/Program.cs create mode 100644 PerfApp/Utils.cs create mode 100644 PerfApp/nts_develop/NetTopologySuite.deps.json create mode 100644 PerfApp/nts_develop/NetTopologySuite.dll create mode 100644 PerfApp/nts_develop/NetTopologySuite.xml create mode 100644 PerfApp/nts_patch_595/NetTopologySuite.deps.json create mode 100644 PerfApp/nts_patch_595/NetTopologySuite.dll create mode 100644 PerfApp/nts_patch_595/NetTopologySuite.xml diff --git a/NetTopologySuite.IO.ShapeFile.sln b/NetTopologySuite.IO.ShapeFile.sln index 3b72122..6568473 100644 --- a/NetTopologySuite.IO.ShapeFile.sln +++ b/NetTopologySuite.IO.ShapeFile.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27004.2009 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31321.278 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B0923F22-AF00-46DA-B5CE-73F4D398DE37}" ProjectSection(SolutionItems) = preProject @@ -16,6 +16,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetTopologySuite.IO.GDB", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetTopologySuite.IO.ShapeFile.Test", "test\NetTopologySuite.IO.ShapeFile.Test\NetTopologySuite.IO.ShapeFile.Test.csproj", "{89254B6E-F130-41F3-8956-2F790E99C6F0}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerfApp", "PerfApp\PerfApp.csproj", "{F1B36647-56E8-492B-8521-6C500ED04389}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -34,6 +36,10 @@ Global {89254B6E-F130-41F3-8956-2F790E99C6F0}.Debug|Any CPU.Build.0 = Debug|Any CPU {89254B6E-F130-41F3-8956-2F790E99C6F0}.Release|Any CPU.ActiveCfg = Release|Any CPU {89254B6E-F130-41F3-8956-2F790E99C6F0}.Release|Any CPU.Build.0 = Release|Any CPU + {F1B36647-56E8-492B-8521-6C500ED04389}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F1B36647-56E8-492B-8521-6C500ED04389}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F1B36647-56E8-492B-8521-6C500ED04389}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F1B36647-56E8-492B-8521-6C500ED04389}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PerfApp/Perf.cs b/PerfApp/Perf.cs new file mode 100644 index 0000000..9770d5b --- /dev/null +++ b/PerfApp/Perf.cs @@ -0,0 +1,46 @@ +using BenchmarkDotNet.Attributes; +using NetTopologySuite.Geometries; +using NetTopologySuite.IO; +using System.Linq; + +namespace PerfApp +{ + public class Perf + { + private const int Count = 50000; + private const int Step = 10; + + private static readonly GeometryFactory Fac = GeometryFactory.Default; + + private readonly string fname; + + public Perf() + { + var features = Utils.CreateFeatures(Fac, Count, Step).ToList(); + fname = Utils.WriteFeatures(features); + } + + private int InternalRead() + { + int i = 0; + var reader = Shapefile.CreateDataReader(fname, Fac); + while (reader.Read()) + i++; + return i; + } + + [Benchmark] + public int ReadWithFlagDisabled() + { + Shapefile.ExperimentalPolygonBuilderEnabled = false; + return InternalRead(); + } + + [Benchmark] + public int ReadWithFlagEnabled() + { + Shapefile.ExperimentalPolygonBuilderEnabled = true; + return InternalRead(); + } + } +} diff --git a/PerfApp/PerfApp.csproj b/PerfApp/PerfApp.csproj new file mode 100644 index 0000000..d0530cd --- /dev/null +++ b/PerfApp/PerfApp.csproj @@ -0,0 +1,27 @@ + + + + Exe + net5.0 + + + + + + + + + + + + + + + + + + + + + + diff --git a/PerfApp/Program.cs b/PerfApp/Program.cs new file mode 100644 index 0000000..230dd97 --- /dev/null +++ b/PerfApp/Program.cs @@ -0,0 +1,12 @@ +using BenchmarkDotNet.Running; + +namespace PerfApp +{ + class Program + { + static void Main(string[] args) + { + var summary = BenchmarkRunner.Run(); + } + } +} diff --git a/PerfApp/Utils.cs b/PerfApp/Utils.cs new file mode 100644 index 0000000..5a0fc8e --- /dev/null +++ b/PerfApp/Utils.cs @@ -0,0 +1,71 @@ +using NetTopologySuite.Features; +using NetTopologySuite.Geometries; +using NetTopologySuite.IO; +using System.Collections.Generic; +using System.IO; + +namespace PerfApp +{ + internal static class Utils + { + internal static IEnumerable CreateFeatures(GeometryFactory fac, uint count, uint step) + { + var list = new List(); + int counter = 0; + int indexer = 0; + for (uint i = 1; i < count * 10; i += step) + { + var shell = fac.CreateLinearRing(new Coordinate[] + { + new Coordinate(1 * i, 1 * i), + new Coordinate(9 * i, 1 * i), + new Coordinate(9 * i, 9* i), + new Coordinate(1 * i, 9* i), + new Coordinate(1 * i, 1* i), + }); + var hole1 = fac.CreateLinearRing(new Coordinate[] + { + new Coordinate(2* i, 2* i), + new Coordinate(3* i, 3* i), + new Coordinate(4* i, 2* i), + new Coordinate(2* i, 2* i), + }); + var hole2 = fac.CreateLinearRing(new Coordinate[] + { + new Coordinate(6* i, 6* i), + new Coordinate(8* i, 8* i), + new Coordinate(7* i, 6* i), + new Coordinate(6* i, 6* i), + }); + var poly = fac.CreatePolygon(shell, new[] { hole1, hole2 }); + list.Add(poly); + if (++counter >= 100) + { + var mpoly = fac.CreateMultiPolygon(list.ToArray()); + var attrs = new AttributesTable { { "id", ++indexer } }; + yield return new Feature(mpoly, attrs); + + list.Clear(); + counter = 0; + } + } + if (list.Count != 0) + { + var mpoly1 = fac.CreateMultiPolygon(list.ToArray()); + var attrs1 = new AttributesTable { { "id", ++indexer } }; + yield return new Feature(mpoly1, attrs1); + } + } + + internal static string WriteFeatures(IList features) + { + string fname = Path.ChangeExtension(Path.GetTempFileName(), ".shp"); + var header = ShapefileDataWriter.GetHeader(features[0], features.Count); + var writer = new ShapefileDataWriter(fname) { Header = header }; + writer.Write(features); + return Path.Combine( + Path.GetDirectoryName(fname), + Path.GetFileNameWithoutExtension(fname)); + } + } +} diff --git a/PerfApp/nts_develop/NetTopologySuite.deps.json b/PerfApp/nts_develop/NetTopologySuite.deps.json new file mode 100644 index 0000000..e2f9d2b --- /dev/null +++ b/PerfApp/nts_develop/NetTopologySuite.deps.json @@ -0,0 +1,152 @@ +{ + "runtimeTarget": { + "name": ".NETStandard,Version=v2.0/", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETStandard,Version=v2.0": {}, + ".NETStandard,Version=v2.0/": { + "NetTopologySuite/2.5.0-pre.190390493+local": { + "dependencies": { + "Microsoft.DotNet.ApiCompat": "6.0.0-beta.21159.11", + "Microsoft.SourceLink.GitHub": "1.1.1", + "NETStandard.Library": "2.0.3", + "System.Memory": "4.5.4" + }, + "runtime": { + "NetTopologySuite.dll": {} + } + }, + "Microsoft.Build.Tasks.Git/1.1.1": {}, + "Microsoft.DotNet.ApiCompat/6.0.0-beta.21159.11": {}, + "Microsoft.NETCore.Platforms/1.1.0": {}, + "Microsoft.SourceLink.Common/1.1.1": {}, + "Microsoft.SourceLink.GitHub/1.1.1": { + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + }, + "NETStandard.Library/2.0.3": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, + "System.Buffers/4.5.1": { + "runtime": { + "lib/netstandard2.0/System.Buffers.dll": { + "assemblyVersion": "4.0.3.0", + "fileVersion": "4.6.28619.1" + } + } + }, + "System.Memory/4.5.4": { + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.4.0", + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + }, + "runtime": { + "lib/netstandard2.0/System.Memory.dll": { + "assemblyVersion": "4.0.1.1", + "fileVersion": "4.6.28619.1" + } + } + }, + "System.Numerics.Vectors/4.4.0": { + "runtime": { + "lib/netstandard2.0/System.Numerics.Vectors.dll": { + "assemblyVersion": "4.1.3.0", + "fileVersion": "4.6.25519.3" + } + } + }, + "System.Runtime.CompilerServices.Unsafe/4.5.3": { + "runtime": { + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll": { + "assemblyVersion": "4.0.4.1", + "fileVersion": "4.6.28619.1" + } + } + } + } + }, + "libraries": { + "NetTopologySuite/2.5.0-pre.190390493+local": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Microsoft.Build.Tasks.Git/1.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==", + "path": "microsoft.build.tasks.git/1.1.1", + "hashPath": "microsoft.build.tasks.git.1.1.1.nupkg.sha512" + }, + "Microsoft.DotNet.ApiCompat/6.0.0-beta.21159.11": { + "type": "package", + "serviceable": true, + "sha512": "sha512-SVX3OOq+Jx+DbPETmOjZO4OlHtrJBkAK7+O99crSJYFndveqTLiIIPMI6v5E2xOBEnWQQPwtiFxaVhEtuqHwtA==", + "path": "microsoft.dotnet.apicompat/6.0.0-beta.21159.11", + "hashPath": "microsoft.dotnet.apicompat.6.0.0-beta.21159.11.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/1.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==", + "path": "microsoft.netcore.platforms/1.1.0", + "hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512" + }, + "Microsoft.SourceLink.Common/1.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg==", + "path": "microsoft.sourcelink.common/1.1.1", + "hashPath": "microsoft.sourcelink.common.1.1.1.nupkg.sha512" + }, + "Microsoft.SourceLink.GitHub/1.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", + "path": "microsoft.sourcelink.github/1.1.1", + "hashPath": "microsoft.sourcelink.github.1.1.1.nupkg.sha512" + }, + "NETStandard.Library/2.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", + "path": "netstandard.library/2.0.3", + "hashPath": "netstandard.library.2.0.3.nupkg.sha512" + }, + "System.Buffers/4.5.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "path": "system.buffers/4.5.1", + "hashPath": "system.buffers.4.5.1.nupkg.sha512" + }, + "System.Memory/4.5.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==", + "path": "system.memory/4.5.4", + "hashPath": "system.memory.4.5.4.nupkg.sha512" + }, + "System.Numerics.Vectors/4.4.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ==", + "path": "system.numerics.vectors/4.4.0", + "hashPath": "system.numerics.vectors.4.4.0.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/4.5.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3TIsJhD1EiiT0w2CcDMN/iSSwnNnsrnbzeVHSKkaEgV85txMprmuO+Yq2AdSbeVGcg28pdNDTPK87tJhX7VFHw==", + "path": "system.runtime.compilerservices.unsafe/4.5.3", + "hashPath": "system.runtime.compilerservices.unsafe.4.5.3.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/PerfApp/nts_develop/NetTopologySuite.dll b/PerfApp/nts_develop/NetTopologySuite.dll new file mode 100644 index 0000000000000000000000000000000000000000..b20f03ab1b15bfe06f25d9a9d944d129749e1fb8 GIT binary patch literal 759296 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%0AiK6`&*0{3{@K#{ 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 )}Pg8ERqnlTeja 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 G!2bXt=; + + + NetTopologySuite + + + +

+ Utility functions for working with angles. + Unless otherwise noted, methods in this class express angles in radians. + + + + + Value of 2 * Pi + + + + + Value of Pi / 2 + + + + + Value of Pi / 4 + + + + + Converts from radians to degrees. + + An angle in radians + The angle in degrees + + + + Converts from degrees to radians. + + An angle in degrees + The angle in radians + + + + Returns the angle of the vector from p0 to p1, relative to the positive X-axis. + + The angle is normalized to be in the range [ -Pi, Pi ]. + The initial point of the vector. + The terminal point of the vector. + The normalized angle (in radians) that p0-p1 makes with the positive X-axis + + + + Returns the angle of the vector from (0,0) to p, relative to the positive X-axis. + + + The angle is normalized to be in the range ( -Pi, Pi ]. + + The terminal point of the vector. + The normalized angle (in radians) that (0,0)-p makes with the positive X-axis. + + + + Tests whether the angle between p0-p1-p2 is acute. + + + An angle is acute if it is less than 90 degrees. + Note: this implementation is not precise (deterministic) for angles very close to 90 degrees. + + An endpoint of the angle + The base of the angle + Another endpoint of the angle + if the angle is acute. + + + + Tests whether the angle between p0-p1-p2 is obtuse + + + An angle is obtuse if it is greater than 90 degrees. + Note: this implementation is not precise (deterministic) for angles very close to 90 degrees. + + An endpoint of the angle + The base of the angle + Another endpoint of the angle + if the angle is obtuse. + + + + Returns the unoriented smallest angle between two vectors. + + + The computed angle will be in the range [0, Pi). + + The tip of one vector + The tail of each vector + The tip of the other vector + + + + Returns the oriented smallest angle between two vectors. + The computed angle will be in the range (-Pi, Pi]. + A positive result corresponds to a rotation (CCW) from v1 to v2; + a negative result corresponds to a (CW) rotation; + a zero result corresponds to no rotation. + + The tip of v1 + The tail of each vector + The tip of v2 + The angle between v1 and v2, relative to v1 + + + + Computes the angle of the unoriented bisector + of the smallest angle between two vectors. + + The computed angle will be in the range (-Pi, Pi]. + The tip of v1 + The tail of each vector + The tip of v2 + The angle of the bisector between v1 and v2 + + + + Computes the interior angle between two segments of a ring. + The ring is assumed to be oriented in a clockwise direction. + + The computed angle will be in the range [0, 2Pi] + A point of the ring + The next point of the ring + The next point of the ring + The interior angle based at + + + + Returns whether an angle must turn clockwise or counterclockwise to overlap another angle. + + An angle (in radians) + An angle (in radians) + Whether a1 must turn , or to overlap a2. + + + + Computes the normalized value of an angle, which is the equivalent angle in the range ( -Pi, Pi ]. + + The angle to normalize + An equivalent angle in the range (-Pi, Pi] + + + + Computes the normalized positive value of an angle, which is the equivalent angle in the range [ 0, 2*Pi ). + + E.g. + + Function callResult + NormalizePositive(0.0)0.0 + NormalizePositive(-PI) + NormalizePositive(-2PI)0.0 + NormalizePositive(-3PI) + NormalizePositive(-4PI)0.0 + NormalizePositive(PI) + NormalizePositive(2PI)0.0 + NormalizePositive(3PI) + NormalizePositive(4PI)0.0 + + + + The angle to normalize, in radians. + An equivalent positive angle + + + + Computes the unoriented smallest difference between two angles. + + + + The angles are assumed to be normalized to the range [-Pi, Pi]. + The result will be in the range [0, Pi]. + + + The angle of one vector (in [-Pi, Pi] ) + The angle of the other vector (in range [-Pi, Pi] ) + The angle (in radians) between the two vectors (in range [0, Pi] ) + + + + Projects a point by a given angle and distance. + + The point to project + The angle at which to project + The distance to project + The projected point + + + + Functions for computing area. + + Martin Davis + + + + Computes the area for a ring. + + The coordinates forming the ring + The area of the ring + + + + Computes the area for a ring. + + The coordinates forming the ring + The area of the ring + + + + Computes the signed area for a ring. The signed area is positive if the + ring is oriented CW, negative if the ring is oriented CCW, and zero if the + ring is degenerate or flat. + + The coordinates forming the ring + The signed area of the ring + + + + Computes the signed area for a ring. The signed area is positive if the + + + value + meaning + + > 0 + The ring is oriented clockwise (CW) + < 0 + The ring is oriented counter clockwise (CCW) + == 0 + The ring is degenerate or flat + + ring is oriented CW, negative if the ring is oriented CCW, and zero if the + ring is degenerate or flat. + + The coordinates forming the ring + The signed area of the ring + + + + An interface for rules which determine whether node points + which are in boundaries of geometry components + are in the boundary of the parent geometry collection. + The SFS specifies a single kind of boundary node rule, + the rule. + However, other kinds of Boundary Node Rules are appropriate + in specific situations (for instance, linear network topology + usually follows the .) + Some JTS operations + (such as , and ) + allow the BoundaryNodeRule to be specified, + and respect the supplied rule when computing the results of the operation. + + An example use case for a non-SFS-standard Boundary Node Rule is + that of checking that a set of s have + valid linear network topology, when turn-arounds are represented + as closed rings. In this situation, the entry road to the + turn-around is only valid when it touches the turn-around ring + at the single (common) endpoint. This is equivalent + to requiring the set of LineStrings to be + simple under the . + The SFS-standard is not + sufficient to perform this test, since it + states that closed rings have no boundary points. + + This interface and its subclasses follow the Strategy design pattern. + + Martin Davis + + + + + + + + Tests whether a point that lies in boundaryCount + geometry component boundaries is considered to form part of the boundary + of the parent geometry. + + boundaryCount the number of component boundaries that this point occurs in + true if points in this number of boundaries lie in the parent boundary + + + + Provides access to static instances of common s. + + + + + The Mod-2 Boundary Node Rule (which is the rule specified in the OGC SFS). + + + + + The Endpoint Boundary Node Rule. + + + + The MultiValent Endpoint Boundary Node Rule. + + + + The Monovalent Endpoint Boundary Node Rule. + + + + + The Boundary Node Rule specified by the OGC Simple Features Specification, + which is the same as the Mod-2 rule. + + + + + + A specifies that points are in the + boundary of a lineal geometry if + the point lies on the boundary of an odd number + of components. + Under this rule s and closed + s have an empty boundary. + + + This is the rule specified by the OGC SFS, + and is the default rule used in JTS. + + Martin Davis + + + + A which specifies that any points which are endpoints + of lineal components are in the boundary of the + parent geometry. + This corresponds to the "intuitive" topological definition + of boundary. + Under this rule s have a non-empty boundary + (the common endpoint of the underlying LineString). + + + This rule is useful when dealing with linear networks. + For example, it can be used to check + whether linear networks are correctly noded. + The usual network topology constraint is that linear segments may touch only at endpoints. + In the case of a segment touching a closed segment (ring) at one point, + the Mod2 rule cannot distinguish between the permitted case of touching at the + node point and the invalid case of touching at some other interior (non-node) point. + The EndPoint rule does distinguish between these cases, + so is more appropriate for use. + + Martin Davis + + + + A which determines that only + endpoints with valency greater than 1 are on the boundary. + This corresponds to the boundary of a + being all the "attached" endpoints, but not + the "unattached" ones. + + Martin Davis + + + + A which determines that only + endpoints with valency of exactly 1 are on the boundary. + This corresponds to the boundary of a + being all the "unattached" endpoints. + + Martin Davis + + + + Computes the centroid of a of any dimension. + For collections the centroid is computed for the collection of + non-empty elements of highest dimension. + The centroid of an empty geometry is null + + +

Algorithm

+ + Dimension 2 - the centroid ic computed + as a weighted sum of the centroids + of a decomposition of the area into (possibly overlapping) triangles. + Holes and multipolygons are handled correctly. + See http://www.faqs.org/faqs/graphics/algorithms-faq/ + for further details of the basic approach. + Dimension 1 - Computes the average of the midpoints + of all line segments weighted by the segment length. + Zero-length lines are treated as points. + + Dimension 0 - Compute the average coordinate over all points. + Repeated points are all included in the average + + + If the input geometries are empty, a null Coordinate is returned. +
+ + + + 1.7 +
+ + + Computes the centroid point of a geometry. + + The geometry to use + + The centroid point, or null if the geometry is empty + + + + + the point all triangles are based at + + + + + temporary variable to hold centroid of triangle + + + + + Partial area sum + + + + + partial centroid sum + + + + + Creates a new instance for computing the centroid of a geometry + + + + + Adds a to the centroid total. + + >The to add. + + + + Gets the computed centroid. + + The computed centroid, or null if the input is empty + + + + Computes three times the centroid of the triangle p1-p2-p3. + The factor of 3 is + left in to permit division to be avoided until later. + + + + + Returns twice the signed area of the triangle p1-p2-p3. + The area is positive if the triangle is oriented CCW, and negative if CW. + + + + + Adds the line segments defined by an array of coordinates + to the linear centroid accumulators. + + An array of s + + + + Adds a point to the point centroid accumulator. + + A + + + + Basic computational geometry algorithms + for geometry and coordinates defined in 3-dimensional Cartesian space. + + Martin Davis + + + + Computes the distance between the points and + in 3D space + + The first point + The second point + The distance between the two points + + + + Computes the distance between the point and the + segment from to in 3D space + + The point + The start point of the segment + The end point of the segment + + + + Computes the distance between two 3D segments. + The start point of the first segment + The end point of the first segment + The start point of the second segment + The end point of the second segment + The distance between the segments + + + + Implements basic computational geometry algorithms using arithmetic. + + Martin Davis + + + + Returns the index of the direction of the point q relative to + a vector specified by p1-p2. + + The origin point of the vector + The final point of the vector + the point to compute the direction to + + + 1 if q is counter-clockwise (left) from p1-p2 + -1 if q is clockwise (right) from p1-p2 + 0 if q is collinear with p1-p2 + + + + + Returns the index of the direction of the point q relative to + a vector specified by p1-p2. + + The x-ordinate of the origin point of the vector + The y-ordinate of the origin point of the vector + The x-ordinate of the final point of the vector + The y-ordinate of the final point of the vector + The x-ordinate of the point to compute the direction to + The y-ordinate of the point to compute the direction to + + + 1 if q is counter-clockwise (left) from p1-p2 + -1 if q is clockwise (right) from p1-p2 + 0 if q is collinear with p1-p2 + + + + + Computes the sign of the determinant of the 2x2 matrix + with the given entries. + + + + + + + + -1 if the determinant is negative, + 1 if the determinant is positive, + 0 if the determinant is 0. + + + + + + A value which is safely greater than the + relative round-off error in double-precision numbers + + + + + A filter for computing the orientation index of three coordinates. + + If the orientation can be computed safely using standard DP + arithmetic, this routine returns the orientation index. + Otherwise, a value i > 1 is returned. + In this case the orientation index must + be computed using some other more robust method. + The filter is fast to compute, so can be used to + avoid the use of slower robust methods except when they are really needed, + thus providing better average performance. + + Uses an approach due to Jonathan Shewchuk, which is in the public domain. + + The x-ordinate of point A + The y-ordinate of point A + The x-ordinate of point B + The y-ordinate of point B + The x-ordinate of point C + The y-ordinate of point C + + + The orientation index if it can be computed safely + > 1 if the orientation index cannot be computed safely> + + + + + + Computes an intersection point between two lines + using DD arithmetic. + If the lines are parallel (either identical + or separate) a null value is returned. + + An endpoint of line segment 1 + An endpoint of line segment 1 + An endpoint of line segment 2 + An endpoint of line segment 2 + An intersection point if one exists, or null if lines are parallel. + + + + Constructs the Largest Empty Circle for a set + of obstacle geometries, up to a specified tolerance. + The obstacles are point and line geometries. + + The Largest Empty Circle is the largest circle which + has its center in the convex hull of the obstacles (the boundary), + and whose interior does not intersect with any obstacle. + The circle center is the point in the interior of the boundary + which has the farthest distance from the obstacles (up to tolerance). + The circle is determined by the center point + and a point lying on an obstacle indicating the circle radius. + + The implementation uses a successive-approximation technique + over a grid of square cells covering the obstacles and boundary. + The grid is refined using a branch-and-bound algorithm. + Point containment and distance are computed in a performant + way by using spatial indexes. + +

Future Enhancements

+ + Support polygons as obstacles + Support a client-defined boundary polygon + +
+ Martin Davis + + + +
+ + + Computes the center point of the Largest Empty Circle + within a set of obstacles, up to a given tolerance distance. + + A geometry representing the obstacles (points and lines) + The distance tolerance for computing the center point + The center point of the Largest Empty Circle + + + + Computes a radius line of the Largest Empty Circle + within a set of obstacles, up to a given distance tolerance. + + A geometry representing the obstacles (points and lines) + The distance tolerance for computing the center point + A line from the center of the circle to a point on the edge + + + + Creates a new instance of a Largest Empty Circle construction. + + A geometry representing the obstacles (points and lines) + The distance tolerance for computing the center point + + + + Sets the area boundary as the convex hull + of the obstacles. + + + + + Gets the center point of the Largest Empty Circle + (up to the tolerance distance). + + The center point of the Largest Empty Circle + + + + Gets a point defining the radius of the Largest Empty Circle. + This is a point on the obstacles which is + nearest to the computed center of the Largest Empty Circle. + The line segment from the center to this point + is a radius of the constructed circle, and this point + lies on the boundary of the circle. + + A point defining the radius of the Largest Empty Circle + + + + Gets a line representing a radius of the Largest Empty Circle. + + A line from the center of the circle to a point on the edge + + + + Computes the signed distance from a point to the constraints + (obstacles and boundary). + Points outside the boundary polygon are assigned a negative distance. + Their containing cells will be last in the priority queue + (but will still end up being tested since they may be refined). + + The point to compute the distance for + The signed distance to the constraints (negative indicates outside the boundary) + + + + Tests whether a cell may contain the circle center, + and thus should be refined (split into subcells + to be investigated further.) + + The cell to test + true if the cell might contain the circle center + + + + Initializes the queue with a grid of cells covering + the extent of the area. + + The area extent to cover + The queue to initialize + + + + A square grid cell centered on a given point + with a given side half-length, + and having a given distance from the center point to the constraints. + The maximum possible distance from any point in the cell to the + constraints can be computed. + This is used as the ordering and upper-bound function in + the branch-and-bound algorithm. + + + + + Constructs the Maximum Inscribed Circle for a + polygonal , up to a specified tolerance. + The Maximum Inscribed Circle is determined by a point in the interior of the area + which has the farthest distance from the area boundary, + along with a boundary point at that distance. + + In the context of geography the center of the Maximum Inscribed Circle + is known as the Pole of Inaccessibility. + A cartographic use case is to determine a suitable point + to place a map label within a polygon. + + The radius length of the Maximum Inscribed Circle is a + measure of how "narrow" a polygon is. It is the + distance at which the negative buffer becomes empty. + + The class supports polygons with holes and multipolygons. + + The implementation uses a successive-approximation technique + over a grid of square cells covering the area geometry. + The grid is refined using a branch-and-bound algorithm. + Point containment and distance are computed in a performant + way by using spatial indexes. +

Future Enhancements

+ + Support a polygonal constraint on placement of center + +
+ Martin Davis + + + +
+ + + Computes the center point of the Maximum Inscribed Circle + of a polygonal geometry, up to a given tolerance distance. + + A polygonal geometry + The distance tolerance for computing the center point + The center point of the maximum inscribed circle + + + + Computes a radius line of the Maximum Inscribed Circle + of a polygonal geometry, up to a given tolerance distance. + + A polygonal geometry + The distance tolerance for computing the center point + A line from the center to a point on the circle + + + + Creates a new instance of a Maximum Inscribed Circle computation. + + An areal geometry + The distance tolerance for computing the centre point + (must be positive) + Thrown if the tolerance is non-positive + Thrown if the input geometry is non-polygonal or empty + + + + Gets the center point of the maximum inscribed circle + (up to the tolerance distance). + The center point of the maximum inscribed circle + + + + Gets a point defining the radius of the Maximum Inscribed Circle. + This is a point on the boundary which is + nearest to the computed center of the Maximum Inscribed Circle. + The line segment from the center to this point + is a radius of the constructed circle, and this point + lies on the boundary of the circle. + + A point defining the radius of the Maximum Inscribed Circle + + + + Gets a line representing a radius of the Largest Empty Circle. + + A line from the center of the circle to a point on the edge + + + + Computes the signed distance from a point to the area boundary. + Points outside the polygon are assigned a negative distance. + Their containing cells will be last in the priority queue + (but may still end up being tested since they may need to be refined). + + The point to compute the distance for + The signed distance to the area boundary (negative indicates outside the area) + + + + Initializes the queue with a grid of cells covering + the extent of the area. + + The area extent to cover + The queue to initialize + + + + A square grid cell centered on a given point + with a given side half-length, + and having a given distance from the center point to the constraints. + The maximum possible distance from any point in the cell to the + constraints can be computed. + This is used as the ordering and upper-bound function in + the branch-and-bound algorithm. + + + + + Computes the convex hull of a . + The convex hull is the smallest convex Geometry that contains all the + points in the input Geometry. + Uses the Graham Scan algorithm. + + + + + Computes the convex hull for the given sequence of instances. + + + The instances whose convex hull to compute. + + + The convex hull of . + + + + + Create a new convex hull construction for the input Geometry. + + + + + + Create a new convex hull construction for the input array. + + + + + + + Returns a Geometry that represents the convex hull of the input point. + The point will contain the minimal number of points needed to + represent the convex hull. In particular, no more than two consecutive + points will be collinear. + + + If the convex hull contains 3 or more points, a Polygon; + 2 points, a LineString; + 1 point, a Point; + 0 points, an empty GeometryCollection. + + + + + Uses a heuristic to reduce the number of points scanned to compute the hull. + The heuristic is to find a polygon guaranteed to + be in (or on) the hull, and eliminate all points inside it. + A quadrilateral defined by the extremal points + in the four orthogonal directions + can be used, but even more inclusive is + to use an octilateral defined by the points in the 8 cardinal directions. + Note that even if the method used to determine the polygon vertices + is not 100% robust, this does not affect the robustness of the convex hull. + + To satisfy the requirements of the Graham Scan algorithm, + the returned array has at least 3 entries. + + + The coordinates to reduce + The reduced array of coordinates + + + + Pre sorts the coordinates + + + + + + + + + + + + + + + + + + + + Whether the three coordinates are collinear + and c2 lies between c1 and c3 inclusive. + + + + + + + + + + + + + + + + + + + + + The vertices of a linear ring, which may or may not be flattened (i.e. vertices collinear). + A 2-vertex LineString if the vertices are collinear; + otherwise, a Polygon with unnecessary (collinear) vertices removed. + + + + + + The vertices of a linear ring, which may or may not be flattened (i.e. vertices collinear). + The coordinates with unnecessary (collinear) vertices removed. + + + + Compares s for their angle and distance + relative to an origin. + + + + + Initializes a new instance of the class. + + + + + + + + + + + + + + + + + + + + + + + Functions to compute distance between basic geometric structures. + + Martin Davis + + + + Computes the distance from a line segment AB to a line segment CD + + Note: NON-ROBUST! + + The first point of the first line + The second point of the first line (must be different to A) + The first point of the second line + The second point of the second line (must be different to C) + The distance from a line segment AB to a line segment CD + + + + Computes the distance from a point to a sequence of line segments. + + A point + A sequence of contiguous line segments defined by their vertices + The minimum distance between the point and the line segments + + + + Computes the distance from a point to a sequence of line segments. + + A point + A sequence of contiguous line segments defined by their vertices + The minimum distance between the point and the line segments + + + + Computes the distance from a point p to a line segment AB + + Note: NON-ROBUST! + + The point to compute the distance for + The first point of the first line + The second point of the first line (must be different to A) + The distance from p to line segment AB + + + + Computes the perpendicular distance from a point p to the (infinite) line + containing the points AB + + The point to compute the distance for + The first point of the first line + The second point of the first line (must be different to A) + The perpendicular distance from p to line segment AB + + + + + Computes the Discrete Fréchet Distance between two s + using a cartesian distance computation function. + + The 1st geometry + The 2nd geometry + The cartesian distance between and + + + + Creates an instance of this class using the provided geometries. + + A geometry + A geometry + + + + Computes the Discrete Fréchet Distance between the input geometries + + The Discrete Fréchet Distance + + + + Creates a matrix to store the computed distances + + The number of rows + The number of cols + A matrix storage + + + + Gets the pair of s at which the distance is obtained. + + The pair of Coordinates at which the distance is obtained + + + + Computes the Fréchet Distance for the given distance matrix. + + An array of Coordinates + An array of Coordinates + An array of alternating col/row index values for the diagonal of the distance matrix + The distance matrix + A lookup for coordinate pairs based on a distance + + + + + Returns the minimum distance at the corner (, }). + + A (sparse) matrix + The row index + The column index + The minimum distance + + + + Computes relevant distances between pairs of s for the + computation of the Discrete Fréchet Distance. + + An array of Coordinates + An array of Coordinates + An array of alternating col/row index values for the diagonal of the distance matrix + The distance matrix + A lookup for coordinate pairs based on a distance + + +
+ Computes the indices for the diagonal of a numCols x numRows grid + using the + Bresenham's line algorithm. + + The number of columns + The number of rows + A packed array of column and row indices. + + + + Abstract base class for storing 2d matrix data + + + + + Gets a value indicating the number of rows + + + + + Gets a value indicating the number of columns + + + + + Gets a value indicating the default value + + + + Creates an instance of this class + The number of rows + The number of columns + A default value + + + + Gets or sets a value for the cell , + + The row index + The column index + The value of the cell , + + + + Gets a flag indicating if the matrix has a set value, e.g. one that is different + than . + + A flag indicating if the matrix has a set value + + + Straight forward implementation of a rectangular matrix + + + + Creates an instance of this matrix using the given number of rows and columns. + A default value can be specified. + + The number of rows + The number of columns + A default value + + + + A matrix implementation that adheres to the + + Compressed sparse row format.
+ Note: Unfortunately not as fast as expected. +
+
+ + + Creates an instance of this matrix using the given number of rows and columns. + A default value can be specified. + + The number of rows + The number of columns + A default value + + + + Creates an instance of this matrix using the given number of rows and columns. + A default value can be specified as well as the number of values expected. + + The number of rows + The number of columns + A default value + The amount of expected values + + + + Computes an initial value for the number of expected values + + The number of rows + The number of columns + The expected number of values in the sparse matrix + + + + Ensures that the column index vector (ci) and value vector (v) are sufficiently large. + + The number of items to store in the matrix + + + + A sparse matrix based on . + + + + + Creates an instance of this matrix using the given number of rows and columns. + A default value can be specified. + + The number of rows + The number of columns + A default value + + + + An algorithm for computing a distance metric + which is an approximation to the Hausdorff Distance + based on a discretization of the input . + + + + The algorithm computes the Hausdorff distance restricted to discrete points + for one of the geometries. + The points can be either the vertices of the geometries (the default), + or the geometries with line segments densified by a given fraction. + Also determines two points of the Geometries which are separated by the computed distance. + + + This algorithm is an approximation to the standard Hausdorff distance. + Specifically, + + for all geometries a, b: DHD(a, b) <= HD(a, b) + + The approximation can be made as close as needed by densifying the input geometries. + In the limit, this value will approach the true Hausdorff distance: + + DHD(A, B, densifyFactor) -> HD(A, B) as densifyFactor -> 0.0 + + The default approximation is exact or close enough for a large subset of useful cases. + + + Examples of these are: + + + computing distance between Linestrings that are roughly parallel to each other, + and roughly equal in length. This occurs in matching linear networks. + + Testing similarity of geometries. + + + + An example where the default approximation is not close is: + + A = LINESTRING (0 0, 100 0, 10 100, 10 100) + B = LINESTRING (0 100, 0 10, 80 10) + + DHD(A, B) = 22.360679774997898 + HD(A, B) ~= 47.8 + + + + + + + Computes the Discrete Hausdorff Distance of two s. + + A geometry + A geometry + The Discrete Hausdorff Distance + + + + Computes the Discrete Hausdorff Distance of two s. + + A geometry + A geometry + The densify fraction. A value of 0 indicates, that no densification should take place + The Discrete Hausdorff Distance + + + + Value of 0.0 indicates that no densification should take place + + + + + Creates an instance of this class using the provided geometries + + A geometry + Another geometry + + + + Gets or sets the fraction by which to densify each segment. + + + Each segment will be (virtually) split into a number of equal-length + sub-segments, whose fraction of the total length is closest + to the given fraction. + + + + + Computes the discrete hausdorff distance between the two assigned geometries. + + The discrete hausdorff distance + + + + Computes the discrete hausdorff distance between the 1st and the 2nd assigned geometry + + The discrete hausdorff distance. + + + + Gets a value indicating the + + + + + A coordinate filter that computes the maximum between points of + an assigned Geometry and all filtered geometries. + + + + + Creates an instance of this class + + A geometry + + + + + + + Gets a value indicating the maximum distance between + an assigned Geometry and the filtered one. + + + + + A coordinate filter that computes the maximum between points of + an assigned Geometry and all filtered geometries. The filtered geometries' line segments + are + + + + + Creates an instance of this filter class + + The geometry to densify + The densification fraction + + + + + + + As this filter does not change the geometry, the return value is always false + + + + As this filter does not end prematurely, the return value is always false + + + + Gets a value indicating the maximum distance between p + + + + + Computes the Euclidean distance (L2 metric) from a to a . + + + Also computes two points on the geometry which are separated by the distance found. + + + + + Computes the Euclidean distance (L2 metric) from a to a . + + The geometry + The Point + The PointPairDistance + + + + Computes the Euclidean distance (L2 metric) from a to a . + + The LineString + The Point + The PointPairDistance + + + + Computes the Euclidean distance (L2 metric) from a to a . + + The LineSegment + The Point + The PointPairDistance + + + + Computes the Euclidean distance (L2 metric) from a to a . + + The Polygon + The Point + The PointPairDistance + + + + Contains a pair of points and the distance between them. + + + Provides methods to update with a new point pair with either maximum or minimum distance. + + + + + Initializes this instance to null. + + + + + Initializes the points, computing the distance between them. + + 1st coordinate + 2nd coordinate + + + + Initializes the points, avoiding recomputing the distance. + + 1st coordinate + 2nd coordinate + the distance between and + + + + The distance between the paired coordinates + + The distance between the paired coordinates + + + + Gets a value indicating the paired coordinates. + + An array containing the paired points + + + + Gets the value of one of the paired points + + An index, valid are [0, 1]. + The Coordinate at index i. + + + + Updates this PointPairDistance if + has greater than this instance. + + The PointPairDistance to test. + + + + Updates this PointPairDistance if the distance between + and is greater than the + of this instance. + + The 1st point's coordinate + The 2nd point's coordinate + + + + Updates this PointPairDistance if + has a smaller than this instance. + + The PointPairDistance to test. + + + + Updates this PointPairDistance if the distance between + and is smaller than the + of this instance. + + The 1st point's coordinate + The 2nd point's coordinate + + + + + + + Represents a homogeneous coordinate in a 2-D coordinate space. + In NTS s are used as a clean way + of computing intersections between line segments. + + David Skea + + + + Computes the (approximate) intersection point between two line segments using homogeneous coordinates. + + + Note that this algorithm is + not numerically stable; i.e. it can produce intersection points which + lie outside the envelope of the line segments themselves. In order + to increase the precision of the calculation input points should be normalized + before passing them to this routine. + + 1st Coordinate of 1st linesegment + 2nd Coordinate of 1st linesegment + 1st Coordinate of 2nd linesegment + 2nd Coordinate of 2nd linesegment + + + + Computes the (approximate) intersection point between two line segments + using homogeneous coordinates. + Note that this algorithm is + not numerically stable; i.e. it can produce intersection points which + lie outside the envelope of the line segments themselves. In order + to increase the precision of the calculation input points should be normalized + before passing them to this routine. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Constructs a homogeneous coordinate which is the intersection of the lines s. + define by the homogeneous coordinates represented by two + + A coordinate + A coordinate + + + + Creates an instance of this + + + + + + + + + Constructs a concave hull of a set of points. + The hull is constructed by removing the longest outer edges + of the Delaunay Triangulation of the points + until a target criterion is reached. + + The target criteria are: + + Maximum Edge Length Ratiothe length of the longest edge of the hull is no larger + than this value. + Maximum Edge Length Factordetermine the Maximum Edge Length + as a fraction of the difference between the longest and shortest edge lengths + in the Delaunay Triangulation. + This normalizes the Maximum Edge Length to be scale-free. + A value of 1 produces the convex hull; a value of 0 produces maximum concaveness. + + The preferred criterion is the Maximum Edge Length Ratio, since it is + scale-free and local(so that no assumption needs to be made about the + total amount of concaveness present). + Other length criteria can be used by setting the Maximum Edge Length directly. + For example, use a length relative to the longest edge length + in the Minimum Spanning Tree of the point set. + Or, use a length derived from the value. + + The computed hull is always a single connected + (unless it is degenerate, in which case it will be a or a ). + This constraint may cause the concave hull to fail to meet the target criteria. + + Optionally the concave hull can be allowed to contain holes. + Note that when using the area-based criterion + this may result in substantially slower computation. + + Martin Davis + + + + Computes the approximate edge length of + a uniform square grid having the same number of + points as a geometry and the same area as its convex hull. + This value can be used to determine a suitable length threshold value + for computing a concave hull. + A value from 2 to 4 times the uniform grid length + seems to produce reasonable results. + + A geometry + The approximate uniform grid length + + + + Computes the concave hull of the vertices in a geometry + using the target criterion of maximum edge length. + + The input geometry + The target maximum edge length + The concave hull + + + + Computes the concave hull of the vertices in a geometry + using the target criterion of maximum edge length, + and optionally allowing holes. + + The input geometry + The target maximum edge length + A flag whether holes are allowed in the result + The concave hull + + + + Computes the concave hull of the vertices in a geometry + using the target criterion of maximum edge length ratio. + The edge length ratio is a fraction of the length difference + between the longest and shortest edges + in the Delaunay Triangulation of the input points. + + The input geometry + The target edge length ratio + The concave hull + + + + Computes the concave hull of the vertices in a geometry + using the target criterion of maximum edge length ratio, + and optionally allowing holes. + The edge length factor is a fraction of the length difference + between the longest and shortest edges + in the Delaunay Triangulation of the input points. + + The input geometry + The target edge length ratio + A flag whether holes are allowed in the result + The concave hull + + + + Creates a new instance for a given geometry. + + The input geometry + + + Gets or sets the target maximum edge length for the concave hull. + The length value must be zero or greater. + + The value 0.0 produces the concave hull of smallest area + that is still connected. + Larger values produce less concave results. + A value equal or greater than the longest Delaunay Triangulation edge length + produces the convex hull. + + The value may be used as + the basis for estimating an appropriate target maximum edge length. + + + The target maximum edge length for the concave hull + + + + Gets or sets the target maximum edge length ratio for the concave hull. + The edge length ratio is a fraction of the difference + between the longest and shortest edge lengths + in the Delaunay Triangulation of the input points. + It is a value in the range 0 to 1. + + The value 0.0 produces a concave hull of minimum area + that is still connected. + The value 1.0 produces the convex hull. + + + The target maximum edge length factor for the concave hull + + + + Gets or sets whether holes are allowed in the concave hull polygon. + + + + + Gets the computed concave hull. + + The concave hull + + + Computes the concave hull using edge length as the target criteria. + + + The erosion is done in two phases: first the border, then any + internal holes (if required). + This allows an fast connection check to be used + when eroding holes, + which makes this much more efficient than the area-based algorithm. + + The triangulation + + + + Adds a Tri to the queue. + Only add tris with a single border edge, + sice otherwise that would risk isolating a vertex. + Sets the ordering size to the length of the border edge. + + The Tri to add + The priority queue to add to + + + + Finds tris which may be the start of holes. + + + Only tris which have a long enough edge and which do not touch the current hull + boundary are included.
+ This avoids the risk of disconnecting the result polygon. + The list is sorted in decreasing order of edge length. +
+ The triangulation + The minimum length of edges to consider + A list of candidate tris that may start a hole +
+ + + Erodes a hole starting at a given triangle, + and eroding all adjacent triangles with boundary edge length above target. + + The triangulation + A tri which is a hole + + + + Tris which are used to form a concave hull. + If a Tri has an edge (or edges) with no adjacent tri + the tri is on the boundary of the triangulation. + The edge is a boundary edge. + The union of those edges + forms the (linear) boundary of the triangulation. + The triangulation area may be a Polygon or MultiPolygon, and may or may not contain holes. + + Martin Davis + + + + Sets the size to be the length of the boundary edges. + This is used when constructing hull without holes, + by erosion from the triangulation boundary. + + + + + Gets an index of a boundary edge, if there is one. + + A boundary edge index, or -1 + + + + Gets the most CCW boundary edge index. + This assumes there is at least one non-boundary edge. + + The CCW boundary edge index + + + + Gets the most CW boundary edge index. + This assumes there is at least one non-boundary edge. + + The CW boundary edge index + + + + Tests if this tri is the only one connecting its 2 adjacents. + Assumes that the tri is on the boundary of the triangulation + and that the triangulation does not contain holes + + true if the tri is the only connection + + + + Gets the index of a vertex which is adjacent to two other tris (if any). + + The vertex index or -1 + + + + Tests whether some vertex of this Tri has degree = 1. + In this case it is not in any other Tris. + + The triangulation + true if any vertex of this tri has a degree of 1 + + + + PriorityQueues sort in ascending order. + To sort with the largest at the head, + smaller sizes must compare as greater than larger sizes. + (i.e. the normal numeric comparison is reversed). + If the sizes are identical (which should be an infrequent case), + the areas are compared, with larger areas sorting before smaller. + (The rationale is that larger areas indicate an area of lower point density, + which is more likely to be in the exterior of the computed shape.) + This improves the determinism of the queue ordering. + + + + + Tests if this tri has a vertex which is in the boundary, + but not in a boundary edge. + + true if the tri touches the boundary at a vertex + + + + Tests if a triangulation is edge-connected, if a triangle is removed.
+ NOTE: this is a relatively slow operation. +
+ The triangulation + The triangle to remove + true if the triangulation is still connected +
+ + + Functions to operate on triangulations represented as + lists of s. + + + + + Creates a polygonal geometry representing the area of a triangulation + which may be disconnected or contain holes. + + The triangulation + The geometry factory + The area polygonal geometry + + + + Creates a Polygon representing the area of a triangulation + which is connected and contains no holes. + + The triangulation + The geometry factory to use + The area polygon + + + + Extracts the coordinates of the edgees along the boundary of a triangulation, + by tracing CW around the border triangles.
+ Assumption: there are at least 2 tris, they are connected, + and there are no holes. + So each tri has at least one non-border edge, and there is only one border. +
+ The triangulation + The border of the triangulation +
+ + + Computes an interior point of a . + An interior point is guaranteed to lie in the interior of the Geometry, + if it possible to calculate such a point exactly. + For collections the interior point is computed for the collection of + non-empty elements of highest dimension. + Otherwise, the point may lie on the boundary of the geometry. + + The interior point of an empty geometry is POINT EMPTY. +

Algorithm

+ The point is chosen to be "close to the center" of the geometry. + The location depends on the dimension of the input: + + Dimension 2the interior point is constructed in the middle of the longest interior segment + of a line bisecting the area. + Dimension 1the interior point is the interior or boundary vertex closest to the centroid. + Dimension 0the point is the point closest to the centroid. + + + + +
+
+ + + Computes a location of an interior point in a . + + Handles all geometry types. + + A geometry in which to find an interior point + the location of an interior point, or POINT EMPTY if the input is empty + + + + + Computes a location of an interior point in a . + + Handles all geometry types. + + + This function is called GetInteriorPoint in JTS. + It has been renamed to GetInteriorCoord to prevent a breaking change. + A geometry in which to find an interior point + the location of an interior point, or null if the input is empty + + + + + Computes a point in the interior of an areal geometry. + The point will lie in the geometry interior + in all except certain pathological cases. + + +

Algorithm:

+ For each input polygon: + + + Determine a horizontal scan line on which the interior + point will be located. + To increase the chance of the scan line + having non-zero-width intersection with the polygon + the scan line Y ordinate is chosen to be near the centre of the polygon's + Y extent but distinct from all of vertex Y ordinates. + + + Compute the sections of the scan line + which lie in the interior of the polygon. + + + Choose the widest interior section + and take its midpoint as the interior point. + + + The final interior point is chosen as + the one occurring in the widest interior section. + + This algorithm is a tradeoff between performance + and point quality (where points further from the geometry + boundary are considered to be higher quality) + Priority is given to performance. + This means that the computed interior point + may not be suitable for some uses + (such as label positioning). + + + The algorithm handles some kinds of invalid/degenerate geometry, + including zero-area and self-intersecting polygons. + + + Empty geometry is handled by returning a point. + +

KNOWN BUGS

+ + + If a fixed precision model is used, + in some cases this method may return a point + which does not lie in the interior. + + + If the input polygon is extremely narrow the computed point + may not lie in the interior of the polygon. + + +
+
+ + + Computes an interior point for the + polygonal components of a Geometry. + + The geometry to compute. + + The computed interior point, + or if the geometry has no polygonal components. + + + + + + + + + + + + + Creates a new interior point finder + for an areal geometry. + + An areal geometry + + + + Gets the computed interior point + or if the input geometry is empty. + + + + + Processes a geometry to determine + the best interior point for + all component polygons. + + The geometry to process. + + + + Computes an interior point of a component Polygon + and updates current best interior point + if appropriate. + + The polygon to process. + + + + Computes an interior point in a single , + as well as the width of the scan-line section it occurs in + to allow choosing the widest section occurrence. + + + + + Initializes a new instance of the class. + + The polygon to test. + + + + Gets the computed interior point, + or if the input geometry is empty. + + + + + Gets the width of the scanline section containing the interior point. + Used to determine the best point to use. + + + + + Compute the interior point. + + + + + Finds the midpoint of the widest interior section. + Sets the location and the + + + The list of scan-line X ordinates + + + + Tests if an edge intersection contributes to the crossing count. + Some crossing situations are not counted, + to ensure that the list of crossings + captures strict inside/outside topology. + + An endpoint of the segment. + An endpoint of the segment. + The Y-ordinate of the horizontal line. + if the edge crossing is counted. + + + + Computes the intersection of a segment with a horizontal line. + The segment is expected to cross the horizontal line + - this condition is not checked. + Computation uses regular double-precision arithmetic. + Test seems to indicate this is as good as using DD arithmetic. + + An endpoint of the segment. + An endpoint of the segment. + The Y-ordinate of the horizontal line + + + + + Tests if an envelope intersects a horizontal line. + + The envelope to test. + The Y-ordinate of the horizontal line. + if the envelope and line intersect. + + + + Tests if a line segment intersects a horizontal line. + + A segment endpoint. + A segment endpoint. + The Y-ordinate of the horizontal line. + if the segment and line intersect. + + + + Finds a safe scan line Y ordinate by projecting + the polygon segments + to the Y axis and finding the + Y-axis interval which contains the centre of the Y extent. + The centre of + this interval is returned as the scan line Y-ordinate. + + Note that in the case of (degenerate, invalid) + zero-area polygons the computed Y value + may be equal to a vertex Y-ordinate. + + + Martin Davis + + + + Computes a point in the interior of an linear point. + Algorithm: + Find an interior vertex which is closest to + the centroid of the linestring. + If there is no interior vertex, find the endpoint which is + closest to the centroid. + + + + + Computes an interior point for the + linear components of a Geometry. + + The geometry to compute. + + The computed interior point, + or if the geometry has no linear components. + + + + + + + + + + + + + + + + Tests the interior vertices (if any) + defined by a linear Geometry for the best inside point. + If a Geometry is not of dimension 1 it is not tested. + + The point to add. + + + + + + + + + + Tests the endpoint vertices + defined by a linear Geometry for the best inside point. + If a Geometry is not of dimension 1 it is not tested. + + The point to add. + + + + + + + + + + + + + + + + Computes a point in the interior of an point point. + Algorithm: + Find a point which is closest to the centroid of the point. + + + + + Computes an interior point for the + puntal components of a Geometry. + + The geometry to compute. + + The computed interior point, + or if the geometry has no puntal components. + + + + + + + + + + + Tests the point(s) defined by a Geometry for the best inside point. + If a Geometry is not of dimension 0 it is not tested. + + The point to add. + + + + + + + + + + + + + + + Functions to compute intersection points between lines and line segments. + + In general it is not possible to compute + the intersection point of two lines exactly, due to numerical roundoff. + This is particularly true when the lines are nearly parallel. + These routines uses numerical conditioning on the input values + to ensure that the computed value is very close to the correct value. + + The Z-ordinate is ignored, and not populated. + + mdavis + + + + Computes the intersection point of two lines. + If the lines are parallel or collinear this case is detected + and null is returned. + + An endpoint of line 1 + An endpoint of line 1 + An endpoint of line 2 + An endpoint of line 2 + + + NOTE: In JTS this function is called Intersection. + + The intersection point between the lines, if there is one, + or null if the lines are parallel or collinear + + + + + Computes the intersection point of a line and a line segment (if any). + There will be no intersection point if: + + the segment does not intersect the line + the line or the segment are degenerate (have zero length) + + If the segment is collinear with the line the first segment endpoint is returned. + + The intersection point, or null if it is not possible to find an intersection + + + + An interface for classes which determine the of points in a + + Martin Davis + + + + Determines the of a point in the . + + The point to test + the location of the point in the geometry + + + + Functions for computing length. + + + Martin Davis + + + + + Computes the length of a LineString specified by a sequence of points. + + The points specifying the LineString + The length of the LineString + + + + A LineIntersector is an algorithm that can both test whether + two line segments intersect and compute the intersection point(s) + if they do. + + There are three possible outcomes when determining whether two line segments intersect: + + - the segments do not intersect + - the segments intersect in a single point + - the segments are collinear and they intersect in a line segment + + + + For segments which intersect in a single point, the point may be either an endpoint + or in the interior of each segment. + If the point lies in the interior of both segments, + this is termed a proper intersection. + The property test for this situation. + + The intersection point(s) may be computed in a precise or non-precise manner. + Computing an intersection point precisely involves rounding it + via a supplied . + + LineIntersectors do not perform an initial envelope intersection test + to determine if the segments are disjoint. + This is because this class is likely to be used in a context where + envelope overlap is already known to occur (or be likely). + + + + + + Indicates that line segments do not intersect + + + + + Indicates that line segments intersect in a single point + + + + + Indicates that line segments intersect in a line segment + + + + + Computes the "edge distance" of an intersection point p along a segment. + The edge distance is a metric of the point along the edge. + The metric used is a robust and easy to compute metric function. + It is not equivalent to the usual Euclidean metric. + It relies on the fact that either the x or the y ordinates of the + points in the edge are unique, depending on whether the edge is longer in + the horizontal or vertical direction. + NOTE: This function may produce incorrect distances + for inputs where p is not precisely on p1-p2 + (E.g. p = (139,9) p1 = (139,10), p2 = (280,1) produces distance 0.0, which is incorrect. + My hypothesis is that the function is safe to use for points which are the + result of rounding points which lie on the line, but not safe to use for truncated points. + + + + + This function is non-robust, since it may compute the square of large numbers. + Currently not sure how to improve this. + + + + + A value indicating the intersection result + + Possible values are: + + + + + + + + + + Array of coordinate arrays forming the lines + + + + + Array of + + + + + The indexes of the endpoints of the intersection lines, in order along + the corresponding line + + + + + Alias the [0] for ease of reference + + + + + Alias the [1] for ease of reference + + + + + If MakePrecise is true, computed intersection coordinates will be made precise + using Coordinate.MakePrecise. + + + + + Creates an instance of this class + + + + + Force computed intersection to be rounded to a given precision model. + No getter is provided, because the precision model is not required to be specified. + + + + + Gets an endpoint of an input segment. + + the index of the input segment (0 or 1) + the index of the endpoint (0 or 1) + The specified endpoint + + + + Compute the intersection of a point p and the line p1-p2. + This function computes the bool value of the hasIntersection test. + The actual value of the intersection (if there is one) + is equal to the value of p. + + + + + Gets a value indicating if the computed intersection is collinear + + + + + Computes the intersection of the lines p1-p2 and p3-p4. + This function computes both the bool value of the hasIntersection test + and the (approximate) value of the intersection point itself (if there is one). + + The 1st point of the 1st segment + The 2nd point of the 1st segment + The 1st point of the 2nd segment + The 2nd point of the 2nd segment + + + + Computes the intersection of two line segments, one defined by and , + the other by and . + + The 1st point of the 1st segment + The 2nd point of the 1st segment + The 1st point of the 2nd segment + The 2nd point of the 2nd segment + + + Don't use this function directly, it is not meant for public use. + Please call + and test or along with and + . + + + + + + + + Gets a value indicating if the intersection is an end-point intersection + + + + + Tests whether the input geometries intersect. + + true if the input geometries intersect. + + + + Returns the number of intersection points found. This will be either 0, 1 or 2. + + The number of intersection points found (0, 1, or 2) + + + + Returns the intIndex'th intersection point. + + is 0 or 1. + The intIndex'th intersection point. + + + + Computes the values. + + + + + Test whether a point is a intersection point of two line segments. + Note that if the intersection is a line segment, this method only tests for + equality with the endpoints of the intersection segment. + It does not return true if the input point is internal to the intersection segment. + + true if the input point is one of the intersection points. + + + + Tests whether either intersection point is an interior point of one of the input segments. + + + true if either intersection point is in the interior of one of the input segment. + + + + + Tests whether either intersection point is an interior point of the specified input segment. + + + true if either intersection point is in the interior of the input segment. + + + + + Tests whether an intersection is proper. + The intersection between two line segments is considered proper if + they intersect in a single point in the interior of both segments + (e.g. the intersection is a single point and is not equal to any of the endpoints). + The intersection between a point and a line segment is considered proper + if the point lies in the interior of the segment (e.g. is not equal to either of the endpoints). + + true if the intersection is proper. + + + + Computes the intIndex'th intersection point in the direction of + a specified input line segment. + + is 0 or 1. + is 0 or 1. + + The intIndex'th intersection point in the direction of the specified input line segment. + + + + + Computes the index (order) of the intIndex'th intersection point in the direction of + a specified input line segment. + + is 0 or 1. + is 0 or 1. + + The index of the intersection point along the segment (0 or 1). + + + + + Computes the intersection line index + + The segment index + + + + Computes the "edge distance" of an intersection point along the specified input line segment. + + is 0 or 1. + is 0 or 1. + The edge distance of the intersection point. + + + + Determines the of s relative to + an areal geometry, using indexing for efficiency. + This algorithm is suitable for use in cases where + many points will be tested against a given area. + + The Location is computed precisely, th that points + located on the geometry boundary or segments will + return . + + and geometries are supported. + + The index is lazy-loaded, which allows + creating instances even if they are not used. + + Thread-safe and immutable. + + Martin Davis + + + + Creates a new locator for a given . + and geometries are supported + + The Geometry to locate in + + + + Determines the of a point in an areal . + + The point to test + The location of the point in the geometry + + + + + Creates the indexed geometry, creating it if necessary. + + + + + An interface for classes which determine the of + points in areal geometries. + + Martin Davis + + + + Determines the of a point in an areal . + + The point to test + The location of the point in the geometry + + + + Static methods for classes + + + + + Convenience method to test a point for intersection with a geometry + + The geometry is wrapped in a class. + + The locator to use. + The coordinate to test. + true if the point is in the interior or boundary of the geometry. + + + + Computes the location of points + relative to an areal , + using a simple O(n) algorithm. + + The algorithm used reports + if a point lies in the interior, exterior, + or exactly on the boundary of the Geometry. + + + Instance methods are provided to implement + the interface . + However, they provide no performance + advantage over the class methods. + + + This algorithm is suitable for use in cases where + only a few points will be tested. + If many points will be tested, + may provide better performance. + + + The algorithm used is only guaranteed to return correct results for points which are not on the boundary of the Geometry. + + + + Determines the of a point in an areal . + The return value is one of: + + if the point is in the geometry interior + if the point lies exactly on the boundary + if the point is outside the geometry + + + The point to test + The areal geometry to test + The Location of the point in the geometry + + + + Determines whether a point is contained in a , + or lies on its boundary. + This is a convenience method for + + Location.Exterior != Locate(p, geom) + + + The point to test. + The geometry to test. + if the point lies in or on the geometry. + + + + Determines whether a point lies in a . + If the point lies on the polygon boundary it is + considered to be inside. + + The point to test + The areal geometry to test + true if the point lies in the polygon + + + + Determines whether a point lies in a LinearRing, using the ring envelope to short-circuit if possible. + + The point to test + A linear ring + true if the point lies inside the ring + + + + Initializes a new instance of the class, + using the provided areal geometry. + + The areal geometry to locate in. + + + + Determines the of a point in an areal . + The return value is one of: + + if the point is in the geometry interior + if the point lies exactly on the boundary + if the point is outside the geometry + + + The point to test + The Location of the point in the geometry. + + + + Measures the degree of similarity between two s + using the area of intersection between the geometries. + The measure is normalized to lie in the range [0, 1]. + Higher measures indicate a great degree of similarity. + + + NOTE: Currently experimental and incomplete. + + mbdavis + + + + Computes the similarity measure between two geometries + + A geometry. + A geometry. + + The value of the similarity measure, in [0.0, 1.0]. + + + + + Measures the degree of similarity between two + s using the Fréchet distance metric. + The measure is normalized to lie in the range [0, 1]. + Higher measures indicate a great degree of similarity. + + The measure is computed by computing the Fréchet distance + between the input geometries, and then normalizing + this by dividing it by the diagonal distance across + the envelope of the combined geometries. + + Note: the input should be normalized, especially when + measuring geometries because for the + Fréchet distance the order of {@link Coordinate}s is + important. + + Felix Obermaier + + + + Creates an instance of this class + + + + + + + + Measures the degree of similarity between two s using the Hausdorff distance metric. + + + + The measure is normalized to lie in the range [0, 1]. Higher measures indicate a great degree of similarity. + + + The measure is computed by computing the Hausdorff distance between the input geometries, and then normalizing + this by dividing it by the diagonal distance across the envelope of the combined geometries. + + + mbdavis + + + + + + + + + + + An interface for classes which measures the degree of similarity between two {@link Geometry}s. + + + The computed measure lies in the range [0, 1]. + Higher measures indicate a great degree of similarity. + A measure of 1.0 indicates that the input geometries are identical + A measure of 0.0 indicates that the geometries have essentially no similarity. + The precise definition of "identical" and "no similarity" may depend on the exact algorithm being used. + + mbdavis + + + + Function to measure the similarity between two s. + + A geometry + A geometry + The similarity value between two s + + + + Provides methods to mathematically combine values. + + Martin Davis + + + + + + + + + + + + Computes the Minimum Bounding Circle (MBC) for the points in a . + The MBC is the smallest circle which covers all the input points + (this is also sometimes known as the Smallest Enclosing Circle). + This is equivalent to computing the Maximum Diameter of the input point set. + + + + The computed circle can be specified in two equivalent ways, + both of which are provide as output by this class: + + As a centre point and a radius + By the set of points defining the circle. + Depending on the number of points in the input + and their relative positions, this set + contains from 0 to 3 points. + + 0 or 1 points indicate an empty or trivial input point arrangement. + 2 points define the diameter of the minimum bounding circle. + 3 points define an inscribed triangle of the minimum bounding circle. + + + + The class can also output a which approximates the + shape of the Minimum Bounding Circle (although as an approximation + it is not guaranteed to cover all the input points.) + + The Maximum Diameter of the input point set can + be computed as well. The Maximum Diameter is + defined by the pair of input points with maximum distance between them. + The points of the maximum diameter are two of the extremal points of the Minimum Bounding Circle. + They lie on the convex hull of the input. + However, that the maximum diameter is not a diameter + of the Minimum Bounding Circle in the case where the MBC is + defined by an inscribed triangle. + + Martin Davis + + + + Creates a new object for computing the minimum bounding circle for the + point set defined by the vertices of the given geometry. + + The geometry to use to obtain the point set + + + + Gets a geometry which represents the Minimum Bounding Circle. + + + + If the input is degenerate (empty or a single unique point), + this method will return an empty geometry or a single Point geometry. + Otherwise, a Polygon will be returned which approximates the + Minimum Bounding Circle. (Note that because the computed polygon is only an approximation, it may not precisely contain all the input points.) + + + A Geometry representing the Minimum Bounding Circle. + + + Gets a geometry representing the maximum diameter of the + input. The maximum diameter is the longest line segment + between any two points of the input. + + The points are two of the extremal points of the Minimum Bounding Circle. + They lie on the convex hull of the input. + + + The result is + + a LineString between the two farthest points of the input + a empty LineString if the input is empty + a Point if the input is a point + + + + + + Gets a geometry representing a line between the two farthest points + in the input. + + These points are two of the extremal points of the Minimum Bounding Circle + They lie on the convex hull of the input. + + A LineString between the two farthest points of the input + An empty LineString if the input is empty + A Point if the input is a point + + + + Finds the farthest pair out of 3 extremal points + + The array of extremal points + The pair of farthest points + + + + Gets a geometry representing the diameter of the computed Minimum Bounding Circle. + + + + the diameter line of the Minimum Bounding Circle + an empty line if the input is empty + a Point if the input is a point + + + + + + Gets the extremal points which define the computed Minimum Bounding Circle. + There may be zero, one, two or three of these points, depending on the number + of points in the input and the geometry of those points. + + 0 or 1 points indicate an empty or trivial input point arrangement. + 2 points define the diameter of the Minimum Bounding Circle. + 3 points define an inscribed triangle of which the Minimum Bounding Circle is the circumcircle. + The longest chords of the circle are the line segments [0-1] and[1 - 2] + + + The points defining the Minimum Bounding Circle + + + + Gets the centre point of the computed Minimum Bounding Circle. + + + + The centre point of the Minimum Bounding Circle or + null if the input is empty + + + + + + Gets the radius of the computed Minimum Bounding Circle. + + The radius of the Minimum Bounding Circle + + + + Computes the minimum diameter of a . + + + + The minimum diameter is defined to be the + width of the smallest band that contains the point, + where a band is a strip of the plane defined + by two parallel lines. + This can be thought of as the smallest hole that the point can be + moved through, with a single rotation. + + + The first step in the algorithm is computing the convex hull of the Geometry. + If the input Geometry is known to be convex, a hint can be supplied to + avoid this computation. + + + This class can also be used to compute a line segment representing + the minimum diameter, the supporting line segment of the minimum diameter, + and a minimum rectangle enclosing the input geometry. + This rectangle will + have width equal to the minimum diameter, and have one side + parallel to the supporting segment. + + + + + + + Gets the minimum rectangle enclosing a geometry. + + The geometry + The minimum rectangle enclosing the geometry + + + + Gets the minimum diameter enclosing a geometry. + + The geometry + The length of the minimum diameter of the geometry + + + + Compute a minimum diameter for a given . + + a Geometry. + + + + Compute a minimum diameter for a giver Geometry, + with a hint if + the Geometry is convex + (e.g. a convex Polygon or LinearRing, + or a two-point LineString, or a Point). + + a Geometry which is convex. + true if the input point is convex. + + + + Gets the length of the minimum diameter of the input Geometry. + + The length of the minimum diameter. + + + + Gets the Coordinate forming one end of the minimum diameter. + + A coordinate forming one end of the minimum diameter. + + + + Gets the segment forming the base of the minimum diameter. + + The segment forming the base of the minimum diameter. + + + + Gets a LineString which is a minimum diameter. + + A LineString which is a minimum diameter. + + + + + + + + + + + + + + + Compute the width information for a ring of Coordinates. + Leaves the width information in the instance variables. + + + + + + + + + + + + + + + + + + + + + + + Gets the minimum rectangular which encloses the input geometry. + + + + The rectangle has width equal to the minimum diameter, and a longer length. + If the convex hull of the input is degenerate (a line or point) a or is returned. + + + The minimum rectangle can be used as an extremely generalized representation for the given geometry. + + + The minimum rectangle enclosing the input (or a line or point if degenerate) + + + + + + + + + + + + + + Functions to compute the orientation of basic geometric structures + including point triplets(triangles) and rings. + Orientation is a fundamental property of planar geometries + (and more generally geometry on two-dimensional manifolds). + + Determining triangle orientation + is notoriously subject to numerical precision errors + in the case of collinear or nearly collinear points. + NTS uses extended-precision arithmetic to increase + the robustness of the computation. + + + Martin Davis + + + + + Returns the orientation index of the direction of the point relative to + a directed infinite line specified by p1->p2. + The index indicates whether the point lies to the + or of the line, or lies on it . + The index also indicates the orientation of the triangle formed by the three points + (, , or + ) + + The origin point of the line vector + The final point of the line vector + The point to compute the direction to + + The of q in regard to the vector p1->p2 + + + ValueDescription + + + , + is collinear with p1->p2 + + + , + is clockwise (right) from p1->p2 + + + , + is counter-clockwise (left) from p1->p2 + + + + + + + Tests if a ring defined by an array of s is + oriented counter-clockwise. + + The list of points is assumed to have the first and last points equal. + This handles coordinate lists which contain repeated points. + This handles rings which contain collapsed segments (in particular, along the top of the ring). + + This algorithm is guaranteed to work with valid rings. + It also works with "mildly invalid" rings + which contain collapsed(coincident) flat segments along the top of the ring. + If the ring is "more" invalid (e.g.self-crosses or touches), + the computed result may not be correct. + + An array of Coordinates forming a ring (with first and last point identical) + true if the ring is oriented counter-clockwise. + + + + Tests if a ring defined by a is + oriented counter-clockwise. + + The list of points is assumed to have the first and last points equal. + This handles coordinate lists which contain repeated points. + This handles rings which contain collapsed segments (in particular, along the top of the ring). + + This algorithm is guaranteed to work with valid rings. + It also works with "mildly invalid" rings + which contain collapsed(coincident) flat segments along the top of the ring. + If the ring is "more" invalid (e.g.self-crosses or touches), + the computed result may not be correct. + + A CoordinateSequences forming a ring (with first and last point identical). + true if the ring is oriented counter-clockwise. + + + + Tests if a ring defined by an array of s is + oriented counter-clockwise, using the signed area of the ring. + + The list of points is assumed to have the first and last points equal. + This handles coordinate lists which contain repeated points. + This handles rings which contain collapsed segments + (in particular, along the top of the ring). + This handles rings which are invalid due to self-intersection + + This algorithm is guaranteed to work with valid rings. + For invalid rings (containing self-intersections), + the algorithm determines the orientation of + the largest enclosed area (including overlaps). + This provides a more useful result in some situations, such as buffering. + + However, this approach may be less accurate in the case of + rings with almost zero area. + (Note that the orientation of rings with zero area is essentially + undefined, and hence non-deterministic.) + + An array of Coordinates forming a ring (with first and last point identical) + true if the ring is oriented counter-clockwise. + + + + Tests if a ring defined by a is + oriented counter-clockwise, using the signed area of the ring. + + The list of points is assumed to have the first and last points equal. + This handles coordinate lists which contain repeated points. + This handles rings which contain collapsed segments + (in particular, along the top of the ring). + This handles rings which are invalid due to self-intersection + + This algorithm is guaranteed to work with valid rings. + For invalid rings (containing self-intersections), + the algorithm determines the orientation of + the largest enclosed area (including overlaps). + This provides a more useful result in some situations, such as buffering. + + However, this approach may be less accurate in the case of + rings with almost zero area. + (Note that the orientation of rings with zero area is essentially + undefined, and hence non-deterministic.) + + An array of Coordinates forming a ring (with first and last point identical) + true if the ring is oriented counter-clockwise. + + + + Re-orients an orientation. + + The orientation + + + + + Angle orientation + + + + A value that indicates an orientation of collinear, or no turn (straight) + + + A value that indicates an orientation of collinear, or no turn (straight) + + + A value that indicates an orientation of collinear, or no turn (straight) + + + A value that indicates an orientation of counterclockwise, or a left turn. + + + A value that indicates an orientation of counterclockwise, or a left turn. + + + A value that indicates an orientation of clockwise or a right turn. + + + A value that indicates an orientation of clockwise or a right turn. + + + + Functions for locating points within basic geometric + structures such as lines and rings. + + Martin Davis + + + + Tests whether a point lies on the line defined by a list of + coordinates. + + The point to test + The line coordinates + + true if the point is a vertex of the line or lies in the interior + of a line segment in the line + + + + + Tests whether a point lies on the line defined by a list of + coordinates. + + The point to test + The line coordinates + + true if the point is a vertex of the line or lies in the interior + of a line segment in the line + + + + + Tests whether a point lies inside or on a ring. The ring may be oriented in + either direction. A point lying exactly on the ring boundary is considered + to be inside the ring. + + This method does not first check the point against the envelope of + the ring. + + The point to check for ring inclusion + An array of coordinates representing the ring (which must have + first point identical to last point) + true if p is inside ring + + + + + Tests whether a point lies inside or on a ring. The ring may be oriented in + either direction. A point lying exactly on the ring boundary is considered + to be inside the ring. + + This method does not first check the point against the envelope of + the ring. + + The point to check for ring inclusion + A CoordinateSequence representing the ring (which must have + first point identical to last point) + true if p is inside ring + + + + Determines whether a point lies in the interior, on the boundary, or in the + exterior of a ring.The ring may be oriented in either direction. + + This method does not first check the point against the envelope of + the ring. + + The point to check for ring inclusion + A CoordinateSequence representing the ring (which must have + first point identical to last point) + the of p relative to the ring + + + + Determines whether a point lies in the interior, on the boundary, or in the + exterior of a ring.The ring may be oriented in either direction. + + This method does not first check the point against the envelope of + the ring. + + The point to check for ring inclusion + A CoordinateSequence representing the ring (which must have + first point identical to last point) + + + + Computes the topological relationship () of a single point to a Geometry. + + + A may be specified to control the evaluation of whether the point lies on the boundary or not + The default rule is to use the SFS Boundary Determination Rule + + Notes: + + s do not enclose any area - points inside the ring are still in the EXTERIOR of the ring. + + Instances of this class are not reentrant. + + + + + + Initializes a new instance of the class. + The default boundary rule is . + + + + + Initializes a new instance of the class using the provided + boundary rule. + + The boundary rule to use. + + + + Convenience method to test a point for intersection with a Geometry + + The coordinate to test. + The Geometry to test. + true if the point is in the interior or boundary of the Geometry. + + + + Computes the topological relationship ({Location}) of a single point to a Geometry. + It handles both single-element and multi-element Geometries. + The algorithm for multi-part Geometries takes into account the boundaryDetermination rule. + + The Location of the point relative to the input Geometry. + + + + Counts the number of segments crossed by a horizontal ray extending to the right + from a given point, in an incremental fashion. + This can be used to determine whether a point lies in a geometry. + The class determines the situation where the point lies exactly on a segment. + When being used for Point-In-Polygon determination, this case allows short-circuiting the evaluation. + + + This class handles polygonal geometries with any number of shells and holes. + The orientation of the shell and hole rings is unimportant. + In order to compute a correct location for a given polygonal geometry, + it is essential that all segments are counted which + + touch the ray + lie in in any ring which may contain the point + + + The only exception is when the point-on-segment situation is detected, in which + case no further processing is required. + The implication of the above rule is that segments which can be a priori determined to not touch the ray + (i.e. by a test of their bounding box or Y-extent) do not need to be counted. This allows for optimization by indexing. + + + This implementation uses the extended-precision orientation test, + to provide maximum robustness and consistency within + other algorithms. + + + Martin Davis + + + + Determines the of a point in a ring. + This method is an exemplar of how to use this class. + + The point to test + An array of Coordinates forming a ring + The location of the point in the ring + + + + Determines the of a point in a ring. + + The point to test + A coordinate sequence forming a ring + The location of the point in the ring + + + + Creates an instance of this class + + A coordinate. + + + + Counts a segment + + An endpoint of the segment + Another endpoint of the segment + + + + Reports whether the point lies exactly on one of the supplied segments. + + + This method may be called at any time as segments are processed. If the result of this method is true, + no further segments need be supplied, since the result will never change again. + + + + + Gets the of the point relative to the ring, polygon + or multipolygon from which the processed segments were provided. + + + This property only determines the correct location + if all relevant segments have been processed. + + + + + Tests whether the point lies in or on + the ring, polygon or multipolygon from which the processed + segments were provided. + + + This property only determines the correct location + if all relevant segments have been processed + + + + + Computes whether a rectangle intersects line segments. + + + Rectangles contain a large amount of inherent symmetry + (or to put it another way, although they contain four + coordinates they only actually contain 4 ordinates + worth of information). + The algorithm used takes advantage of the symmetry of + the geometric situation + to optimize performance by minimizing the number + of line intersection tests. + + Martin Davis + + + + Creates a new intersector for the given query rectangle, + specified as an . + + The query rectangle, specified as an Envelope + + + + Tests whether the query rectangle intersects a given line segment. + + The first endpoint of the segment + The second endpoint of the segment + true if the rectangle intersects the segment + + + + Implements an algorithm to compute the + sign of a 2x2 determinant for double precision values robustly. + It is a direct translation of code developed by Olivier Devillers. + + The original code carries the following copyright notice: + ************************************************************************ + Author : Olivier Devillers + Olivier.Devillers@sophia.inria.fr + http:/www.inria.fr:/prisme/personnel/devillers/anglais/determinant.html + + Olivier Devillers has allowed the code to be distributed under + the LGPL (2012-02-16) saying "It is ok for LGPL distribution." + + ************************************************************************* + ************************************************************************* + Copyright (c) 1995 by INRIA Prisme Project + BP 93 06902 Sophia Antipolis Cedex, France. + All rights reserved + ************************************************************************* + + + + + Computes the sign of the determinant of the 2x2 matrix with the given entries, in a robust way. + + + + + + + + -1 if the determinant is negative, + 1 if the determinant is positive, + 0 if the determinant is null. + + + + + + Returns the index of the direction of the point q relative to + a vector specified by p1-p2. + + The origin point of the vector + The final point of the vector + the point to compute the direction to + + + 1 if q is counter-clockwise (left) from p1-p2 + -1 if q is clockwise (right) from p1-p2 + 0 if q is collinear with p1-p2 + + + + + A robust version of . + + + + + + + + + + + + + + + + This method computes the actual value of the intersection point. + To obtain the maximum precision from the intersection calculation, + the coordinates are normalized by subtracting the minimum + ordinate values (in absolute value). This has the effect of + removing common significant digits from the calculation to + maintain more bits of precision. + + + + + + + + + + Computes a segment intersection using homogeneous coordinates. + Round-off error can cause the raw computation to fail, + (usually due to the segments being approximately parallel). + If this happens, a reasonable approximation is computed instead. + + + + + Tests whether a point lies in the envelopes of both input segments. + A correctly computed intersection point should return true + for this test. + Since this test is for debugging purposes only, no attempt is + made to optimize the envelope test. + + + true if the input point lies within both input segment envelopes. + + + + Finds the endpoint of the segments P and Q which + is closest to the other segment. + This is a reasonable surrogate for the true + intersection points in ill-conditioned cases + (e.g. where two segments are nearly coincident, + or where the endpoint of one segment lies almost on the other segment). + + + This replaces the older CentralEndpoint heuristic, + which chose the wrong endpoint in some cases + where the segments had very distinct slopes + and one endpoint lay almost on the other segment. + + an endpoint of segment P + an endpoint of segment P + an endpoint of segment Q + an endpoint of segment Q + the nearest endpoint to the other segment + + + + Gets the Z value of a coordinate if present, or + interpolates it from the segment it lies on. + If the segment Z values are not fully populate + NaN is returned. + + A coordinate, possibly with Z + A segment endpoint, possibly with Z + A segment endpoint, possibly with Z + The extracted or interpolated Z value (may be NaN) + + + + Interpolates a Z value for a point along + a line segment between two points. + The Z value of the interpolation point (if any) is ignored. + If either segment point is missing Z, + returns NaN. + + A coordinate, possibly with Z + A segment endpoint, possibly with Z + A segment endpoint, possibly with Z + The extracted or interpolated Z value (may be NaN) + + + + Interpolates a Z value for a point along + two line segments and computes their average. + The Z value of the interpolation point (if any) is ignored. + If one segment point is missing Z that segment is ignored + if both segments are missing Z, returns NaN. + + A coordinate + A segment endpoint, possibly with Z + A segment endpoint, possibly with Z + A segment endpoint, possibly with Z + A segment endpoint, possibly with Z + The averaged interpolated Z value (may be NaN) + + + + Structure for a closed 1-dimensional ℝ-interval + + + + + The lower bound of the interval + + + + + The upper bound of the interval + + + + + Initializes this structure with = = + + The value for min and max + + + + Initializes this structure with and values + + The minimum interval values + The maximum interval values + + + + Method to expand + + + + + + + Gets a value if this interval is empty/undefined + + + + + + + + + + + + + + + + + Gets a value indicating the width of the + + + + + Gets a value indicating the centre of the interval (Min + Width * 0.5) + + + + + Function to compute an interval that contains this and + + The interval + An interval + + + + Function to test if this overlaps . + + The interval to test + true if this interval overlaps + + + + Function to test if this overlaps the interval ℝ[, ]. + + The minimum value of the interval + The maximum value of the interval + true if this interval overlaps the interval ℝ[, ] + + + + Function to test if this contains . + + This is more rigid than + The interval to test + true if this interval contains + + + + Function to test if this contains the interval ℝ[, ]. + + This is more rigid than + The minimum value of the interval + The maximum value of the interval + true if this interval contains the interval ℝ[, ] + + + + Function to test if this contains the value . + + The value to test + true if this interval contains the value + + + + Function to test if this intersects the interval . + + + + true if this interval intersects + + + + Function to test if this intersects the interval ℝ[, ]. + + The minimum value of the interval + The maximum value of the interval + true if this interval intersects the interval ℝ[, ]. + + + + Creates an empty or uninitialized Interval + + An empty or uninitialized + + + + Creates an interval with the range ℝ[,] + + The value + An + + + + Creates an interval with the range ℝ[,].
+ If necessary, val1 and val2 are exchanged. +
+ The minimum value + The maximum value + An +
+ + + Creates an interval with the range ℝ[,]. + + The template interval + An + + + + Equality operator for s + + The left-hand-side + The right-hand-side + true if the s are equal. + + + + Inequality operator for s + + The left-hand-side + The right-hand-side + true if the s are not equal. + + + + Densifies a geometry by inserting extra vertices along the line segments + contained in the geometry. + All segments in the created densified geometry will be no longer + than the given distance tolerance + (that is, all segments in the output will have length less than or equal to + the distance tolerance). + + + Densified polygonal geometries are guaranteed to be topologically correct. + + The coordinates created during densification respect the input geometry's . + + By default polygonal results are processed to ensure they are valid. + This processing is costly, and it is very rare for results to be invalid. + Validation processing can be disabled by setting the property to false. + + Note: At some future point this class will offer a variety of densification strategies. + + Martin Davis + + + + Densifies a geometry using a given distance tolerance, and respecting the input geometry's . + + The geometry densify + The distance tolerance () + The densified geometry + + + + Densifies a list of coordinates. + + The coordinate list + The densify tolerance + The precision model to apply on the new coordinates + The densified coordinate sequence + + + + Indicates whether areas should be topologically validated. +
Note: JTS name _isValidated +
+
+ + Creates a new densifier instance + The geometry to densify + + + + Gets or sets the distance tolerance for the densification. All line segments + in the densified geometry will be no longer than the distance tolerance. + The distance tolerance must be positive. + + + + + Gets or sets whether polygonal results are processed to ensure they are valid. + + true if polygonal input is validated. + + + + Gets the densified geometry. + + The densified geometry + + + + Indicates whether areas should be topologically validated. +
Note: JTS name _isValidated +
+
+ + + Creates a valid area geometry from one that possibly has bad topology + (i.e. self-intersections). Since buffer can handle invalid topology, but + always returns valid geometry, constructing a 0-width buffer "corrects" + the topology. Note this only works for area geometries, since buffer + always returns areas. This also may return empty geometries, if the input + has no actual area. + + An area geometry possibly containing self-intersections + A valid area geometry + + + + A graph containing s. + + + + + A HalfEdge which carries information + required to support . + + + + + Tests whether this edge is the starting segment + in a LineString being dissolved. + + true if this edge is a start segment + + + + Sets this edge to be the start segment of an input LineString. + + + + + Dissolves the linear components + from a collection of s. + into a set of maximal-length s + in which every unique segment appears once only. + The output linestrings run between node vertices + of the input, which are vertices which have + either degree 1, or degree 3 or greater. + + + Use cases for dissolving linear components + include generalization + (in particular, simplifying polygonal coverages), + and visualization + (in particular, avoiding symbology conflicts when + depicting shared polygon boundaries). + + + This class does NOT node the input lines. + If there are line segments crossing in the input, + they will still cross in the output. + + + + + Dissolves the linear components in a geometry. + + the geometry to dissolve + the dissolved lines + + + + Creates an instance of this class + + + + + Adds a to be dissolved. + Any number of geometries may be added by calling this method multiple times. + Any type of Geometry may be added. The constituent linework will be + extracted to be dissolved. + + geometry to be line-merged + + + + Adds a collection of Geometries to be processed. May be called multiple times. + Any dimension of Geometry may be added; the constituent linework will be + extracted. + + the geometries to be line-merged + + + + Gets the dissolved result as a . + + the dissolved lines + + + + For each edge in stack + (which must originate at a node) + extracts the line it initiates. + + + + + Updates the tracked ringStartEdge + if the given edge has a lower origin + (using the standard ordering). + + + Identifying the lowest starting node meets two goals: + * It ensures that isolated input rings are created using the original node and orientation. + * For isolated rings formed from multiple input linestrings, + it provides a canonical node and orientation for the output + (rather than essentially random, and thus hard to test). + + + + + + Builds a line starting from the given edge. + The start edge origin is a node (valence = 1 or >= 3), + unless it is part of a pure ring. + + + A pure ring has no other incident lines. + In this case the start edge may occur anywhere on the ring. + + + The line is built up to the next node encountered, + or until the start edge is re-encountered + (which happens if the edges form a ring). + + + + + + Adds edges around this node to the stack. + + + + + + A graph comprised of s. + It supports tracking the vertices in the graph + via edges incident on them, + to allow efficient lookup of edges and vertices. + + + This class may be subclassed to use a + different subclass of HalfEdge, + by overriding . + If additional logic is required to initialize + edges then + can be overridden as well. + + + + + Creates a single HalfEdge. + Override to use a different HalfEdge subclass. + + the origin location + a new with the given origin + + + + Creates a pair, using the HalfEdge type of the graph subclass + + + + A pair + + + + Adds an edge between the coordinates orig and dest + to this graph. + + + Only valid edges can be added (in particular, zero-length segments cannot be added) + + the edge origin location + the edge destination location + The created edge + null if the edge was invalid and not added + + + + + Test if an the coordinates for an edge form a valid edge (with non-zero length) + + The start coordinate + The end coordinate + true of the edge formed is valid + + + + Inserts an edge not already present into the graph. + + the edge origin location + the edge destination location + an existing edge with same orig (if any) + the created edge + + + + Gets all s in the graph. + Both edges of edge pairs are included. + + An enumeration of the graph edges + + + + Finds an edge in this graph with the given origin + and destination, if one exists. + + the origin location + the destination location + an edge with the given orig and dest, or null if none exists + + + + Builds an edge graph from geometries containing edges. + + + + + Adds the edges of a Geometry to the graph. + May be called multiple times. + Any dimension of Geometry may be added; the constituent edges are extracted. + + geometry to be added + + + + Adds the edges in a collection of s to the graph. + May be called multiple times. + Any dimension of may be added. + + the geometries to be added + + + + Represents a directed component of an edge in an . + HalfEdges link vertices whose locations are defined by s. + HalfEdges start at an origin vertex, + and terminate at a destination vertex. + HalfEdges always occur in symmetric pairs, with the method + giving access to the oppositely-oriented component. + HalfEdges and the methods on them form an edge algebra, + which can be used to traverse and query the topology + of the graph formed by the edges. + + To support graphs where the edges are sequences of coordinates + each edge may also have a direction point supplied. + This is used to determine the ordering + of the edges around the origin. + HalfEdges with the same origin are ordered + so that the ring of edges formed by them is oriented CCW. + + By design HalfEdges carry minimal information + about the actual usage of the graph they represent. + They can be subclassed to carry more information if required. + + HalfEdges form a complete and consistent data structure by themselves, + but an is useful to allow retrieving edges + by vertex and edge location, as well as ensuring + edges are created and linked appropriately. + + Martin Davis + + + + Creates a HalfEdge pair representing an edge + between two vertices located at coordinates p0 and p1. + + a vertex coordinate + a vertex coordinate + the HalfEdge with origin at p0 + + + + Initialize a symmetric pair of halfedges. + Intended for use by + subclasses. + + The edges are initialized to have each other + as the edge, and to have + pointers which point to edge other. + This effectively creates a graph containing a single edge. + + A halfedge + A symmetric halfedge + The initialized edge e0 + + + + Creates an edge originating from a given coordinate. + + the origin coordinate + + + + Links this edge with its sym (opposite) edge. + This must be done for each pair of edges created. + + The sym edge to link. + + + + Initializes this edge with as edge. + + A symmetric half edge. + + + + Gets the origin coordinate of this edge. + + + + + Gets the destination coordinate of this edge. + + + + + Gets a value indicating the X component of the direction vector. + + The X component of the direction vector + + + + Gets a value indicating the Y component of the direction vector. + + The Y component of the direction vector + + + + Gets a value indicating the direction point of this edge. + In the base case this is the dest coordinate + of the edge. + + Subclasses may override to + allow a HalfEdge to represent an edge with more than two coordinates. + + The direction point for the edge + + + + Gets or sets the symmetric (opposite) edge of this edge. + + + + + Gets the next edge CCW around the destination vertex of this edge. + If the destination vertex has degree 1 then this is the Sym edge. + + The next outgoing edge CCW around the destination vertex + + + + Gets the previous edge CW around the origin + vertex of this edge, + with that vertex being its destination. + + It is always true that e.Next.Prev == e + + Note that this requires a scan of the origin edges, + so may not be efficient for some uses. + + The previous edge CW around the origin vertex + + + + Gets the next edge CCW around the origin of this edge, + with the same origin.
+ If the origin vertex has degree 1 then this is the edge itself. + + e.ONext is equal to e.Sym.Next() +
+ The next edge around the origin +
+ + + Finds the edge starting at the origin of this edge + with the given dest vertex, if any. + + the dest vertex to search for + + the edge with the required dest vertex, + if it exists, or null + + + + + Tests whether this edge has the given orig and dest vertices. + + the origin vertex to test + the destination vertex to test + true if the vertices are equal to the ones of this edge + + + + Inserts an edge + into the ring of edges around the origin vertex of this edge, + ensuring that the edges remain ordered CCW. + The inserted edge must have the same origin as this edge. + + the edge to insert + + + + Finds the insertion edge for a edge + being added to this origin, + ensuring that the star of edges + around the origin remains fully CCW. + + The edge being added + The edge to insert after + + + + Insert an edge with the same origin after this one. + Assumes that the inserted edge is in the correct + position around the ring. + + the edge to insert (with same origin) + + + + Tests whether the edges around the origin + are sorted correctly. + Note that edges must be strictly increasing, + which implies no two edges can have the same direction point. + + true if the origin edges are sorted correctly + + + + + Finds the lowest edge around the origin, + using the standard edge ordering. + + The lowest edge around the origin + + + + Compares edges which originate at the same vertex + based on the angle they make at their origin vertex with the positive X-axis. + This allows sorting edges around their origin vertex in CCW order. + + + + + Implements the total order relation. + The angle of edge a is greater than the angle of edge b, + where the angle of an edge is the angle made by + the first segment of the edge with the positive x-axis. + When applied to a list of edges originating at the same point, + this produces a CCW ordering of the edges around the point. + Using the obvious algorithm of computing the angle is not robust, + since the angle calculation is susceptible to round off error. + + + A robust algorithm is: + 1. compare the quadrants the edge vectors lie in. + If the quadrants are different, + it is trivial to determine which edge has a greater angle. + 2. If the vectors lie in the same quadrant, the + function + can be used to determine the relative orientation of the vectors. + + + + + The X component of the distance between the orig and dest vertices. + + + + + The Y component of the distance between the orig and dest vertices. + + + + + Computes a string representation of a HalfEdge. + + + + + Provides a string representation of the edges around + the origin node of this edge. + + + Uses the subclass representation for each edge. + + A string showing the edges around the origin + + + + Computes the degree of the origin vertex. + The degree is the number of edges + originating from the vertex. + + the degree of the origin vertex + + + + Finds the first node previous to this edge, if any. + If no such node exists (i.e. the edge is part of a ring) + then null is returned. + + + an edge originating at the node prior to this edge, if any, + or null if no node exists + + + + + A which supports + marking edges with a boolean flag. + Useful for algorithms which perform graph traversals. + + + + + Sets the mark for the given edge pair to a boolean value. + + an edge of the pair to update + the mark value to set + + + + Marks the edges in a pair. + + an edge of the pair to mark + + + + Creates a new marked edge. + + the coordinate of the edge origin + + + + Marks this edge. + + + + + A Depth object records the topological depth of the sides + of an Edge for up to two Geometries. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Calls GetDepth and SetDepth. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A Depth object is null (has never been initialized) if all depths are null. + + true if depth is null (has never been initialized) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Normalize the depths for each point, if they are non-null. + A normalized depth + has depth values in the set { 0, 1 }. + Normalizing the depths + involves reducing the depths by the same amount so that at least + one of them is 0. If the remaining value is > 0, it is set to 1. + + + + + + + + + + + + + + + + Computes the factor for the change in depth when moving from one location to another. + E.g. if crossing from the to the + the depth decreases, so the factor is -1. + + The current location + The next location + Change of depth moving from to + + + + The depth of each side (position) of this edge. + The 0 element of the array is never used. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Set depth for a position + + The position to update + The depth at the provided position + + + + + + + + + Gets or sets a value indicating if both Visited + and Sym.Visited are true. + + Setting the property marks both DirectedEdges attached to a given Edge. + + This is used for edges corresponding to lines, which will only + appear oriented in a single direction in the result. + + + + + + + + + + + + + + + + + + + + + + + + + + Gets a value indicating if this edge is a line edge. + It is if + + at least one of the labels is a line label + any labels which are not line labels have all Location = Exterior. + + + true if edge is a line edge + + + + This is an interior Area edge if + its label is an Area label for both Geometries + and for each Geometry both sides are in the interior. + + true if this is an interior Area edge. + + + + Compute the label in the appropriate orientation for this DirEdge. + + + + + Set both edge depths. + One depth for a given side is provided. + The other is computed depending on the Location + transition and the depthDelta of the edge. + + The position to update + The depth at the provided position + + + + Set both edge depths. + One depth for a given side is provided. + The other is computed depending on the Location + transition and the depthDelta of the edge. + + The position to update + The depth at the provided position + + + + + + + + + + + + + + + + A DirectedEdgeStar is an ordered list of outgoing DirectedEdges around a node. + It supports labelling the edges as well as linking the edges to form both + MaximalEdgeRings and MinimalEdgeRings. + + + + + A list of all outgoing edges in the result, in CCW order. + + + + + Insert a directed edge in the list. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Compute the labelling for all dirEdges in this star, as well + as the overall labelling. + + + + + + For each dirEdge in the star, merge the label . + + + + + Update incomplete dirEdge labels from the labeling for the node. + + The label to apply + + + + + + + + + + Traverse the star of DirectedEdges, linking the included edges together. + To link two dirEdges, the next pointer for an incoming dirEdge + is set to the next outgoing edge. + DirEdges are only linked if: + they belong to an area (i.e. they have sides) + they are marked as being in the result + Edges are linked in CCW order (the order they are stored). + This means that rings have their face on the Right + (in other words, the topological location of the face is given by the RHS label of the DirectedEdge). + PRECONDITION: No pair of dirEdges are both marked as being in the result. + + + + + + + + + + + + + + + + Traverse the star of edges, maintaining the current location in the result + area at this node (if any). + If any L edges are found in the interior of the result, mark them as covered. + + + + + + + + + + + Compute the DirectedEdge depths for a subsequence of the edge array. + + The last depth assigned (from the R side of the last edge visited). + + + + + + + + + + + + + + + Updates an IM from the label for an edge. + Handles edges from both L and A geometries. + + An intersection matrix + A label + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The depthDelta is the change in depth as an edge is crossed from R to L. + + The change in depth as the edge is crossed from R to L. + + + + + + + + + + + + + + + + + + + + + + + + An Edge is collapsed if it is an Area edge and it consists of + two segments which are equal and opposite (eg a zero-width V). + + true if edge is consisting of two segments + which are equal and of oppose orientation (Zero-width V area edge) + + + + + + + + + + + + + + + + + + + + Adds EdgeIntersections for one or both + intersections found for a segment of an edge to the edge intersection list. + + A line intersector + A segment index + A geometry index + + + + Add an EdgeIntersection for intersection intIndex. + An intersection that falls exactly on a vertex of the edge is normalized + to use the higher of the two possible segmentIndexes. + + A line intersector + A segment index + A geometry index + The intersection index (0 or 1) + + + + Update the IM with the contribution for this component. + A component only contributes if it has a labelling for both parent geometries. + + + + + + Equals is defined to be: + e1 equals e2 + if + the coordinates of e1 are the same or the reverse of the coordinates in e2. + + + + + + + + + Equals is defined to be: + e1 equals e2 + if + the coordinates of e1 are the same or the reverse of the coordinates in e2. + + + + + + + + + + + + + + + + + + + + + + Check if coordinate sequences of the Edges are identical. + + The edge to test + + true if the coordinate sequences of the Edges are identical. + + + + > + + + + + + + + + + + + + + + + Models the end of an edge incident on a node. + + + + EdgeEnds have a direction determined by the direction of the ray from the initial + point to the next point. + + + EdgeEnds are IComparable under the ordering "a has a greater angle with the x-axis than b". + This ordering is used to sort EdgeEnds around a node. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Implements the total order relation: + a has a greater angle with the positive x-axis than b. + + Using the obvious algorithm of simply computing the angle is not robust, + since the angle calculation is obviously susceptible to round off. + + A robust algorithm is: + + first compare the quadrant. If the quadrants + are different, it it trivial to determine which vector is "greater". + if the vectors lie in the same quadrant, the computeOrientation function + can be used to decide the relative orientation of the vectors. + + + An EdgeEnd + The of compared to this . + + + + Subclasses should override this if they are using labels + + + + + + + + + + + + + + + A EdgeEndStar is an ordered list of EdgeEnds around a node. + They are maintained in CCW order (starting with the positive x-axis) around the node + for efficient lookup and topology building. + + + + + A map which maintains the edges in sorted order around the node. + + + + + A list of all outgoing edges in the result, in CCW order. + + + + + The location of the point for this star in Geometry i Areas. + + + + + Insert a EdgeEnd into this EdgeEndStar. + + An EdgeEnd + + + + Insert an EdgeEnd into the map, and clear the edgeList cache, + since the list of edges has now changed. + + An EdgeEnd + An EdgeEnd + + + + The coordinate for the node this star is based at. + + + + + + + + + + Iterator access to the ordered list of edges is optimized by + copying the map collection to a list. (This assumes that + once an iterator is requested, it is likely that insertion into + the map is complete). + + Access to ordered list of edges. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + > + + + + An EdgeIntersection represents a point on an + edge which intersects with another edge. + The intersection may either be a single point, or a line segment + (in which case this point is the start of the line segment) + The label attached to this intersection point applies to + the edge from this point forwards, until the next + intersection or the end of the edge. + The intersection point must be precise. + + + + + The point of intersection. + + + + + The index of the containing line segment in the parent edge. + + + + + The edge distance of this point along the containing line segment. + + + + + Creates an instance of this class + + The point of intersection + The index of the containing line segment in the parent edge + The edge distance or this point along the containing line segment + + + + + + + Comparison with segment and distance. + + The index of the containing line segment + The distance of this point along the containing line segment + + -1 this EdgeIntersection is located before the argument location, + 0 this EdgeIntersection is at the argument location, + 1 this EdgeIntersection is located after the argument location. + + + + + + + + + + + + + + + + + + + + + A list of edge intersections along an Edge. + + + + + + + + + + + + + + + + Adds an intersection into the list, if it isn't already there. + The input segmentIndex and dist are expected to be normalized. + + The point of intersection + The index of the containing line segment in the parent edge + The edge distance of this point along the containing line segment + The EdgeIntersection found or added. + + + + Returns an iterator of EdgeIntersections. + + + + + + + + + + + + Adds entries for the first and last points of the edge to the list. + + + + + Creates new edges for all the edges that the intersections in this + list split the parent edge into. + Adds the edges to the input list (this is so a single list + can be used to accumulate all split edges for a Geometry). + + + + + + Create a new "split edge" with the section of points between + (and including) the two intersections. + The label for the new edge is the same as the label for the parent edge. + + + + + + + + + + + + + A EdgeList is a list of Edges. It supports locating edges + that are point-wise equals to a target edge. + + + + + An index of the edges, for fast lookup. + + + + + Remove the selected Edge element from the list if present. + + Edge element to remove from list + + + + Insert an edge unless it is already in the list. + + An Edge + + + + + + + + + + + + + + + If there is an edge equal to e already in the list, return it. + Otherwise return null. + + An Edge + + The equal edge, if there is one already in the list, + null otherwise. + + + + + + + + + + + + + + + + + + + + + + + + + If the edge e is already in the list, return its index. + + An Edge + + The index, if e is already in the list, + -1 otherwise. + + + + + + + + + + + Validates that a collection of is correctly noded. + Throws an appropriate exception if an noding error is found. + + Uses to perform the validation. + + + + + + Checks whether the supplied s are correctly noded. + + an enumeration of Edges. + If the SegmentStrings are not correctly noded + + + + Creates a new validator for the given collection of s. + + + + + Checks whether the supplied edges are correctly noded. + + If the SegmentStrings are not correctly noded + + + + + + + + + The directed edge which starts the list of edges for this EdgeRing. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Compute a LinearRing from the point list previously collected. + Test if the ring is a hole (i.e. if it is CCW) and set the hole flag + accordingly. + + + + + + + + + + + + + + + + + + + Returns the list of DirectedEdges that make up this EdgeRing. + + A list of DirectedEdges + + + + Collect all the points from the DirectedEdges of this ring into a contiguous list. + + + + + + + + + + + + + + + + + + + + + + + + + + + Merge the RHS label from a DirectedEdge into the label for this EdgeRing. + The DirectedEdge label may be null. This is acceptable - it results + from a node which is NOT an intersection node between the Geometries + (e.g. the end node of a LinearRing). In this case the DirectedEdge label + does not contribute any information to the overall labelling, and is simply skipped. + + + + + + + + + + + + + + + This method will cause the ring to be computed. + It will also check any holes, if they have been assigned. + + The point to test + true if the ring contains point + + + + A GeometryGraph is a graph that models a given Geometry. + + + + + Determine boundary + + The boundary node rule to apply for determination of the boundary + The number of component boundaries that a point occurs in. + or + + + + The lineEdgeMap is a map of the linestring components of the + parentGeometry to the edges which are derived from them. + This is used to efficiently perform findEdge queries + + + + + If this flag is true, the Boundary Determination Rule will used when deciding + whether nodes are in the boundary or not + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gets the used with this geometry graph. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Add a Point to the graph. + + + + + + Adds a polygon ring to the graph. Empty rings are ignored. + The left and right topological location arguments assume that the ring is oriented CW. + If the ring is in the opposite orientation, + the left and right locations must be interchanged. + + + + + + + + + + + + + + + + + + + + Add an Edge computed externally. The label on the Edge is assumed + to be correct. + + An Edge + + + + Add a point computed externally. The point is assumed to be a + Point Geometry part, which has a location of INTERIOR. + + A Coordinate + + + + Compute self-nodes, taking advantage of the Geometry type to + minimize the number of intersection tests. (E.g. rings are + not tested for self-intersection, since they are assumed to be valid). + + The LineIntersector to use. + If false, intersection checks are optimized to not test rings for self-intersection. + The computed SegmentIntersector, containing information about the intersections found. + + + + Compute self-nodes, taking advantage of the Geometry type to + minimize the number of intersection tests. (E.g.rings are + not tested for self-intersection, since they are assumed to be valid). + + The LineIntersector to use + If false, intersection checks are optimized to not test rings for self-intersection + Short-circuit the intersection computation if a proper intersection is found + + + + + + + + + + + + + + + + + + + + + Adds candidate boundary points using the current . + This is used to add the boundary + points of dim-1 geometries (Curves/MultiCurves). + + + + + + + + + + + + + Add a node for a self-intersection. + If the node is a potential boundary node (e.g. came from an edge which + is a boundary) then insert it as a potential boundary node. + Otherwise, just add it as a regular node. + + + + + + + + Determines the of the given in this geometry. + + The point to test + + The location of the point in the geometry + + + + + A GraphComponent is the parent class for the objects' + that form a graph. Each GraphComponent can carry a + Label. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IsInResult indicates if this component has already been included in the result. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A coordinate in this component (or null, if there are none). + + + + + Compute the contribution to an IM for this component. + + An IntersectionMatrix + + + + An isolated component is one that does not intersect or touch any other + component. This is the case if the label has valid locations for + only a single Geometry. + + true if this component is isolated. + + + + Update the IM with the contribution for this component. + A component only contributes if it has a labelling for both parent geometries. + + An IntersectionMatrix + + + + An EdgeSetIntersector computes all the intersections between the + edges in the set. It adds the computed intersections to each edge + they are found on. It may be used in two scenarios: + determining the internal intersections between a single set of edges + determining the mutual intersections between two different sets of edges + It uses a SegmentIntersector to compute the intersections between + segments and to record statistics about what kinds of intersections were found. + + + + + Computes all self-intersections between edges in a set of edges, + allowing client to choose whether self-intersections are computed. + + A list of edges to test for intersections. + The SegmentIntersector to use + true if self-intersections are to be tested as well. + + + + Computes all mutual intersections between two sets of edges. + + A set of edges + A set of edges + The SegmentIntersector to use + + + + + + + + + + + + + + + + + + + + + + + MonotoneChains are a way of partitioning the segments of an edge to + allow for fast searching of intersections. + They have the following properties: + the segments within a monotone chain will never intersect each other, and + the envelope of any contiguous subset of the segments in a monotone chain + is simply the envelope of the endpoints of the subset. + Property 1 means that there is no need to test pairs of segments from within + the same monotone chain for intersection. + Property 2 allows + binary search to be used to find the intersection points of two monotone chains. + For many types of real-world data, these properties eliminate a large number of + segment comparisons, producing substantial speed gains. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tests whether the envelopes of two chain sections overlap (intersect). + + true if the section envelopes overlap + + + + MonotoneChains are a way of partitioning the segments of an edge to + allow for fast searching of intersections. + + Specifically, a sequence of contiguous line segments + is a monotone chain if all the vectors defined by the oriented segments + lies in the same quadrant. + + Monotone Chains have the following useful properties: + the segments within a monotone chain will never intersect each other, and + the envelope of any contiguous subset of the segments in a monotone chain + is simply the envelope of the endpoints of the subset. + Property 1 means that there is no need to test pairs of segments from within + the same monotone chain for intersection. + Property 2 allows + binary search to be used to find the intersection points of two monotone chains. + For many types of real-world data, these properties eliminate a large number of + segment comparisons, producing substantial speed gains. + + + Note that due to the efficient intersection test, there is no need to limit the size + of chains to obtain fast performance. + + + + + + + + + + + + + The index of the last point in the monotone chain. + + + + + + Computes the intersection of line segments, + and adds the intersection to the edges containing the segments. + + + + + + + + + + + + + Testing only. + + + + + + + + + + + + + + + + + + + + The proper intersection point, or null if none was found. + + + + + + + + + + A proper intersection is an intersection which is interior to at least two + line segments. Note that a proper intersection is not necessarily + in the interior of the entire Geometry, since another edge may have + an endpoint equal to the intersection, which according to SFS semantics + can result in the point being on the Boundary of the Geometry. + + Indicates a proper intersection with an interior to at least two line segments + + + + A proper interior intersection is a proper intersection which is not + contained in the set of boundary nodes set for this SegmentIntersector. + + Indicates a proper interior intersection + + + + A trivial intersection is an apparent self-intersection which in fact + is simply the point shared by adjacent line segments. + Note that closed edges require a special check for the point shared by the beginning + and end segments. + + An Edge + The segment index of + Another Edge + The segment index of + + + + This method is called by clients of the EdgeIntersector class to test for and add + intersections for two segments of the edges being intersected. + Note that clients (such as MonotoneChainEdges) may choose not to intersect + certain pairs of segments for efficiency reasons. + + + + + + + + + + + + + + + + + + + + + + + + + Finds all intersections in one or two sets of edges, + using the straightforward method of + comparing all segments. + This algorithm is too slow for production use, but is useful for testing purposes. + + + + + + + + + + + + + + + + + + + + + Performs a brute-force comparison of every segment in each Edge. + This has n^2 performance, and is about 100 times slower than using + monotone chains. + + + + + + + + Finds all intersections in one or two sets of edges, + using an x-axis sweepline algorithm in conjunction with Monotone Chains. + While still O(n^2) in the worst case, this algorithm + drastically improves the average-case time. + The use of MonotoneChains as the items in the index + seems to offer an improvement in performance over a sweep-line alone. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Because Delete Events have a link to their corresponding Insert event, + it is possible to compute exactly the range of events which must be + compared to a given Insert event object. + + + + + + + + + + + + + + + + + + + + Finds all intersections in one or two sets of edges, + using a simple x-axis sweepline algorithm. + While still O(n^2) in the worst case, this algorithm + drastically improves the average-case time. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Because DELETE events have a link to their corresponding INSERT event, + it is possible to compute exactly the range of events which must be + compared to a given INSERT event object. + + + + + + + + + + + + + + + + + + + + + + + + + Creates an INSERT event. + + The edge set label for this object. + The event location + the object being inserted + + + + Creates a DELETE event. + + The event location + The corresponding INSERT event + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Events are ordered first by their x-value, and then by their eventType. + Insert events are sorted before Delete events, so that + items whose Insert and Delete events occur at the same x-value will be + correctly handled. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A Label indicates the topological relationship of a component + of a topology graph to a given Geometry. + This class supports labels for relationships to two Geometrys, + which is sufficient for algorithms for binary operations. + Topology graphs support the concept of labeling nodes and edges in the graph. + The label of a node or edge specifies its topological relationship to one or + more geometries. (In fact, since NTS operations have only two arguments labels + are required for only two geometries). A label for a node or edge has one or + two elements, depending on whether the node or edge occurs in one or both of the + input Geometrys. Elements contain attributes which categorize the + topological location of the node or edge relative to the parent + Geometry; that is, whether the node or edge is in the interior, + boundary or exterior of the Geometry. Attributes have a value + from the set {Interior, Boundary, Exterior}. In a node each + element has a single attribute On. For an edge each element has a + triplet of attributes Left, On, Right. + It is up to the client code to associate the 0 and 1 TopologyLocations + with specific geometries. + + + + + Converts a Label to a Line label (that is, one with no side Location). + + Label to convert. + Label as Line label. + + + + Construct a Label with a single location for both Geometries. + Initialize the locations to Null. + + A location value + + + + Construct a Label with a single location for both Geometries. + Initialize the location for the Geometry index. + + A geometry index, 0, or 1. + A location value for On + + + + Construct a Label with On, Left and Right locations for both Geometries. + Initialize the locations for both Geometries to the given values. + + A location value for On + A location value for Left + A location value for Right + + + + Construct a Label with On, Left and Right locations for both Geometries. + Initialize the locations for the given Geometry index. + + A geometry index, 0, or 1. + A location value for On + A location value for Left + A location value for Right + + + + Construct a Label with the same values as the argument Label. + + A Label + + + + Performs on both + s of this Label + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Merge this label with another one. + Merging updates any null attributes of this label with the attributes from . + + The Label to merge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Converts one GeometryLocation to a Line location. + + The index of the TopologyLocation to convert (0 or 1) + + + + + + + + + + + + + + + Only non-null if this node is precise. + + + + + + + + + + + + Gets a value indicating the position of this + + The position of this Node + + + + Gets a value indicating the EdgeEndStar of this Node + + The EdgeEndStar of this Node + + + + Tests whether any incident edge is flagged as + being in the result. + This test can be used to determine if the node is in the result, + since if any incident edge is in the result, the node must be in the result as well. + + true if any incident edge in the in the result + + + + + + + + + Basic nodes do not compute IMs. + + + + + Add the edge to the list of edges at this node. + + An EdgeEnd + + + + Merges 's with this Node's Label. + + A Node + + + + To merge labels for two nodes, + the merged location for each LabelElement is computed. + The location for the corresponding node LabelElement is set to the result, + as long as the location is non-null. + + The Label to merge + + + + + + + + + + + Updates the label of a node to BOUNDARY, + obeying the mod-2 boundaryDetermination rule. + + An index for a (0 or 1) + + + + The location for a given eltIndex for a node will be one + of { Null, Interior, Boundary }. + A node may be on both the boundary and the interior of a point; + in this case, the rule is that the node is considered to be in the boundary. + The merged location is the maximum of the two input values. + + + + + + + + + + + + + + + + + + + A Factory to create s. + + + + + The basic node constructor does not allow for incident edges. + + A Coordinate + The created Node + + + + A map of nodes, indexed by the coordinate of the node. + + + + + Creates an instance of this class using the provided . + + A factory to create Nodes + + + + This method expects that a node has a coordinate value. + + A Coordinate + The Node for the provided Coordinate + + + + Adds a Node to this NodeMap. + If a Node with the same + is already present in this NodeMap, + their s are merged. + + The Node to add + Either or a Node with merged Labels + + + + Adds a node for the start point of this EdgeEnd + (if one does not already exist in this map). + Adds the EdgeEnd to the (possibly new) node. + + An EdgeEnd + + + + Searches for a Node at position. + + A Coordinate + + The node if found; null otherwise. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The computation of the IntersectionMatrix relies on the use of a structure + called a "topology graph". The topology graph contains nodes and edges + corresponding to the nodes and line segments of a Geometry. Each + node and edge in the graph is labeled with its topological location relative to + the source point. + Note that there is no requirement that points of self-intersection be a vertex. + Thus to obtain a correct topology graph, Geometrys must be + self-noded before constructing their graphs. + Two fundamental operations are supported by topology graphs: + Computing the intersections between all the edges and nodes of a single graph + Computing the intersections between the edges and nodes of two different graphs + + + + + For nodes in the Collection, link the DirectedEdges at the node that are in the result. + This allows clients to link only a subset of nodes in the graph, for + efficiency (because they know that only a subset is of interest). + + A collection of Nodes + + + + + + + + + + + + + + + + + + + Creates an instance of this class using the provided + + A factory to create Nodes + + + + Creates an instance of this class using the default . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Searches for a Node at Coordinate position + + A Coordinate position + + The node if found; null otherwise + + + + + Add a set of edges to the graph. For each edge two DirectedEdges + will be created. DirectedEdges are NOT linked by this method. + + A set of Edges to add. + + + + Link the DirectedEdges at the nodes of the graph. + This allows clients to link only a subset of nodes in the graph, for + efficiency (because they know that only a subset is of interest). + + + + + Link the DirectedEdges at the nodes of the graph. + This allows clients to link only a subset of nodes in the graph, for + efficiency (because they know that only a subset is of interest). + + + + + Returns the EdgeEnd which has edge e as its base edge + (MD 18 Feb 2002 - this should return a pair of edges). + + An Edge + The edge, if found null if the edge was not found. + + + + Returns the edge whose first two coordinates are p0 and p1. + + The 1st Coordinate + The 2nd Coordinate + The edge, if found null if the edge was not found. + + + + Returns the edge which starts at p0 and whose first segment is + parallel to p1. + + Starting Coordinate + Coordinate used to establish direction + The matching edge, if found null if the edge was not found. + + + + The coordinate pairs match if they define line segments lying in the same direction. + E.g. the segments are parallel and in the same quadrant + (as opposed to parallel and opposite!). + + + + + + + + + + + + + + + + + + + + An indicator that a Location is on a GraphComponent (0) + + + + + An indicator that a Location is to the left of a GraphComponent (1) + + + + + An indicator that a Location is to the right of a GraphComponent (2) + + + + + An indicator that a Location is is parallel to x-axis of a GraphComponent (-1) + /// + + + + A Position indicates the position of a Location relative to a graph component + (Node, Edge, or Area). + + + + + Returns Positions.Left if the position is Positions.Right, + Positions.Right if the position is Left, or the position + otherwise. + + + + + + Utility functions for working with quadrants, which are numbered as follows: + + 1 | 0 + --+-- + 2 | 3 + + + + + + North-East + + + + + North-West + + + + + South-West + + + + + South-East + + + + + Only static methods! + + + + + Returns the quadrant of a directed line segment (specified as x and y + displacements, which cannot both be 0). + + + + If the displacements are both 0 + + + + Returns the quadrant of a directed line segment from p0 to p1. + + + + if the points are equal + + + + Returns true if the quadrants are 1 and 3, or 2 and 4. + + + + + + + Returns the right-hand quadrant of the halfplane defined by the two quadrants, + or -1 if the quadrants are opposite, or the quadrant if they are identical. + + + + + + + Returns whether the given quadrant lies within the given halfplane (specified + by its right-hand quadrant). + + + + + + + Returns true if the given quadrant is 0 or 1. + + + + + + A TopologyLocation is the labelling of a + GraphComponent's topological relationship to a single Geometry. + + + If the parent component is an area edge, each side and the edge itself + have a topological location. These locations are named: + + Onon the edge + Leftleft-hand side of the edge + Rightright-hand side + + + If the parent component is a line edge or node, there is a single + topological relationship attribute, On. + + The possible values of a topological location are + { , , , } + + The labelling is stored in an array _location[j] where + where j has the values On, Left, Right. + + + + + + + + + + + + Constructs a TopologyLocation specifying how points on, to the left of, and to the + right of some GraphComponent relate to some Geometry. Possible values for the + parameters are Location.Null, Location.Exterior, Location.Boundary, + and Location.Interior. + + Location for On position + Location for Left position + Location for Right position + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Get calls Get(Positions posIndex), + Set calls SetLocation(Positions locIndex, Location locValue) + + + + + + + Get calls Get(Positions posIndex), + Set calls SetLocation(Positions locIndex, Location locValue) + + + + + + + true if all locations are Null. + + + + + true if any locations are Null. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Merge updates only the Null attributes of this object + with the attributes of another. + + + + + + + + + + + A lightweight class used to store coordinates on the 2-dimensional Cartesian plane. + + The base data object is suitable for use with coordinate sequences with + dimension = 2 and measures = 0. + + + + It is distinct from , which is a subclass of . + Unlike objects of type (which contain additional + information such as an envelope, a precision model, and spatial reference + system information), a Coordinate only contains ordinate values + and properties. + + Implementations may optionally support Z-ordinate and M-measure values + as appropriate for a . Use of + and setters or indexer are recommended. + + + + + The value used to indicate a null or missing ordinate value. + In particular, used for the value of ordinates for dimensions + greater than the defined dimension of a coordinate. + + + + + Gets or sets the X-ordinate value. + + + + + Gets or sets the Y-ordinate value. + + + + + Gets or sets the Z-ordinate value, if supported. + If no Z value is present, returns . + + + Thrown if an attempt is made to set the Z-ordinate value on an instance where + the Z-ordinate value is not supported. + + + + + Gets or sets the value of the measure, if supported. + If no measure value is present, returns . + + + Thrown if an attempt is made to set the measure value on an instance where + measures are not supported. + + + + + Constructs a Coordinate at (x,y). + + The X value + The Y value + + + + Constructs a Coordinate at (0,0). + + + + + Constructs a Coordinate having the same (x,y,z) values as + . + + Coordinate to copy. + + + + Gets or sets the value for the given ordinate. + + The ordinate. + The ordinate value + Thrown if is not one of , , , or . + + + + Gets or sets the ordinate value for the given index. + + + The base implementation supports 0 (X) and 1 (Y) as values for the index. + + The ordinate index + The ordinate value + Thrown if is not in the valid range. + + + + Gets/Sets Coordinates (x,y,z) values. + + + + Gets a value indicating if the Coordinate + has valid x- and y ordinate values + + An ordinate value is valid if it is finite. + + true if the coordinate is valid + + + + + + Predicate to check if a value is finite. + + It is finite if both and return false + + The value to test + value + + + + Returns whether the planar projections of the two Coordinates are equal. + + Coordinate with which to do the 2D comparison. + + true if the x- and y-coordinates are equal; + the Z coordinates do not have to be equal. + + + + + Tests if another Coordinate has the same values for the X and Y ordinates, + within a specified tolerance value. The Z ordinate is ignored. + + A . + The tolerance value to use. + true if the X and Y ordinates are within the given tolerance. + The Z ordinate is ignored. + + + + + + + + + + + Compares this object with the specified object for order. + Since Coordinates are 2.5D, this routine ignores the z value when making the comparison. + Returns + -1 : this.x < other.x || ((this.x == other.x) AND (this.y < other.y)) + 0 : this.x == other.x AND this.y = other.y + 1 : this.x > other.x || ((this.x == other.x) AND (this.y > other.y)) + + Coordinate with which this Coordinate is being compared. + + A negative integer, zero, or a positive integer as this Coordinate + is less than, equal to, or greater than the specified Coordinate. + + + + + Compares this object with the specified object for order. + Since Coordinates are 2.5D, this routine ignores the z value when making the comparison. + Returns + -1 : this.x < other.x || ((this.x == other.x) AND (this.y < other.y)) + 0 : this.x == other.x AND this.y = other.y + 1 : this.x > other.x || ((this.x == other.x) AND (this.y > other.y)) + + Coordinate with which this Coordinate is being compared. + + A negative integer, zero, or a positive integer as this Coordinate + is less than, equal to, or greater than the specified Coordinate. + + + + + Create a copy of this . + + A copy of this coordinate. + + + + Create a Coordinate of the same type as this Coordinate, using the provided values. + + Depending on the actual type the following limitations are in place: + + Coordinate (Sub-)ClassLimitation + Coordinate-parameter and -parameter are silently dropped. + CoordinateZ-parameter is silently dropped. + CoordinateM-parameter is silently dropped. + CoordinateZMNo parameter is dropped. + + + The x-ordinate value, if not provided, it is 0d. + The y-ordinate value, if not provided, it is 0d. + The z-ordinate value, if not provided, it is . + The m-ordinate value, if not provided, it is . + A new + + + + Computes the 2-dimensional Euclidean distance to another location. + + A with which to do the distance comparison. + the 2-dimensional Euclidean distance between the locations. + The Z-ordinate is ignored. + + + + Returns true if other has the same values for the x and y ordinates. + Since Coordinates are 2.5D, this routine ignores the z value when making the comparison. + + Coordinate with which to do the comparison. + true if other is a Coordinate with the same values for the x and y ordinates. + + + + Gets a hashcode for this coordinate. + + A hashcode for this coordinate. + + + + Returns a string of the form (x,y,z) . + + string of the form (x,y,z) + + + + Useful utility functions for handling Coordinate arrays. + + + + + Determine dimension based on subclass of . + + pts supplied coordinates + number of ordinates recorded + + + + Determine number of measures based on subclass of . + + supplied coordinates + number of measures recorded + + + + Utility method ensuring array contents are of consistent dimension and measures. + + Array is modified in place if required, coordinates are replaced in the array as required + to ensure all coordinates have the same dimension and measures. The final dimension and + measures used are the maximum found when checking the array. + + Modified in place to coordinates of consistent dimension and measures. + + + + Utility method ensuring array contents are of the specified dimension and measures. + + Array is returned unmodified if consistent, or a copy of the array is made with + each inconsistent coordinate duplicated into an instance of the correct dimension and measures. + + A coordinate array + + + Input array or copy created if required to enforce consistency. + + + + Tests whether an array of s forms a ring, by checking length and closure. + Self-intersection is not checked. + + An array of Coordinates + true if the coordinate form a ring. + + + + Finds a in a list of s + which is not contained in another list of s. + + The s to test. + An array of s to test the input points against. + + A from + which is not in , or null. + + + + + Compares two arrays + in the forward direction of their coordinates, + using lexicographic ordering. + + + + + + + + Determines which orientation of the array is (overall) increasing. + In other words, determines which end of the array is "smaller" + (using the standard ordering on ). + Returns an integer indicating the increasing direction. + If the sequence is a palindrome, it is defined to be + oriented in a positive direction. + + The array of Coordinates to test. + + 1 if the array is smaller at the start or is a palindrome, + -1 if smaller at the end. + + + + + Determines whether two arrays of equal length + are equal in opposite directions. + + + + + + + + Creates a deep copy of the argument Coordinate array. + + Array of Coordinates. + Deep copy of the input. + + + + Creates a deep copy of a given section of a source array into a destination Coordinate array. + The destination array must be an appropriate size to receive the copied coordinates. + + An array of Coordinates + The index to start copying from + The array to receive the deep-copied coordinates + The destination index to start copying to + The number of items to copy + + + + Converts the given of + s into a array. + + of coordinates. + + + + + Returns whether returns true + for any two consecutive coordinates in the given array. + + An array of Coordinates. + true if coord has repeated points; false otherwise. + + + + Returns either the given coordinate array if its length is greater than + the given amount, or an empty coordinate array. + + Length amount. + Array of Coordinates. + New Coordinate array. + + + + If the coordinate array argument has repeated points, + constructs a new array containing no repeated points. + Otherwise, returns the argument. + + An array of Coordinates + The array with repeated coordinates removed + + + + Tests whether an array has any repeated or invalid coordinates. + + An array of coordinates + true if the array contains repeated or invalid coordinates + + + + + If the coordinate array argument has repeated or invalid points, + constructs a new array containing no repeated points. + Otherwise, returns the argument. + + An array of coordinates + The array with repeated or invalid coordinates removed. + + + + + + Collapses a coordinate array to remove all null elements. + + The coordinate array to collapse + An Array containing only non-null elements + + + + Reverses the coordinates in an array in-place. + + Array of Coordinates. + + + + Returns true if the two arrays are identical, both null, or pointwise + equal (as compared using Coordinate.Equals). + + First array of Coordinates. + Second array of Coordinates. + true if two Coordinates array are equals; false otherwise + + + + Compares two arrays + in the forward direction of their coordinates, + using lexicographic ordering. + + + + + Compares the specified s arrays. + + An array of coordinates + An array of coordinates + + + + A comparator for arrays modulo their directionality. + E.g. if two coordinate arrays are identical but reversed + they will compare as equal under this ordering. + If the arrays are not equal, the ordering returned + is the ordering in the forward direction. + + + + + Compares the specified s arrays. + + An array of coordinates + An array of coordinates + + + + + + + Returns true if the two arrays are identical, both null, or pointwise + equal, using a user-defined + for s. + + An array of s. + Another array of s. + + A for s. + + + + + + Returns the minimum coordinate, using the usual lexicographic comparison. + + Array to search. + The minimum coordinate in the array, found using CompareTo. + + + + Shifts the positions of the coordinates until firstCoordinate is first. + + Array to rearrange. + Coordinate to make first. + + + + Shifts the positions of the coordinates until the coordinate + at indexOfFirstCoordinate is first. + + The array of coordinates to arrange + The index of the coordinate to make first + + + + Shifts the positions of the coordinates until the coordinate + at indexOfFirstCoordinate is first. + + + If is true, first and last + coordinate of the returned array are equal. + + The array of coordinates to arrange + The index of the coordinate to make first + A flag indicating if returned array should form a ring. + + + + Returns the index of in . + The first position is 0; the second is 1; etc. + + A to search for. + A array to search. + The position of coordinate, or -1 if it is not found. + + + + Extracts a subsequence of the input array + from indices to (inclusive). + The input indices are clamped to the array size; + If the end index is less than the start index, + the extracted array will be empty. + + The input array. + The index of the start of the subsequence to extract. + The index of the end of the subsequence to extract. + A subsequence of the input array. + + + + Computes the of the coordinates. + + the array to scan. + the of the . + + + + Extracts the coordinates which intersect an . + + The coordinates to scan + The envelope to intersect with + An array of coordinates which intersect with the envelope + + + + A class that can be used to test coordinates for equality. + + It uses the algorithm that was default for NTS prior to v2.2, + i.e. checks if the 2d distance between coordinates x + and y is less than or equal to a tolerance value. + + + + + + + + Compares s and for equality allowing for a . + + A Coordinate + A Coordinate + A tolerance value. + true if and can be considered equal; otherwise false. + + + + + + + Method to test 2 s for equality, allowing a tolerance. + + The 1st Coordinate + The 2nd Coordinate + A tolerance value + true if and can be considered equal. + + + + A class that can be used to test coordinates for equality. + + This class test for each ordinate if the distance is less + than a tolerance value. + + + + + Method to test 2 s for equality, allowing a tolerance. + + The 1st Coordinate + The 2nd Coordinate + A tolerance value + true if and can be considered equal. + + + + Computes the distance between two values + + 1st double + 2nd double + The distance between and + + + + A list of Coordinates, which may + be set to prevent repeated coordinates from occurring in the list. + + + + + Constructs a new list without any coordinates + + + + + Constructs a new list without any coordinates but an initial capacity + + The initial capacity of the list. + + + + Constructs a new list from an array of Coordinates, allowing repeated points. + (I.e. this constructor produces a with exactly the same set of points + as the input array.) + + Initial coordinates + + + + Constructs a new list from a collection of Coordinates, + allows repeated points. + + Collection of coordinates to load into the list. + + + + Constructs a new list from a collection of Coordinates, + allowing caller to specify if repeated points are to be removed. + + Collection of coordinates to load into the list. + If false, repeated points are removed. + + + + Constructs a new list from an array of Coordinates, + allowing caller to specify if repeated points are to be removed. + + Array of coordinates to load into the list. + If false, repeated points are removed. + + + + Returns the coordinate at specified index. + + Coordinate index. + Coordinate specified. + + + + Adds a section of an array of coordinates to the list. + + The coordinates + If set to false, repeated coordinates are collapsed + The index to start from + The index to add up to but not including + true (as by general collection contract) + + + + Adds an array of coordinates to the list. + + Coordinates to be inserted. + If set to false, repeated coordinates are collapsed. + If false, the array is added in reverse order. + Return true. + + + + Adds an array of coordinates to the list. + + Coordinates to be inserted. + If set to false, repeated coordinates are collapsed. + Return true. + + + + Adds a coordinate to the list. + + Coordinate to be inserted, as object. + If set to false, repeated coordinates are collapsed. + Return true. + + + + Adds a coordinate to the end of this list. + + Coordinate to be inserted. + If set to false, repeated coordinates are collapsed. + Return true if all ok. + + + + Inserts the specified coordinate at the specified position in this list. + + The position at which to insert + the coordinate to insert + if set to false, repeated coordinates are collapsed + + + + Add an array of coordinates. + + Coordinates collection to be inserted. + If set to false, repeated coordinates are collapsed. + Return true if at least one element has added (IList not empty). + + + + Ensure this coordList is a ring, by adding the start point if necessary. + + + + + Returns the Coordinates in this collection. + + Coordinates as Coordinate[] array. + + + + Creates an array containing the coordinates in this list, + oriented in the given direction (forward or reverse). + + The direction value: true for forward, false for reverse + An oriented array of coordinates + + + + Returns a deep copy of this collection. + + The copied object. + + + + A lightweight class used to store coordinates on the 2-dimensional Cartesian plane + and an additional measure () value. + + This data object is suitable for use with coordinate sequences with + dimension = 3 and measures = 1. + + + + It is distinct from , which is a subclass of . + Unlike objects of type (which contain additional + information such as an envelope, a precision model, and spatial reference + system information), a CoordinateM only contains ordinate values + and properties. + + CoordinateMs are two-dimensional points, with an additional M-ordinate. + If an M-ordinate value is not specified or not defined, + constructed coordinates have a M-ordinate of NaN + (which is also the value of ). + Apart from the basic accessor functions, NTS supports + only specific operations involving the M-ordinate. + + Implementations may optionally support Z-ordinate and M-measure values + as appropriate for a . Use of + and setters or indexer are recommended. + + + + + Gets or sets the M-ordinate value. + + + + + Constructs a CoordinateM at (x,y,z). + + The X value + The Y value + The measure value + + + + Constructs a CoordinateM at (0,0,NaN). + + + + + Constructs a CoordinateM having the same (x,y) values as + . + + Coordinate to copy. + + + + Constructs a CoordinateM at (x,y,NaN). + + X value. + Y value. + + + + Gets or sets the ordinate value for the given index. + + + The base implementation supports 0 (X), 1 (Y) and 2 (M) as values for the index. + + The ordinate index + The ordinate value + Thrown if is not in the valid range. + + + + Gets/Sets CoordinateMs (x,y,z) values. + + + + + Create a Coordinate of the same type as this Coordinate, + using the provided values for , and . + + A provided value for will be silently dropped. + The x-ordinate value, if not provided, it is 0d. + The y-ordinate value, if not provided, it is 0d. + The z-ordinate value, if not provided, it is . + The m-ordinate value, if not provided, it is . + A new + + + + Returns a string of the form (x, y, m=m). + + string of the form (x, y, m=m) + + + + Useful utility functions for handling Coordinate objects. + + + + + Factory method providing access to common Coordinate implementations. + + + created coordinate + + + + Factory method providing access to common Coordinate implementations. + + + + created coordinate + + + + Determine dimension based on subclass of . + + supplied coordinate + number of ordinates recorded + + + + Determine number of measures based on subclass of . + + supplied coordinate + number of measures recorded + + + + + + + Initializes a new instance of the class. + + The value for . + The value for . + The value for . + + Thrown when any argument is negative. + + + Thrown when and specify fewer + than two (2) spatial dimensions. + + + + + Returns the dimension (number of ordinates in each coordinate) for this sequence. + + This total includes any measures, indicated by non-zero . + + + + + + Gets the number of measures included in for each coordinate for this + sequence. + + + For a measured coordinate sequence a non-zero value is returned. + + For sequence measures is zero + For sequence measure is one + For sequence measure is zero + For sequence measure is one + Values greater than one are supported + + + + + + Gets the number of non-measure dimensions included in for each + coordinate for this sequence. + + Equivalent to Dimension - Measures. + + + + + + Gets the kind of ordinates this sequence supplies. + + + + + Gets a value indicating if is supported. + + + + + Gets a value indicating if is supported. + + + + + Gets the index of the Z ordinate (for use with or + ), or -1 if is + . + + + It's just a cache for with . + + + + + Gets the index of the M ordinate (for use with or + ), or -1 if is + . + + + It's just a cache for with . + + + + + Creates a coordinate for use in this sequence. + + + The coordinate is created supporting the same number of and + as this sequence and is suitable for use with . + + A coordinate for use with this sequence + + + + Returns (possibly a copy of) the ith Coordinate in this collection. + Whether or not the Coordinate returned is the actual underlying + Coordinate or merely a copy depends on the implementation. + Note that in the future the semantics of this method may change + to guarantee that the Coordinate returned is always a copy. Callers are + advised not to assume that they can modify a CoordinateSequence by + modifying the Coordinate returned by this method. + + + + + + + Returns a copy of the i'th coordinate in this sequence. + This method optimizes the situation where the caller is + going to make a copy anyway - if the implementation + has already created a new Coordinate object, no further copy is needed. + + The index of the coordinate to retrieve. + A copy of the i'th coordinate in the sequence + + + + Copies the i'th coordinate in the sequence to the supplied Coordinate. + At least the first two dimensions must be copied. + + The index of the coordinate to copy. + A Coordinate to receive the value. + + + + Returns ordinate X (0) of the specified coordinate. + + + The value of the X ordinate in the index'th coordinate. + + + + Returns ordinate Y (1) of the specified coordinate. + + + The value of the Y ordinate in the index'th coordinate. + + + + Returns ordinate Z of the specified coordinate if available. + + + + The value of the Z ordinate in the index'th coordinate, or + if not defined. + + + + + Returns ordinate M of the specified coordinate if available. + + + + The value of the M ordinate in the index'th coordinate, or + if not defined. + + + + + Sets ordinate X (0) of the specified coordinate to the specified value. + + + The index of the coordinate whose X value to set. + + + The value to set the coordinate's X value to. + + + + + Sets ordinate Y (1) of the specified coordinate to the specified value. + + + The index of the coordinate whose Y value to set. + + + The value to set the coordinate's Y value to. + + + + + Sets ordinate Z of the specified coordinate to the specified value if present. + + + The index of the coordinate whose Z value to set if present. + + + The value to set the coordinate's Z value to if present. + + + + + Sets ordinate M of the specified coordinate to the specified value if present. + + + The index of the coordinate whose M value to set if present. + + + The value to set the coordinate's M value to if present. + + + + + Returns the ordinate of a coordinate in this sequence. + Ordinate indices 0 and 1 are assumed to be X and Y. + + Ordinate indices greater than 1 have user-defined semantics + (for instance, they may contain other dimensions or measure + values as described by and . + + + If the sequence does not provide value for the required ordinate, the implementation must not throw an exception, it should return . + + The coordinate index in the sequence. + The ordinate index in the coordinate (in range [0, dimension-1]). + The ordinate value, or if the sequence does not provide values for "/> + + + + Returns the ordinate of a coordinate in this sequence. + + The coordinate index in the sequence. + The ordinate value to get. + The ordinate value, or if the sequence does not provide values for "/> + + + + Gets a value indicating the first Coordinate in this sequence.
+ For LineStrings e.g. this is the starting point. +
+ First Coordinate in sequence or null if empty. +
+ + + Gets a value indicating the last Coordinate in this sequence.
+ For LineStrings e.g. this is the ending point. +
+ Last Coordinate in sequence or null if empty. +
+ + + Gets a value indicating the number of coordinates in this sequence. + + + + + Sets the value for a given ordinate of a coordinate in this sequence. + + + If the sequence can't store the ordinate value, the implementation must not throw an exception, it should simply ignore the call. + + The coordinate index in the sequence. + The ordinate index in the coordinate (in range [0, dimension-1]). + The new ordinate value. + + + + Sets the value for a given ordinate of a coordinate in this sequence. + + The coordinate index in the sequence. + The ordinate value to set. + The new ordinate value. + + + + Returns (possibly copies of) the Coordinates in this collection. + Whether or not the Coordinates returned are the actual underlying + Coordinates or merely copies depends on the implementation. Note that + if this implementation does not store its data as an array of Coordinates, + this method will incur a performance penalty because the array needs to + be built from scratch. + + + + + + Expands the given Envelope to include the coordinates in the sequence. + Allows implementing classes to optimize access to coordinate values. + + The envelope to expand. + A reference to the expanded envelope. + + + + Returns a deep copy of this collection. + + A copy of the coordinate sequence containing copies of all points + + + + Returns a reversed copy of this . + + + A reversed copy of this . + + + Thrown when returned . + + + + + Retrieves the index at which this sequence stores a particular 's + values, if that ordinate is present in . + + + The value whose index to retrieve. + + + When this method returns, contains the index of the requested ordinate, if the ordinate + is present in this sequence; otherwise, -1. This parameter is passed uninitialized. + + + if this sequence contains ; otherwise, + . + + + + + Compares two s. + + + For sequences of the same dimension, the ordering is lexicographic. + Otherwise, lower dimensions are sorted before higher. + The dimensions compared can be limited; if this is done + ordinate dimensions above the limit will not be compared. + + + If different behaviour is required for comparing size, dimension, + or coordinate values, any or all methods can be overridden. + + + + + Compare two doubles, allowing for NaN values. + NaN is treated as being less than any valid number. + + A double + A double + -1, 0, or 1 depending on whether a is less than, equal to or greater than b + + + + The number of dimensions to test + + + + + Creates a comparator which will test all dimensions. + + + + + Creates a comparator which will test only the specified number of dimensions. + + The number of dimensions to test + + + + Compares two s for relative order. + + A coordinate sequence + A coordinate sequence + -1, 0, or 1 depending on whether o1 is less than, equal to, or greater than o2 + + + + Compares the same coordinate of two s + + A coordinate sequence + A coordinate sequence + The index of the coordinate to test + the number of dimensions to test + + + + Compares two s for relative order. + + A coordinate sequence + A coordinate sequence + -1, 0, or 1 depending on whether s1 is less than, equal to, or greater than s2 + + + + An object that knows how to build a particular implementation of + CoordinateSequence from an array of Coordinates. + + + + + + Initializes a new instance of the class.` + + + + + Initializes a new instance of the class. + + + The maximum set of flags that this instance will be + able to create sequences for. + + + + + Gets the Ordinate flags that sequences created by this factory can maximal cope with. + + + + + Returns a based on the given array; + whether or not the array is copied is implementation-dependent. + + A coordinates array, which may not be null nor contain null elements + A coordinate sequence. + + + + Creates a which is a copy + of the given . + This method must handle null arguments by creating an empty sequence. + + + A coordinate sequence + + + + Creates a of the specified size and dimension. + For this to be useful, the implementation must be mutable. + + + If the requested dimension is larger than the CoordinateSequence implementation + can provide, then a sequence of maximum possible dimension should be created. + An error should not be thrown. + + + the dimension of the coordinates in the sequence + (if user-specifiable, otherwise ignored) + A coordinate sequence + + + + Creates a of the specified size and dimension + with measure support. For this to be useful, the + implementation must be mutable. + + + If the requested dimension or measures are larger than the CoordinateSequence implementation + can provide, then a sequence of maximum possible dimension should be created. + An error should not be thrown. + + The number of coordinates in the sequence + The dimension of the coordinates in the sequence (if user-specifiable, + otherwise ignored) + The number of measures of the coordinates in the sequence (if user-specifiable, + otherwise ignored) + + + + Creates a of the specified size and ordinates. + For this to be useful, the implementation must be mutable. + + The number of coordinates. + + The ordinates each coordinate has. is fix, and can be set. + + A coordinate sequence. + + + + Gets the three parameters needed to create any instance + (, , and + ) such that the sequence can store all the data + from a given array of instances. + + + The array of instances that the sequence will be created from. + + + The values of the three parameters to use for creating the sequence. + + + + + Utility functions for manipulating s. + + + + + Reverses the coordinates in a sequence in-place. + + The coordinate sequence to reverse. + + + + Swaps two coordinates in a sequence. + + seq the sequence to modify + the index of a coordinate to swap + the index of a coordinate to swap + + + + Copies a section of a to another . + The sequences may have different dimensions; + in this case only the common dimensions are copied. + + The sequence to copy coordinates from + The starting index of the coordinates to copy + The sequence to which the coordinates should be copied to + The starting index of the coordinates in + The number of coordinates to copy + + + + Copies a section of a to another . + The sequences must have same dimensions. + + The sequence to copy coordinates from + The starting index of the coordinates to copy + The sequence to which the coordinates should be copied to + The starting index of the coordinates in + The number of coordinates to copy + + + + Copies a section of a to another . + The sequences must have same dimensions. + + The sequence to copy coordinates from + The starting index of the coordinates to copy + The sequence to which the coordinates should be copied to + The starting index of the coordinates in + The number of coordinates to copy + + + + Copies a section of a to another . + The sequences must have same dimensions. + + The sequence to copy coordinates from + The starting index of the coordinates to copy + The sequence to which the coordinates should be copied to + The starting index of the coordinates in + The number of coordinates to copy + + + + Copies a coordinate of a to another . + The sequences may have different dimensions; + in this case only the common dimensions are copied. + + The sequence to copy coordinate from + The index of the coordinate to copy + The sequence to which the coordinate should be copied to + The index of the coordinate in + + + + Copies a coordinate of a to another . + The sequences may have different dimensions; + in this case only the common dimensions are copied. + + The sequence to copy coordinate from + The index of the coordinate to copy + The sequence to which the coordinate should be copied to + The index of the coordinate in + The number of spatial ordinates to copy + The number of measure ordinates to copy + + + + Tests whether a forms a valid , + by checking the sequence length and closure + (whether the first and last points are identical in 2D). + Self-intersection is not checked. + + The sequence to test + True if the sequence is a ring + + + + + Ensures that a CoordinateSequence forms a valid ring, + returning a new closed sequence of the correct length if required. + If the input sequence is already a valid ring, it is returned + without modification. + If the input sequence is too short or is not closed, + it is extended with one or more copies of the start point. + + The CoordinateSequenceFactory to use to create the new sequence + The sequence to test + The original sequence, if it was a valid ring, or a new sequence which is valid. + + + + Extends a given . + + Because coordinate sequences are fix in size, extending is done by + creating a new coordinate sequence of the requested size. + + The new, trailing coordinate entries (if any) are filled with the last + coordinate of the input sequence + + The factory to use when creating the new sequence. + The sequence to extend. + The required size of the extended sequence + The extended sequence + + + + Tests whether two s are equal. + To be equal, the sequences must be the same length. + They do not need to be of the same dimension, + but the ordinate values for the smallest dimension of the two + must be equal. + Two NaN ordinates values are considered to be equal. + + a CoordinateSequence + a CoordinateSequence + true if the sequences are equal in the common dimensions + + + + Tests whether two Coordinates s are equal. + They do not need to be of the same dimension, + but the ordinate values for the common ordinates of the two + must be equal. + Two NaN ordinates values are considered to be equal. + + A CoordinateSequence + The index of the Coordinate in . + a CoordinateSequence + The index of the Coordinate in . + true if the sequences are equal in the common dimensions + + + + Tests whether two Coordinates s are equal. + They do not need to be of the same dimension, + but the ordinate values for the common ordinates of the two + must be equal. + Two NaN ordinates values are considered to be equal. + + A CoordinateSequence + The index of the Coordinate in . + a CoordinateSequence + The index of the Coordinate in . + The number of spatial ordinates to compare + The number of measure ordinates to compare + true if the sequences are equal in the common dimensions + + + + Creates a string representation of a . + The format is: + + ( ord0,ord1.. ord0,ord1,... ... ) + + + the sequence to output + the string representation of the sequence + + + + Returns the minimum coordinate, using the usual lexicographic comparison. + + The coordinate sequence to search + The minimum coordinate in the sequence, found using + + + + Returns the index of the minimum coordinate of the whole + coordinate sequence, using the usual lexicographic comparison. + + The coordinate sequence to search + The index of the minimum coordinate in the sequence, found using + + + + Returns the index of the minimum coordinate of a part of + the coordinate sequence (defined by + and ), using the usual lexicographic + comparison. + + The coordinate sequence to search + The lower search index + The upper search index + The index of the minimum coordinate in the sequence, found using + + + + Shifts the positions of the coordinates until firstCoordinate is first. + + The coordinate sequence to rearrange + The coordinate to make first"> + + + + Shifts the positions of the coordinates until the coordinate at firstCoordinateIndex + is first. + + The coordinate sequence to rearrange + The index of the coordinate to make first + + + + Shifts the positions of the coordinates until the coordinate at firstCoordinateIndex + is first. + + The coordinate sequence to rearrange + The index of the coordinate to make first + Makes sure that will be a closed ring upon exit + + + + Returns the index of coordinate in a + The first position is 0; the second, 1; etc. + + The Coordinate to search for + The coordinate sequence to search + + The position of coordinate, or -1 if it is not found + + + + + A lightweight class used to store coordinates on the 2-dimensional Cartesian plane + and an additional z-ordinate () value. + + This base data object is suitable for use with coordinate sequences with + dimension = 3 and measures = 0. + + + It is distinct from , which is a subclass of . + Unlike objects of type (which contain additional + information such as an envelope, a precision model, and spatial reference + system information), a CoordinateZ only contains ordinate values + and properties. + + CoordinateZs are two-dimensional points, with an additional Z-ordinate. + If an Z-ordinate value is not specified or not defined, + constructed coordinates have a Z-ordinate of NaN + (which is also the value of ). + + Apart from the basic accessor functions, NTS supports + only specific operations involving the Z-ordinate. + + Implementations may optionally support Z-ordinate and M-measure values + as appropriate for a . Use of + and setters or indexer are recommended. + + + + + Gets or sets the Z-ordinate value. + + + + + Constructs a CoordinateZ at (x,y,z). + + The X value + The Y value + The Z value + + + + Constructs a CoordinateZ at (0,0,NaN). + + + + + Constructs a CoordinateZ having the same (x,y) values as + . + + Coordinate to copy. + + + + Constructs a CoordinateZ at (x,y,NaN). + + X value. + Y value. + + + + Gets or sets the ordinate value for the given index. + + + The base implementation supports 0 (X), 1 (Y) and 2 (Z) as values for the index. + + The ordinate index + The ordinate value + Thrown if is not in the valid range. + + + + Gets/Sets CoordinateZs (x,y,z) values. + + + + + Create a Coordinate of the same type as this Coordinate, + using the provided values for , and . + + A provided value for will be silently dropped. + The x-ordinate value, if not provided, it is 0d. + The y-ordinate value, if not provided, it is 0d. + The z-ordinate value, if not provided, it is . + The m-ordinate value, if not provided, it is . + A new + + + + Returns true if + has the same values for X, Y and Z. + + A with which to do the 3D comparison. + + true if is a + with the same values for X, Y and Z. + + + + + Tests if another CoordinateZ has the same value for Z, within a tolerance. + + A . + The tolerance value. + true if the Z ordinates are within the given tolerance. + + + + Returns a string of the form (x, y, z) . + + string of the form (x, y, z) + + + + Computes the 3-dimensional Euclidean distance to another location. + + A with which to do the distance comparison. + the 3-dimensional Euclidean distance between the locations. + + + + A lightweight class used to store coordinates on the 2-dimensional Cartesian plane + and additional z- and m-ordinate values (, ). + + This data object is suitable for use with coordinate sequences with + dimension = 4 and measures = 1. + + + + It is distinct from , which is a subclass of . + Unlike objects of type (which contain additional + information such as an envelope, a precision model, and spatial reference + system information), a CoordinateZM only contains ordinate values + and properties. + + CoordinateZMs are two-dimensional points, with an additional Z-ordinate. + If an Z-ordinate value is not specified or not defined, + constructed coordinates have a Z-ordinate of NaN + (which is also the value of ). + + Apart from the basic accessor functions, NTS supports + only specific operations involving the Z- and/or M-ordinate. + + Implementations may optionally support Z-ordinate and M-measure values + as appropriate for a . Use of + and setters or indexer are recommended. + + + + + Gets or sets the measure-ordinate value. + + + + + Constructs a CoordinateZM at (x,y,z). + + The X value + The Y value + The Z value + The Measure value + + + + Constructs a CoordinateZM at (0,0,NaN,NaN). + + + + + Constructs a CoordinateZM having the same (x,y) values as + . + + Coordinate to copy. + + + + Constructs a CoordinateZM at (x,y,NaN). + + X value. + Y value. + + + + Gets or sets the ordinate value for the given index. + + + The base implementation supports 0 (X), 1 (Y) and 2 (Z) as values for the index. + + The ordinate index + The ordinate value + Thrown if is not in the valid range. + + + + Gets/Sets CoordinateZMs (x,y,z) values. + + + + + Create a Coordinate of the same type as this Coordinate, + using the provided values for , , and . + + The x-ordinate value, if not provided, it is 0d. + The y-ordinate value, if not provided, it is 0d. + The z-ordinate value, if not provided, it is . + The m-ordinate value, if not provided, it is . + A new + + + + Returns a string of the form (x, y, z, m=m) . + + string of the form (x, y, z, m=m) + + + + Provides constants representing the dimensions of a point, a curve and a surface. + + + Also provides constants representing the dimensions of the empty geometry and + non-empty geometries, and the wildcard constant meaning "any dimension". + These constants are used as the entries in s. + + + + + Dimension value of a point (0). + + + + + Dimension value of a point (0). + + + + + Dimension value of a curve (1). + + + + + Dimension value of a curve (1). + + + + + Dimension value of a surface (2). + + + + + Dimension value of a surface (2). + + + + + Dimension value of a empty point (-1). + + + + + Dimension value of non-empty geometries (= {Point,Curve,Surface}). + + + + + Dimension value for any dimension (= {False, True}). + + + + + Dimension value for a unknown spatial object + + + + + Dimension value for a collapsed surface or curve + + + + + Class containing static methods for conversions + between dimension values and characters. + + + + + Symbol for the FALSE pattern matrix entry + + + + + Symbol for the TRUE pattern matrix entry + + + + + Symbol for the DONTCARE pattern matrix entry + + + + + Symbol for the P (dimension 0) pattern matrix entry + + + + + Symbol for the L (dimension 1) pattern matrix entry + + + + + Symbol for the A (dimension 2) pattern matrix entry + + + + + Converts the dimension value to a dimension symbol, + for example, True => 'T' + + Number that can be stored in the IntersectionMatrix. + Possible values are True, False, Dontcare, 0, 1, 2. + Character for use in the string representation of an IntersectionMatrix. + Possible values are T, F, * , 0, 1, 2. + + + + Converts the dimension symbol to a dimension value, + for example, '*' => Dontcare + + Character for use in the string representation of an IntersectionMatrix. + Possible values are T, F, * , 0, 1, 2. + Number that can be stored in the IntersectionMatrix. + Possible values are True, False, Dontcare, 0, 1, 2. + + + + Defines a rectangular region of the 2D coordinate plane. + + + It is often used to represent the bounding box of a Geometry, + e.g. the minimum and maximum x and y values of the Coordinates. + Note that Envelopes support infinite or half-infinite regions, by using the values of + Double.PositiveInfinity and Double.NegativeInfinity. + When Envelope objects are created or initialized, + the supplied extent values are automatically sorted into the correct order. + + + + + Test the point q to see whether it intersects the Envelope + defined by p1-p2. + + One extremal point of the envelope. + Another extremal point of the envelope. + Point to test for intersection. + true if q intersects the envelope p1-p2. + + + + Tests whether the envelope defined by p1-p2 + and the envelope defined by q1-q2 + intersect. + + One extremal point of the envelope Point. + Another extremal point of the envelope Point. + One extremal point of the envelope Q. + Another extremal point of the envelope Q. + true if Q intersects Point + + + + The minimum x-coordinate + + + + + The maximum x-coordinate + + + + + The minimum y-coordinate + + + + + The maximum y-coordinate + + + + + Creates a null Envelope. + + + + + Creates an Envelope for a region defined by maximum and minimum values. + + The first x-value. + The second x-value. + The first y-value. + The second y-value. + + + + Creates an Envelope for a region defined by two Coordinates. + + The first Coordinate. + The second Coordinate. + + + + Creates an Envelope for a region defined by a single Coordinate. + + The Coordinate. + + + + Creates an Envelope for a region defined by an enumeration of Coordinates. + + The Coordinates. + + + + Creates an Envelope for a region defined by a CoordinateSequences. + + The CoordinateSequence. + + + + Create an Envelope from an existing Envelope. + + The Envelope to initialize from. + + + + Initialize to a null Envelope. + + + + + Initialize an Envelope for a region defined by maximum and minimum values. + + The first x-value. + The second x-value. + The first y-value. + The second y-value. + + + + Initialize an Envelope for a region defined by two Coordinates. + + The first Coordinate. + The second Coordinate. + + + + Initialize an Envelope for a region defined by a single Coordinate. + + The Coordinate. + + + + Initialize an Envelope from an existing Envelope. + + The Envelope to initialize from. + + + + Makes this Envelope a "null" envelope.. + + + + + Returns true if this Envelope is a "null" envelope. + + + true if this Envelope is uninitialized + or is the envelope of the empty point. + + + + + Returns the difference between the maximum and minimum x values. + + max x - min x, or 0 if this is a null Envelope. + + + + Returns the difference between the maximum and minimum y values. + + max y - min y, or 0 if this is a null Envelope. + + + + Gets the length of the diameter (diagonal) of the envelope. + + The diameter length + + + + Returns the Envelopes minimum x-value. min x > max x + indicates that this is a null Envelope. + + The minimum x-coordinate. + + + + Returns the Envelopes maximum x-value. min x > max x + indicates that this is a null Envelope. + + The maximum x-coordinate. + + + + Returns the Envelopes minimum y-value. min y > max y + indicates that this is a null Envelope. + + The minimum y-coordinate. + + + + Returns the Envelopes maximum y-value. min y > max y + indicates that this is a null Envelope. + + The maximum y-coordinate. + + + + Gets the area of this envelope. + + The area of the envelope, or 0.0 if envelope is null + + + + Expands this envelope by a given distance in all directions. + Both positive and negative distances are supported. + + The distance to expand the envelope. + + + + Expands this envelope by a given distance in all directions. + Both positive and negative distances are supported. + + The distance to expand the envelope along the the X axis. + The distance to expand the envelope along the the Y axis. + + + + Gets the minimum extent of this envelope across both dimensions. + + + + + + Gets the maximum extent of this envelope across both dimensions. + + + + + + Enlarges this Envelope so that it contains + the given . + Has no effect if the point is already on or within the envelope. + + The Coordinate. + + + + Enlarges this Envelope so that it contains + the given . + + Has no effect if the point is already on or within the envelope. + The value to lower the minimum x to or to raise the maximum x to. + The value to lower the minimum y to or to raise the maximum y to. + + + + Enlarges this Envelope so that it contains + the other Envelope. + Has no effect if other is wholly on or + within the envelope. + + the Envelope to expand to include. + + + + Enlarges this Envelope so that it contains + the other Envelope. + Has no effect if other is wholly on or + within the envelope. + + the Envelope to expand to include. + + + + Translates this envelope by given amounts in the X and Y direction. + + The amount to translate along the X axis. + The amount to translate along the Y axis. + + + + Computes the coordinate of the centre of this envelope (as long as it is non-null). + + + The centre coordinate of this envelope, + or null if the envelope is null. + . + + + + Computes the intersection of two s. + + The envelope to intersect with + + A new Envelope representing the intersection of the envelopes (this will be + the null envelope if either argument is null, or they do not intersect + + + + + Check if the region defined by other + intersects the region of this Envelope. + + The Envelope which this Envelope is + being checked for intersecting. + + + true if the Envelopes intersect. + + + + + Check if the point p overlaps (lies inside) the region of this Envelope. + + the Coordinate to be tested. + true if the point overlaps this Envelope. + + + + Check if the point (x, y) overlaps (lies inside) the region of this Envelope. + + the x-ordinate of the point. + the y-ordinate of the point. + true if the point overlaps this Envelope. + + + + Tests if the extent defined by two extremal points + intersects the extent of this Envelope. + + A point + Another point + true if the extents intersect + + + + Tests if the region defined by other + is disjoint from the region of this Envelope. + + The Envelope being checked for disjointness + true if the Envelopes are disjoint + + + + + Tests if the Envelope other lies wholely inside this Envelope (inclusive of the boundary). + + + Note that this is not the same definition as the SFS contains, + which would exclude the envelope boundary. + + The Envelope to check + true if other is contained in this Envelope + + + + + Tests if the given point lies in or on the envelope. + + + Note that this is not the same definition as the SFS contains, + which would exclude the envelope boundary. + + the point which this Envelope is being checked for containing + true if the point lies in the interior or on the boundary of this Envelope. + + + + + Tests if the given point lies in or on the envelope. + + + Note that this is not the same definition as the SFS contains, which would exclude the envelope boundary. + + the x-coordinate of the point which this Envelope is being checked for containing + the y-coordinate of the point which this Envelope is being checked for containing + + true if (x, y) lies in the interior or on the boundary of this Envelope. + + + + + + Tests if the given point lies in or on the envelope. + + the x-coordinate of the point which this Envelope is being checked for containing + the y-coordinate of the point which this Envelope is being checked for containing + true if (x, y) lies in the interior or on the boundary of this Envelope. + + + + Tests if the given point lies in or on the envelope. + + the point which this Envelope is being checked for containing + true if the point lies in the interior or on the boundary of this Envelope. + + + + Tests if the Envelope other lies wholely inside this Envelope (inclusive of the boundary). + + the Envelope to check + true if this Envelope covers the other + + + + Computes the distance between this and another + Envelope. + The distance between overlapping Envelopes is 0. Otherwise, the + distance is the Euclidean distance between the closest points. + + The distance between this and another Envelope. + + + + + + + + + + Compares two envelopes using lexicographic ordering. + The ordering comparison is based on the usual numerical + comparison between the sequence of ordinates. + Null envelopes are less than all non-null envelopes. + + An envelope + + + + Compares two envelopes using lexicographic ordering. + The ordering comparison is based on the usual numerical + comparison between the sequence of ordinates. + Null envelopes are less than all non-null envelopes. + + An envelope + + + + + + + Function to get a textual representation of this envelope + + A textual representation of this envelope + + + + Creates a deep copy of the current envelope. + + + + + + Method to parse an envelope from its value + + The envelope string + The envelope + + + + A representation of a planar, linear vector geometry. + + + +

Binary Predicates:

+ Because it is not clear at this time what semantics for spatial + analysis methods involving GeometryCollections would be useful, + GeometryCollections are not supported as arguments to binary + predicates or the Relate method. +
+ +

Overlay Methods:

+ The spatial analysis methods will + return the most specific class possible to represent the result. If the + result is homogeneous, a Point, LineString, or + Polygon will be returned if the result contains a single + element; otherwise, a MultiPoint, MultiLineString, + or MultiPolygon will be returned. If the result is + heterogeneous a GeometryCollection will be returned. +
+ + Representation of Computed Geometries: + The SFS states that the result + of a set-theoretic method is the "point-set" result of the usual + set-theoretic definition of the operation (SFS 3.2.21.1). However, there are + sometimes many ways of representing a point set as a Geometry. + The SFS does not specify an unambiguous representation of a given point set + returned from a spatial analysis method. One goal of NTS is to make this + specification precise and unambiguous. NTS uses a canonical form for + Geometrys returned from overlay methods. The canonical + form is a Geometry which is simple and noded: + Simple means that the Geometry returned will be simple according to + the NTS definition of IsSimple. + Noded applies only to overlays involving LineStrings. It + means that all intersection points on LineStrings will be + present as endpoints of LineStrings in the result. + This definition implies that non-simple geometries which are arguments to + spatial analysis methods must be subjected to a line-dissolve process to + ensure that the results are simple. + + + Constructed Points And The Precision Model: + The results computed by the set-theoretic methods may + contain constructed points which are not present in the input Geometrys. + These new points arise from intersections between line segments in the + edges of the input Geometrys. In the general case it is not + possible to represent constructed points exactly. This is due to the fact + that the coordinates of an intersection point may contain twice as many bits + of precision as the coordinates of the input line segments. In order to + represent these constructed points explicitly, NTS must truncate them to fit + the PrecisionModel. + Unfortunately, truncating coordinates moves them slightly. Line segments + which would not be coincident in the exact result may become coincident in + the truncated representation. This in turn leads to "topology collapses" -- + situations where a computed element has a lower dimension than it would in + the exact result. + When NTS detects topology collapses during the computation of spatial + analysis methods, it will throw an exception. If possible the exception will + report the location of the collapse. + + + +

Geometry Equality

+ There are two ways of comparing geometries for equality: + structural equality and topological equality. +

Structural Equality

+ Structural Equality is provided by the + method. + This implements a comparison based on exact, structural pointwise + equality. + The is a synonym for this method, + to provide structural equality semantics for + use in collections. + It is important to note that structural pointwise equality + is easily affected by things like + ring order and component order. In many situations + it will be desirable to normalize geometries before + comparing them (using the + or methods). + is provided + as a convenience method to compute equality over + normalized geometries, but it is expensive to use. + Finally, + allows using a tolerance value for point comparison. + +

Topological Equality

+ Topological Equality is provided by the + method. + It implements the SFS definition of point-set equality + defined in terms of the DE-9IM matrix. + To support the SFS naming convention, the method + is also provided as a synonym. + However, due to the potential for confusion with + its use is discouraged. +
+ + Since and are overridden, + Geometries can be used effectively in .Net collections. + +
+
+ + + An enumeration of sort values for geometries + + + NOTE:
+ For JTS v1.17 the values in this enum have been renamed to 'TYPECODE...' + In order not to break binary compatibility we did not follow. +
+
+ + Sort hierarchy value of a + + + Sort hierarchy value of a + + + Sort hierarchy value of a + + + Sort hierarchy value of a + + + Sort hierarchy value of a + + + Sort hierarchy value of a + + + Sort hierarchy value of a + + + Sort hierarchy value of a + + + + The name of point geometries + + + + + The name of multi-point geometries + + + + + The name of linestring geometries + + + + + The name of linearring geometries + + + + + The name of multi-linestring geometries + + + + + The name of polygon geometries + + + + + The name of multi-polygon geometries + + + + + The name of geometry collection geometries. + + + + + Gets the factory which contains the context in which this point was created. + + The factory for this point. + + + + Gets/Sets the user data object for this point, if any. + + + A simple scheme for applications to add their own custom data to a Geometry. + An example use might be to add an object representing a Coordinate Reference System. + Note that user data objects are not present in geometries created by + construction methods. + + + + + The bounding box of this Geometry. + + + + + Sets the ID of the Spatial Reference System used by the Geometry. + + + + NOTE: This method should only be used for exceptional circumstances or + for backwards compatibility. Normally the SRID should be set on the + used to create the geometry. + SRIDs set using this method will change the . + + + + + + + Creates a new Geometry via the specified GeometryFactory. + + The factory + + + + Returns the name of this Geometry's actual class. + + The name of this Geometrys actual class. + + + + Gets the OGC geometry type + + + + + Returns true if the array contains any non-empty Geometrys. + + an array of Geometrys; no elements may be null + + true if any of the Geometrys + IsEmpty methods return false. + + + + + Returns true if the array contains any null elements. + + an array to validate. + true if any of arrays elements are null. + + + + Returns true if the array contains any null elements. + + an array to validate. + true if any of arrays elements are null. + + + + Returns the PrecisionModel used by the Geometry. + + + the specification of the grid of allowable points, for this + Geometry and all other Geometrys. + + + + + Returns a vertex of this Geometry + (usually, but not necessarily, the first one). + + + The returned coordinate should not be assumed to be an actual Coordinate object used in the internal representation. + + a Coordinate which is a vertex of this Geometry. + null if this Geometry is empty. + + + + + Returns an array containing the values of all the vertices for + this geometry. + + + If the geometry is a composite, the array will contain all the vertices + for the components, in the order in which the components occur in the geometry. + + In general, the array cannot be assumed to be the actual internal + storage for the vertices. Thus modifying the array + may not modify the geometry itself. + Use the or + method + (possibly on the components) to modify the underlying data. + If the coordinates are modified, + must be called afterwards. + + + The vertices of this Geometry. + + + + + + + Gets an array of ordinate values + + The ordinate index + An array of ordinate values + + + + Returns the count of this Geometrys vertices. The Geometry + s contained by composite Geometrys must be + Geometry's; that is, they must implement NumPoints. + + The number of vertices in this Geometry. + + + + Returns the number of Geometryes in a GeometryCollection, + or 1, if the geometry is not a collection. + + + + + Returns an element Geometry from a GeometryCollection, + or this, if the geometry is not a collection. + + The index of the geometry element. + The n'th geometry contained in this geometry. + + + + Tests whether this is simple. + + The SFS definition of simplicity + follows the general rule that a Geometry is simple if it has no points of + self-tangency, self-intersection or other anomalous points. + + Simplicity is defined for each subclass as follows: + + Valid polygonal geometries are simple, since their rings + must not self-intersect. IsSimple + tests for this condition and reports false if it is not met. + (This is a looser test than checking for validity). + Linear rings have the same semantics. + Linear geometries are simple if they do not self-intersect at points + other than boundary points. + Zero-dimensional geometries (points) are simple if they have no + repeated points. + Empty Geometrys are always simple. + + + true if this Geometry is simple + + + + + Tests whether this Geometry is topologically + valid, according to the OGC SFS specification. + For validity rules see the documentation for the specific geometry subclass. + + true if this Geometry is valid. + + + + Tests whether the set of points covered in this Geometry is empty. + + Note this test is for topological emptiness, not structural emptiness.
+ A collection containing only empty elements is reported as empty.
+ To check structural emptiness use . +
+ true if this Geometry does not cover any points. +
+ + + Returns the minimum distance between this Geometry + and another Geometry g. + + The Geometry from which to compute the distance. + The distance between the geometries + 0 if either input geometry is empty + if g is null + + + + Tests whether the distance from this Geometry + to another is less than or equal to a specified value. + + the Geometry to check the distance to. + the distance value to compare. + true if the geometries are less than distance apart. + + + + Returns the area of this Geometry. + Areal Geometries have a non-zero area. + They override this function to compute the area. + Others return 0.0 + + The area of the Geometry. + + + + Returns the length of this Geometry. + Linear geometries return their length. + Areal geometries return their perimeter. + They override this function to compute the length. + Others return 0.0 + + The length of the Geometry. + + + + Computes the centroid of this Geometry. + The centroid + is equal to the centroid of the set of component Geometries of highest + dimension (since the lower-dimension geometries contribute zero + "weight" to the centroid). + + The centroid of an empty geometry is POINT EMPTY. + + A Point which is the centroid of this Geometry. + + + + Computes an interior point of this Geometry. + + + An interior point is guaranteed to lie in the interior of the Geometry, + if it possible to calculate such a point exactly. Otherwise, + the point may lie on the boundary of the point. + + The interior point of an empty geometry is POINT EMPTY. + + A Point which is in the interior of this Geometry. + + + + + + + + + Returns the dimension of this geometry. + + + The dimension of a geometry is is the topological + dimension of its embedding in the 2-D Euclidean plane. + In the NTS spatial model, dimension values are in the set {0,1,2}. + + Note that this is a different concept to the dimension of + the vertex s. + The geometry dimension can never be greater than the coordinate dimension. + For example, a 0-dimensional geometry (e.g. a Point) + may have a coordinate dimension of 3 (X,Y,Z). + + + + The topological dimensions of this geometry + + + + + Returns the boundary, or an empty geometry of appropriate dimension + if this Geometry is empty. + For a discussion of this function, see the OpenGIS Simple + Features Specification. As stated in SFS Section 2.1.13.1, "the boundary + of a Geometry is a set of Geometries of the next lower dimension." + + The closure of the combinatorial boundary of this Geometry. + + + + Returns the dimension of this Geometrys inherent boundary. + + + The dimension of the boundary of the class implementing this + interface, whether or not this object is the empty point. Returns + Dimension.False if the boundary is the empty point. + + + + + Gets a geometry representing the envelope (bounding box) of this Geometry. + + If this Geometry is + + empty, returns an empty Point + a point, returns a Point + a line parallel to an axis, a two-vertex LineString, + otherwise, returns a + Polygon whose vertices are (minx, miny), (maxx, miny), + (maxx, maxy), (minx, maxy), (minx, miny). + + + + A Geometry representing the envelope of this Geometry + + + + + + Gets an containing + the minimum and maximum x and y values in this Geometry. + If the geometry is empty, an empty Envelope + is returned. + + + The returned object is a copy of the one maintained internally, + to avoid aliasing issues. + For best performance, clients which access this + envelope frequently should cache the return value. + the envelope of this Geometry. + An empty Envelope if this Geometry is empty + + + + Notifies this geometry that its coordinates have been changed by an external + party (for example, via a ). + + + When this method is called the geometry will flush + and/or update any derived information it has cached (such as its ). + The operation is applied to all component Geometries. + + + + + Notifies this Geometry that its Coordinates have been changed by an external + party. When GeometryChanged is called, this method will be called for + this Geometry and its component Geometries. + + + + + Tests whether this geometry is disjoint from the argument geometry. + + + The Disjoint predicate has the following equivalent definitions: + + The DE-9IM intersection matrix for the two geometries matches FF*FF****. + !g.intersects(this) == true
(Disjoint is the inverse of Intersects)
+
+
+ The Geometry with which to compare this Geometry. + true if the two Geometrys are disjoint. + +
+ + + Tests whether this geometry touches the argument geometry + + + The Touches predicate has the following equivalent definitions: + + The geometries have at least one point in common, + but their interiors do not intersect + The DE-9IM Intersection Matrix for the two geometries matches + at least one of the following patterns + + FT*******, + F**T***** or + F***T****. + + + If both geometries have dimension 0, the predicate returns false, + since points have only interiors. + This predicate is symmetric. + + The Geometry with which to compare this Geometry. + + true if the two Geometrys touch; + Returns false if both Geometrys are points. + + + + + Tests whether this geometry intersects the argument geometry. + + + The Intersects predicate has the following equivalent definitions: + + The two geometries have at least one point in common + The DE-9IM Intersection Matrix for the two geometries matches
+ [T********] or
+ [*T*******] or
+ [***T*****] or
+ [****T****]
+ !g.disjoint(this)
+ (Intersects is the inverse of Disjoint)
+
+ The Geometry with which to compare this Geometry. + true if the two Geometrys intersect. + +
+ + + Tests whether this geometry crosses the specified geometry. + + + The Crosses predicate has the following equivalent definitions: + + The geometries have some but not all interior points in common. + The DE-9IM Intersection Matrix for the two geometries matches + one of the following patterns: + + CodeDescription + [T*T******]for P/L, P/A, and L/A situations + [T*****T**]for L/P, A/P, and A/L situations) + [0********]for L/L situations + + + + For the A/A and P/P situations this predicate returns false. + + The SFS defined this predicate only for P/L, P/A, L/L, and L/A situations. + To make the relation symmetric, + NTS extends the definition to apply to L/P, A/P and A/L situations as well. + + + The Geometry with which to compare this Geometry + true if the two Geometrys cross. + + + + Tests whether this geometry is within the specified geometry. + + + The within predicate has the following equivalent definitions: + + + Every point of this geometry is a point of the other geometry, + and the interiors of the two geometries have at least one point in common. + + The DE-9IM Intersection Matrix for the two geometries matches [T*F**F***] + g.contains(this) == true
(Within is the converse of )
+
+ + An implication of the definition is that "The boundary of a geometry is not within the Polygon". + In other words, if a geometry A is a subset of the points in the boundary of a geometry B, A.within(B) == false + (As a concrete example, take A to be a LineString which lies in the boundary of a Polygon B.) + For a predicate with similar behaviour but avoiding + this subtle limitation, see . + +
+ The Geometry with which to compare this Geometry. + true if this Geometry is within other. + + +
+ + + Tests whether this geometry contains the argument geometry. + + + The Contains predicate has the following equivalent definitions: + + Every point of the other geometry is a point of this geometry, + and the interiors of the two geometries have at least one point in common. + The DE-9IM Intersection Matrix for the two geometries matches the pattern + [T*****FF*] + g.within(this)
+ (Contains is the converse of )
+
+ + An implication of the definition is that "Geometries do not + contain their boundary". In other words, if a geometry A is a subset of + the points in the boundary of a geometry B, B.Contains(A) == false. + (As a concrete example, take A to be a LineString which lies in the boundary of a Polygon B.) + For a predicate with similar behaviour but avoiding + this subtle limitation, see . + +
+ the Geometry with which to compare this Geometry + true if this Geometry contains g + + +
+ + + Tests whether this geometry overlaps the specified geometry. + + + The Overlaps predicate has the following equivalent definitions: + + The geometries have at least one point each not shared by the other (or equivalently neither covers the other), + they have the same dimension, + and the intersection of the interiors of the two geometries has + the same dimension as the geometries themselves. + The DE-9IM Intersection Matrix for the two geometries matches + [T*T***T**] (for two points or two surfaces) + or [1*T***T**] (for two curves) + + If the geometries are of different dimension this predicate returns false. + + The Geometry with which to compare this Geometry. + + true if the two Geometrys overlap. + For this function to return true, the Geometry + s must be two points, two curves or two surfaces. + + + + + Tests whether this geometry covers the argument geometry + + + The covers predicate has the following equivalent definitions: + + Every point of the other geometry is a point of this geometry. + The DE-9IM Intersection Matrix for the two geometries matches at least + one of the following patterns: + + [T*****FF*] or
+ [*T****FF*] or
+ [***T**FF*] or
+ [****T*FF*] +
+
+ g.CoveredBy(this) == true
+ (covers is the converse of )
+
+ If either geometry is empty, the value of this predicate is false. + + This predicate is similar to , + but is more inclusive (i.e. returns true for more cases). + In particular, unlike Contains it does not distinguish between + points in the boundary and in the interior of geometries. + For most situations, Covers should be used in preference to Contains. + As an added benefit, Covers is more amenable to optimization, + and hence should be more performant. + +
+ The Geometry with which to compare this Geometry + true if this Geometry covers + + +
+ + Tests whether this geometry is covered by the specified geometry. + + The CoveredBy predicate has the following equivalent definitions: + + Every point of this geometry is a point of the other geometry. + The DE-9IM Intersection Matrix for the two geometries matches + at least one of the following patterns: + + [T*F**F***] + [*TF**F***] + [**FT*F***] + [**F*TF***] + g.Covers(this) == true
+ (CoveredBy is the converse of ) +
+
+ If either geometry is empty, the value of this predicate is false. + + This predicate is similar to , + but is more inclusive (i.e. returns true for more cases). + +
+ the Geometry with which to compare this Geometry + true if this Geometry is covered by g + + +
+ + + Tests whether the elements in the DE-9IM + for the two Geometrys match the elements in intersectionPattern. + + + The pattern is a 9-character string, with symbols drawn from the following set: + + 0(dimension 0) + 1(dimension 1) + 2(dimension 2) + T( matches 0, 1 or 2) + F( matches FALSE) + *( matches any value) + + For more information on the DE-9IM, see the OpenGIS Simple Features + Specification. + + the Geometry with which to compare this Geometry + the pattern against which to check the + intersection matrix for the two Geometrys + true if the DE-9IM intersection + matrix for the two Geometrys match intersectionPattern + + + + + Returns the DE-9IM intersection matrix for the two Geometrys. + + The Geometry with which to compare this Geometry + + A matrix describing the intersections of the interiors, + boundaries and exteriors of the two Geometrys. + + + + + Tests whether this geometry is + topologically equal to the argument geometry. + + This method is included for backward compatibility reasons. + It has been superseded by the method, + which has been named to clearly denote its functionality. + + This method should NOT be confused with the method + , which implements + an exact equality comparison. + + The Geometry with which to compare this Geometry + true if the two Geometrys are topologically equal. + + + + + Tests whether this geometry is topologically equal to the argument geometry + as defined by the SFS Equals predicate. + + + The SFS equals predicate has the following equivalent definitions: + + The two geometries have at least one point in common, + and no point of either geometry lies in the exterior of the other geometry. + The DE-9IM Intersection Matrix for the two geometries matches + the pattern T*F**FFF* +
+            T*F
+            **F
+            FF*
+            
+
+ Note that this method computes topologically equality. + For structural equality, see {@link #equalsExact(Geometry)}. +
+ the Geometry with which to compare this Geometry + true if the two Geometrys are topologically equal +
+ + + Tests whether this geometry is structurally and numerically equal + to a given Object. + + + If the argument Object is not a Geometry, + the result is false. + Otherwise, the result is computed using + . + + This method is provided to fulfill the Java contract + for value-based object equality. + In conjunction with + it provides semantics which are most useful + for using + Geometrys as keys and values in Java collections. + + Note that to produce the expected result the input geometries + should be in normal form. It is the caller's + responsibility to perform this where required + (using + or as appropriate). + + The object to compare + true if this geometry is exactly equal to the argument + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gets a hash code for the Geometry. + + + An integer value suitable for use as a hashcode + + + + + Returns the Well-known Text representation of this Geometry. + For a definition of the Well-known Text format, see the OpenGIS Simple + Features Specification. + + + The Well-known Text representation of this Geometry. + + + + + Returns the Well-known Text representation of this Geometry. + For a definition of the Well-known Text format, see the OpenGIS Simple + Features Specification. + + + The Well-known Text representation of this Geometry. + + + + + + + + + + + Returns the Well-known Binary representation of this Geometry. + For a definition of the Well-known Binary format, see the OpenGIS Simple + Features Specification. + + The Well-known Binary representation of this Geometry. + + + + + + + + + + Returns the feature representation as GML 2.1.1 XML document. + This XML document is based on Geometry.xsd schema. + NO features or XLink are implemented here! + + + + + Computes a buffer area around this geometry having the given width. The + buffer of a Geometry is the Minkowski sum or difference of the geometry + with a disc of radius Abs(distance). + + Mathematically-exact buffer area boundaries can contain circular arcs. + To represent these arcs using linear geometry they must be approximated with line segments. + The buffer geometry is constructed using 8 segments per quadrant to approximate + the circular arcs. + The end cap style is EndCapStyle.Round. + + The buffer operation always returns a polygonal result. The negative or + zero-distance buffer of lines and points is always an empty . + This is also the result for the buffers of degenerate (zero-area) polygons. + + + + The width of the buffer (may be positive, negative or 0), interpreted according to the + PrecisionModel of the Geometry. + + + a polygonal geometry representing the buffer region (which may be empty) + + If a robustness error occurs + + + + + + + + Computes a buffer region around this Geometry having the given width. + The buffer of a Geometry is the Minkowski sum or difference of the geometry + with a disc of radius Abs(distance). + + + The end cap style specifies the buffer geometry that will be + created at the ends of linestrings. The styles provided are: +
    +
  • - (default) a semi-circle
  • +
  • - a straight line perpendicular to the end segment
  • +
  • - a half-square
  • +
+ The buffer operation always returns a polygonal result. The negative or + zero-distance buffer of lines and points is always an empty . +
+ + The width of the buffer, interpreted according to the + PrecisionModel of the Geometry. + + Cap Style to use for compute buffer. + + a polygonal geometry representing the buffer region (which may be empty) + + If a robustness error occurs + + + + +
+ + + Computes a buffer region around this Geometry having the given + width and with a specified accuracy of approximation for circular arcs. + The buffer of a Geometry is the Minkowski sum of the Geometry with + a disc of radius distance. Curves in the buffer polygon are + approximated with line segments. This method allows specifying the + accuracy of that approximation. + + Mathematically-exact buffer area boundaries can contain circular arcs. + To represent these arcs using linear geometry they must be approximated with line segments. + The quadrantSegments argument allows controlling the accuracy of + the approximation by specifying the number of line segments used to + represent a quadrant of a circle + The buffer operation always returns a polygonal result. The negative or + zero-distance buffer of lines and points is always an empty . + This is also the result for the buffers of degenerate (zero-area) polygons. + + + + The width of the buffer (may be positive, negative or 0), interpreted according to the + PrecisionModel of the Geometry. + + The number of segments to use to approximate a quadrant of a circle. + + a polygonal geometry representing the buffer region (which may be empty) + + If a robustness error occurs + + + + + + + + Computes a buffer region around this Geometry having the given + width and with a specified number of segments used to approximate curves. + The buffer of a Geometry is the Minkowski sum of the Geometry with + a disc of radius distance. Curves in the buffer polygon are + approximated with line segments. This method allows specifying the + accuracy of that approximation. + + Mathematically-exact buffer area boundaries can contain circular arcs. + To represent these arcs using linear geometry they must be approximated with line segments. + The quadrantSegments argument allows controlling the accuracy of + the approximation by specifying the number of line segments used to + represent a quadrant of a circle + The end cap style specifies the buffer geometry that will be + created at the ends of linestrings. The styles provided are: +
    +
  • - (default) a semi-circle
  • +
  • - a straight line perpendicular to the end segment
  • +
  • - a half-square
  • +
+ The buffer operation always returns a polygonal result. The negative or + zero-distance buffer of lines and points is always an empty . + This is also the result for the buffers of degenerate (zero-area) polygons. + +
+ + The width of the buffer, interpreted according to the + PrecisionModel of the Geometry. + + The number of segments to use to approximate a quadrant of a circle. + Cap Style to use for compute buffer. + + a polygonal geometry representing the buffer region (which may be empty) + + If a robustness error occurs + + + + +
+ + + Computes a buffer region around this Geometry having the given + width and with a specified number of segments used to approximate curves. + The buffer of a Geometry is the Minkowski sum of the Geometry with + a disc of radius distance. Curves in the buffer polygon are + approximated with line segments. This method allows specifying the + accuracy of that approximation. + + Mathematically-exact buffer area boundaries can contain circular arcs. + To represent these arcs using linear geometry they must be approximated with line segments. + The bufferParameters argument has a property QuadrantSegments controlling the accuracy of + the approximation by specifying the number of line segments used to + represent a quadrant of a circle + The EndCapStyle property of the bufferParameters argument specifies the buffer geometry that will be + created at the ends of linestrings. The styles provided are: +
    +
  • - (default) a semi-circle
  • +
  • - a straight line perpendicular to the end segment
  • +
  • - a half-square
  • +
+ The buffer operation always returns a polygonal result. The negative or + zero-distance buffer of lines and points is always an empty . + This is also the result for the buffers of degenerate (zero-area) polygons. + +
+ + The width of the buffer, interpreted according to the + PrecisionModel of the Geometry. + + This argument type has a number of properties that control the construction of the + buffer, including QuadrantSegments, EndCapStyle, JoinStyle, and MitreLimit + + a polygonal geometry representing the buffer region (which may be empty) + + If a robustness error occurs + + + + +
+ + + Returns the smallest convex Polygon that contains all the + points in the Geometry. This obviously applies only to Geometry + s which contain 3 or more points. + + the minimum-area convex polygon containing this Geometry's points. + + + + Computes a new geometry which has all component coordinate sequences + in reverse order (opposite orientation) to this one. + + A reversed geometry + Don't override this function, implement . + + + + The actual implementation of the function + + A reversed geometry + In JTS this function is abstract, but that would break binary compatibility of current version. + + + + Computes a Geometry representing the point-set which is + common to both this Geometry and the other Geometry. + + The intersection of two geometries of different dimension produces a result + geometry of dimension less than or equal to the minimum dimension of the input + geometries. + The result geometry may be a heterogeneous . + If the result is empty, it is an atomic geometry + with the dimension of the lowest input dimension. + + Intersection of s is supported + only for homogeneous collection types. + + Non-empty heterogeneous arguments are not supported. + + The Geometry with which to compute the intersection. + A geometry representing the point-set common to the two Geometrys. + if a robustness error occurs. + if the argument is a non-empty heterogeneous GeometryCollection + if the argument has a factory with a different GeometryOverlay object assigned + + + + Computes a Geometry representing the point-set + which is contained in both this + Geometry and the other Geometry. + + + The method may be used on arguments of different dimension, but it does not + support arguments. + + The union of two geometries of different dimension produces a result + geometry of dimension equal to the maximum dimension of the input + geometries. + The result geometry may be a heterogeneous + . + If the result is empty, it is an atomic geometry + with the dimension of the highest input dimension. + + Unioning s has the effect of + noding and dissolving the input linework. In this context + "noding" means that there will be a node or endpoint in the result for + every endpoint or line segment crossing in the input. "Dissolving" means + that any duplicate (i.e. coincident) line segments or portions of line + segments will be reduced to a single line segment in the result. + If merged linework is required, the + class can be used. + + Non-empty arguments are not supported. + the Geometry with which to compute the union + A point-set combining the points of this Geometry and the + points of other + Thrown if a robustness error occurs + Thrown if either input is a non-empty GeometryCollection + if the argument has a factory with a different GeometryOverlay object assigned + + + + + Computes a Geometry representing the closure of the point-set + of the points contained in this Geometry that are not contained in + the other Geometry. + + If the result is empty, it is an atomic geometry + with the dimension of the left-hand input. + + Non-empty arguments are not supported. + + The Geometry with which to compute the difference. + A Geometry representing the point-set difference of this Geometry with other. + if the argument has a factory with a different GeometryOverlay object assigned + + + + Computes a Geometry representing the closure of the point-set + which is the union of the points in this Geometry which are not + contained in the other Geometry, + with the points in the other Geometry not contained in this + Geometry. + If the result is empty, it is an atomic geometry + with the dimension of the highest input dimension. + + Non-empty arguments are not supported. + + The Geometry with which to compute the symmetric difference. + a Geometry representing the point-set symmetric difference of this Geometry with other. + if the argument has a factory with a different GeometryOverlay object assigned + + + + Computes the union of all the elements of this geometry. + + + This method supports s (which the other overlay operations currently do not). + + The result obeys the following contract: + + Unioning a set of s has the effect of fully noding and dissolving the linework. + Unioning a set of s always returns a geometry + (unlike ), which may return geometries of lower dimension if a topology + collapse occurred). + + + Thrown if a robustness error occurs + + + + Returns true if the two Geometrys are exactly equal, + up to a specified tolerance. + Two Geometries are exactly within a tolerance equal if: + + they have the same class, + they have the same values of Coordinates, + within the given tolerance distance, in their internal + Coordinate lists, in exactly the same order. + + This method does not + test the values of the GeometryFactory, the SRID, + or the UserData fields. + + To properly test equality between different geometries, + it is usually necessary to them first. + + The Geometry with which to compare this Geometry + have identical structure and point values, up to the distance tolerance. + Distance at or below which two Coordinates will be considered equal. + + true if this and the other Geometry + are of the same class and have equal internal data. + + + + + + + + Returns true if the two Geometrys are exactly equal. + Two Geometries are exactly equal if: + + they have the same class, + they have the same values of Coordinates in their internal + Coordinate lists, in exactly the same order. + + This provides a stricter test of equality than + , which is more useful + in certain situations + (such as using geometries as keys in collections). + + This method does not + test the values of the GeometryFactory, the SRID, + or the UserData fields. + + To properly test equality between different geometries, + it is usually necessary to them first. + + The Geometry with which to compare this Geometry. + + true if this and the other Geometry have identical structure and point values. + + + + + Tests whether two geometries are exactly equal + in their normalized forms. + + This is a convenience method which creates normalized + versions of both geometries before computing + . + This method is relatively expensive to compute. + For maximum performance, the client + should instead perform normalization on the individual geometries + at an appropriate point during processing. + + + A geometry + true if the input geometries are exactly equal in their normalized form + + + + + Performs an operation with or on this Geometry's coordinates. + + + If this method modifies any coordinate values, + must be called to update the geometry state. + Note that you cannot use this method to + modify this Geometry if its underlying CoordinateSequence's #get method + returns a copy of the Coordinate, rather than the actual Coordinate stored + (if it even stores Coordinate objects at all). + + The filter to apply to this Geometry's coordinates + + + + Performs an operation on the coordinates in this Geometry's s. + + + If the filter reports that a coordinate value has been changed, + will be called automatically. + + The filter to apply + + + + Performs an operation on this Geometry's s. + + + If the filter reports that a coordinate value has been changed, + will be called automatically. + + The filter to apply + + + + Performs an operation with or on this Geometry and its + subelement Geometrys (if any). + Only GeometryCollections and subclasses + have subelement Geometry's. + + + The filter to apply to this Geometry (and + its children, if it is a GeometryCollection). + + + + + Performs an operation with or on this Geometry and its + component Geometry's. Only GeometryCollections and + Polygons have component Geometry's; for Polygons they are the LinearRings + of the shell and holes. + + The filter to apply to this Geometry. + + + + Creates a deep copy of this object. + Coordinate sequences contained in it are copied. + All instance fields are copied + (i.e. the SRID, EnvelopeInternal and UserData). + + + NOTE: The UserData object reference (if present) is copied, + but the value itself is not copied. + If a deep copy is required this must be performed by the caller. + + A deep copy of this geometry + + + + An internal method to copy subclass-specific geometry data. + + A copy of the target geometry object. + + + + Converts this Geometry to normal form (or canonical form ). + + + + Normal form is a unique representation for Geometrys. + It can be used to test whether two Geometrys are equal + in a way that is independent of the ordering of the coordinates within + them. Normal form equality is a stronger condition than topological + equality, but weaker than pointwise equality. + + The definitions for normal + form use the standard lexicographical ordering for coordinates. "Sorted in + order of coordinates" means the obvious extension of this ordering to + sequences of coordinates. + + + NOTE that this method mutates the value of this geometry in-place. + If this is not safe and/or wanted, the geometry should be + cloned prior to normalization. + + + + + + Creates a new Geometry which is a normalized copy of this Geometry. + + A normalized copy of this geometry. + + + + + Returns whether this Geometry is greater than, equal to, + or less than another Geometry. + + If their classes are different, they are compared using the following + ordering: + + Point (lowest), + MultiPoint, + LineString, + LinearRing, + MultiLineString, + Polygon, + MultiPolygon, + GeometryCollection (highest). + + If the two Geometrys have the same class, their first + elements are compared. If those are the same, the second elements are + compared, etc. + + A Geometry with which to compare this Geometry + + A positive number, 0, or a negative number, depending on whether + this object is greater than, equal to, or less than o, as + defined in "Normal Form For Geometry" in the NTS Technical + Specifications. + + + + + Returns whether this Geometry is greater than, equal to, + or less than another Geometry. + + If their classes are different, they are compared using the following + ordering: + + Point (lowest), + MultiPoint, + LineString, + LinearRing, + MultiLineString, + Polygon, + MultiPolygon, + GeometryCollection (highest). + /// + If the two Geometrys have the same class, their first + elements are compared. If those are the same, the second elements are + compared, etc. + + A Geometry with which to compare this Geometry + + A positive number, 0, or a negative number, depending on whether + this object is greater than, equal to, or less than o, as + defined in "Normal Form For Geometry" in the NTS Technical + Specifications. + + + + + Returns whether this Geometry is greater than, equal to, + or less than another Geometry, using the given . + + If their classes are different, they are compared using the following + ordering: + + Point (lowest), + MultiPoint, + LineString, + LinearRing, + MultiLineString, + Polygon, + MultiPolygon, + GeometryCollection (highest). + + If the two Geometrys have the same class, their first + elements are compared. If those are the same, the second elements are + compared, etc. + + A Geometry with which to compare this Geometry + A IComparer<CoordinateSequence> + + A positive number, 0, or a negative number, depending on whether + this object is greater than, equal to, or less than o, as + defined in "Normal Form For Geometry" in the NTS Technical + Specifications. + + + + + Returns whether the two Geometrys are equal, from the point + of view of the EqualsExact method. Called by EqualsExact + . In general, two Geometry classes are considered to be + "equivalent" only if they are the same class. An exception is LineString + , which is considered to be equivalent to its subclasses. + + The Geometry with which to compare this Geometry for equality. + + true if the classes of the two Geometry + s are considered to be equal by the equalsExact method. + + + + + Throws an exception if g's type is a GeometryCollection. + (Its subclasses do not trigger an exception). + + The Geometry to check. + + if g is a GeometryCollection, but not one of its subclasses. + + + + + Tests whether this is an instance of a general {@link GeometryCollection}, + rather than a homogeneous subclass. + + true if this is a heterogeneous GeometryCollection + + + + Returns the minimum and maximum x and y values in this Geometry, + or a null Envelope if this Geometry is empty. + Unlike EnvelopeInternal, this method calculates the Envelope + each time it is called; EnvelopeInternal caches the result + of this method. + + + This Geometrys bounding box; if the Geometry + is empty, Envelope.IsNull will return true. + + + + + Returns whether this Geometry is greater than, equal to, + or less than another Geometry having the same class. + + A Geometry having the same class as this Geometry. + + A positive number, 0, or a negative number, depending on whether + this object is greater than, equal to, or less than o, as + defined in "Normal Form For Geometry" in the NTS Technical + Specifications. + + + + + Returns whether this Geometry is greater than, equal to, + or less than another Geometry of the same class. + using the given . + + A Geometry having the same class as this Geometry + The comparer + + A positive number, 0, or a negative number, depending on whether + this object is greater than, equal to, or less than o, as + defined in "Normal Form For Geometry" in the JTS Technical + Specifications + + + + + Returns the first non-zero result of CompareTo encountered as + the two Collections are iterated over. If, by the time one of + the iterations is complete, no non-zero result has been encountered, + returns 0 if the other iteration is also complete. If b + completes before a, a positive number is returned; if a + before b, a negative number. + + A Collection of IComparables. + A Collection of IComparables. + The first non-zero compareTo result, if any; otherwise, zero. + + + + + + + + + + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + + + + + + + + + Tests whether this is a rectangular . + + true if the geometry is a rectangle. + Polygon overrides to check for actual rectangle. + + + + A predefined with == . + + + + + + + Basic implementation of GeometryCollection. + + + + + Represents an empty GeometryCollection. + + + + + Internal representation of this GeometryCollection. + + + + + + + + The Geometrys for this GeometryCollection, + or null or an empty array to create the empty + point. Elements may be empty Geometrys, + but not nulls. + + + For create this is used a standard + with == . + + + + + + + + The Geometrys for this GeometryCollection, + or null or an empty array to create the empty + point. Elements may be empty Geometrys, + but not nulls. + + + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + + + + + + Collects all coordinates of all subgeometries into an Array. + Note that while changes to the coordinate objects themselves + may modify the Geometries in place, the returned Array as such + is only a temporary container which is not synchronized back. + + The collected coordinates. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Returns the name of this object's interface. + + "GeometryCollection" + + + + Gets the OGC geometry type + + + + + + + + + + Returns the area of this GeometryCollection. + + + + + Returns the length of this GeometryCollection. + + + + + + + + + + + + + + + + + + + + + + + + + + + > + + + + + + + + + + + + + + + + + + + + + Return true if all features in collection are of the same type. + + + + + + + + Returns the iTh element in the collection. + + + + + + + Creates a with + every component reversed. + The order of the components in the collection are not reversed. + + A in the reverse order + + + + The actual implementation of the function for GeometryCollections. + + A reversed geometry + + + + Returns the number of geometries contained by this . + + + + + Iterates over all Geometry's in a GeometryCollection. + Implements a pre-order depth-first traversal of the GeometryCollection + (which may be nested). The original GeometryCollection is + returned as well (as the first object), as are all sub-collections. It is + simple to ignore the GeometryCollection objects if they are not + needed. + + + + + The GeometryCollection being iterated over. + + + + + Indicates whether or not the first element (the GeometryCollection) + has been returned. + + + + + The number of Geometrys in the the GeometryCollection. + + + + + The index of the Geometry that will be returned when next + is called. + + + + + The iterator over a nested GeometryCollection, or null + if this GeometryCollectionIterator is not currently iterating + over a nested GeometryCollection. + + + + + Constructs an iterator over the given GeometryCollection. + + + The collection over which to iterate; also, the first + element returned by the iterator. + + + + > + + + > + The parent GeometryCollection is the first object returned! + + + + + + + + + + + + + + + + + + + Delegate function declaration to handle filter operation + + The geometry to filter + + + + An implementation that applies filtering with the provided + + + + + Creates an instance of this class + + The filter method to be used + + + + Supplies a set of utility methods for building Geometry objects + from lists of Coordinates. + + + Note that the factory constructor methods do not change the input coordinates in any way. + In particular, they are not rounded to the supplied PrecisionModel. + It is assumed that input Coordinates meet the given precision. + + Instances of this class are thread-safe. + + + + + A predefined with c + == . + + + + + A predefined with + == . + + A shortcut for . + + + + A predefined with + == . + + + + + A predefined with + == . + + + + + Returns the PrecisionModel that Geometries created by this factory + will be associated with. + + + + + + + + + + The SRID value defined for this factory. + + + + + Gets a value indicating the geometry overlay function set to use + + A geometry overlay function set. + + + + Gets a value indicating the geometry overlay function set to use + + A geometry overlay function set. + + + + Gets a value indicating the object that created this factory. + + + + + + + + + + + + + Constructs a GeometryFactory that generates Geometries having the given + precision model, spatial-reference ID, + CoordinateSequence and + NtsGeometryServices. + + A precision model + A spatial reference id + A coordinate sequence factory + NtsGeometryServices object creating this factory + + + + Constructs a GeometryFactory that generates Geometries having the given + PrecisionModel, spatial-reference ID, and CoordinateSequence implementation. + + + + + Constructs a GeometryFactory that generates Geometries having the given + CoordinateSequence implementation, a double-precision floating PrecisionModel and a + spatial-reference ID of 0. + + + + + Constructs a GeometryFactory that generates Geometries having the given + {PrecisionModel} and the default CoordinateSequence + implementation. + + The PrecisionModel to use. + + + + Constructs a GeometryFactory that generates Geometries having the given + PrecisionModel and spatial-reference ID, and the default CoordinateSequence + implementation. + + The PrecisionModel to use. + The SRID to use. + + + + Constructs a GeometryFactory that generates Geometries having a floating + PrecisionModel and a spatial-reference ID of 0. + + + + + Converts the IEnumerable to an array. + + The IEnumerable of Points to convert. + The IEnumerable in array format. + + + + Converts the IEnumerable to an array. + + The IEnumerable of Geometry's to convert. + The IEnumerable in array format. + + + + Converts the IEnumerable to an array. + + The IEnumerable of LineStrings to convert. + The IEnumerable in array format. + + + + Converts the IEnumerable to an array. + + The IEnumerable of LinearRings to convert. + The IEnumerable in array format. + + + + Converts the IEnumerable to an array. + + The IEnumerable of Polygons to convert. + The IEnumerable in array format. + + + + Converts the IEnumerable to an array. + + The IEnumerable of MultiPoints to convert. + The IEnumerable in array format. + + + + Converts the IEnumerable to an array. + + The IEnumerable of MultiLineStrings to convert. + The IEnumerable in array format. + + + + Converts the IEnumerable to an array. + + The IEnumerable of MultiPolygons to convert. + The IEnumerable in array format. + + + + Creates a with the same extent as the given envelope. + + + + The Geometry returned is guaranteed to be valid. + To provide this behavior, the following cases occur: + + + If the Envelope is: +
    +
  • null returns an empty
  • +
  • a point returns a non-empty
  • +
  • a line returns a two-point
  • +
  • a rectangle returns a whose points are (minx, maxy), (minx, maxy), (maxx, maxy), (maxx, miny).
  • +
+
+
+ The Envelope + + An empty Point (for null Envelopes), a Point (when min x = max x and min y = max y) or a Polygon (in all other cases) + +
+ + + Creates an empty Point + + + An empty Point + + + + + Creates a Point using the given Coordinate. + A null coordinate creates an empty Geometry. + + a Coordinate, or null + A object + + + + Creates a Point using the given CoordinateSequence; a null or empty + CoordinateSequence will create an empty Point. + + a CoordinateSequence (possibly empty), or null + A object + + + + Creates an empty LineString + + An empty LineString + + + + Creates a LineString using the given Coordinates. + A null or empty array creates an empty LineString. + + An array without null elements, or an empty array, or null. + A object + + + + Creates a LineString using the given CoordinateSequence. + A null or empty CoordinateSequence creates an empty LineString. + + A CoordinateSequence (possibly empty), or null. + A object + + + Creates an empty LinearRing + An empty LinearRing + + + + Creates a LinearRing using the given Coordinates; a null or empty array + creates an empty LinearRing. The points must form a closed and simple + linestring. Consecutive points must not be equal. + + An array without null elements, or an empty array, or null. + A object + If the ring is not closed, or has too few points + + + + Creates a LinearRing using the given CoordinateSequence; a null or empty CoordinateSequence + creates an empty LinearRing. The points must form a closed and simple + linestring. Consecutive points must not be equal. + + A CoordinateSequence (possibly empty), or null. + A object + If the ring is not closed, or has too few points + + + Creates an empty Polygon + An empty Polygon + + + + Constructs a Polygon with the given exterior boundary and + interior boundaries. + + + The outer boundary of the new Polygon, or + null or an empty LinearRing if + the empty point is to be created. + + + The inner boundaries of the new Polygon, or + null or empty LinearRing s if + the empty point is to be created. + + A object + + + + Constructs a Polygon with the given exterior boundary. + + the outer boundary of the new Polygon, or + null or an empty LinearRing if + the empty geometry is to be created. + A object + If the boundary ring is invalid + + + + Constructs a Polygon with the given exterior boundary. + + the outer boundary of the new Polygon, or + null or an empty LinearRing if + the empty geometry is to be created. + A object + If the boundary ring is invalid + + + + Constructs a Polygon with the given exterior boundary. + + the outer boundary of the new Polygon, or + null or an empty LinearRing if + the empty geometry is to be created. + the created Polygon + If the boundary ring is invalid + + + Creates an empty MultiPoint + An empty MultiPoint + + + + Creates a using the given Points. + A null or empty array will create an empty MultiPoint. + + An array (without null elements), or an empty array, or null. + A object + + + + Creates a using the given Coordinates. + A null or empty array will create an empty MultiPoint. + + An array (without null elements), or an empty array, or null + A object + + + + Creates a using the given CoordinateSequence. + A null or empty CoordinateSequence will create an empty MultiPoint. + + A CoordinateSequence (possibly empty), or null. + A object + + + Creates an empty MultiLineString + An empty MultiLineString + + + + Creates a MultiLineString using the given LineStrings; a null or empty + array will create an empty MultiLineString. + + LineStrings, each of which may be empty but not null- + A object + + + Creates an empty MultiPolygon + An empty MultiPolygon + + + + Creates a MultiPolygon using the given Polygons; a null or empty array + will create an empty Polygon. The polygons must conform to the + assertions specified in the OpenGIS Simple Features + Specification for SQL. + + Polygons, each of which may be empty but not null. + A object + + + Creates an empty GeometryCollection + An empty GeometryCollection + + + + Creates a GeometryCollection using the given Geometries; a null or empty + array will create an empty GeometryCollection. + + an array of Geometries, each of which may be empty but not null, or null + A object + + + + Build an appropriate Geometry, MultiGeometry, or + GeometryCollection to contain the Geometrys in + it. + + + If geomList contains a single Polygon, + the Polygon is returned.
+ If geomList contains several Polygons, a + MultiPolygon is returned.
+ If geomList contains some Polygons and + some LineStrings, a GeometryCollection is + returned.
+ If geomList is empty, an empty GeometryCollection + is returned. + Note that this method does not "flatten" Geometries in the input, and hence if + any MultiGeometries are contained in the input a GeometryCollection containing + them will be returned. +
+ The Geometry to combine. + + A of the "smallest", "most type-specific" + class that can contain the elements of geomList. + +
+ + + Creates an empty atomic geometry of the given dimension. + If passed a dimension of + will create an empty . + + The required dimension (, , or ) + An empty atomic geometry of given dimension + + + + Creates a deep copy of the input . + The defined for this factory + is used to copy the s + of the input geometry. + + This is a convenient way to change the CoordinateSequence + used to represent a geometry, or to change the + factory used for a geometry. + + can also be used to make a deep copy, + but it does not allow changing the CoordinateSequence type. + + The geometry + A deep copy of the input geometry, using the CoordinateSequence type of this factory + + + + + Returns a new whose is + the given value and whose other values and behavior are, as near as we possibly can make + it, the same as our own. + + + The for the result. + + + The cloned instance. + + + + + + + + An extended that is capable of enforcing a ring orientation for polygons. + + + + + Gets or sets the default polygon shell ring orientation that is used when nothing else has been set. + + + + + Gets or sets the default precision model to use with these geometry factories + + + + + Gets or sets the default coordinate sequence factory to use with these geometry factories + + + + + Gets or sets the default spatial reference id. + + + + + Constructs a GeometryFactory that generates Geometries having the given + PrecisionModel, spatial-reference ID, and CoordinateSequence implementation. + + + + + Constructs a GeometryFactory that generates Geometries having the given + PrecisionModel, spatial-reference ID, and CoordinateSequence implementation. + + + + + Constructs a GeometryFactory that generates Geometries having the given + CoordinateSequence implementation, a double-precision floating PrecisionModel and a + spatial-reference ID of 0. + + + + + Constructs a GeometryFactory that generates Geometries having the given + {PrecisionModel} and the default CoordinateSequence + implementation. + + The PrecisionModel to use. + + + + Constructs a GeometryFactory that generates Geometries having the given + PrecisionModel and spatial-reference ID, and the default CoordinateSequence + implementation. + + The PrecisionModel to use. + The SRID to use. + + + + Constructs a GeometryFactory that generates Geometries having a floating + PrecisionModel and a spatial-reference ID of 0. + + + + + The polygon shell ring orientation enforced by this factory + + + + + Gets or sets a value indicating the ring orientation of the + Polygon's exterior rings. + If its value is , this + factory behaves just like the base . + + + + The setter of this property has to be used prior to any call + to CreatePolygon, CreateMultiPolygon, or + ReplaceSRID + + + + + + + + + Gets a value indicating the ring orientation for the interior rings + + + This value is always opposite of , + except when its value is . + + + + + Constructs a Polygon with the given exterior boundary and + interior boundaries. + + The is enforced on the constructed polygon. + + + The outer boundary of the new Polygon, or + null or an empty LinearRing if + the empty point is to be created. + + + The inner boundaries of the new Polygon, or + null or empty LinearRing s if + the empty point is to be created. + + A object + + + + Creates a MultiPolygon using the given Polygons; a null or empty array + will create an empty Polygon. The polygons must conform to the + assertions specified in the OpenGIS Simple Features + Specification for SQL. + The is enforced on each polygon. + + Polygons, each of which may be empty but not null. + A object + + + + + + + Utility function to enforce a specific ring orientation on a linear ring + + The ring + The required orientation + A ring + + + + A class that encapsulates geometry overlay functionality + + + + + Gets a value indicating a geometry overlay operation class that uses old NTS overlay operation set. + + + + + Gets a value indicating a geometry overlay operation class that uses next-generation NTS overlay operation set. + + + + + Computes a Geometry representing the overlay of geometries a and b + using the spatial function defined by opCode. + + The 1st geometry + The 2nd geometry + The spatial function for the overlay operation + The computed geometry + + + + Computes a Geometry representing the point-set which is + common to both a and b Geometry. + + The 1st Geometry + The 2nd Geometry + A geometry representing the point-set common to the two Geometrys. + + + + + Computes a Geometry representing the point-set + which is contained in both input Geometrys . + + The 1st Geometry + The 2nd Geometry + A point-set combining the points of + Geometry's a and b. + + + + + + Computes a Geometry representing the closure of the point-set + of the points contained in this Geometry that are not contained in + the other Geometry. + + The 1st Geometry + The 2nd Geometry + + A Geometry representing the point-set difference + of Geometry's a and b. + + + + + + Computes a Geometry representing the closure of the point-set + which is the union of the points in Geometry a which are not + contained in the Geometry b, + with the points in the b Geometry not contained in the Geometry a. + + The 1st Geometry + The 2nd Geometry + + A Geometry representing the point-set symmetric difference + of Geometry's a and b. + + + + + + Computes the union of all the elements in the Geometry a. + + The Geometry + The union of a + + + + + A spatial object in an AbstractSTRtree. + + + + + Returns a representation of space that encloses this Boundable, preferably + not much bigger than this Boundable's boundary yet fast to test for intersection + with the bounds of other Boundables. The class of object returned depends + on the subclass of AbstractSTRtree. + + + An Envelope (for STRtrees), an Interval (for SIRtrees), or other object + (for other subclasses of AbstractSTRtree). + + + + + Gets the item that is bounded + + + + + An interface for classes which use the values of the coordinates in a . + Coordinate filters can be used to implement centroid and + envelope computation, and many other functions. + + ICoordinateFilter is + an example of the Gang-of-Four Visitor pattern. + + Note: it is not recommended to use these filters to mutate the coordinates. + There is no guarantee that the coordinate is the actual object stored in the source geometry. + In particular, modified values may not be preserved if the source Geometry uses a non-default . + If in-place mutation is required, use . + + + + + + + Performs an operation with the provided coord. + Note that there is no guarantee that the input coordinate + is the actual object stored in the source geometry, + so changes to the coordinate object may not be persistent. + + A Coordinate to which the filter is applied. + + + + An interface for classes which process the coordinates in a . + A filter can either record information about each coordinate, + or change the value of the coordinate. + Filters can be + used to implement operations such as coordinate transformations, centroid and + envelope computation, and many other functions. + classes support the concept of applying a + CoordinateSequenceFilter to each + s they contain. + + For maximum efficiency, the execution of filters can be short-circuited by using the property. + + + + CoordinateSequenceFilter is an example of the Gang-of-Four Visitor pattern. + Note: In general, it is preferable to treat Geometrys as immutable. + Mutation should be performed by creating a new Geometry object (see + and for convenient ways to do this). + An exception to this rule is when a new Geometry has been created via . + In this case mutating the Geometry will not cause aliasing issues, + and a filter is a convenient way to implement coordinate transformation. + + + Martin Davis + + + + + + + Performs an operation on a coordinate in a . + + the CoordinateSequence to which the filter is applied + i the index of the coordinate to apply the filter to + + + + Reports whether the application of this filter can be terminated. + + + Once this method returns true, it must + continue to return true on every subsequent call. + + + + + Reports whether the execution of this filter has modified the coordinates of the geometry. + If so, will be executed + after this filter has finished being executed. + + Most filters can simply return a constant value reflecting whether they are able to change the coordinates. + + + + A variant of , except it receives each + just once, instead of once for each of its coordinates. + + + + + Reports whether the application of this filter can be terminated. + + + Once this method returns it must continue to return + on every subsequent call. + + + + + Reports whether the execution of this filter has modified the coordinates of the geometry. + If so, will be executed + after this filter has finished being executed. + + + Most filters can simply return a constant value reflecting whether they are able to + change the coordinates. + + + + + Performs an operation on a . + + + The . + + + + + Interface describing objects that can expand themselves by objects of type . + + The type of objects that can expand clients + + + + Method to expand this object by + + The object to expand with + + + + Function to expand compute a new object that is this object by expanded by . + + The object to expand with + The expanded object + + + + Geometry classes support the concept of applying + an IGeometryComponentFilter filter to the Geometry. + + + The filter is applied to every component of the Geometry + which is itself a Geometry + and which does not itself contain any components. + (For instance, all the LinearRings in Polygons are visited, + but in a MultiPolygon the Polygons themselves are not visited.) + Thus the only classes of Geometry which must be + handled as arguments to + are s, s and s. + An IGeometryComponentFilter filter can either + record information about the Geometry + or change the Geometry in some way. + IGeometryComponentFilter is an example of the Gang-of-Four Visitor pattern. + > + + + + Performs an operation with or on geom. + + A Geometry to which the filter is applied. + + + + GeometryCollection classes support the concept of + applying a IGeometryFilter to the Geometry. + The filter is applied to every element Geometry. + A IGeometryFilter can either record information about the Geometry + or change the Geometry in some way. + IGeometryFilter is an example of the Gang-of-Four Visitor pattern. + + + + + Performs an operation with or on geom. + + A Geometry to which the filter is applied. + + + + Interface describing objects that can perform an intersects predicate with objects. + + The type of the component that can intersect + + + + Predicate function to test if intersects with this object. + + The object to test + true if this objects intersects with + + + + Interface to identify all Geometry subclasses that have a Dimension of + and have components which are s. + + Martin Davis + + + + + + A backed by an array of s. + This is the implementation that s use by default. + + Coordinates returned by , and are live -- + modifications to them are actually changing the + CoordinateSequence's underlying data. + A dimension may be specified for the coordinates in the sequence, + which may be 2 or 3. + The actual coordinates will always have 3 ordinates, + but the dimension is useful as metadata in some situations. + + + + + Array of coordinates in sequence + + + + + Constructs a sequence based on the given array of s. + The coordinate dimension defaults to 2 + + + The array is not copied. + + The coordinate array that will be referenced. + + + + Constructs a sequence based on the given array + of s. + + The Array is not copied + The coordinate array that will be referenced. + The dimension of the coordinates + + + + Constructs a sequence based on the given array + of s. + + The Array is not copied + + It is your responsibility to ensure the array contains Coordinates of the + indicated dimension and measures (See ). + + The coordinate array that will be referenced. + The dimension of the coordinates + The number of measure ordinate values. + + + + Constructs a sequence of a given size, populated with new Coordinates. + + The size of the sequence to create. + + + + Constructs a sequence of a given , populated + with new s of the given . + + The size of the sequence to create. + the dimension of the coordinates + + + + Constructs a sequence of a given , populated + with new s of the given + with the given number of + + The size of the sequence to create. + the dimension of the coordinates + the number of measures of the coordinates + + + + Creates a new sequence based on a deep copy of the given . + + The coordinate sequence that will be copied + + + + Ensure array contents of the same type, making use of as needed. + + A new array will be created if needed to return a consistent result. + + + array containing consistent coordinate instances + + + + Get the Coordinate with index i. + + The index of the coordinate. + The requested Coordinate instance. + + + + Get a copy of the Coordinate with index i. + + The index of the coordinate. + A copy of the requested Coordinate. + + + + Copies the i'th coordinate in the sequence to the supplied Coordinate. + + The index of the coordinate to copy. + A Coordinate to receive the value. + + + + Returns ordinate X (0) of the specified coordinate. + + + + The value of the X ordinate in the index'th coordinate. + + + + + Returns ordinate Y (1) of the specified coordinate. + + + + The value of the Y ordinate in the index'th coordinate. + + + + + Returns ordinate Z of the specified coordinate if available. + + + + The value of the Z ordinate in the index'th coordinate, or Double.NaN if not defined. + + + + + Returns ordinate M of the specified coordinate if available. + + + + The value of the M ordinate in the index'th coordinate, or Double.NaN if not defined. + + + + + Returns the ordinate of a coordinate in this sequence. + Ordinate indices 0 and 1 are assumed to be X and Y. + Ordinate indices greater than 1 have user-defined semantics + (for instance, they may contain other dimensions or measure values). + + The coordinate index in the sequence. + The ordinate index in the coordinate (in range [0, dimension-1]). + + + + + Creates a deep copy of the CoordinateArraySequence. + + The deep copy. + + + + + + + + + + Sets the value for a given ordinate of a coordinate in this sequence. + + The coordinate index in the sequence. + The ordinate index in the coordinate (in range [0, dimension-1]). + The new ordinate value. + + + + This method exposes the internal Array of Coordinate Objects. + + + + + + Expands the given Envelope to include the coordinates in the sequence. + Allows implementing classes to optimize access to coordinate values. + + The envelope to expand. + A reference to the expanded envelope. + + + + + + + Returns the string representation of the coordinate array. + + + + + + Creates CoordinateSequences represented as an array of Coordinates. + + + + + Returns the singleton instance of CoordinateArraySequenceFactory. + + + + + Returns a CoordinateArraySequence based on the given array (the array is not copied). + + the coordinates, which may not be null nor contain null elements. + + + + + + + + + + + A coordinate sequence that follows the dotspatial shape range + + + + + Creates an instance of this class + + The coordinates + + + + + Constructs a sequence of a given size, populated with new Coordinates. + + The size of the sequence to create. + The number of dimensions. + The number of measures. + + + + Constructs a sequence of a given size, populated with new Coordinates. + + The size of the sequence to create. + The kind of ordinates. + + + + Creates a sequence based on the given coordinate sequence. + + The coordinate sequence. + The ordinates to copy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a reversed version of this coordinate sequence with cloned s + + A reversed version of this sequence + + + + Gets the vector with x- and y-ordinate values; + + If you modify the values of this vector externally, you need to call ! + + + + Gets the vector with z-ordinate values + + If you modify the values of this vector externally, you need to call ! + + + + Gets the vector with measure values + + If you modify the values of this vector externally, you need to call ! + + + + Releases the weak reference to the weak referenced coordinate array + + This is necessary if you modify the values of the , , arrays externally. + + + + A coordinate sequence factory class that creates DotSpatial's Shape/ShapeRange like coordinate sequences. + + + + + Returns the singleton instance of DotSpatialAffineCoordinateSequenceFactory. + + + + + + Returns a CoordinateArraySequence based on the given array (the array is not copied). + + the coordinates, which may not be null nor contain null elements. + + + + + Creates a which is a copy + of the given . + This method must handle null arguments by creating an empty sequence. + + + A coordinate sequence + + + + + + + Creates a of the specified size and ordinates. + For this to be useful, the implementation must be mutable. + + The number of coordinates. + + The ordinates each coordinate has. is fix, + and can be set. + + A coordinate sequence. + + + + Creates an instance of this class using the provided array for x- and y ordinates + + The x- and y-ordinates + A coordinate sequence + + + + Creates an instance of this class using the provided array for x- and y ordinates, + the array for either z-ordinates or measure values. This is indicated by . + + The x- and y-ordinates + An array of z- or measure values + A value indicating if contains z-ordinates or measure values. + A coordinate sequence + + + + Creates an instance of this class using the provided array for x- and y ordinates, + the array for z ordinates and for measure values. + + The x- and y-ordinates + An array of z- or measure values + An array of measure values. + A coordinate sequence + + + + A CoordinateSequence implementation based on a packed arrays. + + + + + A soft reference to the Coordinate[] representation of this sequence. + Makes repeated coordinate array accesses more efficient. + + + + + Creates an instance of this class + + The number of s in the sequence. + The total number of ordinates that make up a in this sequence. + the number of measure-ordinates each { in this sequence has. + + + + Returns (possibly a copy of) the ith Coordinate in this collection. + Whether or not the Coordinate returned is the actual underlying + Coordinate or merely a copy depends on the implementation. + Note that in the future the semantics of this method may change + to guarantee that the Coordinate returned is always a copy. Callers are + advised not to assume that they can modify a CoordinateSequence by + modifying the Coordinate returned by this method. + + + + + + + Returns (possibly copies of) the Coordinates in this collection. + Whether or not the Coordinates returned are the actual underlying + Coordinates or merely copies depends on the implementation. + Note that if this implementation does not store its data as an array of Coordinates, + this method will incur a performance penalty because the array needs to + be built from scratch. + + + + + + Releases the weak reference to the coordinate array. + + + This is necessary if you directly modify the array from GetRawCoordinates. + + + + + + + + Returns a Coordinate representation of the specified coordinate, by always + building a new Coordinate object. + + The coordinate index + The at the given index + + + + Packed coordinate sequence implementation based on doubles. + + + + + The packed coordinate array + + + + + Initializes a new instance of the class. + + An array of double values that contains the ordinate values of the sequence. + The total number of ordinates that make up a in this sequence. + The number of measure-ordinates each in this sequence has. + + + + Initializes a new instance of the class. + + An array of float values that contains the ordinate values of the sequence. + The total number of ordinates that make up a in this sequence. + The number of measure-ordinates each in this sequence has. + + + + Initializes a new instance of the class. + + An array of s. + + + + Initializes a new instance of the class. + + An array of s. + The total number of ordinates that make up a in this sequence. + + + + Initializes a new instance of the class. + + An array of s. + The total number of ordinates that make up a in this sequence. + The number of measure-ordinates each in this sequence has. + + + + Initializes a new instance of the class. + + The number of coordinates in this sequence + The total number of ordinates that make up a in this sequence. + The number of measure-ordinates each in this sequence has. + + + + Gets the underlying array containing the coordinate values. + + The array of coordinate values + + + + + + + Returns the ordinate of a coordinate in this sequence. + Ordinate indices 0 and 1 are assumed to be X and Y. + Ordinate indices greater than 1 have user-defined semantics + (for instance, they may contain other dimensions or measure values). + + + Beware, for performance reasons the ordinate index is not checked, if + it's over dimensions you may not get an exception but a meaningless + value. + + The coordinate index in the sequence. + The ordinate index in the coordinate (in range [0, dimension-1]). + + + + + Sets the ordinate of a coordinate in this sequence. + + The coordinate index. + The ordinate index in the coordinate, 0 based, + smaller than the number of dimensions. + The new ordinate value. + + Warning: for performance reasons the ordinate index is not checked. + If it is larger than the dimension a meaningless value may be returned. + + + + + Expands the given Envelope to include the coordinates in the sequence. + Allows implementing classes to optimize access to coordinate values. + + The envelope to expand. + A reference to the expanded envelope. + + + + Packed coordinate sequence implementation based on floats. + + + + + The packed coordinate array + + + + + Initializes a new instance of the class. + + An array of float values that contains the ordinate values of the sequence. + The total number of ordinates that make up a in this sequence. + The number of measure-ordinates each in this sequence has. + + + + Initializes a new instance of the class. + + An array of double values that contains the ordinate values of the sequence. + The total number of ordinates that make up a in this sequence. + The number of measure-ordinates each in this sequence has. + + + + Initializes a new instance of the class. + + An array of s. + + + + Initializes a new instance of the class. + + An array of s. + The total number of ordinates that make up a in this sequence. + + + + Initializes a new instance of the class. + + An array of s. + The total number of ordinates that make up a in this sequence. + The number of measure-ordinates each in this sequence has. + + + + Initializes a new instance of the class. + + + + + + + + Gets the underlying array containing the coordinate values. + + The array of coordinate values + + + + + + + Returns the ordinate of a coordinate in this sequence. + Ordinate indices 0 and 1 are assumed to be X and Y. + Ordinate indices greater than 1 have user-defined semantics + (for instance, they may contain other dimensions or measure values). + + + Beware, for performance reasons the ordinate index is not checked, if + it's over dimensions you may not get an exception but a meaningless + value. + + The coordinate index in the sequence. + The ordinate index in the coordinate (in range [0, dimension-1]). + + + + + Sets the ordinate of a coordinate in this sequence. + + The coordinate index. + The ordinate index in the coordinate, 0 based, + smaller than the number of dimensions. + The new ordinate value. + + Warning: for performance reasons the ordinate index is not checked: + if it is over dimensions you may not get an exception but a meaningless value. + + + + + Expands the given Envelope to include the coordinates in the sequence. + Allows implementing classes to optimize access to coordinate values. + + The envelope to expand. + A reference to the expanded envelope. + + + + Builds packed array coordinate sequences. + The array data type can be either + double or float, + and defaults to double. + + + + + An enumeration of valid type codes + + + + + Type code for arrays of type double. + + + + + Type code for arrays of type float. + + + + + A factory creating coordinate sequences + + + + + A factory creating coordinate sequences + + + + + Initializes a new instance of the class, + using double values. + + + + + Initializes a new instance of the class. + + The type. + + + + Gets the type of packed coordinate sequence this factory builds, either + or + + The type of packed array built. + + + + Returns a CoordinateSequence based on the given array; whether or not the + array is copied is implementation-dependent. + + Coordinates array, which may not be null nor contain null elements + + + + + Returns a CoordinateSequence based on the given coordinate sequence; whether or not the + array is copied is implementation-dependent. + + + + + + + Creates a packed coordinate sequence of type from the provided double array + using the provided dimension and a measure of 0. + + The array containing coordinate values + The coordinate dimension + A packed coordinate sequence of + + + + Creates a packed coordinate sequence of type from the provided double array + using the provided dimension and a measure of 0. + + The array containing coordinate values + The coordinate dimension + The coordinate measure count + A packed coordinate sequence of + + + + Creates a packed coordinate sequence of type from the provided float array + using the provided dimension and a measure of 0. + + The array containing coordinate values + The coordinate dimension + A packed coordinate sequence of + + + + Creates a packed coordinate sequence of type from the provided float array + using the provided dimension and a measure of 0. + + The array containing coordinate values + The coordinate dimension + The coordinate measure count + A packed coordinate sequence of + + + + + + + An implementation of that packs its contents in a way that + can be customized by the creator. + + + + + Initializes a new instance of the class. + + + Contains the raw data for this sequence. + + + Contains a pair of indexes to tell us, for each dimension, where to find its data in + . + + + The value for . + + + + + Gets the underlying for the ordinates at the given index, along + with a "stride" value that represents how many slots there are between elements. + + + The index of the ordinate whose values to get, from + . + + + The underlying and stride. + + + Assuming is nonzero, the first element of the + returned array holds the first coordinate's value for the requested ordinate, and the + last element of the returned array holds the last coordinate's value for the requested + ordinate. + + + + + + + + + + + + + + + + + + + + + + + Factory for creating instances. + + + + + Initializes a new instance of the class. + + + A sequence of zero or more flags representing ordinate values + that should be allocated together. + + + Thrown when is . + + + Thrown when a given flag appears in more than one element of + . + + + Any flags not represented in , and any spatial or + measure dimensions beyond the 16th, will be allocated together, SoA-style. + + Elements without any bits set will be silently ignored. + + + + + Creates a new that uses the given arrays for reading + and writing X and Y data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X values, laid out as + [x0, x1, x2, ..., xn]. + + + An array of Y values, laid out as + [y0, y1, y2, ..., yn]. + + + A instance that's backed by the given arrays. + + + Thrown when the input arrays do not contain data for the same number of coordinates. + + + + + Creates a new that uses the given array for reading + and writing X and Y data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X and Y values, laid out as + [x0, y0, x1, y1, x2, y2, ..., xn, yn]. + + + A instance that's backed by the given array. + + + The resulting instance is essentially a + with slightly more overhead, so the main reason to prefer this over that one would be if + you really need to avoid copying the data to fit it into that format. + + + Thrown when the length of is not a multiple of 2. + + + + + Creates a new that uses the given arrays for reading + and writing X, Y, and Z data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X values, laid out as + [x0, x1, x2, ..., xn]. + + + An array of Y values, laid out as + [y0, y1, y2, ..., yn]. + + + An array of Z values, laid out as + [z0, z1, z2, ..., zn]. + + + A instance that's backed by the given arrays. + + + Thrown when the input arrays do not contain data for the same number of coordinates. + + + + + Creates a new that uses the given array for reading + and writing X, Y, and Z data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X and Y values, laid out as + [x0, y0, x1, y1, x2, y2, ..., xn, yn]. + + + An array of Z values, laid out as + [z0, z1, z2, ..., zn]. + + + A instance that's backed by the given array. + + + The resulting instance is essentially a + with slightly more overhead, so the main reason to prefer this over that one would be if + you really need to avoid copying the data to fit it into that format. + + + Thrown when the length of is not a multiple of 2, or when the + input arrays do not contain data for the same number of coordinates. + + + + + Creates a new that uses the given array for reading + and writing X, Y, and Z data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X, Y, and Z values, laid out as + [x0, y0, z0, x1, y1, z1, x2, y2, z2, ..., xn, yn, zn]. + + + A instance that's backed by the given array. + + + The resulting instance is essentially a + with slightly more overhead, so the main reason to prefer this over that one would be if + you really need to avoid copying the data to fit it into that format. + + + Thrown when the length of is not a multiple of 3. + + + + + Creates a new that uses the given arrays for reading + and writing X, Y, and M data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X values, laid out as + [x0, x1, x2, ..., xn]. + + + An array of Y values, laid out as + [y0, y1, y2, ..., yn]. + + + An array of M values, laid out as + [m0, m1, m2, ..., mn]. + + + A instance that's backed by the given arrays. + + + Thrown when the input arrays do not contain data for the same number of coordinates. + + + + + Creates a new that uses the given array for reading + and writing X, Y, and M data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X and Y values, laid out as + [x0, y0, x1, y1, x2, y2, ..., xn, yn]. + + + An array of M values, laid out as + [m0, m1, m2, ..., mn]. + + + A instance that's backed by the given array. + + + The resulting instance is essentially a + with slightly more overhead, so the main reason to prefer this over that one would be if + you really need to avoid copying the data to fit it into that format. + + + Thrown when the length of is not a multiple of 2, or when the + input arrays do not contain data for the same number of coordinates. + + + + + Creates a new that uses the given array for reading + and writing X, Y, and M data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X, Y, and M values, laid out as + [x0, y0, m0, x1, y1, m1, x2, y2, m2, ..., xn, yn, mn]. + + + A instance that's backed by the given array. + + + The resulting instance is essentially a + with slightly more overhead, so the main reason to prefer this over that one would be if + you really need to avoid copying the data to fit it into that format. + + + Thrown when the length of is not a multiple of 3. + + + + + Creates a new that uses the given arrays for reading + and writing X, Y, Z, and M data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X values, laid out as + [x0, x1, x2, ..., xn]. + + + An array of Y values, laid out as + [y0, y1, y2, ..., yn]. + + + An array of Z values, laid out as + [z0, z1, z2, ..., zn]. + + + An array of M values, laid out as + [m0, m1, m2, ..., mn]. + + + A instance that's backed by the given arrays. + + + Thrown when the input arrays do not contain data for the same number of coordinates. + + + + + Creates a new that uses the given array for reading + and writing X, Y, Z, and M data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X and Y values, laid out as + [x0, y0, x1, y1, x2, y2, ..., xn, yn]. + + + An array of Z values, laid out as + [z0, z1, z2, ..., zn]. + + + An array of M values, laid out as + [m0, m1, m2, ..., mn]. + + + A instance that's backed by the given array. + + + The resulting instance is essentially a + with slightly more overhead, so the main reason to prefer this over that one would be if + you really need to avoid copying the data to fit it into that format. + + + Thrown when the length of is not a multiple of 2, or when the + input arrays do not contain data for the same number of coordinates. + + + + + Creates a new that uses the given array for reading + and writing X, Y, Z, and M data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X, Y, Z, and M values, laid out as + [x0, y0, z0, m0, x1, y1, z1, m1, x2, y2, z2, m2, ..., xn, yn, zn, mn]. + + + A instance that's backed by the given array. + + + The resulting instance is essentially a + with slightly more overhead, so the main reason to prefer this over that one would be if + you really need to avoid copying the data to fit it into that format. + + + Thrown when the length of is not a multiple of 4. + + + + + + + + Models a Dimensionally Extended Nine-Intersection Model (DE-9IM) matrix. + + + DE-9IM matrix values (such as "212FF1FF2") + specify the topological relationship between two s. + This class can also represent matrix patterns (such as "T*T******") + which are used for matching instances of DE-9IM matrices. + + DE-9IM matrices are 3x3 matrices with integer entries. + The matrix indices {0,1,2} + represent the topological locations + that occur in a geometry(Interior, Boundary, Exterior). + These are provided by the constants + , , and . + + When used to specify the topological relationship between two geometries, + the matrix entries represent the possible dimensions of each intersection: + = 2, = 1, = 0 and = -1.
+ When used to represent a matrix pattern entries can have the additional values + ("T") and ("*"). + + For a description of the DE-9IM and the spatial predicates derived from it, see the following references: + + OGC 99-049 OpenGIS Simple Features Specification for SQL. + + OGC 06-103r4 OpenGIS Implementation Standard for Geographic information - Simple feature access - Part 1: Common architecture, + Section 6.1.15 (which provides some further details on certain predicate specifications). + Wikipedia article on DE-9IM + + + Methods are provided to: + + set and query the elements of the matrix in a convenient fashion + convert to and from the standard string representation(specified in SFS Section 2.1.13.2). + test if a matrix matches a given pattern string. + test if a matrix(possibly with geometry dimensions) matches a standard named spatial predicate + +
+
+ + + Internal representation of this . + + + + + Creates an with null location values. + + + + + Creates an with the given dimension + symbols. + + A string of nine dimension symbols in row major order. + + + + Creates an with the same elements as + other. + + An to copy. + + + + Adds one matrix to another. + Addition is defined by taking the maximum dimension value of each position + in the summand matrices. + + The matrix to add. + + + + Tests if the dimension value matches TRUE + (i.e. has value 0, 1, 2 or TRUE). + + A number that can be stored in the IntersectionMatrix. + Possible values are {, , , , , } + true if the dimension value matches + + + + Tests if the dimension value satisfies the dimension symbol. + + + a number that can be stored in the IntersectionMatrix. + Possible values are {True, False, Dontcare, 0, 1, 2}. + + + A character used in the string + representation of an . + Possible values are T, F, * , 0, 1, 2. + + + true if the dimension symbol encompasses the dimension value. + + + + + Tests if each of the actual dimension symbols in a matrix string satisfies the + corresponding required dimension symbol in a pattern string. + + + Nine dimension symbols to validate. + Possible values are T, F, * , 0, 1, 2. + + + Nine dimension symbols to validate + against. Possible values are T, F, * , 0, 1, 2. + + + true if each of the required dimension + symbols encompass the corresponding actual dimension symbol. + + + + + Changes the value of one of this elements. + + + The row of this , + indicating the interior, boundary or exterior of the first + + + The column of this , + indicating the interior, boundary or exterior of the second + + The new value of the element + + + + Changes the elements of this to the + dimension symbols in dimensionSymbols. + + + Nine dimension symbols to which to set this + s elements. Possible values are {T, F, * , 0, 1, 2} + + + + + Changes the specified element to minimumDimensionValue if the element is less. + + + The row of this , + indicating the interior, boundary or exterior of the first . + + + The column of this , + indicating the interior, boundary or exterior of the second . + + + The dimension value with which to compare the + element. The order of dimension values from least to greatest is + True, False, Dontcare, 0, 1, 2. + + + + + If row >= 0 and column >= 0, changes the specified element to minimumDimensionValue + if the element is less. Does nothing if row is smaller to 0 or column is smaller to 0. + + + + + + + + For each element in this , changes the + element to the corresponding minimum dimension symbol if the element is + less. + + + Nine dimension symbols with which to + compare the elements of this . The + order of dimension values from least to greatest is Dontcare, True, False, 0, 1, 2. + + + + + Changes the elements of this to dimensionValue. + + + The dimension value to which to set this + s elements. Possible values True, False, Dontcare, 0, 1, 2}. + + + + + Returns the value of one of this s + elements. + + + The row of this , indicating + the interior, boundary or exterior of the first . + + + The column of this , + indicating the interior, boundary or exterior of the second . + + The dimension value at the given matrix position. + + + + See methods Get(int, int) and Set(int, int, int value) + + + + + Tests if this matrix matches [FF*FF****]. + + + true if the two 's related by + this matrix are disjoint. + + + + + Tests if isDisjoint returns . + + + true if the two 's related by + this matrix intersect. + + + + + Tests if this matrix matches + [FT*******], [F**T*****] or [F***T****]. + + The dimension of the first . + The dimension of the second . + + true if the two + s related by this matrix touch; Returns false + if both s are points. + + + + + Tests whether this geometry crosses the + specified geometry. + + + The crosses predicate has the following equivalent definitions: + + The geometries have some but not all interior points in common. + The DE-9IM Intersection Matrix for the two geometries matches + + [T*T******] (for P/L, P/A, and L/A situations) + [T*****T**] (for L/P, L/A, and A/L situations) + [0********] (for L/L situations) + + + For any other combination of dimensions this predicate returns false. + + The SFS defined this predicate only for P/L, P/A, L/L, and L/A situations. + JTS extends the definition to apply to L/P, A/P and A/L situations as well. + This makes the relation symmetric. + + The dimension of the first . + The dimension of the second . + + true if the two + s related by this matrix cross. + + + + + Tests whether this matrix matches [T*F**F***]. + + true if the first is within the second. + + + + Tests whether this matrix matches [T*****FF*] + + true if the first contains the second. + + + + Tests if this matrix matches + [T*****FF*] + or [*T****FF*] + or [***T**FF*] + or [****T*FF*]. + + true if the first covers the second + + + + Tests if this matrix matches + [T*F**F***] + or [*TF**F***] + or [**FT*F***] + or [**F*TF***]. + + true if the first is covered by the second + + + + Tests whether the argument dimensions are equal and + this matrix matches the pattern [T*F**FFF*]. + + Note: This pattern differs from the one stated in + Simple feature access - Part 1: Common architecture. + That document states the pattern as [TFFFTFFFT]. This would + specify that + two identical POINTs are not equal, which is not desirable behaviour. + The pattern used here has been corrected to compute equality in this situation. + + The dimension of the first . + The dimension of the second . + + true if the two s + related by this matrix are equal; the + s must have the same dimension to be equal. + + + + + Tests if this matrix matches + + [T*T***T**] (for two points or two surfaces) + [1*T***T**] (for two curves) + + + The dimension of the first . + The dimension of the second . + + true if the two + s related by this matrix overlap. For this + function to return true, the s must + be two points, two curves or two surfaces. + + + + + Tests whether this matrix matches the given matrix pattern + + + A pattern containing nine dimension symbols with which to + compare the entries of this matrix.Possible + symbol values are { T, F, * , 0, 1, 2}. + + + true if this + matches the required dimension symbols. + + + + + Transposes this IntersectionMatrix. + + This as a convenience, + + + + Returns a nine-character String representation of this . + + + The nine dimension symbols of this + in row-major order. + + + + + Interface to identify all Geometry subclasses that have a Dimension of + and have components that are s. + + Martin Davis + + + + + + Interface to identify all Geometry subclasses that have a Dimension of + and have components that ar s. + + Martin Davis + + + + + + Models an OGC SFS LinearRing. + + + A LinearRing is a which is both closed and simple. + In other words, + the first and last coordinate in the ring must be equal, + and the ring must not self-intersect. + Either orientation of the ring is allowed. + + A ring must have either 0 or 3 or more points. + The first and last points must be equal (in 2D). + If these conditions are not met, the constructors throw + an
+ A ring with 3 points is invalid, because it is collapsed + and thus has a self-intersection. It is allowed to be constructed + so that it can be represented, and repaired if needed. +
+
+ + + The minimum number of vertices allowed in a valid non-empty ring. + Empty rings with 0 vertices are also valid. + + + + + Constructs a LinearRing with the vertices specified + by the given . + + A sequence points forming a closed and simple linestring, + or null to create the empty geometry. + The factory that creates this LinearRing + If the ring is not closed, or has too few points + + + + + + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + Returns Dimensions.False, since by definition LinearRings do not have a boundary. + + + + + + + + + + Returns the name of this object's interface. + + "LinearRing" + + + > + + + + + + + The actual implementation of the function for LINEARRINGs. + + A reversed geometry + + + + Gets a value indicating if this LINEARRING is oriented + + + + + Initializes a new instance of the class. + + The points used for create this instance. + + For create this is used a standard + with == . + + If the ring is not closed, or has too few points + + + + An enumeration of ring orientation values + + + + + The orientation of the ring's coordinates is counter-clockwise. + + + + + The orientation of the ring's coordinates follows the left-hand-rule, + saying that if you follow the ring in the direction of its coordinates + your left hand will be inside the ring. + + + + + + The orientation of the ring's coordinates is counter-clockwise. + + + + + The orientation of the rings coordinates does not matter. + + + + + The default orientation of the rings coordinates. + Set to + + + + + The orientation of the ring's coordinates is clockwise. + + + + + The orientation of the ring's coordinates follows the right-hand-rule, + saying that if you follow the ring in the direction of its coordinates + your right hand will be inside the ring. + + + + + + The orientation of the ring's coordinates is clockwise. + + + + + Represents a line segment defined by two Coordinates. + Provides methods to compute various geometric properties + and relationships of line segments. + This class is designed to be easily mutable (to the extent of + having its contained points public). + This supports a common pattern of reusing a single LineSegment + object as a way of computing segment properties on the + segments defined by arrays or lists of Coordinates. + + + + + The end-point + + + + + The start-point + + + + + Creates an instance of this class using two coordinates + + The start-point + The end-point + + + + Creates an instance of this class using another instance + + + + + + + + + + + Creates an instance of this class + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gets the minimum X ordinate + + + + + Gets the maximum X ordinate + + + + + Gets the minimum Y ordinate + + + + + Gets the maximum Y ordinate + + + + + Computes the length of the line segment. + + The length of the line segment. + + + + Tests whether the segment is horizontal. + + true if the segment is horizontal. + + + + Tests whether the segment is vertical. + + true if the segment is vertical. + + + + Determines the orientation of a LineSegment relative to this segment. + The concept of orientation is specified as follows: + Given two line segments A and L, + A is to the left of a segment L if A lies wholly in the + closed half-plane lying to the left of L + A is to the right of a segment L if A lies wholly in the + closed half-plane lying to the right of L + otherwise, A has indeterminate orientation relative to L. This + happens if A is collinear with L or if A crosses the line determined by L. + + The LineSegment to compare. + + 1 if seg is to the left of this segment, + -1 if seg is to the right of this segment, + 0 if seg is collinear to or crosses this segment. + + + + + Determines the orientation index of a relative to this segment. + The orientation index is as defined in . + + + + + 1if p is to the left of this segment + -1if p is to the right of this segment + 0if p is collinear with this segment + " + + + + + + Reverses the direction of the line segment. + + + + + Puts the line segment into a normalized form. + This is useful for using line segments in maps and indexes when + topological equality rather than exact equality is desired. + + + + + The angle this segment makes with the x-axis (in radians). + + + + The midpoint of the segment + + + + Computes the distance between this line segment and another one. + + + + + + + Computes the distance between this line segment and a point. + + + + + Computes the perpendicular distance between the (infinite) line defined + by this line segment and a point. + + + + + + + Computes the that lies a given + fraction along the line defined by this segment. + + + A fraction of 0.0 returns the start point of the segment; + A fraction of 1.0 returns the end point of the segment. + If the fraction is < 0.0 or > 1.0 the point returned + will lie before the start or beyond the end of the segment. + + the fraction of the segment length along the line + the point at that distance + + + + Computes the that lies a given + + + A fraction along the line defined by this segment and offset from + the segment by a given distance. + A fraction of 0.0 offsets from the start point of the segment; + A fraction of 1.0 offsets from the end point of the segment. + The computed point is offset to the left of the line if the offset distance is + positive, to the right if negative. + + the fraction of the segment length along the line + the distance the point is offset from the segment + (positive is to the left, negative is to the right) + the point at that distance and offset + if the segment has zero length + + + Computes the Projection Factor for the projection of the point p + onto this LineSegment. The Projection Factor is the constant r + by which the vector for this segment must be multiplied to + equal the vector for the projection of p on the line + defined by this segment. + + The projection factor will lie in the range (-inf, +inf), + or be NaN if the line segment has zero length. + + The point to compute the factor for + The projection factor for the point + + + + Computes the fraction of distance (in [0.0, 1.0]) + that the projection of a point occurs along this line segment. + If the point is beyond either ends of the line segment, + the closest fractional value (0.0 or 1.0) is returned. + + + Essentially, this is the clamped to + the range [0.0, 1.0]. + + the point + the fraction along the line segment the projection of the point occurs + + + + Compute the projection of a point onto the line determined + by this line segment. + Note that the projected point may lie outside the line segment. + If this is the case, the projection factor will lie outside the range [0.0, 1.0]. + + + + + + + Project a line segment onto this line segment and return the resulting + line segment. The returned line segment will be a subset of + the target line line segment. This subset may be null, if + the segments are oriented in such a way that there is no projection. + Note that the returned line may have zero length (i.e. the same endpoints). + This can happen for instance if the lines are perpendicular to one another. + + The line segment to project. + The projected line segment, or null if there is no overlap. + + + + Computes the that is offset from + the segment by a given distance. + The computed segment is offset to the left of the line if the offset distance is + positive, to the right if negative. + + The distance the point is offset from the segment + (positive is to the left, negative is to the right) + A line segment offset by the specified distance + Thrown if the segment has zero length + + + + Computes the closest point on this line segment to another point. + + The point to find the closest point to. + + A Coordinate which is the closest point on the line segment to the point p. + + + + + Computes the closest points on a line segment. + + + + A pair of Coordinates which are the closest points on the line segments. + + + + + Computes the reflection of a point in the line defined + by this line segment. + + The point to reflect + The reflected point + + + + Computes an intersection point between two segments, if there is one. + There may be 0, 1 or many intersection points between two segments. + If there are 0, null is returned. If there is 1 or more, a single one + is returned (chosen at the discretion of the algorithm). If + more information is required about the details of the intersection, + the class should be used. + + A line segment + An intersection point, or null if there is none. + + + + + Computes the intersection point of the lines defined by two segments, if there is one. + + + There may be 0, 1 or an infinite number of intersection points between two lines. + If there is a unique intersection point, it is returned. + Otherwise, null is returned. + If more information is required about the details of the intersection, + the class should be used. + + A line segment defining a straight line + An intersection point, or null if there is none or an infinite number + + + + + Creates a LineString with the same coordinates as this segment + + the geometry factory to use + A LineString with the same geometry as this segment + + + + Returns true if o has the same values for its points. + + A LineSegment with which to do the comparison. + + true if o is a LineSegment + with the same values for the x and y ordinates. + + + + + + + + + + + + + + + + + + + + + Compares this object with the specified object for order. + Uses the standard lexicographic ordering for the points in the LineSegment. + + + The LineSegment with which this LineSegment + is being compared. + + + A negative integer, zero, or a positive integer as this LineSegment + is less than, equal to, or greater than the specified LineSegment. + + + + + Returns true if other is + topologically equal to this LineSegment (e.g. irrespective + of orientation). + + + A LineSegment with which to do the comparison. + + + true if other is a LineSegment + with the same values for the x and y ordinates. + + + + + + + + + + + + Return HashCode. + + + + + Models an OGC-style LineString + + + A LineString consists of a sequence of two or more vertices, + along with all points along the linearly-interpolated curves + (line segments) between each + pair of consecutive vertices. + Consecutive vertices may be equal. + The line segments in the line may intersect each other (in other words, + the LineString may "curl back" in itself and self-intersect. + LineStrings with exactly two identical points are invalid. + A LineString must have either 0 or 2 or more points. + If these conditions are not met, the constructors throw an . + + + + + + Represents an empty LineString. + + + + + The points of this LineString. + + + + + Initializes a new instance of the class. + + + For create this is used a standard + with == . + + The coordinates used for create this . + If too few points are provided + + + + Initializes a new instance of the class. + + + The points of the LineString, or null + to create the empty point. Consecutive points may not be equal. + + + If too few points are provided + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + Returns an array containing the values of all the vertices for + this geometry. + + + If the geometry is a composite, the array will contain all the vertices + for the components, in the order in which the components occur in the geometry. + + In general, the array cannot be assumed to be the actual internal + storage for the vertices. Thus modifying the array + may not modify the geometry itself. + Use the method + (possibly on the components) to modify the underlying data. + If the coordinates are modified, + must be called afterwards. + + + The vertices of this Geometry. + + + + + + + Gets an array of ordinate values + + The ordinate index + An array of ordinate values + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gets + + + + + + + Gets a value indicating the start point of this LINESTRING + + + + + Gets a value indicating the end point of this LINESTRING + + + + + Gets a value indicating if this LINESTRING is closed. + + + + + Gets a value indicating if this LINESTRING forms a ring. + + + + + Returns the name of this object's interface. + + "LineString" + + + + Gets the OGC geometry type + + + + + Returns the length of this LineString + + The length of the polygon. + + + + Returns the boundary, or an empty geometry of appropriate dimension + if this Geometry is empty. + For a discussion of this function, see the OpenGIS Simple + Features Specification. As stated in SFS Section 2.1.13.1, "the boundary + of a Geometry is a set of Geometries of the next lower dimension." + + The closure of the combinatorial boundary of this Geometry. + + + + Creates a whose coordinates are in the reverse order of this objects. + + A with coordinates in the reverse order. + + + + The actual implementation of the function for LINESTRINGs. + + A reversed geometry + + + + Returns true if the given point is a vertex of this LineString. + + The Coordinate to check. + true if pt is one of this LineString's vertices. + + + + + + + + + + + + + + + + + + + + + + + + Performs an operation on the coordinates in this Geometry's s. + + + If the filter reports that a coordinate value has been changed, + will be called automatically. + + The filter to apply + + + + + + + Performs an operation with or on this Geometry and its + subelement Geometrys (if any). + Only GeometryCollections and subclasses + have subelement Geometry's. + + + The filter to apply to this Geometry (and + its children, if it is a GeometryCollection). + + + + + Performs an operation with or on this Geometry and its + component Geometry's. Only GeometryCollections and + Polygons have component Geometry's; for Polygons they are the LinearRings + of the shell and holes. + + The filter to apply to this Geometry. + + + > + + + + Normalizes a LineString. A normalized LineString + has the first point which is not equal to it's reflected point + less than the reflected point. + + + + + + + + + + + + + + + + + + + + + + + + + + + The location of a relative to a + + + + + DE-9IM row index of the interior of the first point and column index of + the interior of the second point. Location value for the interior of a + point. + + int value = 0; + + + + DE-9IM row index of the boundary of the first point and column index of + the boundary of the second point. Location value for the boundary of a + point. + + int value = 1; + + + + DE-9IM row index of the exterior of the first point and column index of + the exterior of the second point. Location value for the exterior of a + point. + + int value = 2; + + + + Used for uninitialized location values. + + int value = 1; + + + + Utility class for enumeration + + + + + Converts the location value to a location symbol, for example, EXTERIOR => 'e'. + + + Either 'e', 'b', 'i' or '-'. + + + + Models a collection of s. + + Any collection of LineStrings is a valid MultiLineString. + + + + + Represents an empty MultiLineString. + + + + + Constructs a MultiLineString. + + + The LineStrings for this MultiLineString, + or null or an empty array to create the empty + point. Elements may be empty LineStrings, + but not nulls. + + + + + + Constructs a MultiLineString. + + + The LineStrings for this MultiLineString, + or null or an empty array to create the empty + point. Elements may be empty LineStrings, + but not nulls. + + + For create this is used a standard + with == . + + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + + + + + + + + + + + + + Returns the name of this object's interface. + + "MultiLineString" + + + + Gets the OGC geometry type + + + + + Gets a value indicating whether this instance is closed. + + true if this instance is closed; otherwise, false. + + + + Creates a in the reverse order to this object. + Both the order of the component LineStrings + and the order of their coordinate sequences are reversed. + + a in the reverse order. + + + + + + > + + + + + + + + + + + + Models a collection of Points. + + + + + Represents an empty MultiPoint. + + + + + Constructs a MultiPoint. + + + The Points for this MultiPoint + , or null or an empty array to create the empty point. + Elements may be empty Points, but not nulls. + + + + + + Constructs a MultiPoint. + + + The Points for this MultiPoint + , or null or an empty array to create the empty point. + Elements may be empty Points, but not nulls. + + + For create this is used a standard + with == . + + + + > + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + + + + + + + + + + + Returns the name of this object's interface. + + "MultiPoint" + + + + Gets the boundary of this geometry. + Zero-dimensional geometries have no boundary by definition, + so an empty GeometryCollection is returned. + + + + + + + + + + + + + + + + + + + Returns the Coordinate at the given position. + + The index of the Coordinate to retrieve, beginning at 0. + + The nth Coordinate. + + + + Basic implementation of MultiPolygon. + + + + + Represents an empty MultiPolygon. + + + + + Constructs a MultiPolygon. + + + The Polygons for this MultiPolygon + , or null or an empty array to create the empty point. + Elements may be empty Polygons, but not null + s. The polygons must conform to the assertions specified in the + OpenGIS Simple Features + Specification for SQL. + + + For create this is used a standard + with == . + + + + + Constructs a MultiPolygon. + + + The Polygons for this MultiPolygon + , or null or an empty array to create the empty point. + Elements may be empty Polygons, but not null + s. The polygons must conform to the assertions specified in the + OpenGIS Simple Features + Specification for SQL. + + + + + > + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + + + + + + + + + + + Returns the name of this object's interface. + + "MultiPolygon" + + + > + + + + + + + + + + + + + + + + + Creates a with every component reversed. + + The order of the components in the collection are not reversed. + An in the reverse order + + + + + + + A bounding container for a which is in the shape of a general octagon. + + + The OctagonalEnvelope of a geometric object + is a geometry which is tight bound along the (up to) four extremal rectilinear parallels + and along the (up to) four extremal diagonal parallels. + Depending on the shape of the contained + geometry, the octagon may be degenerate to any extreme + (e.g. it may be a rectangle, a line, or a point). + + + + + Gets the octagonal envelope of a geometry + + The geometry + The octagonal envelope of the geometry + + + + Creates a new null bounding octagon + + + + + Creates a new null bounding octagon bounding a + + The coordinate to bound + + + + Creates a new null bounding octagon bounding a pair of s + + A coordinate to bound + A coordinate to bound + + + + Creates a new null bounding octagon bounding an + + + + + Creates a new null bounding octagon bounding an + (the copy constructor). + + + + + Creates a new null bounding octagon bounding a + + + + + Gets a value indicating the minimal x-ordinate value + + + + + Gets a value indicating the maximal x-ordinate value + + + + + Gets a value indicating the minimal y-ordinate value + + + + + Gets a value indicating the maximal y-ordinate value + + + + + Gets a value indicating the minimal a value + + + + + Gets a value indicating the maximal a value + + + + + Gets a value indicating the minimal b value + + + + + Gets a value indicating the maximal b value + + + + + Gets a value indicating that this object is null + + + + + Method to expand this to include the provided geometry. + + The geometry + + + + Method to expand this to include the provided coordinate sequence. + + The coordinate sequence + A reference to this octagonal envelope, expanded by + + + + Method to expand this to include the provided OctogonalEnvelope. + + The OctogonalEnvelope + A reference to this octagonal envelope, expanded by + + + + Function to expand this to include the provided coordinate. + + The coordinate + A reference to this octagonal envelope, expanded by + + + + Function to expand this to include the provided envelope. + + The envelope + A reference to this octagonal envelope, expanded by + + + + Function to expand this to include the provided - and ordinates. + + A x-ordinate value + A y-ordinate value + A reference to this octagonal envelope, expanded by and + + + + Gets a value indicating if the extremal values for this octagon are valid. + + true if this object has valid values + + + + Function to test if this octagonal envelope intersects octagonal envelope . + + An octagonal envelope + true if this octagonal envelope intersects octagonal envelope . + + + + Function to test if this octagonal envelope contains coordinate. + + A coordinate + true if this octagonal envelope contains coordinate. + + + + Function to test if this octagonal envelope contains octagonal envelope. + + An octagonal envelope + true if this octagonal envelope contains octagonal envelope. + + + + Function to convert this octagonal envelope into a geometry + + The factory to create the geometry + A geometry + + + + OGC compliant geometry factory + + + + + Creates an instance of this class using the default + values for , + and + . + + + + + Creates an instance of this class using the default + values for , + , + but the specified . + + + + Creates an instance of this class using the default + values for , + but the + specified . + + + + + + + + The is guaranteed to be orientated counter-clockwise. + + + + + + The is guaranteed to be orientated counter-clockwise. + + + + + + The is guaranteed to be orientated counter-clockwise. + + + + + + The is guaranteed to be orientated counter-clockwise. +
The are guaranteed to be orientated clockwise. +
+
+ + + Enumeration of OGC Geometry Types + + + + + Point. + + + + + LineString. + + + + + Polygon. + + + + + MultiPoint. + + + + + MultiLineString. + + + + + MultiPolygon. + + + + + GeometryCollection. + + + + + CircularString + + + + + CompoundCurve + + + + + CurvePolygon + + + + + MultiCurve + + + + + MultiSurface + + + + + Curve + + + + + Surface + + + + + PolyhedralSurface + + + + + TIN + + + + + Identifies the different well-supported components of coordinate values. + + All supported coordinates define values for at least the X and the Y components. + + + The first 16 spatial and 16 measure dimensions may also be accessed this way. + + + + + + The 1st spatial dimension. + + + + + The "X" ordinate. + + + + + The 2nd spatial dimension. + + + + + The "Y" ordinate. + + + + + The 3rd spatial dimension. + + + + + The "Z" ordinate. + + + + + The 4th spatial dimension. + + + + + The 5th spatial dimension. + + + + + The 6th spatial dimension. + + + + + The 7th spatial dimension. + + + + + The 8th spatial dimension. + + + + + The 9th spatial dimension. + + + + + The 10th spatial dimension. + + + + + The 11th spatial dimension. + + + + + The 12th spatial dimension. + + + + + The 13th spatial dimension. + + + + + The 14th spatial dimension. + + + + + The 15th spatial dimension. + + + + + The 16th spatial dimension. + + + + + The 1st measure dimension. + + + + + The "M" ordinate. + + + + + The 2nd measure dimension. + + + + + The 3rd measure dimension. + + + + + The 4th measure dimension. + + + + + The 5th measure dimension. + + + + + The 6th measure dimension. + + + + + The 7th measure dimension. + + + + + The 8th measure dimension. + + + + + The 9th measure dimension. + + + + + The 10th measure dimension. + + + + + The 11th measure dimension. + + + + + The 12th measure dimension. + + + + + The 13th measure dimension. + + + + + The 14th measure dimension. + + + + + The 15th measure dimension. + + + + + The 16th measure dimension. + + + + + Flags for Ordinate values + + + + + No ordinates + + + + + Flag for the x-ordinate + + + + + Flag for the y-ordinate + + + + + Flag for the z-ordinate + + + + + Flag for the m-ordinate + + + + + Flag for both x- and y-ordinate + + + + + Flag for x-, y- and z-ordinate + + + + + Flag for x-, y- and m-ordinate + + + + + Flag for x-, y-, z- and m-ordinate + + + + + Flag for the 1st spatial dimension. + + + + + Flag for the 2nd spatial dimension. + + + + + Flag for the 3rd spatial dimension. + + + + + Flag for the 4th spatial dimension. + + + + + Flag for the 5th spatial dimension. + + + + + Flag for the 6th spatial dimension. + + + + + Flag for the 7th spatial dimension. + + + + + Flag for the 8th spatial dimension. + + + + + Flag for the 9th spatial dimension. + + + + + Flag for the 10th spatial dimension. + + + + + Flag for the 11th spatial dimension. + + + + + Flag for the 12th spatial dimension. + + + + + Flag for the 13th spatial dimension. + + + + + Flag for the 14th spatial dimension. + + + + + Flag for the 15th spatial dimension. + + + + + Flag for the 16th spatial dimension. + + + + + Flags for all spatial ordinates. + + + + + Flag for the 1st measure dimension. + + + + + Flag for the 2nd measure dimension. + + + + + Flag for the 3rd measure dimension. + + + + + Flag for the 4th measure dimension. + + + + + Flag for the 5th measure dimension. + + + + + Flag for the 6th measure dimension. + + + + + Flag for the 7th measure dimension. + + + + + Flag for the 8th measure dimension. + + + + + Flag for the 9th measure dimension. + + + + + Flag for the 10th measure dimension. + + + + + Flag for the 11th measure dimension. + + + + + Flag for the 12th measure dimension. + + + + + Flag for the 13th measure dimension. + + + + + Flag for the 14th measure dimension. + + + + + Flag for the 15th measure dimension. + + + + + Flag for the 16th measure dimension. + + + + + Flags for all non-spatial ordinates. + + + + + Flags for all recognized ordinates. + + + + + Static utility functions for dealing with and dimension + + + + + Translates the -flag to a number of dimensions. + + The ordinates flag + The number of dimensions + + + + Translates the -flag to a number of measures. + + The ordinates flag + The number of measures + + + + Represents a single point. + + A Point is topologically valid if and only if: + + The coordinate which defines it if any) is a valid coordinate + (i.e. does not have an NaN X- or Y-ordinate + + + + + + + Represents an empty Point. + + + + + The Coordinate wrapped by this Point. + + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + + + + + + Initializes a new instance of the class. + + The coordinate used for create this . + + For create this is used a standard + with == . + + + + + Constructs a Point with the given coordinate. + + + Contains the single coordinate on which to base this Point, + or null to create the empty point. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Returns the name of this object's interface. + + "Point" + + + + Gets the OGC geometry type + + + + + Gets the boundary of this geometry. + Zero-dimensional geometries have no boundary by definition, + so an empty GeometryCollection is returned. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + > + + + + + + + The actual implementation of the function for POINTs. + + A reversed geometry + + + + + + + + + + + + + + + + + + + + + + Initializes a new instance of the class. + + The x coordinate. + The y coordinate. + The z coordinate. + /// + For create this is used a standard + with set to . + + + + + Initializes a new instance of the class. + + The x coordinate. + The y coordinate. + /// + For create this is used a standard + with set to . + + + + + + + + + + Represents a polygon with linear edges, which may include holes. + The outer boundary (shell) + and inner boundaries (holes) of the polygon are represented by {@link LinearRing}s. + The boundary rings of the polygon may have any orientation. + Polygons are closed, simple geometries by definition. + + The polygon model conforms to the assertions specified in the + OpenGIS Simple Features + Specification for SQL. + + A Polygon is topologically valid if and only if: + + the coordinates which define it are valid coordinates + the linear rings for the shell and holes are valid + (i.e. are closed and do not self-intersect) + holes touch the shell or another hole at at most one point + (which implies that the rings of the shell and holes must not cross) + the interior of the polygon is connected, + or equivalently no sequence of touching holes + makes the interior of the polygon disconnected + (i.e. effectively split the polygon into two pieces). + + + + + + Represents an empty Polygon. + + + + + The exterior boundary, or null if this Polygon + is the empty point. + + + + + The interior boundaries, if any. + + + + + Initializes a new instance of the class. + + + The outer boundary of the new Polygon, + or null or an empty LinearRing if the empty + point is to be created. + + + The inner boundaries of the new Polygon + , or null or empty LinearRings if the empty + point is to be created. + + + For create this is used a standard + with == . + + + + + Constructs a Polygon with the given exterior boundary and + interior boundaries. + + + The outer boundary of the new Polygon, + or null or an empty LinearRing if the empty + point is to be created. + + + The inner boundaries of the new Polygon + , or null or empty LinearRings if the empty + point is to be created. + + + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + Returns a vertex of this Geometry + (usually, but not necessarily, the first one). + + + The returned coordinate should not be assumed to be an actual Coordinate object used in the internal representation. + + a Coordinate which is a vertex of this Geometry. + null if this Geometry is empty. + + + + + Returns an array containing the values of all the vertices for + this geometry. + + + If the geometry is a composite, the array will contain all the vertices + for the components, in the order in which the components occur in the geometry. + + In general, the array cannot be assumed to be the actual internal + storage for the vertices. Thus modifying the array + may not modify the geometry itself. + Use the method + (possibly on the components) to modify the underlying data. + If the coordinates are modified, + must be called afterwards. + + + The vertices of this Geometry. + + + + + + + Gets an array of ordinate values + + The ordinate index + An array of ordinate values + + + + Returns the count of this Geometrys vertices. The Geometry + s contained by composite Geometrys must be + Geometry's; that is, they must implement NumPoints. + + The number of vertices in this Geometry. + + + + Returns the dimension of this geometry. + + + The dimension of a geometry is is the topological + dimension of its embedding in the 2-D Euclidean plane. + In the NTS spatial model, dimension values are in the set {0,1,2}. + + Note that this is a different concept to the dimension of + the vertex s. + The geometry dimension can never be greater than the coordinate dimension. + For example, a 0-dimensional geometry (e.g. a Point) + may have a coordinate dimension of 3 (X,Y,Z). + + + + The topological dimensions of this geometry + + + + + Returns the dimension of this Geometrys inherent boundary. + + + The dimension of the boundary of the class implementing this + interface, whether or not this object is the empty point. Returns + Dimension.False if the boundary is the empty point. + + NOTE: make abstract and remove setter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Returns the name of this object's interface. + + "Polygon" + + + + + + + Returns the area of this Polygon + + + + + + Returns the perimeter of this Polygon. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tests whether this is a rectangular . + + true if the geometry is a rectangle. + + + + + + + The actual implementation of the function for POLYGONs + + A reversed geometry + + + + Constructs a Polygon with the given exterior boundary. + + + The outer boundary of the new Polygon, + or null or an empty LinearRing if the empty + polygon is to be created. + + + + + + Constructs a Polygon with the given exterior boundary. + + + The outer boundary of the new Polygon, + or null or an empty LinearRing if the empty + polygon is to be created. + + + + + + + + + + + + + + + Indicates the position of a location relative to a + node or edge component of a planar topological structure. + + + + + Specifies that a location is on a component + + 0 + + + + Specifies that a location is to the left of a component + + 1 + + + + Specifies that a location is to the right of a component + + 2 + + + + Specifies that a location is is parallel to x-axis of a component + + -1 + + + + Creates a new position index + + A position index + + + + Gets a value indicating the position index + + + + + Returns if the position is , + if the position is , or the position + otherwise. + + + + + Equality comparer for indices + + The position index on the left-hand-side + The position index on the right-hand-side + true if both indices are equal. + + + + Inequality comparer for indices + + The position index on the left-hand-side + The position index on the right-hand-side + true if both indices are not equal. + + + + Implicit conversion operator for to conversion. + + The position index + + + + Specifies the precision model of the Coordinates in a Geometry. + In other words, specifies the grid of allowable points for a Geometry. + A precision model may befloating ( or ), + in which case normal floating-point value semantics apply. + + + For a precision model the + method allows rounding a + coordinate to a "precise" value; that is, one whose precision + is known exactly. + + Coordinates are assumed to be precise in geometries. + That is, the coordinates are assumed to be rounded to the + precision model given for the geometry. + + All internal operations + assume that coordinates are rounded to the precision model. + Constructive methods (such as bool operations) always round computed + coordinates to the appropriate precision model.
+ Three types of precision model are supported: + + FloatingRepresents full double precision floating point. + This is the default precision model used in NTS + FloatingSingleRepresents single precision floating point + FixedRepresents a model with a fixed number of decimal places. + A Fixed Precision Model is specified by a scale factor. + The scale factor specifies the size of the grid which numbers are rounded to. + + Input coordinates are mapped to fixed coordinates according to the following + equations: + + jtsPt.X = Math.Round( inputPt.X * scale, MidPointRounding.AwayFromZero ) / scale ) + jtsPt.Y = Math.Round( inputPt.Y * scale, MidPointRounding.AwayFromZero ) / scale ) + + + For example, to specify 3 decimal places of precision, use a scale factor + of 1000. To specify -3 decimal places of precision (i.e. rounding to + the nearest 1000), use a scale factor of 0.001. + + It is also supported to specify a precise grid size + by providing it as a negative scale factor. + This allows setting a precise grid size rather than using a fractional scale, + which provides more accurate and robust rounding. + For example, to specify rounding to the nearest 1000 use a scale factor of -1000. + + Coordinates are represented internally as Java double-precision values. + .NET uses the IEEE-394 floating point standard, which + provides 53 bits of precision. (Thus the maximum precisely representable + integer is 9,007,199,254,740,992 - or almost 16 decimal digits of precision). +
+
+ + + Determines which of two s is the most precise + + A precision model + A precision model + The PrecisionModel which is most precise + + + + The maximum precise value representable in a double. Since IEE754 + double-precision numbers allow 53 bits of mantissa, the value is equal to + 2^53 - 1. This provides almost 16 decimal digits of precision. + + + + + The type of PrecisionModel this represents. + + + + + The scale factor which determines the number of decimal places in fixed precision. + + + + + If non-zero, the precise grid size specified. + In this case, the scale is also valid and is computed from the grid size. + If zero, the scale is used to compute the grid size where needed. + + + + + Gets a value indicating a precision model with double precision. + + A double precision model + + + + Gets a value indicating a precision model with single precision. + + A single precision model + + + + Gets a value indicating a precision model with a scale of 1. + + A fixed precision model + + + + Creates a PrecisionModel with a default precision + of Floating. + + + + + Creates a PrecisionModel that specifies + an explicit precision model type. + If the model type is Fixed the scale factor will default to 1. + + + The type of the precision model. + + + + + Creates a PrecisionModel that specifies Fixed precision. + Fixed-precision coordinates are represented as precise internal coordinates, + which are rounded to the grid defined by the scale factor. + + The provided scale may be negative, to specify an exact grid size. + The scale is then computed as the reciprocal. + + + Amount by which to multiply a coordinate, to obtain a precise coordinate. + Must be non-zero + + + + + Copy constructor to create a new PrecisionModel + from an existing one. + + + + + + Tests whether the precision model supports floating point. + + true if the precision model supports floating point. + + + + Returns the maximum number of significant digits provided by this + precision model. + Intended for use by routines which need to print out precise values. + + + The maximum number of decimal places provided by this precision model. + + + + + Returns the scale factor used to specify a fixed precision model. + + + The number of decimal places of precision is + equal to the base-10 logarithm of the scale factor. + Non-integral and negative scale factors are supported. + Negative scale factors indicate that the places + of precision is to the left of the decimal point. + + + The scale factor for the fixed precision model + + + + + Computes the grid size for a fixed precision model. + This is equal to the reciprocal of the scale factor. + If the grid size has been set explicity (via a negative scale factor) + it will be returned. + + The grid size at a fixed precision scale. + + + + Gets the type of this PrecisionModel. + + + + + + Rounds a numeric value to the PrecisionModel grid. + Symmetric Arithmetic Rounding is used, to provide + uniform rounding behaviour no matter where the number is + on the number line. + + + This method has no effect on NaN values + + + + + + Rounds a Coordinate to the PrecisionModel grid. + + + + + + + + + + + + + + + + + + > + + + + + + + + + + + + + + + + + + + + + + + + + + + Compares this PrecisionModel object with the specified object for order. + A PrecisionModel is greater than another if it provides greater precision. + The comparison is based on the value returned by the + {getMaximumSignificantDigits) method. + This comparison is not strictly accurate when comparing floating precision models + to fixed models; however, it is correct when both models are either floating or fixed. + + + The PrecisionModel with which this PrecisionModel + is being compared. + + + A negative integer, zero, or a positive integer as this PrecisionModel + is less than, equal to, or greater than the specified PrecisionModel. + + + + + + + + + + + + + + + + + Floating precision corresponds to the standard + double-precision floating-point representation, which is + based on the IEEE-754 standard + + + + + Floating single precision corresponds to the standard + single-precision floating-point representation, which is + based on the IEEE-754 standard + + + + + Fixed Precision indicates that coordinates have a fixed number of decimal places. + The number of decimal places is determined by the log10 of the scale factor. + + + + + A base class containing the logic for computes the contains + and covers spatial relationship predicates + for a relative to all other classes. + Uses short-circuit tests and indexing to improve performance. + + + + Contains and covers are very similar, and differ only in how certain + cases along the boundary are handled. These cases require + full topological evaluation to handle, so all the code in + this class is common to both predicates. + + + It is not possible to short-circuit in all cases, in particular + in the case where line segments of the test geometry touches the polygon linework. + In this case full topology must be computed. + (However, if the test geometry consists of only points, this + can be evaluated in an optimized fashion. + + + Martin Davis + + + + This flag controls a difference between contains and covers. + For contains the value is true. + For covers the value is false. + + + + + Creates an instance of this operation. + + The PreparedPolygon to evaluate + + + + Evaluate the contains or covers relationship + for the given geometry. + + the test geometry + true if the test geometry is contained + + + + Evaluation optimized for Point geometries. + This provides about a 2x performance increase, and less memory usage. + + A Point or MultiPoint geometry + The value of the predicate being evaluated + + + + Tests whether a geometry consists of a single polygon with no holes. + + True if the geometry is a single polygon with no holes + + + + Computes the full topological predicate. + Used when short-circuit tests are not conclusive. + + The test geometry + true if this prepared polygon has the relationship with the test geometry + + + + A base class for subclasses. + + + Contains default implementations for methods, which simply delegate to the equivalent methods. + This class may be used as a "no-op" class for Geometry types which do not have a corresponding implementation. + + Martin Davis + + + + Gets the list of representative points for this geometry. + One vertex is included for every component of the geometry + (i.e. including one for every ring of polygonal geometries). + + Do not modify the returned list! + + + + + Tests whether any representative of the target geometry intersects the test geometry. + This is useful in A/A, A/L, A/P, L/P, and P/P cases. + + The test geometry + true if any component intersects the areal test geometry + + + + Determines whether a Geometry g interacts with this geometry by testing the geometry envelopes. + + A geometry + true if the envelopes intersect + + + + Determines whether the envelope of this geometry covers the Geometry g. + + A geometry + true if g is contained in this envelope + + + + Tests whether the base contains a given geometry. + + The Geometry to test + true if this Geometry contains the given Geometry + + Default implementation. + + + + Tests whether the base properly contains a given geometry. + + The ContainsProperly predicate has the following equivalent definitions: + + Every point of the other geometry is a point of this geometry's interior. + The DE-9IM Intersection Matrix for the two geometries matches >[T**FF*FF*] + + In other words, if the test geometry has any interaction with the boundary of the target + geometry the result of ContainsProperly is false. + This is different semantics to the predicate, + in which test geometries can intersect the target's boundary and still be contained. + + The advantage of using this predicate is that it can be computed + efficiently, since it avoids the need to compute the full topological relationship + of the input boundaries in cases where they intersect. + + An example use case is computing the intersections + of a set of geometries with a large polygonal geometry. + Since intersection is a fairly slow operation, it can be more efficient + to use to filter out test geometries which lie + wholly inside the area. In these cases the intersection is + known a priori to be simply the original test geometry. + + The geometry to test + true if this geometry properly contains the given geometry + + Default implementation. + + + + + Tests whether the base is covered by a given geometry. + + The geometry to test + true if this geometry is covered by the given geometry + + Default implementation. + + + + Tests whether the base covers a given geometry. + + The geometry to test + true if this geometry covers the given geometry + + Default implementation. + + + + Tests whether the base crosses a given geometry. + + The geometry to test + true if this geometry crosses the given geometry + + Default implementation. + + + + Tests whether the base is disjoint from given geometry. + + The geometry to test + true if this geometry is disjoint from the given geometry + + Standard implementation for all geometries. + + + + Tests whether the base intersects a given geometry. + + The geometry to test + true if this geometry intersects the given geometry + + Default implementation. + + + + Tests whether the base overlaps a given geometry. + + The geometry to test + true if this geometry overlaps the given geometry + + Default implementation. + + + + Tests whether the base touches a given geometry. + + The geometry to test + true if this geometry touches the given geometry + + Default implementation. + + + + Tests whether the base is within a given geometry. + + The geometry to test + true if this geometry is within the given geometry + + Default implementation. + + + + + + + An interface for classes which prepare s + in order to optimize the performance of repeated calls to specific geometric operations. + + + + A given implementation may provide optimized implementations + for only some of the specified methods, and delegate the remaining + methods to the original operations. + + + An implementation may also only optimize certain situations, and delegate others. + See the implementing classes for documentation about which methods and situations + they optimize. + + Subclasses are intended to be thread-safe, to allow IPreparedGeometry + to be used in a multi-threaded context + (which allows extracting maximum benefit from the prepared state). + + + Martin Davis + + + + Gets the original which has been prepared. + + + + + Tests whether the base contains a given geometry. + + The Geometry to test + true if this Geometry contains the given Geometry + + + + + Tests whether the base contains a given geometry. + + + + The ContainsProperly predicate has the following equivalent definitions: + + Every point of the other geometry is a point of this geometry's interior. + The DE-9IM Intersection Matrix for the two geometries matches >[T**FF*FF*] + + The advantage to using this predicate is that it can be computed + efficiently, with no need to compute topology at individual points. + + + An example use case for this predicate is computing the intersections + of a set of geometries with a large polygonal geometry. + Since intersection is a fairly slow operation, it can be more efficient + to use containsProperly to filter out test geometries which lie + wholly inside the area. In these cases the intersection + known a priori to be simply the original test geometry. + + + The geometry to test + true if this geometry properly contains the given geometry + + + + Tests whether the base is covered by a given geometry. + + The geometry to test + true if this geometry is covered by the given geometry + + + + + Tests whether the base covers a given geometry. + + The geometry to test + true if this geometry covers the given geometry + + + + + Tests whether the base crosses a given geometry. + + The geometry to test + true if this geometry crosses the given geometry + + + + + Tests whether the base is disjoint from given geometry. + + + This method supports s as input + + The geometry to test + true if this geometry is disjoint from the given geometry + + + + + Tests whether the base intersects a given geometry. + + + This method supports s as input + + The geometry to test + true if this geometry intersects the given geometry + + + + + Tests whether the base overlaps a given geometry. + + The geometry to test + true if this geometry overlaps the given geometry + + + + + Tests whether the base touches a given geometry. + + The geometry to test + true if this geometry touches the given geometry + + + + + Tests whether the base is within a given geometry. + + The geometry to test + true if this geometry is within the given geometry + + + + + A factory for creating s. It chooses an appropriate implementation of PreparedGeometry + based on the geometric type of the input geometry. + + In the future, the factory may accept hints that indicate + special optimizations which can be performed. + + Instances of this class are thread-safe. + + Martin Davis + + + + Creates a new appropriate for the argument . + + The geometry to prepare + + the prepared geometry + + + + + Creates a new appropriate for the argument . + + The geometry to prepare + + the prepared geometry + + + + + A prepared version for geometries. + Instances of this class are thread-safe. + + mbdavis + + + + Computes the intersects spatial relationship predicate + for a target relative to other classes. + + + Uses short-circuit tests and indexing to improve performance. + + Martin Davis + + + + Computes the intersects predicate between a + and a . + + The prepared linestring + A test geometry + true if the linestring intersects the geometry + + + + Creates an instance of this operation. + + The target PreparedLineString + + + + Tests whether this geometry intersects a given geometry. + + The test geometry + true if the test geometry intersects + + + + Tests whether any representative point of the test Geometry intersects + the target geometry. + + + Only handles test geometries which are Puntal (dimension 0) + + A Puntal geometry to test + true if any point of the argument intersects the prepared geometry + + + + A prepared version for geometries. + Instances of this class are thread-safe. + + Martin Davis + + + + Tests whether this point intersects a . + + + The optimization here is that computing topology for the test geometry + is avoided. This can be significant for large geometries. + + + + + A prepared version for geometries. + This class supports both s and s. + This class does not support MultiPolygons which are non-valid + (e.g. with overlapping elements). + + + Instances of this class are thread-safe and immutable. + + mbdavis + + + + Computes the contains spatial relationship predicate for a relative to all other classes. + Uses short-circuit tests and indexing to improve performance. + + + + It is not possible to short-circuit in all cases, in particular + in the case where the test geometry touches the polygon linework. + In this case full topology must be computed. + + + Martin Davis + + + + Computes the contains spatial relationship predicate between a and a . + + The prepared polygon + A test geometry + true if the polygon contains the geometry + + + + Creates an instance of this operation. + + the PreparedPolygon to evaluate + + + + Tests whether this PreparedPolygon contains a given geometry. + + The test geometry + true if the test geometry is contained + + + + Computes the full topological contains predicate.
+ Used when short-circuit tests are not conclusive. +
+ The test geometry + true if this prepared polygon contains the test geometry +
+ + + Computes the containsProperly spatial relationship predicate for s relative to all other {@link Geometry} classes.
+ Uses short-circuit tests and indexing to improve performance. +
+ + + A Geometry A containsProperly another Geometry B if + all points of B are contained in the Interior of A. + Equivalently, B is contained in A AND B does not intersect + the Boundary of A. + + + The advantage to using this predicate is that it can be computed + efficiently, with no need to compute topology at individual points. + In a situation with many geometries intersecting the boundary + of the target geometry, this can make a performance difference. + + + Martin Davis +
+ + Computes the containsProperly predicate between a and a . + + The prepared polygon + A test geometry + true if the polygon properly contains the geometry + + + + Creates an instance of this operation. + + The PreparedPolygon to evaluate + + + + Tests whether this PreparedPolygon containsProperly a given geometry. + + The test geometry + true if the polygon properly contains the geometry + + + + Computes the Covers spatial relationship predicate for a relative to all other classes. + + + Uses short-circuit tests and indexing to improve performance. + + It is not possible to short-circuit in all cases, in particular in the case where the test geometry touches the polygon linework. + In this case full topology must be computed. + + Martin Davis + + + + Computes the Covers spatial relationship predicate for a relative to all other classes. + + The prepared polygon + A test geometry + true if the polygon covers the geometry + + + + Creates an instance of this operation. + + The PreparedPolygon to evaluate + + + + Tests whether this PreparedPolygon covers a given geometry. + + The test geometry + true if the test geometry is covered + + + + Computes the full topological covers predicate. Used when short-circuit tests are not conclusive. + + The test geometry + true if this prepared polygon covers the test geometry + + + + Computes the intersects spatial relationship predicate + for s relative to all other classes. + + Uses short-circuit tests and indexing to improve performance. + Martin Davis + + + + Computes the intersects predicate between a + and a . + + The prepared polygon + A test geometry + true if the polygon intersects the geometry + + + + Creates an instance of this operation. + + The prepared polygon + + + + Tests whether this PreparedPolygon intersects a given geometry. + + The test geometry + true if the test geometry intersects + + + + A base class for predicate operations on s. + + mbdavis + + + + Creates an instance of this operation. + + the PreparedPolygon to evaluate + + + + Tests whether all components of the test Geometry are contained in the target geometry. + + Handles both linear and point components. + A geometry to test + + true if all components of the argument are contained in the target geometry + + + + + Tests whether all components of the test Geometry are contained in the interior of the target geometry. + + Handles both linear and point components. + A geometry to test + true if all components of the argument are contained in the target geometry interior + + + + Tests whether any component of the test Geometry intersects + the area of the target geometry. + Handles test geometries with both linear and point components. + + A geometry to test + true if any component of the argument intersects the prepared area geometry + + + + Tests whether any point of the test Geometry intersects the interior of the target geometry. + + Handles test geometries with both linear and point components. + A geometry to test + true if any point of the argument intersects the prepared area geometry + + + + Tests whether any point of the test Geometry intersects the interior of the target geometry. + + A geometry to test + true if any point of the argument intersects the prepared area geometry interior + + + + Tests whether any component of the test Geometry intersects the interior of the target geometry. + + Handles test geometries with both linear and point components. + A geometry to test + true if any component of the argument intersects the prepared area geometry interior + + + + Tests whether all points of the test Pointal geometry + are contained in the target geometry. + + A geometry to test + true if all points of the argument are contained in the target geometry + + + + Tests whether any component of the target geometry intersects the test geometry (which must be an areal geometry) + + The test geometry + The representative points of the target geometry + true if any component intersects the areal test geometry + + + + Quadrant values + + + The quadants are numbered as follows: + + + 1 - NW | 0 - NE
+ -------+-------
+ 2 - SW | 3 - SE +
+
+
+
+ + + Undefined + + + + + North-East + + + + + North-West + + + + + South-West + + + + + South-East + + + + + Creates a quadrant with t + + + + + + Creates a quadrant of a directed line segment (specified as x and y + displacements, which cannot both be 0). + + + + If the displacements are both 0 + + + + Returns the quadrant of a directed line segment from p0 to p1. + + + + if the points are equal + + + + + + + + + + + + + Returns true if the quadrants are 1 and 3, or 2 and 4. + + A quadrant + + + + Returns the right-hand quadrant of the halfplane defined by the two quadrants, + or -1 if the quadrants are opposite, or the quadrant if they are identical. + + + + + + + Returns whether this quadrant lies within the given halfplane (specified + by its right-hand quadrant). + + + + + + Returns true if the given quadrant is 0 or 1. + + + + + Equality operator for quadrants + + Quadrant value on the left-hand-side + Quadrant value on the right-hand-side + true if quadrant value of and are equal. + + + + Inequality operator for quadrants + + Quadrant value on the left-hand-side + Quadrant value on the right-hand-side + true if quadrant value of and are not equal. + + + + Greater than (>) operator for quadrants + + Quadrant value on the left-hand-side + Quadrant value on the right-hand-side + true if quadrant value of and are not equal. + + + + Less than (<) operator for quadrants + + Quadrant value on the left-hand-side + Quadrant value on the right-hand-side + true if quadrant value of and are not equal. + + + + Indicates an invalid or inconsistent topological situation encountered during processing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Represents a planar triangle, and provides methods for calculating various + properties of triangles. + + + + + A corner point of the triangle + + + + + A corner point of the triangle + + + + + A corner point of the triangle + + + + + Tests whether a triangle is acute. A triangle is acute if all interior + angles are acute. This is a strict test - right triangles will return + false A triangle which is not acute is either right or obtuse. + + Note: this implementation is not robust for angles very close to 90 degrees. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + True if the triangle is acute. + + + + Tests whether a triangle is oriented counter-clockwise. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + true if the triangle orientation is counter-clockwise + + + + Tests whether a triangle intersects a point. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point to test + true if the triangle intersects the point + + + + Computes the line which is the perpendicular bisector of the + + A point + Another point + The perpendicular bisector, as an HCoordinate line segment a-b. + + + Computes the circumcentre of a triangle. + + The circumcentre is the centre of the circumcircle, + the smallest circle which encloses the triangle. + It is also the common intersection point of the + perpendicular bisectors of the sides of the triangle, + and is the only point which has equal distance to all three + vertices of the triangle. + + The circumcentre does not necessarily lie within the triangle. For example, + the circumcentre of an obtuse isosceles triangle lies outside the triangle. + + This method uses an algorithm due to J.R.Shewchuk which uses normalization + to the origin to improve the accuracy of computation. (See Lecture Notes + on Geometric Robustness, Jonathan Richard Shewchuk, 1999). + + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The circumcentre of the triangle + + + + Computes the circumcentre of a triangle. The circumcentre is the centre of + the circumcircle, the smallest circle which encloses the triangle.It is + also the common intersection point of the perpendicular bisectors of the + sides of the triangle, and is the only point which has equal distance to + all three vertices of the triangle. + + The circumcentre does not necessarily lie within the triangle. For example, + the circumcentre of an obtuse isosceles triangle lies outside the triangle. + + This method uses extended-precision arithmetic to + provide more accurate results than + + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The circumcentre of the triangle + + + + Computes the determinant of a 2x2 matrix. Uses standard double-precision + arithmetic, so is susceptible to round-off error. + + the [0,0] entry of the matrix + the [0,1] entry of the matrix + the [1,0] entry of the matrix + the [1,1] entry of the matrix + The determinant + + + + Computes the incentre of a triangle. + + + The InCentre of a triangle is the point which is equidistant + from the sides of the triangle. + It is also the point at which the bisectors of the triangle's angles meet. + It is the centre of the triangle's InCircle, which is the unique circle + that is tangent to each of the triangle's three sides. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point which is the incentre of the triangle + + + Computes the centroid (centre of mass) of a triangle. + + This is also the point at which the triangle's three + medians intersect (a triangle median is the segment from a vertex of the triangle to the + midpoint of the opposite side). + The centroid divides each median in a ratio of 2:1. + The centroid always lies within the triangle. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The centroid of the triangle + + + + Compute the length of the perimeter of a triangle + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The length of the perimeter of the triangle + + + Computes the length of the longest side of a triangle + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The length of the longest side of the triangle + + + Computes the point at which the bisector of the angle ABC cuts the segment AC. + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The angle bisector cut point + + + + Computes the 2D area of a triangle. + The area value is always non-negative. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The area of the triangle + + + + + Computes the signed 2D area of a triangle. + + + + The area value is positive if the triangle is oriented CW, + and negative if it is oriented CCW. + + + The signed area value can be used to determine point orientation, but + the implementation in this method is susceptible to round-off errors. + Use for robust orientation + calculation. + + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The area of the triangle + + + + + + Computes the 3D area of a triangle. + The value computed is always non-negative. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The 3D area of the triangle + + + + Computes the Z-value (elevation) of an XY point + on a three-dimensional plane defined by a triangle + whose vertices have Z-values. + The defining triangle must not be degenerate + (in other words, the triangle must enclose a + non-zero area), + and must not be parallel to the Z-axis. + + This method can be used to interpolate + the Z-value of a point inside a triangle + (for example, of a TIN facet with elevations on the vertices). + + The point to compute the Z-value of + A vertex of a triangle, with a Z ordinate + A vertex of a triangle, with a Z ordinate + A vertex of a triangle, with a Z ordinate + The computed Z-value (elevation) of the point + + + + Creates a new triangle with the given vertices. + + A vertex + A vertex + A vertex + + + + Computes the InCentre of this triangle + + The InCentre of a triangle is the point which is equidistant + from the sides of the triangle. + This is also the point at which the bisectors of the angles meet. + It is the centre of the triangle's InCircle, + which is the unique circle that is tangent to each of the triangle's three sides. + + + The point which is the InCentre of the triangle. + + + + + Tests whether this triangle is acute. A triangle is acute if all interior + angles are acute. This is a strict test - right triangles will return + false A triangle which is not acute is either right or obtuse. + + Note: this implementation is not robust for angles very close to 90 + degrees. + + true if this triangle is acute + + + + Tests whether this triangle is oriented counter-clockwise. + + true if the triangle orientation is counter-clockwise + + + + Computes the circumcentre of this triangle. The circumcentre is the centre + of the circumcircle, the smallest circle which encloses the triangle. It is + also the common intersection point of the perpendicular bisectors of the + sides of the triangle, and is the only point which has equal distance to + all three vertices of the triangle. + + The circumcentre does not necessarily lie within the triangle. + + This method uses an algorithm due to J.R.Shewchuk which uses normalization + to the origin to improve the accuracy of computation. (See Lecture Notes + on Geometric Robustness, Jonathan Richard Shewchuk, 1999). + + The circumcentre of this triangle + + + + Computes the centroid (centre of mass) of this triangle. This is also the + point at which the triangle's three medians intersect (a triangle median is + the segment from a vertex of the triangle to the midpoint of the opposite + side). The centroid divides each median in a ratio of 2:1. + + The centroid always lies within the triangle. + + The centroid of this triangle + + + + Computes the length of the perimeter of this triangle. + + The length of the perimeter + + + + Computes the length of the longest side of this triangle + + The length of the longest side of this triangle + + + + Computes the 2D area of this triangle. The area value is always + non-negative. + + The area of this triangle + + + + + Computes the signed 2D area of this triangle. The area value is positive if + the triangle is oriented CW, and negative if it is oriented CCW. + + The signed area value can be used to determine point orientation, but the + implementation in this method is susceptible to round-off errors. Use + + for robust orientation calculation. + + The signed 2D area of this triangle + + + + + Computes the 3D area of this triangle. The value computed is always + non-negative. + + The 3D area of this triangle + + + + Computes the Z-value (elevation) of an XY point on a three-dimensional + plane defined by this triangle (whose vertices must have Z-values). This + triangle must not be degenerate (in other words, the triangle must enclose + a non-zero area), and must not be parallel to the Z-axis. + + This method can be used to interpolate the Z-value of a point inside this + triangle (for example, of a TIN facet with elevations on the vertices). + + The point to compute the Z-value of + The computed Z-value (elevation) of the point + + + + Represents an affine transformation on the 2D Cartesian plane. + + + + It can be used to transform a or . + An affine transformation is a mapping of the 2D plane into itself + via a series of transformations of the following basic types: +
    +
  • reflection (through a line)
  • +
  • rotation (around the origin)
  • +
  • scaling (relative to the origin)
  • +
  • shearing (in both the X and Y directions)
  • +
  • translation
  • +
+
+ + In general, affine transformations preserve straightness and parallel lines, + but do not preserve distance or shape. + + + An affine transformation can be represented by a 3x3 + matrix in the following form: +
+ T = | m00 m01 m02 |
+ | m10 m11 m12 |
+ | 0 0 1 | +
+ A coordinate P = (x, y) can be transformed to a new coordinate P' = (x', y') + by representing it as a 3x1 matrix and using matrix multiplication to compute: +
+ | x' | = T x | x |
+ | y' | | y |
+ | 1 | | 1 | +
+
+

Transformation Composition

+ + Affine transformations can be composed using the method. + Composition is computed via multiplication of the + transformation matrices, and is defined as: +
+            A.compose(B) = TB x TA
+            
+
+ + This produces a transformation whose effect is that of A followed by B. + The methods , , + , , and + have the effect of composing a transformation of that type with + the transformation they are invoked on. + The composition of transformations is in general not commutative. + +

Transformation Inversion

+ + Affine transformations may be invertible or non-invertible. + If a transformation is invertible, then there exists + an inverse transformation which when composed produces + the identity transformation. + The method + computes the inverse of a transformation, if one exists. + + + @author Martin Davis + +
+
+ + + Creates a transformation for a reflection about the + line (x0,y0) - (x1,y1). + + the x-ordinate of a point on the reflection line + the y-ordinate of a point on the reflection line + the x-ordinate of a another point on the reflection line + the y-ordinate of a another point on the reflection line + a transformation for the reflection + + + + Creates a transformation for a reflection about the + line (0,0) - (x,y). + + the x-ordinate of a point on the reflection line + the y-ordinate of a point on the reflection line + a transformation for the reflection + + + + Creates a transformation for a rotation + about the origin + by an angle theta. + + + Positive angles correspond to a rotation + in the counter-clockwise direction. + + the rotation angle, in radians + a transformation for the rotation + + + + Creates a transformation for a rotation + by an angle theta, + specified by the sine and cosine of the angle. + + + This allows providing exact values for sin(theta) and cos(theta) + for the common case of rotations of multiples of quarter-circles. + + the sine of the rotation angle + the cosine of the rotation angle + a transformation for the rotation + + + + Creates a transformation for a rotation + about the point (x,y) by an angle theta. + + + Positive angles correspond to a rotation + in the counter-clockwise direction. + + the rotation angle, in radians + the x-ordinate of the rotation point + the y-ordinate of the rotation point + a transformation for the rotation + + + + Creates a transformation for a rotation + about the point (x,y) by an angle theta, + specified by the sine and cosine of the angle. + + + This allows providing exact values for sin(theta) and cos(theta) + for the common case of rotations of multiples of quarter-circles. + + the sine of the rotation angle + the cosine of the rotation angle + the x-ordinate of the rotation point + the y-ordinate of the rotation point + a transformation for the rotation + + + + Creates a transformation for a scaling relative to the origin. + + the value to scale by in the x direction + the value to scale by in the y direction + a transformation for the scaling + + + + Creates a transformation for a scaling relative to the point (x,y). + + The value to scale by in the x direction + The value to scale by in the y direction + The x-ordinate of the point to scale around + The y-ordinate of the point to scale around + A transformation for the scaling + + + + Creates a transformation for a shear. + + the value to shear by in the x direction + the value to shear by in the y direction + a transformation for the shear + + + + Creates a transformation for a translation. + + the value to translate by in the x direction + the value to translate by in the y direction + a transformation for the translation + + + + Constructs a new identity transformation + + + + + Constructs a new transformation whose + matrix has the specified values. + + an array containing the 6 values { m00, m01, m02, m10, m11, m12 } + if matrix is null + if matrix is too small + + + + Constructs a new transformation whose + matrix has the specified values. + + the entry for the [0, 0] element in the transformation matrix + the entry for the [0, 1] element in the transformation matrix + the entry for the [0, 2] element in the transformation matrix + the entry for the [1, 0] element in the transformation matrix + the entry for the [1, 1] element in the transformation matrix + the entry for the [1, 2] element in the transformation matrix + + + + Constructs a transformation which is + a copy of the given one. + + the transformation to copy + + + + Constructs a transformation + which maps the given source + points into the given destination points. + + source point 0 + source point 1 + source point 2 + the mapped point for source point 0 + the mapped point for source point 1 + the mapped point for source point 2 + + + + Sets this transformation to be the identity transformation. + + + The identity transformation has the matrix: +
+ | 1 0 0 |
+ | 0 1 0 |
+ | 0 0 1 | +
+
+ this transformation, with an updated matrix +
+ + + Sets this transformation's matrix to have the given values. + + the entry for the [0, 0] element in the transformation matrix + the entry for the [0, 1] element in the transformation matrix + the entry for the [0, 2] element in the transformation matrix + the entry for the [1, 0] element in the transformation matrix + the entry for the [1, 1] element in the transformation matrix + the entry for the [1, 2] element in the transformation matrix + this transformation, with an updated matrix + + + + Sets this transformation to be a copy of the given one + + a transformation to copy + this transformation, with an updated matrix + + + + Gets an array containing the entries + of the transformation matrix. + + + Only the 6 non-trivial entries are returned, + in the sequence: +
+            m00, m01, m02, m10, m11, m12
+            
+
+ an array of length 6 +
+ + + Computes the determinant of the transformation matrix. + + + + The determinant is computed as: +
+ | m00 m01 m02 |
+ | m10 m11 m12 | = m00 * m11 - m01 * m10
+ | 0 0 1 | +
+
+ + If the determinant is zero, + the transform is singular (not invertible), + and operations which attempt to compute + an inverse will throw a . + +
+ the determinant of the transformation + + + The determinant of the transformation + +
+ + + Computes the inverse of this transformation, if one + exists. + + + + The inverse is the transformation which when + composed with this one produces the identity + transformation. + A transformation has an inverse if and only if it + is not singular (i.e. its + determinant is non-zero). + Geometrically, an transformation is non-invertible + if it maps the plane to a line or a point. + If no inverse exists this method + will throw a . + + + The matrix of the inverse is equal to the + inverse of the matrix for the transformation. + It is computed as follows: +
+ 1 + inverse(A) = --- x adjoint(A) + det + + + = 1 | m11 -m01 m01*m12-m02*m11 | + --- x | -m10 m00 -m00*m12+m10*m02 | + det | 0 0 m00*m11-m10*m01 | + + + + = | m11/det -m01/det m01*m12-m02*m11/det | + | -m10/det m00/det -m00*m12+m10*m02/det | + | 0 0 1 | +
+
+
+ A new inverse transformation + + +
+ + + Explicitly computes the math for a reflection. May not work. + + The x-ordinate of one point on the reflection line + The y-ordinate of one point on the reflection line + The x-ordinate of another point on the reflection line + The y-ordinate of another point on the reflection line + This transformation with an updated matrix + + + + Sets this transformation to be a reflection about the line defined by a line (x0,y0) - (x1,y1). + + The x-ordinate of one point on the reflection line + The y-ordinate of one point on the reflection line + The x-ordinate of another point on the reflection line + The y-ordinate of another point on the reflection line + This transformation with an updated matrix + + + + Sets this transformation to be a reflection + about the line defined by vector (x,y). + + + The transformation for a reflection + is computed by: +
+ d = sqrt(x2 + y2) + sin = x / d; + cos = x / d; + Tref = Trot(sin, cos) x Tscale(1, -1) x Trot(-sin, cos) +
+
+ the x-component of the reflection line vector + the y-component of the reflection line vector + this transformation, with an updated matrix +
+ + + Sets this transformation to be a rotation around the orign. + + + A positive rotation angle corresponds + to a counter-clockwise rotation. + The transformation matrix for a rotation + by an angle theta + has the value: +
+            |  cos(theta)  -sin(theta)   0 |
+            |  sin(theta)   cos(theta)   0 |
+            |           0            0   1 |
+            
+
+ the rotation angle, in radians + this transformation, with an updated matrix +
+ + + Sets this transformation to be a rotation around the origin + by specifying the sin and cos of the rotation angle directly. + + + The transformation matrix for the rotation + has the value: +
+            |  cosTheta  -sinTheta   0 |
+            |  sinTheta   cosTheta   0 |
+            |         0          0   1 |
+            
+
+ the sine of the rotation angle + the cosine of the rotation angle + this transformation, with an updated matrix +
+ + + Sets this transformation to be a rotation + around a given point (x,y). + + + A positive rotation angle corresponds + to a counter-clockwise rotation. + The transformation matrix for a rotation + by an angle + has the value: +
+            |  cosTheta  -sinTheta   x-x*cos+y*sin |
+            |  sinTheta   cosTheta   y-x*sin-y*cos |
+            |           0            0   1 |
+            
+
+ the rotation angle, in radians + the x-ordinate of the rotation point + the y-ordinate of the rotation point + this transformation, with an updated matrix +
+ + + Sets this transformation to be a rotation + around a given point (x,y) + by specifying the sin and cos of the rotation angle directly. + + + The transformation matrix for the rotation + has the value: +
+            |  cosTheta  -sinTheta   x-x*cos+y*sin |
+            |  sinTheta   cosTheta   y-x*sin-y*cos |
+            |         0          0         1       |
+            
+
+ the sine of the rotation angle + the cosine of the rotation angle + the x-ordinate of the rotation point + the y-ordinate of the rotation point + this transformation, with an updated matrix +
+ + + Sets this transformation to be a scaling. + + + The transformation matrix for a scale + has the value: +
+            |  xScale      0  dx |
+            |  0      yScale  dy |
+            |  0           0   1 |
+            
+
+ the amount to scale x-ordinates by + the amount to scale y-ordinates by + this transformation, with an updated matrix +
+ + + Sets this transformation to be a shear. + + + The transformation matrix for a shear + has the value: +
+            |  1      xShear  0 |
+            |  yShear      1  0 |
+            |  0           0  1 |
+            
+ Note that a shear of (1, 1) is not + equal to shear(1, 0) composed with shear(0, 1). + Instead, shear(1, 1) corresponds to a mapping onto the + line x = y. +
+ the x component to shear by + the y component to shear by + this transformation, with an updated matrix +
+ + + Sets this transformation to be a translation. + + + For a translation by the vector (x, y) + the transformation matrix has the value: +
+            |  1  0  dx |
+            |  1  0  dy |
+            |  0  0   1 |
+            
+
+ the x component to translate by + the y component to translate by + this transformation, with an updated matrix +
+ + + Updates the value of this transformation + to that of a reflection transformation composed + with the current value. + + the x-ordinate of a point on the line to reflect around + the y-ordinate of a point on the line to reflect around + the x-ordinate of a point on the line to reflect around + the y-ordinate of a point on the line to reflect around + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a reflection transformation composed + with the current value. + + the x-ordinate of the line to reflect around + the y-ordinate of the line to reflect around + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a rotation transformation composed + with the current value. + + + Positive angles correspond to a rotation + in the counter-clockwise direction. + + the angle to rotate by in radians + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a rotation around the origin composed + with the current value, + with the sin and cos of the rotation angle specified directly. + + the sine of the angle to rotate by + the cosine of the angle to rotate by + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a rotation around a given point composed + with the current value. + + + Positive angles correspond to a rotation + in the counter-clockwise direction. + + the angle to rotate by, in radians + the x-ordinate of the rotation point + the y-ordinate of the rotation point + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a rotation around a given point composed + with the current value, + with the sin and cos of the rotation angle specified directly. + + the sine of the angle to rotate by + the cosine of the angle to rotate by + the x-ordinate of the rotation point + the y-ordinate of the rotation point + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a scale transformation composed + with the current value. + + the value to scale by in the x direction + the value to scale by in the y direction + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a shear transformation composed + with the current value. + + the value to shear by in the x direction + the value to shear by in the y direction + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a translation transformation composed + with the current value. + + the value to translate by in the x direction + the value to translate by in the y direction + this transformation, with an updated matrix + + + + Updates this transformation to be + the composition of this transformation with the given . + + + This produces a transformation whose effect + is equal to applying this transformation + followed by the argument transformation. + Mathematically, +
+            A.compose(B) = TB x TA
+            
+
+ an affine transformation + this transformation, with an updated matrix +
+ + + Updates this transformation to be the composition + of a given with this transformation. + + + This produces a transformation whose effect + is equal to applying the argument transformation + followed by this transformation. + Mathematically, +
+            A.composeBefore(B) = TA x TB
+            
+
+ an affine transformation + this transformation, with an updated matrix +
+ + + Applies this transformation to the coordinate + and places the results in the coordinate + (which may be the same as the source). + + the coordinate to transform + the coordinate to accept the results + the dest coordinate + + + + + Creates a new which is the result of this transformation applied to the input Geometry. + + A Geometry + The transformed Geometry + + + + Applies this transformation to the i'th coordinate + in the given CoordinateSequence. + + a CoordinateSequence + the index of the coordinate to transform + + + + Transforms the i'th coordinate in the input sequence + + A CoordinateSequence + The index of the coordinate to transform + + + + Reports that this filter should continue to be executed until + all coordinates have been transformed. + + false + + + Tests if this transformation is the identity transformation. + + + + Tests if an object is an AffineTransformation and has the same matrix as this transformation. + + An object to test + true if the given object is equal to this object + + + + + + + Gets a text representation of this transformation. + The string is of the form: + + AffineTransformation[[m00, m01, m02], [m10, m11, m12]] + + + A string representing this transformation + + + + Clones this transformation + + A copy of this transformation + + + + Builds an defined by a set of control vectors. + + + + A control vector consists of a source point and a destination point, + which is the image of the source point under the desired transformation. + + + A transformation is well-defined + by a set of three control vectors + if and only if the source points are not collinear. + (In particular, the degenerate situation + where two or more source points are identical will not produce a well-defined transformation). + A well-defined transformation exists and is unique. + If the control vectors are not well-defined, the system of equations + defining the transformation matrix entries is not solvable, + and no transformation can be determined. + + No such restriction applies to the destination points. + However, if the destination points are collinear or non-unique, + a non-invertible transformations will be generated. + + + This technique of recovering a transformation + from its effect on known points is used in the Bilinear Interpolated Triangulation + algorithm for warping planar surfaces. + + + Martin Davis + + + + Constructs a new builder for the transformation defined by the given set of control point mappings. + + A control point + A control point + A control point + The image of under the required transformation + The image of under the required transformation + The image of under the required transformation + + + + Computes the + determined by the control point mappings, + or null if the control vectors do not determine a well-defined transformation. + + + An affine transformation, or if the control vectors do not + determine a well-defined transformation. + + + + + Computes the transformation matrix by + solving the two systems of linear equations + defined by the control point mappings, + if this is possible. + + True if the transformation matrix is solvable + + + + Solves the transformation matrix system of linear equations + for the given right-hand side vector. + + The vector for the right-hand side of the system + The solution vector, or if no solution could be determined. + + + + Supports creating s defined by various kinds of inputs and transformation mapping rules. + + Martin Davis + + + + Creates a transformation from a set of three control vectors. A control + vector consists of a source point and a destination point, which is the + image of the source point under the desired transformation. Three control + vectors allows defining a fully general affine transformation. + + + + + + + + The computed transformation + + + + Creates an AffineTransformation defined by a pair of control vectors. A + control vector consists of a source point and a destination point, which is + the image of the source point under the desired transformation. The + computed transformation is a combination of one or more of a uniform scale, + a rotation, and a translation (i.e. there is no shear component and no + reflection) + + + + + + The computed transformation + null if the control vectors do not determine a well-defined transformation + + + + Creates an AffineTransformation defined by a single control vector. A + control vector consists of a source point and a destination point, which is + the image of the source point under the desired transformation. This + produces a translation. + + The start point of the control vector + The end point of the control vector + The computed transformation + + + + Creates an AffineTransformation defined by a set of control vectors. + Between one and three vectors must be supplied. + + The source points of the vectors + The destination points of the vectors + The computed transformation + if the control vector arrays are too short, long or of different lengths + + + + Creates an AffineTransformation defined by a mapping between two baselines. + The computed transformation consists of: + + a translation from the start point of the source baseline to the start point of the destination baseline, + a rotation through the angle between the baselines about the destination start point, + and a scaling equal to the ratio of the baseline lengths. + + If the source baseline has zero length, an identity transformation is returned. + + The start point of the source baseline + The end point of the source baseline + The start point of the destination baseline + The end point of the destination baseline + + + + + Extracts a representative + from each connected component of a . + + 1.9 + + + + Extracts a representative + from each connected component in a geometry. + + If more than one geometry is to be processed, it is more + efficient to create a single + instance and pass it to each geometry. + + The Geometry from which to extract + A list of representative Coordinates + + + + Constructs a LineExtracterFilter with a list in which to store LineStrings found. + + + + + Utility to combine just the s of a list of geometries. + + + + + Gets the smallest within which all input geometries fit, or a + null envelope if no non-empty geometries were found in + the input list. + + + The list of input geometries. + + + The smallest within which all input geometries fit, or a + null envelope if no non-empty geometries were found in + the input list. + + + + + Gets the smallest within which all input geometries fit, or a + null envelope if no non-empty geometries were found in + the input list. + + + The list of input geometries. + + + The smallest within which all input geometries fit, or a + null envelope if no non-empty geometries were found in + the input list. + + + + + Initializes a new instance of the class. + + + The instances to combine. + + + + + Initializes a new instance of the class. + + + The instances to combine. + + + + + Gets the smallest within which all input geometries fit, or a + null envelope if no non-empty geometries were found in + the input list. + + + The smallest within which all input geometries fit, or a + null envelope if no non-empty geometries were found in + the input list. + + + + + Maps the members of a + into another GeometryCollection via a defined + mapping function. + + Martin Davis + + + + + + + + + + + + Creates an instance of this class + + + + + + + + + + + + + Combines s to produce a of the most appropriate type. + + + Input geometries which are already collections will have their elements extracted first. + No validation of the result geometry is performed. + (The only case where invalidity is possible is where geometries are combined and result in a self-intersection). + + mbdavis + + + + Combines a collection of geometries. + The geometries to combine + The combined geometry + + + + Combines two geometries. + + A geometry to combine + A geometry to combine + The combined geometry + + + + Combines three geometries. + + A geometry to combine + A geometry to combine + A geometry to combine + The combined geometry + + + + Creates a list from two items + + + + A list from two geometries + + + + Creates a list from three items + + + + + A list from three geometries + + + + Value indicating whether empty geometries should be skipped + + + + + Creates a new combiner for a collection of geometries + + The geometries to combine + + + + Extracts the GeometryFactory used by the geometries in a collection + + + a GeometryFactory + + + + Computes the combination of the input geometries to produce the most appropriate or + + A Geometry which is the combination of the inputs + + + + + A class which supports creating new s + which are modifications of existing ones, + maintaining the same type structure. + + + Geometry objects are intended to be treated as immutable. + This class allows you to "modifies" a Geometrys + by traversing them, applying a user-defined + , or + and creating a new Geometrys with the same structure but + (possibly) modified components. + + Examples of the kinds of modifications which can be made are: + + + The values of the coordinates may be changed. + The editor does not check whether changing coordinate values makes the result Geometry invalid + + + The coordinate lists may be changed (e.g. by adding, deleting or modifying coordinates). + The modified coordinate lists must be consistent with their original parent component + (e.g. a LinearRing must always have at least 4 coordinates, and the first and last + coordinate must be equal). + + + Components of the original point may be deleted + (e.g. holes may be removed from a Polygon, or LineStrings removed from a MultiLineString). + Deletions will be propagated up the component tree appropriately. + + + + All changes must be consistent with the original Geometry's structure + (e.g. a Polygon cannot be collapsed into a LineString). + If changing the structure is required, use a . + + + This class supports creating an edited Geometry + using a different via the + constructor. + Examples of situations where this is required is if the geometry is + transformed to a new SRID and/or a new PrecisionModel. + + Usage notes + + The resulting Geometry is not checked for validity. + If validity needs to be enforced, the new Geometry's + method should be called. + By default the UserData of the input geometry is not copied to the result. + + + + + + + + + The factory used to create the modified Geometry. + + + If null the GeometryFactory of the input is used. + + + + + Creates a new GeometryEditor object which will create + edited with the same as the input Geometry. + + + + + Creates a new GeometryEditor object which will create + edited s with the given . + + The GeometryFactory to create the edited Geometry with. + + + + Gets or sets a value indicating if the User Data is copied to the edit result. + If so, only the object reference is copied. + + + + + Edit the input Geometry with the given edit operation. + Clients can create subclasses of GeometryEditorOperation or + CoordinateOperation to perform required modifications. + + The Geometry to edit. + The edit operation to carry out. + A new Geometry which is the result of the editing (which may be empty). + + + + A interface which specifies an edit operation for Geometries. + + + + + Edits a Geometry by returning a new Geometry with a modification. + The returned Geometry may be the input geometry itself. + It may be null if the geometry is to be deleted. + + The Geometry to modify. + + The factory with which to construct the modified Geometry + (may be different to the factory of the input point). + + A new Geometry which is a modification of the input Geometry. + null if the Geometry is to be deleted completely + + + + A GeometryEditorOperation which does not modify + the input geometry. + This can be used for simple changes of + (including PrecisionModel and SRID). + + mbdavis + + + + A GeometryEditorOperation which edits the coordinate list of a Geometry. + Operates on Geometry subclasses which contains a single coordinate list. + + + + + + + + + + + + + Edits the array of Coordinates from a Geometry. + + The coordinate array to operate on. + The point containing the coordinate list. + An edited coordinate array (which may be the same as the input). + + + + A which edits the + of a . + + Operates on Geometry subclasses which contains a single coordinate list. + + + + An edited coordinate sequence (which may be the same as the input) + + + + Extracts the components of a given type from a . + + + + + Extracts the T components from an and adds them to the provided . + + the geometry from which to extract + the list to add the extracted elements to + The geometry type to extract + + + + Extracts the T elements from a single and returns them in a . + + the geometry from which to extract + + + + Extracts the components of geometryType from a + + The geometry from which to extract + Geometry type to extract (null or all white-space means all types) + + + + Extracts the components of geometryType from a + and adds them to the provided + + The geometry from which to extract + Geometry type to extract (null or all white-space means all types) + The list to add the extracted elements to + + + + Extracts the components of type T from a . + + + + + Constructs a filter with a list in which to store the elements found. + + Geometry type to extract (null means all types) + The list to extract into + + + + Y + + + + + + + + + + + Extracts the components of type T from a . + + + + + Constructs a filter with a list in which to store the elements found. + + The list to extract into + + + + Fixes a geometry to be a valid geometry, while preserving as much as + possible of the shape and location of the input. + Validity is determined according to . + + Input geometries are always processed, so even valid inputs may + have some minor alterations.The output is always a new geometry object. +

Semantic Rules

+ + Vertices with non-finite X or Y ordinates are removed (as per ) + Repeated points are reduced to a single point + Empty atomic geometries are valid and are returned unchanged + Empty elements are removed from collections + Point: keep valid coordinate, or EMPTY + LineString: coordinates are fixed + LinearRing: coordinates are feixed, keep valid ring or else convert into LineString + Polygon: transform into a valid polygon, + preserving as much of the extent and vertices as possible. + + Rings are fixed to ensure they are valid + Holes intersection the shell are subtracted from the shell + Holes outside the shell are converted into polygons + + MultiPolygon: each polygon is fixed, + then result made non - overlapping (via union) + GeometryCollection: each element is fixed + Collapsed lines and polygons are handled as follows, + depending on the keepCollapsed setting: + + false: (default) collapses are converted to empty geometries + (and removed if they are elements of collections) + true: collapses are converted to a valid geometry of lower dimension + + +
+ Martin Davis + +
+ + + Fixes a geometry to be valid. + + The geometry to be fixed + The valid fixed geometry + + + + Fixes a geometry to be valid, allowing to set a flag controlling how + single item results from fixed MULTI geometries should be + returned. + + The geometry to be fixed + A flag indicating if MULTI geometries should not + be converted to single instance types if they consist of only one item. + The valid fixed geometry + + + Creates a new instance to fix a given geometry + The geometry to be fixed + + + + Gets or sets a value indicating whether collapsed + geometries are converted to empty, + (which will be removed from collections), + or to a valid geometry of lower dimension. + The default is to convert collapses to empty geometries (false). + + + + + Gets or sets a value indicating whether collapsed + geometries are converted to empty, + (which will be removed from collections), + or to a valid geometry of lower dimension. + The default is to convert collapses to empty geometries (false). + + + + + Gets the fixed geometry. + + The fixed geometry + + + + Returns a clean copy of the input coordinate array. + + Coordinates to clean + An array of clean coordinates + + + Subtracts a list of polygonal geometries from a polygonal geometry. + polygonal geometry for shell + polygonal geometries for holes + The result geometry + + + + Unions a list of polygonal geometries. + Optimizes case of zero or one input geometries. + Requires that the inputs are net new objects. + + The polygonal geometries to union + The union of the inputs + + + + Methods to map various collections + of s + via defined mapping functions. + + Martin Davis + + + + Maps the members of a + (which may be atomic or composite) + into another Geometry of most specific type. + null results are skipped. + In the case of hierarchical s, + only the first level of members are mapped. + + The input atomic or composite geometry + The mapping operation delegate + A result collection or geometry of most specific type + + + + Maps the members of a + (which may be atomic or composite) + into another Geometry of most specific type. + null results are skipped. + In the case of hierarchical s, + only the first level of members are mapped. + + The input atomic or composite geometry + The mapping operation + A result collection or geometry of most specific type + + + + Maps the atomic elements of a + (which may be atomic or composite) + using a mapping operation + into an atomic Geometry or a flat collection + of the most specific type. + null and empty values returned from the mapping operation + are discarded. + + The geometry to map + The dimension of empy geometry to create + The mapping operation + The mapped result + + + + An interface for geometry functions used for mapping. + + Martin Davis + + + + Computes a new geometry value. + + The input geometry + A result geometry + + + + Standard implementation of a geometry mapping + + + + + Creates an instance of this class using the provided mapping operation function + + A mapping operation function + + + + Computes a new geometry value. + + The input geometry + A result geometry + + + + A framework for processes which transform an input Geometry into + an output , possibly changing its structure and type(s). + + + + This class is a framework for implementing subclasses + which perform transformations on + various different Geometry subclasses. + + + It provides an easy way of applying specific transformations + to given point types, while allowing unhandled types to be simply copied. + Also, the framework handles ensuring that if subcomponents change type + the parent geometries types change appropriately to maintain valid structure. + Subclasses will override whichever TransformX methods + they need to to handle particular Geometry types. + + + A typically usage would be a transformation that may transform Polygons into + Polygons, LineStrings or Points, depending on the geometry of the input + (For instance, a simplification operation). + This class would likely need to override the + method to ensure that if input Polygons change type the result is a GeometryCollection, + not a MultiPolygon. + + The default behaviour of this class is simply to recursively transform + each Geometry component into an identical object by deep copying down + to the level of, but not including, coordinates. + + + Note that all TransformXXX methods may return null, + to avoid creating empty point objects. This will be handled correctly + by the transformer. TransformXXX methods should always return valid + geometry - if they cannot do this they should return null + (for instance, it may not be possible for a transformLineString implementation + to return at least two points - in this case, it should return null). + The method itself will always + return a non-null Geometry object (but this may be empty). + > + + + + The geometry factory + + + + + true if empty geometries should not be included in the result. + + + + + true if a homogenous collection result + from a GeometryCollection should still + be a general GeometryCollection. + + + + + true if the type of the input should be preserved. + + + + + Makes the input geometry available + + + + + + + + + + + + Convenience method which provides standard way of + creating a CoordinateSequence. + + The coordinate array to copy. + A coordinate sequence for the array. + + + + Convenience method which provides a standard way of copying s. + + The sequence to copy. + A deep copy of the sequence. + + + + Transforms a . + This method should always return a valid coordinate list for + the desired result type. (E.g. a coordinate list for a LineString + must have 0 or at least 2 points). + If this is not possible, return an empty sequence - + this will be pruned out. + + The coordinates to transform + The parent geometry + The transformed coordinates + + + + Transforms a geometry. + + The Point to transform + The parent geometry + A Point + + + + Transforms a geometry. + + The MultiPoint to transform + The parent geometry + A MultiPoint + + + + Transforms a . + + The transformation of a LinearRing may result in a coordinate sequence + which does not form a structurally valid ring (i.e. a degenerate ring of 3 or fewer points). + In this case a LineString is returned. + Subclasses may wish to override this method and check for this situation + (e.g.a subclass may choose to eliminate degenerate linear rings) + + The LinearRing to transform + The parent geometry + + A LinearRing if the transformation resulted in a structurally valid ring, otherwise, + if the transformation caused the LinearRing to collapse to 3 or fewer points, a LineString + + + + + Transforms a geometry. + + The LineString to transform + The parent geometry + A LineString + + + + Transforms a geometry. + + The MultiLineString to transform + The parent geometry + A MultiLineString + + + + Transforms a geometry. + + The Polygon to transform + The parent geometry + A Polygon + + + + Transforms a geometry. + + The MultiPolygon to transform + The parent geometry + A MultiPolygon + + + + Transforms a geometry. + + The GeometryCollection to transform + The parent geometry + A GeometryCollection + + + + Extracts all the 1-dimensional () components from a . + For polygonal geometries, this will extract all the component s. + If desired, s can be forced to be returned as s. + + + + + Extracts the linear components from a + and adds them to the provided . + + The geometry from which to extract linear components + The Collection to add the extracted linear components to + The Collection of linear components (LineStrings or LinearRings) + + + + Extracts the linear components from a + and adds them to the provided . + + The geometry from which to extract linear components + The Collection to add the extracted linear components to + + The Collection of linear components (LineStrings or LinearRings) + + + + Extracts the linear components from a single + and adds them to the provided . + + The geometry from which to extract linear components + The Collection to add the extracted linear components to + The Collection of linear components (LineStrings or LinearRings) + + + + Extracts the linear components from a single + and adds them to the provided . + + The geometry from which to extract linear components + The Collection to add the extracted linear components to + + The Collection of linear components (LineStrings or LinearRings) + + + + Extracts the linear components from a single point. + If more than one point is to be processed, it is more + efficient to create a single LineExtracterFilter instance + and pass it to multiple geometries. + + The point from which to extract linear components. + The list of linear components. + + + + Extracts the linear components from a single geometry. + If more than one geometry is to be processed, it is more + efficient to create a single instance + and pass it to multiple geometries. + + The geometry from which to extract linear components + true if s should be converted to s + The list of linear components + + + + Extracts the linear components from a single + and returns them as either a or . + + The geometry from which to extract + A linear geometry + + + + Extracts the linear components from a single + and returns them as either a or . + + The geometry from which to extract + true if s should be converted to s + A linear geometry + + + + Constructs a LineExtracterFilter with a list in which to store LineStrings found. + + + + + + Constructs a LineExtracterFilter with a list in which to store LineStrings found. + + + + + + + + + + + + + + + + + + Extracts all the elements from a . + + + + + + Extracts the elements from a single + and adds them to the. + + The geometry from which to extract + The list to add the extracted elements to + The list argument + + + + Extracts the elements from a single + and returns them in a . + + The geometry from which to extract + A list containing the linear elements + + + + Extracts the elements from a single + and returns them as either a or . + + The geometry from which to extract + A linear geometry + + + + Constructs a filter with a list in which to store the elements found. + + + + + Implements some 2D matrix operations (in particular, solving systems of linear equations). + + Martin Davis + + + + Solves a system of equations using Gaussian Elimination.
+ In order to avoid overhead the algorithm runs in-place + on A - if A should not be modified the client must supply a copy. +
+ A an nxn matrix in row/column order )modified by this method) + A vector of length n + if the matrix is the wrong size + + + A vector containing the solution (if any) + null if the system has no or no unique solution + + +
+ + + Indicates that an is non-invertible. + + Martin Davis + + + + Extracts all the 0-dimensional (Point) components from a Geometry. + + + + + + Extracts the elements from a single and adds them to the provided . + + The geometry from which to extract + The list to add the extracted elements to + + + + + Extracts the elements from a single and returns them in a . + + the geometry from which to extract + + + + Constructs a PointExtracterFilter with a list in which to store Points found. + + + + + + + + + + + + Extracts all the elements from a . + + + + + + Extracts the elements from a single and adds them to the provided . + + The geometry from which to extract + The list to add the extracted elements to + + + + + Extracts the elements from a single and returns them in a . + + The geometry from which to extract + + + + Constructs a PolygonExtracterFilter with a list in which to store Polygons found. + + + + + + + + + + + + A visitor to elements which components, which + allows short-circuiting when a defined condition holds. + + + + + + + + + + + + + + + + + Reports whether visiting components can be terminated. + Once this method returns , it must + continue to return on every subsequent call. + + + if visiting can be terminated. + + + + + Creates geometries which are shaped like multi-armed stars with each arm shaped like a sine wave. + These kinds of geometries are useful as a more complex geometry for testing algorithms. + + + Martin Davis + + + + + Creates a sine star with the given parameters. + + The origin point. + The size of the star. + The number of points in the star. + The number of arms to generate. + The arm length ratio. + A sine star shape. + + + + Creates a factory which will create sine stars using the default + + + + + Creates a factory which will create sine stars using the given + + The factory to use + + + Gets/Sets the number of arms in the star + + + + Gets or sets the ratio of the length of each arm to the radius of the star. + A smaller number makes the arms shorter. + + Value should be between 0.0 and 1.0 + + + + Generates the geometry for the sine star + + The geometry representing the sine star + + + + Builds an array of all visited items. + + + + + Builds an array of all visited items. + + + + + Visits an item. + + The item to visit. + + + + Gets the array of visited items. + + + + + An BinTree (or "Binary Interval Tree") + is a 1-dimensional version of a quadtree. + It indexes 1-dimensional intervals (which may + be the projection of 2-D objects on an axis). + It supports range searching + (where the range may be a single point). + + + + This structure is dynamic - + new items can be added at any time, + and it will support deletion of items + (although this is not currently implemented). + + + This implementation does not require specifying the extent of the inserted + items beforehand. It will automatically expand to accommodate any extent + of dataset. + This index is different to the Interval Tree of Edelsbrunner + or the Segment Tree of Bentley. + + + + + Ensure that the Interval for the inserted item has non-zero extents. + Use the current minExtent to pad it, if necessary. + + + + + + + + + + + + + + + + + + + + Compute the total number of nodes in the tree. + + The number of nodes in the tree. + + + + + + + + + + + Removes a single item from the tree. + + itemEnv the Envelope of the item to be removed + the item to remove + true if the item was found (and thus removed) + + + + + + + + + + + + + + + + + Queries the tree to find all candidate items which + may overlap the query interval. + If the query interval is null, all items in the tree are found. + min and max may be the same value. + + The interval to query for or null + + + + Adds items in the tree which potentially overlap the query interval + to the given collection. + If the query interval is null, add all items in the tree. + + A query interval, or null + The candidate items found + + + + + + + + + + Represents an (1-dimensional) closed interval on the Real number line. + + + + + Gets or sets a value indicating the minimum value of the closed interval. + + + + + Gets or sets a value indicating the maximum value of the closed interval. + + + + + Gets the width of the interval ( - ) + + + + + Gets the centre of the interval ( + * 0.5d) + + + + + Creates a new interval instance, setting ==0d; + + + + + Creates a new interval instance, setting = and =; + + The minimum value + The maximum value + + + + Creates a new interval instance, setting = and =. + + + + + + Method to initialize the interval with the given and values.
+ If < , their values are exchanged. +
+ The minimum value + The maximum value +
+ + + Method to expand this interval to contain . + + The interval to contain. + + + + Function to test if this overlaps . + + The interval to test + true if this interval overlaps + + + + Function to test if this overlaps the interval R[, ]. + + The mimimum value of the interval + The maximum value of the interval + true if this interval overlaps the interval R[, ] + + + + Function to test if this contains . + + This is more rigid than + The interval to test + true if this interval contains + + + + Function to test if this contains the interval R[, ]. + + This is more rigid than + The mimimum value of the interval + The maximum value of the interval + true if this interval contains the interval R[, ] + + + + Function to test if this contains the value . + + The value to test + true if this interval contains the value + + + + A Key is a unique identifier for a node in a tree. + It contains a lower-left point and a level number. The level number + is the power of two for the size of the node envelope. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Return a square envelope containing the argument envelope, + whose extent is a power of two and which is based at a power of 2. + + + + + + + + + + + + + A node of a Bintree. + + + + + Creates a node + + The interval of the node item + A new node + + + + Creates a larger node, that contains both and + If is null, a node for is created. + + The original node + The additional interval + A new node + + + + Creates a new node instance + + The node's interval + The node's level + + + + Gets the node's + + + + + + + + + + + + Returns the subnode containing the envelope. + Creates the node if + it does not already exist. + + + + + + Returns the smallest existing + node containing the envelope. + + + + + + + + + + + + Get the subnode for the index. + If it doesn't exist, create it. + + + + + + + + + + + + The base class for nodes in a Bintree. + + + + + Returns the index of the subnode that wholely contains the given interval. + If none does, returns -1. + + + + + + + + + + + + Subnodes are numbered as follows: + 0 | 1 + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Adds items in the tree which potentially overlap the query interval + to the given collection. + If the query interval is null, add all items in the tree. + + A query interval, or null + The candidate items found + + + + Removes a single item from this subtree. + + The envelope containing the item + The item to remove + true if the item was found and removed + + + + Gets whether this node is prunable + + + + + Gets whether this node has any children + + + + + + + + + + Gets whether this node has any subnodes + + + + + + + + + + + + + + + The root node of a single Bintree. + It is centred at the origin, + and does not have a defined extent. + + + + + Insert an item into the tree this is the root of. + + + + + + + Insert an item which is known to be contained in the tree rooted at + the given Node. Lower levels of the tree will be created + if necessary to hold the item. + + + + + + + + The root node matches all searches. + + + + + + MonotoneChains are a way of partitioning the segments of a linestring to + allow for fast searching of intersections. + + + + They have the following properties: + + the segments within a monotone chain never intersect each other + the envelope of any contiguous subset of the segments in a monotone chain + is equal to the envelope of the endpoints of the subset. + + + + Property 1 means that there is no need to test pairs of segments from within + the same monotone chain for intersection. + Property 2 allows an efficient + binary search to be used to find the intersection points of two monotone chains. + For many types of real-world data, these properties eliminate a large number of + segment comparisons, producing substantial speed gains. + + One of the goals of this implementation of MonotoneChains is to be + as space and time efficient as possible. One design choice that aids this + is that a MonotoneChain is based on a subarray of a list of points. + This means that new arrays of points (potentially very large) do not + have to be allocated. + + MonotoneChains support the following kinds of queries: + + Envelope selectdetermine all the segments in the chain which + intersect a given envelope. + Overlapdetermine all the pairs of segments in two chains whose + envelopes overlap. + + + + This implementation of MonotoneChains uses the concept of internal iterators + ( and ) + to return the resultsets for the above queries. + This has time and space advantages, since it + is not necessary to build lists of instantiated objects to represent the segments + returned by the query. + Queries made in this manner are thread-safe. + + + MonotoneChains support being assigned an integer id value + to provide a total ordering for a set of chains. + This can be used during some kinds of processing to + avoid redundant comparisons + (i.e.by comparing only chains where the first id is less than the second). + + + MonotoneChains support using an tolerance distance for overlap tests. + This allows reporting overlap in situations where + intersection snapping is being used. + If this is used the chain envelope must be computed + providing an expansion distance using . + + + + + + Creates a new MonotoneChain based on the given array of points. + + The points containing the chain + The index of the first coordinate in the chain + The index of the last coordinate in the chain + A user-defined data object + + + + Gets or sets the Id of this chain + + + Useful for assigning an ordering to a set of + chains, which can be used to avoid redundant processing. + + + + + Gets or sets the overlap distance used in overlap tests + with other chains. + + + + + Gets the chain's user-defined context data value. + + + + + Gets the envelope of this chain + + + + + Gets the envelope for this chain, + expanded by a given distance. + + Distance to expand the envelope by + The expanded envelope of the chain + + + + Gets the index of the start of the monotone chain + in the underlying array of points. + + + + + Gets the index of the end of the monotone chain + in the underlying array of points. + + + + + Gets the line segment starting at + + The index of the segment + The line segment to extract to + + + + Return the subsequence of coordinates forming this chain. + Allocates a new array to hold the Coordinates. + + + + + Determine all the line segments in the chain whose envelopes overlap + the searchEnvelope, and process them. + + + The monotone chain search algorithm attempts to optimize + performance by not calling the select action on chain segments + which it can determine are not in the search envelope. + However, it *may* call the select action on segments + which do not intersect the search envelope. + This saves on the overhead of checking envelope intersection + each time, since clients may be able to do this more efficiently. + + The search envelope + The select action to execute on selected segments + + + + + + + + + + + + + Determines the line segments in two chains which may overlap, + and passes them to an overlap action. + + + The monotone chain search algorithm attempts to optimize + performance by not calling the overlap action on chain segments + which it can determine do not overlap. + However, it* may* call the overlap action on segments + which do not actually interact. + This saves on the overhead of checking intersection + each time, since clients may be able to do this more efficiently. + + The chain to compare to + The overlap action to execute on selected segments + + + + Determines the line segments in two chains which may overlap, + using an overlap distance tolerance, + and passes them to an overlap action. + + The chain to compare to + The overlap tolerance distance (may be 0) + The overlap action to execute on selected segments + + + + Uses an efficient mutual binary search strategy + to determine which pairs of chain segments + may overlap, and calls the given overlap action on them. + + The start index of this chain section + The end index of this chain section + The target monotone chain + The start index of the target chain section + The end index of the target chain section + The overlap tolerance distance (may be 0) + The overlap action to execute on selected segments + + + + Tests whether the envelope of a section of the chain + overlaps(intersects) the envelope of a section of another target chain. + This test is efficient due to the monotonicity property + of the sections(i.e.the envelopes can be are determined + from the section endpoints + rather than a full scan). + + The start index of this chain section + The end index of this chain section + The target monotone chain + The start index of the target chain section + The end index of the target chain section + The overlap tolerance distance (may be 0) + true if the section envelopes overlap + + + The 1st coordinate of the 1st segment + The 2nd coordinate of the 1st segment + The 1st coordinate of the 2nd segment + The 2nd coordinate of the 2nd segment + The overlap tolerance distance (may be 0) + + + + Constructs s + for sequences of s. + + + + + Only static methods! + + + + + Computes a list of the s + for a list of coordinates. + + The list of points to compute chains for + A list of the monotone chains for the points + + + + Return a list of the MonotoneChains + for the given list of coordinates. + + The list of points to compute chains for + A data object to attach to each chain + A list of the monotone chains for the points + + + + Return an array containing lists of start/end indexes of the monotone chains + for the given list of coordinates. + The last entry in the array points to the end point of the point array, + for use as a sentinel. + + + + + + Finds the index of the last point in a monotone chain + starting at a given point. + Any repeated points (0-length segments) will be included + in the monotone chain returned. + + The coordinates + The start index + + The index of the last point in the monotone chain starting at start. + + + + + The action for the internal iterator for performing + overlap queries on a MonotoneChain. + + + + + + + + + + + + + + + This function can be overridden if the original chains are needed. + + + The index of the start of the overlapping segment from mc1. + + The index of the start of the overlapping segment from mc2. + + + + This is a convenience function which can be overridden to obtain the actual + line segments which overlap. + + + + + + + The action for the internal iterator for performing + envelope select queries on a MonotoneChain. + + + + + + + + + + This method is overridden to process a segment + in the context of the parent chain. + + The parent chain + The index of the start vertex of the segment being processed + + + + This is a convenience method which can be overridden to obtain the actual + line segment which is selected. + + + + + + A Hilbert-Packed R-tree. This is a static R-tree + which is packed by using the Hilbert ordering + of the tree items. + + The tree is constructed by sorting the items + by the Hilbert code of the midpoint of their envelope. + Then, a set of internal layers is created recursively + as follows: + + The items/nodes of the previous are partitioned into blocks of size nodeCapacity + For each block a layer node is created with range equal to the envelope of the items/nodess in the block + + The internal layers are stored using an array to + store the node bounds. + The link between a node and its children is + stored implicitly in the indexes of the array. + For efficiency, the offsets to the layers + within the node array are pre-computed and stored. + + NOTE: Based on performance testing, + the HPRtree is somewhat faster than the STRtree. + It should also be more memory-efficent, + due to fewer object allocations. + + However, it is not clear whether this + will produce a significant improvement + for use in JTS operations. + + + Martin Davis + + + + Creates a new index with the default node capacity. + + + + + Creates a new index with the given node capacity. + + The node capacity to use + + + Gets the number of items in the index. + The number of items + + + + + + + + + + + + + Tests whether two envelopes intersect. + Avoids the null check in . + An envelope + An envelope + true if the envelopes intersect + + + + Not supported, will always return false + + + + Builds the index, if not already built. + + + + + Computes the number of blocks (nodes) required to + cover a given number of children. + + + + the number of nodes needed to cover the children + + + + Gets the extents of the internal index nodes + + A list of the internal node extents + + + + This property is named Item in JTS + + + + + + + + A visitor for nodes and items in an index. + + + + + + + + + + + A visitor for items in a . + + + + + Visits an item in the index. + + The index item to be visited. + + + + A visitor for items in a + Not used, commited by accident! + + The type of the items in the index + [Obsolete] + + + + Gets a value indicating if no more items need to be visited + + + + + + + + A static index on a set of 1-dimensional intervals, + using an R-Tree packed based on the order of the interval midpoints. + + + It supports range searching, + where the range is an interval of the real line (which may be a single point). + A common use is to index 1-dimensional intervals which + are the projection of 2-D objects onto an axis of the coordinate system. + + This index structure is static + - items cannot be added or removed once the first query has been made. + The advantage of this characteristic is that the index performance + can be optimized based on a fixed set of items. + + Martin Davis + + + + + If root is null that indicates + that the tree has not yet been built, + OR nothing has been added to the tree. + In both cases, the tree is still open for insertions. + + + + + Adds an item to the index which is associated with the given interval + + The lower bound of the item interval + The upper bound of the item interval + The item to insert + if the index has already been queried + + + + Search for intervals in the index which intersect the given closed interval + and apply the visitor to them. + + The lower bound of the query interval + The upper bound of the query interval + The visitor to pass any matched items to + + + + The basic insertion and query operations supported by classes + implementing spatial index algorithms. + A spatial index typically provides a primary filter for range rectangle queries. A + secondary filter is required to test for exact intersection. Of course, this + secondary filter may consist of other tests besides intersection, such as + testing other kinds of spatial relationships. + + + + + Adds a spatial item with an extent specified by the given Envelope to the index. + + + + + Queries the index for all items whose extents intersect the given search Envelope + Note that some kinds of indexes may also return objects which do not in fact + intersect the query envelope. + + The envelope to query for. + A list of the items found by the query. + + + + Queries the index for all items whose extents intersect the given search , + and applies an to them. + Note that some kinds of indexes may also return objects which do not in fact + intersect the query envelope. + + The envelope to query for. + A visitor object to apply to the items found. + + + + Removes a single item from the tree. + + The Envelope of the item to remove. + The item to remove. + true if the item was found. + + + + A visitor for s in a index. + + 1.7 + + + + Visits a node. + + The node to visit + + + + A node of a , which represents one or more points in the same location. + + The type of the object + dskea + + + + Creates a new KdNode. + + coordinate of point + coordinate of point + A data objects to associate with this node + + + + Creates a new KdNode. + + The point location of new node + A data objects to associate with this node + + + + Gets x-ordinate of this node + + The x-ordinate + + + + Gets y-ordinate of this node + + The y-ordinate + + + + Gets the split value at a node, depending on + whether the node splits on X or Y. + The X (or Y) ordinates of all points in the left subtree + are less than the split value, and those + in the right subtree are greater than or equal to the split value. + + A flag whether the node splits a X or Y + The splitting value + + + + Gets the location of this node + + The Coordinate + + + + Gets the user data object associated with this node. + + The user data + + + + Gets or sets the left node of the tree + + The left node + + + + Gets or sets the right node of the tree + + The right node + + + + Gets the number of inserted points that are coincident at this location. + + + + + Gets whether more than one point with this value have been inserted (up to the tolerance) + + + + + + Tests whether the node's left subtree may contain values + in a given range envelope. + + A flag whether the node splits on X or Y + The range envelope + true if the left subtree is in range + + + + Tests whether the node's right subtree may contain values + in a given range envelope. + + A flag whether the node splits on X or Y + The range envelope + trueif the right subtree is in range + + + + Tests whether a point is strictly to the left + of the splitting plane for this node. + If so it may be in the left subtree of this node, + Otherwise, the point may be in the right subtree. + The point is to the left if its X (or Y) ordinate + is less than the split value. + + A flag whether the node splits on X or Y + The query point + true if the point is strictly to the left. + + + + + An implementation of a + KD - Tree + over two dimensions(X and Y). + KD-trees provide fast range searching and fast lookup for point data. + The tree is built dynamically by inserting points. + The tree supports queries by range and for point equality. + For querying an internal stack is used instead of recursion to avoid overflow. + + + This implementation supports detecting and snapping points which are closer + than a given distance tolerance. + If the same point (up to tolerance) is inserted + more than once , it is snapped to the existing node. + In other words, if a point is inserted which lies + within the tolerance of a node already in the index, + it is snapped to that node. + When an inserted point is snapped to a node then a new node is not created + but the count of the existing node is incremented. + If more than one node in the tree is within tolerance of an inserted point, + the closest and then lowest node is snapped to. + + The structure of a KD-Tree depends on the order of insertion of the points. + A tree may become umbalanced if the inserted points are coherent + (e.g.monotonic in one or both dimensions). + A perfectly balanced tree has depth of only log2(N), + but an umbalanced tree may be much deeper. + This has a serious impact on query efficiency. + One solution to this is to randomize the order of points before insertion + (e.g. by using Fisher - Yates shuffling). + + The type of the user data object + David Skea + Martin Davis + + + + Converts a collection of s to an array of s. + + A collection of nodes + An array of the coordinates represented by the nodes + + + + Converts a collection of {@link KdNode}s + to an array of s, + specifying whether repeated nodes should be represented + by multiple coordinates. + + a collection of nodes + true if repeated nodes should + be included multiple times + An array of the coordinates represented by the nodes + + + + Creates a new instance of a KdTree with a snapping tolerance of 0.0. + (I.e. distinct points will not be snapped) + + + + + Creates a new instance of a KdTree with a snapping distance + tolerance. Points which lie closer than the tolerance to a point already + in the tree will be treated as identical to the existing point. + + The tolerance distance for considering two points equal + + + + Tests whether the index contains any items. + + + + + Gets a value indicating the root node of the tree + + The root node of the tree + + + + Inserts a new point in the kd-tree, with no data. + + The point to insert + The kdnode containing the point + + + + Inserts a new point into the kd-tree. + + The point to insert + A data item for the point + + A new KdNode if a new point is inserted, else an existing + node is returned with its counter incremented. This can be checked + by testing returnedNode.getCount() > 1. + + + + + Finds the node in the tree which is the best match for a point + being inserted. + The match is made deterministic by returning the lowest of any nodes which + lie the same distance from the point. + There may be no match if the point is not within the distance tolerance of any + existing node. + + The point being inserted + + + the best matching node + null if no match was found + + + + + + Inserts a point known to be beyond the distance tolerance of any existing node. + The point is inserted at the bottom of the exact splitting path, + so that tree shape is deterministic. + + The point to insert + The data associated with + + + The data for the point + The created node + + + + + + Performs a range search of the points in the index and visits all nodes found. + + The range rectangle to query + A visitor to visit all nodes found by the search + + + + Performs a range search of the points in the index. + + The range rectangle to query + A collection of the KdNodes found + + + + Performs a range search of the points in the index. + + The range rectangle to query + A collection to accumulate the result nodes into + + + + Searches for a given point in the index and returns its node if found. + + the point to query + the point node, if it is found in the index, or if not + + + + Gets a value indicating the depth of the tree + + The depth of the tree + + + + Gets a value indicating the number of items in the tree. + + The number of items in the tree. + + + + Extensions methods for the . + + + + + Performs a nearest neighbor search of the points in the index. + + The KdTree to look for the nearest neighbor + The point to search the nearset neighbor for + + + + DoubleBits manipulates Double numbers + by using bit manipulation and bit-field extraction. + For some operations (such as determining the exponent) + this is more accurate than using mathematical operations + (which suffer from round-off error). + The algorithms and constants in this class + apply only to IEEE-754 double-precision floating point format. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Determines the exponent for the number. + + + + + Determines the exponent for the number. + + + + + + + + + + + + + + + + + + This computes the number of common most-significant bits in the mantissa. + It does not count the hidden bit, which is always 1. + It does not determine whether the numbers have the same exponent - if they do + not, the value computed by this function is meaningless. + + + The number of common most-significant mantissa bits. + + + + A representation of the Double bits formatted for easy readability. + + + + + Provides a test for whether an interval is + so small it should be considered as zero for the purposes of + inserting it into a binary tree. + The reason this check is necessary is that round-off error can + cause the algorithm used to subdivide an interval to fail, by + computing a midpoint value which does not lie strictly between the + endpoints. + + + + + Only static methods! + + + + + This value is chosen to be a few powers of 2 less than the + number of bits available in the double representation (i.e. 53). + This should allow enough extra precision for simple computations to be correct, + at least for comparison purposes. + + + + + Computes whether the interval [min, max] is effectively zero width. + I.e. the width of the interval is so much less than the + location of the interval that the midpoint of the interval cannot be + represented precisely. + + + + + A Key is a unique identifier for a node in a quadtree. + It contains a lower-left point and a level number. The level number + is the power of two for the size of the node envelope. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Return a square envelope containing the argument envelope, + whose extent is a power of two and which is based at a power of 2. + + + + + + + + + + + + + Represents a node of a Quadtree. Nodes contain + items which have a spatial extent corresponding to the node's position + in the quadtree. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Returns the subquad containing the envelope . + Creates the subquad if + it does not already exist. + + The envelope to search for + The subquad containing the search envelope. + + + + Returns the smallest existing + node containing the envelope. + + + + + + + + + + + + Get the subquad for the index. + If it doesn't exist, create it. + + + + + + + + + + + + + Gets a value indicating the level of this node + + The level of this node + + + + The base class for nodes in a Quadtree. + + + + + Gets the index of the subquad that wholly contains the given envelope. + If none does, returns -1. + + The index of the subquad that wholly contains the given envelope
+ or -1 if no subquad wholly contains the envelope
+
+ + + + + + + + subquads are numbered as follows: + 2 | 3 + --+-- + 0 | 1 + + + + + + + + + + + + + + + + + + + + + Removes a single item from this subtree. + + The envelope containing the item. + The item to remove. + true if the item was found and removed. + + + + + + + + + + + + + + Gets a value indicating that this node is empty, i.e. it does not contain an items or sub-nodes. + + + + + Insert items in this into the parameter! + + IList for adding items. + Parameter IList with this items. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A Quadtree is a spatial index structure for efficient range querying + of items bounded by 2D rectangles.
+ s can be indexed by using their s.
+ Any type of object can also be indexed, as long as it has an extent that can be + represented by an . + + This Quadtree index provides a primary filter + for range rectangle queries. The various query methods return a list of + all items which may intersect the query rectangle. Note that + it may thus return items which do not in fact intersect the query rectangle. + A secondary filter is required to test for actual intersection + between the query rectangle and the envelope of each candidate item. + The secondary filter may be performed explicitly, + or it may be provided implicitly by subsequent operations executed on the items + (for instance, if the index query is followed by computing a spatial predicate + between the query geometry and tree items, + the envelope intersection check is performed automatically. + + This implementation does not require specifying the extent of the inserted + items beforehand. It will automatically expand to accommodate any extent + of dataset. + + This data structure is also known as an MX-CIF quadtree + following the terminology usage of Samet and others. +
+
+ + + Ensure that the envelope for the inserted item has non-zero extents. + Use the current minExtent to pad the envelope, if necessary. + + + + + + + minExtent is the minimum envelope extent of all items + inserted into the tree so far. It is used as a heuristic value + to construct non-zero envelopes for features with zero X and/or Y extent. + Start with a non-zero extent, in case the first feature inserted has + a zero extent in both directions. This value may be non-optimal, but + only one feature will be inserted with this value. + + + + + Constructs a Quadtree with zero items. + + + + + Returns the number of levels in the tree. + + + + + Tests whether the index contains any items. + + + + + Returns the number of items in the tree. + + + + + + + + + + + + Removes a single item from the tree. + + The Envelope of the item to be removed. + The item to remove. + true if the item was found (and thus removed). + + + + Queries the tree and returns items which may lie in the given search envelope. + + + Precisely, the items that are returned are all items in the tree + whose envelope may intersect the search Envelope. + Note that some items with non-intersecting envelopes may be returned as well; + the client is responsible for filtering these out. + In most situations there will be many items in the tree which do not + intersect the search envelope and which are not returned - thus + providing improved performance over a simple linear scan. + + The envelope of the desired query area. + A List of items which may intersect the search envelope + + + + Queries the tree and visits items which may lie in the given search envelope. + + + Precisely, the items that are visited are all items in the tree + whose envelope may intersect the search Envelope. + Note that some items with non-intersecting envelopes may be visited as well; + the client is responsible for filtering these out. + In most situations there will be many items in the tree which do not + intersect the search envelope and which are not visited - thus + providing improved performance over a simple linear scan. + + The envelope of the desired query area. + A visitor object which is passed the visited items + + + + Return a list of all items in the Quadtree. + + + + + + + + + + + Gets a value indicating the root node of this QuadTree + + The root node of this QuadTree + + + + Item visitor that specifically excludes a predefined area. + + The type of the items to visit + + + + Initialize with + + + + + > + + + + Get a value indicating the gathered items + + + + + QuadRoot is the root of a single Quadtree. + It is centred at the origin, + and does not have a defined extent. + + + + + Insert an item into the quadtree this is the root of. + + + + + Insert an item which is known to be contained in the tree rooted at + the given QuadNode root. Lower levels of the tree will be created + if necessary to hold the item. + + + + + + + + + + + + A node of an . A node is one of: + + empty + an interior node containing child s + a leaf node containing data items (s). + + A node stores the bounds of its children, and its level within the index tree. + + + + + Constructs an AbstractNode at the given level in the tree + + + 0 if this node is a leaf, 1 if a parent of a leaf, and so on; the + root node will have the highest level. + + + + + Returns either child s, or if this is a leaf node, real data (wrapped + in s). + + + + + Returns a representation of space that encloses this Boundable, + preferably not much bigger than this Boundable's boundary yet fast to + test for intersection with the bounds of other Boundables. The class of + object returned depends on the subclass of AbstractSTRtree. + + + An Envelope (for STRtrees), an Interval (for SIRtrees), or other + object (for other subclasses of AbstractSTRtree). + + + + + Gets the bounds of this node + + + + + Returns 0 if this node is a leaf, 1 if a parent of a leaf, and so on; the + root node will have the highest level. + + + + + Gets the count of the s at this node. + + + + + Tests whether there are any s at this node. + + + + + Adds either an AbstractNode, or if this is a leaf node, a data object + (wrapped in an ItemBoundable). + + The child to add. + + + + Base class for STRtree and SIRtree. STR-packed R-trees are described in: + P. Rigaux, Michel Scholl and Agnes Voisard. Spatial Databases With + Application To GIS. Morgan Kaufmann, San Francisco, 2002. + + This implementation is based on s rather than just s, + because the STR algorithm operates on both nodes and + data, both of which are treated as s. + + + + + + A test for intersection between two bounds, necessary because subclasses + of AbstractSTRtree have different implementations of bounds. + + + + + For STRtrees, the bounds will be Envelopes; + for SIRtrees, Intervals; + for other subclasses of AbstractSTRtree, some other class. + + The bounds of one spatial object. + The bounds of another spatial object. + Whether the two bounds intersect. + + + + Constructs an AbstractSTRtree with the specified maximum number of child + nodes that a node may have. + + + + + + Constructs an AbstractSTRtree with the specified maximum number of child + nodes that a node may have, and the root node + + The maximum number of child nodes in a node + The root node that links to all other nodes in the tree + + + + Constructs an AbstractSTRtree with the specified maximum number of child + nodes that a node may have, and all leaf nodes in the tree + + The maximum number of child nodes in a node + The list of leaf nodes in the tree + + + + Creates parent nodes, grandparent nodes, and so forth up to the root + node, for the data that has been inserted into the tree. Can only be + called once, and thus can be called only after all of the data has been + inserted into the tree. + + + + + + + + + + + + Sorts the childBoundables then divides them into groups of size M, where + M is the node capacity. + + + + + + + Creates the levels higher than the given level. + + The level to build on. + the level of the Boundables, or -1 if the boundables are item + boundables (that is, below level 0). + The root, which may be a ParentNode or a LeafNode. + + + + Gets the root node of the tree. + + + + + Gets the maximum number of child nodes that a node may have. + + + + + Tests whether the index contains any items. + This method does not build the index, + so items can still be inserted after it has been called. + + + + + Gets the number of elements in the tree + + + + + Also builds the tree, if necessary. + + + + + + Gets a tree structure (as a nested list) + corresponding to the structure of the items and nodes in this tree. + The returned Lists contain either Object items, + or Lists which correspond to subtrees of the tree + Subtrees which do not contain any items are not included. + Builds the tree if necessary. + + a List of items and/or Lists + + + + A test for intersection between two bounds, necessary because subclasses + of AbstractSTRtree have different implementations of bounds. + + + + + Removes an item from the tree. + (Builds the tree, if necessary.) + + + + + Gets a value indicating the boundable items that have to be included in the index + + A list of boundable items + + + + A pair of s, whose leaf items + support a distance metric between them. + Used to compute the distance between the members, + and to expand a member relative to the other + in order to produce new branches of the + Branch-and-Bound evaluation tree. + Provides an ordering based on the distance between the members, + which allows building a priority queue by minimum distance. + + Martin Davis + + + + Creates an instance of this class with the given s and the function. + + The first boundable + The second boundable + The item distance function + + + + Gets one of the member s in the pair + (indexed by [0, 1]). + + The index of the member to return (0 or 1) + The chosen member + + + + Computes the maximum distance between any + two items in the pair of nodes. + + the maximum distance between items in the pair + + + + Computes the distance between the s in this pair. + The boundables are either composites or leaves. + If either is composite, the distance is computed as the minimum distance + between the bounds. + If both are leaves, the distance is computed by . + + The distance between the s in this pair. + + + + Gets the minimum possible distance between the Boundables in + this pair. + If the members are both items, this will be the + exact distance between them. + Otherwise, this distance will be a lower bound on + the distances between the items in the members. + + The exact or lower bound distance for this pair + + + + Compares two pairs based on their minimum distances + + + + + Tests if both elements of the pair are leaf nodes + + + + + For a pair which is not a leaf + (i.e. has at least one composite boundable) + computes a list of new pairs + from the expansion of the larger boundable + with distance less than minDistance + and adds them to a priority queue. + + Note that expanded pairs may contain + the same item/node on both sides. + This must be allowed to support distance + functions which have non-zero distances + between the item and itself (non-zero reflexive distance). + + The priority queue to add the new pairs to. + The limit on the distance between added pairs. + + + + The Class BoundablePairDistanceComparator. It implements .Net and is used + as a parameter to sort the BoundablePair list. + + + + The normal order + + + + Instantiates a new boundable pair distance comparator. + + + A value of true puts the lowest record at the head of this queue. + This is the natural order. will get the least element. + + + + + + + + Utility functions for working with s. + + mdavis + + + + Computes the maximum distance between the points defining two envelopes. + This is the distance between the two corners which are farthest apart. + + Note that this is NOT the MinMax distance, which is a tighter bound on + the distance between the points in the envelopes. + + An envelope + An envelope + The maximum distance between the points defining the envelopes + + + + Computes the Min-Max Distance between two s. + It is equal to the minimum of the maximum distances between all pairs of + edge segments from the two envelopes. + This is the tight upper bound on the distance between + geometric items bounded by the envelopes. + + Theoretically this bound can be used in the R-tree nearest-neighbour branch-and-bound search + instead of . + However, little performance improvement is observed in practice. + + An envelope + An envelope + The min-max-distance between the envelopes + + + + Computes the maximum distance between two line segments. + + x-ordinate of first endpoint of segment 1 + y-ordinate of first endpoint of segment 1 + x-ordinate of second endpoint of segment 1 + y-ordinate of second endpoint of segment 1 + x-ordinate of first endpoint of segment 2 + y-ordinate of first endpoint of segment 2 + x-ordinate of second endpoint of segment 2 + y-ordinate of second endpoint of segment 2 + Maximum distance between the segments + + + + An function for + items which are using the method. + + To make this distance function suitable for + using to query a single index tree, + the distance metric is anti-reflexive. + That is, if the two arguments are the same Geometry object, + the distance returned is . + + Martin Davis + + + + Computes the distance between two items, + using the method. + + An item which is a geometry. + An item which is a geometry. + if either item is not a Geometry + The distance between the two items. + + + + A function method which computes the distance + between two s in an . + Used for Nearest Neighbour searches. + + To make a distance function suitable for + querying a single index tree + via , + the function should have a non-zero reflexive distance. + That is, if the two arguments are the same object, + the distance returned should be non-zero. + If it is required that only pairs of distinct items be returned, + the distance function must be anti-reflexive, + and must return for identical arguments. + + Martin Davis + + + + Computes the distance between two items. + + The first item. + The second item. + If the metric is not applicable to the arguments + The distance between and . + + + + A contiguous portion of 1D-space. Used internally by SIRtree. + + + + + + + + + + + + + + + + + + Gets the centre of the interval. + + + + + + + + this + + + + + + + this + + + + + + + + + + + + + + + + + + + + + Boundable wrapper for a non-Boundable spatial object. Used internally by + AbstractSTRtree. + + + + + + + + + + + + The bounds + + + + + The item + + + + + One-dimensional version of an STR-packed R-tree. SIR stands for + "Sort-Interval-Recursive". STR-packed R-trees are described in: + P. Rigaux, Michel Scholl and Agnes Voisard. Spatial Databases With + Application To GIS. Morgan Kaufmann, San Francisco, 2002. + + + + + + + + + + + + + + + + + Constructs an SIRtree with the default (10) node capacity. + + + + + Constructs an SIRtree with the given maximum number of child nodes that + a node may have. + + + + + + + + + + + + Inserts an item having the given bounds into the tree. + + + + + + + + Returns items whose bounds intersect the given value. + + + + + + Returns items whose bounds intersect the given bounds. + + Possibly equal to x2. + Possibly equal to x1. + + + + + + + + + + + + + + + A query-only R-tree created using the Sort-Tile-Recursive (STR) algorithm. + For two-dimensional spatial data. + + The STR packed R-tree is simple to implement and maximizes space + utilization; that is, as many leaves as possible are filled to capacity. + Overlap between nodes is far less than in a basic R-tree. + However, the index is semi-static; once the tree has been built + (which happens automatically upon the first query), items may + not be added.
+ Items may be removed from the tree using . + + Described in: P. Rigaux, Michel Scholl and Agnes Voisard. Spatial Databases With + Application To GIS. Morgan Kaufmann, San Francisco, 2002. + + Note that inserting items into a tree is not thread-safe. + Inserting performed on more than one thread must be synchronized externally. + + Querying a tree is thread-safe. The building phase is done synchronously, + and querying is stateless. +
+
+ + + Constructs an STRtree with the default (10) node capacity. + + + + + Constructs an STRtree with the given maximum number of child nodes that + a node may have. + + The minimum recommended capacity setting is 4. + + + + Constructs an AbstractSTRtree with the specified maximum number of child + nodes that a node may have, and the root node + + The minimum recommended capacity setting is 4 + The maximum number of child nodes in a node + The root node that links to all other nodes in the tree + + + + Constructs an AbstractSTRtree with the specified maximum number of child + nodes that a node may have, and all leaf nodes in the tree + + The minimum recommended capacity setting is 4 + The maximum number of child nodes in a node + The list of leaf nodes in the tree + + + + + + + + + + + + + + + + + + + + + + + + + + Creates the parent level for the given child level. First, orders the items + by the x-values of the midpoints, and groups them into vertical slices. + For each slice, orders the items by the y-values of the midpoints, and + group them into runs of size M (the node capacity). For each run, creates + a new (parent) node. + + + + + + + + + + + + + + + + + + + + + + + + + Must be sorted by the x-value of the envelope midpoints. + + + + + + + + + + + + + + + + + Inserts an item having the given bounds into the tree. + + + + + + + Returns items whose bounds intersect the given envelope. + + + + + + Returns items whose bounds intersect the given envelope. + + + + + + + Removes a single item from the tree. + + The Envelope of the item to remove. + The item to remove. + true if the item was found. + + + + + + + + + + Finds the two nearest items in the tree, + using as the distance metric. + A Branch-and-Bound tree traversal algorithm is used + to provide an efficient search. + + If the tree is empty, the return value is null. + If the tree contains only one item, the return value is a pair containing that item. + If it is required to find only pairs of distinct items, + the function must be anti-reflexive. + + A distance metric applicable to the items in this tree + The pair of the nearest items or null if the tree is empty + + + + Finds the item in this tree which is nearest to the given , + using as the distance metric. + A Branch-and-Bound tree traversal algorithm is used + to provide an efficient search. + + The query does not have to be + contained in the tree, but it does + have to be compatible with the + distance metric. + + The envelope of the query item + The item to find the nearest neighbour of + A distance metric applicable to the items in this tree and the query item + The nearest item in this tree or null if the tree is empty + + + + Finds the two nearest items from this tree + and another tree, + using as the distance metric. + A Branch-and-Bound tree traversal algorithm is used + to provide an efficient search. + The result value is a pair of items, + the first from this tree and the second + from the argument tree. + + Another tree + A distance metric applicable to the items in the trees + The pair of the nearest items, one from each tree or null if no pair of distinct items can be found. + + + + Tests whether some two items from this tree and another tree + lie within a given distance. + is used as the distance metric. + A Branch-and-Bound tree traversal algorithm is used + to provide an efficient search. + + Another tree + A distance metric applicable to the items in the trees + The distance limit for the search + true if there are items within the distance + + + + Performs a withinDistance search on the tree node pairs. + This is a different search algorithm to nearest neighbour. + It can utilize the between + tree nodes to confirm if two internal nodes must + have items closer than the maxDistance, + and short-circuit the search. + + The initial pair containing the tree root nodes + The maximum distance to search for + true if two items lie within the given distance + + + + Finds k items in this tree which are the top k nearest neighbors to the given item, + using itemDist as the distance metric. + A Branch-and-Bound tree traversal algorithm is used + to provide an efficient search. + This method implements the KNN algorithm described in the following paper: + + Roussopoulos, Nick, Stephen Kelley, and Frédéric Vincent. "Nearest neighbor queries." + ACM sigmod record. Vol. 24. No. 2. ACM, 1995. + + The query item does not have to be + contained in the tree, but it does + have to be compatible with the itemDist + distance metric. + + The envelope of the query item + The item to find the nearest neighbour of + A distance metric applicable to the items in this tree and the query item + The K nearest items in kNearestNeighbour + K nearest items in this tree + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ProjectionEvents are ordered first by their x-value, and then by their eventType. + It is important that Insert events are sorted before Delete events, so that + items whose Insert and Delete events occur at the same x-value will be + correctly handled. + + + + + + A sweepline implements a sorted index on a set of intervals. + It is used to compute all overlaps between the interval in the index. + + + + + + + + + + + Because Delete Events have a link to their corresponding Insert event, + it is possible to compute exactly the range of events which must be + compared to a given Insert event object. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Extends the class to allow writing values in the BigEndian format. + + + While extends + adding methods for writing integer values () + and double values () in the BigEndian format, + this implementation overrides methods, such + and and more, + for writing values in the BigEndian format. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The supplied stream. + output is null. + + The stream does not support writing, or the stream is already closed. + + + + Initializes a new instance of the class. + + The supplied stream. + The character encoding. + output or encoding is null. + + The stream does not support writing, or the stream is already closed. + + + + Writes a two-byte signed integer to the current stream using BigEndian encoding + and advances the stream position by two bytes. + + The two-byte signed integer to write. + The stream is closed. + An I/O error occurs. + + + + Writes a two-byte unsigned integer to the current stream using BigEndian encoding + and advances the stream position by two bytes. + + The two-byte unsigned integer to write. + The stream is closed. + An I/O error occurs. + + + + Writes a four-byte signed integer to the current stream using BigEndian encoding + and advances the stream position by four bytes. + + The four-byte signed integer to write. + The stream is closed. + An I/O error occurs. + + + + Writes a four-byte unsigned integer to the current stream using BigEndian encoding + and advances the stream position by four bytes. + + The four-byte unsigned integer to write. + The stream is closed. + An I/O error occurs. + + + + Writes an eight-byte signed integer to the current stream using BigEndian encoding + and advances the stream position by eight bytes. + + The eight-byte signed integer to write. + The stream is closed. + An I/O error occurs. + + + + Writes an eight-byte unsigned integer to the current stream using BigEndian encoding + and advances the stream position by eight bytes. + + The eight-byte unsigned integer to write. + The stream is closed. + An I/O error occurs. + + + + Writes a four-byte floating-point value to the current stream using BigEndian encoding + and advances the stream position by four bytes. + + The four-byte floating-point value to write. + The stream is closed. + An I/O error occurs. + + + + Writes an eight-byte floating-point value to the current stream using BigEndian encoding + and advances the stream position by eight bytes. + + The eight-byte floating-point value to write. + The stream is closed. + An I/O error occurs. + + + + Extends the class to allow reading values in the specified format. + + + While extends + adding methods for reading integer values () + and double values () in the specified format, + this implementation overrides methods, such + and and more, + for reading values in the specified by format. + + + + + Initializes a new instance of the class. + + The stream. + + + + Initializes a new instance of the class. + + The supplied stream. + The byte order. + The stream does not support reading, the stream is null, or the stream is already closed. + + + + Encoding type + + + + + Reads a 2-byte signed integer from the current stream using the specified encoding + and advances the current position of the stream by two bytes. + + + A 2-byte signed integer read from the current stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads a 2-byte unsigned integer from the current stream using the specified encoding + and advances the position of the stream by two bytes. + + + A 2-byte unsigned integer read from this stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads a 4-byte signed integer from the current stream using the specified encoding + and advances the current position of the stream by four bytes. + + + A 4-byte signed integer read from the current stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads a 4-byte unsigned integer from the current stream using the specified encoding + and advances the position of the stream by four bytes. + + + A 4-byte unsigned integer read from this stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads an 8-byte signed integer from the current stream using the specified encoding + and advances the current position of the stream by eight bytes. + + + An 8-byte signed integer read from the current stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads an 8-byte unsigned integer from the current stream using the specified encoding + and advances the position of the stream by eight bytes. + + + An 8-byte unsigned integer read from this stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads a 4-byte floating point value from the current stream using the specified encoding + and advances the current position of the stream by four bytes. + + + A 4-byte floating point value read from the current stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads an 8-byte floating point value from the current stream using the specified encoding + and advances the current position of the stream by eight bytes. + + + An 8-byte floating point value read from the current stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads a string from the current stream. + The string is prefixed with the length, encoded as an integer seven bits at a time. + + The string being read. + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads a decimal value from the current stream + and advances the current position of the stream by sixteen bytes. + + + A decimal value read from the current stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Byte order + + + + + BigEndian + + + + + LittleEndian + + + + + Lightweight class that handles OGC Geometry type declaration + + + + + Initializes this instance + + The value describing the + + + + Inititalizes this instance based on a geometry and an Ordinates flag. + + The geometry. + The ordinates flag. + + + + Inititalizes this instance based on an + + The OGC geometry type + + + + Inititalizes this instance based on an and an SRID indicator + + The OGC geometry type + Indicator if a SRID is supplied. + + + + Inititalizes this instance based on an and an SRID indicator + + The OGC geometry type + The ordinates flag. + Indicator if a SRID is supplied. + + + + Gets or sets the base geometry type + + + + + Gets the OGC Well-Known-Binary type code + + + + + Gets the PostGIS Enhanced Well-Known-Binary type code + + + + + Gets or sets whether z-ordinate values are stored along with the geometry. + + + + + Gets or sets whether m-ordinate values are stored along with the geometry. + + + + + Gets whether SRID value is stored along with the geometry. + + + + + Gets or sets whether z-ordinate values are stored along with the geometry. + + + + + Gets or sets whether m-ordinate values are stored along with the geometry. + + + + + Gets or sets whether z-ordinates are stored along with the geometry. + PostGis EWKB format. + + + + + Gets or sets whether z-ordinates are stored along with the geometry. + PostGis EWKB format. + + + + + Gets or sets whether z-ordinates are stored along with the geometry. + PostGis EWKB format. + + + + + Reads a GML document and creates a representation of the features based on NetTopologySuite model. + Uses GML 2.1.1 Geometry.xsd schema for base for features. + + + + + builder. + + + + + Initialize reader with a standard . + + + + + Initialize reader with the given . + + + + + Read a GML document and returns relative . + + + + + + + Read a GML document and returns relative . + + + + + + + Reads the coordinate. + + The reader. + + + + + Extract a from a x,y string value. + + + + + + + Extract a from a pos entity string value. + + + + + + + Extract a from a x,y string value. + + + + + Identifies a version of the GML specification. + + + + + Version 2.1.1 (OGC 02-009). + + + + + Version 3.2.2 (OGC 07-036r1 / ISO 19136:2007). + + + + + Writes the GML representation of the features of NetTopologySuite model. + Uses GML 2.1.1 Geometry.xsd schema for base for features. + + Thanks to rstuven for improvements :) + + + + + + Formatter for double values of coordinates + + + + + Initializes a new instance of the class. + + + + + Returns an XmlReader with feature informations. + Use XmlDocument.Load(XmlReader) for obtain a XmlDocument to work. + + + + + + + Writes a GML feature into a generic Stream, such a FileStream or other streams. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sets corrent length for Byte Stream. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Provides the EPSG code exposing the SRID of the geometry + + The SRID of the geometry + + + + + Writes the GML representation of the features of NetTopologySuite model. + Uses GML 3.2.2 gml.xsd schema for base for features. + + + + + Initializes a new instance of the class. + + + + + Constructs objects from the OGC KML representation. + Works only with KML geometry elements and may also parse attributes within these elements + + + + + Creates a reader that creates objects using the default . + + + + + Creates a reader that creates objects using the given . + + The factory used to create Geometrys. + + + + Creates a reader that creates objects using the default . + + Names of attributes that should be parsed (i.e. extrude, altitudeMode, tesselate, etc). + + + + Creates a reader that creates objects using the given . + + The factory used to create Geometrys. + Names of attributes that should be parsed (i.e. extrude, altitudeMode, tesselate, etc). + + + + Reads a KML representation of a from a . + + If any attribute names were specified during {@link KMLReader} construction, + they will be stored as in . + + The string that specifies kml representation of geometry. + A Geometry + Thrown if a parsing problem occurs. + + + + Reads a KML representation of a from a . + + If any attribute names were specified during {@link KMLReader} construction, + they will be stored as in . + + The text stream reader. + A Geometry + Thrown if a parsing problem occurs. + + + + Writes a formatted string containing the KML representation + of a JTS . + The output is KML fragments which can be substituted + wherever the KML abstract + element can be used. + + + Output elements are indented to provide a + nicely-formatted representation. + An output line prefix and maximum + number of coordinates per line can be specified. + + + The Z ordinate value output can be forced to be a specific value. + The and modes can be set. + If set, the corresponding sub-elements will be output. + + + + + The KML standard value clampToGround for use in . + + + + + The KML standard value relativeToGround for use in . + + + + + The KML standard value absolute for use in . + + + + + Writes a Geometry as KML to a string, using + a specified Z value. + + the geometry to write + the Z value to use + a string containing the KML geometry representation + + + + Writes a Geometry as KML to a string, using + a specified Z value, precision, extrude flag, + and altitude mode code. + + the geometry to write + the Z value to use + the maximum number of decimal places to write + the extrude flag to write + the altitude model code to write + a string containing the KML geometry representation + + + + A tag string which is prefixed to every emitted text line. + This can be used to indent the geometry text in a containing document. + + + + + The maximum number of coordinates to output per line. + + + + + The Z value to be output for all coordinates. + This overrides any Z value present in the Geometry coordinates. + + + + + The flag to be output in the extrude element. + + + + + The flag to be output in the tesselate element. + + + + + The value output in the altitudeMode element. + + + + + The maximum number of decimal places to output in ordinate values. + Useful for limiting output size. + + + negative values set the precision to , + like standard behavior. + + + + + Writes a in KML format as a string. + + the geometry to write + a string containing the KML geometry representation + + + + Writes the KML representation of a to a . + + the geometry to write + the writer to write to + + + + Appends the KML representation of a to a . + + the geometry to write + the buffer to write into + + + + Takes a list of coordinates and converts it to KML. + + + 2D and 3D aware. Terminates the coordinate output with a newline. + + + + + Formats numeric values for ordinates + in a consistent, accurate way. + + The format has the following characteristics: + + It is consistent in all locales (in particular, the decimal separator is always a period) + Scientific notation is never output, even for very large numbers. This means that it is possible that output can contain a large number of digits. + The maximum number of decimal places reflects the available precision + NaN values are represented as "NaN" + Inf values are represented as "Inf" or "-Inf" + + + mdavis + + + + The output representation of + + + + + The output representation of + + + + + The output representation of + + + + + The maximum number of fraction digits to support output of reasonable ordinate values. + + The default is chosen to allow representing the smallest possible IEEE-754 double-precision value, + although this is not expected to occur (and is not supported by other areas of the JTS/NTS code). + + + + + The default formatter using the maximum number of digits in the fraction portion of a number. + + + + + Creates an OrdinateFormat using the default maximum number of fraction digits. + + + + + Creates an OrdinateFormat using the given maximum number of fraction digits. + + The maximum number of fraction digits to output + + + + Returns a string representation of the given ordinate numeric value. + + The ordinate value + The formatted number string + + + + Thrown by a WKTReader when a parsing problem occurs. + + + + + Creates a ParseException with the given detail message. + + A description of this ParseException. + + + + Creates a ParseException with es detail message. + + An exception that occurred while a WKTReader was + parsing a Well-known Text string. + + + + Creates a ParseException with s detail message + + + The inner exception + + + + WKB Geometry Types + + + + + Point. + + + + + LineString. + + + + + Polygon. + + + + + MultiPoint. + + + + + MultiLineString. + + + + + MultiPolygon. + + + + + GeometryCollection. + + + + + Point with Z coordinate. + + + + + LineString with Z coordinate. + + + + + Polygon with Z coordinate. + + + + + MultiPoint with Z coordinate. + + + + + MultiLineString with Z coordinate. + + + + + MultiPolygon with Z coordinate. + + + + + GeometryCollection with Z coordinate. + + + + + Point with M ordinate value. + + + + + LineString with M ordinate value. + + + + + Polygon with M ordinate value. + + + + + MultiPoint with M ordinate value. + + + + + MultiLineString with M ordinate value. + + + + + MultiPolygon with M ordinate value. + + + + + GeometryCollection with M ordinate value. + + + + + Point with Z coordinate and M ordinate value. + + + + + LineString with Z coordinate and M ordinate value. + + + + + Polygon with Z coordinate and M ordinate value. + + + + + MultiPoint with Z coordinate and M ordinate value. + + + + + MultiLineString with Z coordinate and M ordinate value. + + + + + MultiPolygon with Z coordinate and M ordinate value. + + + + + GeometryCollection with Z coordinate and M ordinate value. + + + + + Reads a sequence of {@link Geometry}s in WKBHex format + from a text file. + Each WKBHex geometry must be on a single line + The geometries in the file may be separated by any amount + of whitespace and newlines. + + Martin Davis + + + + Creates a new given the + to use to parse the geometries. + + The geometry reader to use + + + + Gets or sets a value indicating the maximum number of geometries to read + + + + + Gets or sets the number of geometries to skip before storing. + + + + + Reads a sequence of geometries.
+ If an is specified, geometries read up to the offset count are skipped. + If a is specified, no more than geometries are read. +
+ The path to the file + Thrown if no filename was specified + Thrown if the filename specified does not exist + Thrown if an I/O exception was encountered + Thrown if an error occurred reading a geometry +
+ + + Reads a sequence of geometries.
+ If an is specified, geometries read up to the offset count are skipped. + If a is specified, no more than geometries are read. +
+ The path to the file + Thrown if no stream was passed + Thrown if passed stream is not readable or seekable + Thrown if an I/O exception was encountered + Thrown if an error occured reading a geometry +
+ + + Reads a sequence of geometries.
+ If an is specified, geometries read up to the offset count are skipped. + If a is specified, no more than geometries are read. +
+ The stream reader to use. + Thrown if an I/O exception was encountered + Thrown if an error occured reading a geometry +
+ + + Tests if reader has reached limit + + A collection of already read geometries + true if number of geometries has been read. + + + + Tests if reader is at EOF. + + + + + Converts a Well-Known Binary byte data to a Geometry. + + + This class reads the format describe in {@link WKBWriter}. + It partially handles theExtended WKB format used by PostGIS, + by parsing and storing optional SRID values. + If a SRID is not specified in an element geometry, it is inherited + from the parent's SRID. + The default SRID value depends on . + + Although not defined in the WKB spec, empty points + are handled if they are represented as a Point with NaN X and Y ordinates. + + The reader repairs structurally-invalid input + (specifically, LineStrings and LinearRings which contain + too few points have vertices added, + and non-closed rings are closed). + + The reader handles most errors caused by malformed or malicious WKB data. + It checks for obviously excessive values of the fields + numElems, numRings, and numCoords. + It also checks that the reader does not read beyond the end of the data supplied. + A is thrown if this situation is detected. + + + + + Converts a hexadecimal string to a byte array. + The hexadecimal digit symbols are case-insensitive. + + A string containing hex digits + An array of bytes with the value of the hex string + + + + Initialize reader with a standard . + + + + + Creates an instance of this class using the provided NtsGeometryServices + + + + + + Reads a in binary WKB format from an array of s. + + The byte array to read from + The geometry read + if the WKB data is ill-formed. + + + + Reads a in binary WKB format from an . + + The stream to read from + The geometry read + if the WKB data is ill-formed. + + + + WKB Coordinate Systems + + + + + 2D coordinate system + + + + + 3D coordinate system + + + + + 2D coordinate system with additional measure value + + + + + 3D coordinate system with additional measure value + + + + + + + + + + + + + + + + + + Function to read a coordinate sequence. + + The reader + The number of ordinates + The coordinate system + The read coordinate sequence. + + + + Function to read a coordinate sequence that is supposed to form a ring. + + The reader + The number of ordinates + The coordinate system + The read coordinate sequence. + + + + Function to read a coordinate sequence that is supposed to serve a line string. + + The reader + The number of ordinates + The coordinate system + The read coordinate sequence. + + + + Function to convert from to + + The coordinate system + The corresponding + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Gets or sets a value indicating if a possibly encoded SRID value should be handled. + + + + + Gets a value indicating which ordinates can be handled. + + + + + Gets a value indicating which ordinates should be handled. + + + + + Gets or sets a value indicating if the reader should attempt to repair malformed input. + + + Malformed in this case means the ring has too few points (4), + or is not closed. + + + + + Gets or sets whether invalid linear rings should be fixed + + + + + Function to determine whether an ordinate should be handled or not. + + + + + + + Writes a Well-Known Binary byte data representation of a Geometry. + + + There are a few cases which are not specified in the standard. + The implementation uses a representation which is compatible with + other common spatial systems (notably, PostGIS). + + sare written as s. + Empty geometries are output as follows + + PointA WKBPoint with double.NaN ordinate values + LineStringA WKBLineString with zero points + Polygoncurrently output as a WKBPolygon with one LinearRing with zero points. + Note: This is different to other systems. It will change to a WKBPolygon with zero LinearRings. + Multi geometriesA WKBMulti with zero elements + GeometryCollectionA WKBGeometryCollection with zero elements + + + + This implementation supports the Extended WKB standard. + Extended WKB allows writing 3-dimensional coordinates + and the geometry SRID value. + The presence of 3D coordinates is indicated + by setting the high bit of the wkbType word. + The presence of a SRID is indicated + by setting the third bit of the wkbType word. + EWKB format is upward-compatible with the original SFS WKB format. + + SRID output is optimized, if specified. + The top-level geometry has the SRID included. Child geometries + have it included if their value differs from its parent. + + This class supports reuse of a single instance to read multiple + geometries. This class is not thread - safe; each thread should create its own + instance. + + + + Converts a byte array to a hexadecimal string. + A byte array + + + + Writes the WKB Header for the geometry + + The writer + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Gets or sets the binary encoding type + + + + + Standard byte size for each complex point. + Each complex point (LineString, Polygon, ...) contains: + 1 byte for ByteOrder and + 4 bytes for WKBType. + 4 bytes for SRID value + + + + + Calculates the number of bytes required to store (E)WKB Header information. + + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The size of the + + + + Initializes writer with LittleIndian byte order. + + + + + Initializes writer with the specified byte order. + + Encoding type + + + + Initializes writer with the specified byte order. + + Encoding type + SRID values, present or not, should be emitted. + + + + Initializes writer with the specified byte order. + + Encoding type + SRID values, present or not, should be emitted. + Z values, present or not, should be emitted + + + + Initializes writer with the specified byte order. + + Encoding type + SRID values, present or not, should be emitted. + Z values, present or not, should be emitted + M values, present or not, should be emitted + + + + Writes a WKB representation of a given point. + + + + + + + Writes a WKB representation of a given point. + + + + + + + + + + + + + + + + + + + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Writes the ByteOrder defined in . + + The writer to use + + + + Write a . + + The coordinate + The writer. + + + + Write a . + + The coordinate sequence to write + A flag indicating if the size of should be written, too. + The writer. + + + + Write a point in its WKB format + + The point + The writer + + + + Write a point in its WKB format + + The point + The writer + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Write a LineString in its WKB format + + The LineString + The writer + + + + Write a LineString in its WKB format + + The LineString + The writer + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Write LinearRing information + + The linear ring + The writer + + + + Write a Polygon in its WKB format + + The Polygon + The writer + + + + Write a Polygon in its WKB format + + The Polygon + The writer + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Write a MultiPoint in its WKB format + + The MultiPoint + The writer + + + + Write a MultiPoint in its WKB format + + The MultiPoint + The writer + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Write a MultiLineString in its WKB format + + The MultiLineString + The writer + + + + Write a MultiLineString in its WKB format + + The MultiLineString + The writer + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Write a MultiPolygon in its WKB format + + The MultiPolygon + The writer + + + + Write a MultiPolygon in its WKB format + + The MultiPolygon + The writer + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Write a GeometryCollection in its WKB format + + The GeometryCollection + The writer + + + + Write a GeometryCollection in its WKB format + + The GeometryCollection + The writer + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Gets a buffer for the to write to. + + The geometry to write + A buffer + + + + Gets a buffer for the to write to. + + The geometry to write + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + A buffer + + + + Computes the length of a buffer to write in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Gets a value whether or not EWKB featues may be used. + EWKB features are + + 0x80000000 flag if geometry's z-ordinate values are written + 0x40000000 flag if geometry's m-ordinate values are written + 0x20000000 flag if geometry's SRID value is written + + + + + Gets a value indicating if only original WKT elements should be handled + + + + + Gets or sets a value indicating if an encoded SRID value should be handled or ignored. + + + + + Gets the that this class can write. + + + + + Gets or sets the maximum to write out. + The default is equivalent to . + + + + The purpose of this property is to restrict what gets written out to ensure that, + e.g., Z values are never written out even if present on a geometry instance. Ordinates + that are not present on a geometry instance will be omitted regardless of this value. + + + Flags not present in are silently ignored. + + + and are always present. + + + + + + Constants used in the WKT (Well-Known Text) format. + + Martin Davis + + + + Token text for geometries + + + + + Token text for geometries + + + + + Token text for geometries + + + + + Token text for geometries + + + + + Token text for geometries + + + + + Token text for geometries + + + + + Token text for geometries + + + + + Token text for geometries + + + + + Token text for empty geometries + + + + + Token text indicating that geometries have measure-ordinate values + + + + + Token text indicating that geometries have z-ordinate values + + + + + Token text indicating that geometries have both z- and measure-ordinate values + + + + + Reads a sequence of s in WKT format from a text file. + + The geometries in the file may be separated by any amount of whitespace and newlines. + + Martin Davis + + + + + Creates a new given the to read from and a to use to parse the geometries. + + the to read from + the geometry reader to use + + + + Creates a new , given the name of the file to read from. + + The name of the file to read from + The geometry reader to use + + + + Creates a new , given a to read from. + + The stream to read from + The geometry reader to use + + + + Creates a new , given a to read with. + + The stream reader of the file to read from + The geometry reader to use + + + + Gets/Sets the maximum number of geometries to read. + + + + + Gets/Sets allow ignoring WKT parse errors + after at least one geometry has been read, + to return a partial result. + + + + + Gets/Sets the number of geometries to skip before reading. + + + + + Reads a sequence of geometries. + + + + If an offset is specified, geometries read up to the offset count are skipped. + If a limit is specified, no more than geometries are read. + + Thrown if an I/O exception was encountered + Thrown if an error occurred reading a geometry + The list of geometries read + + + + Tests if reader is at EOF. + + + + + Converts a Well-Known Text string to a Geometry. + + The WKTReader allows + extracting Geometry objects from either input streams or + internal strings. This allows it to function as a parser to read Geometry + objects from text blocks embedded in other data formats (e.g. XML). + + The Well-known + Text format is defined in the + OpenGIS Simple Features Specification for SQL . + + As of version 2.0, NTS can read WKT syntax + which specifies coordinate dimension Z, M or ZM as modifiers(e.g.POINT Z) + or in the name of the geometry type(e.g.LINESTRINGZM). + If the coordinate dimension is specified it will be set in the created geometry. + If the coordinate dimension is not specified, the default behaviour is to + create XYZ geometry(this is backwards compatible with older JTS versions). + This can be altered to create XY geometry by + setting to false. + + NOTE: There is an inconsistency in the SFS. + The WKT grammar states that MultiPoints are represented by + MULTIPOINT ( ( x y), (x y) ), + but the examples show MultiPoints as MULTIPOINT ( x y, x y ). + Other implementations follow the latter syntax, so NTS will adopt it as well. + A WKTReader is parameterized by a GeometryFactory, + to allow it to create Geometry objects of the appropriate + implementation. In particular, the GeometryFactory will + determine the PrecisionModel and SRID that is used. + The WKTReader will convert the input numbers to the precise + internal representation. + + reads also non-standard tags. + + + + + + Creates a WKTReader that creates objects using a basic GeometryFactory. + + + + + Creates a WKTReader that creates objects using a basic GeometryFactory. + + + + + Creates a WKTReader that creates objects using the given + GeometryFactory. + + The factory used to create Geometrys. + + + + Gets or sets a value indicating whether or not coordinates may have 3 ordinate values + even though no Z or M ordinate indicator is present. The default value is + . + + + + + Gets or sets a value indicating whether or not point coordinates in a MultiPoint + geometry must not be enclosed in paren. The default value is . + + + + + Gets or sets the factory to create geometries + + + + + Gets or sets the default SRID + + + + + Gets or sets a value indicating if the reader should attempt to repair malformed input. + + + Malformed in this case means the ring has too few points (4), + or is not closed. + + + + + Converts a Well-known Text representation to a Geometry. + + + one or more Geometry Tagged Text strings (see the OpenGIS + Simple Features Specification) separated by whitespace. + + + A Geometry specified by wellKnownText + + + + + Converts a Well-known Text representation to a Geometry. + + + one or more Geometry Tagged Text strings (see the OpenGIS + Simple Features Specification) separated by whitespace. + + + A Geometry specified by wellKnownText + + + + + Converts a Well-known Text representation to a Geometry. + + + A Reader which will return a "Geometry Tagged Text" + string (see the OpenGIS Simple Features Specification). + + A Geometry read from reader. + + + + + Reads a Coordinate from a stream using the given . + + All ordinate values are read, but -depending on the + of the underlying - not necessarily all can be handled. + Those are silently dropped. + + + A geometry factory + the tokenizer to use. + a bit-mask defining the ordinates to read. + a value indicating if a starting "(" should be probed. + a of length 1 containing the read ordinate values. + if an I/O error occurs. + if an unexpected token was encountered. + + + + Reads a Coordinate from a stream using the given . + + All ordinate values are read, but -depending on the + of the underlying - not necessarily all can be handled. + Those are silently dropped. + + + A geometry factory + the tokenizer to use. + a bit-mask defining the ordinates to read. + a of length 1 containing the read ordinate values. + if an I/O error occurs. + if an unexpected token was encountered. + + + + Reads a CoordinateSequence from a stream using the given + for an old-style JTS MultiPoint (Point coordinates not enclosed in parentheses). + + All ordinate values are read, but -depending on the + of the underlying - not necessarily all can be handled. + Those are silently dropped. + + + A geometry factory + the tokenizer to use. + a bit-mask defining the ordinates to read. + a of length 1 containing the read ordinate values. + if an I/O error occurs. + if an unexpected token was encountered. + + + + Computes the required dimension based on the given ordinate bit-mask. + It is assumed that is set. + + the ordinate bit-mask. + the number of dimensions required to store ordinates for the given bit-mask. + + + + Merges an array of one-coordinate-s into one + . + + A geometry factory + an array of coordinate sequences. Each sequence contains exactly one coordinate. + a bit-mask of required ordinates. + a coordinate sequence containing all coordinate. + + + + + + + + + + + + + + + + + + Returns the next number in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next token must be a number. + + The next number in the stream. + if the next token is not a valid number + + + + Returns the next WKTConstants.EMPTY or "(" in the stream as uppercase text. + + + Tokenizer over a stream of text in Well-known Text + format. The next token must be or "(". + + + The next WKTConstants.EMPTY or "(" in the stream as uppercase text. + + + + Returns the next ordinate flag information in the stream as uppercase text. + This can be Z, M or ZM. + + tokenizer over a stream of text in Well-known Text + the next ordinate flags. + if an I/O error occurs + if the next token is not EMPTY or L_PAREN + + + + Returns the next word in the stream. + + tokenizer over a stream of text in Well-known Text format. The next token must be a word. + the next word in the stream as uppercase text + if the next token is not a word + if an I/O error occurs + + + + Returns the next ")" or "," in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next token must be ")" or ",". + + + The next ")" or "," in the stream. + + + + Returns the next ")" in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next token must be ")". + + + The next ")" in the stream. + + + + Returns the next word in the stream as uppercase text. + + + Tokenizer over a stream of text in Well-known Text + format. The next token must be a word. + + + to advance the stream, to just peek. + + The next word in the stream as uppercase text. + + + + Creates a Geometry using the next token in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a <Geometry Tagged Text. + + A Geometry specified by the next token + in the stream. + + + + Creates a Point using the next token in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a <Point Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + A Point specified by the next token in + the stream. + + + + Creates a LineString using the next token in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a <LineString Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + + A LineString specified by the next + token in the stream. + + + + Creates a LinearRing using the next token in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a <LineString Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + A LinearRing specified by the next + token in the stream. + + + + Creates a MultiPoint using the next token in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a <MultiPoint Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + + A MultiPoint specified by the next + token in the stream. + + + + Creates a Polygon using the next token in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a Polygon Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + + A Polygon specified by the next token + in the stream. + + + + + Creates a MultiLineString using the next token in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a MultiLineString Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + + A MultiLineString specified by the + next token in the stream. + + + + Creates a MultiPolygon using the next token in the stream. + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a MultiPolygon Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + + A MultiPolygon specified by the next + token in the stream, or if if the coordinates used to create the + Polygon shells and holes do not form closed linestrings. + + + + Creates a GeometryCollection using the next token in the + stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a <GeometryCollection Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + + A GeometryCollection specified by the + next token in the stream. + + + + Outputs the textual representation of a . + The outputs coordinates rounded to the precision + model. No more than the maximum number of necessary decimal places will be + output. + The Well-known Text format is defined in the OpenGIS Simple Features + Specification for SQL. + A non-standard "LINEARRING" tag is used for LinearRings. The WKT spec does + not define a special tag for LinearRings. The standard tag to use is + "LINESTRING". + + + + + Generates the WKT for a Point specified by a . + + The point coordinate. + The WKT + + + + Generates the WKT for a N-point LineString specified by a . + + The sequence to write. + The WKT + + + + Generates the WKT for a LINESTRING specified by an array of s. + + An array of coordinates + The WKT + + + + Generates the WKT for a LineString specified by two s. + + The first coordinate. + The second coordinate. + The WKT + + + + Creates the NumberFormatInfo used to write doubles + with a sufficient number of decimal places. + + + The PrecisionModel used to determine + the number of decimal places to write. + + + A NumberFormatInfo that write doubles + without scientific notation. + + + + + A filter implementation to test if a coordinate sequence actually has meaningful values + for an ordinate bit-pattern + + + + + Initializes a new instance of the flag. + + + The index for the ordinates to test. + + + if implies + , otherwise. + + + + + + + + + + + + + + Gets the evaluated ordinate bit-pattern of ordinates with valid values masked by + . + + + + + Creates an instance of this class which is writing at most 2 dimensions. + + + + + Creates an instance of this class which is writing at most dimensions. + + + + + Gets/sets whether the output will be formatted + + + + + Gets/sets the maximum number of coordinates per line written in formatted output. + + If the provided coordinate number is < 0, coordinates will be written all on one line. + + + Gets/sets the tab size to use for indenting. + If the size is non-positive + + + + Gets or sets the to be written. Possible members are: + + + + + + + Values of and are always assumed and + not particularly checked for. + + + + + Gets or sets a that should be used on the ordinates written. + + If none/ is assigned, the precision model of the + is used. + + + Note: The precision model is applied to all ordinate values, not just x and y. + + + + + + Creates a new instance of the class suitable for MSSQL's non- + standard WKT format. + + + A new instance of the class suitable for MSSQL's non-standard + WKT format. + + + + + Converts a Geometry to its Well-known Text representation. + + A Geometry to process. + A Geometry Tagged Text string (see the OpenGIS Simple Features Specification). + + + + Converts a Geometry to its Well-known Text representation. + + A Geometry to process. + A Stream to write into + + + + Converts a Geometry to its Well-known Text representation. + + A Geometry to process. + + A "Geometry Tagged Text" string (see the OpenGIS Simple Features Specification) + + + + Same as write, but with newlines and spaces to make the + well-known text more readable. + + A Geometry to process + + A "Geometry Tagged Text" string (see the OpenGIS Simple + Features Specification), with newlines and spaces. + + + + + Same as write, but with newlines and spaces to make the + well-known text more readable. + + A Geometry to process + + + A Geometry Tagged Text string (see the OpenGIS Simple + Features Specification), with newlines and spaces. + + + + + Converts a Geometry to its Well-known Text representation. + + A Geometry to process + A flag indicating that the output should be formatted. + the output writer to append to. + The precision model to use. + + A "Geometry Tagged Text" string (see the OpenGIS Simple + Features Specification). + + + + + Converts a to <Geometry Tagged Text> format, then appends + it to the writer. + + the to process. + A flag indicating that the output should be formatted. + the output writer to append to. + The format to use for writing ordinate values. + + + + Converts a to <Geometry Tagged Text> format, then appends + it to the writer. + + the to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted. + The indentation level + the output writer to append to. + The format to use for writing ordinate values. + + + + Converts a Coordinate to Point Tagged Text format, + then appends it to the writer. + + The Point to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Converts a LineString to <LineString Tagged Text + format, then appends it to the writer. + + The LineString to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Converts a LinearRing to <LinearRing Tagged Text + format, then appends it to the writer. + + The LinearRing to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Converts a Polygon to Polygon Tagged Text format, + then appends it to the writer. + + The Polygon to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Converts a MultiPoint to <MultiPoint Tagged Text + format, then appends it to the writer. + + The MultiPoint to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Converts a MultiLineString to MultiLineString Tagged + Text format, then appends it to the writer. + + The MultiLineString to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Converts a MultiPolygon to MultiPolygon Tagged Text + format, then appends it to the writer. + + The MultiPolygon to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Converts a GeometryCollection to GeometryCollection + Tagged Text format, then appends it to the writer. + + The GeometryCollection to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Appends the i'th coordinate from the sequence to the writer + + If the has coordinates that are NaN, + these are not written, even though suggests this. + + + the to process + A bit pattern of output ordinates + the index of the coordinate to write + writer the output writer to append to + The format to use for writing ordinate values + + + + + Converts a to a . + + The to convert. + A + + The as a . + + + + + Appends additional ordinate information. This function may + + + + append 'Z' if in the value is included. + + + + + append 'M' if in the value is included. + + + + + append 'ZM' if in the and + values are included. + + + + + A bit-pattern of ordinates to write. + the output writer to append to. + if an error occurs while using the writer. + + + + Appends all members of a to the stream. Each + is separated from another using a colon, the ordinates of a + are separated by a space. + + the to process. + A bit-pattern of ordinates to write. + flag indicating that. + the indentation level. + flag indicating that the first of the sequence should be indented for better visibility. + the output writer to append to. + The format to use for writing ordinate values. + + + + Converts a Polygon to Polygon Text format, then + appends it to the writer. + + The Polygon to process. + A bit-pattern of ordinates to write. + flag indicating that. + the indentation level. + flag indicating that the first of the sequence should be indented for better visibility. + the output writer to append to. + The format to use for writing ordinate values. + + + + Converts a MultiPoint to <MultiPoint Text format, then + appends it to the writer. + + The MultiPoint to process. + A bit-pattern of ordinates to write. + flag indicating that. + the indentation level. + the output writer to append to. + The format to use for writing ordinate values. + + + + Converts a MultiLineString to <MultiLineString Text + format, then appends it to the writer. + + The MultiLineString to process. + A bit-pattern of ordinates to write. + flag indicating that. + the indentation level. + the output writer to append to. + The format to use for writing ordinate values. + + + + Converts a MultiPolygon to <MultiPolygon Text format, + then appends it to the writer. + + The MultiPolygon to process. + A bit-pattern of ordinates to write. + flag indicating that. + the indentation level. + the output writer to append to. + The format to use for writing ordinate values. + + + + Converts a GeometryCollection to GeometryCollectionText + format, then appends it to the writer. + + The GeometryCollection to process. + + flag indicating that. + the indentation level. + the output writer to append to. + The format to use for writing ordinate values. + + + + Extracts the subline of a linear between + two s on the line. + + + + + Computes the subline of a between + two s on the line. + If the start location is after the end location, + the computed linear geometry has reverse orientation to the input line. + + The line to use as the baseline. + The start location. + The end location. + The extracted subline. + + + + Initializes a new instance of the class. + + + + + + Extracts a subline of the input. + If is minor that , + the linear geometry computed will be reversed. + + The start location. + The end location. + A linear geometry. + + + + + + + + + + + Assumes input is valid + (e.g. minor or equals to ). + + + + + + + + Supports linear referencing along a linear + using the length along the line as the index. + Negative length values are taken as measured in the reverse direction + from the end of the geometry. + Out-of-range index values are handled by clamping + them to the valid range of values. + Non-simple lines (i.e. which loop back to cross or touch + themselves) are supported. + + + + + Constructs an object which allows a linear + to be linearly referenced using length as an index. + + The linear geometry to reference along. + + + + Computes the for the point + on the line at the given index. + If the index is out of range the first or last point on the + line will be returned. + + + The Z-ordinate of the computed point will be interpolated from + the Z-ordinates of the line segment containing it, if they exist. + + The index of the desired point. + The at the given index. + + + + Computes the for the point on the line at the given index, offset by the given distance. + + + If the index is out of range the first or last point on the line will be returned. + The computed point is offset to the left of the line if the offset distance is + positive, to the right if negative. + The Z-ordinate of the computed point will be interpolated from the Z-ordinates of the line segment containing it, if they exist. + + The index of the desired point + The distance the point is offset from the segment (positive is to the left, negative is to the right) + The Coordinate at the given index + + + + Computes the for the interval + on the line between the given indices. + If the lies before the , + the computed geometry is reversed. + + + + + + + + + + + + + + + Computes the minimum index for a point on the line. + If the line is not simple (i.e. loops back on itself) + a single point may have more than one possible index. + In this case, the smallest index is returned. + The supplied point does not necessarily have to lie precisely + on the line, but if it is far from the line the accuracy and + performance of this function is not guaranteed. + Use to compute a guaranteed result for points + which may be far from the line. + + A point on the line. + The minimum index of the point. + + + + + Finds the index for a point on the line + which is greater than the given index. + If no such index exists, returns . + This method can be used to determine all indexes for + a point which occurs more than once on a non-simple line. + It can also be used to disambiguate cases where the given point lies + slightly off the line and is equidistant from two different + points on the line. + The supplied point does not necessarily have to lie precisely + on the line, but if it is far from the line the accuracy and + performance of this function is not guaranteed. + Use to compute a guaranteed result for points + which may be far from the line. + + A point on the line. + The value the returned index must be greater than. + The index of the point greater than the given minimum index. + + + + + Computes the indices for a subline of the line. + (The subline must conform to the line; that is, + all vertices in the subline (except possibly the first and last) + must be vertices of the line and occur in the same order). + + A subLine of the line. + A pair of indices for the start and end of the subline.. + + + + Computes the index for the closest point on the line to the given point. + If more than one point has the closest distance the first one along the line is returned. + (The point does not necessarily have to lie precisely on the line.) + + + + + + + Returns the index of the start of the line. + + + + + Returns the index of the end of the line. + + + + + Tests whether an index is in the valid index range for the line. + + The index to test. + true if the index is in the valid range. + + + + Computes a valid index for this line + by clamping the given index to the valid range of index values + + A valid index value + + + + + + + + + Initializes a new instance of the class. + + A linear geometry. + + + + Find the nearest location along a linear to a given point. + + The coordinate to locate. + The location of the nearest point. + + + + Finds the nearest index along the linear + to a given after the specified minimum index. + If possible the location returned will be strictly + greater than the . + If this is not possible, the value returned + will equal . + (An example where this is not possible is when + = [end of line] ). + + The coordinate to locate. + The minimum location for the point location. + The location of the nearest point. + + + + + + + + + + + + + + + + + + + + + Computes the for a given length + along a linear + Negative lengths are measured in reverse from end of the linear geometry. + Out-of-range values are clamped. + + + + + Computes the for a + given length along a linear . + + The linear geometry to use. + The length index of the location. + The for the length. + + + + Computes the for a + given length along a linear , + with control over how the location + is resolved at component endpoints. + + The linear geometry to use + The length index of the location + If true lengths are resolved to the lowest possible index + + + + Computes the length for a given + on a linear . + + The linear geometry to use. + The index of the location. + The length for the . + + + + Initializes a new instance of the class. + + A linear geometry. + + + + Compute the corresponding to a length. + Negative lengths are measured in reverse from end of the linear geometry. + Out-of-range values are clamped. + Ambiguous indexes are resolved to the lowest possible location value. + + The length index. + The corresponding . + + + + Compute the corresponding to a length. + Negative lengths are measured in reverse from end of the linear geometry. + Out-of-range values are clamped. + Ambiguous indexes are resolved to the lowest or highest possible location value, + depending on the value of resolveLower + + The length index + + The corresponding . + + + + + + + + + + + + + + + + + + Builds a linear geometry ( or ) + incrementally (point-by-point). + + + + + Creates an instance of this class. + + The geometry factory to use. + + + + Allows invalid lines to be fixed rather than causing Exceptions. + An invalid line is one which has only one unique point. + + + + + Allows invalid lines to be ignored rather than causing Exceptions. + An invalid line is one which has only one unique point. + + + + + Adds a point to the current line. + + The to add. + + + + Adds a point to the current line. + + The to add. + If true, allows the insertions of repeated points. + + + + + + + + + Terminate the current . + + + + + + + + + + + + Builds and returns the . + + + + + + An iterator over the components and coordinates of a linear geometry + (s and s. + + + + + + + + + + + + Invariant: currentLine <> null if the iterator is pointing at a valid coordinate + + + + + Creates an iterator initialized to the start of a linear . + + The linear geometry to iterate over. + if is not + + + + Creates an iterator starting at a on a linear . + + The linear geometry to iterate over. + The location to start at. + if is not + + + + Creates an iterator starting at + a component and vertex in a linear . + + The linear geometry to iterate over. + The component to start at. + The vertex to start at. + if is not + + + + + + + + + Tests whether there are any vertices left to iterator over. + Specifically, HasNext() returns true if the + current state of the iterator represents a valid location + on the linear geometry. + + true if there are more vertices to scan. + + + + Jump to the next element of the iteration. + + + + + Checks whether the iterator cursor is pointing to the + endpoint of a component . + + + + + The component index of the vertex the iterator is currently at. + + + + + The vertex index of the vertex the iterator is currently at. + + + + + Gets the component the iterator is current at. + + + + + Gets the first of the current segment + (the coordinate of the current vertex). + + + + + Gets the second of the current segment + (the coordinate of the next vertex). + If the iterator is at the end of a line, null is returned. + + + + + Represents a location along a or .
+ The referenced geometry is not maintained within this location, + but must be provided for operations which require it. + Various methods are provided to manipulate the location value + and query the geometry it references. +
+
+ + + Gets a location which refers to the end of a linear . + + The linear geometry. + A new LinearLocation. + + + + Computes the of a point a given fraction + along the line segment (p0, p1). + + + + If the fraction is greater than 1.0 the last + point of the segment is returned. + If the fraction is less than or equal to 0.0 the first point + of the segment is returned. + + The Z ordinate is interpolated from the Z-ordinates of the given points, + if they are specified. + + The first point of the line segment. + The last point of the line segment. + The length to the desired point. + + + + + Initializes a new instance of the class: + creates a location referring to the start of a linear geometry. + + + + + Initializes a new instance of the class: + creates a location referring to the start of a linear geometry. + + Index of the segment. + The segment fraction. + + + + Initializes a new instance of the class: + creates a location referring to the start of a linear geometry. + + Index of the component. + Index of the segment. + The segment fraction. + + + + Initializes a new instance of the class: + creates a location referring to the start of a linear geometry. + + Index of the component. + Index of the segment. + The segment fraction. + If true, ensures the individual values are locally valid. + + + + Creates a new location equal to a given one. + + A linear location + + + + Ensures the individual values are locally valid. + Does not ensure that the indexes are valid for + a particular linear geometry. + + + + + Ensures the indexes are valid for a given linear . + + A linear geometry. + + + + Snaps the value of this location to + the nearest vertex on the given linear , + if the vertex is closer than . + + A linear geometry. + The minimum allowable distance to a vertex. + + + + Gets the length of the segment in the given + Geometry containing this location. + + A linear geometry. + The length of the segment. + + + + Sets the value of this location to + refer to the end of a linear geometry. + + The linear geometry to use to set the end. + + + + Gets the component index for this location. + + + + + Gets the segment index for this location. + + + + + Gets the segment fraction for this location. + + + + + Tests whether this location refers to a vertex: + returns true if the location is a vertex. + + + + + Gets the along the + given linear which is + referenced by this location. + + A linear geometry. + The at the location. + + + + Gets a representing the segment of the given linear which contains this location. + + A linear geometry + the LineSegment containing the location + + + + Tests whether this location refers to a valid + location on the given linear . + + A linear geometry. + true if this location is valid. + + + + Compares the current instance with another object of the same type. + + + The LineStringLocation with which this + Coordinate is being compared. + + + A negative integer, zero, or a positive integer as this + LineStringLocation is less than, equal to, + or greater than the specified LineStringLocation. + + + is not the same type as this instance. + + + + + Compares the current instance with another object of the same type. + + + The LineStringLocation with which this + Coordinate is being compared. + + + A negative integer, zero, or a positive integer as this + LineStringLocation is less than, equal to, + or greater than the specified LineStringLocation. + + + + + Compares this object with the specified index values for order. + + The component index. + The segment index. + The segment fraction. + + A negative integer, zero, or a positive integer as this LineStringLocation + is less than, equal to, or greater than the specified locationValues. + + + + + Compares two sets of location values for order. + + The first component index. + The first segment index. + The first segment fraction. + The second component index. + The second segment index. + The second segment fraction. + + A negative integer, zero, or a positive integer + as the first set of location values is less than, equal to, + or greater than the second set of locationValues. + + + + + Tests whether two locations are on the same segment in the parent . + + A location on the same geometry + true if the locations are on the same segment of the parent geometry + + + + Tests whether this location is an endpoint of + the linear component it refers to. + + The linear geometry referenced by this location + True if the location is a component endpoint + + + + Converts a linear location to the lowest equivalent location index. + The lowest index has the lowest possible component and segment indices. + Specifically: + * if the location point is an endpoint, a location value is returned as (nseg-1, 1.0) + * if the location point is ambiguous (i.e. an endpoint and a startpoint), the lowest endpoint location is returned + If the location index is already the lowest possible value, the original location is returned. + + The linear geometry referenced by this location. + The lowest equivalent location. + + + + + + + Gets the count of the number of line segments + in a . + This is one less than the number of coordinates. + + A LineString + The number of segments + + + + Supports linear referencing along a linear + using s as the index. + + + + + Constructs an object which allows linear referencing along + a given linear . + + The linear geometry to reference alo + + + + Computes the for the point on the line at the given index. + If the is out of range, + the first or last point on the line will be returned. + + + The Z-ordinate of the computed point will be interpolated from + the Z-ordinates of the line segment containing it, if they exist. + + The index of the desired point. + The at the given index. + + + + Computes the for the point + on the line at the given index, offset by the given distance. + If the index is out of range the first or last point on the + line will be returned. + The computed point is offset to the left of the line if the offset distance is + positive, to the right if negative. + The Z-ordinate of the computed point will be interpolated from + the Z-ordinates of the line segment containing it, if they exist. + + The index of the desired point + The distance the point is offset from the segment + (positive is to the left, negative is to the right) + The Coordinate at the given index + + + + Computes the for the point on the line at the given index, offset by the given distance. + + + If the index is out of range the first or last point on the line will be returned. + The computed point is offset to the left of the line if the offset distance is + positive, to the right if negative. + The Z-ordinate of the computed point will be interpolated from the Z-ordinates of the line segment containing it, if they exist. + + The index of the desired point + The distance the point is offset from the segment (positive is to the left, negative is to the right) + The Coordinate at the given index + + + + Computes the for the interval + on the line between the given indices. + If the start location is after the end location, + the computed linear geometry has reverse orientation to the input line. + + The index of the start of the interval. + The index of the end of the interval. + The linear interval between the indices. + + + + Computes the index for a given point on the line. + The supplied point does not necessarily have to lie precisely + on the line, but if it is far from the line the accuracy and + performance of this function is not guaranteed. + Use to compute a guaranteed result for points + which may be far from the line. + + A point on the line. + The index of the point. + + + + + Computes the indices for a subline of the line. + (The subline must conform to the line; that is, + all vertices in the subline (except possibly the first and last) + must be vertices of the line and occur in the same order). + + A subLine of the line. + A pair of indices for the start and end of the subline. + + + + Finds the index for a point on the line which is greater than the given index. + If no such index exists, returns . + + + + This method can be used to determine all indexes for + a point which occurs more than once on a non-simple line. + It can also be used to disambiguate cases where the given point lies + slightly off the line and is equidistant from two different + points on the line. + + + The supplied point does not necessarily have to lie precisely + on the line, but if it is far from the line the accuracy and + performance of this function is not guaranteed. + Use to compute a guaranteed result for points + which may be far from the line. + + + A point on the line + The value the returned index must be greater than + The index of the point greater than the given minimum index + + + + + Computes the index for the closest point on the line to the given point. + If more than one point has the closest distance the first one along the line is returned. + (The point does not necessarily have to lie precisely on the line.) + + A point on the line. + The index of the point. + + + + Returns the index of the start of the line. + + + + + Returns the index of the end of the line. + + + + + Tests whether an index is in the valid index range for the line. + + The index to test. + true if the index is in the valid range. + + + + Computes a valid index for this line by clamping + the given index to the valid range of index values. + + + A valid index value. + + + + Determines the location of a subline along a linear . + The location is reported as a pair of s. + NOTE: Currently this algorithm is not guaranteed to + return the correct substring in some situations where + an endpoint of the test line occurs more than once in the input line. + (However, the common case of a ring is always handled correctly). + + + + + + + + + + + + + Initializes a new instance of the class. + + The linear geom. + + + + + + + + + + + Computes the of the point + on a linear nearest a given . + The nearest point is not necessarily unique; this class + always computes the nearest point closest + to the start of the geometry. + + + + + + + + + + + + + Initializes a new instance of the class. + + A linear geometry. + + + + Find the nearest location along a linear to a given point. + + The coordinate to locate. + The location of the nearest point. + + + + Find the nearest along the linear + to a given after the specified minimum . + If possible the location returned will be strictly greater than the . + If this is not possible, the value returned will equal . + (An example where this is not possible is when = [end of line] ). + + The coordinate to locate. + The minimum location for the point location. + The location of the nearest point. + + + + Implements extended-precision floating-point numbers + which maintain 106 bits (approximately 30 decimal digits) of precision. + + A DoubleDouble uses a representation containing two double-precision values. + A number x is represented as a pair of doubles, x.hi and x.lo, + such that the number represented by x is x.hi + x.lo, where +
+                |x.lo| <= 0.5*ulp(x.hi)
+            
+ and ulp(y) means "unit in the last place of y". + The basic arithmetic operations are implemented using + convenient properties of IEEE-754 floating-point arithmetic. + + The range of values which can be represented is the same as in IEEE-754. + The precision of the representable numbers + is twice as great as IEEE-754 double precision. + + The correctness of the arithmetic algorithms relies on operations + being performed with standard IEEE-754 double precision and rounding. + This is the Java standard arithmetic model, but for performance reasons + Java implementations are not + constrained to using this standard by default. + Some processors (notably the Intel Pentium architecture) perform + floating point operations in (non-IEEE-754-standard) extended-precision. + A JVM implementation may choose to use the non-standard extended-precision + as its default arithmetic mode. + To prevent this from happening, this code uses the + Java strictfp modifier, + which forces all operations to take place in the standard IEEE-754 rounding model. + + The API provides both a set of value-oriented operations + and a set of mutating operations. + Value-oriented operations treat DoubleDouble values as + immutable; operations on them return new objects carrying the result + of the operation. This provides a simple and safe semantics for + writing DoubleDouble expressions. However, there is a performance + penalty for the object allocations required. + The mutable interface updates object values in-place. + It provides optimum memory performance, but requires + care to ensure that aliasing errors are not created + and constant values are not changed. + + This implementation uses algorithms originally designed variously by + Knuth, Kahan, Dekker, and Linnainmaa. + Douglas Priest developed the first C implementation of these techniques. + Other more recent C++ implementation are due to Keith M. Briggs and David Bailey et al. +

References

+ + Priest, D., Algorithms for Arbitrary Precision Floating Point Arithmetic, + in P. Kornerup and D. Matula, Eds., Proc. 10th Symposium on Computer Arithmetic, + IEEE Computer Society Press, Los Alamitos, Calif., 1991. + Yozo Hida, Xiaoye S. Li and David H. Bailey, + Quad-Double Arithmetic: Algorithms, Implementation, and Application, + manuscript, Oct 2000; Lawrence Berkeley National Laboratory Report BNL-46996. + David Bailey, High Precision Software Directory; + http://crd.lbl.gov/~dhbailey/mpdist/index.html + +
+ Martin Davis +
+ + The value nearest to the constant Pi. + + + The value nearest to the constant 2 * Pi. + + + The value nearest to the constant Pi / 2. + + + + The value nearest to the constant e (the natural logarithm base). + + + + + A value representing the result of an operation which does not return a valid number. + + + + + The smallest representable relative difference between two values + + + + + Converts the string argument to a DoubleDouble number. + + A string containing a representation of a numeric value + The extended precision version of the value + Thrown if is not a valid representation of a number + + + + Operator to parse a DoubleDouble from a string + + The DoubleDouble string + + + + Converts the double argument to a DoubleDouble number. + + A numeric value + The extended precision version of the value + + + + Operator to convert the double value to a DoubleDouble value. + + The DoubleDouble string + + + + The value to split a double-precision value on during multiplication + + + + + The high-order component of the double-double precision value. + + + + + The low-order component of the double-double precision value. + + + + + Creates a new with value x. + + The initial value + + + + Creates a new with value (hi, lo). + + The high order component + The low order component + + + + Creates a with a value equal to the argument + + The initial value + + + + Creates a new with value equal to the argument. + + The value to initialize by + if is not a valid representation of a number + + + + Creates a new with the value of the argument. + + The value to copy + A copy of + + + + Creates and returns a copy of this value. + + A copy of this value + + + + Returns the sum of and . + + The left hand side + The right hand side + The sum of and + + + + Returns the sum of and . + + The left hand side + The right hand side + The sum of and + + + + Returns the difference of and . + + The left hand side + The right hand side + The difference of and + + + + Returns the difference of and . + + The left hand side + The right hand side + The difference of and + + + + Subtracts the argument from the value of this. + + The subtrahend + The result of this - y + + + + Multiplies by . + + A DoubleDouble value. + A double value. + The result of the multiplication. + + + + Multiplies by . + + A DoubleDouble value. + A DoubleDouble value. + The result of the multiplication. + + + + Divides by . + + A DoubleDouble numerator. + A double divisor. + The result of the division. + + + + Divides by . + + A DoubleDouble numerator. + A DoubleDouble divisor. + The result of the division. + + + + Returns a whose value is 1 / this. + + The reciprocal of this value + + + + Computes the determinant of the 2x2 matrix with the given entries. + + A matrix entry + A matrix entry + A matrix entry + A matrix entry + The determinant of the matrix of values + + + + Computes the determinant of the 2x2 matrix with the given entries. + + A matrix entry + A matrix entry + A matrix entry + A matrix entry + The determinant of the matrix of values + + + + Computes the minimum of this and another DD number. + + A DD number + The minimum of the two numbers + + + + Computes the maximum of this and another DD number. + + A DD number + The maximum of the two numbers + + + + Returns the largest (closest to positive infinity) + value that is not greater than the argument + and is equal to a mathematical integer. + Special cases: + + If this value is NaN, returns NaN. + + + The largest (closest to positive infinity) + value that is not greater than the argument + and is equal to a mathematical integer. + + + + + Returns the smallest (closest to negative infinity) value + that is not less than the argument and is equal to a mathematical integer. + Special cases: + + If this value is NaN, returns NaN. + + + + The smallest (closest to negative infinity) value + that is not less than the argument and is equal to a mathematical integer. + + + + + Returns an integer indicating the sign of this value. + + + if this value is > 0, returns 1 + if this value is < 0, returns -1 + if this value is = 0, returns 0 + if this value is NaN, returns 0 + + + + An integer indicating the sign of this value + + + + Rounds this value to the nearest integer. + The value is rounded to an integer by adding 1/2 and taking the floor of the result. + Special cases: + + If this value is NaN, returns NaN. + + + This value rounded to the nearest integer + + + + Returns the integer which is largest in absolute value and not further + from zero than this value. + + Special cases: + + If this value is NaN, returns NaN. + + + + The integer which is largest in absolute value and not further from zero than this value + + + + + Returns the absolute value of this value. + + Special cases: + + if this value is NaN, it is returned. + + + The absolute value of this value + + + + Computes the square of this value. + + The square of this value + + + + Computes the square of this value. + + The square of this value. + + + + Computes the positive square root of this value. + If the number is NaN or negative, NaN is returned. + + If this is NaN or less than zero, the result is NaN. + + + + Computes the positive square root of a DoubleDouble value. + If the number is NaN or negative, NaN is returned. + + A numeric value + the positive square root of this number. + If the argument is NaN or less than zero, the result is NaN. + + + + Computes the value of this number raised to an integral power. + Follows semantics of .Net Math.Pow as closely as possible. + + The integer exponent + x raised to the integral power exp + + + + Converts this value to the nearest number. + + The nearest value + + + + Converts this value to the nearest value. + + The nearest value + + + + Gets a value indicating whether this object is zero (0) or not + + + + + Gets a value indicating whether this object is negative or not + + + + + Gets a value indicating whether this object is positive or not + + + + + Gets a value indicating whether this object is positive or not + + + + + Checks if is infinity. + + A DoubleDouble value + true if value is infinity. + + + + Tests whether this value is equal to another DoubleDouble value. + + A DoubleDouble value + true if this value == . + + + + Equality operator for DoubleDouble values + + A DoubleDouble value + A DoubleDouble value + true if == . + + + + Inequality operator for DoubleDouble values + + A DoubleDouble value + A DoubleDouble value + true if != . + + + + Tests whether this value is greater than another DoubleDouble value. + + A DoubleDouble value + true if this value > . + + + + Tests whether this value is greater than or equals to another DoubleDouble value. + + A DoubleDouble value + true if this value >= . + + + + Tests whether this value is less than another DoubleDouble value. + + A DoubleDouble value + true if this value is < + + + + Tests whether this value is less than or equal to another DoubleDouble value. + + A DoubleDouble + true if this value is <= + + + + Compares two DoubleDouble objects numerically. + + An other DoubleDouble value + + -1,0 or 1 depending on whether this value is less than, equal to + or greater than the value of + + + + + + + Dumps the components of this number to a string. + + A string showing the components of the number + + + + Returns a string representation of this number, in either standard or scientific notation. + If the magnitude of the number is in the range [ 10-3, 108 ] + standard notation will be used. Otherwise, scientific notation will be used. + + A string representation of this number + + + + Returns the string representation of this value in standard notation. + + The string representation in standard notation + + + + Returns the string representation of this value in scientific notation. + + The string representation in scientific notation + + + + Extracts the significant digits in the decimal representation of the argument. + A decimal point may be optionally inserted in the string of digits + (as long as its position lies within the extracted digits + - if not, the caller must prepend or append the appropriate zeroes and decimal point). + + + + The string containing the significant digits and possibly a decimal point + + + + Returns the string for this value if it has a known representation (e.g. NaN or 0.0). + + The string for this special number
+ or null if the number is not a special number
+
+ + + Determines the decimal magnitude of a number. + The magnitude is the exponent of the greatest power of 10 which is less than + or equal to the number. + + The number to find the magnitude of + The decimal magnitude of + + + + Converts a string representation of a real number into a DoubleDouble value. + The format accepted is similar to the standard Java real number syntax. + It is defined by the following regular expression: +
+            [+|-] {digit} [ . {digit} ] [ ( e | E ) [+|-] {digit}+
+            
+
+ The string to parse + The value of the parsed number + Thrown if str is not a valid representation of a number +
+ + + + + + + + + Various utility functions for mathematical and numerical operations. + + + + + Clamps a double value to a given range. + + The value to clamp + The minimum value of the range + The maximum value of the range + The clamped value + + + + Clamps a int value to a given range. + + The value to clamp + The minimum value of the range + The maximum value of the range + The clamped value + + + + Clamps an integer to a given maximum limit. + + The value to clamp + The maximum value of the range + The clamped value + + + + Computes the ceiling function of the dividend of two integers. + + The numerator + The denominator + The ceiling of num / denom + + + + Computes the base-10 logarithm of a double value. + + + If the argument is NaN or less than zero, then the result is NaN. + If the argument is positive infinity, then the result is positive infinity. + If the argument is positive zero or negative zero, then the result is negative infinity. + + + + A positive number + The value log a, the base-10 logarithm of the input value + + + + Computes an index which wraps around a given maximum value. + For values >= 0, this is equals to val % max. + For values < 0, this is equal to max - (-val) % max + + The index to wrap + The maximum value (or modulus) + The wrapped index + + + + Computes the average of two numbers. + + A number + A number + The average of the inputs + + + + Computes the maximum fo three values + + A number + A number + A number + The maximum value of , and + + + + Computes the maximum of four values + + A number + A number + A number + A number + The maximum value of , , and + + + + Computes the minimum of four values + + A number + A number + A number + The minimum value of , and + + + + Computes the minimum of four values + + A number + A number + A number + A number + The minimum value of , , and + + + The inverse of the Golden Ratio phi. + + + + + + Implements some 2D matrix operations + (in particular, solving systems of linear equations). + + Martin Davis + + + + Solves a system of equations using Gaussian Elimination. + In order to avoid overhead the algorithm runs in-place + on - if should not be modified the client must supply a copy. + + An nxn matrix in row/column order )modified by this method) + A vector of length n + A vector containing the solution (if any)
or null if the system has no or no unique solution +
+ If the matrix has the wrong size +
+ + + Enumeration for the 3 coordinate planes + + + + + Models a plane in 3-dimensional Cartesian space. + + Martin Davis + + + + Computes the oriented distance from a point to the plane.
+ The distance is: + + positive if the point lies above the plane (relative to the plane normal) + zero if the point is on the plane + negative if the point lies below the plane (relative to the plane normal) + +
+ The point to compute the distance for + The oriented distance to the plane +
+ + + Computes the axis plane that this plane lies closest to. + + Geometries lying in this plane undergo least distortion + (and have maximum area) + when projected to the closest axis plane. + This provides optimal conditioning for + computing a Point-in-Polygon test. + + The index of the closest axis plane + + + + A 2-dimensional mathematical vector represented by double-precision X and Y components. + + mbdavis + + + + Creates a new vector with all components set to Zero + + + + + Creates a new vector with given X and Y components. + + The x component + The y component + A new vector + + + + Creates a new vector from an existing one. + + The vector to copy + A new vector + + + + Creates a vector from a . + + The coordinate to copy + A new vector + + + Creates a vector with the direction and magnitude + of the difference between the + and s. + + The origin coordinate + The destination coordinate + A new vector + + + The X component of this vector + + + The Y component of this vector. + + + + Creates an new vector instance + + + + + Creates a new vector instance using the provided and ordinates + + The x-ordinate value + The y-ordinate value + + + + Creates a new vector instance based on . + + The vector + + + Creates a new vector with the direction and magnitude + of the difference between the + and s. + + The origin coordinate + The destination coordinate + + + + Creates a vector from a . + + The coordinate + A new vector + + + + Gets the x-ordinate value + + + + + Gets the y-ordinate value + + + + + Gets the ordinate values by index + + The index + Thrown if index < 0 or > 1 + + + + Adds to this vector instance. + + The vector to add + The result vector + + + + Subtracts from this vector instance + + The vector to subtract + The result vector + + + + Multiplies the vector by a scalar value. + + The value to multiply by + A new vector with the value v * d + + + + Divides the vector by a scalar value. + + The value to divide by + A new vector with the value v / d + + + + Negates this vector + + A new vector with [-_x, -_y] + + + + + + + + + + + + + + + + Normalizes the vector + + A new normalized vector + + + + + + + + + + + Computes the weighted sum of this vector + with another vector, + with this vector contributing a fraction + of frac to the total. + + In other words, +
+            sum = frac * this + (1 - frac) * v
+            
+
+ The vector to sum + The fraction of the total contributed by this vector + The weighted sum of the two vectors +
+ + + Computes the distance between this vector and another one. + + A vector + The distance between the vectors + + + + Computes the dot-product of two vectors + + A vector + The dot product of the vectors + + + + Computes the angle this vector describes to the horizontal axis + + The angle + + + + + + + + + + + + + + + + + + Rotates this vector by + + The angle + The rotated vector + + + + Rotates a vector by a given number of quarter-circles (i.e. multiples of 90 + degrees or Pi/2 radians). A positive number rotates counter-clockwise, a + negative number rotates clockwise. Under this operation the magnitude of + the vector and the absolute values of the ordinates do not change, only + their sign and ordinate index. + + The number of quarter-circles to rotate by + The rotated vector. + + + + + + + + + + + Gets a made of this vector translated by . + + The translation coordinate + A coordinate + + + + Gets a from this vector + + A coordinate + + + + Creates a copy of this vector + + A copy of this vector + + + + Gets a string representation of this vector + + A string representing this vector + + + + Tests if a vector has the same values for the x and y components. + + A with which to do the comparison. + true if is a with the same values for the X and Y components. + + + + Gets a hashcode for this vector. + + A hashcode for this vector + + + + Adds two vectors. + + The first vector to add. + The second vector to add. + The sum of the two vectors. + + + + Modulates a vector with another by performing component-wise multiplication"/>. + + The first vector to multiply. + The second vector to multiply. + The multiplication of the two vectors. + + + + Subtracts two vectors. + + The first vector to subtract. + The second vector to subtract. + The difference of the two vectors. + + + + Reverses the direction of a given vector. + + The vector to negate. + A vector facing in the opposite direction. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Tests for equality between two objects. + + The first value to compare. + The second value to compare. + true if has the same value as + ; otherwise, false. + + + + Tests for inequality between two objects. + + The first value to compare. + The second value to compare. + true if has a different value + than ; otherwise, false. + + + + Represents a vector in 3-dimensional Cartesian space. + + Martin Davis + + + + Creates a new vector with all components set to Zero + + + + + Computes the dot product of the 3D vectors AB and CD. + + The start point of the 1st vector + The end point of the 1st vector + The start point of the 2nd vector + The end point of the 2nd vector + The dot product + + + + Calculates the cross product of two vectors. + + First source vector. + Second source vector. + + + + Creates a new vector with given , and components. + + The x component + The y component + The z component + A new vector + + + + Creates a vector from a 3D . + + The coordinate should have the + X,Y and Z ordinates specified. + + The coordinate to copy + A new vector + + + + Computes the 3D dot-product of two s + + The 1st vector + The 2nd vector + The dot product of the (coordinate) vectors + + + + Creates a new 3D vector from a . The coordinate should have + the X,Y and Z ordinates specified. + + The coordinate to copy + + + + Creates a new vector with the direction and magnitude + of the difference between the + and s. + + The origin coordinate + The destination coordinate + + + + Creates a new vector with the given , and components + + The x component + The y component + The z component + + + + Creates a new using a plus a value for component + + A vector containing the values with which to initialize the X and Y components. + Initial value for the Z component of the vector. + + + + Gets a value indicating the x-ordinate + + + + + Gets a value indicating the y-ordinate + + + + + Gets a value indicating the z-ordinate + + + + + Computes a vector which is the sum + of this vector and the given vector. + + The vector to add + The sum of this and v + + + + Computes a vector which is the difference + of this vector and the given vector. + + The vector to subtract + The difference of this and v + + + + Creates a new vector which has the same direction + and with length equals to the length of this vector + divided by the scalar value d. + + The scalar divisor + A new vector with divided length + + + + Computes the dot-product of this and + + The 2nd vector + The dot product of the vectors + + + + Computes the cross-product of this and + + The 2nd vector + The cross product of the vectors + + + + Computes the length of this vector + + The length of this vector + + + + Computes the length of vector . + + A coordinate representing a 3D Vector + The length of + + + + Computes a vector having identical direction + but normalized to have length 1. + + A new normalized vector + + + + Computes a vector having identical direction as v + but normalized to have length 1. + + A coordinate representing a 3D vector + A coordinate representing the normalized vector + + + + + + + + + + + + + Adds two vectors. + + The first vector to add. + The second vector to add. + The sum of the two vectors. + + + + Modulates a vector with another by performing component-wise multiplication. + + The first vector to multiply. + The second vector to multiply. + The multiplication of the two vectors. + + + + Assert a vector (return it unchanged). + + The vector to assert (unchanged). + The asserted (unchanged) vector. + + + + Subtracts two vectors. + + The first vector to subtract. + The second vector to subtract. + The difference of the two vectors. + + + + Reverses the direction of a given vector. + + The vector to negate. + A vector facing in the opposite direction. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Tests for equality between two objects. + + The first value to compare. + The second value to compare. + true if has the same value as ; otherwise, false. + + + + Tests for inequality between two objects. + + The first value to compare. + The second value to compare. + true if has a different value than ; otherwise, false. + + + + Functions for performing vector mathematics. + + + + + Computes the normal vector to the triangle p0-p1-p2. In order to compute the normal each + triangle coordinate must have a Z value. If this is not the case, the returned Coordinate + will have NaN values. The returned vector has unit length. + + A point + A point + A point + The normal vector to the triangle -- + + + + Normalizes the vector + + The normalized + + + + Computes the cross product of and + + A vector + A vector + The cross product of and + + + + Computes the dot product of and + + A vector + A vector + The dot product of and + + + + Computes the determinant of a 2x2 matrix + + The m[0,0] value + The m[0,1] value + The m[1,0] value + The m[1,1] value + The determinant + + + + Represents a read-only list of contiguous line segments. + This can be used for detection of intersections or nodes. + s can carry a context object, which is useful + for preserving topological or parentage information. + + If adding nodes is required use . + + + + + + Creates a new segment string from a list of vertices. + + the vertices of the segment string + the user-defined data of this segment string (may be null) + + + Gets the user-defined data for this segment string. + + + + + Gets the octant of the segment starting at vertex index + + the index of the vertex starting the segment. Must not be the last index in the vertex list + octant of the segment at the vertex + + + + + + + Validates that a collection of s is correctly noded. + Indexing is used to improve performance. + + + + By default validation stops after a single + non-noded intersection is detected. + Alternatively, it can be requested to detect all intersections + by using the property. + + The validator does not check for topology collapse situations + (e.g. where two segment strings are fully co-incident). + + The validator checks for the following situations which indicated incorrect noding: + + Proper intersections between segments (i.e. the intersection is interior to both segments) + Intersections at an interior vertex (i.e. with an endpoint or another interior vertex) + + + + The client may either test the condition, + or request that a suitable be thrown. + + + + + + + Gets a list of all intersections found. + Intersections are represented as s. + List is empty if none were found. + A collection of SegmentStrings + a list of + + + + + Creates a new noding validator for a given set of linework. + + A collection of s + + + + Gets or sets whether all intersections should be found. + + + + + Gets a list of all intersections found. + + Intersections are represented as s. + List is empty if none were found. + + + + + + Checks for an intersection and reports if one is found. + + + + + Returns an error message indicating the segments containing the intersection. + + an error message documenting the intersection location + + + + Checks for an intersection and throws + a TopologyException if one is found. + + if an intersection is found + + + + Finds if two sets of s intersect. + + + Uses indexing for fast performance and to optimize repeated tests + against a target set of lines. + Short-circuited to return as soon an intersection is found. + + Immutable and thread-safe. + + + + + Creates an intersection finder against a given set of segment strings. + + The segment strings to search for intersections + + + Gets the segment set intersector used by this class. + This allows other uses of the same underlying indexed structure. + + + + Tests for intersections with a given set of target s. + + The SegmentStrings to test + true if an intersection was found + + + + Tests for intersections with a given set of target s. + using a given SegmentIntersectionDetector. + + The SegmentStrings to test + The intersection detector to use + true if the detector reports intersections + + + + An interface for classes which support adding nodes to a segment string. + + + + Adds an intersection node for a given point and segment to this segment string. + + the location of the intersection + the index of the segment containing the intersection + + + + Computes all intersections between segments in a set of s. + Intersections found are represented as s and added to the + s in which they occur. + As a final step in the noding a new set of segment strings split at the nodes may be returned. + + + + + Computes the noding for a collection of s. + Some Noders may add all these nodes to the input s; + others may only add some or none at all. + + + + + + Returns a of fully noded s. + The s have the same context as their parent. + + + + + + Finds interior intersections + between line segments in s, + and adds them as nodes + using . + This class is used primarily for Snap-Rounding. + For general-purpose noding, use . + + + + + + Creates an intersection finder which finds all proper intersections. + + The to use. + + + + + + + + + This method is called by clients + of the class to process + intersections for two segments of the s being intersected.
+ Note that some clients (such as MonotoneChains) may optimize away + this call for segment pairs which they have determined do not intersect + (e.g. by an disjoint envelope test). +
+ + + + +
+ + + Always process all intersections + + + + + Computes the possible intersections between two line segments in s + and adds them to each string + using . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Initializes a new instance of the class. + + + + + + + + + + + Returns the proper intersection point, or null if none was found. + + + + + + + + + + A proper intersection is an intersection which is interior to at least two + line segments. Note that a proper intersection is not necessarily + in the interior of the entire , since another edge may have + an endpoint equal to the intersection, which according to SFS semantics + can result in the point being on the Boundary of the . + + + + + A proper interior intersection is a proper intersection which is not + contained in the set of boundary nodes set for this . + + + + + An interior intersection is an intersection which is + in the interior of some segment. + + + + + A trivial intersection is an apparent self-intersection which in fact + is simply the point shared by adjacent line segments. + Note that closed edges require a special check for the point shared by the beginning and end segments. + + + + + + + + + + This method is called by clients + of the class to process + intersections for two segments of the being intersected.
+ Note that some clients (such as MonotoneChain") may optimize away + this call for segment pairs which they have determined do not intersect + (e.g. by an disjoint envelope test). +
+ + + + +
+ + + Always process all intersections + + + + + Processes possible intersections detected by a . + + + + The is passed to a . + + The + method is called whenever the + detects that two s might intersect. + + This class may be used either to find all intersections, or + to detect the presence of an intersection. In the latter case, + Noders may choose to short-circuit their computation by calling the + property. + + + + This class is an example of the Strategy pattern. + + This class may be used either to find all intersections, or + to detect the presence of an intersection. In the latter case, + Noders may choose to short-circuit their computation by calling the + property. + + + + + + This method is called by clients + of the interface to process + intersections for two segments of the s being intersected. + + + + + + + + + Reports whether the client of this class needs to continue testing + all intersections in an arrangement. + + if there is no need to continue testing segments + + + + An interface for classes which represent a sequence of contiguous line segments. + SegmentStrings can carry a context object, which is useful + for preserving topological or parentage information. + + + + + Gets/Sets the user-defined data for this segment string. + + + + + Points that make up ISegmentString + + + + + Size of Coordinate Sequence + + + + + States whether ISegmentString is closed + + + + + Nodes a set of s completely. + The set of s is fully noded; + i.e. noding is repeated until no further intersections are detected. + + Iterated noding using a precision model is not guaranteed to converge, + due to round off error. This problem is detected and an exception is thrown. + Clients can choose to rerun the noding using a lower precision model. + + + + + + + + + + + Initializes a new instance of the class. + + + + + + Gets/Sets the maximum number of noding iterations performed before + the noding is aborted. Experience suggests that this should rarely need to be changed + from the default. The default is . + + + + + Returns a of fully noded s. + The s have the same context as their parent. + + + + + + Fully nodes a list of s, i.e. performs noding iteratively + until no intersections are found between segments. + Maintains labelling of edges correctly through the noding. + + A collection of SegmentStrings to be noded. + If the iterated noding fails to converge. + + + + Node the input segment strings once + and create the split edges between the nodes. + + + + + + + Nodes a set of s using a index based + on s and a . + The used should be something that supports + envelope (range) queries efficiently (such as a Quadtree" + or . + + The noder supports using an overlap tolerance distance. + This allows determining segment intersection using a buffer for uses + involving snapping with a distance tolerance. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The to use. + + + + Initializes a new instance of the class. + + The to use. + The expansion distance for overlap tests + + + + + + + + + + + + + + Returns a of fully noded s. + The s have the same context as their parent. + + + + + + Computes the noding for a collection of s. + Some Noders may add all these nodes to the input s; + others may only add some or none at all. + + + + + + + + + + + + + + + + + + + + + + Initializes a new instance of the class. + + The + + + + + + + + + + + + + Intersects two sets of s using a index based + on s and a . + + Thread-safe and immutable. + + + + + Constructs a new intersector for a given set of s. + + The base segment strings to intersect + + + + Gets the index constructed over the base segment strings + + NOTE: To retain thread-safety, treat returned value as immutable + + + + Calls + for all candidate intersections between + the given collection of SegmentStrings and the set of indexed segments. + + A set of segments to intersect + The SegmentIntersector to use + + + + Segment overlap action class + + + + + Creates an instance of this class using the provided + + The segment intersector to use + + + + Represents a list of contiguous line segments, and supports noding the segments. + The line segments are represented by an array of s. + Intended to optimize the noding of contiguous segments by + reducing the number of allocated objects. + s can carry a context object, which is useful + for preserving topological or parentage information. + All noded substrings are initialized with the same context object. + + For read-only applications use , + which is (slightly)more lightweight. + + + + + + Gets the s which result from splitting this string at node points. + + A collection of NodedSegmentStrings + A collection of NodedSegmentStrings representing the substrings + + + + Adds the noded s which result from splitting this string at node points. + + A collection of NodedSegmentStrings + A list which will collect the NodedSegmentStrings representing the substrings + + + + Creates an instance from a list of vertices and optional data object. + + The vertices of the segment string. + The user-defined data of this segment string (may be null). + + + + Creates a new instance from a . + + The segment string to use. + + + + Gets/Sets the user-defined data for this segment string. + + In JTS this property is called Data + + + + + + + + + + + + + + + + + + + + + + + + + + + Gets a list of coordinates with all nodes included. + + An array of coordinates including nodes + + + + + + + + + Gets the octant of the segment starting at vertex index. + + + The index of the vertex starting the segment. + Must not be the last index in the vertex list + + The octant of the segment at the vertex + + + + Adds EdgeIntersections for one or both + intersections found for a segment of an edge to the edge intersection list. + + + + + + + + Add an for intersection intIndex. + An intersection that falls exactly on a vertex + of the is normalized + to use the higher of the two possible segmentIndexes. + + + + + + + + + + + + + + + + + + + Finds non-noded intersections in a set of {@link SegmentString}s, + if any exist. + + Non-noded intersections include: + + Interior intersectionswhich lie in the interior of a segment + (with another segment interior or with a vertex or endpoint) + Vertex intersectionswhich occur at vertices in the interior of s + (with a segment string endpoint or with another interior vertex) + + The finder can be limited to finding only interior intersections + by setting . + + By default only the first intersection is found, + but all can be found by setting . + + + + + Creates a finder which tests if there is at least one intersection. + Uses short-circuiting for efficient performance. + The intersection found is recorded. + + A line intersector. + A finder which tests if there is at least one intersection. + + + + Creates a finder which tests if there is at least one intersection. + The intersections are recorded for later inspection. + + A line intersector. + A finder which finds all intersections. + + + + Creates a finder which finds all interior intersections. + The intersections are recorded for later inspection. + + A line intersector + A finder which finds all interior intersections. + + + + Creates a finder which counts all intersections. + The intersections are note recorded to reduce memory usage. + + A line intersector. + A finder which counts all intersections. + + + + Creates a finder which counts all interior intersections. + The intersections are note recorded to reduce memory usage. + + A line intersector. + A finder which counts all interior intersections. + + + + Creates an intersection finder which finds an interior intersection if one exists + + the LineIntersector to use + + + + Gets/Sets whether all intersections should be computed. + + When this is false (the default value), the value of + is true after the first intersection is found. + Default is false. + + + + + + Gets or sets a value indicating whether only interior (proper) intersections will be found. + + + + + Gets/Sets whether intersection points are recorded. + + If the only need is to count intersection points, this can be set to false. + Default is true. + + + + + + Gets/Sets whether only end segments should be tested for intersection. + This is a performance optimization that may be used if + the segments have been previously noded by an appropriate algorithm. + It may be known that any potential noding failures will occur only in + end segments. + + + + + Tests whether an intersection was found. + + + + + Gets the intersections found. + + A list of . + + + + Gets the count of intersections found. + + The intersection count. + + + + Gets the computed location of the intersection. + Due to round-off, the location may not be exact. + + + + + Gets the computed location of the intersection. + Due to round-off, the location may not be exact. + + + + + Gets the endpoints of the intersecting segments. + + + + + This method is called by clients of the class to process + intersections for two segments of the s being intersected.
+ Note that some clients (such as MonotoneChains) may optimize away + this call for segment pairs which they have determined do not intersect + (e.g. by an disjoint envelope test). +
+ + + + +
+ + + Tests if an intersection occurs between a segmentString interior vertex and another vertex. + Note that intersections between two endpoint vertices are valid noding, + and are not flagged. + + A segment vertex + A segment vertex + A segment vertex + A segment vertex + true if vertex is a segmentString endpoint + true if vertex is a segmentString endpoint + true if vertex is a segmentString endpoint + true if vertex is a segmentString endpoint + true if an intersection is found/ + + + + Tests if two vertices with at least one in a segmentString interior + are equal. + + A segment vertex + A segment vertex + true if vertex is a segmentString endpoint + true if vertex is a segmentString endpoint + true if an intersection is found + + + + Tests whether a segment in a is an end segment. + (either the first or last). + + a segment string + the index of a segment in the segment string + true if the segment is an end segment + + + + + + + + + Validates that a collection of s is correctly noded. + Throws an appropriate exception if an noding error is found. + + + + + Creates a new validator for the given collection + of s. + + The seg strings. + + + + Checks whether the supplied segment strings + are correctly noded. Throws an exception if they are not. + + + + + Checks if a segment string contains a segment pattern a-b-a (which implies a self-intersection). + + + + + Checks all pairs of segments for intersections at an interior point of a segment. + + + + + Checks for intersections between an endpoint of a segment string + and an interior vertex of another segment string + + + + + Octants in the Cartesian plane. + Octants are numbered as follows: + + \2|1/ + 3 \|/ 0 + ---+-- + 4 /|\ 7 + /5|6\ + + If line segments lie along a coordinate axis, the octant is the lower of the two possible values. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Methods for computing and working with of the Cartesian plane. + + + + + Returns the octant of a directed line segment (specified as x and y + displacements, which cannot both be 0). + + + + + + + + Returns the octant of a directed line segment from p0 to p1. + + + + + + + + Allows comparing arrays in an orientation-independent way. + + + + + Creates a new } + for the given array. + + + + + + Computes the canonical orientation for a coordinate array. + + + + true if the points are oriented forwards
+ or falseif the points are oriented in reverse. +
+
+ + + Compares two s for their relative order. + + + + -1 this one is smaller;
+ 0 the two objects are equal;
+ 1 this one is greater. +
+
+ + + + + + + + + + + + + Wraps a and transforms its input into the integer domain. + This is intended for use with Snap-Rounding noders, + which typically are only intended to work in the integer domain. + + Clients should be aware that rescaling can involve loss of precision, + which can cause zero-length line segments to be created. + These in turn can cause problems when used to build a planar graph. + This situation should be checked for and collapsed segments removed if necessary. + + + + + + Initializes a new instance of the class. + + The noder to use + The scale factor to use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A noder which extracts all line segments + as s. + This enables fast overlay of geometries which are known to be already fully noded. + In particular, it provides fast union of polygonal and linear coverages. + Unioning a noded set of lines is an effective way + to perform line merging and line dissolving. + + No precision reduction is carried out. + If that is required, another noder must be used (such as a snap-rounding noder), + or the input must be precision-reduced beforehand. + + Martin Davis + + + + Detects and records an intersection between two s, + if one exists. Only a single intersection is recorded. + + + This strategy can be configured to search for proper intersections. + In this case, the presence of any intersection will still be recorded, + but searching will continue until either a proper intersection has been found + or no intersections are detected. + + + + + Creates an intersection finder using a + + + + + Creates an intersection finder using a given + + The LineIntersector to use + + + + Gets or sets whether processing must continue until a proper intersection is found + + + + + Gets or sets whether processing can terminate once any intersection is found. + + + + + Tests whether an intersection was found. + + + + + Tests whether a proper intersection was found. + + + + + Tests whether a non-proper intersection was found. + + + + + Gets the computed location of the intersection. Due to round-off, the location may not be exact. + + + + Gets the endpoints of the intersecting segments. + + An array of the segment endpoints (p00, p01, p10, p11) + + + + This method is called by clients of the class to process + intersections for two segments of the s being intersected. + + + Note that some clients (such as MonotoneChains) may optimize away + this call for segment pairs which they have determined do not intersect + (e.g. by an disjoint envelope test). + + + + + Tests whether processing can terminate, + because all required information has been obtained + (e.g. an intersection of the desired type has been detected). + + + + + Represents an intersection point between two s. + + + + + + + + + + + + + + + Initializes a new instance of the class. + + + + + + + + + Gets the giving the location of this node. + + + + + + + + + + + + + + + + + + + + + -1 this SegmentNode is located before the argument location;
+ 0 this SegmentNode is at the argument location;
+ 1 this SegmentNode is located after the argument location. +
+
+ + + + + + + + > + + + + A list of the s present along a noded . + + + + + Initializes a new instance of the class. + + The edge. + + + + + + + + + + Adds an intersection into the list, if it isn't already there. + The input segmentIndex and dist are expected to be normalized. + + + + The SegmentIntersection found or added. + + + + Returns an iterator of SegmentNodes. + + An iterator of SegmentNodes. + + + + Adds nodes for the first and last points of the edge. + + + + + Adds nodes for any collapsed edge pairs. + Collapsed edge pairs can be caused by inserted nodes, or they can be + pre-existing in the edge vertex list. + In order to provide the correct fully noded semantics, + the vertex at the base of a collapsed pair must also be added as a node. + + + + + Adds nodes for any collapsed edge pairs + which are pre-existing in the vertex list. + + + + + + Adds nodes for any collapsed edge pairs caused by inserted nodes + Collapsed edge pairs occur when the same coordinate is inserted as a node + both before and after an existing edge vertex. + To provide the correct fully noded semantics, + the vertex must be added as a node as well. + + + + + + + + + + + + + + + Creates new edges for all the edges that the intersections in this + list split the parent edge into. + Adds the edges to the provided argument list + (this is so a single list can be used to accumulate all split edges + for a set of s). + + + + + + Create a new "split edge" with the section of points between + (and including) the two intersections. + The label for the new edge is the same as the label for the parent edge. + + + + + + + + Extracts the points for a split edge running between two nodes. + The extracted points should contain no duplicate points. + There should always be at least two points extracted + (which will be the given nodes). + + The start node of the split edge + The end node of the split edge + The points for the split edge + + + Gets the list of coordinates for the fully noded segment string, + including all original segment string vertices and vertices + introduced by nodes in this list. + Repeated coordinates are collapsed. + + An array of s + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Implements a robust method of comparing the relative position of two points along the same segment. + The coordinates are assumed to lie "near" the segment. + This means that this algorithm will only return correct results + if the input coordinates have the same precision and correspond to rounded values + of exact coordinates lying on the segment. + + + + + Compares two s for their relative position along a segment + lying in the specified . + + + + + + -1 if node0 occurs first, or
+ 0 if the two nodes are equal, or
+ 1 if node1 occurs first. +
+
+ + + + + + + + + + + + + + + + + + + An intersector for the red-blue intersection problem. + In this class of line arrangement problem, + two disjoint sets of linestrings are intersected. + + Implementing classes must provide a way + of supplying the base set of segment strings to + test against (e.g. in the constructor, + for straightforward thread-safety). + + In order to allow optimizing processing, + the following condition is assumed to hold for each set: + + the only intersection between any two linestrings occurs at their endpoints. + + Implementations can take advantage of this fact to optimize processing + (i.e. by avoiding testing for intersections between linestrings + belonging to the same set). + + + + + Computes the intersections with a given set of s, + using the supplied . + + A collection of s to node + The intersection detector to either record intersection occurrences + or add intersection nodes to the input segment strings. + + + + Dissolves a noded collection of s to produce + a set of merged linework with unique segments. + + + A custom merging strategy + can be supplied. + This strategy will be called when two identical (up to orientation) + strings are dissolved together. + The default merging strategy is simply to discard one of the merged strings. + + A common use for this class is to merge noded edges + while preserving topological labelling. + This requires a custom merging strategy to be supplied + to merge the topology labels appropriately. + + + + + + A merging strategy which can be used to update the context data of s + which are merged during the dissolve process. + + mbdavis + + + + Updates the context data of a + when an identical (up to orientation) one is found during dissolving. + + The segment string to update. + The segment string being dissolved. + + true if the strings are in the same direction, + false if they are opposite. + + + + + Creates a dissolver with a user-defined merge strategy. + + + + + + Creates a dissolver with the default merging strategy. + + + + + Dissolve all s in the input . + + + + + + + + + + + + + Dissolve the given . + + + + + + + + + Gets the collection of dissolved (i.e. unique) s + + + + + Utility methods for processing s + + Martin Davis + + + + Extracts all linear components from a given + to s.
+ The 's data item is set to be the source . +
+ The to extract from. + a list of s. +
+ + + Extracts all linear components from a given + to s.
+ The 's data item is set to be the source . +
+ The to extract from. + a list of s. +
+ + + Extracts all linear components from a given to s. + The 's data item is set to be the source Geometry. + + The to extract from. + a list of s. + + + + Converts a collection of s into a . + The geometry will be either a + or a (possibly empty). + + A collection of . + A geometry factory + A or a . + + + + Nodes a set of s by + performing a brute-force comparison of every segment to every other one. + This has n^2 performance, so is too slow for use on large numbers of segments. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + + + + + Returns a of fully noded s. + The s have the same context as their parent. + + + + + + Computes the noding for a collection of s. + Some Noders may add all these nodes to the input s; + others may only add some or none at all. + + + + + + + + + + + + + Intersects two sets of s using + brute-force comparison. + + + + + Constructs a new intersector for a given set of s. + + The base segment strings to intersect + + + + Calls + for all candidate intersections between + the given collection of SegmentStrings and the set of base segments. + + A collection of s to node + The intersection detector to either record intersection occurences + or add intersection nodes to the input segment strings. + + + + Processes all of the segment pairs in the given segment strings + using the given SegmentIntersector. + + A segment string + A segment string + The segment intersector to use + + + + Base class for s which make a single pass to find intersections. + This allows using a custom + (which for instance may simply identify intersections, rather than insert them). + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The to use. + + + + Gets/sets the to use with this noder. + A will normally add intersection nodes + to the input segment strings, but it may not - it may + simply record the presence of intersections. + However, some s may require that intersections be added. + + + + + Computes the noding for a collection of s. + Some Noders may add all these nodes to the input s; + others may only add some or none at all. + + + + + + Returns a of fully noded s. + The s have the same context as their parent. + + + + + + Nodes the linework in a list of s using Snap-Rounding + to a given . + + The input coordinates do not need to be rounded to the + precision model. + All output coordinates are rounded to the precision model. + + This class does not dissolve the output linework, + so there may be duplicate linestrings in the output. + Subsequent processing (e.g. polygonization) may require + the linework to be unique. Using UnaryUnion is one way + to do this (although this is an inefficient approach). + + + + + Creates a new noder which snap-rounds to a grid specified by the given + + The precision model for the grid to snap-round to. + + + + Gets or sets whether noding validity is checked after noding is performed. + + + + + Nodes the linework of a set of Geometrys using SnapRounding. + + A collection of Geometrys of any type + A list of LineStrings representing the noded linework of the input + + + + Implements a "hot pixel" as used in the Snap Rounding algorithm. + A hot pixel is a square region centred + on the rounded valud of the coordinate given, + and of width equal to the size of the scale factor. + It is a partially open region, which contains + the interior of the tolerance square and + the boundary + minus the top and right segments. + This ensures that every point of the space lies in a unique hot pixel. + It also matches the rounding semantics for numbers. + + The hot pixel operations are all computed in the integer domain + to avoid rounding problems. + + Hot Pixels support being marked as nodes. + This is used to prevent introducing nodes at line vertices + which do not have other lines snapped to them. + + + + The scaled x-ordinate of the hot pixel point () + + + The scaled y-ordinate of the hot pixel point () + + + + Initializes a new instance of the class. + + The coordinate at the center of the hot pixel + The scale factor determining the pixel size + The intersector to use for testing intersection with line segments + + + + Creates a new hot pixel centered on a rounded point, using a given scale factor. + The scale factor must be strictly positive(non-zero). + + The coordinate at the center of the hot pixel (already rounded) + The scale factor determining the pixel size + + + + Gets the coordinate this hot pixel is based at. + + + + + Gets the scale factor for the precision grid for this pixel. + + + + + Gets the width of the hot pixel in the original coordinate system. + + + + + Gets or sets a value indicating whether this pixel has been marked as a node. + + true if the pixel is marked as a node + + + + Scale without rounding. + This ensures intersections are checked against original + linework. + This is required to ensure that intersections are not missed + because the segment is moved by snapping. + + + + + Returns a "safe" envelope that is guaranteed to contain the hot pixel. + The envelope returned will be larger than the exact envelope of the pixel. + + An envelope which contains the pixel + + + + Tests whether a coordinate lies in (intersects) this hot pixel. + + The coordinate to test + true if the coordinate intersects this hot pixel + + + + Tests whether the line segment (p0-p1) + intersects this hot pixel. + + The first coordinate of the line segment to test + The second coordinate of the line segment to test + true if the line segment intersects this hot pixel. + + + + + + + + + + + + Test whether the given segment intersects + the closure of this hot pixel. + This is NOT the test used in the standard snap-rounding + algorithm, which uses the partially closed tolerance square instead. + This routine is provided for testing purposes only. + + + + + + + + Adds a new node (equal to the snap pt) to the specified segment + if the segment passes through the hot pixel + + + + true if a node was added to the segment + + + + An index which creates unique s for provided points, + and performs range queries on them. + The points passed to the index do not needed to be + rounded to the specified scale factor; this is done internally + when creating the HotPixels for them. + + Martin Davis + + + + Creates a new hot pixel index using the provided . + + The precision model + + + + Utility class to enumerate through a shuffled array of + s using the + Fisher-Yates shuffle algorithm + + + + + Creates an instance of this class using the provided s. + + An array of coordinates + + + + Creates an instance of this class using the provided s. + + An array of coordinates + + + + + + + + + + + + + + + + + + + Adds a series of points as non-node pixels + + The points to add + + + + Adds a list of points as node pixels. + + The points to add + + + + Adds a point as a Hot Pixel.
+ If the point has been added already, it is marked as a node. +
+ The point to add + The hot-pixel for the point +
+ + + Visits all the hot pixels which may intersect a segment (p0-p1). + The visitor must determine whether each hot pixel actually intersects + the segment. + + The segment start point + The segment end point + The visitor to apply + + + + "Snaps" all s in a containing + s to a given . + + + + + Initializes a new instance of the class. + + + + + + + + + + + + + + + + + + + + + + + Snaps (nodes) all interacting segments to this hot pixel. + The hot pixel may represent a vertex of an edge, + in which case this routine uses the optimization + of not noding the vertex itself + + The hot pixel to snap to. + The edge containing the vertex, if applicable, or null. + + true if a node was added for this pixel. + + + + Snaps (nodes) all interacting segments to this hot pixel. + The hot pixel may represent a vertex of an edge, + in which case this routine uses the optimization + of not noding the vertex itself + + The hot pixel to snap to. + true if a node was added for this pixel. + + + + Returns a "safe" envelope that is guaranteed to contain the hot pixel. + The envelope returned is larger than the exact envelope of the + pixel by a safe margin. + + An envelope which contains the hot pixel + + + + + + + + + Initializes a new instance of the class. + + + + + + + + Reports whether the HotPixel caused a node to be added in any target + segmentString(including its own). If so, the HotPixel must be added as a + node as well. + + + true if a node was added in any target segmentString. + + + + + Check if a segment of the monotone chain intersects + the hot pixel vertex and introduce a snap node if so. + Optimized to avoid noding segments which + contain the vertex (which otherwise + would cause every vertex to be noded). + + A monotone chain + A start index + + + + Adds a new node (equal to the snap pt) to the specified segment + if the segment passes through the hot pixel + + if a node was added to the segment + + + + Uses Snap Rounding to compute a rounded, + fully noded arrangement from a set of s. + Implements the Snap Rounding technique described in + papers by Hobby, Guibas and Marimont, and Goodrich et al. + Snap Rounding assumes that all vertices lie on a uniform grid; + hence the precision model of the input must be fixed precision, + and all the input vertices must be rounded to that precision. + + This implementation uses a monotone chains and a spatial index to + speed up the intersection tests. + +

KNOWN BUGS

+ This implementation is not fully robust. + instead. +
+ +
+ + + Initializes a new instance of the class. + + The to use. + + + + Returns a of fully noded s. + The s have the same context as their parent. + + + + + + Computes the noding for a collection of s. + Some Noders may add all these nodes to the input s; + others may only add some or none at all. + + + + + + + + + + + + + Computes all interior intersections in the collection of s, + and returns their s. + + Does NOT node the segStrings. + + + + A list of Coordinates for the intersections. + + + + Snaps segments to nodes created by segment intersections. + + + + + + Snaps segments to all vertices + + The list of segment strings to snap together + + + + Snaps segments to the vertices of a Segment String. + + + + + + Uses Snap Rounding to compute a rounded, + fully noded arrangement from a set of s. + + Implements the Snap Rounding technique described in + the papers by Hobby, Guibas & Marimont, and Goodrich et al. + Snap Rounding enforces that all vertices lie on a uniform grid, + which is determined by the provided . + Input vertices do not have to be rounded to this grid; + this will be done during the snap-rounding process. + + This implementation uses simple iteration over the line segments. + This is not an efficient approach for large sets of segments. + This implementation appears to be fully robust using an integer precision model. + It will function with non-integer precision models, but the + results are not 100% guaranteed to be correctly noded. + + + + + + Initializes a new instance of the class. + + The to use. + + + + Returns a of fully noded s. + The s have the same context as their parent. + + A Collection of NodedSegmentStrings representing the substrings + + + + Computes the noding for a collection of s. + Some Noders may add all these nodes to the input s; + others may only add some or none at all. + + A collection of NodedSegmentStrings + + + + + + + + + + Gets a list of the rounded coordinates. + Duplicate (collapsed) coordinates are removed. + + The coordinates to round + An array of rounded coordinates + + + + Computes all interior intersections in the collection of s, + and returns their s. + + Also adds the intersection nodes to the segments. + + + A list of s for the intersections. + + + + Computes nodes introduced as a result of snapping segments to snap points (hot pixels). + + + + + + + + + + + + This is where all the work of snapping to hot pixels gets done + (in a very inefficient brute-force way). + + + + + Computes nodes introduced as a result of + snapping segments to vertices of other segments. + + The list of segment strings to snap together + + + + Performs a brute-force comparison of every segment in each . + This has n^2 performance. + + + + + + + Finds intersections between line segments which will be snap-rounded, + and adds them as nodes to the segments. + + Intersections are detected and computed using full precision. + Snapping takes place in a subsequent phase. + + The intersection points are recorded, so that HotPixels can be created for them. + + To avoid robustness issues with vertices which lie very close to line segments + a heuristic is used: + nodes are created if a vertex lies within a tolerance distance + of the interior of a segment. + The tolerance distance is chosen to be significantly below the snap-rounding grid size. + This has empirically proven to eliminate noding failures. + + + + + Creates an intersector which finds all snapped interior intersections, + and adds them as nodes. + + The precision model to use + + + + Creates an intersector which finds all snapped interior intersections, + and adds them as nodes. + + the intersection distance tolerance + + + + Gets the created intersection nodes, + so they can be processed as hot pixels. + + A list of intersection points + + + + This method is called by clients + of the class to process + intersections for two segments of the + s being intersected. + Note that some clients (such as MonotoneChain s) may optimize away + this call for segment pairs which they have determined do not intersect + (e.g.by an disjoint envelope test). + + + + + If an endpoint of one segment is near + the interior of the other segment, add it as an intersection. + EXCEPT if the endpoint is also close to a segment endpoint + (since this can introduce "zigs" in the linework). + + This resolves situations where + a segment A endpoint is extremely close to another segment B, + but is not quite crossing.Due to robustness issues + in orientation detection, this can + result in the snapped segment A crossing segment B + without a node being introduced. + + + + + Always process all intersections + + Always false + + + + Uses Snap Rounding to compute a rounded, + fully noded arrangement from a set of s, + in a performant way, and avoiding unnecessary noding. + + Implements the Snap Rounding technique described in + the papers by Hobby, Guibas & Marimont, and Goodrich et al. + Snap Rounding enforces that all output vertices lie on a uniform grid, + which is determined by the provided . + + Input vertices do not have to be rounded to the grid beforehand; + this is done during the snap-rounding process. + In fact, rounding cannot be done a priori, + since rounding vertices by themselves can distort the rounded topology + of the arrangement (i.e. by moving segments away from hot pixels + that would otherwise intersect them, or by moving vertices + across segments). + + To minimize the number of introduced nodes, + the Snap-Rounding Noder avoids creating nodes + at edge vertices if there is no intersection or snap at that location. + However, if two different input edges contain identical segments, + each of the segment vertices will be noded. + This still provides fully-noded output. + This is the same behaviour provided by other noders, + such as + and . + + 1.17 + + + + The division factor used to determine + nearness distance tolerance for intersection detection. + + + + + Gets a Collection of NodedSegmentStrings representing the substrings + + + + + Computes the nodes in the snap-rounding line arrangement. + The nodes are added to the s provided as the input. + + A Collection of NodedSegmentStrings + + + + Detects interior intersections in the collection of {@link SegmentString}s, + and adds nodes for them to the segment strings. + Also creates HotPixel nodes for the intersection points. + + The input NodedSegmentStrings + + + + Creates HotPixels for each vertex in the input segStrings. + The HotPixels are not marked as nodes, since they will + only be nodes in the final line arrangement + if they interact with other segments(or they are already + created as intersection nodes). + + The input NodedSegmentStrings + + + + Gets a list of the rounded coordinates. + Duplicate (collapsed) coordinates are removed. + + The coordinates to round + Array of rounded coordinates + + + + Computes new segment strings which are rounded and contain + intersections added as a result of snapping segments to snap points (hot pixels). + + Segments to snap + The snapped segment strings + + + + Add snapped vertices to a segment string. + If the segment string collapses completely due to rounding, + null is returned. + + The segment string to snap + + The snapped segment string, or null if it collapses completely + + + + + Snaps a segment in a segmentString to HotPixels that it intersects. + + The segment start coordinate + The segment end coordinate + The segment string to add intersections to + The index of the segment/ + + + + Add nodes for any vertices in hot pixels that were + added as nodes during segment noding. + + A noded segment string + + + + Finds intersections between line segments which are being snapped, + and adds them as nodes. + + 1.17 + + + + Creates an intersector which finds all snapped intersections, + and adds them as nodes. + + The snapping tolerance distance + A snap index to use + + + + This method is called by clients + of the class to process + intersections for two segments of the s being intersected. + Note that some clients (such as MonotoneChains) may optimize away + this call for segment pairs which they have determined do not intersect + (e.g. by an disjoint envelope test). + + + + + If an endpoint of one segment is near + the interior of the other segment, add it as an intersection. + EXCEPT if the endpoint is also close to a segment endpoint + (since this can introduce "zigs" in the linework). + + This resolves situations where + a segment A endpoint is extremely close to another segment B, + but is not quite crossing. Due to robustness issues + in orientation detection, this can + result in the snapped segment A crossing segment B + without a node being introduced. + + + + + Test if two segments are adjacent segments on the same SegmentString. + Note that closed edges require a special check for the point shared by the beginning + and end segments. + + + + > + Always process all intersections> + false + + + + Nodes a set of segment strings + snapping vertices and intersection points together if + they lie within the given snap tolerance distance. + Vertices take priority over intersection points for snapping. + Input segment strings are generally only split at true node points + (i.e.the output segment strings are of maximal length in the output arrangement). + + The snap tolerance should be chosen to be as small as possible + while still producing a correct result. + It probably only needs to be small enough to eliminate + "nearly-coincident" segments, for which intersection points cannot be computed accurately. + This implies a factor of about 10e-12 + smaller than the magnitude of the segment coordinates. + + With an appropriate snap tolerance this algorithm appears to be very robust. + So far no failure cases have been found, + given a small enough snap tolerance. + + The correctness of the output is not verified by this noder. + If required this can be done by . + + 1.17 + + + + Creates a snapping noder using the given snap distance tolerance. + + Points are snapped if within this distance + + + > + A collection of s representing the substrings + + + Computes the noding of a set of s + A Collection of s + + + + Seeds the snap index with a small set of vertices + chosen quasi-randomly using a low-discrepancy sequence. + Seeding the snap index KdTree induces a more balanced tree. + This prevents monotonic runs of vertices + unbalancing the tree and causing poor query performance. + + The segStrings to be noded + + + + Computes all interior intersections in the collection of s, + and returns their s. + + Also adds the intersection nodes to the segments. + + A list of noded substrings + + + + An index providing fast creation and lookup of snap points. + + + + + Since points are added incrementally, this index needs to be dynamic. + This class also makes use of the KdTree support for a tolerance distance + for point equality. + + + + + Creates a snap point index using a specified distance tolerance. + + Points are snapped if within this distance + + + + Snaps a coordinate to an existing snap point, + if it is within the snap tolerance distance. + Otherwise adds the coordinate to the snap point index. + + The point to snap + The point it snapped to, or the input point + + + + Gets a value indicating the snapping tolerance value for the index + + + + + Gets a value indicating the depth of the tree + + + + + A wrapper for s which validates + the output arrangement is correctly noded. + An arrangement of line segments is fully noded if + there is no line segment + which has another segment intersecting its interior. + If the noding is not correct, a is thrown + with details of the first invalid location found. + + Martin Davis + + + + + Creates a noding validator wrapping the given + + The noder to validate + + + + Checks whether the output of the wrapped noder is fully noded. + Throws an exception if it is not. + + + + + + + + + A geometry service provider class + + + When overriding this class, you need to provide a public constructor with the following arguments: + + CoordinateSequenceFactoryA factory to create coordinate sequences + PrecisionModelA precision model + intspatial reference id (srid) + GeometryOverlayA class that bundles an overlay operation function set + CoordinateEqualityComparerA class that performs checks s for equality. + + + + + + + Creates an instance of this class, using the + as default and a precision model.
+ No is specified.
+ The function set for overlay operations is being used. +
+
+ + + Creates an instance of this class, using the + as default and a precision model. + No is specified + + The function set to perform overlay operations + + + + Creates an instance of this class, using the as default.
+ No is specified.
+ The default precision model is defined by .
+ The function set for overlay operations is being used. +
+
+ + + Creates an instance of this class, using the as default.
+ A value of is assigned to .
+ The default precision model is defined by .
+ The function set for overlay operations is being used. +
+
+ + + Creates an instance of this class, using a precision model as default.
+ No is specified.
+ The default coordinate sequence factory is defined by .
+ The function set for overlay operations is being used. +
+
+ + + Creates an instance of this class, using the provided , + and spatial reference Id (). + + The coordinate sequence factory to use. + The precision model. + The default spatial reference ID + + + + Creates an instance of this class, using the provided , + , a spatial reference Id () and + a . + + The coordinate sequence factory to use. + The precision model. + The default spatial reference ID + The geometry overlay function set to use. + The equality comparer for coordinates + + + + Gets or sets the default instance of . + + + Thrown when trying to set the value to . + + + + + Gets or sets a value indicating the operations to use for geometry overlay. + + A set of geometry overlay functions. + + + + Gets an object that is used to test 2 coordinates for equality. + + A coordinate equality tester object + + + + Gets the default spatial reference id + + + + + Gets or sets the coordiate sequence factory to use + + + + + Gets or sets the default precision model + + + + + Creates a precision model based on given precision model type + + The precision model type + + + + Creates a precision model based on given precision model. + + The precision model + + + + Creates a precision model based on the given scale factor. + + The scale factor + The precision model. + + + + Creates or retrieves a geometry factory using , and + . + + A geometry factory + + + + Creates or retrieves a geometry factory using , and + . + + A geometry factory + + + + Creates or retrieves a geometry factory using , and + . + + A geometry factory + + + + Creates or retrieves a geometry factory using , and + . + + The precision model to use. + A geometry factory + + + + Creates or retrieves a geometry factory using , and + . + + The precision model to use. + The spatial reference id. + A geometry factory + + + + Creates or retrieves a geometry factory using , and + . + + The precision model to use. + The spatial reference id. + + A geometry factory + + + + Creates a based on the given parameters. + + + The value for . + + + The value for . + + + The value for . + + + A that has the given values. + + + + This method is expected to be safe to call from any number of threads at once. + + + Implementations must make sure to use a constructor which + is properly assigning to the factory. + + + Although the result for a given set of parameters is cached, there is no guarantee that, + once this method is called with some set of parameters, it will never be called again + with an exactly equal set of parameters. When this does happen, an arbitrary result is + chosen as the winner (not necessarily the first one to start or finish), and all other + results are discarded. + + + + + + Computes the boundary of a . + Allows specifying the to be used. + This operation will always return a of the appropriate + dimension for the boundary (even if the input geometry is empty). + The boundary of zero-dimensional geometries (Points) is + always the empty . + + Martin Davis + + + + Computes a geometry representing the boundary of a geometry. + + The input geometry. + The computed boundary. + + + + Computes a geometry representing the boundary of a geometry, + using an explicit . + + The input geometry. + The Boundary Node Rule to use. + The computed boundary. + + + + Tests if a geometry has a boundary (it is non-empty).
+ The semantics are: + + Empty geometries do not have boundaries. + Points do not have boundaries. + For linear geometries the existence of the boundary + is determined by the . + Non-empty polygons always have a boundary. + +
+ The geometry providing the boundary + The Boundary Node Rule to use + true if the boundary exists +
+ + + Initializes a new instance of the class for the given geometry. + + The input geometry. + + + + Initializes a new instance of the class for the given geometry. + + The input geometry. + Tthe Boundary Node Rule to use. + + + + Gets the computed boundary. + + The boundary geometry. + + + + A map which maintains the edges in sorted order around the node. + + + + + Stores an integer count, for use as a Map entry. + + Martin Davis + + + + Builds the buffer geometry for a given input geometry and precision model. + Allows setting the level of approximation for circular arcs, + and the precision model in which to carry out the computation. + + + When computing buffers in floating point double-precision + it can happen that the process of iterated noding can fail to converge (terminate). + In this case a will be thrown. + Retrying the computation in a fixed precision + can produce more robust results. + + + + Compute the change in depth as an edge is crossed from R to L + + + + Initializes a new instance of the class using the given parameters. + + The buffer parameters to use. + + + + Sets the precision model to use during the curve computation and noding, + if it is different to the precision model of the Geometry. + + + If the precision model is less than the precision of the Geometry precision model, + the Geometry must have previously been rounded to that precision. + + + + + Sets the to use during noding. + This allows choosing fast but non-robust noding, or slower + but robust noding. + + + + + Sets whether the offset curve is generated + using the inverted orientation of input rings. + This allows generating a buffer(0) polygon from the smaller lobes + of self-crossing rings. + + + + + Inserted edges are checked to see if an identical edge already exists. + If so, the edge is not inserted, but its label is merged + with the existing edge. + + + + + Completes the building of the input subgraphs by depth-labelling them, + and adds them to the PolygonBuilder. + + + The subgraph list must be sorted in rightmost-coordinate order. + + the subgraphs to build + the PolygonBuilder which will build the final polygons + + + + Gets the standard result for an empty buffer. + Since buffer always returns a polygonal result, this is chosen to be an empty polygon. + + The empty result geometry + + + + Creates all the raw offset curves for a buffer of a Geometry. + Raw curves need to be noded together and polygonized to form the final buffer area. + + + + + + + The input geometry + The offset distance + A precision model + The buffer parameters + + + + Gets or sets a value indicating whether the offset curve is generated + using the inverted orientation of input rings. + This allows generating a buffer(0) polygon from the smaller lobes + of self-crossing rings. + + + + + Computes orientation of a ring using a signed-area orientation test. + For invalid (self-crossing) rings this ensures the largest enclosed area + is taken to be the interior of the ring. + This produces a more sensible result when + used for repairing polygonal geometry via buffer-by-zero. + For buffer use the lower robustness of orientation-by-area + doesn't matter, since narrow or flat rings + produce an acceptable offset curve for either orientation. + + The ring coordinates + true if the ring is CCW + + + + Computes the set of raw offset curves for the buffer. + Each offset curve has an attached {Label} indicating + its left and right location. + + A Collection of SegmentStrings representing the raw buffer curves. + + + + Creates a {SegmentString} for a coordinate list which is a raw offset curve, + and adds it to the list of buffer curves. + The SegmentString is tagged with a Label giving the topology of the curve. + The curve may be oriented in either direction. + If the curve is oriented CW, the locations will be: + Left: Location.Exterior. + Right: Location.Interior. + + + + + + + + + + + + + + + + + Add a Point to the graph. + + + + + + Keeps only valid coordinates, and removes repeated points. + + The coordinates to clean + An array of clean coordinates + + + + + + + + + + Adds an offset curve for a polygon ring. + The side and left and right topological location arguments + assume that the ring is oriented CW. + If the ring is in the opposite orientation, + the left and right locations must be interchanged and the side flipped. + + The coordinates of the ring (must not contain repeated points). + The distance at which to create the buffer. + The side of the ring on which to construct the buffer line. + The location on the L side of the ring (if it is CW). + The location on the R side of the ring (if it is CW). + + + + Tests whether the offset curve for a ring is fully inverted. + An inverted ("inside-out") curve occurs in some specific situations + involving a buffer distance which should result in a fully-eroded (empty) buffer. + It can happen that the sides of a small, convex polygon + produce offset segments which all cross one another to form + a curve with inverted orientation.
+ This happens at buffer distances slightly greater than the distance at + which the buffer should disappear.
+ The inverted curve will produce an incorrect non-empty buffer (for a shell) + or an incorrect hole (for a hole). + It must be discarded from the set of offset curves used in the buffer. + Heuristics are used to reduce the number of cases which area checked, + for efficiency and correctness. + + See +
+ the input ring + the buffer distance + the generated offset curve + true if the offset curve is inverted +
+ + + Computes the maximum distance out of a set of points to a linestring. + + The points + The linestring vertices + The maximum distance + + + + Tests whether a ring buffer is eroded completely (is empty) + based on simple heuristics. + + The is assumed to contain no repeated points. + It may be degenerate (i.e. contain only 1, 2, or 3 points). + In this case it has no area, and hence has a minimum diameter of 0. + + + + + + + + Tests whether a triangular ring would be eroded completely by the given + buffer distance. + This is a precise test. It uses the fact that the inner buffer of a + triangle converges on the inCentre of the triangle (the point + equidistant from all sides). If the buffer distance is greater than the + distance of the inCentre from a side, the triangle will be eroded completely. + This test is important, since it removes a problematic case where + the buffer distance is slightly larger than the inCentre distance. + In this case the triangle buffer curve "inverts" with incorrect topology, + producing an incorrect hole in the buffer. + + + + + + + + Simplifies a buffer input line to remove concavities with shallow depth. + + + + The most important benefit of doing this + is to reduce the number of points and the complexity of + shape which will be buffered. + It also reduces the risk of gores created by + the quantized fillet arcs (although this issue + should be eliminated in any case by the + offset curve generation logic). + + + A key aspect of the simplification is that it + affects inside (concave or inward) corners only. + Convex (outward) corners are preserved, since they + are required to ensure that the generated buffer curve + lies at the correct distance from the input geometry. + + + Another important heuristic used is that the end segments + of the input are never simplified. This ensures that + the client buffer code is able to generate end caps faithfully. + + + No attempt is made to avoid self-intersections in the output. + This is acceptable for use for generating a buffer offset curve, + since the buffer algorithm is insensitive to invalid polygonal + geometry. However, + this means that this algorithm + cannot be used as a general-purpose polygon simplification technique. + + + Martin Davis + + + + Simplify the input coordinate list. + If the distance tolerance is positive, + concavities on the LEFT side of the line are simplified. + If the supplied distance tolerance is negative, + concavities on the RIGHT side of the line are simplified. + + The coordinate list to simplify + simplification distance tolerance to use + The simplified coordinate list + + + + Simplify the input coordinate list. + + + If the distance tolerance is positive, concavities on the LEFT side of the line are simplified. + If the supplied distance tolerance is negative, concavities on the RIGHT side of the line are simplified. + + Simplification distance tolerance to use + + The simplified coordinates list + + + + + Uses a sliding window containing 3 vertices to detect shallow angles + in which the middle vertex can be deleted, since it does not + affect the shape of the resulting buffer in a significant way. + + + + + + Finds the next non-deleted index, or the end of the point array if none + + The start index to search from + The next non-deleted index, if any
+ or _inputLine.Length if there are no more non-deleted indices +
+
+ + + Checks for shallowness over a sample of points in the given section. + This helps to prevent the simplification from incrementally + "skipping" over points which are in fact non-shallow. + + A coordinate of section + A coordinate of section + The start index of section + The end index of section + The tolerated distance + + + + Computes the buffer of a geometry, for both positive and negative buffer distances. + + + + In GIS, the positive (or negative) buffer of a geometry is defined as + the Minkowski sum (or difference) of the geometry + with a circle of radius equal to the absolute value of the buffer distance. + In the CAD/CAM world buffers are known as offset curves. + In morphological analysis the + operation of positive and negative buffering + is referred to as erosion and dilation + + + The buffer operation always returns a polygonal result. + The negative or zero-distance buffer of lines and points is always an empty . + + + Since true buffer curves may contain circular arcs, + computed buffer polygons are only approximations to the true geometry. + The user can control the accuracy of the approximation by specifying + the number of linear segments used to approximate arcs. + This is specified via + or . + + + The of a linear buffer may be specified. + The following end cap styles are supported: +
    +
  • - the usual round end caps
  • +
  • - end caps are truncated flat at the line ends
  • +
  • - end caps are squared off at the buffer distance beyond the line ends
  • +
+
+ + The of the corners in a buffer may be specified. + The following join styles are supported: +
    +
  • - the usual round join
  • +
  • - corners are "sharp" (up to a distance limit})
  • +
  • - corners are beveled (clipped off)
  • +
+
+ + The buffer algorithm may perform simplification on the input to increase performance. + The simplification is performed a way that always increases the buffer area + (so that the simplified input covers the original input). + The degree of simplification can be specified with , + with a used otherwise. + Note that if the buffer distance is zero then so is the computed simplify tolerance, + no matter what the simplify factor. + + + Buffer results are always valid geometry. + Given this, computing a zero-width buffer of an invalid polygonal geometry is + an effective way to "validify" the geometry. + Note however that in the case of self-intersecting "bow-tie" geometries, + only the largest enclosed area will be retained. + +
+
+ + + A number of digits of precision which leaves some computational "headroom" + for floating point operations. + + + This value should be less than the decimal precision of double-precision values (16). + + + + + Compute a scale factor to limit the precision of + a given combination of Geometry and buffer distance. + The scale factor is determined by + the number of digits of precision in the (geometry + buffer distance), + limited by the supplied value. + + The scale factor is based on the absolute magnitude of the (geometry + buffer distance). + since this determines the number of digits of precision which must be handled. + + the Geometry being buffered + the buffer distance + the max # of digits that should be allowed by + the precision determined by the computed scale factor + + a scale factor for the buffer computation + + + + Computes the buffer of a geometry for a given buffer distance. + + the geometry to buffer + the buffer distance + the buffer of the input geometry + + + + Computes the buffer for a geometry for a given buffer distance + and accuracy of approximation. + + the geometry to buffer + the buffer distance + the buffer parameters to use + the buffer of the input geometry + + + + Computes the buffer for a geometry for a given buffer distance + and accuracy of approximation. + + the geometry to buffer + the buffer distance + the number of segments used to approximate a quarter circle + the buffer of the input geometry + + + + Buffers a geometry with distance zero. + The result can be computed using the maximum-signed-area orientation, + or by combining both orientations. + + This can be used to fix an invalid polygonal geometry to be valid + (i.e.with no self-intersections). + For some uses(e.g.fixing the result of a simplification) + a better result is produced by using only the max-area orientation. + Other uses (e.g.fixing geometry) require both orientations to be used. + + This function is for INTERNAL use only. + + The polygonal geometry to buffer by zero + A flag indicating if both orientations of input rings should be used + The buffered polygonal geometry + + + + Combines the elements of two polygonal geometries together. + The input geometries must be non-adjacent, to avoid + creating an invalid result. + + A polygonal geometry (which may be empty) + Another polygonal geometry (which may be empty) + A combined polygonal geometry + + + + Initializes a buffer computation for the given geometry + + the geometry to buffer + + + + Initializes a buffer computation for the given geometry + with the given set of parameters + + the geometry to buffer + the buffer parameters to use + + + + Gets or sets the number of line segments in a quarter-circle + used to approximate angle fillets for round end caps and joins. + + + + + Returns the buffer computed for a geometry for a given buffer distance. + + the buffer distance + the buffer of the input geometry + + + + A value class containing the parameters which + specify how a buffer should be constructed. + + The parameters allow control over: + + Quadrant segments (accuracy of approximation for circular arcs) + End Cap style + Join style + Mitre limit + whether the buffer is single-sided + + + Martin Davis + + + + The default number of facets into which to divide a fillet of 90 degrees.
+ A value of 8 gives less than 2% max error in the buffer distance. + For a max error of < 1%, use QS = 12. + For a max error of < 0.1%, use QS = 18. +
+
+ + + The default number of facets into which to divide a fillet of 90 degrees.
+ A value of 8 gives less than 2% max error in the buffer distance. + For a max error of < 1%, use QS = 12. + For a max error of < 0.1%, use QS = 18. +
+
+ + + The default mitre limit + Allows fairly pointy mitres. + + + + + The default simplify factor. + Provides an accuracy of about 1%, which matches + the accuracy of the parameter. + + + + + Creates a default set of parameters + + + + + Creates a set of parameters with the given quadrantSegments value. + + The number of quadrant segments to use + + + + Creates a set of parameters with the + given quadrantSegments and endCapStyle values. + + the number of quadrant segments to use + the end cap style to use + + + + Creates a set of parameters with the + given parameter values. + + the number of quadrant segments to use + the end cap style to use + the join style to use + the mitre limit to use + + + + Gets or sets the number of line segments in a quarter-circle + used to approximate angle fillets in round endcaps and joins. + The value should be at least 1. + + This determines the + error in the approximation to the true buffer curve.
+ The default value of 8 gives less than 2% error in the buffer distance. + For an error of < 1%, use QS = 12. + For an error of < 0.1%, use QS = 18. + The error is always less than the buffer distance + (in other words, the computed buffer curve is always inside the true + curve). +
+
+ + + Computes the maximum distance error due to a given level of approximation to a true arc. + + The number of segments used to approximate a quarter-circle + The error of approximation + + + + Gets or sets the end cap style of the generated buffer. + + + + The styles supported are , + , and + . + + The default is . + + + + + Gets/Sets the join style for outside (reflex) corners between line segments. + + + The styles supported are , + and + The default is + + + + + Sets the limit on the mitre ratio used for very sharp corners. + + + + The mitre ratio is the ratio of the distance from the corner + to the end of the mitred offset corner. + When two line segments meet at a sharp angle, + a miter join will extend far beyond the original geometry. + (and in the extreme case will be infinitely far.) + To prevent unreasonable geometry, the mitre limit + allows controlling the maximum length of the join corner. + Corners with a ratio which exceed the limit will be beveled. + + + + + + Gets or sets whether the computed buffer should be single-sided. + A single-sided buffer is constructed on only one side of each input line. + + The side used is determined by the sign of the buffer distance: + + a positive distance indicates the left-hand side + a negative distance indicates the right-hand side + + The single-sided buffer of point geometries is the same as the regular buffer. + + The End Cap Style for single-sided buffers is always ignored, + and forced to the equivalent of . + + + + + + Factor used to determine the simplify distance tolerance + for input simplification. + Simplifying can increase the performance of computing buffers. + Generally the simplify factor should be greater than 0. + Values between 0.01 and .1 produce relatively good accuracy for the generate buffer. + Larger values sacrifice accuracy in return for performance. + + + + + Creates a copy + + + + + + A connected subset of the graph of + DirectedEdges and Nodes. + Its edges will generate either + a single polygon in the complete buffer, with zero or more holes, or + one or more connected holes. + + + + + + + + + + + + + + + + + + + + Gets the rightmost coordinate in the edges of the subgraph. + + + + + Creates the subgraph consisting of all edges reachable from this node. + Finds the edges in the graph and the rightmost coordinate. + + A node to start the graph traversal from. + + + + Adds all nodes and edges reachable from this node to the subgraph. + Uses an explicit stack to avoid a large depth of recursion. + + A node known to be in the subgraph. + + + + Adds the argument node and all its out edges to the subgraph + + The node to add. + The current set of nodes being traversed. + + + + + + + + + + + + + + + Compute depths for all dirEdges via breadth-first traversal of nodes in graph. + + Edge to start processing with. + + + + + + + + + + + + + + + + Find all edges whose depths indicates that they are in the result area(s). + Since we want polygon shells to be + oriented CW, choose dirEdges with the interior of the result on the RHS. + Mark them as being in the result. + Interior Area edges are the result of dimensional collapses. + They do not form part of the result area boundary. + + + + + BufferSubgraphs are compared on the x-value of their rightmost Coordinate. + This defines a partial ordering on the graphs such that: + g1 >= g2 - Ring(g2) does not contain Ring(g1) + where Polygon(g) is the buffer polygon that is built from g. + This relationship is used to sort the BufferSubgraphs so that shells are guaranteed to + be built before holes. + + + + + End cap style constants + + + + + Specifies a round line buffer end cap style. + + + + + Specifies a flat line buffer end cap style. + + + + + Specifies a square line buffer end cap style. + + + + + Join style constants + + + + + Specifies a round join style. + + + + + Specifies a mitre join style. + + + + + Specifies a bevel join style. + + + + + Computes an offset curve from a geometry. + The offset curve is a linear geometry which is offset a specified distance + from the input. + If the offset distance is positive the curve lies on the left side of the input; + if it is negative the curve is on the right side. + + The offset curve of a line is a . + The offset curve of a Point is an empty . + The offset curve of a Polygon is the boundary of the polygon buffer (which + may be a . + For a collection the output is a {@link MultiLineString} of the element offset curves. + + The offset curve is computed as a single contiguous section of the geometry buffer boundary. + In some geometric situations this definition is ill-defined. + This algorithm provides a "best-effort" interpretation. + In particular: + + For self-intersecting lines, the buffer boundary includes + offset lines for both left and right sides of the input line. + Only a single contiguous portion on the specified side is returned. + If the offset corresponds to buffer holes, only the largest hole is used. + + Offset curves support setting the number of quadrant segments, + the join style, and the mitre limit(if applicable) via + the . + + Martin Davis + + + + The nearness tolerance between the raw offset linework and the buffer curve. + + + + + Computes the offset curve of a geometry at a given distance. + + A geometry + the offset distance (positive = left, negative = right) + The offset curve + + + + Computes the offset curve of a geometry at a given distance, + and for a specified quadrant segments, join style and mitre limit. + + A geometry + The offset distance (positive = left, negative = right) + The quadrant segments + The join style + The mitre limit + The offset curve + + + + Creates a new instance for computing an offset curve for a geometryat a given distance. + with default quadrant segments( + and join style (). + + The geometry + A distance value + + + Creates a new instance for computing an offset curve for a geometry at a given distance. + allowing the quadrant segments and join style and mitre limit to be set + via {@link BufferParameters}. + + @param geom + @param distance + @param bufParams + + + + Gets the computed offset curve. + + The offset curve geometry + + + + Force LinearRings to be LineStrings. + + A geometry, which may be a LinearRing + A geometry which will be a LineString or MulitLineString + + + + Gets the raw offset line. + The quadrant segments and join style and mitre limit to be set + via . + + The raw offset line may contain loops and other artifacts which are + not present in the true offset curve. + The raw offset line is matched to the buffer ring (which is clean) + to extract the offset curve. + + The LineString to offset + The offset distance + The buffer parameters to use + The raw offset line + + + + Gets the raw offset line, with default buffer parameters. + + The LineString to offset + The offset distance + The raw offset line + + + + Extracts the largest polygon by area from a geometry. + Used here to avoid issues with non-robust buffer results which have spurious extra polygons. + + A geometry + The polygon element of largest area + + + + An action to match a raw offset curve segment + to segments in the buffer ring + and mark them as being in the offset curve. + + Martin Davis + + + + Extracts a section of a ring of coordinates, starting at a given index, + and keeping coordinates which are flagged as being required. + + The ring of points + The index of the start coordinate + A flag indicating if coordinate is to be extracted + + + + Computes the raw offset curve for a + single component (ring, line or point). + A raw offset curve line is not noded - + it may contain self-intersections (and usually will).g + The final buffer polygon is computed by forming a topological graph + of all the noded raw curves and tracing outside contours. + The points in the raw curve are rounded + to a given . + + + + + Gets the buffer parameters being used to generate the curve. + + + + + This method handles single points as well as LineStrings. + LineStrings are assumed not to be closed (the function will not + fail for closed lines, but will generate superfluous line caps). + + The vertices of the line to offset + The offset distance + A Coordinate array representing the curve
+ or null if the curve is empty +
+
+ + + Tests whether the offset curve for line or point geometries + at the given offset distance is empty (does not exist). + This is the case if: + + the distance is zero + the distance is negative, except for the case of singled-sided buffers + + + The offset curve distance + true if the offset curve is empty + + + + This method handles the degenerate cases of single points and lines, + as well as rings. + + A Coordinate array representing the curve
+ or null if the curve is empty
+
+ + + This method handles the degenerate cases of single points and lines, + as well as rings. + + A Coordinate array representing the curve
+ or null if the curve is empty
+
+ + + Computes the distance tolerance to use during input + line simplification. + + The buffer distance + The simplification tolerance + + + + Creates all the raw offset curves for a buffer of a Geometry. + Raw curves need to be noded together and polygonized to form the final buffer area. + + + + + + + + + + + + + Gets or sets a value indicating whether the offset curve is generated + using the inverted orientation of input rings. + This allows generating a buffer(0) polygon from the smaller lobes + of self-crossing rings. + + + + + Computes orientation of a ring using a signed-area orientation test. + For invalid (self-crossing) rings this ensures the largest enclosed area + is taken to be the interior of the ring. + This produces a more sensible result when + used for repairing polygonal geometry via buffer-by-zero. + For buffer use the lower robustness of orientation-by-area + doesn't matter, since narrow or flat rings + produce an acceptable offset curve for either orientation. + + The ring coordinates + true if the ring is CCW + + + + Computes the set of raw offset curves for the buffer. + Each offset curve has an attached {Label} indicating + its left and right location. + + A Collection of SegmentStrings representing the raw buffer curves. + + + + Creates a {SegmentString} for a coordinate list which is a raw offset curve, + and adds it to the list of buffer curves. + The SegmentString is tagged with a Label giving the topology of the curve. + The curve may be oriented in either direction. + If the curve is oriented CW, the locations will be: + Left: Location.Exterior. + Right: Location.Interior. + + + + + + + + + + + + + + + + + Add a Point to the graph. + + + + + + Keeps only valid coordinates, and removes repeated points. + + The coordinates to clean + An array of clean coordinates + + + + + + + + + + Adds an offset curve for a polygon ring. + The side and left and right topological location arguments + assume that the ring is oriented CW. + If the ring is in the opposite orientation, + the left and right locations must be interchanged and the side flipped. + + The coordinates of the ring (must not contain repeated points). + The distance at which to create the buffer. + The side of the ring on which to construct the buffer line. + The location on the L side of the ring (if it is CW). + The location on the R side of the ring (if it is CW). + + +
+ Tests whether the offset curve for a ring is fully inverted. + An inverted ("inside-out") curve occurs in some specific situations + involving a buffer distance which should result in a fully-eroded (empty) buffer. + It can happen that the sides of a small, convex polygon + produce offset segments which all cross one another to form + a curve with inverted orientation.
+ This happens at buffer distances slightly greater than the distance at + which the buffer should disappear.
+ The inverted curve will produce an incorrect non-empty buffer (for a shell) + or an incorrect hole (for a hole). + It must be discarded from the set of offset curves used in the buffer. + Heuristics are used to reduce the number of cases which area checked, + for efficiency and correctness. + + See
+
+ the input ring + the buffer distance + the generated offset curve + true if the offset curve is inverted + + + + Computes the maximum distance out of a set of points to a linestring. + + The points + The linestring vertices + The maximum distance + + + + Tests whether a ring buffer is eroded completely (is empty) + based on simple heuristics. + + The is assumed to contain no repeated points. + It may be degenerate (i.e. contain only 1, 2, or 3 points). + In this case it has no area, and hence has a minimum diameter of 0. + + + + + + + + Tests whether a triangular ring would be eroded completely by the given + buffer distance. + This is a precise test. It uses the fact that the inner buffer of a + triangle converges on the inCentre of the triangle (the point + equidistant from all sides). If the buffer distance is greater than the + distance of the inCentre from a side, the triangle will be eroded completely. + This test is important, since it removes a problematic case where + the buffer distance is slightly larger than the inCentre distance. + In this case the triangle buffer curve "inverts" with incorrect topology, + producing an incorrect hole in the buffer. + + + + + + + + A list of the vertices in a constructed offset curve. + + Automatically removes close adjacent vertices. + Martin Davis + + + + Gets/Sets the precision model to use when adding new points. + + + + + The distance below which two adjacent points on the curve are considered to be coincident. + + This is chosen to be a small fraction of the offset distance. + + + + Function to add a point + + + The point is only added if evaluates to false. + + The point to add. + + + + Tests whether the given point duplicates the previous point in the list (up to tolerance) + + The point to test + true if the point duplicates the previous point + + + + Automatically closes the ring (if it not alread is). + + + + + Gets the Coordinates for the curve. + + + + + + + + Generates segments which form an offset curve. + Supports all end cap and join options + provided for buffering. + This algorithm implements various heuristics to + produce smoother, simpler curves which are + still within a reasonable tolerance of the + true curve. + + Martin Davis + + + + Factor which controls how close offset segments can be to + skip adding a filler or mitre. + + + + + Factor which controls how close curve vertices on inside turns can be to be snapped + + + + + Factor which controls how close curve vertices can be to be snapped + + + + + Factor which determines how short closing segs can be for round buffers + + + + + The max error of approximation (distance) between a quad segment and the true fillet curve + + + + + The angle quantum with which to approximate a fillet curve + (based on the input # of quadrant segments) + + + + + The Closing Segment Length Factor controls how long + "closing segments" are. Closing segments are added + at the middle of inside corners to ensure a smoother + boundary for the buffer offset curve. + In some cases (particularly for round joins with default-or-better + quantization) the closing segments can be made quite short. + This substantially improves performance (due to fewer intersections being created). + + A closingSegFactor of 0 results in lines to the corner vertex + A closingSegFactor of 1 results in lines halfway to the corner vertex + A closingSegFactor of 80 results in lines 1/81 of the way to the corner vertex + (this option is reasonable for the very common default situation of round joins + and quadrantSegs >= 8) + + + + + + Gets whether the input has a narrow concave angle + (relative to the offset distance). + In this case the generated offset curve will contain self-intersections + and heuristic closing segments. + This is expected behaviour in the case of buffer curves. + For pure offset curves, + the output needs to be further treated + before it can be used. + + + + + Add last offset point + + + + + Adds the offset points for an outside (convex) turn + + + + + Adds the offset points for an inside (concave) turn. + + + + + + + Compute an offset segment for an input segment on a given side and at a given distance. + The offset points are computed in full double precision, for accuracy. + + The segment to offset + The side of the segment the offset lies on + The offset distance + The points computed for the offset segment + + + + Add an end cap around point , terminating a line segment coming from + + + + + + + Adds a mitre join connecting two convex offset segments. + The mitre is beveled if it exceeds the mitre limit factor. + The mitre limit is intended to prevent extremely long corners occurring. + If the mitre limit is very small it can cause unwanted artifacts around fairly flat corners. + This is prevented by using a simple bevel join in this case. + In other words, the limit prevents the corner from getting too long, + but it won't force it to be very short/flat. + + A corner point + The first offset segment + The second offset segment + The offset distance + + + + Adds a limited mitre join connecting two convex offset segments. + A limited mitre join is beveled at the distance + determined by the mitre limit factor, + or as a standard bevel join, whichever is further. + + The first offset segment + The second offset segment + The offset distance + The mitre limit distance + + + + Projects a point to a given distance in a given direction angle. + + The point to project + The projection distance + The direction angle (in radians) + The projected point + + + + Adds a bevel join connecting the two offset segments + around a reflex corner. + + The first offset segment + The second offset segment + + + + Add points for a circular fillet around a convex corner. + Adds the start and end points + + Base point of curve + Start point of fillet curve + Endpoint of fillet curve + The orientation of the fillet + The radius of the fillet + + + + Adds points for a circular fillet arc + between two specified angles. + The start and end point for the fillet are not added - + the caller must add them if required. + + The center point + Is -1 for a angle, 1 for a angle + The start angle of the fillet + The end angle of the fillet + The radius of the fillet + + + + Creates a circle around a point + + + + + Creates a square around a point + + + + + A dynamic list of the vertices in a constructed offset curve. + Automatically removes adjacent vertices + which are closer than a given tolerance. + + Martin Davis + + + + The distance below which two adjacent points on the curve + are considered to be coincident.
+ This is chosen to be a small fraction of the offset distance. +
+
+ + + Tests whether the given point is redundant + relative to the previous + point in the list (up to tolerance). + + + true if the point is redundant + + + + Computes the raw offset curve for a single component (ring, line or point). + + + A raw offset curve line is not noded - it may contain self-intersections (and usually will). + The final buffer polygon is computed by forming a topological graph + of all the noded raw curves and tracing outside contours. + The points in the raw curve are rounded to the required precision model. + + + + + The angle quantum with which to approximate a fillet curve + (based on the input # of quadrant segments) + + + + + The max error of approximation (distance) between a quad segment and the true fillet curve + + + + + Factor which controls how close curve vertices can be to be snapped + + + + + Factor which controls how close offset segments can be to + skip adding a filler or mitre. + + + + + Factor which controls how close curve vertices on inside turns can be to be snapped + + + + + Factor which determines how short closing segs can be for round buffers + + + + + The Closing Segment Factor controls how long + "closing segments" are. Closing segments are added + at the middle of inside corners to ensure a smoother + boundary for the buffer offset curve.
+ In some cases (particularly for round joins with default-or-better + quantization) the closing segments can be made quite short. + This substantially improves performance (due to fewer intersections being created). +
+ A closingSegFactor of 0 results in lines to the corner vertex
+ A closingSegFactor of 1 results in lines halfway to the corner vertex
+ A closingSegFactor of 80 results in lines 1/81 of the way to the corner vertex + (this option is reasonable for the very common default situation of round joins + and quadrantSegs >= 8) +
+
+ + + This method handles single points as well as lines. + Lines are assumed to not be closed (the function will not + fail for closed lines, but will generate superfluous line caps). + + a List of Coordinate[] + + + + This method handles the degenerate cases of single points and lines, as well as rings. + + a List of Coordinate[] + + + + This method handles the degenerate cases of single points and lines, as well as rings. + + a List of Coordinate[] + + + + Use a value which results in a potential distance error which is + significantly less than the error due to + the quadrant segment discretization. + For QS = 8 a value of 100 is reasonable. + This should produce a maximum of 1% distance error. + + + + + Computes the distance tolerance to use during input + line simplification. + + The buffer distance + The simplification tolerance + + + + Adds the offset points for an outside (convex) turn + + + + + + + + Adds the offset points for an inside (concave) turn. + + + + + + + Add last offset point + + + + + Compute an offset segment for an input segment on a given side and at a given distance. + The offset points are computed in full double precision, for accuracy. + + The segment to offset + The side of the segment () the offset lies on + The offset distance + The points computed for the offset segment + + + + Add an end cap around point p1, terminating a line segment coming from p0 + + + + + Adds a mitre join connecting the two reflex offset segments. + The mitre will be beveled if it exceeds the mitre ratio limit. + + The base point + The first offset segment + The second offset segment + The offset distance + + + + Adds a limited mitre join connecting the two reflex offset segments. + + + A limited mitre is a mitre which is beveled at the distance + determined by the mitre ratio limit. + + The first offset segment + The second offset segment + The offset distance + The mitre limit ratio + + + + Adds a bevel join connecting the two offset segments around a reflex corner. + + The first offset segment + The second offset segment + + + + Add points for a circular fillet around a reflex corner. Adds the start and end points + + Base point of curve + Start point of fillet curve + Endpoint of fillet curve + The orientation of the fillet + The radius of the fillet + + + + Adds points for a circular fillet arc between two specified angles. + + + The start and end point for the fillet are not added - the caller must add them if required. + + The point around which to add the fillet points + The start angle (in radians) + The end angle (in radians) + Is -1 for a CW angle, 1 for a CCW angle + The radius of the fillet + + + + Adds a CW circle around a point + + + + + Adds a CW square around a point + + + + + A RightmostEdgeFinder find the DirectedEdge in a list which has the highest coordinate, + and which is oriented L to R at that point. (I.e. the right side is on the RHS of the edge.) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A spatial index over a segment sequence + using s. + + Martin Davis + + + + Locates a subgraph inside a set of subgraphs, + in order to determine the outside depth of the subgraph. + The input subgraphs are assumed to have had depths + already calculated for their edges. + + + + + + + + + + + + + + + + + + Finds all non-horizontal segments intersecting the stabbing line. + The stabbing line is the ray to the right of stabbingRayLeftPt. + + The left-hand origin of the stabbing line. + A List of {DepthSegments} intersecting the stabbing line. + + + + Finds all non-horizontal segments intersecting the stabbing line + in the list of dirEdges. + The stabbing line is the ray to the right of stabbingRayLeftPt. + + The left-hand origin of the stabbing line. + + The current list of DepthSegments intersecting the stabbing line. + + + + Finds all non-horizontal segments intersecting the stabbing line + in the input dirEdge. + The stabbing line is the ray to the right of stabbingRayLeftPt. + + The left-hand origin of the stabbing line. + + The current list of DepthSegments intersecting the stabbing line. + + + + A segment from a directed edge which has been assigned a depth value + for its sides. + + + + + Gets or sets the depth to the left of this segment + + + + + Initializes this DepthSegments + + A line segment + A depth value + + + + Defines a comparison operation on s + which orders them left to right. + + + Assumes the segments are normalized. + + The definition of ordering is: + + -1if DS1.seg is left of or below DS2.seg (DS1 < DS2). + 1if DS1.seg is right of or above DS2.seg (DS1 > DS2). + 0if the segments are identical + + Known Bugs: + + The logic does not obey the contract. + This is acceptable for the intended usage, but may cause problems if used with some + utilities in the .Net standard library (e.g. . + + + A DepthSegment + The comparison value + + + + Finds the approximate maximum distance from a buffer curve to + the originating geometry. + + The approximate maximum distance is determined by testing + all vertices in the buffer curve, as well + as midpoints of the curve segments. + Due to the way buffer curves are constructed, this + should be a very close approximation. + This is similar to the Discrete Oriented Hausdorff distance + from the buffer curve to the input. + + mbdavis + + + + Validates that a given buffer curve lies an appropriate distance + from the input generating it. + + + Useful only for round buffers (cap and join). + Can be used for either positive or negative distances. + + This is a heuristic test, and may return false positive results + (I.e. it may fail to detect an invalid result.) + It should never return a false negative result, however + (I.e. it should never report a valid result as invalid.) + + mbdavis + + + + Gets a geometry which indicates the location and nature of a validation failure. + + The indicator is a line segment showing the location and size + of the distance discrepancy. + + + A geometric error indicator + or null, if no error was found + + + + Checks that two geometries are at least a minimum distance apart. + + A geometry + A geometry + The minimum distance the geometries should be separated by + + + + Checks that the furthest distance from the buffer curve to the input + is less than the given maximum distance. + + + This uses the Oriented Hausdorff distance metric. It corresponds to finding + the point on the buffer curve which is furthest from some point on the input. + + A geometry + A geometry + The maximum distance that a buffer result can be from the input + + + + Validates that the result of a buffer operation + is geometrically correct, within a computed tolerance. + + + This is a heuristic test, and may return false positive results + (I.e. it may fail to detect an invalid result.) + It should never return a false negative result, however + (I.e. it should never report a valid result as invalid.) + This test may be (much) more expensive than the original buffer computation. + + Martin Davis + + + Checks whether the geometry buffer is valid, and returns an error message if not. + + + + + An appropriate error message
+ or nullif the buffer is valid
+ +
+ + + Gets the error message + + + + + Gets the error location + + + + + Gets a geometry which indicates the location and nature of a validation failure. + + If the failure is due to the buffer curve being too far or too close + to the input, the indicator is a line segment showing the location and size + of the discrepancy. + + + A geometric error indicator
+ or null, if no error was found
+
+ + + Computes the Euclidean distance (L2 metric) from a Point to a Geometry. + Also computes two points which are separated by the distance. + + + + + Contains a pair of points and the distance between them. + Provides methods to update with a new point pair with + either maximum or minimum distance. + + + + + Initializes the points, avoiding recomputing the distance. + + The first point + The second point + The distance between and + + + + Creates a buffer polygon with a varying buffer distance + at each vertex along a line. + + Only single lines are supported as input, since buffer widths + generally need to be specified individually for each line. + + Martin Davis + + + + Creates a buffer polygon along a line with the buffer distance interpolated + between a start distance and an end distance. + + The line to buffer + The buffer width at the start of the line + The buffer width at the end of the line + The variable-distance buffer polygon + + + + Creates a buffer polygon along a line with the buffer distance interpolated + between a start distance, a middle distance and an end distance. + The middle distance is attained at + the vertex at or just past the half-length of the line. + For smooth buffering of a (or the rings of a ) + the start distance and end distance should be equal. + + The line to buffer + The buffer width at the start of the line + The buffer width at the middle vertex of the line + The buffer width at the end of the line + The variable-distance buffer polygon + + + + Creates a buffer polygon along a line with the distance specified + at each vertex. + + The line to buffer + The buffer distance for each vertex of the line + The variable-width buffer polygon + + + + Computes a list of values for the points along a line by + interpolating between values for the start and end point. + The interpolation is + based on the distance of each point along the line + relative to the total line length. + + The line to interpolate along + The start value + The end value + The array of interpolated values + + + + Computes a list of values for the points along a line by + interpolating between values for the start, middle and end points. + The interpolation is + based on the distance of each point along the line + relative to the total line length. + The middle distance is attained at + the vertex at or just past the half-length of the line. + + The line to interpolate along + The start value + The mid value + The end value + The array of interpolated values + + + + Creates a generator for a variable-distance line buffer. + + The linestring to buffer + The buffer distance for each vertex of the line + + + + Computes the buffer polygon. + + A buffer polygon + + + + Computes a variable buffer polygon for a single segment, + with the given endpoints and buffer distances. + The individual segment buffers are unioned + to form the final buffer. + + The segment start point + The segment end point + The buffer distance at the start point + The buffer distance at the end point + The segment buffer + + + + Returns a circular polygon. + + The circle center point + The radius + A polygon, or null if the radius is 0 + + + + Adds a semi-circular cap CCW around the point . + + The centre point of the cap + The cap radius + the starting point of the cap + The ending point of the cap + The coordinate list to add to + + + + Computes the angle for the given cap point index. + + The fillet angle index + + + + Computes the canonical cap point index for a given angle. + The angle is rounded down to the next lower + index. + + In order to reduce the number of points created by overlapping end caps, + cap points are generated at the same locations around a circle. + The index is the index of the points around the circle, + with 0 being the point at (1,0). + The total number of points around the circle is + 4 * . + + The angle + The index for the angle. + + +
+ Computes the two circumference points defining the outer tangent line + between two circles. + + For the algorithm see Wikipedia. + + The centre of circle 1 + The radius of circle 1 + The centre of circle 2 + The radius of circle 2 + The outer tangent line segment, or null if none exists + + + + Snap trig values to integer values for better consistency. + + The result of a trigonometric function + snapped to the integer interval + + + + A wrapper which + projects 3D coordinates into one of the + three Cartesian axis planes, + using the standard orthonormal projection + (i.e. simply selecting the appropriate ordinates into the XY ordinates). + The projected data is represented as 2D coordinates. + + Martin Davis + + + + Creates a wrapper projecting to the XY plane. + + The sequence to be projected + A sequence which projects coordinates + + + + Creates a wrapper projecting to the XZ plane. + + The sequence to be projected + A sequence which projects coordinates + + + + Creates a wrapper projecting to the YZ plane. + + The sequence to be projected + A sequence which projects coordinates + + + + + + + Find two points on two 3D s which lie within a given distance, + or else are the nearest points on the geometries (in which case this also + provides the distance between the geometries). + + 3D geometries have vertex Z ordinates defined. + 3D s are assumed to lie in a single plane (which is enforced if not actually the case). + 3D s and s may have any configuration. + + The distance computation also finds a pair of points in the input geometries + which have the minimum distance between them. If a point lies in the interior + of a line segment, the coordinate computed is a close approximation to the + exact point. + + The algorithms used are straightforward O(n^2) comparisons. This worst-case + performance could be improved on by using Voronoi techniques or spatial + indexes. + + 1.13 + + + + Compute the distance between the nearest points of two geometries. + + A geometry + A geometry + The distance between the geometries + + + + Test whether two geometries lie within a given distance of each other. + + A geometry + A geometry + The distance to test + true if g0.distance(g1) <= + + + + Compute the the nearest points of two geometries. The points are + presented in the same order as the input Geometries. + + A geometry + A geometry + The nearest points in the geometries + + + + Constructs a DistanceOp that computes the distance and nearest points + between the two specified geometries. + + A geometry + A geometry + + + + Constructs a DistanceOp that computes the distance and nearest points + between the two specified geometries. + + A geometry + A geometry + The distance on which to terminate the search + + + + Report the distance between the nearest points on the input geometries. + + The distance between the geometries
+ or 0 if either input geometry is empty
+ Thrown if either input geometry is null. +
+ + + Report the coordinates of the nearest points in the input geometries. The + points are presented in the same order as the input Geometries. + + A pair of s of the nearest points + + + + Gets the locations of the nearest points in the input geometries. The + locations are presented in the same order as the input Geometries. + + A pair of s for the nearest points + + + + Finds the index of the "most polygonal" input geometry. + This optimizes the computation of the best-fit plane, + since it is cached only for the left-hand geometry. + + The index of the most polygonal geometry + + + + Convenience method to create a Plane3DPolygon + + + + + Computes distance between two polygons. + + + To compute the distance, compute the distance + between the rings of one polygon and the other polygon, + and vice-versa. + If the polygons intersect, then at least one ring must + intersect the other polygon. + Note that it is NOT sufficient to test only the shell rings. + A counter-example is a "figure-8" polygon A + and a simple polygon B at right angles to A, with the ring of B + passing through the holes of A. + The polygons intersect, + but A's shell does not intersect B, and B's shell does not intersect A. + + + Compute distance between a polygon and the rings of another. + + + + Computes a point at a distance along a segment + specified by two relatively proportional values. + The fractional distance along the segment is d0/(d0+d1). + + Start point of the segment. + End point of the segment + Proportional distance from start point to computed point + Proportional distance from computed point to end point + The computed point + + + + Models a polygon lying in a plane in 3-dimensional Cartesian space. + The polygon representation is supplied + by a , + containing coordinates with XYZ ordinates. + 3D polygons are assumed to lie in a single plane. + The plane best fitting the polygon coordinates is + computed and is represented by a . + + Martin Davis + + + + Creates an instance of this class using the provided . + + The polygon + + + + Finds a best-fit plane for the polygon, + by sampling a few points from the exterior ring. + + The algorithm used is Newell's algorithm: + + a base point for the plane is determined from the average of all vertices + the normal vector is determined by computing the area of the projections on each of the axis planes + + + The polygon to determine the plane for + The best-fit plane + + + + Computes an average normal vector from a list of polygon coordinates. + Uses Newell's method, which is based + on the fact that the vector with components + equal to the areas of the projection of the polygon onto + the Cartesian axis planes is normal. + + The sequence of coordinates for the polygon + A normal vector + + + + Computes a point which is the average of all coordinates + in a sequence.
+ If the sequence lies in a single plane, + the computed point also lies in the plane. +
+ A coordinate sequence + A Coordinate with averaged ordinates +
+ + + Gets a value indicating the plane + + + + + Gets a value indicating the polygon + + + + + Checks if intersects with this . + + The point to check + true if intPt intersects this PlanarPolygon3d. + + + + Checks if the point intersects with when projected to this instance's facing plane + + A point + A ring + true if point and linestring intersect + + + + A ConnectedElementPointFilter extracts a single point + from each connected element in a Geometry + (e.g. a polygon, linestring or point) + and returns them in a list. The elements of the list are + s. + Empty geometries do not provide a location item. + + + + + Returns a list containing a point from each Polygon, LineString, and Point + found inside the specified point. Thus, if the specified point is + not a GeometryCollection, an empty list will be returned. The elements of the list + are s. + + + + + + + + + + + + + + + + + Extracts a single point + from each connected element in a Geometry + (e.g. a polygon, linestring or point) + and returns them in a list + + + + + Returns a list containing a Coordinate from each Polygon, LineString, and Point + found inside the specified point. Thus, if the specified point is + not a GeometryCollection, an empty list will be returned. + + + + + + + + + + + + + + + + + Computes the distance and + closest points between two Geometrys. + The distance computation finds a pair of points in the input geometries + which have minimum distance between them. These points may + not be vertices of the geometries, but may lie in the interior of + a line segment. In this case the coordinate computed is a close + approximation to the exact point. + + Empty geometry collection components are ignored. + + The algorithms used are straightforward O(n^2) + comparisons. This worst-case performance could be improved on + by using Voronoi techniques. + + + + + Compute the distance between the closest points of two geometries. + + A Geometry. + Another Geometry. + The distance between the geometries. + + + + Test whether two geometries lie within a given distance of each other. + + + + + + + + + Compute the the closest points of two geometries. + The points are presented in the same order as the input Geometries. + + A Geometry. + Another Geometry. + The closest points in the geometries. + + + + Constructs a that computes the distance and closest points between + the two specified geometries. + + A geometry + A geometry + + + + Constructs a that computes the distance and closest points between + the two specified geometries. + + A geometry + A geometry + The distance on which to terminate the search. + + + + Report the distance between the closest points on the input geometries. + + The distance between the geometries
+ or 0 if either input geometry is empty.
+ if either input geometry is null +
+ + + Report the coordinates of the nearest points in the input geometries. + The points are presented in the same order as the input Geometries. + + A pair of Coordinates of the nearest points. + + + + Report the locations of the nearest points in the input geometries. + The locations are presented in the same order as the input Geometries. + + A pair of s for the nearest points. + + + + + + + + + + + + + + + + + + + + + + + + + + + Computes distance between facets (lines and points) of input geometries. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Represents a sequence of facets (points or line segments) of a + specified by a subsequence of a . + + Martin Davis + + + + Creates a new sequence of facets based on a + contained in the given . + + The geometry containing the facets. + The sequence containing the facet points. + The index of the start point. + The index of the end point. + + + + Creates a new sequence of facets based on a . + + The sequence containing facet points. + The index of the start point + The index of the end point + 1 + + + + Creates a new sequence for a single point from a CoordinateSequence. + + The sequence containing the facet point. + the index of the point + + + + Gets the envelope of this facet sequence + + + + + Gets the number of coordinates in this facet sequence + + + + + Gets the coordinate at the given index + + The index + The coordinate at the given index + + + + Tests if this facet sequence consists of only one point + + + + + Computes the distance between this and another + . + + The sequence to compute the distance to. + The minimum distance between the sequences. + + + + Computes the locations of the nearest points between this sequence + and another sequence. + The locations are presented in the same order as the input sequences. + + A pair of s for the nearest points. + + + + + + + Utility class to build facet sequencs STRtrees- + + + + + + + + + + + + Creates facet sequences from a given geometry + + The geometry + A list of s + + + + Represents the location of a point on a Geometry. + Maintains both the actual point location + (which may not be exact, if the point is not a vertex) + as well as information about the component + and segment index where the point occurs. + Locations inside area Geometrys will not have an associated segment index, + so in this case the segment index will have the sentinel value of . + + + + + A special value of segmentIndex used for locations inside area geometries. + These locations are not located on a segment, + and thus do not have an associated segment index. + + + + + Constructs a GeometryLocation specifying a point on a point, as well as the + segment that the point is on (or if the point is not on a segment). + + The component of the geometry containing the point + The segment index of the location, or + The coordinate of the location + + + + Constructs a GeometryLocation specifying a point inside an area point. + + The component of the geometry containing the point + The coordinate of the location + + + + Returns the geometry component on (or in) which this location occurs. + + + + + Returns the segment index for this location. If the location is inside an + area, the index will have the value . + + + + + Returns the of this location. + + + + + Tests whether this location represents a point inside an area geometry. + + + + + + + + Computes the distance between the facets (segments and vertices) + of two s + using a Branch-and-Bound algorithm. + The Branch-and-Bound algorithm operates over a + traversal of R-trees built + on the target and the query geometries. + + This approach provides the following benefits: + + + Performance is dramatically improved due to the use of the + R-tree index + and the pruning due to the Branch-and-Bound approach + + The spatial index on the target geometry is cached + which allow reuse in an repeated query situation. + + Using this technique is usually much more performant + than using the brute-force + when one or both input geometries are large, + or when evaluating many distance computations against + a single geometry. + + + This class is thread-safe. + + Martin Davis + + + + + Computes the distance between facets of two geometries. + + + For geometries with many segments or points, + this can be faster than using a simple distance + algorithm. + + A geometry + A geometry + The distance between the two geometries + + + + Tests whether the facets of two geometries lie within a given distance. + + A geometry + A geometry + The distance limit + true if two facets lie with the given distance + + + + Computes the nearest points of the facets of two geometries. + + A geometry + A geometry + The nearest points on the facets of the geometries + + + + Creates a new distance-finding instance for a given target . + + + + Distances will be computed to all facets of the input geometry. + The facets of the geometry are the discrete segments and points + contained in its components. + + In the case of and inputs, + this is equivalent to computing the conventional distance. + + In the case of inputs, this is equivalent + to computing the distance to the polygon boundaries. + + + A Geometry, which may be of any type. + + + + Computes the distance from the base geometry to the given geometry. + + The geometry to compute the distance to. + The computed distance + + + + Computes the nearest locations on the base geometry + and the given geometry. + + Ihe geometry to compute the nearest location to. + The nearest locations. + + + + Computes the nearest locations on the target geometry + and the given geometry. + + Ihe geometry to compute the nearest point to. + The nearest points. + + + + Tests whether the base geometry lies within + a specified distance of the given geometry. + + The geometry to test + The maximum distance to test + true if the geometry lies with the specified distance + + + + The base class for operations that require s. + + + + + + + + + + + + + + + The operation args into an array so they can be accessed by index. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tests whether a is simple. + In general, the SFS specification of simplicity + follows the rule: + + + A Geometry is simple if and only if the only self-intersections are at boundary points. + + + + + Simplicity is defined for each } subclass as follows: + + Valid geometries are simple by definition, so + IsSimple trivially returns true.
+ (Note: this means that IsSimple cannot be used to test + for (invalid) self-intersections in Polygons. + In order to check if a Polygonal geometry has self-intersections, + use ).
+ geometries are simple if and only if they do not self-intersect at interior points + (i.e. points other than boundary points). + This is equivalent to saying that no two linear components satisfy the SFS + predicate. + Zero-dimensional () geometries are simple if and only if they have no + repeated points. + Empty s are always simple by definition. +
+ For geometries the evaluation of simplicity + can be customized by supplying a + to define how boundary points are determined. + The default is the SFS-standard . + Note that under the Mod-2 rule, closed LineStrings (rings) + will never satisfy the touches predicate at their endpoints, since these are + interior points, not boundary points. + If it is required to test whether a set of LineStrings touch + only at their endpoints, use IsSimpleOp with . + For example, this can be used to validate that a set of lines form a topologically valid + linear network. +
+
+ + + Creates a simplicity checker using the default SFS Mod-2 Boundary Node Rule + + The geometry to test + + + + Creates a simplicity checker using a given + + The geometry to test + The rule to use + + + + Tests whether the geometry is simple. + + true if the geometry is simple + + + + Gets a coordinate for the location where the geometry fails to be simple. + (i.e. where it has a non-boundary self-intersection). + must be called before this location is accessed + + a coordinate for the location of the non-boundary self-intersection + or null if the geometry is simple + + + + Computes simplicity for polygonal geometries. + Polygonal geometries are simple if and only if + all of their component rings are simple. + + A Polygonal geometry + true if the geometry is simple + + + Semantics for GeometryCollection is + simple if all components are simple. + A GeometryCollection + true if the geometry is simple + + + + For all edges, check if there are any intersections which are NOT at an endpoint. + The Geometry is not simple if there are intersections not at endpoints. + + + + + + + + + + + Creates an instance of this class + + The endpoint + + + + Tests that no edge intersection is the endpoint of a closed line. + This ensures that closed lines are not touched at their endpoint, + which is an interior point according to the Mod-2 rule + To check this we compute the degree of each endpoint. + The degree of endpoints of closed lines + must be exactly 2. + + + + + Add an endpoint to the map, creating an entry for it if none exists. + + + + + + + + A sequence of LineMergeDirectedEdges forming one of the lines that will + be output by the line-merging process. + + + + + Constructs an EdgeString with the given factory used to convert this EdgeString + to a LineString. + + + + + + Adds a directed edge which is known to form part of this line. + + + + + + + + + + + Converts this EdgeString into a LineString. + + + + + A com.vividsolutions.jts.planargraph.DirectedEdge of a LineMergeGraph. + + + + + Constructs a LineMergeDirectedEdge connecting the from node to the to node. + + + + + specifies this DirectedEdge's direction (given by an imaginary + line from the from node to directionPt). + + + whether this DirectedEdge's direction is the same as or + opposite to that of the parent Edge (if any). + + + + + Returns the directed edge that starts at this directed edge's end point, or null + if there are zero or multiple directed edges starting there. + + + + + An edge of a LineMergeGraph. The marked field indicates + whether this Edge has been logically deleted from the graph. + + + + + Constructs a LineMergeEdge with vertices given by the specified LineString. + + + + + + Returns the LineString specifying the vertices of this edge. + + + + + A planar graph of edges that is analyzed to sew the edges together. The + marked flag on s + and s indicates whether they have been + logically deleted from the graph. + + + + + Adds an Edge, DirectedEdges, and Nodes for the given LineString representation + of an edge. + + + + + + + + + + + + Sews together a set of fully noded LineStrings. + + + Sewing stops at nodes of degree 1 + or 3 or more -- the exception is an isolated loop, which only has degree-2 nodes, + in which case a node is simply chosen as a starting point. The direction of each + merged LineString will be that of the majority of the LineStrings from which it + was derived. + + Any dimension of Geometry is handled -- the constituent linework is extracted to + form the edges. The edges must be correctly noded; that is, they must only meet + at their endpoints. The LineMerger will still run on incorrectly noded input + but will not form polygons from incorrected noded edges. + + NOTE:once merging has been performed, no more + + + + + + + + + + + + + + + + + + + + + + Adds a Geometry to be processed. May be called multiple times. + Any dimension of Geometry may be added; the constituent linework will be + extracted. + + + + + + Adds a collection of Geometries to be processed. May be called multiple times. + Any dimension of Geometry may be added; the constituent linework will be + extracted. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Returns the LineStrings built by the merging process. + + + + + + + Builds a sequence from a set of s, + so that they are ordered end to end. + A sequence is a complete non-repeating list of the linear + components of the input. Each linestring is oriented + so that identical endpoints are adjacent in the list. + + + The input linestrings may form one or more connected sets. + The input linestrings should be correctly noded, or the results may + not be what is expected. + The output of this method is a single , + containing the ordered linestrings in the sequence. + + + The sequencing employs the classic 'Eulerian path' graph algorithm. + Since Eulerian paths are not uniquely determined, further rules are used to + make the computed sequence preserve as much as possible of the input ordering. + Within a connected subset of lines, the ordering rules are: + - If there is degree-1 node which is the start + node of an linestring, use that node as the start of the sequence. + - If there is a degree-1 node which is the end + node of an linestring, use that node as the end of the sequence. + - If the sequence has no degree-1 nodes, use any node as the start + + + Not all arrangements of lines can be sequenced. + For a connected set of edges in a graph, + Euler's Theorem states that there is a sequence containing each edge once + if and only if there are no more than 2 nodes of odd degree. + If it is not possible to find a sequence, the + property will return false. + + + + + + Tests whether a is sequenced correctly. + s are trivially sequenced. + s are checked for correct sequencing. + Otherwise, IsSequenced is defined + to be true for geometries that are not lineal. + + The to test. + + true if the is sequenced or is not lineal. + + + + + Adds a of s to be sequenced. + May be called multiple times. + Any dimension of Geometry may be added; the constituent linework will be extracted. + + A of geometries to add. + + + + Adds a to be sequenced. + May be called multiple times. + Any dimension of may be added; + the constituent linework will be extracted. + + + + + + A private implementation for + + + + + Initializes a new instance of the class. + + The sequencer. + + + + Performs an operation with or on + + + A to which the filter is applied. + + + + + Tests whether the arrangement of linestrings has a valid sequence. + + true if a valid sequence exists. + + + + Returns the or + built by the sequencing process, if one exists. + + The sequenced linestrings, + or null if a valid sequence does not exist. + + + + Tests whether a complete unique path exists in a graph + using Euler's Theorem. + + The containing the edges. + true if a sequence exists. + + + + Finds an for an unvisited edge (if any), + choosing the which preserves orientation, if possible. + + The to examine. + + The found, + or null if none were unvisited. + + + + + Computes a version of the sequence which is optimally + oriented relative to the underlying geometry. + + Heuristics used are: + - If the path has a degree-1 node which is the start + node of an linestring, use that node as the start of the sequence. + - If the path has a degree-1 node which is the end + node of an linestring, use that node as the end of the sequence. + - If the sequence has no degree-1 nodes, use any node as the start + (NOTE: in this case could orient the sequence according to the majority of the + linestring orientations). + + + A of s. + + A of s oriented appropriately. + + + + + Reverse the sequence. + This requires reversing the order of the s, + and flipping each as well. + + + A enumeration of s, + in sequential order. + + The reversed sequence. + + + + Builds a geometry ( or ) + representing the sequence. + + + An enumeration of s of s + with s as their parent edges. + + + The sequenced geometry, or null if no sequence exists. + + + + + Unions a valid coverage of polygons or lines + in an efficient way. + + A valid polygonal coverage is a collection of s + which satisfy the following conditions: + + Vector-cleanLine segments within the collection + must either be identical or intersect only at endpoints. + Non-overlappingNo two polygons + may overlap. Equivalently, polygons must be interior-disjoint. + + + A valid linear coverage is a collection of s + which satisfies the Vector-clean condition. + Note that this does not require the LineStrings to be fully noded + - i.e. they may contain coincident linework. + Coincident line segments are dissolved by the union. + Currently linear output is not merged (this may be added in a future release.) + + Currently no checking is done to determine whether the input is a valid coverage. + This is because coverage validation involves segment intersection detection, + which is much more expensive than the union phase. + If the input is not a valid coverage + then in some cases this will be detected during processing + and a is thrown. + Otherwise, the computation will produce output, but it will be invalid. + + Unioning a valid coverage implies that no new vertices are created. + This means that a precision model does not need to be specified. + The precision of the vertices in the output geometry is not changed. + + Martin Davis + + + + + Unions a valid polygonal coverage or linear network. + + A coverage of polygons or lines + The union of the coverage + Thrown in some cases if the coverage is invalid + + + + Represents the linework for edges in a topology graph, + derived from(up to) two parent geometries. + An edge may be the result of the merging of + two or more edges which have the same linework + (although possibly different orientations). + In this case the topology information is + derived from the merging of the information in the + source edges.
+ Merged edges can occur in the following situations + + Due to coincident edges of polygonal or linear geometries. + Due to topology collapse caused by snapping or rounding + of polygonal geometries. + + The source edges may have the same parent geometry, + or different ones, or a mix of the two. +
+ Martin Davis +
+ + + Tests if the given point sequence + is a collapsed line. + A collapsed edge has fewer than two distinct points. + + The point sequence to check + true if the points form a collapsed line + + + + Compares two coincident edges to determine + whether they have the same or opposite direction. + + An edge + true if the edges have the same direction, false if not + + + + Populates the label for an edge resulting from an input geometry. + + + If the edge is not part of the input, the label is left as + If input is an Area and the edge is on the boundary (which may include some collapses), edge is marked as an edge and side locations are assigned + If input is an Area and the edge is collapsed (depth delta = 0), the label is set to . The location will be determined later by evaluating the final graph topology. + If input is a Line edge is set to a edge. For line edges the line location is not significant (since there is no parent area for which to determine location). + + + + + + Tests whether the edge is part of a shell in the given geometry. + This is only the case if the edge is a boundary. + + The index of the geometry + true if this edge is a boundary and part of a shell + + + + Merges an edge into this edge, + updating the topology info accordingly. + + The edge to merge + + + + A key for sorting and comparing edges in a noded arrangement. + Relies on the fact that in a correctly noded arrangement + edges are identical (up to direction) + if they have their first segment in common. + + Martin Davis + + + + + + + + + + + + + Performs merging on the noded edges of the input geometries. + Merging takes place on edges which are coincident + (i.e.have the same coordinate list, modulo direction). + The following situations can occur: + + Coincident edges from different input geometries have their labels combined + Coincident edges from the same area geometry indicate a topology collapse. + In this case the topology locations are "summed" to provide a final + assignment of side location + Coincident edges from the same linear geometry can simply be merged + using the same ON location + + + The merging attempts to preserve the direction of linear + edges if possible(which is the case if there is + no other coincident edge, or if all coincident edges have the same direction). + This ensures that the overlay output line direction will be as consistent + as possible with input lines. + + The merger also preserves the order of the edges in the input. + This means that for polygon-line overlay + the result lines will be in the same order as in the input + (possibly with multiple result lines for a single input line). + + Martin Davis + + + + Builds a set of noded, unique, labelled Edges from + the edges of the two input geometries. + + It performs the following steps: + + Extracts input edges, and attaches topological information + if clipping is enabled, handles clipping or limiting input geometry + chooses a based on provided precision model, unless a custom one is supplied + calls the chosen Noder, with precision model + removes any fully collapsed noded edges + builds s and merges them + + + Martin Davis + + + + Creates a new builder, with an optional custom noder. + If the noder is not provided, a suitable one will + be used based on the supplied precision model. + + The precision model to use + An optional noder to use (may be null) + + + + Gets or sets a noder appropriate for the precision model supplied.
+ This is one of: + + Fixed precision:a snap-rounding noder (which should be fully robust) + Floating precision:a conventional noder (which may be non-robust). + In this case, a validation step is applied to the output from the noder. + +
+
+ + + Reports whether there are noded edges + for the given input geometry. + If there are none, this indicates that either + the geometry was empty, or has completely collapsed + (because it is smaller than the noding precision). + + index of the input geometry + true if there are edges for the geometry + + + + Creates a set of labelled {Edge}s. + representing the fully noded edges of the input geometries. + Coincident edges (from the same or both geometries) + are merged along with their labels + into a single unique, fully labelled edge. + + The first geometry + The second geometry + The noded, merged, labelled edges + + + + Nodes a set of segment strings and creates s from the result. + The input segment strings each carry a object, + which is used to provide source topology info to the constructed Edges + (and is then discarded). + + + + + Adds a polygon ring to the graph. + + Empty rings are ignored. + + + + Tests whether a geometry (represented by its envelope) + lies completely outside the clip extent(if any). + + The geometry envelope + true if the geometry envelope is outside the clip extent. + + + + If clipper is present, + clip the line to the clip extent. + + If clipping is enabled, then every ring MUST + be clipped, to ensure that holes are clipped to + be inside the shell. + This means it is not possible to skip + clipping for rings with few vertices. + + The line to clip + The points in the clipped ring + + + + Removes any repeated points from a linear component. + This is required so that noding can be computed correctly. + + The line to process + The points of the line with repeated points removed + + + + Adds a line geometry, limiting it if enabled, + and otherwise removing repeated points. + + The line to add + The index of the parent geometry + + + + Tests whether it is worth limiting a line. + Lines that have few vertices or are covered + by the clip extent do not need to be limited. + + The line to test + true if the line should be limited + + + + If limiter is provided, + limit the line to the clip envelope. + + The line to clip + the point sections in the clipped line + + + + Records topological information about an + edge representing a piece of linework (lineString or polygon ring) + from a single source geometry. + This information is carried through the noding process + (which may result in many noded edges sharing the same information object). + It is then used to populate the topology info fields + in s (possibly via merging). + That information is used to construct the topology graph s. + + Martin Davis + + + A simple elevation model used to populate missing Z values + in overlay results. + + The model divides the extent of the input geometry(s) + into an NxM grid. + The default grid size is 3x3. + If the input has no extent in the X or Y dimension, + that dimension is given grid size 1. + The elevation of each grid cell is computed as the average of the Z values + of the input vertices in that cell (if any). + If a cell has no input vertices within it, it is assigned + the average elevation over all cells. + + If no input vertices have Z values, the model does not assign a Z value. + + The elevation of an arbitrary location is determined as the + Z value of the nearest grid cell. + + An elevation model can be used to populate missing Z values + in an overlay result geometry. + + Martin Davis + + + + Creates an elevation model from two geometries (which may be null). + + An input geometry + An input geometry + The elevation model computed from the geometries + + + + Creates a new elevation model covering an extent by a grid of given dimensions. + + The XY extent to cover + The number of grid cells in the X dimension + The number of grid cells in the Y dimension + + + + Updates the model using the Z values of a given geometry. + + The geometry to scan for Z values. + + + + Gets the model Z value at a given location. + If the location lies outside the model grid extent, + this returns the Z value of the nearest grid cell. + If the model has no elevation computed (i.e. due + to empty input), the value is returned as + + x-ordinate of the location + y-ordinate of the location + The computed Z value + + + + Computes Z values for any missing Z values in a geometry, + using the computed model. + If the model has no Z value, or the geometry coordinate dimension + does not include Z, the geometry is not updated. + + The geometry to populate Z values for + + + + Locates points on a linear geometry, + using a spatial index to provide good performance. + + Martin Davis + + + + Manages the input geometries for an overlay operation. + The second geometry is allowed to be null, + to support for instance precision reduction. + + Martin Davis + + + + Gets the index of an input which is an area, + if one exists. + Otherwise returns -1. + + The index of an area input, or -1 + + + + Tests if an input geometry has edges. + This indicates that topology needs to be computed for them. + + + true if the input geometry has edges + + + + Determines the location within an area geometry. + This allows disconnected edges to be fully + located. + + The index of the geometry + The coordinate to locate + The location of the coordinate + + + + + Extracts Point resultants from an overlay graph + created by an Intersection operation + between non-Point inputs. + Points may be created during intersection + if lines or areas touch one another at single points. + Intersection is the only overlay operation which can + result in Points from non-Point inputs. + + Overlay operations where one or more inputs + are Points are handled via a different code path. + + Martin Davis + + + + + Controls whether lines created by area topology collapses + to participate in the result computation.
+ True provides the original JTS semantics. +
+
+ + + Tests if a node is a result point. + This is the case if the node is incident on edges from both + inputs, and none of the edges are themselves in the result. + + An edge originating at the node + true if the node is a result point. + + + + Finds and builds overlay result lines from the overlay graph. + Output linework has the following semantics: + + Linework is fully noded + Lines are as long as possible between nodes + + Various strategies are possible for how to + merge graph edges into lines. + This implementation uses the approach + of having output lines run contiguously from node to node. + For rings a node point is chosen arbitrarily. + + Another possible strategy would be to preserve input linework + as far as possible (i.e.any sections of input lines which are not + coincident with other linework would be preserved). + + It would also be possible to output LinearRings, + if the input is a LinearRing and is unchanged. + This will require additional info from the input linework. + + Martin Davis + + + + Indicates whether intersections are allowed to produce + heterogeneous results including proper boundary touches. + This does not control inclusion of touches along collapses.
+ True provides the original JTS semantics. +
+
+ + + Allow lines created by area topology collapses + to appear in the result.
+ True provides the original JTS semantics. +
+
+ + + Creates a builder for linear elements which may be present + in the overlay result. + + The input geometries + The topology graph + true if an area has been generated for the result + The overlay operation code + The output geometry factory + + + + Checks if the topology indicated by an edge label + determines that this edge should be part of a result line. + + Note that the logic here relies on the semantic + that for intersection lines are only returned if + there is no result area components. + + The label for an edge + true if the edge should be included in the result + + + + Determines the effective location for a line, + for the purpose of overlay operation evaluation. + Line edges and Collapses are reported as INTERIOR + so they may be included in the result + if warranted by the effect of the operation on the two edges. + (For instance, the intersection of a line edge and a collapsed boundary + is included in the result). + + The label of line + The index of parent geometry + The effective location of the line + + + + Adds lines which form rings (i.e. have only degree-2 vertices). + + + + + Traverses edges from edgeStart which + lie in a single line (have degree = 2). + + The direction of the linework is preserved as far as possible. + Specifically, the direction of the line is determined + by the start edge direction. This implies + that if all edges are reversed, the created line + will be reversed to match. + This ensures the orientation of linework is faithful to the input + in the case of polygon-line overlay. + However, this does not provide a consistent orientation + in the case of line-line intersection(where A and B might have different orientations). + (Other more complex strategies would be possible. + E.g. using the direction of the majority of segments, + or preferring the direction of the A edges.) + + + + + Finds the next edge around a node which forms + part of a result line. + + A line edge originating at the node to be scanned + The next line edge, or null if there is none + + + + + Computes the degree of the line edges incident on a node + + Node to compute degree for + Degree of the node line edges + + + + Limits the segments in a list of segments + to those which intersect an envelope. + This creates zero or more sections of the input segment sequences, + containing only line segments which intersect the limit envelope. + Segments are not clipped, since that can move + line segments enough to alter topology, + and it happens in the overlay in any case. + This can substantially reduce the number of vertices which need to be + processed during overlay. + + This optimization is only applicable to Line geometries, + since it does not maintain the closed topology of rings. + Polygonal geometries are optimized using the . + + + Martin Davis + + + + Creates a new limiter for a given envelope. + + The envelope to limit to + + + + Limits a list of segments. + + The segment sequence to limit + The sections which intersect the limit envelope + + + + Traverses the star of edges originating at a node + and links consecutive result edges together + into maximal edge rings. + To link two edges the resultNextMax pointer + for an incoming result edge + is set to the next outgoing result edge. + + Edges are linked when: + + they belong to an area (i.e.they have sides) + they are marked as being in the result + + + Edges are linked in CCW order + (which is the order they are linked in the underlying graph). + This means that rings have their face on the Right + (in other words, + the topological location of the face is given by the RHS label of the DirectedEdge). + This produces rings with CW orientation. + + PRECONDITIONS:
+ - This edge is in the result
+ - This edge is not yet linked
+ - The edge and its sym are NOT both marked as being in the result +
+
+ + + Links the edges of a around this node + into minimal edge rings (s). + Minimal ring edges are linked in the opposite orientation (CW) + to the maximal ring. + This changes self-touching rings into a two or more separate rings, + as per the OGC SFS polygon topology semantics. + This relinking must be done to each max ring separately, + rather than all the node result edges, since there may be + more than one max ring incident at the node. + + The maximal ring to link + An edge originating at this node + + + + Tests if an edge of the maximal edge ring is already linked into + a minimal . If so, this node has already been processed + earlier in the maximal edgering linking scan. + + An edge of a maximal edgering + The maximal edgering + true if the edge has already been linked into a minimal edgering. + + + + Creates a single OverlayEdge. + + + + + A new edge based on the given coordinates and direction. + + + + Gets a which sorts by the origin Coordinates. + + + + + true indicates direction is forward along segString
+ false is reverse direction
+ The label must be interpreted accordingly. +
+
+ + + Adds the coordinates of this edge to the given list, + in the direction of the edge. + Duplicate coordinates are removed + (which means that this is safe to use for a path + of connected edges in the topology graph). + + The coordinate list to add to + + + + ets the symmetric pair edge of this edge. + + The symmetric pair edge + + + + Gets the next edge CCW around the origin of this edge, + with the same origin.
+ If the origin vertex has degree 1 then this is the edge itself. +
+ + The next edge around the origin + +
+ + + Gets or sets a link to next edge in the result ring. + The origin of the edge is the dest of this edge. + + + + + Tests whether this ring is a hole. + + true if this ring is a hole + + + + Tests whether this ring has a shell assigned to it. + + true if the ring has a shell + + + + Gets or sets a value indicating the shell for this ring.
+ The shell is the ring itself if it is not a hole, otherwise its parent shell. +
+
+ + + Computes the list of coordinates which are contained in this ring. + The coordinates are computed once only and cached. + + An array of the s in this ring + + + + Finds the innermost enclosing shell OverlayEdgeRing + containing this OverlayEdgeRing, if any. + The innermost enclosing ring is the smallest enclosing ring. + The algorithm used depends on the fact that: +
+ ring A contains ring B if envelope(ring A) contains envelope(ring B) +
+ This routine is only safe to use if the chosen point of the hole + is known to be properly contained in a shell + (which is guaranteed to be the case if the hole does not touch its shell) + + To improve performance of this function the caller should + make the passed shellList as small as possible (e.g. + by using a spatial index filter beforehand). +
+ The containing EdgeRing, if there is one + or null if no containing EdgeRing is found + +
+ + + Computes the formed by this ring and any contained holes. + + The formed by this ring and its holes. + + + + A planar graph of edges, representing + the topology resulting from an overlay operation. + Each source edge is represented + by a pair of s, + with opposite(symmetric) orientation. + The pair of OverlayEdges share the edge coordinates + and a single . + + Martin Davis + + + + Gets the set of edges in this graph. + Only one of each symmetric pair of OverlayEdges is included. + The opposing edge can be found by using . + + The collection of representative edges in this graph + + + + Gets the collection of edges representing the nodes in this graph. + For each star of edges originating at a node + a single representative edge is included.
+ The other edges around the node can be found by following the next and prev links. +
+ The collection of representative node edges +
+ + + Gets an edge originating at the given node point. + + The node coordinate to query + An edge originating at the point, or null if none exists + + + + Gets the representative edges marked as being in the result area. + + The result area edges + + + + Adds an edge between the coordinates orig and dest + to this graph.
+ Only valid edges can be added (in particular, zero-length segments cannot be added) +
+ The edge to add. + The edge topology information + The created graph edge with same orientation as the linework +
+ + + Inserts a single half-edge into the graph. + The sym edge must also be inserted. + + The half-edge to insert + + + + A structure recording the topological situation + for an edge in a topology graph + used during overlay processing. + + + A label contains the topological for + one or two input geometries to an overlay operation. + An input geometry may be either a Line or an Area. + The label locations for each input geometry are populated + with the + for the edge s + when they are created or once they are computed by topological evaluation. + A label also records the(effective) dimension of each input geometry. + For area edges the role(shell or hole) + of the originating ring is recorded, to allow + determination of edge handling in collapse cases. + + In an + a single label is shared between + the two oppositely-oriented s + of a symmetric pair. + Accessors for orientation-sensitive information + are parameterized by the orientation of the containing edge. + + For each input geometry (0 and 1), the label records + that an edge is in one of the following states + (identified by thedim field). + Each state has additional information about the edge topology. + + A Boundary edge of an Area (polygon) + + dim = DIM_BOUNDARY + locLeft, locRight : the locations of the edge sides for the Area + locLine : INTERIOR + isHole : whether the edge is in a shell or a hole (the ring role) + + + + A Collapsed edge of an input Area + (formed by merging two or more parent edges) + + dim = DIM_COLLAPSE + locLine : the location of the edge relative to the effective input Area + (a collapsed spike is EXTERIOR, a collapsed gore or hole is INTERIOR) + isHole : true if all parent edges are in holes; + false if some parent edge is in a shell + + + + A Line edge from an input line + + dim = DIM_LINE + locLine : the location of the edge relative to the Line. + Initialized to LOC_UNKNOWN to simplify logic. + + + An edge which is Not Part of an input geometry + (and thus must be part of the other geometry). + + dim = NOT_PART + + + + Note that: + + an edge cannot be both a Collapse edge and a Line edge in the same input geometry, + because each input geometry must be homogeneous. + an edge may be an Boundary edge in one input geometry + and a Line or Collapse edge in the other input. + + + Martin Davis + + + + The dimension of an input geometry which is not known. + + + + + The dimension of an edge which is not part of a specified input geometry. + + + + + The dimension of an edge which is a line. + + + + + The dimension for an edge which is part of an input Area geometry boundary. + + + + + The dimension for an edge which is a collapsed part of an input Area geometry boundary. + A collapsed edge represents two or more line segments which have the same endpoints. + They usually are caused by edges in valid polygonal geometries + having their endpoints become identical due to precision reduction. + + + + + Indicates that the location is currently unknown + + + + + Creates a label for an Area edge + + The input index of the parent geometry + The location of the left side of the edge + The location of the right side of the edge + Whether the edge role is a hole or a shell + + + + Creates a label for a Line edge + + The input index of the parent geometry + + + + Creates an uninitialized label + + + + + Creates a label which is a copy of another label. + + The template label + + + + Gets the effective dimension of the given input geometry. + + The input index of the parent geometry + The dimension + + + + + + + + + Initializes the label for an input geometry which is an Area boundary. + + The input index of the parent geometry + The location of the left side of the edge + The location of the right side of the edge + Whether the edge role is a hole or a shell + + + + Initializes the label for an edge which is the collapse of + part of the boundary of an Area input geometry. + + The location of the collapsed edge relative to the + parent area geometry is initially unknown. + It must be determined from the topology of the overlay graph + + The index of the parent input geometry + Whether the dominant edge role is a hole or a shell + + + + Initializes the label for an input geometry which is a Line. + + The index of the parent input geometry + + + + Initializes the label for an edge which is not part of an input geometry. + + The index of the parent input geometry + + + + Sets the line location. +
+ This is used to set the locations for linear edges + encountered during area label propagation. +
+ The index of the input geometry + Location to set +
+ + + Sets the location of all postions for a given input. + + The index of the input geometry + The location to set + + + + Sets the location for a collapsed edge (the Line position) + for an input geometry, + depending on the ring role recorded in the label. + If the input geometry edge is from a shell, + the location is , if it is a hole + it is . + + The index of the input geometry + + + + Tests whether at least one of the sources is a Line. + + true if at least one source is a line + + + + Tests whether a source is a Line. + + The index of the input geometry + true if the input is a Line + + + + Tests whether an edge is linear (a Line or a Collapse) in an input geometry. + + The index of the input geometry + true if the edge is linear + + + + Tests whether the source of a label is known. + + The index of the input geometry + true if the source is known + + + + Tests whether a label is for an edge which is not part + of a given input geometry. + + The index of the input geometry + true if the edge is not part of the geometry + + + + Gets a value indicating if a label is for an edge which is in the boundary of either source geometry. + + true if the label is a boundary for either source + + + + Gets a value indicating if a label is for an edge which is in the boundary of both source geometries. + + true if the label is a boundary for both sources + + + + Tests if the label is a collapsed edge of one area + and is a(non-collapsed) boundary edge of the other area. + + true if the label is for a collapse coincident with a boundary + + + + Tests if a label is for an edge where two + area touch along their boundary. + + true if the edge is a boundary touch + + + + Tests if a label is for an edge which is in the boundary of a source geometry. + Collapses are not reported as being in the boundary. + + The index of the input geometry + true if the label is a boundary for the source + + + + Tests whether a label is for an edge which is a boundary of one geometry + and not part of the other. + + true if the edge is a boundary singleton + + + + Tests if the line location for a source is unknown. + + The index of the input geometry + true if the line location is unknown + + + + Tests if a line edge is inside a source geometry + (i.e.it has location ). + + The index of the input geometry + true if the line is inside the source geometry + + + + Tests if the ring role of an edge is a hole. + + The index of the input geometry + true if the ring role is a hole + + + + Tests if an edge is a Collapse for a source geometry. + + The index of the input geometry + true if the label indicates the edge is a collapse for the source + + + + Tests if a label is a Collapse has location {@link Location#INTERIOR}, + to at least one source geometry. + + true if the label is an Interior Collapse to a source geometry + + + + Tests if a label is a Collapse + and NotPart with location {@link Location#INTERIOR} for the other geometry. + + true if the label is a Collapse and a NotPart with Location Interior + + + + Gets the line location for a source geometry. + + The index of the input geometry + The line location for the source + + + + Tests if a line is in the interior of a source geometry. + + The index of the source geometry + true if the label is a line and is interior + + + + Gets the location for a of an edge of a source + for an edge with given orientation. + + The index of the input geometry + The position to get the location for + true if the orientation of the containing edge is forward + The location of the oriented position in the source + + + + Gets the location for this label for either + a Boundary or a Line edge. + This supports a simple determination of + whether the edge should be included as a result edge. + + The source index + The position for a boundary label + The direction for a boundary label + The location for the specified position + + + + Gets the linear location for the given source. + + The source geometry index + The linear location for the source + + + + Tests whether this label has side position information + for a source geometry. + + The index of the input geometry + true if at least one side position is known + + + + Creates a copy of this label + + A copy of this label + + + + Gets a symbol for the a ring role (Shell or Hole). + + true for a hole, false for a shell + The ring role symbol character + + + + Gets the symbol for the dimension code of an edge. + + The dimension code + The dimension symbol character + + + + Implements the logic to compute the full labeling + for the edges in an . + + Martin Davis + + + + Computes the topological labeling for the edges in the graph. + + + + + Labels edges around nodes based on the arrangement + of incident area boundary edges. + Also propagates the labeling to connected linear edges. + + The nodes to label + + + + Scans around a node CCW, propagating the side labels + for a given area geometry to all edges (and their sym) + with unknown locations for that geometry. + + + The geometry to propagate locations for + + + + Finds a boundary edge for this geom originating at the given + node, if one exists. + A boundary edge should exist if this is a node on the boundary + of the parent area geometry. + + An edge for this node + The parent geometry index + A boundary edge, or null if no boundary edge exists + + + + At this point collapsed edges with unknown location + must be disconnected from the boundary edges of the parent + (because otherwise the location would have + been propagated from them).
+ They can be now located based on their parent ring role(shell or hole). + (This cannot be done earlier, because the location + based on the boundary edges must take precedence.
+ There are situations where a collapsed edge has a location + which is different to its ring role - + e.g.a narrow gore in a polygon, which is in + the interior of the reduced polygon, but whose + ring role would imply the location EXTERIOR.) + + Note that collapsed edges can NOT have location determined via a PIP location check, + because that is done against the unreduced input geometry, + which may give an invalid result due to topology collapse. + + The labeling is propagated to other connected linear edges, + since there may be NOT_PART edges which are connected, + and they can be labeled in the same way. + (These would get labeled anyway during subsequent disconnected labeling pass, + but may be more efficient and accurate to do it here.) +
+
+ + + There can be edges which have unknown location + but are connected to a linear edge with known location. + In this case linear location is propagated to the connected edges. + + + + + Performs a breadth-first graph traversal to find and label + connected linear edges. + + The index of the input geometry to label. + + + + Finds all OverlayEdges which are linear + (i.e.line or collapsed) and have a known location + for the given input geometry. + + The index of the input geometry + A list of linear edges with known location + + + + At this point there may still be edges which have unknown location + relative to an input geometry.
+ This must be because they are NOT_PART edges for that geometry, + and are disconnected from any edges of that geometry. + An example of this is rings of one geometry wholly contained + in another geometry.
+ The location must be fully determined to compute a + correct result for all overlay operations. + + If the input geometry is an Area the edge location can + be determined via a PIP test. + If the input is not an Area the location is EXTERIOR. +
+
+ + + Determines the location of an edge relative to a target input geometry. + The edge has no location information + because it is disconnected from other + edges that would provide that information. + The location is determined by checking + if the edge lies inside the target geometry area(if any). + + The edge to label + The input geometry to label against + + + + Determines the for an edge within an Area geometry + via point-in-polygon location. + + NOTE this is only safe to use for disconnected edges, + since the test is carried out against the original input geometry, + and precision reduction may cause incorrect results for edges + which are close enough to a boundary to become connected. + + The parent geometry index + The edge to locate + The location of the edge. + + + + Determines the {@link Location} for an edge within an Area geometry + via point-in-polygon location, + by checking that both endpoints are interior to the target geometry. + Checking both endpoints ensures correct results in the presence of topology collapse. + + NOTE this is only safe to use for disconnected edges, + since the test is carried out against the original input geometry, + and precision reduction may cause incorrect results for edges + which are close enough to a boundary to become connected. + + The parent geometry index + The edge to locate + The location of the edge + + + + Marks an edge which forms part of the boundary of the result area. + This is determined by the overlay operation being executed, + and the location of the edge. + The relevant location is either the right side of a boundary edge, + or the line location of a non-boundary edge. + + The edge to mark + The overlay operation + + + + Unmarks result area edges where the sym edge + is also marked as in the result. + This has the effect of merging edge-adjacent result areas, + as required by polygon validity rules. + + + + + Computes an overlay where one input is Point(s) and one is not. + This class supports overlay being used as an efficient way + to find points within or outside a polygon. + + Input semantics are: + + Duplicates are removed from Point output + Non-point output is rounded and noded using the given precision model + + Output semantics are: + + An empty result is an empty atomic geometry + with dimension determined by the inputs and the operation as per overlay semantics + + + For efficiency the following optimizations are used: + + Input points are not included in the noding of the non-point input geometry + (in particular, they do not participate in snap-rounding if that is used). + If the non-point input geometry is not included in the output + it is not rounded and noded.This means that points + are compared to the non-rounded geometry. + This will be apparent in the result. + + This means that overlay is efficient to use for finding points + within or outside a polygon. + + Martin Davis + + + + Copy the non-point input geometry if not + already done by precision reduction process. + + A copy of the non-point geometry + + + + Computes the geometric overlay of two s, + using an explicit precision model to allow robust computation. + + The overlay can be used to determine any of the + following set-theoretic operations (boolean combinations) of the geometries: + + all points which lie in both geometries + all points which lie in at least one geometry + all points which lie in the first geometry but not the second + all points which lie in one geometry but not both + + Input geometries may have different dimension. + Input collections must be homogeneous (all elements must have the same dimension). + + The precision model used for the computation can be supplied + independent of the precision model of the input geometry. + The main use for this is to allow using a fixed precision + for geometry with a floating precision model. + This does two things: ensures robust computation; + and forces the output to be validly rounded to the precision model. + + For fixed precision models noding is performed using a . + This provides robust computation(as long as precision is limited to + around 13 decimal digits). + + For floating precision an is used. + This is not fully robust, so can sometimes result in + s being thrown. + For robust full-precision overlay see . + + A custom can be supplied. + This allows using a more performant noding strategy in specific cases, + for instance in . + + Note: If a is used + it is best to specify a fairly small snap tolerance, + since the intersection clipping optimization can + interact with the snapping to alter the result. + + Optionally the overlay computation can process using strict mode + (via = true). + In strict mode result semantics are: + + Lines and Points resulting from topology collapses are not included in the result + Result geometry is homogeneous + for the and operations. + Result geometry is homogeneous + for the and operations + if the inputs have the same dimension + + Strict mode has the following benefits: + + Results are simpler + Overlay operations are easily chainable + without needing to remove lower-dimension elements + + The original JTS overlay semantics corresponds to non-strict mode. + + If a robustness error occurs, a is thrown. + These are usually caused by numerical rounding causing the noding output + to not be fully noded. + For robust computation with full-precision + can be used. + + + + + The code for the Intersection overlay operation. + + + + + The code for the Union overlay operation. + + + + + The code for the Difference overlay operation. + + + + + The code for the Symmetric Difference overlay operation. + + + + + The default setting for Strict Mode. + + The original JTS overlay semantics used non-strict result + semantics, including;
+ - An Intersection result can be mixed-dimension, + due to inclusion of intersection components of all dimensions
+ - Results can include lines caused by Area topology collapse +
+
+ + + Tests whether a point with a given topological + relative to two geometries is contained in + the result of overlaying the geometries using + a given overlay operation. + + The method handles arguments of correctly + + The topological label of the point + The code for the overlay operation to test + true if the label locations correspond to the overlay + + + + Tests whether a point with given s + relative to two geometries would be contained in + the result of overlaying the geometries using + a given overlay operation. + This is used to determine whether components + computed during the overlay process should be + included in the result geometry. + + The method handles arguments of correctly. + + The code for the overlay operation to test + The code for the location in the first geometry + The code for the location in the second geometry + true if a point with given locations is in the result of the overlay operation + + + + Computes an overlay operation for + the given geometry operands, with the + noding strategy determined by the precision model. + + The first geometry argument + The second geometry argument + The code for the desired overlay operation + The precision model to use + The result of the overlay operation + + + + Computes an overlay operation for + the given geometry operands, using a supplied . + + The first geometry argument + The second geometry argument + The code for the desired overlay operation + The precision model to use (which may be null if the noder does not use one) + The noder to use + The result of the overlay operation + + + + Computes an overlay operation on the given geometry operands, + using a supplied . + + The first geometry argument + The second geometry argument + The code for the desired overlay operation + The noder to use + The result of the overlay operation + + + + Computes an overlay operation on + the given geometry operands, + using the precision model of the geometry. + and an appropriate noder. + + The noder is chosen according to the precision model specified. + + For + a snap-rounding noder is used, and the computation is robust. + For + a non-snapping noder is used, + and this computation may not be robust. + If errors occur a is thrown. + + + The first geometry argument + The second geometry argument + The code for the desired overlay operation + The result of the overlay operation + + + + Computes a union operation on + the given geometry, with the supplied precision model. + + The input must be a valid geometry. + Collections must be homogeneous. + + To union an overlapping set of polygons in a more performant way use . + To union a polygonal coverage or linear network in a more performant way, + use . + + The geometry + The precision model to use + The result of the union operation + + + + + Computes a union of a single geometry using a custom noder. + + The primary use of this is to support coverage union. + Because of this the overlay is performed using strict mode. + + The geometry to union + The precision model to use (maybe be null) + The noder to use + the result geometry + + + + + Creates an overlay operation on the given geometries, + with a defined precision model. + + The A operand geometry + The B operand geometry (may be null) + The precision model to use + The overlay opcode + + + + Creates an overlay operation on the given geometries + using the precision model of the geometries. + + The noder is chosen according to the precision model specified. + + For + a snap - rounding noder is used, and the computation is robust. + For a non - snapping noder is used, + and this computation may not be robust. + If errors occur a is thrown. + + + The A operand geometry + The B operand geometry (may be null) + The overlay opcode + + + + Creates a union of a single geometry with a given precision model. + + The geometry + The precision model to use + + + + Gets or sets whether the overlay results are computed according to strict mode + semantics. + + Lines resulting from topology collapse are not included + Result geometry is homogeneous for the + and + operations. + Result geometry is homogeneous for the + and + operations if the inputs have the same dimension + + + + + + + Gets or sets a value indicating whether overlay processing optimizations are enabled. + + It may be useful to disable optimizations + for testing purposes. + + Default is true (optimization enabled). + + + + + Gets or sets whether the result can contain only components. + This is used if it is known that the result must be an (possibly empty) area. + + true if the result should contain only area components + + + + Gets the result of the overlay operation. + e + The result of the overlay operation. + Thrown, if the input is not supported (e.g. a mixed-dimension geometry) + Thrown, if a robustness error occurs + + + + Extracts the result geometry components from the fully labelled topology graph. + + This method implements the semantic that the result of an + intersection operation is homogeneous with highest dimension. + In other words, + if an intersection has components of a given dimension + no lower-dimension components are output. + For example, if two polygons intersect in an area, + no linestrings or points are included in the result, + even if portions of the input do meet in lines or points. + This semantic choice makes more sense for typical usage, + in which only the highest dimension components are of interest. + + The overlay operation + The topology graph + The result geometry + + + + Performs an overlay operation using , + increasing robustness by using a series of + increasingly robust (but slower) noding strategies. + + The noding strategies used are: + + A simple fast noder using precision + A using an automatically-determined snap tolerance + First snapping each geometry to itself, and then overlaying them wih a + The above two strategies are repeated with increasing snap tolerance, up to a limit + Finally a is used with a automatically-determined scale factor. + + If all of the above heuristics fail to compute a valid overlay, + the original is thrown. + In practice this should be extremely unlikely to occur. + + This algorithm relies on each overlay operation execution + throwing a if it is unable + to compute the overlay correctly. + Generally this occurs because the noding phase does + not produce a valid noding. + This requires the use of a + in order to check the results of using a floating noder. + + Martin Davis + + + + Computes the unary union of a geometry using robust computation. + + The geometry to union + The union result + + + + Computes the unary union of a collection of geometries using robust computation. + + An enumeration of geometries to union + The union result + + + + Computes the unary union of a collection of geometries using robust computation. + + An enumeration of geometries to union + The geometry factory to use + The union of the geometries + + + + Overlay two geometries, using heuristics to ensure + computation completes correctly. + In practice the heuristics are observed to be fully correct. + + A geometry + A geometry + The overlay operation code + The overlay result geometry + + + + Attempt overlay using snapping with repeated tries with increasing snap tolerances. + + + + + The computed overlay result, or null if the overlay fails + + + + Attempt overlay using a . + + + + + + The computed overlay result, or null if the overlay fails + + + + Attempt overlay with first snapping each geometry individually. + + + + + + The computed overlay result, or null if the overlay fails + + + + Self-snaps a geometry by running a union operation with it as the only input. + This helps to remove narrow spike/gore artifacts to simplify the geometry, + which improves robustness. + Collapsed artifacts are removed from the result to allow using + it in further overlay operations. + + Geometry to self-snap + Snap tolerance + The snapped geometry (homogenous) + + + + A factor for a snapping tolerance distance which + should allow noding to be computed robustly. + + + + + Computes a heuristic snap tolerance distance + for overlaying a pair of geometries using a . + + + + + + + + Computes the largest magnitude of the ordinates of a geometry, + based on the geometry envelope. + + + The magnitude of the largest ordinate + + + + Attempt Overlay using Snap-Rounding with an automatically-determined + scale factor. + + + + + the computed overlay result, or null if the overlay fails + + + + Performs an overlay operation on inputs which are both point geometries. + + Semantics are: + + Points are rounded to the precision model if provided + Points with identical XY values are merged to a single point + Extended ordinate values are preserved in the output, apart from merging + An empty result is returned as POINT EMPTY + + + Martin Davis + + + + Performs an overlay operation on inputs which are both point geometries. + + The code for the desired overlay operation + The first geometry argument + The second geometry argument + The precision model to use + The result of the overlay operation + + + + Creates an instance of an overlay operation on inputs which are both point geometries. + + The code for the desired overlay operation + The first geometry argument + The second geometry argument + The precision model to use + + + + Gets the result of the overlay. + + + + + Round the key point if precision model is fixed. + Note: return value is only copied if rounding is performed. + + + + + Utility methods for overlay processing. + + Martin Davis + + + + A null-handling wrapper for + + A precision model + true if the provided precision model is floating + + + + Computes a clipping envelope for overlay input geometries. + The clipping envelope encloses all geometry line segments which + might participate in the overlay, with a buffer to + account for numerical precision + (in particular, rounding due to a precision model. + The clipping envelope is used in both the + and in the . + + Some overlay operations (i.e. and ) + cannot use clipping as an optimization, + since the result envelope is the full extent of the two input geometries. + In this case the returned + envelope is null to indicate this. + + The overlay op code + The input geometries + The precision model being used + An envelope for clipping and line limiting, or null if no clipping is performed + + + + Computes an envelope which covers the extent of the result of + a given overlay operation for given inputs. + The operations which have a result envelope smaller than the extent of the inputs + are: + + + result envelope is the intersection of the input envelopes + + result envelope is the envelope of the A input geometry + + Otherwise, null is returned to indicate full extent. + + The overlay op code + The input geometries + The precision model being used + The result envelope, or null if the full extent + + + + Determines a safe geometry envelope for clipping, + taking into account the precision model being used. + + A safe geometry envelope for clipping + The precision model + A safe envelope to use for clipping + + + + Tests if the result can be determined to be empty + based on simple properties of the input geometries + (such as whether one or both are empty, + or their envelopes are disjoint). + + The overlay operation + The A operand geometry + The B operand geometry + The precision model to use + true if the overlay result is determined to be empty + + + + Tests if the geometry envelopes are disjoint, or empty. + The disjoint test must take into account the precision model + being used, since geometry coordinates may shift under rounding. + + The A operand geometry + The B operand geometry + The precision model to use + true if the geometry envelopes are disjoint or empty + + + + Tests for disjoint envelopes adjusting for rounding + caused by a fixed precision model. + Assumes envelopes are non-empty. + + The A operand envelope + The B operand envelope + The precision model to use + true if the envelopes are disjoint + + + + Creates an empty result geometry of the appropriate dimension, + based on the given overlay operation and the dimensions of the inputs. + The created geometry is an atomic geometry, + not a collection(unless the dimension is , + in which case a GEOMETRYCOLLECTION EMPTY is created. + + The dimension of the empty geometry + The geometry factory being used for the operation + An empty atomic geometry of the appropriate dimension + + + + Computes the dimension of the result of + applying the given operation to inputs + with the given dimensions. + This assumes that complete collapse does not occur. + + The result dimension is computed using the following rules: + + result has the dimension of the lowest input dimension + result has the dimension of the highest input dimension + result has the dimension of the left-hand input + result has the dimension of the highest input dimension + (since the Symmetric Difference is the Union of the Differences). + + + The overlay operation + Dimension of the LH input + Dimension of the RH input + + + + + Creates an overlay result geometry for homogeneous or mixed components. + + An enumeration of result polygons (may be empty or null) + An enumeration of result lines (may be empty or null) + An enumeration of result points (may be empty or null) + The geometry factory to use. + A geometry structured according to the overlay result semantics + + + + Round the key point if precision model is fixed. + Note: return value is only copied if rounding is performed. + + The point to round + The precision model to use + The rounded point coordinate, or null if empty + + + + A heuristic check for overlay result correctness + comparing the areas of the input and result. + The heuristic is necessarily coarse, but it detects some obvious issues.
+ (e.g. ) + + Note: - this check is only safe if the precision model is floating. + It should also be safe for snapping noding if the distance tolerance is reasonably small. + (Fixed precision models can lead to collapse causing result area to expand.) +
+ Input geometry 0 + Input geometry 1 + The overlay opcode + The overlay result + true if the result area is consistent +
+ + + For all OverlayEdges in result, form them into MaximalEdgeRings + + + + + Finds the single shell, if any, out of + a list of minimal rings derived from a maximal ring. + The other possibility is that they are a set of (connected) holes, + in which case no shell will be found. + + The shell ring, if there is one + or null, if all rings are holes + + + + + For the set of minimal rings comprising a maximal ring, + assigns the holes to the shell known to contain them. + Assigning the holes directly to the shell serves two purposes: + + it is faster than using a point-in-polygon check later on. + it ensures correctness, since if the PIP test was used the point + chosen might lie on the shell, which might return an incorrect result from the + PIP test + + + + + + Place holes have not yet been assigned to a shell. + These "free" holes should + all be properly contained in their parent shells, so it is safe to use the + findEdgeRingContaining method. + (This is the case because any holes which are NOT + properly contained (i.e. are connected to their + parent shell) would have formed part of a MaximalEdgeRing + and been handled in a previous step). + + If a hole cannot be assigned to a shell + + + + Functions to reduce the precision of a geometry + by rounding it to a given precision model. + + This class handles only polygonal and linear inputs. + For full functionality . + + + Martin Davis + + + + Reduces the precision of a geometry by rounding and snapping it to the + supplied .
+ The input geometry must be polygonal or linear. + + The output is always a valid geometry. This implies that input components + may be merged if they are closer than the grid precision. + if merging is not desired, then the individual geometry components + should be processed separately. + + The output is fully noded (i.e. coincident lines are merged and noded). + This provides an effective way to node / snap-round a collection of s. +
+ The geometry to reduce + The precision model to use + The precision-reduced geometry +
+ + + Functions for computing precision model scale factors + that ensure robust geometry operations. + In particular, these can be used to + automatically determine appropriate scale factors for operations + using limited-precision noding (such as ). + + WARNING: the inherentScale and robustScale + functions can be very slow, due to the method used to determine + number of decimal places of a number. + These are not recommended for production use. + + Martin Davis + + + + A number of digits of precision which leaves some computational "headroom" + to ensure robust evaluation of certain double-precision floating point geometric operations. + + This value should be less than the maximum decimal precision of double-precision values (16). + + + + + Computes a safe scale factor for a numeric value. + A safe scale factor ensures that rounded + number has no more than + digits of precision. + + A numeric value. + A safe scale factor for the value + + + + Computes a safe scale factor for a geometry. + A safe scale factor ensures that rounded + number has no more than + digits of precision. + + A geometry. + A safe scale factor for the geometry ordinates + + + + Computes a safe scale factor for two geometry. + A safe scale factor ensures that rounded + number has no more than + digits of precision. + + A geometry. + A geometry (which may be null). + A safe scale factor for the geometry ordinates + + + + Determines the maximum magnitude (absolute value) of the bounds of an + of an envelope. + This is equal to the largest ordinate value + which must be accommodated by a scale factor. + + An envelope + The value of the maximum bound magnitude + + + + Computes the scale factor which will + produce a given number of digits of precision(significant digits) + when used to round the given number. + + For example: to provide 5 decimal digits of precision + for the number 123.456 the precision scale factor is 100; + for 3 digits of precision the scale factor is 1; + for 2 digits of precision the scale factor is 0.1. + + Rounding to the scale factor can be performed with + + A number to be rounded + The number of digits of precision required + The scale factor which provides the required number of digits of precision + + + + + Computes the inherent scale of a number. + The inherent scale is the scale factor for rounding + which preserves all digits of precision + (significant digits) + present in the numeric value. + In other words, it is the scale factor which does not + change the numeric value when rounded: + + num = round( num, inherentScale(num) ) + + + A number + The inherent scale factor of the number + + + + Computes the inherent scale of a geometry. + The inherent scale is the scale factor for rounding + which preserves all digits of precision + (significant digits) + present in the geometry ordinates. + + This is the maximum inherent scale + of all ordinate values in the geometry. + + WARNING: this is very slow. + + A geometry + The inherent scale factor in the geometry's ordinates + + + + Computes the inherent scale of two geometries. + The inherent scale is the scale factor for rounding + which preserves all digits of precision + (significant digits) + present in the geometry ordinates. + + This is the maximum inherent scale + of all ordinate values in the geometries. + + A geometry + A geomety (which may be null) + The inherent scale factor in the geometries' ordinates + + + + Determines the + number of decimal places represented in a double-precision + number (as determined by .NET). + This uses the .NET double-precision print routine + to determine the number of decimal places, + This is likely not optimal for performance, + but should be accurate and portable. + + A numeric value + The number of decimal places in the value + + + + Applies the inherent scale calculation + to every ordinate in a geometry. + + WARNING: this is very slow. + + Martin Davis + + + + Determines a precision model to + use for robust overlay operations for one geometry. + The precision scale factor is chosen to maximize + output precision while avoiding round-off issues. + + NOTE: this is a heuristic determination, so is not guaranteed to + eliminate precision issues. + + WARNING: this is very slow. + + A geometry + A suitable precision model for overlay + + + + Determines a scale factor which maximizes + the digits of precision and is + safe to use for overlay operations. + The robust scale is the minimum of the + inherent scale and the safe scale factors. + + WARNING: this is very slow. + + A geometry + A geometry + A scale factor for use in overlay operations + + + + Determines a scale factor which maximizes + the digits of precision and is + safe to use for overlay operations. + The robust scale is the minimum of the + inherent scale and the safe scale factors. + + A geometry + A scale factor for use in overlay operations + + + + Clips a ring of points to an rectangle. + Uses a variant of Cohen-Sutherland clipping. + + In general the output is not topologically valid. + In particular, the output may contain coincident non-noded line segments + along the clip rectangle sides. + However, the output is sufficiently well-structured + that it can be used as input to the algorithm + (which is able to process coincident linework due + to the need to handle topology collapse under precision reduction). + + Because of the likelihood of creating + extraneous line segments along the clipping rectangle sides, + this class is not suitable for clipping linestrings. + + The clipping envelope should be generated using , + to ensure that intersecting line segments are not perturbed + by clipping. + This is required to ensure that the overlay of the + clipped geometry is robust and correct (i.e. the same as + if clipping was not used). + + + Martin Davis + + + + Creates a new clipper for the given envelope. + + The clipping envelope + + + + Clips a list of points to the clipping rectangle box. + + The points of the ring + The points of the clipped ring + + + + Clips line to the axis-parallel line defined by a single box edge. + + The coordinates + An edge index + A flag indicating whether to close the ring. + The clipped coordinates + + + + Computes the intersection point of a segment + with an edge of the clip box. + The segment must be known to intersect the edge. + + First endpoint of the segment + Second endpoint of the segment + Index of box edge + + The intersection point with the box edge + + + + + Computes a robust clipping envelope for a pair of polygonal geometries. + The envelope is computed to be large enough to include the full + length of all geometry line segments which intersect + a given target envelope. + This ensures that line segments which might intersect are + not perturbed when clipped using . + + Martin Davis + + + + Adds a polygon ring to the graph. Empty rings are ignored. + + + + + Unions a collection of geometries in an + efficient way, using + to ensure robust computation. + + This class is most useful for performing UnaryUnion using + a fixed-precision model.
+ For unary union using floating precision, + should be used. +
+ Martin Davis +
+ + + Unions a geometry (which is often a collection) + using a given precision model. + + The geometry to union + The precision model to use + The union of the geometry + + + + + Unions a geometry (which is often a collection) + using a given precision model. + + The geometries to union + The precision model to use + The union of the geometries + + + + + Unions a geometry (which is often a collection) + using a given precision model. + + The geometries to union + The geometry factory to use + The precision model to use + The union of the geometries + + + + + Nodes a set of edges. + Takes one or more sets of edges and constructs a + new set of edges consisting of all the split edges created by + noding the input edges together. + + + + + + + + + + + + + + + + + + + + + + Forms NTS LineStrings out of a the graph of DirectedEdges + created by an OverlayOp. + + + + + + + + + + + + + + + + + A list of the LineStrings in the result of the specified overlay operation. + + + + + Find and mark L edges which are "covered" by the result area (if any). + L edges at nodes which also have A edges can be checked by checking + their depth at that node. + L edges at nodes which do not have A edges can be checked by doing a + point-in-polygon test with the previously computed result areas. + + + + + + + + + + + + + + + + + + + Collect edges from Area inputs which should be in the result but + which have not been included in a result area. + This happens ONLY: + during an intersection when the boundaries of two + areas touch in a line segment + OR as a result of a dimensional collapse. + + + + + + + + + + + + + + + + + + + + Label an isolated node with its relationship to the target point. + + + + + + + A ring of edges which may contain nodes of degree > 2. + A MaximalEdgeRing may represent two different spatial entities: + a single polygon possibly containing inversions (if the ring is oriented CW) + a single hole possibly containing exversions (if the ring is oriented CCW) + If the MaximalEdgeRing represents a polygon, + the interior of the polygon is strongly connected. + These are the form of rings used to define polygons under some spatial data models. + However, under the OGC SFS model, MinimalEdgeRings are required. + A MaximalEdgeRing can be converted to a list of MinimalEdgeRings using the + BuildMinimalRings() method. + + + + + + + + + + + + + + + + + + + + + + + + + + For all nodes in this EdgeRing, + link the DirectedEdges at the node to form minimalEdgeRings + + + + + + + + + + + A ring of edges with the property that no node + has degree greater than 2. These are the form of rings required + to represent polygons under the OGC SFS spatial data model. + + + + + + + + + + + + + + + + + + + + + + + + + + Creates nodes for use in the PlanarGraphs constructed during + overlay operations. + + + + + + + + + + + + The spatial functions supported by this class. + These operations implement various bool combinations of the resultants of the overlay. + + + + + The code for the Intersection overlay operation + + + + + The code for the Union overlay operation + + + + + The code for the Difference overlay operation + + + + + The code for the Symmetric Difference overlay operation + + + + + Computes the geometric overlay of two s. The overlay + can be used to determine any bool combination of the geometries. + + + + + Disable + when an intersection is made (), + so performances are dramatically improved but failures are not managed. + + + Use ay your own risk! + + + + + Computes an overlay operation + for the given geometry arguments. + + The first geometry argument + The second geometry argument + The code for the desired overlay operation + The result of the overlay operation + Thrown if a robustness problem is encountered. + + + + Tests whether a point with a given topological + relative to two geometries is contained in + the result of overlaying the geometries using + a given overlay operation. + + The method handles arguments of correctly + + The topological label of the point + The code for the overlay operation to test + true if the label locations correspond to the overlayOpCode + + + + Tests whether a point with given s + relative to two geometries is contained in + the result of overlaying the geometries using + a given overlay operation. + + The method handles arguments of correctly + + the code for the location in the first geometry + the code for the location in the second geometry + the code for the overlay operation to test + true if the locations correspond to the overlayOpCode. + + + + Constructs an instance to compute a single overlay operation + for the given geometries. + + The first geometry argument + The second geometry argument + + + + Gets the result of the overlay for a given overlay operation. + + Note: this method can be called once only. + + The code of the overlay operation to perform + The computed result geometry + Thrown if a robustness problem is encountered + + + + Gets the graph constructed to compute the overlay. + + + + + Insert an edge from one of the noded input graphs. + Checks edges that are inserted to see if an + identical edge already exists. + If so, the edge is not inserted, but its label is merged + with the existing edge. + + The edge to insert + + + + Update the labels for edges according to their depths. + For each edge, the depths are first normalized. + Then, if the depths for the edge are equal, + this edge must have collapsed into a line edge. + If the depths are not equal, update the label + with the locations corresponding to the depths + (i.e. a depth of 0 corresponds to a Location of Exterior, + a depth of 1 corresponds to Interior) + + + + + If edges which have undergone dimensional collapse are found, + replace them with a new edge which is a L edge + + + + + Copy all nodes from an arg point into this graph. + The node label in the arg point overrides any previously computed + label for that argIndex. + (E.g. a node may be an intersection node with + a previously computed label of Boundary, + but in the original arg Geometry it is actually + in the interior due to the Boundary Determination Rule) + + + + + + Compute initial labelling for all DirectedEdges at each node. + In this step, DirectedEdges will acquire a complete labelling + (i.e. one with labels for both Geometries) + only if they + are incident on a node which has edges for both Geometries + + + + + For nodes which have edges from only one Geometry incident on them, + the previous step will have left their dirEdges with no labelling for the other + Geometry. However, the sym dirEdge may have a labelling for the other + Geometry, so merge the two labels. + + + + + Incomplete nodes are nodes whose labels are incomplete. + (e.g. the location for one Geometry is null). + These are either isolated nodes, + or nodes which have edges from only a single Geometry incident on them. + Isolated nodes are found because nodes in one graph which don't intersect + nodes in the other are not completely labelled by the initial process + of adding nodes to the nodeList. + To complete the labelling we need to check for nodes that lie in the + interior of edges, and in the interior of areas. + When each node labelling is completed, the labelling of the incident + edges is updated, to complete their labelling as well. + + + + + Label an isolated node with its relationship to the target point. + + + + + Find all edges whose label indicates that they are in the result area(s), + according to the operation being performed. Since we want polygon shells to be + oriented CW, choose dirEdges with the interior of the result on the RHS. + Mark them as being in the result. + Interior Area edges are the result of dimensional collapses. + They do not form part of the result area boundary. + + + + + If both a dirEdge and its sym are marked as being in the result, cancel + them out. + + + + + Tests if a point node should be included in the result or not. + + The point coordinate + true if the coordinate point is covered by a result Line or Area geometry. + + + + Tests if an L edge should be included in the result or not. + + The point coordinate + true if the coordinate point is covered by a result Area geometry. + + + + true if the coord is located in the interior or boundary of + a point in the list. + + + + + Creates an empty result geometry of the appropriate dimension, + based on the given overlay operation and the dimensions of the inputs. + The created geometry is always an atomic geometry, + not a collection. + + The empty result is constructed using the following rules: + + - result has the dimension of the lowest input dimension + - result has the dimension of the highest input dimension + - result has the dimension of the left-hand input + - result has the dimension of the highest input dimension + (since symDifference is the union of the differences). + + + The overlay operation being performed + An input geometry + An input geometry + The geometry factory being used for the operation + An empty atomic geometry of the appropriate dimension + + + + Constructs Points from the nodes of an overlay graph. + + + + + Creates an instance of this class + + The operation + The geometry factory + + + + Computes the Point geometries which will appear in the result, + given the specified overlay operation. + + The spatial function + + A list of the Points in the result. + + + + + Determines nodes which are in the result, and creates s for them. + + + This method determines nodes which are candidates for the result via their + labelling and their graph topology. + + The overlay operation + + + + Converts non-covered nodes to Point objects and adds them to the result. + + + A node is covered if it is contained in another element Geometry + with higher dimension (e.g. a node point might be contained in a polygon, + in which case the point can be eliminated from the result). + + The node to test + + + + Forms Polygons out of a graph of {DirectedEdge}s. + The edges to use are marked as being in the result Area. + + + + + + + + + + + Add a complete graph. + The graph is assumed to contain one or more polygons, + possibly with holes. + + + + + + Add a set of edges and nodes, which form a graph. + The graph is assumed to contain one or more polygons, + possibly with holes. + + + + + + + + + + + + For all DirectedEdges in result, form them into MaximalEdgeRings. + + + + + + + + + + + + + + + + This method takes a list of MinimalEdgeRings derived from a MaximalEdgeRing, + and tests whether they form a Polygon. This is the case if there is a single shell + in the list. In this case the shell is returned. + The other possibility is that they are a series of connected holes, in which case + no shell is returned. + + The shell EdgeRing, if there is one
or + null, if all the rings are holes.
+
+ + + This method assigns the holes for a Polygon (formed from a list of + MinimalEdgeRings) to its shell. + Determining the holes for a MinimalEdgeRing polygon serves two purposes: + it is faster than using a point-in-polygon check later on. + it ensures correctness, since if the PIP test was used the point + chosen might lie on the shell, which might return an incorrect result from the + PIP test. + + + + + + + For all rings in the input list, + determine whether the ring is a shell or a hole + and add it to the appropriate list. + Due to the way the DirectedEdges were linked, + a ring is a shell if it is oriented CW, a hole otherwise. + + + + + + + + This method determines finds a containing shell for all holes + which have not yet been assigned to a shell. + These "free" holes should + all be properly contained in their parent shells, so it is safe to use the + findEdgeRingContaining method. + (This is the case because any holes which are NOT + properly contained (i.e. are connected to their + parent shell) would have formed part of a MaximalEdgeRing + and been handled in a previous step). + + + + + + + Find the innermost enclosing shell EdgeRing containing the argument EdgeRing, if any. + The innermost enclosing ring is the smallest enclosing ring. + The algorithm used depends on the fact that: + ring A contains ring B if envelope(ring A) contains envelope(ring B). + This routine is only safe to use if the chosen point of the hole + is known to be properly contained in a shell + (which is guaranteed to be the case if the hole does not touch its shell). + + + + Containing EdgeRing, if there is one
or + null if no containing EdgeRing is found.
+
+ + + + + + + + + + Snaps the vertices and segments of a + to another Geometry's vertices. + A snap distance tolerance is used to control where snapping is performed. + Snapping one geometry to another can improve + robustness for overlay operations by eliminating + nearly-coincident edges + (which cause problems during noding and intersection calculation). + It can also be used to eliminate artifacts such as narrow slivers, spikes and gores. + Too much snapping can result in invalid topology + beging created, so the number and location of snapped vertices + is decided using heuristics to determine when it + is safe to snap. + This can result in some potential snaps being omitted, however. + + Martin Davis + + + + Estimates the snap tolerance for a Geometry, taking into account its precision model. + + + The estimated snap tolerance + + + + + + + + + + + + + + + + + + + Snaps two geometries together with a given tolerance. + + + + + + + + + Snaps a geometry to itself. + Allows optionally cleaning the result to ensure it is topologically valid + (which fixes issues such as topology collapses in polygonal inputs). + Snapping a geometry to itself can remove artifacts such as very narrow slivers, gores and spikes. + + the geometry to snap + the snapping tolerance + whether the result should be made valid + a new snapped + + + + Creates a new snapper acting on the given geometry + + the geometry to snap + + + + Snaps the vertices in the component s + of the source geometry to the vertices of the given snap geometry. + + a geometry to snap the source to + + a new snapped Geometry + + + Snaps the vertices in the component s + of the source geometry to the vertices of the same geometry. + Allows optionally cleaning the result to ensure it is topologically valid + (which fixes issues such as topology collapses in polygonal inputs). + The snapping tolerance + Whether the result should be made valid + The geometry snapped to itself + + + + + + + + + + + Computes the snap tolerance based on the input geometries. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Snaps the vertices and segments of a + to a set of target snap vertices. + A snap distance tolerance is used to control where snapping is performed. + The implementation handles empty geometry and empty snap vertex sets. + + + + + Creates a new snapper using the points in the given + as target snap points. + + A LineString to snap (may be empty) + the snap tolerance to use + + + + Creates a new snapper using the given points + as source points to be snapped. + + + + + + + Snaps the vertices and segments of the source LineString + to the given set of snap points. + + the vertices to snap to + list of the snapped points + + + + Snap source vertices to vertices in the target. + + the points to snap + the points to snap to + + + + + + + + + + + + Snap segments of the source to nearby snap vertices. + Source segments are "cracked" at a snap vertex. + A single input segment may be snapped several times + to different snap vertices. + For each distinct snap vertex, at most one source segment + is snapped to. This prevents "cracking" multiple segments + at the same point, which would likely cause + topology collapse when being used on polygonal linework. + + The coordinates of the source linestring to snap + The target snap vertices + + + + Finds a src segment which snaps to (is close to) the given snap point + Only a single segment is selected for snapping. + This prevents multiple segments snapping to the same snap vertex, + which would almost certainly cause invalid geometry + to be created. + (The heuristic approach of snapping used here + is really only appropriate when + snap pts snap to a unique spot on the src geometry) + Also, if the snap vertex occurs as a vertex in the src coordinate list, + no snapping is performed. + + The point to snap to + The source segment coordinates + The index of the snapped segment
+ or -1 if no segment snaps to the snap point.
+
+ + + Performs an overlay operation using snapping and enhanced precision + to improve the robustness of the result. + This class only uses snapping + if an error is detected when running the standard JTS overlay code. + Errors detected include thrown exceptions + (in particular, ) + and invalid overlay computations. + + + + + Performs an overlay operation using snapping and enhanced precision + to improve the robustness of the result. + This class always uses snapping. + This is less performant than the standard JTS overlay code, + and may even introduce errors which were not present in the original data. + For this reason, this class should only be used + if the standard overlay code fails to produce a correct result. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Finds the most likely of a point relative to + the polygonal components of a geometry, using a tolerance value. + + + If a point is not clearly in the Interior or Exterior, + it is considered to be on the Boundary. + In other words, if the point is within the tolerance of the Boundary, + it is considered to be on the Boundary; otherwise, + whether it is Interior or Exterior is determined directly. + + Martin Davis + + + + Extracts linework for polygonal components. + + The geometry from which to extract + A lineal geometry containing the extracted linework + + + + Extracts the LineStrings in the boundaries of all the polygonal elements in the target . + + Martin Davis + + + + Filters out all linework for polygonal elements + + + + + Gets the list of polygonal linework. + + + + + Generates points offset by a given distance from both sides of the midpoint of all segments in a . + + + + Can be used to generate probe points for determining whether a polygonal overlay result is incorrect. + + + The input geometry may have any orientation for its rings, + but is + only meaningful if the orientation is known. + + + Martin Davis + + + + Set the sides on which to generate offset points. + + + + + + + Gets the computed offset points. + + + + + Generates the two points which are offset from the + midpoint of the segment (p0, p1) by the offsetDistance + + The first point of the segment to offset from. + The second point of the segment to offset from + + + + + + Validates that the result of an overlay operation is geometrically correct within a determined tolerance. + Uses fuzzy point location to find points which are + definitely in either the interior or exterior of the result + geometry, and compares these results with the expected ones. + + + This algorithm is only useful where the inputs are polygonal. + This is a heuristic test, and may return false positive results + (I.e. it may fail to detect an invalid result.) + It should never return a false negative result, however + (I.e. it should never report a valid result as invalid.) + + Martin Davis + + + + + Represents a ring of s which form + a ring of a polygon. The ring may be either an outer shell or a hole. + + + + + Find the innermost enclosing shell EdgeRing containing the argument EdgeRing, if any. + The innermost enclosing ring is the smallest enclosing ring. + The algorithm used depends on the fact that: + ring A contains ring B if envelope(ring A) contains envelope(ring B). + This routine is only safe to use if the chosen point of the hole + is known to be properly contained in a shell + (which is guaranteed to be the case if the hole does not touch its shell). + + To improve performance of this function the caller should + make the passed shellList as small as possible(e.g. + by using a spatial index filter beforehand). + + + + Containing EdgeRing, if there is one
+ or null if no containing EdgeRing is found.
+
+ + + Traverses a ring of DirectedEdges, accumulating them into a list. + This assumes that all dangling directed edges have been removed + from the graph, so that there is always a next dirEdge. + + The DirectedEdge to start traversing at + A list of DirectedEdges that form a ring + + + + + + + + + + Adds a DirectedEdge which is known to form part of this ring. + + The DirectedEdge to add. + + + + Tests whether this ring is a hole. + Due to the way the edges in the polygonization graph are linked, + a ring is a hole if it is oriented counter-clockwise. + + true if this ring is a hole. + + + + Computes whether this ring is a hole. + Due to the way the edges in the polygonization graph are linked, + a ring is a hole if it is oriented counter-clockwise. + + + + + Adds a hole to the polygon formed by this ring. + + The LinearRing forming the hole. + + + + Adds a hole to the polygon formed by this ring. + + the forming the hole. + + + + Computes and returns the Polygon formed by this ring and any contained holes. + + + + + Tests if the ring formed by this edge ring is topologically valid. + + true if the ring is valid. + + + + Computes and returns the list of coordinates which are contained in this ring. + The coordinates are computed once only and cached. + + + + + Gets the coordinates for this ring as a LineString. + Used to return the coordinates in this ring + as a valid point, when it has been detected that the ring is topologically + invalid. + + + + + Returns this ring as a LinearRing, or null if an Exception occurs while + creating it (such as a topology problem). Details of problems are written to + standard output. + + + + + + + + + + + + + Gets or sets a value indicating the containing shell ring of a ring that has been determined to be a hole. + + + + + Gets a value indicating whether this ring has a shell assigned to it. + + + + + Tests whether this ring is an outer hole. + A hole is an outer hole if it is not contained by a shell. + + + + + Tests whether this ring is an outer shell. + + + + + Gets the outer hole of a shell, if it has one. + An outer hole is one that is not contained + in any other shell. + Each disjoint connected group of shells + is surrounded by an outer hole. + + The outer hole edge ring, or null + + + + Updates the included status for currently non-included shells + based on whether they are adjacent to an included shell. + + + + + Gets a string representation of this object. + + + + + Gets or sets a value indicating whether this ring has been processed. + + + + + Compares EdgeRings based on their envelope, + using the standard lexicographic ordering. + This ordering is sufficient to make edge ring sorting deterministic. + + mbdavis + + + + Assigns hole rings to shell rings + during polygonization. + Uses spatial indexing to improve performance + of shell lookup. + + mdavis + + + + Assigns hole rings to shell rings. + + An enumeration of hole rings to assign + An enumeration of shell rings + + + + Creates a new hole assigner. + + An enumeration of shell rings to assign holes to + + + + Assigns holes to the shells. + + An enumeration of holes to assign to shells + + + + Find the innermost enclosing shell EdgeRing containing the argument EdgeRing, if any. + The innermost enclosing ring is the smallest enclosing ring. + The algorithm used depends on the fact that: + + ring A contains ring B if envelope(ring A) contains envelope(ring B) + + This routine is only safe to use if the chosen point of the hole + is known to be properly contained in a shell + (which is guaranteed to be the case if the hole does not touch its shell) + + An edge ring to test + + The containing shell EdgeRing, if there is one + or null if no containing EdgeRing is found + + + + + A DirectedEdge of a PolygonizeGraph, which represents + an edge of a polygon formed by the graph. + May be logically deleted from the graph by setting the marked flag. + + + + + Constructs a directed edge connecting the from node to the + to node. + + + + + Specifies this DirectedEdge's direction (given by an imaginary + line from the from node to directionPt). + + + Whether this DirectedEdge's direction is the same as or + opposite to that of the parent Edge (if any). + + + + + Returns the identifier attached to this directed edge. + Attaches an identifier to this directed edge. + + + + + Returns the next directed edge in the EdgeRing that this directed edge is a member of. + Sets the next directed edge in the EdgeRing that this directed edge is a member of. + + + + + Returns the ring of directed edges that this directed edge is + a member of, or null if the ring has not been set. + + + + + Gets/Sets the ring of directed edges that this directed edge is + a member of. + + + + + An edge of a polygonization graph. + + + + + + + + + + + + + + + + Represents a planar graph of edges that can be used to compute a + polygonization, and implements the algorithms to compute the + s formed by the graph. + The marked flag on DirectedEdges is used to indicate that a directed edge + has be logically deleted from the graph. + + + + + + + + + + + + + + + + + + + + Deletes all edges at a node. + + + + + + Create a new polygonization graph. + + + + + + Add a LineString forming an edge of the polygon graph. + + The line to add. + + + + + + + + + + + + + + + + Convert the maximal edge rings found by the initial graph traversal + into the minimal edge rings required by NTS polygon topology rules. + + The list of start edges for the edgeRings to convert. + + + + Finds all nodes in a maximal edgering which are self-intersection nodes + + + + + The list of intersection nodes found, + or null if no intersection nodes were found. + + + + + Computes the minimal EdgeRings formed by the edges in this graph. + + A list of the{EdgeRings found by the polygonization process. + + + + Finds and labels all edgerings in the graph. + The edge rings are labeling with unique integers. + The labeling allows detecting cut edges. + + A List of the DirectedEdges in the graph. + A List of DirectedEdges, one for each edge ring found. + + + + Finds and removes all cut edges from the graph. + + A list of the LineStrings forming the removed cut edges. + + + + + + + + + + + + + + + + + Computes the next edge pointers going CCW around the given node, for the + given edgering label. + This algorithm has the effect of converting maximal edgerings into minimal edgerings + + + + + + + + + + + + + + Marks all edges from the graph which are "dangles". + Dangles are which are incident on a node with degree 1. + This process is recursive, since removing a dangling edge + may result in another edge becoming a dangle. + In order to handle large recursion depths efficiently, + an explicit recursion stack is used. + + A List containing the s that formed dangles. + + + + Traverses the polygonized edge rings in the graph + and computes the depth parity (odd or even) + relative to the exterior of the graph. + + If the client has requested that the output + be polygonally valid, only odd polygons will be constructed. + + + + + Traverses all connected edges, computing the depth parity of the associated polygons. + + + + + + Polygonizes a set of s which contain linework that + represents the edges of a planar graph. + + + All types of Geometry are accepted as input; + the constituent linework is extracted as the edges to be polygonized. + The processed edges must be correctly noded; that is, they must only meet + at their endpoints. Polygonization will accept incorrectly noded input + but will not form polygons from non-noded edges, + and reports them as errors. + + The Polygonizer reports the follow kinds of errors: + + Danglesedges which have one or both ends which are not incident on another edge endpoint + edges which are connected at both ends but which do not form part of polygon + edges which form rings which are invalid + (e.g. the component lines contain a self-intersection) + + + + The constructor allows + extracting only polygons which form a valid polygonal result. + The set of extracted polygons is guaranteed to be edge-disjoint. + This is useful for situations where it is known that the input lines form a + valid polygonal geometry (which may include holes or nested polygons). + + + + + + The default polygonizer output behavior + + + + + Adds every linear element in a into the polygonizer graph. + + + + + Filters all geometry instances + + The geometry instance + + + + Default linestring adder. + + + + + Allows disabling the valid ring checking, + to optimize situations where invalid rings are not expected. + + The default is true + + + + Creates a polygonizer that extracts all polygons. + + + + + Creates a polygonizer, specifying whether a valid polygonal geometry must be created. + If the argument is true + then areas may be discarded in order to + ensure that the extracted geometry is a valid polygonal geometry. + + true if a valid polygonal geometry should be extracted + + + + Adds a collection of s to be polygonized. + May be called multiple times. + Any dimension of Geometry may be added; + the constituent linework will be extracted and used. + + A list of Geometrys with linework to be polygonized. + + + + Adds a to the linework to be polygonized. + May be called multiple times. + Any dimension of Geometry may be added; + the constituent linework will be extracted and used + + A Geometry with linework to be polygonized. + + + + Adds a to the graph of polygon edges. + + The to add. + + + + Gets the list of polygons formed by the polygonization. + + + + + Gets a geometry representing the polygons formed by the polygonization. + If a valid polygonal geometry was extracted the result is a geometry. + + A geometry containing the polygons + + + + Gets the list of dangling lines found during polygonization. + + + + + Gets the list of cut edges found during polygonization. + + + + + Gets the list of lines forming invalid rings found during polygonization. + + + + + Performs the polygonization, if it has not already been carried out. + + + + + For each outer hole finds and includes a single outer shell. + This seeds the traversal algorithm for finding only polygonal shells. + + The list of shell EdgeRings + + + + Optimized implementation of spatial predicate "contains" + for cases where the first Geometry is a rectangle. + As a further optimization, + this class can be used directly to test many geometries against a single rectangle. + + + + + + + + + + + + + Create a new contains computer for two geometries. + + A rectangular geometry. + + + + + + + + + + + + + + + + + + + + + + + + + Tests if a point is contained in the boundary of the target rectangle. + + the point to test + true if the point is contained in the boundary + + + + Tests if a linestring is completely contained in the boundary of the target rectangle. + + the linestring to test + true if the linestring is contained in the boundary + + + + Tests if a line segment is contained in the boundary of the target rectangle. + + an endpoint of the segment + an endpoint of the segment + true if the line segment is contained in the boundary + + + I + Implementation of the Intersects spatial predicate + optimized for the case where one is a rectangle. + + + This class works for all input geometries, including s. + + As a further optimization, this class can be used in batch style + to test many geometries against a single rectangle. + + + + + Crossover size at which brute-force intersection scanning + is slower than indexed intersection detection. + Must be determined empirically. Should err on the + safe side by making value smaller rather than larger. + + + + + Tests whether a rectangle intersects a given geometry. + + A rectangular polygon + A geometry of any kind + true if the geometries intersect. + + + + Create a new intersects computer for a rectangle. + + A rectangular polygon. + + + + Tests whether the given Geometry intersects the query rectangle. + + The Geometry to test (may be of any type) + true if an intersection must occur + or false if no conclusion about intersection can be made + + + + Tests whether it can be concluded that a rectangle intersects a geometry, + based on the relationship of the envelope(s) of the geometry. + + Martin Davis + + + + Creates an instance of this class using the provided Envelope + + The query envelope + + + + Reports whether it can be concluded that an intersection occurs, + or whether further testing is required. + + true if an intersection must occur
+ or false if no conclusion about intersection can be made
+
+ + + + + + + + + + + + + + + A visitor which tests whether it can be + concluded that a geometry contains a vertex of + a query geometry. + + Martin Davis + + + + + + + + + + Gets a value indicating whether it can be concluded that a corner point of the rectangle is + contained in the geometry, or whether further testing is required. + + true if a corner point is contained + or false if no conclusion about intersection can be made + + + + + + + + + + + + + + + + + A visitor to test for intersection between the query rectangle and the line segments of the geometry. + + Martin Davis + + + + Creates a visitor for checking rectangle intersection with segments + + the query rectangle + + + Reports whether any segment intersection exists. + true if a segment intersection exists or + false if no segment intersection exists + + + + Tests if any line segments in two sets of intersect. + Optimized for use when at least one input is of small size. + Short-circuited to return as soon an intersection is found. + + + + + + + + + + + + + + + + + + + + + An EdgeEndBuilder creates EdgeEnds for all the "split edges" + created by the intersections determined for an Edge. + Computes the EdgeEnds which arise from a noded Edge. + + + + + + + + + + + + Creates stub edges for all the intersections in this + Edge (if any) and inserts them into the graph. + + + + + + + Create a EdgeStub for the edge before the intersection eiCurr. + The previous intersection is provided + in case it is the endpoint for the stub edge. + Otherwise, the previous point from the parent edge will be the endpoint. + eiCurr will always be an EdgeIntersection, but eiPrev may be null. + + + + + + + + + Create a StubEdge for the edge after the intersection eiCurr. + The next intersection is provided + in case it is the endpoint for the stub edge. + Otherwise, the next point from the parent edge will be the endpoint. + eiCurr will always be an EdgeIntersection, but eiNext may be null. + + + + + + + + + A collection of EdgeStubs which obey the following invariant: + They originate at the same node and have the same direction. + Contains all EdgeEnds which start at the same point and are parallel. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This computes the overall edge label for the set of + edges in this EdgeStubBundle. It essentially merges + the ON and side labels for each edge. + These labels must be compatible + + + + + + Compute the overall ON location for the list of EdgeStubs. + (This is essentially equivalent to computing the self-overlay of a single Geometry) + edgeStubs can be either on the boundary (e.g. Polygon edge) + OR in the interior (e.g. segment of a LineString) + of their parent Geometry. + In addition, GeometryCollections use the to determine + whether a segment is on the boundary or not. + Finally, in GeometryCollections it can occur that an edge is both + on the boundary and in the interior (e.g. a LineString segment lying on + top of a Polygon edge.) In this case the Boundary is given precedence. + These observations result in the following rules for computing the ON location: + if there are an odd number of Bdy edges, the attribute is Bdy + if there are an even number >= 2 of Bdy edges, the attribute is Int + if there are any Int edges, the attribute is Int + otherwise, the attribute is Null. + + + + + + + Compute the labelling for each side + + + + + + To compute the summary label for a side, the algorithm is: + FOR all edges + IF any edge's location is Interior for the side, side location = Interior + ELSE IF there is at least one Exterior attribute, side location = Exterior + ELSE side location = Null + Note that it is possible for two sides to have apparently contradictory information + i.e. one edge side may indicate that it is in the interior of a point, while + another edge side may indicate the exterior of the same point. This is + not an incompatibility - GeometryCollections may contain two Polygons that touch + along an edge. This is the reason for Interior-primacy rule above - it + results in the summary label having the Geometry interior on both sides. + + + + + + + Update the IM with the contribution for the computed label for the EdgeStubs. + + + + + + + + + + + + An ordered list of EdgeEndBundles around a RelateNode. + They are maintained in CCW order (starting with the positive x-axis) around the node + for efficient lookup and topology building. + + + + + Insert a EdgeEnd in order in the list. + If there is an existing EdgeStubBundle which is parallel, the EdgeEnd is + added to the bundle. Otherwise, a new EdgeEndBundle is created + to contain the EdgeEnd. + + + + + + Update the IM with the contribution for the EdgeStubs around the node. + + + + + + Computes the topological relationship between two Geometries. + RelateComputer does not need to build a complete graph structure to compute + the IntersectionMatrix. The relationship between the geometries can + be computed by simply examining the labelling of edges incident on each node. + RelateComputer does not currently support arbitrary GeometryCollections. + This is because GeometryCollections can contain overlapping Polygons. + In order to correct compute relate on overlapping Polygons, they + would first need to be noded and merged (if not explicitly, at least + implicitly). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Copy all nodes from an arg point into this graph. + The node label in the arg point overrides any previously computed + label for that argIndex. + (E.g. a node may be an intersection node with + a computed label of Boundary, + but in the original arg Geometry it is actually + in the interior due to the Boundary Determination Rule) + + + + + + Insert nodes for all intersections on the edges of a Geometry. + Label the created nodes the same as the edge label if they do not already have a label. + This allows nodes created by either self-intersections or + mutual intersections to be labelled. + Endpoint nodes will already be labelled from when they were inserted. + + + + + + For all intersections on the edges of a Geometry, + label the corresponding node IF it doesn't already have a label. + This allows nodes created by either self-intersections or + mutual intersections to be labelled. + Endpoint nodes will already be labelled from when they were inserted. + + + + + + If the Geometries are disjoint, we need to enter their dimension and + boundary dimension in the Ext rows in the IM + + An intersection matrix + The Boundary Node Rule to use + + + + Compute the IM entry for the intersection of the boundary + of a geometry with the Exterior. + This is the nominal dimension of the boundary + unless the boundary is empty, in which case it is . + For linear geometries the Boundary Node Rule determines + whether the boundary is empty. + + The geometry providing the boundary + The Boundary Node Rule to use + The IM dimension entry + + + + + + + + + Update the IM with the sum of the IMs for each component. + + + + + + Processes isolated edges by computing their labelling and adding them + to the isolated edges list. + Isolated edges are guaranteed not to touch the boundary of the target (since if they + did, they would have caused an intersection to be computed and hence would + not be isolated). + + + + + + + Label an isolated edge of a graph with its relationship to the target point. + If the target has dim 2 or 1, the edge can either be in the interior or the exterior. + If the target has dim 0, the edge must be in the exterior. + + + + + + + + Isolated nodes are nodes whose labels are incomplete + (e.g. the location for one Geometry is null). + This is the case because nodes in one graph which don't intersect + nodes in the other are not completely labelled by the initial process + of adding nodes to the nodeList. + To complete the labelling we need to check for nodes that lie in the + interior of edges, and in the interior of areas. + + + + + Label an isolated node with its relationship to the target point. + + + + + + + A RelateNode is a Node that maintains a list of EdgeStubs + for the edges that are incident on it. + + + + + + + + + + + + Update the IM with the contribution for this component. + A component only contributes if it has a labelling for both parent geometries. + + + + + Update the IM with the contribution for the EdgeEnds incident on this node. + + + + + + Used by the NodeMap in a RelateNodeGraph to create RelateNodes. + + + + + + + + + + + + Implements the simple graph of Nodes and EdgeEnd which is all that is + required to determine topological relationships between Geometries. + Also supports building a topological graph of a single Geometry, to + allow verification of valid topology. + It is not necessary to create a fully linked + PlanarGraph to determine relationships, since it is sufficient + to know how the Geometries interact locally around the nodes. + In fact, this is not even feasible, since it is not possible to compute + exact intersection points, and hence the topology around those nodes + cannot be computed robustly. + The only Nodes that are created are for improper intersections; + that is, nodes which occur at existing vertices of the Geometries. + Proper intersections (e.g. ones which occur between the interior of line segments) + have their topology determined implicitly, without creating a Node object + to represent them. + + + + + + + + + + + + + + + + + Insert nodes for all intersections on the edges of a Geometry. + Label the created nodes the same as the edge label if they do not already have a label. + This allows nodes created by either self-intersections or + mutual intersections to be labelled. + Endpoint nodes will already be labelled from when they were inserted. + Precondition: edge intersections have been computed. + + + + + + + Copy all nodes from an arg point into this graph. + The node label in the arg point overrides any previously computed + label for that argIndex. + (E.g. a node may be an intersection node with + a computed label of Boundary, + but in the original arg Geometry it is actually + in the interior due to the Boundary Determination Rule). + + + + + + + + + + + + + Implements the SFS relate() generalized spatial predicate on two s. +
+ The class supports specifying a custom + to be used during the relate computation. +
+ + If named spatial predicates are used on the result + of the RelateOp, the result may or not be affected by the + choice of BoundaryNodeRule, depending on the exact nature of the pattern. + For instance, is insensitive + to the choice of BoundaryNodeRule, + whereas is affected by the rule chosen. + + Note: custom Boundary Node Rules do not (currently) + affect the results of other methods (such + as . The results of + these methods may not be consistent with the relationship computed by + a custom Boundary Node Rule. + +
+ + + Computes the for the spatial relationship + between two s, using the default (OGC SFS) Boundary Node Rule + + A geometry to test + A geometry to test + The IntersectionMatrix for the spatial relationship between the geometries + + + + Computes the for the spatial relationship + between two s, using the specified Boundary Node Rule + + A geometry to test + A geometry to test + The Boundary Node Rule to use + The IntersectionMatrix for the spatial relationship between the geometries + + + + Creates a new Relate operation, using the default (OGC SFS) Boundary Node Rule. + + a Geometry to relate + another Geometry to relate + + + + Creates a new Relate operation, using the default (OGC SFS) Boundary Node Rule. + + a Geometry to relate + another Geometry to relate + The Boundary Node Rule to use + + + + Gets the IntersectionMatrix for the spatial relationship + between the input geometries. + + + + + Provides an efficient method of unioning a collection of + geometries. + The geometries are indexed using a spatial index, + and unioned recursively in index order. + For geometries with a high degree of overlap, + this has the effect of reducing the number of vertices + early in the process, which increases speed + and robustness. + + This algorithm is faster and more robust than + the simple iterated approach of + repeatedly unioning each polygon to a result geometry. + + The buffer(0) trick is sometimes faster, but can be less robust and + can sometimes take a long time to complete. + This is particularly the case where there is a high degree of overlap + between the polygons. In this case, buffer(0) is forced to compute + with all line segments from the outset, + whereas cascading can eliminate many segments + at each stage of processing. + The best situation for using buffer(0) is the trivial case + where there is no overlap between the input geometries. + However, this case is likely rare in practice. + + Martin Davis + + + + + A union strategy that uses the classic NTS , + and for polygonal geometries a robustness fallback using Buffer(0). + + + + + An alternative way of unioning polygonal geometries + by using Buffer(0). + Only worth using if regular overlay union fails. + + A polygonal geometry + A polygonal geometry + The union of the geometries + + + + Computes the union of + a collection of s. + + A collection of s. + The union of the + + + + Computes the union of + a collection of s. + + A collection of s. + A strategy to perform the unioning. + The union of the + + + + Creates a new instance to union + the given collection of s. + + A collection of s + + + + Creates a new instance to union + the given collection of s. + + A collection of s + + + + + The effectiveness of the index is somewhat sensitive + to the node capacity. + Testing indicates that a smaller capacity is better. + For an STRtree, 4 is probably a good number (since + this produces 2x2 "squares"). + + + + + Computes the union of the input geometries. + + + + This method discards the input geometries as they are processed. + In many input cases this reduces the memory retained + as the operation proceeds. + Optimal memory usage is achieved + by disposing of the original input collection + before calling this method. + + The union of the input geometries, + or null if no input geometries were provided + + if this method is called more than once + + + + Unions a list of geometries + by treating the list as a flattened binary tree, + and performing a cascaded union on the tree. + + The list of geometries to union + The union of the list + + + + Unions a section of a list using a recursive binary union on each half + of the section. + + The list of geometries containing the section to union + The start index of the section + The index after the end of the section + The union of the list section + + + + Gets the element at a given list index, or + null if the index is out of range. + + The list of geometries + The index + The geometry at the given index or + null if the index is out of range + + + + Reduces a tree of geometries to a list of geometries + by recursively unioning the subtrees in the list. + + A tree-structured list of geometries + A list of Geometrys + + + + Computes the union of two geometries, + either or both of which may be null. + + A Geometry + A Geometry + The union of the input(s) or + null if both inputs are null + + + + Encapsulates the actual unioning of two polygonal geometries. + + A geometry to union + A geometry to union + A + The union of the inputs + + + Computes a containing only components. + Extracts the s from the input + and returns them as an appropriate geometry. + + If the input is already Polygonal, it is returned unchanged. + + A particular use case is to filter out non-polygonal components + returned from an overlay operation. + + The geometry to filter + A polygonal geometry + + + + Extracts atomic elements from + input geometries or collections, + recording the dimension found. + Empty geometries are discarded since they + do not contribute to the result of . + + Martin Davis + + + + Extracts elements from an enumeration of geometries. + + An enumeration of geometries + An extracter over the geometries. + + + + Extracts elements from a geometry. + + An geometry to extract from + An extracter over the geometry. + + + The default dimension for an empty GeometryCollection + + + + Gets a value indicating if there were any non-empty geometries extracted + + + + + Gets a value indicating the maximum extracted. + + + + + Gets a value indicating the geometry factory from the extracted geometry, + if there is one. + If an empty collection was extracted, will return null. + + + + + Gets the extracted atomic geometries of the given dimension dim. + + The dimension of geometry to return + A list of the extracted geometries of dimension dim. + + + + Unions MultiPolygons efficiently by + using full topological union only for polygons which may overlap, + and combining with the remaining polygons. + Polygons which may overlap are those which intersect the common extent of the inputs. + Polygons wholly outside this extent must be disjoint to the computed union. + They can thus be simply combined with the union result, + which is much more performant. + (There is one caveat to this, which is discussed below). + + This situation is likely to occur during cascaded polygon union, + since the partitioning of polygons is done heuristically + and thus may group disjoint polygons which can lie far apart. + It may also occur in real world data which contains many disjoint polygons + (e.g. polygons representing parcels on different street blocks). + + +

Algorithm

+ The overlap region is determined as the common envelope of intersection. + The input polygons are partitioned into two sets: + + OverlappingPolygons which intersect the overlap region, and thus potentially overlap each other + DisjointPolygons which are disjoint from (lie wholly outside) the overlap region + + The Overlapping set is fully unioned, and then combined with the Disjoint set. + Performing a simple combine works because + the disjoint polygons do not interact with each + other(since the inputs are valid MultiPolygons). + They also do not interact with the Overlapping polygons, + since they are outside their envelope. +

Discussion

+ In general the Overlapping set of polygons will + extend beyond the overlap envelope. This means that the union result + will extend beyond the overlap region. + There is a small chance that the topological + union of the overlap region will shift the result linework enough + that the result geometry intersects one of the Disjoint geometries. + This situation is detected and if it occurs + is remedied by falling back to performing a full union of the original inputs. + Detection is done by a fairly efficient comparison of edge segments which + extend beyond the overlap region. If any segments have changed + then there is a risk of introduced intersections, and full union is performed. + + This situation has not been observed in JTS using floating precision, + but it could happen due to snapping. It has been observed + in other APIs(e.g.GEOS) due to more aggressive snapping. + It is more likely to happen if a Snap - Rounding overlay is used. + + NOTE: Test has shown that using this heuristic impairs performance. +
+ Martin Davis +
+ + + Union a pair of geometries, + using the more performant overlap union algorithm if possible. + + A geometry to union + A geometry to union + The union of the inputs + + + + Union a pair of geometries, + using the more performant overlap union algorithm if possible. + + A geometry to union + A geometry to union + Function to union two geometries + The union of the inputs + + + + Creates a new instance for unioning the given geometries. + + A geometry to union + A geometry to union + + + + Creates a new instance for unioning the given geometries. + + A geometry to union + A geometry to union + Function to union two geometries + + + + Union a pair of geometries, + using the more performant overlap union algorithm if possible. + + The union of the inputs + + + + Gets a value indicating whether the optimized + or full union was performed. + + Used for unit testing.> + true if the optimized union was performed + + + + Implements union using the buffer-by-zero trick. + This seems to be more robust than overlay union, + for reasons somewhat unknown. + + A geometry + A geometry + The union of the geometries + + + + Computes the union of a geometry with + another arbitrary . + Does not copy any component geometries. + + + + + + + + Unions a Collection of s or a single Geometry (which may be a ) together. + + + + By using this special-purpose operation over a collection of geometries + it is possible to take advantage of various optimizations to improve performance. + + + Heterogeneous s are fully supported. + + + The result obeys the following contract: + + Unioning a set of s has the effect of merging the areas (i.e. the same effect as iteratively unioning all individual polygons together). + Unioning a set of s has the effect of fully noding + and dissolving the input linework. + In this context "fully noded" means that there will be + an endpoint or node in the result + for every endpoint or line segment crossing in the input. + "Dissolved" means that any duplicate (e.g. coincident) line segments or portions + of line segments will be reduced to a single line segment in the output. + This is consistent with the semantics of the + operation. + If merged linework is required, the class can be used. + Unioning a set of s has the effect of merging all identical points (producing a set with no duplicates). + + + UnaryUnion always operates on the individual components of MultiGeometries. + So it is possible to use it to "clean" invalid self-intersecting MultiPolygons + (although the polygon components must all still be individually valid.) + + + + mbdavis + + + + + Computes the geometric union of a + + A collection of geometries + The union of the geometries, + or null if the input is empty + + + + Computes the geometric union of a + If no input geometries were provided but a was provided, + an empty is returned. + + A collection of geometries + The geometry factory to use if the collection is empty + The union of the geometries + or an empty GEOMETRYCOLLECTION + + + Constructs a unary union operation for a + (which may be a ). + + A geometry to union + The union of the elements of the geometry + or an empty GEOMETRYCOLLECTION + + + + Constructs a unary union operation for an enumeration + of s, using the + of the input geometries. + + An enumeration of geometries + + + + Constructs a unary union operation for an enumeration + of s. + If no input geometries were provided but a was provided, + + An enumeration of geometries + The geometry factory to use if the enumeration is empty + + + + Constructs a unary union operation for a + (which may be a ). + + A geometry to union + + + + Named setter named setUnionFun[ction] in JTS + + + + + Gets the union of the input geometries. + + The result of empty input is determined as follows: + + If the input is empty and a dimension can be + determined (i.e. an empty geometry is present), + an empty atomic geometry of that dimension is returned. + If no input geometries were provided but a was provided, + an empty is returned. + Otherwise, the return value is null. + + + + A Geometry containing the union, + or an empty atomic geometry, or an empty GEOMETRYCOLLECTION, + ornull if no GeometryFactory was provided + + + + + Computes the union of two geometries, either of both of which may be null. + + + + + The union of the input(s) + or null if both inputs are null + + + + + Computes a unary union with no extra optimization, and no short-circuiting. + + + Due to the way the overlay operations are implemented, this is still efficient in the case of linear and puntal geometries. + + A geometry + The union of the input geometry + + + + Experimental code to union MultiPolygons with processing limited to the elements which actually interact. + + Not currently used, since it doesn't seem to offer much of a performance advantage. + mbdavis + + + + An strategy class that allows UnaryUnion to adapt to different + kinds of overlay algorithms. + + Martin Davis + + + + Computes the union of two geometries. + This method may throw a + if one is encountered. + + A geometry + A geometry + The union of the input + + + + Indicates whether the union function operates using + a floating(full) precision model. + If this is the case, then the unary union code + can make use of the { @link OverlapUnion} + performance optimization, + and perhaps other optimizations as well. + Otherwise, the union result extent may not be the same as the extent of the inputs, + which prevents using some optimizations. + + + + + This class tests that the interior of an area + ( or ) + is connected. An area Geometry is invalid if the interior is disconnected. + This can happen if: + - a shell self-intersects, + - one or more holes form a connected chain touching a shell at two different points, + - one or more holes form a ring around a subset of the interior. + If a disconnected situation is found the location of the problem is recorded. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Form s in graph into Minimal EdgeRings. + (Minimal Edgerings must be used, because only they are guaranteed to provide + a correct isHole computation). + + + + + + + Mark all the edges for the edgeRings corresponding to the shells of the input polygons. + Only ONE ring gets marked for each shell - if there are others which remain unmarked + this indicates a disconnected interior. + + + + + + + + + + + + + + + + + + + + Check if any shell ring has an unvisited edge. + A shell ring is a ring which is not a hole and which has the interior + of the parent area on the RHS. + (Note that there may be non-hole rings with the interior on the LHS, + since the interior of holes will also be polygonized into CW rings + by the LinkAllDirectedEdges() step). + + + true if there is an unvisited edge in a non-hole ring. + + + + Checks that a {GeometryGraph} representing an area + (a Polygon or MultiPolygon ) + is consistent with the SFS semantics for area geometries. + Checks include: + Testing for rings which self-intersect (both properly and at nodes). + Testing for duplicate rings. + If an inconsistency if found the location of the problem is recorded. + + + + + + + + + + + Returns the intersection point, or null if none was found. + + + + + + + + + + Check all nodes to see if their labels are consistent. + If any are not, return false. + + + + + Checks for two duplicate rings in an area. + Duplicate rings are rings that are topologically equal + (that is, which have the same sequence of points up to point order). + If the area is topologically consistent (determined by calling the + isNodeConsistentArea, + duplicate rings can be found by checking for EdgeBundles which contain more than one EdgeEnd. + (This is because topologically consistent areas cannot have two rings sharing + the same line segment, unless the rings are equal). + The start point of one of the equal rings will be placed in invalidPoint. + Returns true if this area Geometry is topologically consistent but has two duplicate rings. + + + + + Tests whether any holes of a Polygon are + nested inside another hole, using a spatial + index to speed up the comparisons. + + The logic assumes that the holes do not overlap and have no collinear segments + (so they are properly nested, and there are no duplicate holes). + + The situation where every vertex of a hole touches another hole + is invalid because either the hole is nested, + or else it disconnects the polygon interior. + This class detects the nested situation. + The disconnected interior situation must be checked elsewhere. + + + + + Gets a value indicating a point on a nested hole, if one exists. + + A point on a nested hole, or null if none are nested + + + + Tests if any hole is nested (contained) within another hole. + This is invalid. + The will be set to reflect this. + + true if some hole is nested. + + + + Tests whether a MultiPolygon has any element polygon + nested inside another polygon, using a spatial + index to speed up the comparisons. + + The logic assumes that the polygons do not overlap and have no collinear segments + (so they are properly nested, and there are no duplicate rings). + + + + + Gets a point on a nested polygon, if one exists. + + A point on a nested polygon, or null if none are nested + + + + Tests if any polygon is nested (contained) within another polygon. + This is invalid. + The nested point will be set to reflect this. + + true if some polygon is nested + + + + Finds a point of a shell segment which lies inside a polygon, if any. + The shell is assume to touch the polyon only at shell vertices, + and does not cross the polygon. + + The shell to test + The polygon to test against + An interior segment point, or null if the shell is nested correctly + + + + Tests whether any of a set of s are + nested inside another ring in the set, using a spatial + index to speed up the comparisons. + + + + + Tests whether a Geometry is simple as defined by the OGC SFS specification. + + Simplicity is defined for each + type as follows: + + Pointgeometries are simple. + MultiPointgeometries are simple if every point is unique + LineStringgeometries are simple if they do not self-intersect at interior points + (i.e.points other than the endpoints). + MultiLineStringgeometries are simple if + their elements are simple and they intersect only at points + which are boundary points of both elements. + (The notion of boundary points can be user-specified - see below). + Polygonalgeometries have no definition of simplicity. + The IsSimple code checks if all polygon rings are simple. + (Note: this means thatIsSimple cannot be used to test + for all self-intersections in Polygon s. + In order to check if a IPolygonal geometry has self-intersections, + use . + GeometryCollectiongeometries are simple if all their elements are simple. + Empty geometries are simple + + For geometries the evaluation of simplicity + can be customized by supplying a + to define how boundary points are determined. + The default is the SFS-standard . + + Note that under the Mod-2 rule, closed LineStrings (rings) + have no boundary. + This means that an intersection at their endpoints makes the geometry non-simple. + If it is required to test whether a set of LineStrings touch + only at their endpoints, use . + For example, this can be used to validate that a collection of lines + form a topologically valid linear network. + + By default this class finds a single non-simple location. + To find all non-simple locations, set + before calling , and retrieve the locations + via . + This can be used to find all intersection points in a linear network. + + + + + + + Tests whether a geometry is simple. + + The input geometry + true if the geometry is simple + + + + Gets a non-simple location in a geometry, if any. + + The input geometry + A non-simple location, or null if the geometry is simple + + + + Creates a simplicity checker using the default SFS Mod-2 Boundary Node Rule + + The geometry to test + + + + Creates a simplicity checker using a given + + The geometry to test + The boundary node rule to use + + + Gets or sets a value indicating if all non-simple points should be reported. + + + + Tests whether the geometry is simple. + + true if the geometry is simple. + + + + Gets the coordinate for an location where the geometry + fails to be simple (i.e. where it has a non-boundary + self-intersection). + + A Coordinate for the location of the non-boundary self-intersection + or null if the geometry is simple + + + + Gets all non-simple intersection locations. + + A list of the Coordinates of non-simple locations. + + + + Computes simplicity for polygonal geometries. + Polygonal geometries are simple if and only if + all of their component rings are simple. + + A geometry + true if the geometry is simple + + + + Semantics for GeometryCollection is + simple if all components are simple. + + A geometry collection + true if the geometry is simple + + + + Creates an instance of this class + + A flag indicating if closed endpoints belong to the interior + A flag indicating that all non-simple intersection points should be found + A list to add the non-simple intersection points to. + + + + Tests whether an intersection was found. + + true if an intersection was found. + + + + + + + Tests whether an intersection vertex is an endpoint of a segment string. + + The segment string + The index of the segment in + The line intersector + The index of the segment in intersector + true if the intersection vertex is an endpoint + + + + Finds the vertex index in a segment of an intersection + which is known to be a vertex. + + The line intersector + The intersection segment index + + The vertex index (0 or 1) in the segment vertex of the intersection point + + + + + + + + Implements the algorithms required to compute the + method for s. + See the documentation for the various geometry types for a specification of validity. + + + + + Tests whether a is valid. + + The geometry to test + true if the geometry is valid + In JTS this function is called IsValid + + + + Checks whether a coordinate is valid for processing. + Coordinates are valid if their x and y ordinates are in the + range of the floating point representation. + + The coordinate to validate + true if the coordinate is valid + + + + The geometry being validated + + + + + If the following condition is TRUE JTS will validate inverted shells and exverted holes + (the ESRI SDE model) + + + + + Creates a new validator for a geometry + + The geometry to validate + + + + Gets or sets a value indicating whether polygons using Self-Touching Rings to form + holes are reported as valid. + If this flag is set, the following Self-Touching conditions + are treated as being valid: + + the shell ring self-touches to create a hole touching the shell + a hole ring self-touches to create two holes touching at a point + + + The default (following the OGC SFS standard) + is that this condition is not valid (false). + + Self-Touching Rings which disconnect the + the polygon interior are still considered to be invalid + (these are invalid under the SFS, and many other + spatial models as well). + This includes: + + exverted ("bow-tie") shells which self-touch at a single point + inverted shells with the inversion touching the shell at another point + exverted holes with exversion touching the hole at another point + inverted ("C-shaped") holes which self-touch at a single point causing an island to be formed + inverted shells or exverted holes which form part of a chain of touching rings + (which disconnect the interior) + + + + + + + Gets/Sets whether polygons using Self-Touching Rings to form + holes are reported as valid. + If this flag is set, the following Self-Touching conditions + are treated as being valid:
+ - The shell ring self-touches to create a hole touching the shell.
+ - A hole ring self-touches to create two holes touching at a point.
+
+ + The default (following the OGC SFS standard) + is that this condition is not valid (false). + + + This does not affect whether Self-Touching Rings + disconnecting the polygon interior are considered valid + (these are considered to be invalid under the SFS, and many other + spatial models as well). + This includes "bow-tie" shells, + which self-touch at a single point causing the interior to be disconnected, + and "C-shaped" holes which self-touch at a single point causing an island to be formed. + +
+ States whether geometry with this condition is valid. +
+ + + Tests the validity of the input geometry. + + true if the geometry is valid. + + + + Gets a value indicating the validity of the geometry + If not valid, returns the validation error for the geometry, + or null if the geometry is valid. + + The validation error, if the geometry is invalid + or null if the geometry is valid + + + + Tests validity of a Point. + + The Point to test + true if the Point is valid + In JTS this function is called IsValid + + + + Tests validity of a MultiPoint. + + The MultiPoint to test + true if the MultiPoint is valid + In JTS this function is called IsValid + + + + Tests validity of a LineString.
+ Almost anything goes for LineStrings! +
+ The LineString to test + In JTS this function is called IsValid +
+ + + Tests validity of a LinearRing.
+
+ The LinearRing to test + In JTS this function is called IsValid +
+ + + Tests validity of a Polygon.
+
+ The Polygon to test + In JTS this function is called IsValid +
+ + + Tests validity of a MultiPolygon.
+
+ The MultiPolygon to test + In JTS this function is called IsValid +
+ + + Tests validity of a GeometryCollection.
+
+ The GeometryCollection to test + In JTS this function is called IsValid +
+ + + Check the number of non-repeated points is at least a given size. + + The line to test + The minimum number of points in + true if the line has the required number of points + + + + Test if the number of non-repeated points in a line + is at least a given minimum size. + + The line to test + The minimum number of points in + true if the line has the required number of non-repeated points + + + + Check whether a ring self-intersects (except at its endpoints). + + The linear ring to check + + + + Tests that each hole is inside the polygon shell. + This routine assumes that the holes have previously been tested + to ensure that all vertices lie on the shell or on the same side of it + (i.e. that the hole rings do not cross the shell ring). + Given this, a simple point-in-polygon test of a single point in the hole can be used, + provided the point is chosen such that it does not lie on the shell. + + The polygon to be tested for hole inclusion + + + + Checks if a polygon hole lies inside its shell + and if not returns a point indicating this. + The hole is known to be wholly inside or outside the shell, + so it suffices to find a single point which is interior or exterior, + or check the edge topology at a point on the boundary of the shell. + + The hole to test + The polygon shell to test against + A hole point outside the shell, or null if it is inside. + + + + Checks if any polygon hole is nested inside another. + Assumes that holes do not cross (overlap), + This is checked earlier. + + The polygon with holes to test + + + + Checks that no element polygon is in the interior of another element polygon. + Preconditions: + + shells do not partially overlap + shells do not touch along an edge + no duplicate rings exist + These have been confirmed by the . + + + + + Find a point from the list of testCoords + that is NOT a node in the edge for the list of searchCoords. + + + + + The point found, or null if none found. + + + Finds and analyzes intersections in and between polygons, + to determine if they are valid. + + The s which are analyzed can have s + attached. If so they will be updated with intersection information + to support further validity analysis which must be done after + basic intersection validity has been confirmed. + + Martin Davis + + + + Creates a new finder, allowing for the mode where inverted rings are valid. + + true if inverted rings are valid. + + + + For a segment string for a ring, gets the coordinate + previous to the given index (wrapping if the index is 0) + + The ring segment string + The segment index + The coordinate previous to the given segment + + + + Tests if two segments in a closed are adjacent. + This handles determining adjacency across the start/end of the ring. + + The segment string + A segment index + A segment index + true if the segments are adjacent + + + + Functions to compute topological information + about nodes (ring intersections) in polygonal geometry. + + Martin Davis + + + + Check if the edges at a node between two rings (or one ring) cross. + The node is topologically valid if the ring edges do not cross. + This function assumes that the edges are not collinear. + + The node location + The previous edge endpoint in a ring + The next edge endpoint in a ring + The previous edge endpoint in the other ring + The next edge endpoint in the other ring + + true if the edges cross at the node + + + + + Tests whether an edge node-b lies in the interior or exterior + of a corner of a ring given by a0-node-a1. + The ring interior is assumed to be on the right of the corner (a CW ring). + The edge must not be collinear with the corner segments. + + The node location + The first vertex of the corner + The second vertex of the corner + The destination vertex of the edge + true if the edge is interior to the ring corner + + + + Tests if an edge p is between edges e0 and e1, + where the edges all originate at a common origin. + The "inside" of e0 and e1 is the arc which does not include the origin. + The edges are assumed to be distinct (non-collinear). + + the origin + the destination point of edge p + the destination point of edge e0 + the destination point of edge e1 + true if p is between e0 and e1 + + + + Tests if the angle with the origin of a vector P is greater than that of the + vector Q. + + The origin of the vectors + The endpoint of the vector P + The endpoint of the vector Q + true if vector P has angle greater than Q + + + + A ring of a polygon being analyzed for topological validity. + The shell and hole rings of valid polygons touch only at discrete points. + The "touch" relationship induces a graph over the set of rings. + The interior of a valid polygon must be connected. + This is the case if there is no "chain" of touching rings + (which would partition off part of the interior). + This is equivalent to the touch graph having no cycles. + Thus the touch graph of a valid polygon is a forest - a set of disjoint trees. + + Also, in a valid polygon two rings can touch only at a single location, + since otherwise they disconnect a portion of the interior between them. + This is checked as the touches relation is built + (so the touch relation representation for a polygon ring does not need to support + more than one touch location for each adjacent ring). + + The cycle detection algorithm works for polygon rings which also contain self-touches + (inverted shells and exverted holes). + + Polygons with no holes do not need to be checked for + a connected interior, unless self-touches are allowed. + + The class also records the topology at self-touch nodes, + to support checking if an invalid self-touch disconnects the polygon. + + Martin Davis + + + + Tests if a polygon ring represents a shell. + + The ring to test (may be null) + true if the ring represents a shell + + + + Records a touch location between two rings, + and checks if the rings already touch in a different location. + + A polygon ring + A polygon ring + The location where they touch + true if the polygons already touch + + + + Finds a location (if any) where a chain of holes forms a cycle + in the ring touch graph. + The shell may form part of the chain as well. + This indicates that a set of holes disconnects the interior of a polygon. + + The list of rings to check + A vertex contained in a ring cycle or null if none is found. + + + + Finds a location of an interior self-touch in a list of rings, + if one exists. + This indicates that a self-touch disconnects the interior of a polygon, + which is invalid. + + The list of rings to check + The location of an interior self-touch node, or null if there are none + + + + The root of the touch graph tree containing this ring. + Serves as the id for the graph partition induced by the touch relation. + + + + + The set of links + for this ring. + The set of all touches in the rings of a polygon + forms the polygon touch graph. + This supports detecting touch cycles, which + reveal the condition of a disconnected interior. + + Only a single touch is recorded between any two rings, + since more than one touch between two rings + indicates interior disconnection as well. + + + + + The set of self-nodes in this ring. + This supports checking valid ring self-touch topology. + + + + + Creates a ring for a polygon shell. + + The polygon shell + + + + Creates a ring for a polygon hole. + + The ring geometry + The index of the hole + The parent polygon shell + + + + Adds a point where a touches another one. + + The other + The touch location + + + + Adds the node (intersection point) + and the endpoints of the four adjacent segments. + + The node + The 1st position of the 1st edge + The 2nd position of the 1st edge + The 1st position of the 2nd edge + The 2nd position of the 2nd edge + + + + Tests if this ring touches a given ring at + the single point specified. + + The other polygon ring + The touch point + true if the rings touch only at the given point. + + + + Detects whether the subgraph of holes linked by touch to this ring + contains a hole cycle. + If no cycles are detected, the set of touching rings is a tree. + The set is marked using this ring as the root. + + A vertex om a hole cycle or null if no cycle found + + + + Scans for a hole cycle starting at a given touch. + + The touch to investigate + The root of the touch subgraph + The queue of rings to scan + + + + Finds the location of an invalid interior self-touch in this ring, + if one exists. + + The location of an interior self-touch node, or null if there are none + + + + + + + + Records a point where a touches another one. + This forms an edge in the induced ring touch graph. + + Martin Davis + + + + Creates an instance of this item + + The polygon ring + The touch position + + + + Represents a ring self-touch node, recording the node (intersection point) + and the endpoints of the four adjacent segments. + + This is used to evaluate validity of self-touching nodes, + when they are allowed. + + Martin Davis + + + + Creates an instance of this point + + The self touch position + The 1st position of the 1st edge + The 2nd position of the 1st edge + The 1st position of the 2nd edge + The 2nd position of the 2nd edge + + + + Gets a value indicating the node point + + + + + Tests if a self-touch has the segments of each half of the touch + lying in the exterior of a polygon. + This is a valid self-touch. + It applies to both shells and holes. + Only one of the four possible cases needs to be tested, + since the situation has full symmetry. + + A flag indicating if the interior is to the right of the parent ring + true if the self-touch is on the exterior. + + + + Analyzes the topology of polygonal geometry + to determine whether it is valid. + + Martin Davis + + + + Finds a self-intersection (if any) in a . + + The ring to analyze + A self-intersection point if one exists, or null + + + + Tests whether a segment p0-p1 is inside or outside a ring. + + Preconditions: + + The segment intersects the ring only at the endpoints + One, none or both of the segment endpoints may lie on the ring + The ring does not self-cross, but it may self-touch + + + A segment vertex + A segment vertex + The ring to test + true if the segment lies inside the ring + + + + Tests whether a touching segment is interior to a ring. + + Preconditions: + + The segment does not intersect the ring other than at the endpoints + The segment vertex p0 lies on the ring + The ring does not self-cross, but it may self-touch + + This works for both shells and holes, but the caller must know + the ring role. + + The first vertex of the segment + The second vertex of the segment + The points of the ring + true if the segment is inside the ring. + + + + Computes the index of the segment which intersects a given point. + + The ring points + The intersection point + The intersection segment index, or -1 if not intersection is found. + + + + Tests whether the interior of the polygonal geometry is + disconnected.
+ If true, the disconnection location is available from + . +
+ true if the interior is disconnected +
+ + + Gets a location where the polyonal interior is disconnected.
+ must be called first. +
+ The location of an interior disconnection, or null +
+ + + Tests whether any polygon with holes has a disconnected interior + by virtue of the holes (and possibly shell) forming a touch cycle. + + This is a global check, which relies on determining + the touching graph of all holes in a polygon. + + If inverted rings disconnect the interior + via a self-touch, this is checked by the . + If inverted rings are part of a disconnected ring chain + this is detected here. + + true if a polygon has a disconnected interior. + + + + Tests if an area interior is disconnected by a self-touching ring. + This must be evaluated after other self-intersections have been analyzed + and determined to not exist, since the logic relies on + the rings not self-crossing (winding). + + true if an area interior is disconnected by a self-touch + + + + Implements the appropriate checks for repeated points + (consecutive identical coordinates) as defined in the + NTS spec. + + + + + Gets a value indicating the location of the repeated point + + + + + Checks if a geometry has a repeated point + + The geometry to test + true if the geometry has a repeated point, otherwise false + + + + Checks if an array of Coordinates has a repeated point + + An array of coordinates + true if has a repeated point, otherwise false + + + + Checks if an array of Coordinates has a repeated point + + A coordinate sequence + true if has a repeated point, otherwise false + + + + Contains information about the nature and location of + a validation error. + + + + + + + + + Indicates that a hole of a polygon lies partially + or completely in the exterior of the shell. + + + + + Indicates that a hole lies + in the interior of another hole in the same polygon. + + + + + Indicates that the interior of a polygon is disjoint + (often caused by set of contiguous holes splitting + the polygon into two parts). + + + + + Indicates that two rings of a polygonal geometry intersect. + + + + + Indicates that a ring self-intersects. + + + + + Indicates that a polygon component of a + lies inside another polygonal component. + + + + + Indicates that a polygonal geometry + contains two rings which are identical. + + + + + Indicates that either: + - A contains a single point. + - A contains 2 or 3 points. + + + + + Indicates that the X or Y ordinate of + a is not a valid + numeric value (e.g. ). + + + + + Indicates that a ring is not correctly closed + (the first and the last coordinate are different). + + + + + Contains information about the nature and location of a Geometry + validation error. + + + + + These messages must synch up with the indexes above + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Finds all connected s of a . + + + + + Initializes a new instance of the class. + + The . + + + + Adds all nodes and edges reachable from this node to the subgraph. + Uses an explicit stack to avoid a large depth of recursion. + + + + + + + Adds the argument node and all its out edges to the subgraph. + + + + + + + + Represents a directed edge in a PlanarGraph. A DirectedEdge may or + may not have a reference to a parent Edge (some applications of + planar graphs may not require explicit Edge objects to be created). Usually + a client using a PlanarGraph will subclass DirectedEdge + to add its own application-specific data and methods. + + + + + Returns a List containing the parent Edge (possibly null) for each of the given + DirectedEdges. + + + + + + + Constructs a DirectedEdge connecting the from node to the + to node. + + + + + Specifies this DirectedEdge's direction (given by an imaginary + line from the from node to directionPt). + + + Whether this DirectedEdge's direction is the same as or + opposite to that of the parent Edge (if any). + + + + + Returns this DirectedEdge's parent Edge, or null if it has none. + Associates this DirectedEdge with an Edge (possibly null, indicating no associated + Edge). + + + + + Returns 0, 1, 2, or 3, indicating the quadrant in which this DirectedEdge's + orientation lies. + + + + + Returns 0, 1, 2, or 3, indicating the quadrant in which this DirectedEdge's + orientation lies. + + + + + Returns a point to which an imaginary line is drawn from the from-node to + specify this DirectedEdge's orientation. + + + + + Returns whether the direction of the parent Edge (if any) is the same as that + of this Directed Edge. + + + + + Returns the node from which this DirectedEdge leaves. + + + + + Returns the node to which this DirectedEdge goes. + + + + + Returns the coordinate of the from-node. + + + + + Returns the angle that the start of this DirectedEdge makes with the + positive x-axis, in radians. + + + + + Returns the symmetric DirectedEdge -- the other DirectedEdge associated with + this DirectedEdge's parent Edge. + Sets this DirectedEdge's symmetric DirectedEdge, which runs in the opposite + direction. + + + + + Returns 1 if this DirectedEdge has a greater angle with the + positive x-axis than b", 0 if the DirectedEdges are collinear, and -1 otherwise. + Using the obvious algorithm of simply computing the angle is not robust, + since the angle calculation is susceptible to round off. A robust algorithm + is: + first compare the quadrants. If the quadrants are different, it it + trivial to determine which vector is "greater". + if the vectors lie in the same quadrant, the robust + RobustCGAlgorithms.ComputeOrientation(Coordinate, Coordinate, Coordinate) + function can be used to decide the relative orientation of the vectors. + + + + + + + Returns 1 if this DirectedEdge has a greater angle with the + positive x-axis than b", 0 if the DirectedEdges are collinear, and -1 otherwise. + Using the obvious algorithm of simply computing the angle is not robust, + since the angle calculation is susceptible to round off. A robust algorithm + is: + first compare the quadrants. If the quadrants are different, it it + trivial to determine which vector is "greater". + if the vectors lie in the same quadrant, the robust + RobustCGAlgorithms.ComputeOrientation(Coordinate, Coordinate, Coordinate) + function can be used to decide the relative orientation of the vectors. + + + + + + + Writes a detailed string representation of this DirectedEdge to the given PrintStream. + + + + + + Tests whether this component has been removed from its containing graph. + + + + + + Removes this directed edge from its containing graph. + + + + + + + + A sorted collection of DirectedEdges which leave a Node + in a PlanarGraph. + + + + + The underlying list of outgoing DirectedEdges. + + + + + Adds a new member to this DirectedEdgeStar. + + + + + + Drops a member of this DirectedEdgeStar. + + + + + + Returns an Iterator over the DirectedEdges, in ascending order by angle with the positive x-axis. + + + + + Returns the number of edges around the Node associated with this DirectedEdgeStar. + + + + + Returns the coordinate for the node at which this star is based. + + + + + Returns the DirectedEdges, in ascending order by angle with the positive x-axis. + + + + + + + + + + Returns the zero-based index of the given Edge, after sorting in ascending order + by angle with the positive x-axis. + + + + + + + Returns the zero-based index of the given DirectedEdge, after sorting in ascending order + by angle with the positive x-axis. + + + + + + + Returns the remainder when i is divided by the number of edges in this + DirectedEdgeStar. + + + + + + + Returns the on the left-hand + side of the given + (which must be a member of this DirectedEdgeStar). + + + + + + + Returns the on the right-hand (CW) + side of the given + (which must be a member of this DirectedEdgeStar). + + + + + Represents an undirected edge of a {PlanarGraph}. An undirected edge + in fact simply acts as a central point of reference for two opposite + DirectedEdges. + Usually a client using a PlanarGraph will subclass Edge + to add its own application-specific data and methods. + + + + + The two DirectedEdges associated with this Edge. + + + + + Constructs an Edge whose DirectedEdges are not yet set. Be sure to call + SetDirectedEdges(DirectedEdge, DirectedEdge). + + + + + Constructs an Edge initialized with the given DirectedEdges, and for each + DirectedEdge: sets the Edge, sets the symmetric DirectedEdge, and adds + this Edge to its from-Node. + + + + + + + Initializes this Edge's two DirectedEdges, and for each DirectedEdge: sets the + Edge, sets the symmetric DirectedEdge, and adds this Edge to its from-Node. + + + + + + + Returns one of the DirectedEdges associated with this Edge. + + 0 or 1. + + + + + Returns the DirectedEdge that starts from the given node, or null if the + node is not one of the two nodes associated with this Edge. + + + + + + + If node is one of the two nodes associated with this Edge, + returns the other node; otherwise returns null. + + + + + + + Removes this edge from its containing graph. + + + + + Tests whether this component has been removed from its containing graph. + + + + + + The base class for all graph component classes. + Maintains flags of use in generic graph algorithms. + Provides two flags: + marked - typically this is used to indicate a state that persists + for the course of the graph's lifetime. For instance, it can be + used to indicate that a component has been logically deleted from the graph. + visited - this is used to indicate that a component has been processed + or visited by an single graph algorithm. For instance, a breadth-first traversal of the + graph might use this to indicate that a node has already been traversed. + The visited flag may be set and cleared many times during the lifetime of a graph. + + + + + Sets the state + for all s in an . + + A to scan. + The state to set the flag to. + + + + Sets the state + for all s in an . + + A to scan. + The state to set the flag to. + + + + Finds the first + in a set + which has the specified state. + + A to scan. + The state to test. + The first found, or null if none found. + + + + Tests if a component has been visited during the course of a graph algorithm. + + + + + Gets/Sets the visited flag for this component. + + + + + Tests if a component has been marked at some point during the processing + involving this graph. + + + + + Gets/Sets the marked flag for this component. + + + + + Tests whether this component has been removed from its containing graph. + + + + + Gets or sets user defined data for this component + + + + + A node in a PlanarGraph is a location where 0 or more Edges + meet. A node is connected to each of its incident Edges via an outgoing + DirectedEdge. Some clients using a PlanarGraph may want to + subclass Node to add their own application-specific + data and methods. + + + + + Returns all Edges that connect the two nodes (which are assumed to be different). + + + + + + + + The location of this Node. + + + + + The collection of DirectedEdges that leave this Node. + + + + + Constructs a Node with the given location. + + + + + + Constructs a Node with the given location and collection of outgoing DirectedEdges. + + + + + + + Returns the location of this Node. + + + + + Adds an outgoing DirectedEdge to this Node. + + + + + + Returns the collection of DirectedEdges that leave this Node. + + + + + Returns the number of edges around this Node. + + + + + Returns the zero-based index of the given Edge, after sorting in ascending order + by angle with the positive x-axis. + + + + + + + Removes a incident on this node. Does not change the state of the directed edge. + + + + + Removes this node from its containing graph. + + + + + Tests whether this component has been removed from its containing graph. + + + + + + + + + + + + A map of nodes, indexed by the coordinate of the node. + + + + + Adds a node to the map, replacing any that is already at that location. + + + The added node. + + + + Removes the Node at the given location, and returns it (or null if no Node was there). + + + + + + + Returns the Node at the given location, or null if no Node was there. + + + + + + + Returns an Iterator over the Nodes in this NodeMap, sorted in ascending order + by angle with the positive x-axis. + + + + + Returns the Nodes in this NodeMap, sorted in ascending order + by angle with the positive x-axis. + + + + + Returns the number of Nodes in this NodeMap. + + + + + Represents a directed graph which is embeddable in a planar surface. + This class and the other classes in this package serve as a framework for + building planar graphs for specific algorithms. This class must be + subclassed to expose appropriate methods to construct the graph. This allows + controlling the types of graph components ({DirectedEdge}s, + Edges and Nodes) which can be added to the graph. An + application which uses the graph framework will almost always provide + subclasses for one or more graph components, which hold application-specific + data and graph algorithms. + + + + + + + + + + + + + + + + + + + + Returns the at the given location, or null if no was there. + + The location + The node found
+ or null if this graph contains no node at the location +
+
+ + + Adds a node to the map, replacing any that is already at that location. + Only subclasses can add Nodes, to ensure Nodes are of the right type. + + + The added node. + + + + Adds the Edge and its DirectedEdges with this PlanarGraph. + Assumes that the Edge has already been created with its associated DirectEdges. + Only subclasses can add Edges, to ensure the edges added are of the right class. + + + + + + Adds the Edge to this PlanarGraph; only subclasses can add DirectedEdges, + to ensure the edges added are of the right class. + + + + + + Returns an IEnumerator over the Nodes in this PlanarGraph. + + + + + + Returns the Nodes in this PlanarGraph. + + + + + Returns an Iterator over the DirectedEdges in this PlanarGraph, in the order in which they + were added. + + + + + + Returns an Iterator over the Edges in this PlanarGraph, in the order in which they + were added. + + + + + + Returns the Edges that have been added to this PlanarGraph. + + + + + Removes an Edge and its associated DirectedEdges from their from-Nodes and + from this PlanarGraph. Note: This method does not remove the Nodes associated + with the Edge, even if the removal of the Edge reduces the degree of a + Node to zero. + + + + + + Removes a from its from- and from this PlanarGraph. + + + This method does not remove the s associated with the DirectedEdge, + even if the removal of the DirectedEdge reduces the degree of a Node to zero. + + + + + + Removes a node from the graph, along with any associated DirectedEdges and + Edges. + + + + + + Returns all Nodes with the given number of Edges around it. + + + + + + + A subgraph of a . + A subgraph may contain any subset of s + from the parent graph. + It will also automatically contain all s + and s associated with those edges. + No new objects are created when edges are added - + all associated components must already exist in the parent graph. + + + + + + + + + + + + + + + + + + + + + + + + + Creates a new subgraph of the given . + + + + + + Gets the which this subgraph is part of. + + + + + + Adds an to the subgraph. + The associated s and s are also added. + + The to add. + + + + Returns an over the s in this graph, + in the order in which they were added. + + + + + + Returns an over the s in this graph, + in the order in which they were added. + + + + + + Returns an over the s in this graph. + + + + + + Tests whether an is contained in this subgraph. + + The to test. + true if the is contained in this subgraph. + + + + Determines the maximum number of common most-significant + bits in the mantissa of one or numbers. + Can be used to compute the double-precision number which + is represented by the common bits. + If there are no common bits, the number computed is 0.0. + + + + + Computes the bit pattern for the sign and exponent of a + double-precision number. + + + The bit pattern for the sign and exponent. + + + + This computes the number of common most-significant bits in the mantissas + of two double-precision numbers. + It does not count the hidden bit, which is always 1. + It does not determine whether the numbers have the same exponent - if they do + not, the value computed by this function is meaningless. + + + /// + The number of common most-significant mantissa bits. + + + + Zeroes the lower n bits of a bitstring. + + The bitstring to alter. + the number of bits to zero. + The zeroed bitstring. + + + + Extracts the i'th bit of a bitstring. + + The bitstring to extract from. + The bit to extract. + The value of the extracted bit. + + + + + + + + + + + + + + + A representation of the Double bits formatted for easy readability + + + + + + + Provides versions of Geometry spatial functions which use + common bit removal to reduce the likelihood of robustness problems. + In the current implementation no rounding is performed on the + reshifted result point, which means that it is possible + that the returned Geometry is invalid. + Client classes should check the validity of the returned result themselves. + + + + + Creates a new instance of class, which reshifts result Geometrys. + + + + + Creates a new instance of class, specifying whether + the result Geometrys should be reshifted. + + + + + + Computes the set-theoretic intersection of two Geometrys, using enhanced precision. + + The first Geometry. + The second Geometry. + The Geometry representing the set-theoretic intersection of the input Geometries. + + + + Computes the set-theoretic union of two Geometrys, using enhanced precision. + + The first Geometry. + The second Geometry. + The Geometry representing the set-theoretic union of the input Geometries. + + + + Computes the set-theoretic difference of two Geometrys, using enhanced precision. + + The first Geometry. + The second Geometry, to be subtracted from the first. + The Geometry representing the set-theoretic difference of the input Geometries. + + + Computes the set-theoretic symmetric difference of two geometries, + using enhanced precision. + + The first Geometry. + The second Geometry. + The Geometry representing the set-theoretic symmetric difference of the input Geometries. + + + + Computes the buffer a point, using enhanced precision. + + The Geometry to buffer. + The buffer distance. + The Geometry representing the buffer of the input Geometry. + + + + If required, returning the result to the original precision if required. + In this current implementation, no rounding is performed on the + reshifted result point, which means that it is possible + that the returned Geometry is invalid. + + The result Geometry to modify. + The result Geometry with the required precision. + + + + Computes a copy of the input Geometry with the calculated common bits + removed from each coordinate. + + The Geometry to remove common bits from. + A copy of the input Geometry with common bits removed. + + + + Computes a copy of each input Geometrys with the calculated common bits + removed from each coordinate. + + A Geometry to remove common bits from. + A Geometry to remove common bits from. + + An array containing copies + of the input Geometry's with common bits removed. + + + + + Removes common most-significant mantissa bits + from one or more s. + + The CommonBitsRemover "scavenges" precision + which is "wasted" by a large displacement of the geometry + from the origin. + For example, if a small geometry is displaced from the origin + by a large distance, + the displacement increases the significant figures in the coordinates, + but does not affect the relative topology of the geometry. + Thus the geometry can be translated back to the origin + without affecting its topology. + In order to compute the translation without affecting + the full precision of the coordinate values, + the translation is performed at the bit level by + removing the common leading mantissa bits. + + If the geometry envelope already contains the origin, + the translation procedure cannot be applied. + In this case, the common bits value is computed as zero. + + If the geometry crosses the Y axis but not the X axis + (and mutatis mutandum), + the common bits for Y are zero, + but the common bits for X are non-zero. + + + + + Add a point to the set of geometries whose common bits are + being computed. After this method has executed the + common coordinate reflects the common bits of all added + geometries. + + A Geometry to test for common bits. + + + + The common bits of the Coordinates in the supplied Geometries. + + + + + Removes the common coordinate bits from a Geometry. + The coordinates of the Geometry are changed. + + The Geometry from which to remove the common coordinate bits. + The shifted Geometry. + + + + Adds the common coordinate bits back into a Geometry. + The coordinates of the Geometry are changed. + + The Geometry to which to add the common coordinate bits. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The coordinate sequence + + + + Reduces the precision of the s in a + to match the supplied . + + + Uses . + The input is modified in-place, so + it should be cloned beforehand if the + original should not be modified. + + mbdavis + + + + Creates a new precision reducer filter. + + The PrecisionModel to use + + + + Rounds the Coordinates in the sequence to match the PrecisionModel + + + + + Always runs over all geometry components. + + + + + Always reports that the geometry has changed + + + + + Provides versions of Geometry spatial functions which use + enhanced precision techniques to reduce the likelihood of robustness problems. + + + + + Only static methods! + + + + + Computes the set-theoretic intersection of two Geometrys, using enhanced precision. + + The first Geometry. + The second Geometry. + The Geometry representing the set-theoretic intersection of the input Geometries. + + + + Computes the set-theoretic union of two Geometrys, using enhanced precision. + + The first Geometry. + The second Geometry. + The Geometry representing the set-theoretic union of the input Geometries. + + + + Computes the set-theoretic difference of two Geometrys, using enhanced precision. + + The first Geometry. + The second Geometry. + The Geometry representing the set-theoretic difference of the input Geometries. + + + + Computes the set-theoretic symmetric difference of two Geometrys, using enhanced precision. + + The first Geometry. + The second Geometry. + The Geometry representing the set-theoretic symmetric difference of the input Geometries. + + + + Reduces the precision of a + according to the supplied , + ensuring that the result is valid (unless specified otherwise). + + By default the geometry precision model is not changed. + This can be overridden by using . +

Topological Precision Reduction

+ The default mode of operation ensures the reduced result is topologically valid + (i.e. is true). + To ensure this polygonal geometry is reduced in a topologically valid fashion + (technically, by using snap-rounding). + Note that this may change polygonal geometry structure + (e.g.two polygons separated by a distance below the specified precision + will be merged into a single polygon). + Duplicate vertices are removed. + This mode is invoked by the static method . + + Normally, collapsed linear components(e.g.lines collapsing to a point) + are not included in the result. + This behavior can be changed + by setting to false, + or by using the static method . + + In general input must be valid geometry, or an + will be thrown. However if the invalidity is "mild" or very small then it + may be eliminated by precision reduction. +

Pointwise Precision Reduction

+ Alternatively, geometry can be reduced pointwise by using {@link #setPointwise(boolean)}. + Linear and point geometry are always reduced pointwise(i.e.without further change to + topology or structure), since this does not change validity. + Invalid inputs are allowed. + Duplicate vertices are preserved. + Collapsed components are always included in the result. + The result geometry may be invalid. + + This mode is invoked by the static method . +
+
+ + + Reduces precision of a geometry, ensuring output geometry is valid. + Collapsed linear and polygonal components are removed. + The geometry precision model is not changed. + Invalid input geometry may cause an error, + unless the invalidity is below the scale of the precision reduction. + + The geometry to reduce + The precision model to use + The reduced geometry + Thrwon if the reduction fails due to invalid input geometry + + + + Reduces precision of a geometry, ensuring output polygonal geometry is valid, + and preserving collapsed linear elements. + The geometry precision model is not changed. + Invalid input geometry may cause an error, + unless the invalidity is below the scale of the precision reduction. + + The geometry to reduce + The precision model to use + The reduced geometry + Thrwon if the reduction fails due to invalid input geometry + + + + Reduce precision of a geometry in a pointwise way. + All input geometry elements are preserved in the output, + including invalid polygons and collapsed polygons and linestrings. + The output may not be valid, due to collapse or self-intersection. + The geometry precision model is not changed. + Invalid input geometry is allowed. + + The geometry to reduce + The precision model to use + The reduced geometry + + + Gets or sets whether the reduction will result in collapsed components + being removed completely, or simply being collapsed to an (invalid) + Geometry of the same type. + The default is to remove collapsed components. + + + + + Gets or sets whether the of the new reduced Geometry + will be changed to be the supplied to + specify the precision reduction. + + The default is to not change the precision model + + + + + Gets or sets whether the precision reduction will be done + in pointwise fashion only. + Pointwise precision reduction reduces the precision + of the individual coordinates only, but does + not attempt to recreate valid topology. + This is only relevant for geometries containing polygonal components. + + + + + Reduces the precision of a geometry, + according to the specified strategy of this reducer. + + The geometry to reduce + The precision-reduced geometry + if the reduction fails + due to input geometry is invalid. + + + + Duplicates a geometry to one that uses a different PrecisionModel, + without changing any coordinate values. + + The geometry to duplicate + The precision model to use + The geometry value with a new precision model + + + + Computes the Minimum Clearance of a . + + The Minimum Clearance is a measure of + what magnitude of perturbation of + the vertices of a geometry can be tolerated + before the geometry becomes topologically invalid. + The smaller the Minimum Clearance distance, + the less vertex perturbation the geometry can tolerate + before becoming invalid. + + + The concept was introduced by Thompson and Van Oosterom + [TV06], based on earlier work by Milenkovic [Mi88]. + + The Minimum Clearance of a geometry G + is defined to be the value r + such that "the movement of all points by a distance + of r in any direction will + guarantee to leave the geometry valid" [TV06]. + An equivalent constructive definition [Mi88] is that + r is the largest value such: + + No two distinct vertices of G are closer than r. + No vertex of G is closer than r to an edge of G of which the vertex is not an endpoint + + The following image shows an example of the Minimum Clearance + of a simple polygon. + +
minimum clearance
+ + If G has only a single vertex (i.e. is a + ), the value of the minimum clearance + is . + + If G is a or geometry, + then in fact no amount of perturbation + will render the geometry invalid. + In this case a Minimum Clearance is still computed + based on the vertex and segment distances + according to the constructive definition. + + It is possible for no Minimum Clearance to exist. + For instance, a with all members identical + has no Minimum Clearance + (i.e. no amount of perturbation will cause + the member points to become non-identical). + Empty geometries also have no such distance. + The lack of a meaningful MinimumClearance distance is detected + and suitable values are returned by + and . + + The computation of Minimum Clearance utilizes + the + method to provide good performance even for + large inputs. + + An interesting note is that for the case of s, + the computed Minimum Clearance line + effectively determines the Nearest Neighbours in the collection. +

References

+ + [Mi88] Milenkovic, V. J., + Verifiable implementations of geometric algorithms + using finite precision arithmetic. + in Artificial Intelligence, 377-401. 1988 + [TV06] Thompson, Rod and van Oosterom, Peter, + Interchange of Spatial Data-Inhibiting Factors, + Agile 2006, Visegrad, Hungary. 2006 + +
+ /// Martin Davis +
+ + + Computes the Minimum Clearance distance for + the given Geometry. + + The input geometry + The minimum clearance + + + + Gets a LineString containing two points + which are at the Minimum Clearance distance + for the given Geometry. + + The input geometry + The value of the minimum clearance distance
+ or LINESTRING EMPTY if no minimum clearance distance exists.
+
+ + + Creates an object to compute the Minimum Clearance for the given Geometry + + The input geometry + + + + Gets the Minimum Clearance distance. + If no distance exists + (e.g. in the case of two identical points) + is returned. + + + The value of the minimum clearance distance
+ or if no Minimum Clearance distance exists +
+
+ + + Gets a LineString containing two points + which are at the Minimum Clearance distance. + If no distance could be found + (e.g. in the case of two identical points) + LINESTRING EMPTY is returned. + + The value of the minimum clearance distance,
+ or LINESTRING EMPTY if no minimum clearance distance exists.
+
+ + + Implements the MinimumClearance distance function: + + dist(p1, p2) = + p1 != p2 : p1.distance(p2) + p1 == p2 : Double.MAX + + dist(p, seg) = + p != seq.p1 && p != seg.p2 + ? seg.distance(p) + : Double.MaxValue + + Also computes the values of the nearest points, if any. + + Martin Davis + + + + A transformer to reduce the precision of a geometry pointwise. + + Martin Davis + + + + A transformer to reduce the precision of geometry in a + topologically valid way.
+ Repeated points are removed. + If geometry elements collapse below their valid length, + they may be removed + by specifying isRemoveCollapsed as true. +
+ Martin Davis +
+ + + + + + + + + Computes the minimum clearance of a geometry or + set of geometries. + The Minimum Clearance is a measure of + what magnitude of perturbation of its vertices can be tolerated + by a geometry before it becomes topologically invalid. + + This class uses an inefficient O(N^2) scan. + It is primarily for testing purposes. + + + Martin Davis + + + + Creates a curved geometry by replacing the segments + of the input with Cubic Bezier Curves. + + + The Bezier control points are determined from the segments of the geometry + and the alpha control parameter controlling curvedness, and + the optional skew parameter controlling the shape of the curve at vertices. + The Bezier Curves are created to be C2-continuous (smooth) + at each input vertex. + + Alternatively, the Bezier control points can be supplied explicitly. + + The result is not guaranteed to be valid, since large alpha values + may cause self-intersections. + + + + + Creates a geometry of linearized Cubic Bezier Curves + defined by the segments of the input and a parameter + controlling how curved the result should be. + + The geometry defining the curve + A curvedness parameter (0 is linear, 1 is round, >1 is increasingly curved) + The linearized curved geometry + + + + Creates a geometry of linearized Cubic Bezier Curves + defined by the segments of the inputand a parameter + controlling how curved the result should be, with a skew factor + affecting the curve shape at each vertex. + + The geometry defining the curve + The curvedness parameter (0 is linear, 1 is round, >1 is increasingly curved) + The skew parameter (0 is none, positive skews towards longer side, negative towards shorter + The linearized curved geometry + + + + Creates a geometry of linearized Cubic Bezier Curves + defined by the segments of the input + and a list (or lists) of control points. + + + Typically the control point geometry + is a or + containing an element for each line or ring in the input geometry. + The list of control points for each linear element must contain two + vertices for each segment (and thus 2 * npts - 2). + + The geometry defining the curve + A geometry containing the control point elements. + The linearized curved geometry + + + + Creates a new instance producing a Bezier curve defined by a geometry + and an alpha curvedness value. + + The geometry defining curve + A curvedness parameter (0 = linear, 1 = round, 2 = distorted) + + + + Creates a new instance producing a Bezier curve defined by a geometry, + an alpha curvedness value, and a skew factor. + + The geometry defining curve + curvedness parameter (0 is linear, 1 is round, >1 is increasingly curved) + The skew parameter (0 is none, positive skews towards longer side, negative towards shorter + + + + Creates a new instance producing a Bezier curve defined by a geometry, + and a list (or lists) of control points. + + + Typically the control point geometry + is a or + containing an element for each line or ring in the input geometry. + The list of control points for each linear element must contain two + vertices for each segment (and thus 2 * npts - 2). + + + + + Gets the computed Bezier curve geometry + + The curved geometry + + + + Creates control points for each vertex of curve. + The control points are collinear with each vertex, + thus providing C1-continuity. + By default the control vectors are the same length, + which provides C2-continuity(same curvature on each + side of vertex. + The alpha parameter controls the length of the control vectors. + Alpha = 0 makes the vectors zero-length, and hence flattens the curves. + Alpha = 1 makes the curve at right angles roughly circular. + Alpha > 1 starts to distort the curve and may introduce self-intersections. + + The control point array contains a pair of coordinates for each input segment. + + + + + Sets the end control points for a line. + Produce a symmetric curve for the first and last segments + by using mirrored control points for start and end vertex. + + The coordinates + The control points + + + + Creates a control point aimed at the control point at the opposite end of the segment. + + + + + Calculates vertices along a cubic Bezier curve. + + The start point + The end point + The first control point + The second control point + A set of interpolation parameters + An array to hold generated points. + + + + Gets the interpolation parameters for a Bezier curve approximated by a + given number of vertices. + + The number of vertices + An array of double[4] holding the parameter values + + + + Encodes points as the index along finite planar Hilbert curves. + + The planar Hilbert Curve is a continuous space-filling curve. + In the limit the Hilbert curve has infinitely many vertices and fills + the space of the unit square. + A sequence of finite approximations to the infinite Hilbert curve + is defined by the level number. + The finite Hilbert curve at level n Hₙ contains 2ⁿ⁺¹ points. + Each finite Hilbert curve defines an ordering of the + points in the 2-dimensional range square containing the curve. + Curves fills the range square of side 2ˡᵉᵛᵉˡ. + Curve points have ordinates in the range [0, 2ˡᵉᵛᵉˡ - 1]. + The index of a point along a Hilbert curve is called the Hilbert code. + The code for a given point is specific to the level chosen. + + + This implementation represents codes using 32-bit integers. + This allows levels 0 to 16 to be handled. + The class supports encoding points in the range of a given level curve + and decoding the point for a given code value. + + + The Hilbert order has the property that it tends to preserve locality. + This means that codes which are near in value will have spatially proximate + points. The converse is not always true - the delta between + codes for nearby points is not always small. But the average delta + is small enough that the Hilbert order is an effective way of linearizing space + to support range queries. + + + + Martin Davis + + + + + + + The maximum curve level that can be represented. + + + + + The number of points in the curve for the given level. + The number of points is 2²ˡᵉᵛᵉˡ. + + The level of the curve + The number of points. + + + + The maximum ordinate value for points + in the curve for the given level. + The maximum ordinate is 2ˡᵉᵛᵉˡ - 1. + + The level of the curve. + The maximum ordinate value. + + + + The level of the finite Hilbert curve which contains at least + the given number of points. + + The number of points required. + The level of the curve. + + + + Encodes a point (x,y) + in the range of the the Hilbert curve at a given level + as the index of the point along the curve. + The index will lie in the range [0, 2ˡᵉᵛᵉˡ⁺¹]. + + The level of the Hilbert curve. + The x ordinate of the point. + The y ordinate of the point. + The index of the point along the Hilbert curve. + + + + Clamps a level to the range valid for + the index algorithm used. + + The level of a Hilbert curve. + A valid level. + + + + Computes the point on a Hilbert curve + of given level for a given code index. + The point ordinates will lie in the range [0, 2ˡᵉᵛᵉˡ - 1]. + + The Hilbert curve level. + The index of the point on the curve. + The point on the Hilbert curve. + + + + Generates a representing the Hilbert Curve + at a given level. + + + + + Initializes a new instance of the class + using the provided . + + The geometry factory to use. + + + + Gets or sets the level of curve to generate. + The level must be in the range [0 - 16]. + This determines the + number of points in the generated curve. + + + + + + + + The height of an equilateral triangle of side one + + + + + Encodes points as the index along the planar Morton (Z-order) curve. + + The planar Morton (Z-order) curve is a continuous space-filling curve. + The Morton curve defines an ordering of the + points in the positive quadrant of the plane. + The index of a point along the Morton curve is called the Morton code. + + + A sequence of subsets of the Morton curve can be defined by a level number. + Each level subset occupies a square range. + The curve at level n Mₙ contains 2ⁿ⁺¹ points. + It fills the range square of side 2ˡᵉᵛᵉˡ. + Curve points have ordinates in the range [0, 2ˡᵉᵛᵉˡ - 1]. + The code for a given point is identical at all levels. + The level simply determines the number of points in the curve subset + and the size of the range square. + + + This implementation represents codes using 32-bit integers. + This allows levels 0 to 16 to be handled. + The class supports encoding points + and decoding the point for a given code value. + + + The Morton order has the property that it tends to preserve locality. + This means that codes which are near in value will have spatially proximate + points. The converse is not always true - the delta between + codes for nearby points is not always small. But the average delta + is small enough that the Morton order is an effective way of linearizing space + to support range queries. + + + + Martin Davis + + + + + + + The maximum curve level that can be represented. + + + + + The number of points in the curve for the given level. + The number of points is 2²ˡᵉᵛᵉˡ. + + The level of the curve + The number of points. + + + + The maximum ordinate value for points + in the curve for the given level. + The maximum ordinate is 2ˡᵉᵛᵉˡ - 1. + + The level of the curve. + The maximum ordinate value. + + + + The level of the finite Morton curve which contains at least + the given number of points. + + The number of points required. + The level of the curve. + + + + Computes the index of the point (x,y) + in the Morton curve ordering. + + The x ordinate of the point. + The y ordinate of the point. + The index of the point along the Morton curve. + + + + Computes the point on the Morton curve + for a given index. + + The index of the point on the curve. + The point on the curve. + + + + Generates a representing the Morton Curve + at a given level. + + + + + Initializes a new instance of the class + using the provided . + + The geometry factory to use. + + + + Gets or sets the level of curve to generate. + The level must be in the range [0 - 16]. + + + + + + + + Gets or sets the total number of points in the created . + The created geometry will have no more than this number of points, + unless more are needed to create a valid geometry. + + + + + Creates random point sets contained in a + region defined by either a rectangular or a polygonal extent. + + mbdavis + + + + Create a shape factory which will create shapes using the default + . + + + + + Create a shape factory which will create shapes using the given + + + The factory to use + + + + Sets a polygonal mask. + + if the mask is not polygonal + + + + Creates random point sets where the points + are constrained to lie in the cells of a grid. + + mbdavis + + + + Create a builder which will create shapes using the default + . + + + + + Create a builder which will create shapes using the given + . + + The factory to use + + + + Gets or sets whether generated points are constrained to lie + within a circle contained within each grid cell. + This provides greater separation between points + in adjacent cells. + + The default is to not be constrained to a circle. + + + + + Gets or sets the fraction of the grid cell side which will be treated as + a gutter, in which no points will be created. + + The provided value is clamped to the range [0.0, 1.0]. + + + + + Gets the containing the generated point + + A MultiPoint + + + + Simplifies a line (sequence of points) using + the standard Douglas-Peucker algorithm. + + + + + + + + + + + + + Creates an instance of this class using the provided array of coordinates + + An array of coordinates + + + + The distance tolerance for the simplification. + + + + + + + + + + + Simplifies a using the Douglas-Peucker algorithm. + + + Ensures that any polygonal geometries returned are valid. + Simple lines are not guaranteed to remain simple after simplification. + All geometry types are handled. + Empty and point geometries are returned unchanged. + Empty geometry components are deleted. + + Note that in general D-P does not preserve topology - + e.g. polygons can be split, collapse to lines or disappear + holes can be created or disappear, + and lines can cross. + To simplify point while preserving topology use TopologySafeSimplifier. + (However, using D-P is significantly faster). + + KNOWN BUGS: + In some cases the approach used to clean invalid simplified polygons + can distort the output geometry severely. + + + + + + Simplifies a geometry using a given tolerance. + + The geometry to simplify. + The tolerance to use. + A simplified version of the geometry. + + + + Creates a simplifier for a given geometry. + + The geometry to simplify. + + + + The distance tolerance for the simplification. + + + All vertices in the simplified geometry will be within this + distance of the original geometry. + The tolerance value must be non-negative. + + + + + Controls whether simplified polygons will be "fixed" + to have valid topology. + + + The caller may choose to disable this because: + + valid topology is not required + fixing topology is a relative expensive operation + in some pathological cases the topology fixing operation may either fail or run for too long + + The default is to fix polygon topology. + + + + + Gets the simplified geometry. + + The simplified geometry. + + + + The transformer class + + + + + + + + Simplifies a polygon, fixing it if required. + + The geometry to transform + The parent geometry + + + + + Simplifies a LinearRing. If the simplification results in a degenerate ring, remove the component. + + null if the simplification results in a degenerate ring + + + + + + + Creates a valid area point from one that possibly has + bad topology (i.e. self-intersections). + Since buffer can handle invalid topology, but always returns + valid point, constructing a 0-width buffer "corrects" the + topology. + Note this only works for area geometries, since buffer always returns + areas. This also may return empty geometries, if the input + has no actual area.
+ If the input is empty or is not polygonal, + this ensures that POLYGON EMPTY is returned. +
+ An area point possibly containing self-intersections. + A valid area point. +
+ + + An index of LineSegments. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ItemVisitor subclass to reduce volume of query results. + + + + + + + + + + + + + + + + + + + + + + Simplifies a linestring (sequence of points) using the + Visvalingam-Whyatt algorithm. + The Visvalingam-Whyatt algorithm simplifies geometry + by removing vertices while trying to minimize the area changed. + + 1.7 + + + + A LineSegment which is tagged with its location in a Geometry. + Used to index the segments in a point and recover the segment locations + from the index. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Simplifies a collection of TaggedLineStrings, preserving topology + (in the sense that no new intersections are introduced). + This class is essentially just a container for the common + indexes used by . + + + + + Gets or sets the distance tolerance for the simplification.
+ Points closer than this tolerance to a simplified segment may + be removed. +
+
+ + + Simplifies a collection of TaggedLineStrings. + + The collection of lines to simplify. + + + + Represents a which can be modified to a simplified shape. + This class provides an attribute which specifies the minimum allowable length + for the modified result. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Simplifies a TaggedLineString, preserving topology + (in the sense that no new intersections are introduced). + Uses the recursive Douglas-Peucker algorithm. + + + + + Sets the distance tolerance for the simplification. + All vertices in the simplified geometry will be within this + distance of the original geometry. + + + + + Simplifies the given + using the distance tolerance specified. + + The linestring to simplify. + + + + Flattens a section of the line between + indexes and , + replacing them with a line between the endpoints. + The input and output indexes are updated + to reflect this. + + The start index of the flattened section. + The end index of the flattened section. + The new segment created. + + + + Tests whether a segment is in a section of a . + + + + + + + + + Remove the segs in the section of the line. + + + + + + + + Simplifies a point and ensures that + the result is a valid point having the + same dimension and number of components as the input, + and with the components having the same topological + relationship. + + If the input is a polygonal geometry + ( or ): + + The result has the same number of shells and holes as the input, + with the same topological structure + The result rings touch at no more than the number of touching points in the input + (although they may touch at fewer points). + The key implication of this statement is that if the + input is topologically valid, so is the simplified output. + + For linear geometries, if the input does not contain + any intersecting line segments, this property + will be preserved in the output. + + For all geometry types, the result will contain + enough vertices to ensure validity. For polygons + and closed linear geometries, the result will have at + least 4 vertices; for open LineStrings the result + will have at least 2 vertices. + + All geometry types are handled. + Empty and point geometries are returned unchanged. + Empty geometry components are deleted. + + The simplification uses a maximum-distance difference algorithm + similar to the Douglas-Peucker algorithm. + + +

KNOWN BUGS

+ + May create invalid topology if there are components which are small + relative to the tolerance value. + In particular, if a small hole is very near an edge, + it is possible for the edge to be moved by a relatively large tolerance value + and end up with the hole outside the result shell (or inside another hole). + Similarly, it is possible for a small polygon component to end up inside + a nearby larger polygon. + A workaround is to test for this situation in post-processing and remove + any invalid holes or polygons. + +
+ +
+ + + + + + + + + + + Creates an instance of this class for the provided geometry + + The geometry to simplify + + + + Gets or sets the distance tolerance for the simplification.
+ Points closer than this tolerance to a simplified segment may + be removed. +
+
+ + + + + + + + + A LineString transformer + + + + > + + + + A filter to add linear geometries to the LineString map + with the appropriate minimum size constraint. + Closed s (including s + have a minimum output size constraint of 4, + to ensure the output is valid. + For all other LineStrings, the minimum size is 2 points. + + Martin Davis + + + + Filters linear geometries. + + A geometry of any type + + + + Simplifies a linestring (sequence of points) using the + Visvalingam-Whyatt algorithm. + The Visvalingam-Whyatt algorithm simplifies geometry + by removing vertices while trying to minimize the area changed. + + 1.7 + + + + Simplifies a using the Visvalingam-Whyatt area-based algorithm. + Ensures that any polygonal geometries returned are valid. Simple lines are not + guaranteed to remain simple after simplification. All geometry types are + handled. Empty and point geometries are returned unchanged. Empty geometry + components are deleted. + The simplification tolerance is specified as a distance. + This is converted to an area tolerance by squaring it. + + Known Bugs + * Not yet optimized for performance. + * Does not simplify the endpoint of rings. + To Do + * Allow specifying desired number of vertices in the output. + + + + Note that in general this algorithm does not preserve topology - e.g. polygons can be split, + collapse to lines or disappear holes can be created or disappear, and lines + can cross. + + 1.7 + + + + Simplifies a using a given tolerance. + + The to simplify. + The tolerance to use. + A simplified version of the . + + + + Creates a simplifier for a given . + + The to simplify. + + + + Sets the distance tolerance for the simplification. All vertices in the + simplified will be within this distance of the original geometry. + The tolerance value must be non-negative. + + + + + Controls whether simplified polygons will be "fixed" to have valid + topology. The caller may choose to disable this because: + * valid topology is not required. + * fixing topology is a relative expensive operation. + * in some pathological cases the topology fixing operation may either + fail or run for too long. + + The default is to fix polygon topology. + + + + Gets the simplified . + + The simplified . + + + + Simplifies a , fixing it if required. + + + + + + + + Simplifies a . If the simplification results in a degenerate + ring, remove the component. + + + + null if the simplification results in a degenerate ring. + + + + Simplifies a , fixing it if required. + + + + + + + + Creates a valid area geometry from one that possibly has bad topology + (i.e. self-intersections). Since buffer can handle invalid topology, but + always returns valid geometry, constructing a 0-width buffer "corrects" + the topology. Note this only works for area geometries, since buffer + always returns areas. This also may return empty geometries, if the input + has no actual area. + + An area geometry possibly containing self-intersections. + A valid area geometry. + + + + A utility class which creates Conforming Delaunay Triangulations + from collections of points and linear constraints, and extract the resulting + triangulation edges or triangles as geometries. + + Martin Davis + + + + Sets the sites (point or vertices) which will be triangulated. + All vertices of the given geometry will be used as sites. + The site vertices do not have to contain the constraint + vertices as well; any site vertices which are + identical to a constraint vertex will be removed + from the site vertex set. + + The geometry from which the sites will be extracted. + + + + Sets the linear constraints to be conformed to. + All linear components in the input will be used as constraints. + The constraint vertices do not have to be disjoint from + the site vertices. + The constraints must not contain duplicate segments (up to orientation). + + + + + Sets the snapping tolerance which will be used + to improved the robustness of the triangulation computation. + A tolerance of 0.0 specifies that no snapping will take place. + + + + + Gets the QuadEdgeSubdivision which models the computed triangulation. + + The subdivision containing the triangulation + + + + Gets the edges of the computed triangulation as a . + + The geometry factory to use to create the output + the edges of the triangulation + + + + Gets the faces of the computed triangulation as a + of . + + the geometry factory to use to create the output + the faces of the triangulation + + + + Computes a Conforming Delaunay Triangulation over a set of sites and a set of + linear constraints. + + + + A conforming Delaunay triangulation is a true Delaunay triangulation. In it + each constraint segment is present as a union of one or more triangulation + edges. Constraint segments may be subdivided into two or more triangulation + edges by the insertion of additional sites. The additional sites are called + Steiner points, and are necessary to allow the segments to be faithfully + reflected in the triangulation while maintaining the Delaunay property. + Another way of stating this is that in a conforming Delaunay triangulation + every constraint segment will be the union of a subset of the triangulation + edges (up to tolerance). + + + A Conforming Delaunay triangulation is distinct from a Constrained Delaunay triangulation. + A Constrained Delaunay triangulation is not necessarily fully Delaunay, + and it contains the constraint segments exactly as edges of the triangulation. + + + A typical usage pattern for the triangulator is: + + ConformingDelaunayTriangulator cdt = new ConformingDelaunayTriangulator(sites, tolerance); + + // optional + cdt.SplitPointFinder = splitPointFinder; + cdt.VertexFactory = vertexFactory; + + cdt.SetConstraints(segments, new List<Vertex>(vertexMap.Values)); + cdt.FormInitialDelaunay(); + cdt.EnforceConstraints(); + subdiv = cdt.Subdivision; + + + + David Skea + Martin Davis + + + + Creates a Conforming Delaunay Triangulation based on the given + unconstrained initial vertices. The initial vertex set should not contain + any vertices which appear in the constraint set. + + a collection of + the distance tolerance below which points are considered identical + + + + Sets the constraints to be conformed to by the computed triangulation. + The constraints must not contain duplicate segments (up to orientation). + The unique set of vertices (as es) + forming the constraints must also be supplied. + Supplying it explicitly allows the ConstraintVertexes to be initialized + appropriately (e.g. with external data), and avoids re-computing the unique set + if it is already available. + + list of the constraint s + the set of unique es referenced by the segments + + + + Gets or sets the to be + used during constraint enforcement. + Different splitting strategies may be appropriate + for special situations. + + the ConstraintSplitPointFinder to be used + + + + Gets the tolerance value used to construct the triangulation. + + a tolerance value + + + + Gets and sets the used to create new constraint vertices at split points. + + Allows the setting of a custom to be used + to allow vertices carrying extra information to be created. + + + + + Gets the which represents the triangulation. + + + + + Gets the which contains the vertices of the triangulation. + + + + + Gets the sites (vertices) used to initialize the triangulation. + + + + + Gets the s which represent the constraints. + + + + + Gets the convex hull of all the sites in the triangulation, + including constraint vertices. + Only valid after the constraints have been enforced. + + the convex hull of the sites + + + + Creates a vertex on a constraint segment + + the location of the vertex to create + the constraint segment it lies on + the new constraint vertex + + + + Inserts all sites in a collection + + a collection of ConstraintVertex + + + + Inserts a site into the triangulation, maintaining the conformal Delaunay property. + This can be used to further refine the triangulation if required + (e.g. to approximate the medial axis of the constraints, + or to improve the grading of the triangulation). + + the location of the site to insert + + + + Computes the Delaunay triangulation of the initial sites. + + + + + Enforces the supplied constraints into the triangulation. + + + if the constraints cannot be enforced + + + + Given a set of points stored in the kd-tree and a line segment defined by + two points in this set, finds a in the circumcircle of + the line segment, if one exists. This is called the Gabriel point - if none + exists then the segment is said to have the Gabriel condition. Uses the + heuristic of finding the non-Gabriel point closest to the midpoint of the + segment. + + the line segment + + A point which is non-Gabriel, + or null if no point is non-Gabriel + + + + + Indicates a failure during constraint enforcement. + + Martin Davis + 1.0 + + + + Creates a new instance with a given message. + + a string + + + + Creates a new instance with a given message and approximate location. + + a string + the location of the error + + + + Gets the approximate location of this error. + + a location + + + + A vertex in a Constrained Delaunay Triangulation. + The vertex may or may not lie on a constraint. + If it does it may carry extra information about the original constraint. + + Martin Davis + + + + Creates a new constraint vertex + + the location of the vertex + + + + Gets or sets whether this vertex lies on a constraint. + + true if the vertex lies on a constraint + + + + Gets or sets the external constraint object + + object which carries information about the constraint this vertex lies on + + + + Merges the constraint data in the vertex other into this vertex. + This method is called when an inserted vertex is + very close to an existing vertex in the triangulation. + + the constraint vertex to merge + + + + An interface for factories which create a + + Martin Davis + + + + A utility class which creates Delaunay Triangulations + from collections of points and extract the resulting + triangulation edges or triangles as geometries. + + Martin Davis + + + + Extracts the unique s from the given . + + the geometry to extract from + a List of the unique Coordinates + + + + Converts all s in a collection to es. + + the coordinates to convert + a List of Vertex objects + + + + Computes the of a collection of s. + + a List of Coordinates + the envelope of the set of coordinates + + + + Sets the sites (vertices) which will be triangulated. + All vertices of the given geometry will be used as sites. + + the geometry from which the sites will be extracted. + + + + Sets the sites (vertices) which will be triangulated + from a collection of s. + + a collection of Coordinates. + + + + Sets the snapping tolerance which will be used + to improved the robustness of the triangulation computation. + A tolerance of 0.0 specifies that no snapping will take place. + + + + + Gets the which models the computed triangulation. + + the subdivision containing the triangulation + + + + Gets the edges of the computed triangulation as a . + + the geometry factory to use to create the output + the edges of the triangulation + + + + Gets the faces of the computed triangulation as a + of . + + the geometry factory to use to create the output + the faces of the triangulation + + + + An interface for strategies for determining the location of split points on constraint segments. + The location of split points has a large effect on the performance and robustness of enforcing a + constrained Delaunay triangulation. Poorly chosen split points can cause repeated splitting, + especially at narrow constraint angles, since the split point will end up encroaching on the + segment containing the original encroaching point. With detailed knowledge of the geometry of the + constraints, it is sometimes possible to choose better locations for splitting. + + mbdavis + + + + Finds a point at which to split an encroached segment to allow the original segment to appear + as edges in a constrained Delaunay triangulation. + + the encroached segment + the encroaching point + the point at which to split the encroached segment + + + + Computes a Delaunay Triangulation of a set of es, using an + incremental insertion algorithm. + + Martin Davis + 1.0 + + + + Creates a new triangulator using the given . + The triangulator uses the tolerance of the supplied subdivision. + + a subdivision in which to build the TIN + + + + Inserts all sites in a collection. The inserted vertices MUST be + unique up to the provided tolerance value. (i.e. no two vertices should be + closer than the provided tolerance value). They do not have to be rounded + to the tolerance grid, however. + + a Collection of Vertex + if the location algorithm fails to converge in a reasonable number of iterations + + + + Inserts a new point into a subdivision representing a Delaunay + triangulation, and fixes the affected edges so that the result is still a + Delaunay triangulation. + + a quadedge containing the inserted vertex + + + + A simple split point finder which returns the midpoint of the split segment. This is a default + strategy only. Usually a more sophisticated strategy is required to prevent repeated splitting. + Other points which could be used are: +
    +
  • The projection of the encroaching point on the segment
  • +
  • A point on the segment which will produce two segments which will not be further encroached
  • +
  • The point on the segment which is the same distance from an endpoint as the encroaching
  • + point +
+
+ Martin Davis +
+ + + Gets the midpoint of the split segment + + + + + A strategy for finding constraint split points which attempts to maximise the length of the split + segments while preventing further encroachment. (This is not always possible for narrow angles). + + Martin Davis + + + + A basic strategy for finding split points when nothing extra is known about the geometry of + the situation. + + the encroached segment + the encroaching point + the point at which to split the encroached segment + + + + Computes a split point which is the projection of the encroaching point on the segment + + The segment + The enchroaching point + A split point on the segment + + + + Computes the Constrained Delaunay Triangulation of polygons. + The Constrained Delaunay Triangulation of a polygon is a set of triangles + covering the polygon, with the maximum total interior angle over all + possible triangulations. It provides the "best quality" triangulation + of the polygon. + + Holes are supported. + + Martin Davis + + + + Computes the Constrained Delaunay Triangulation of each polygon element in a geometry. + + The input geometry + A GeometryCollection of the computed triangle polygons + + + + Constructs a new Constrained Delaunay triangulator. + + The input geometry + + + + Gets the triangulation as a of triangular s. + + A collection of the result triangle polygons + + + + Gets the triangulation as a list of s. + + The list of Tris in the triangulation + + + + Computes the triangulation of a single polygon + and returns it as a list of s. + + The input polygon + A list of Tris forming the triangulation + + + + Triangulates a polygon using the Ear-Clipping technique. + The polygon is provided as a closed list of contiguous vertices + defining its boundary. + The vertices must have clockwise orientation. + + The polygon boundary must not self-cross, + but may self-touch at points or along an edge. + It may contain repeated points, which are treated as a single vertex. + By default every vertex is triangulated, + including ones which are "flat" (the adjacent segments are collinear). + These can be removed by setting . + + The polygon representation does not allow holes. + Polygons with holes can be triangulated by preparing them with . + + Martin Davis + + + + Triangulates a polygon via ear-clipping. + + The vertices of the polygon + A list of Tris + + + + The polygon vertices are provided in CW orientation. + Thus for convex interior angles + the vertices forming the angle are in CW orientation. + + + + + Indexing vertices improves ear intersection testing performance. + The polyShell vertices are contiguous, so are suitable for an SPRtree. + Note that a KDtree cannot be used because the vertex indices must be stored + and duplicates must be stored. + + + + + Creates a new instance of this class + + The vertices of the polygon to process + + + + Gets or sets whether flat corners formed by collinear adjacent line segments + are included in the triangulation. + Skipping flat corners reduces the number of triangles in the output. + However, it produces a triangulation which does not include + all input vertices. This may be undesirable for downstream processes + (such as computing a Constrained Delaunay Triangulation for + purposes of computing the medial axis). + + The default is to include all vertices in the result triangulation. + This still produces a valid triangulation, with no zero-area triangles. + + Note that repeated vertices are always skipped. + + A flag indicating if flat corners formed by collinear adjacent line segments + are included in the triangulation + + + + Finds a vertex contained in the corner triangle, if any. + Uses the vertex spatial index for efficiency. + + Also finds any vertex which is a duplicate of the corner apex vertex. + This requires a full scan of the vertices to confirm ear is valid. + This is usually a rare situation, so has little impact on performance. + + The index of the corner apex vertex + The corner vertices + The index of an intersecting or duplicate vertex, or if none + + + + Scan all vertices in current ring to check if any are duplicates + of the corner apex vertex, and if so whether the corner ear + intersects the adjacent segments and thus is invalid. + + The index of the corner apex + The corner vertices + true if the corner ia a valid ear + + + + Remove the corner apex vertex and update the candidate corner location. + + + + + Fetch the corner vertices from the indices. + + An array for the corner vertices + + + + Move to next corner. + + + + + Get the index of the next available shell coordinate starting from the given index. + + Coordinate position + Index of the next available shell coordinate + + + + Detects if a corner has repeated points (AAB or ABB), or is collapsed (ABA). + + The corner points + true if the corner is flat or collapsed + + + + Transforms a polygon with holes into a single self-touching (invalid) ring + by connecting holes to the exterior shell or to another hole. + The holes are added from the lowest upwards. + As the resulting shell develops, a hole might be added to what was + originally another hole. + + There is no attempt to optimize the quality of the join lines. + In particular, a hole which already touches at a vertex may be + joined at a different vertex. + + + + + Computes the joined ring. + + The points in the joined ring + + + + Adds a coordinate to the set and + clears the array. + + A coordinate + + + + Joins a single hole to the current shellRing. + + The hole to join + + + + Get the i'th in that the current should add after + + The coordinate of the shell vertex + The coordinate of the hole vertex + The i'th shellvertex + + + + Find the index of the coordinate in ShellCoords ArrayList, + skipping over some number of matches + + + + + + + + Gets a list of shell vertices that could be used to join with the hole. + This list contains only one item if the chosen vertex does not share the same + x value with + + The hole coordinate + A list of candidate join vertices + + + + Determine if a line segment between a hole vertex + and a shell vertex lies inside the input polygon. + + A hole coordinate + A shell coordinate + true if the line lies inside the polygon + + + + Tests whether a line segment crosses the polygon boundary. + + A vertex + A vertex + true if the line segment crosses the polygon boundary + + + + Add hole at proper position in shell coordinate list. + Also adds hole points to ordered coordinates. + + + + + + + + Sort the holes by minimum X, minimum Y. + + Polygon that contains the holes + A list of ordered hole geometry + + + + Gets a list of indices of the leftmost vertices in a ring. + + The hole ring + Index of the left most vertex + + + + Computes a triangulation of each polygon in a {@link Geometry}. + A polygon triangulation is a non-overlapping set of triangles which + cover the polygon and have the same vertices as the polygon. + The priority is on performance rather than triangulation quality, + so that the output may contain many narrow triangles. + + Holes are handled by joining them to the shell to form a + (self-touching) polygon shell with no holes. + Although invalid, this can be triangulated effectively. + + For better-quality triangulation use . + + + Martin Davis + + + + Computes a triangulation of each polygon in a geometry. + + A geometry containing polygons + A GeometryCollection containing the polygons + + + + Constructs a new triangulator. + + The input geometry + + + + Gets the triangulation as a of triangular s. + + A collection of the result triangle polygons + + + + Gets the triangulation as a list of s. + + The list of Tris in the triangulation + + + + Computes the triangulation of a single polygon + + A list of triangular polygons + + + + Improves the quality of a triangulation of s via + iterated Delaunay flipping. + This produces a Constrained Delaunay Triangulation + with the constraints being the boundary of the input triangulation. + + Martin Davis + + + + Improves the quality of a triangulation of {@link Tri}s via + iterated Delaunay flipping. + The Tris are assumed to be linked into a Triangulation + (e.g. via ). + + The list of Tris to improve + + + Improves a triangulation by examining pairs of adjacent triangles + (forming a quadrilateral) and testing if flipping the diagonal of + the quadrilateral would produce two new triangles with larger minimum + interior angles. + + The number of flips that were made + + + + Does a flip of the common edge of two Tris if the Delaunay condition is not met. + + A Tri + The index of the + true if the triangles were flipped + + + + Tests if the quadrilateral formed by two adjacent triangles is convex. + opp0-adj0-adj1 and opp1-adj1-adj0 are the triangle corners + and hence are known to be convex. + The quadrilateral is convex if the other corners opp0-adj0-opp1 + and opp1-adj1-opp0 have the same orientation (since at least one must be convex). + + The adjacent edge vertex 0 + The adjacent edge vertex 1 + The corner vertex of triangle 0 + The corner vertex of triangle 1 + true if the quadrilateral is convex + + + + Tests if either of a pair of adjacent triangles satisfy the Delaunay condition. + The triangles are opp0-adj0-adj1 and opp1-adj1-adj0. + The Delaunay condition is not met if one opposite vertex + lies is in the circumcircle of the other triangle. + + The adjacent edge vertex 0 + The adjacent edge vertex 1 + The corner vertex of triangle 0 + The corner vertex of triangle 1 + true if the triangles are Delaunay + + + + Tests whether a point p is in the circumcircle of a triangle abc + (oriented clockwise). + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point + true if the point is in the circumcircle + + + + A semi-static spatial index for points which occur + in a spatially-coherent sequence. + In particular, this is suitable for indexing the vertices + of a {@link LineString} or {@link Polygon} ring. + + The index is constructed in a batch fashion on a given sequence of coordinates. + Coordinates can be removed via the {@link #remove(int)} method. + + Note that this index queries only the individual points + of the input coordinate sequence, + not any line segments which might be lie between them. + + Martin Davis + + + + Number of items/nodes in a parent node. + Determined empirically. Performance is not too sensitive to this. + + + + + Creates a new tree over the given sequence of coordinates. + The sequence should be spatially coherent to provide query performance. + + A sequence of points + + + + Computes the level offsets. + This is the position in the bounds array of each level. + The levelOffsets array includes a sentinel value of offset[0] = 0. + The top level is always of size 1, + and so also indicates the total number of bounds. + + The level offsets + + + + Queries the index to find all items which intersect an extent. + The query result is a list of the indices of input coordinates + which intersect the extent. + + The query extent + An array of the indices of the input coordinates + + + + Removes the input item at the given index from the spatial index. + + Index the index of the item in the input + + + + A framework to visit sets of edge-connected s in breadth-first order + + Martin Davis + 1.0 + + + + Called to initialize the traversal queue with a given set of s + + a collection of QuadEdgeTriangle + + + + Subclasses call this method to perform the visiting process. + + + + + An interface for classes which locate an edge in a + which either contains a given V + or is an edge of a triangle which contains V. + Implementors may utilized different strategies for + optimizing locating containing edges/triangles. + + Martin Davis + + + + Interface for classes which process triangles visited during traversals of a + + + Martin Davis + + + + Visits a triangle during a traversal of a . An implementation of + this method may perform processing on the current triangle. It must also decide whether a + neighbouring triangle should be added to the queue so its neighbours are visited. Often it + will perform processing on the neighbour triangle as well, in order to mark it as processed + (visited) and/or to determine if it should be visited. Note that choosing not to + visit the neighbouring triangle is the terminating condition for many traversal algorithms. + In particular, if the neighbour triangle has already been visited, it should not be visited + again. + + the current triangle being processed + the index of the edge in the current triangle being traversed + a neighbouring triangle next in line to visit + true if the neighbour triangle should be visited + + + + An interface for algorithms which process the triangles in a . + + Martin Davis + 1.0 + + + + Visits the s of a triangle. + + an array of the 3 quad edges in a triangle (in CCW order) + + + + Locates s in a , + optimizing the search by starting in the + locality of the last edge found. + + Martin Davis + + + + Locates an edge e, such that either v is on e, or e is an edge of a triangle containing v. + The search starts from the last located edge and proceeds on the general direction of v. + + + + + A class that represents the edge data structure which implements the quadedge algebra. + The quadedge algebra was described in a well-known paper by Guibas and Stolfi, + "Primitives for the manipulation of general subdivisions and the computation of Voronoi diagrams", + ACM Transactions on Graphics, 4(2), 1985, 75-123. + + Each edge object is part of a quartet of 4 edges, + linked via their Rot references. + Any edge in the group may be accessed using a series of operations. + Quadedges in a subdivision are linked together via their Next references. + The linkage between the quadedge quartets determines the topology + of the subdivision. + + + The edge class does not contain separate information for vertices or faces; a vertex is implicitly + defined as a ring of edges (created using the Next field). + + + David Skea + Martin Davis + + + + Creates a new QuadEdge quartet from o to d. + + the origin Vertex + the destination Vertex + the new QuadEdge quartet + + + + Creates a new QuadEdge connecting the destination of a to the origin of + b, in such a way that all three have the same left face after the + connection is complete. Additionally, the data pointers of the new edge + are set. + + the connected edge + + + + Splices two edges together or apart. + Splice affects the two edge rings around the origins of a and b, and, independently, the two + edge rings around the left faces of a and b. + In each case, (i) if the two rings are distinct, + Splice will combine them into one, or (ii) if the two are the same ring, Splice will break it + into two separate pieces. Thus, Splice can be used both to attach the two edges together, and + to break them apart. + + an edge to splice + an edge to splice + + + + Turns an edge counterclockwise inside its enclosing quadrilateral. + + the quadedge to turn + + + + Quadedges must be made using {@link makeEdge}, + to ensure proper construction. + + + + + Gets the primary edge of this quadedge and its sym. + The primary edge is the one for which the origin + and destination coordinates are ordered + according to the standard ordering + + the primary quadedge + + + + Gets or sets the external data value for this edge. + + + an object containing external data + + + + + Marks this quadedge as being deleted. + This does not free the memory used by + this quadedge quartet, but indicates + that this edge no longer participates + in a subdivision. + + + + + Tests whether this edge has been deleted. + + true if this edge has not been deleted. + + + + Sets the connected edge + + edge + + + + Gets the dual of this edge, directed from its right to its left. + + Gets or Sets the rotated edge + + + + Gets the dual of this edge, directed from its left to its right. + + Gets the inverse rotated edge. + + + + Gets the edge from the destination to the origin of this edge. + + Gets the sym of the edge. + + + + Gets the next CCW edge around the origin of this edge. + + Gets the next linked edge. + + + + Gets the next CW edge around (from) the origin of this edge. + + Gets the previous edge. + + + + Gets the next CCW edge around (into) the destination of this edge. + + Get the next destination edge. + + + + Gets the next CW edge around (into) the destination of this edge. + + Get the previous destination edge. + + + + Gets the CCW edge around the left face following this edge. + + Gets the next left face edge. + + + + Gets the CCW edge around the left face before this edge. + + Get the previous left face edge. + + + + Gets the edge around the right face ccw following this edge. + + Gets the next right face edge. + + + + Gets the edge around the right face ccw before this edge. + + Gets the previous right face edge. + + + + Gets or sets the vertex for the edge's origin + + Gets the origin vertex + + + + Gets or sets the vertex for the edge's destination + + Gets the destination vertex + + + + Gets the length of the geometry of this quadedge. + + Gets the length of the quadedge + + + + Tests if this quadedge and another have the same line segment geometry, + regardless of orientation. + + a quadedge + true if the quadedges are based on the same line segment regardless of orientation + + + + Tests if this quadedge and another have the same line segment geometry + with the same orientation. + + a quadedge + true if the quadedges are based on the same line segment + + + + Creates a representing the + geometry of this edge. + + a LineSegment + + + + Converts this edge to a WKT two-point LINESTRING indicating + the geometry of this edge. + + a String representing this edge's geometry + + + + A class that contains the s representing a planar + subdivision that models a triangulation. + The subdivision is constructed using the + quadedge algebra defined in the class . + All metric calculations + are done in the class. + In addition to a triangulation, subdivisions + support extraction of Voronoi diagrams. + This is easily accomplished, since the Voronoi diagram is the dual + of the Delaunay triangulation. + + Subdivisions can be provided with a tolerance value. Inserted vertices which + are closer than this value to vertices already in the subdivision will be + ignored. Using a suitable tolerance value can prevent robustness failures + from happening during Delaunay triangulation. + + + Subdivisions maintain a frame triangle around the client-created + edges. The frame is used to provide a bounded "container" for all edges + within a TIN. Normally the frame edges, frame connecting edges, and frame + triangles are not included in client processing. + + + David Skea + Martin Davis + + + + Gets the edges for the triangle to the left of the given . + + + + if the edges do not form a triangle + + + + Creates a new instance of a quad-edge subdivision based on a frame triangle + that encloses a supplied bounding box. A new super-bounding box that + contains the triangle is computed and stored. + + the bounding box to surround + the tolerance value for determining if two sites are equal + + + + Gets the vertex-equality tolerance value + used in this subdivision + + Gets the tolerance value + + + + Gets the envelope of the Subdivision (including the frame). + + Gets the envelope + + + + Gets the collection of base s (one for every pair of + vertices which is connected). + + a collection of QuadEdges + + + + Sets the to use for locating containing triangles + in this subdivision. + + a QuadEdgeLocator + + + + Creates a new quadedge, recording it in the edges list. + + The origin vertex + The destination vertex + A new quadedge + + + + Creates a new QuadEdge connecting the destination of a to the origin of b, + in such a way that all three have the same left face after the connection + is complete. The quadedge is recorded in the edges list. + + A quadedge + A quadedge + A quadedge + + + + Deletes a quadedge from the subdivision. Linked quadedges are updated to + reflect the deletion. + + the quadedge to delete + + + + Locates an edge of a triangle which contains a location + specified by a Vertex v. + The edge returned has the + property that either v is on e, or e is an edge of a triangle containing v. + The search starts from startEdge amd proceeds on the general direction of v. + + + This locate algorithm relies on the subdivision being Delaunay. For + non-Delaunay subdivisions, this may loop for ever. + + the location to search for + an edge of the subdivision to start searching at + a QuadEdge which contains v, or is on the edge of a triangle containing v + + if the location algorithm fails to converge in a reasonable + number of iterations + + + + + Finds a quadedge of a triangle containing a location + specified by a , if one exists. + + the vertex to locate + a quadedge on the edge of a triangle which touches or contains the location
+ or null if no such triangle exists +
+
+ + + Finds a quadedge of a triangle containing a location + specified by a , if one exists. + + the Coordinate to locate + a quadedge on the edge of a triangle which touches or contains the location, + or null if no such triangle exists + + + + + Locates the edge between the given vertices, if it exists in the + subdivision. + + a coordinate + another coordinate + the edge joining the coordinates, if present, + or null if no such edge exists + + + + + Inserts a new site into the Subdivision, connecting it to the vertices of + the containing triangle (or quadrilateral, if the split point falls on an + existing edge). + + + + This method does NOT maintain the Delaunay condition. If desired, this must + be checked and enforced by the caller. + + + This method does NOT check if the inserted vertex falls on an edge. This + must be checked by the caller, since this situation may cause erroneous + triangulation + + + the vertex to insert + a new quad edge terminating in v + + + + Tests whether a QuadEdge is an edge incident on a frame triangle vertex. + + the edge to test + true if the edge is connected to the frame triangle + + + + Tests whether a QuadEdge is an edge on the border of the frame facets and + the internal facets. E.g. an edge which does not itself touch a frame + vertex, but which touches an edge which does. + + the edge to test + true if the edge is on the border of the frame + + + + Tests whether a vertex is a vertex of the outer triangle. + + the vertex to test + true if the vertex is an outer triangle vertex + + + + Tests whether a {@link Coordinate} lies on a {@link QuadEdge}, up to a + tolerance determined by the subdivision tolerance. + + a QuadEdge + a point + true if the vertex lies on the edge + + + + Tests whether a is the start or end vertex of a + , up to the subdivision tolerance distance. + + + + true if the vertex is a endpoint of the edge + + + + Gets the unique es in the subdivision, + including the frame vertices if desired. + + true if the frame vertices should be included + a collection of the subdivision vertices + + + + + Gets a collection of s whose origin + vertices are a unique set which includes + all vertices in the subdivision. + The frame vertices can be included if required. + + + This is useful for algorithms which require traversing the + subdivision starting at all vertices. + Returning a quadedge for each vertex + is more efficient than + the alternative of finding the actual vertices + using and then locating + quadedges attached to them. + + true if the frame vertices should be included + a collection of QuadEdge with the vertices of the subdivision as their origins + + + + Gets all primary quadedges in the subdivision. + A primary edge is a + which occupies the 0'th position in its array of associated quadedges. + These provide the unique geometric edges of the triangulation. + + true if the frame edges are to be included + a List of QuadEdges + + + + A TriangleVisitor which computes and sets the + circumcentre as the origin of the dual + edges originating in each triangle. + + mbdavis + + + + The quadedges forming a single triangle. + Only one visitor is allowed to be active at a + time, so this is safe. + + + + + Stores the edges for a visited triangle. Also pushes sym (neighbour) edges + on stack to visit later. + + + + + + the visited triangle edges,
+ or null if the triangle should not be visited (for instance, if it is outer) +
+
+ + + Gets a list of the triangles + in the subdivision, specified as + an array of the primary quadedges around the triangle. + + true if the frame triangles should be included + a List of QuadEdge[3] arrays + + + + Gets a list of the triangles in the subdivision, + specified as an array of the triangle es. + + true if the frame triangles should be included + a List of Vertex[3] arrays + + + + Gets the coordinates for each triangle in the subdivision as an array. + + true if the frame triangles should be included + a list of Coordinate[4] representing each triangle + + + + Gets the geometry for the edges in the subdivision as a + containing 2-point lines. + + the GeometryFactory to use + a MultiLineString + + + + Gets the geometry for the triangles in a triangulated subdivision as a + of triangular s. + + the GeometryFactory to use + a GeometryCollection of triangular Polygons + + + + Gets the cells in the Voronoi diagram for this triangulation. + The cells are returned as a of s + + + The userData of each polygon is set to be the + of the cell site. This allows easily associating external + data associated with the sites to the cells. + + a geometry factory + a GeometryCollection of Polygons + + + + Gets a List of s for the Voronoi cells + of this triangulation. + + + The UserData of each polygon is set to be the + of the cell site. This allows easily associating external + data associated with the sites to the cells. + + a geometry factory + a List of Polygons + + + + Gets the Voronoi cell around a site specified + by the origin of a QuadEdge. + + + The userData of the polygon is set to be the + of the site. This allows attaching external + data associated with the site to this cell polygon. + + a quadedge originating at the cell site + a factory for building the polygon + a polygon indicating the cell extent + + + + Models a triangle formed from s in a + which forms a triangulation. The class provides methods to access the + topological and geometric properties of the triangle and its neighbours in + the triangulation. Triangle vertices are ordered in CCW orientation in the + structure. + + + QuadEdgeTriangles support having an external data attribute attached to them. + Alternatively, this class can be subclassed and attributes can + be defined in the subclass. Subclasses will need to define + their own BuilderVisitor class + and CreateOn method. + + Martin Davis + 1.0 + + + + Creates s for all facets of a + representing a triangulation. + The data attributes of the s in the subdivision + will be set to point to the triangle which contains that edge. + This allows tracing the neighbour triangles of any given triangle. + + The QuadEdgeSubdivision to create the triangles on. + A List of the created QuadEdgeTriangles + + + + Tests whether the point pt is contained in the triangle defined by 3 es. + + an array containing at least 3 Vertexes + the point to test + true if the point is contained in the triangle + + + + Tests whether the point pt is contained in the triangle defined by 3 es. + + an array containing at least 3 QuadEdges + the point to test + true if the point is contained in the triangle + + + + Creates a new triangle from the given edges. + + An array of the edges of the triangle in CCW order + + + + Gets or sets the external data value for this triangle. + + + + + Gets the vertices for this triangle. + + a new array containing the triangle vertices + + + + Gets the index for the given edge of this triangle + + a QuadEdge + the index of the edge in this triangle,
+ or -1 if the edge is not an edge of this triangle +
+
+ + + Gets the index for the edge that starts at vertex v. + + the vertex to find the edge for + the index of the edge starting at the vertex,
+ or -1 if the vertex is not in the triangle +
+
+ + + + + + Tests whether this triangle is adjacent to the outside of the subdivision. + + true if the triangle is adjacent to the subdivision exterior + + + + Gets the triangles which are adjacent (include) to a + given vertex of this triangle. + + The vertex to query + A list of the vertex-adjacent triangles + + + + Gets the neighbours of this triangle. If there is no neighbour triangle, the array element is + null + + an array containing the 3 neighbours of this triangle + + + + Gets all edges which are incident on the origin of the given edge. + + the edge to start at + a List of edges which have their origin at the origin of the given + edge + + + + Algorithms for computing values and predicates + associated with triangles. + + + For some algorithms extended-precision + implementations are provided, which are more robust + (i.e. they produce correct answers in more cases). + Also, some more robust formulations of + some algorithms are provided, which utilize + normalization to the origin. + + Martin Davis + + + + Tests if a point is inside the circle defined by + the triangle with vertices a, b, c (oriented counter-clockwise). + This test uses simple + double-precision arithmetic, and thus is not 100% robust. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point to test + true if this point is inside the circle defined by the points a, b, c + + + + Tests if a point is inside the circle defined by + the triangle with vertices a, b, c (oriented counter-clockwise). + + + This test uses simple + double-precision arithmetic, and thus is not 100% robust. + However, by using normalization to the origin + it provides improved robustness and increased performance. + Based on code by J.R.Shewchuk. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point to test + true if this point is inside the circle defined by the points a, b, c + + + + Computes twice the area of the oriented triangle (a, b, c), i.e., the area is positive if the + triangle is oriented counterclockwise. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The area of the triangle defined by the points a, b, c + + + + Tests if a point is inside the circle defined by + the triangle with vertices a, b, c (oriented counter-clockwise). + + + This method uses more robust computation. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point to test + true if this point is inside the circle defined by the points a, b, c + + + + Tests if a point is inside the circle defined by + the triangle with vertices a, b, c (oriented counter-clockwise). + + + The computation uses arithmetic for robustness, but a faster approach. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point to test + true if this point is inside the circle defined by the points a, b, c + + + + Computes twice the area of the oriented triangle (a, b, c), i.e., the area + is positive if the triangle is oriented counterclockwise. + + + The computation uses {@link DD} arithmetic for robustness. + + a vertex of the triangle + a vertex of the triangle + a vertex of the triangle + The area of a triangle defined by the points a, b and c + + + + + + + + + + + + + + Computes the inCircle test using distance from the circumcentre. + Uses standard double-precision arithmetic. + + + In general this doesn't + appear to be any more robust than the standard calculation. However, there + is at least one case where the test point is far enough from the + circumcircle that this test gives the correct answer. +
+            LINESTRING (1507029.9878 518325.7547, 1507022.1120341457 518332.8225183258,
+            1507029.9833 518325.7458, 1507029.9896965567 518325.744909031)
+            
+
+ A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point to test + The area of a triangle defined by the points a, b and c +
+ + + Models a site (node) in a . + The sites can be points on a line string representing a + linear site. + The vertex can be considered as a vector with a norm, length, inner product, cross + product, etc. Additionally, point relations (e.g., is a point to the left of a line, the circle + defined by this point and two others, etc.) are also defined in this class. + + It is common to want to attach user-defined data to + the vertices of a subdivision. + One way to do this is to subclass Vertex + to carry any desired information. + + David Skea + Martin Davis + + + + Creates an instance of this class using the given x- and y-ordinate valuse + + x-ordinate value + y-ordinate value + + + + Creates an instance of this class using the given x-, y- and z-ordinate values + + x-ordinate value + y-ordinate value + z-ordinate value + + + + Creates an instance of this class using a clone of the given . + + The coordinate + + + + Gets the x-ordinate value + + + + + Gets the y-ordinate value + + + + + Gets the z-ordinate value + + + + + Gets the coordinate + + + + + + + + Computes the cross product k = u X v. + + a vertex + returns the magnitude of u X v + + + + Computes the inner or dot product + + A vertex + The dot product u.v + + + + Computes the scalar product c(v) + + A vertex + The scaled vector + + + + Tests if this is inside the circle defined by the points a, b, c. This test uses simple + double-precision arithmetic, and thus may not be robust. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + true if this vertex is inside the circumcircle (a, b, c) + + + + Tests whether the triangle formed by this vertex and two + other vertices is in CCW orientation. + + a vertex + a vertex + true if the triangle is oriented CCW + + + + Computes the value of the ratio of the circumradius to shortest edge. If smaller than some + given tolerance B, the associated triangle is considered skinny. For an equal lateral + triangle this value is 0.57735. The ratio is related to the minimum triangle angle theta by: + circumRadius/shortestEdge = 1/(2sin(theta)). + + second vertex of the triangle + third vertex of the triangle + ratio of circumradius to shortest edge. + + + + returns a new vertex that is mid-way between this vertex and another end point. + + the other end point. + the point mid-way between this and that. + + + + Computes the centre of the circumcircle of this vertex and two others. + + + + the Coordinate which is the circumcircle of the 3 points. + + + + For this vertex enclosed in a triangle defined by three vertices v0, v1 and v2, interpolate + a z value from the surrounding vertices. + + + + + Interpolates the Z-value (height) of a point enclosed in a triangle + whose vertices all have Z values. + The containing triangle must not be degenerate + (in other words, the three vertices must enclose a + non-zero area). + + The point to interpolate the Z value of + A vertex of a triangle containing the + A vertex of a triangle containing the + A vertex of a triangle containing the + The interpolated Z-value (height) of the point + + + + Computes the interpolated Z-value for a point p lying on the segment p0-p1 + + The point to interpolate the Z value of + A vertex of the segment is lying on + A vertex of the segment is lying on + The interpolated Z-value (height) of the point + + + + Models a constraint segment in a triangulation. + A constraint segment is an oriented straight line segment between a start point + and an end point. + + David Skea + Martin Davis + + + + + Creates a new instance for the given ordinates. + + + + + Creates a new instance for the given ordinates, with associated external data. + + + + + Creates a new instance for the given points, with associated external data. + + the start point + the end point + an external data object + + + + Creates a new instance for the given points. + + the start point + the end point + + + + Gets the start coordinate of the segment + + a Coordinate + + + + Gets the end coordinate of the segment + + a Coordinate + + + + Gets the start X ordinate of the segment + + the X ordinate value + + + + Gets the start Y ordinate of the segment + + the Y ordinate value + + + + Gets the start Z ordinate of the segment + + the Z ordinate value + + + + Gets the end X ordinate of the segment + + the X ordinate value + + + + Gets the end Y ordinate of the segment + + he Y ordinate value + + + + Gets the end Z ordinate of the segment + + the Z ordinate value + + + + Gets a LineSegment modelling this segment. + + a LineSegment + + + + Gets or sets the external data associated with this segment + + a data object + + + + Determines whether two segments are topologically equal. + I.e. equal up to orientation. + + a segment + true if the segments are topologically equal + + + + Computes the intersection point between this segment and another one. + + a segment + the intersection point, or null if there is none + + + + Computes a string representation of this segment. + + a string + + + + Models a constraint segment which can be split in two in various ways, + according to certain geometric constraints. + + Martin Davis + + + + Computes the {@link Coordinate} that lies a given fraction along the line defined by the + reverse of the given segment. A fraction of 0.0 returns the end point of the + segment; a fraction of 1.0 returns the start point of the segment. + + the LineSegment + the fraction of the segment length along the line + the point at that distance + + + + A memory-efficient representation of a triangle in a triangulation. + Contains three vertices, and links to adjacent Tris for each edge. + Tris are constructed independently, and if needed linked + into a triangulation using . + + An edge of a Tri in a triangulation is called a boundary edge + if it has no adjacent triangle.
+ The set of Tris containing boundary edges are called the triangulation border. +
+ Martin Davis +
+ + + Creates a of s + representing the triangles in a list. + + A list of Tris + The GeometryFactory to use + The Polygons for the triangles + + + + Computes the area of a set of Tris. + + A set of tris + The total area of the triangles + + + + Validates a list of Tris. + + The list of Tris to validate + + + + Creates a triangle with the given vertices. + The vertices should be oriented clockwise. + + The first triangle vertex + The second triangle vertex + The third triangle vertex + The created trianlge + + + + Creates a triangle from an array with three vertex coordinates. + The vertices should be oriented clockwise. + + The array of vertex coordinates + The created triangle + + + + Creates a triangle with the given vertices. + The vertices should be oriented clockwise. + + The first triangle vertex + The second triangle vertex + The third triangle vertex + + + + Sets the adjacent triangles.
+ The vertices of the adjacent triangles are + assumed to match the appropriate vertices in this triangle. +
+ The triangle adjacent to edge 0 + The triangle adjacent to edge 1 + The triangle adjacent to edge 2 +
+ + + Sets the triangle adjacent to the edge originating + at a given vertex.
+ The vertices of the adjacent triangles are + assumed to match the appropriate vertices in this triangle. +
+ The edge start point + The adjacent triangle +
+ + + Sets the triangle adjacent to an edge.
+ The vertices of the adjacent triangle are + assumed to match the appropriate vertices in this triangle. +
+ The edge triangle is adjacent to + The adjacent triangle +
+ + + Splits a triangle by a point located inside the triangle. + Creates the three new resulting triangles with adjacent links + set correctly. + Returns the new triangle whose 0'th vertex is the splitting point. + + The point to insert + The new triangle whose 0'th vertex is + + + + Interchanges the vertices of this triangle and a neighbor + so that their common edge + becomes the the other diagonal of the quadrilateral they form. + Neighbour triangle links are modified accordingly. + + The index of the adjacent tri to flip with + + + + Replaces an adjacent triangle with a different one. + + An adjacent triangle + The triangle to replace with + + + + Computes the degree of a Tri vertex, which is the number of tris containing it. + This must be done by searching the entire triangulation, + since the containing tris may not be adjacent or edge-connected. + + The vertex index + The triangulation + The degree of the vertex + + + + Removes this tri from the triangulation containing it. + All links between the tri and adjacent ones are nulled. + + The triangulation + + + + Removes this triangle from a triangulation. + All adjacent references and the references to this + Tri in the adjacent Tris are set to null. + + + + + Gets the triangles adjacent to the quadrilateral + formed by this triangle and an adjacent one. + The triangles are returned in the following order: + + Order: + + opp0-adj0 edge + opp0-adj1 edge + opp1-adj0 edge + opp1-adj1 edge + + + An adjacent triangle + The index of the common edge in this triangle + The index of the common edge in the adjacent triangle + + + + + Validates that a is correct. + Currently just checks that orientation is CW. + + Thrown if is not valid + + + + Validates that the vertices of an adjacent linked triangle are correct. + + The index of the adjacent triangle + + + + Gets the coordinate for a vertex. + This is the start vertex of the edge. + + The vertex (edge) index + The vertex coordinate + + + + Gets the index of the triangle vertex which has a given coordinate (if any). + This is also the index of the edge which originates at the vertex. + + The coordinate to find + The vertex index, or -1 if it is not in the triangle + + + + Gets the edge index which a triangle is adjacent to (if any), + based on the adjacent triangle link. + + The Tri to find + The index of the edge adjacent to the triangle, or -1 if not found + + + + Gets the triangle adjacent to an edge. + + The edge index + The adjacent triangle (may be null) + + + + Tests if this tri has any adjacent tris. + + true if there is at least one adjacent tri + + + + Tests if there is an adjacent triangle to an edge. + + The edge index + true if there is a triangle adjacent to edge + + + + Tests if a triangle is adjacent to some edge of this triangle. + + The triangle to test + true if the triangle is adjacent + + + + + Computes the number of triangle adjacent to this triangle. + This is a number in the range [0,2]. + The number of adjacent triangles + + + + Tests if a tri vertex is interior. + A vertex of a triangle is interior if it + is fully surrounded by other triangles. + + The vertex index + true if the vertex is interior + + + + Tests if a tri contains a boundary edge, + and thus on the border of the triangulation containing it. + + true if the tri is on the border of the triangulation + + + + Tests if an edge is on the boundary of a triangulation. + + The index of an edge + true if the edge is on the boundary + + + + Computes the vertex or edge index which is the next one + (counter-clockwise) around the triangle. + + The index + The next index value + + + + Computes the vertex or edge index which is the previous one + (counter-clockwise) around the triangle. + + The index + The previous index value + + + + Gets the index of the vertex opposite an edge. + + The edge index + The index of the opposite vertex + + + + Gets the index of the edge opposite a vertex. + + The index of the vertex + The index of the opposite edge + + + + Computes a coordinate for the midpoint of a triangle edge. + + The edge index + the midpoint of the triangle edge + + + Gets the area of the triangle. + The area of the triangle + + + + Gets the length of the perimeter of the triangle. + + + + + Creates a representing this triangle. + + The geometry factory + A polygon + + + + + + + Builds a triangulation from a set of s + by populating the links to adjacent triangles. + + Martin Davis + + + + Computes the triangulation of a set of s. + + An enumeration of s + + + + Creates an instance of this class and computes the triangulation of a set of s. + + An enumeration of s + + + + Represents an edge in a , + to be used as a key for looking up Tris + while building a triangulation. + The edge value is normalized to allow lookup + of adjacent triangles. + + Martin Davis + + + + Gets or sets a value indicating the start point of this + + + + + Gets or sets a value indicating the end point of this + + + + + Creates an instance of this class + + A coordinate + A coordinate + + + + Creates a map between the vertex s of a + set of s, + and the parent geometry, and transfers the source geometry + data objects to geometry components tagged with the coordinates. + + + This class can be used in conjunction with + to transfer data objects from the input site geometries + to the constructed Voronoi polygons. + + Martin Davis + + + + + Loads the vertices of a geometry and maps them with th the . + + A geometry + + + + Loads the vertices of a collection of geometries and maps them with the . + + A collection of geometry + + + + Loads the vertices of the geometries of a GeometryCollection and maps them with the . + + A GeometryCollection + + + + Gets a value indicating the coordinates. + + A list of Coordinates. + + + + Input is assumed to be a multiGeometry + in which every component has its userData + set to be a Coordinate which is the key to the output data. + The Coordinate is used to determine + the output data object to be written back into the component. + + + + + + A utility class which creates Voronoi Diagrams + from collections of points. + The diagram is returned as a of s, + representing the faces of the Voronoi diagram. + /// The faces are clipped to the larger of: + + + an envelope supplied by . + + + an envelope determined by the input sites. + + + The userData attribute of each face Polygon is set to + the Coordinate of the corresponding input site. + This allows using a Map to link faces to data associated with sites. + + Martin Davis + + + + Sets the sites (point or vertices) which will be diagrammed. + All vertices of the given geometry will be used as sites. + + geom the geometry from which the sites will be extracted. + + + + Sets the sites (point or vertices) which will be diagrammed + from a collection of s. + + a collection of Coordinates. + + + + Sets the envelope to clip the diagram to. + The diagram will be clipped to the larger + of this envelope or an envelope surrounding the sites. + + the clip envelope. + + + + Sets the snapping tolerance which will be used + to improved the robustness of the triangulation computation. + A tolerance of 0.0 specifies that no snapping will take place. + + tolerance the tolerance distance to use + + + + Gets the which models the computed diagram. + + the subdivision containing the triangulation + + + + Gets the faces of the computed diagram as a + of s, clipped as specified. + + The attribute of each face is set to + the Coordinate of the corresponding input site. + This allows using a to link faces to data associated with sites. + + the geometry factory to use to create the output + a containing the face s of the diagram + + + + An alternative implementation of the priority queue abstract data type. + This allows us to do more than , which we + got from JTS. Ultimately, this queue enables scenarios that have more + favorable execution speed characteristics at the cost of less favorable + memory and usability characteristics. + + + The type of the priority for each queue node. + + + The type of data stored in the queue. + + + When enumerating over the queue, note that the elements will not be in + sorted order. To get at the elements in sorted order, use the copy + constructor and repeatedly elements from it. + + + + + Initializes a new instance of the + class. + + + + + Initializes a new instance of the + class. + + + The initial queue capacity. + + + is less than 1. + + + + + Initializes a new instance of the + class. + + + The to use to compare priority values, + or to use the default comparer for the type. + + + + + Initializes a new instance of the + class. + + + The initial queue capacity. + + + The to use to compare priority values, + or to use the default comparer for the type. + + + is less than 1. + + + + + Initializes a new instance of the + class. + + + The to + copy from. + + + is . + + + + + Gets the number of nodes currently stored in this queue. + + + + + Gets the node at the head of the queue. + This is the node whose compares + less than or equal to the priority of all other nodes in the queue. + + + + + Removes all nodes from this queue. + + + + + Determines whether the given node is contained within this queue. + + + The node to locate in the queue. + + + if is found in the + queue, otherwise . + + + + + Adds a given node to the queue with the given priority. + + + The node to add to the queue. + + + The priority for the node. + + + is . + + + + + Removes and returns the head of the queue. + + + The removed element. + + + + + Changes the priority of the given node. + + + The node whose priority to change. + + + The new priority for the node. + + + is . + + + + + Removes the given node from this queue if it is present. + + + The node to remove if present. + + + A value indicating whether the node was removed. + + + + + + + + + + + A utility for making programming assertions. + + + + + Tests if is true + + If the test fails, with no message is thrown. + + The assertion value + + + + Tests if is true + + If the test fails, with is thrown. + + The assertion value + A message describing the failure condition. + + + + Tests if two values are equal. + + If the test fails, with no specific message is thrown. + + The expected value + The actual value + + + + Tests if two values are equal. + + If the test fails, with is thrown. + + The expected value + The actual value + A message describing the failure condition. + + + + Throws an with no specific message text. + + + + + Throws an with as specific message text. + + A text describing the failure condition + + + + + + + + + + + + + + + + + + + + A CoordinateFilter that creates an array containing every coordinate in a Geometry. + + + + + Constructs a CoordinateArrayFilter. + + The number of points that the CoordinateArrayFilter will collect. + + + + Returns the Coordinates collected by this CoordinateArrayFilter. + + + + + + + + + + + CoordinateCompare is used in the sorting of arrays of Coordinate objects. + Implements a lexicographic comparison. + + + + + Compares two object and returns a value indicating whether one is less than, equal to or greater + than the other. + + First Coordinate object to compare. + Second Coordinate object to compare. + + <table cellspacing="0" class="dtTABLE"> + <TR VALIGN="top"> + <TH width=50%>Value</TH> + <TH width=50%>Condition</TH> + </TR> + <TR VALIGN="top"> + <TD width=50%>Less than zero</TD> + <TD width=50%><I>a</I> is less than <I>b</I>.</TD> + </TR> + <TR VALIGN="top"> + <TD width=50%>Zero</TD> + <TD width=50%><I>a</I> equals <I>b</I>.</TD> + </TR> + <TR VALIGN="top"> + <TD width=50%>Greater than zero</TD> + <TD width=50%><I>a</I> is greater than <I>b</I>.</TD> + </TR> + </table> + + If a implements IComparable, then a. CompareTo (b) is returned; otherwise, if b + implements IComparable, then b. CompareTo (a) is returned. + Comparing a null reference (Nothing in Visual Basic) with any type is allowed and does not + generate an exception when using IComparable. When sorting, a null reference (Nothing) is + considered to be less than any other object. + + + + + A CoordinateFilter that counts the total number of coordinates + in a Geometry. + + + + + Returns the result of the filtering. + + + + + + + + + + + Converts degrees to radians. + + + + + Converts degrees to radians. + + The angle in degrees. + The angle in radians. + + + + A utility class to get s, s + off of s or to build aggregate geometries. + + + + + Gets a default envelope + + + + + Gets the envelope of a geometry. + + A geometry + The envelope of or if g == null. + + + + Function to get the geometry factory of a geometry. If + is null, a default geometry + factory is returned. + + A geometry + A geometry factory + + + + Function to get the geometry factory of the first + geometry in a series of geometries. + If no geometry is provided in , + a default geometry factory is returned. + + An enumeration of geometries + A geometry factory + + + + Builds a geometry from a list of geometries. + + The function returns + + nullif the list is null or empty + [0]if the list contains one single item. + a if is a GeometryCollection. + a Multi-geometry in all other cases. + + + A list of geometries. + A parent geometry + A geometry. + + + + Builds a geometry from a list of geometries. + + The function returns + + nullif the list is null or empty + [0]if the list contains one single item. + a if is a GeometryCollection. + a Multi-geometry in all other cases. + + + A list of geometries. + A parent geometry + A geometry. + + + + Method to build a geometry. + + An array of geometries + A GEOMETRYCOLLECTION containing . + + + + Method to build a geometry. + + A geometry + A geometry + A GEOMETRYCOLLECTION containing and . + + + + Computes various kinds of common geometric shapes. + Allows various ways of specifying the location and extent of the shapes, + as well as number of line segments used to form them. + + + + + A geometry factory + + + + + A precision model + + + + + + Create a shape factory which will create shapes using the default GeometryFactory. + + + + + Create a shape factory which will create shapes using the given GeometryFactory. + + The factory to use. + + + + Gets/Sets the location of the shape by specifying the base coordinate + (which in most cases is the + lower left point of the envelope containing the shape). + + + + + Gets/Sets the location of the shape by specifying the centre of + the shape's bounding box. + + + + + Gets or sets the envelope of the shape + + + + + Gets/Sets the total number of points in the created Geometry. + + + + + Gets/Sets the size of the extent of the shape in both x and y directions. + + + + + Gets/Sets the width of the shape. + + + + + Gets/Sets the height of the shape. + + + + + Gets/Sets the rotation angle, in radians, to use for the shape. + The rotation is applied relative to the centre of the shape. + + + + + Rotates a geometry by angle + + The geometry to rotate + A rotated geometry + + + + Creates a coordinate at (, ) + + The x-ordinate value + The y-ordinate value + A coordinate + + + + Creates a translated coordinate at ( + , + ) + + The x-ordinate value + The y-ordinate value + A translation vector (coordinate) + A coordinate + + + + Creates a rectangular Polygon. + + A rectangular polygon. + + + + Creates a circular Polygon. + + A circular polygon. + + + + Creates an elliptical Polygon. + If the supplied envelope is square the + result will be a circle. + + An an ellipse or circle. + + + + Creates a squircular . + + a squircle + + + + Creates a supercircular + of a given positive power. + + a supercircle + + + + Creates a elliptical arc, as a LineString. + + The arc is always created in a counter-clockwise direction. + + Start angle in radians + Size of angle in radians + + + + + Creates an elliptical arc polygon. + + + The polygon is formed from the specified arc of an ellipse + and the two radii connecting the endpoints to the centre of the ellipse. + + Start angle in radians + Size of angle in radians + An elliptical arc polygon + + + + A dimension class for s + + + + + Gets or sets a value indicating the base of the shapes to be created + + + + + Gets or sets a value indicating the centre of the shapes to be created + + + + + Gets or sets a value indicating the width of the . + + + + + Gets or sets a value indicating the height of the . + + + + + Sets and to the same value + + + + + Gets a value indicating the minimum size of the shape's + + + + + Gets or sets a value indicating the bounds of the shape to be created + + + + + + + + + + + + + + + + + + + + + + + + + + A guard class + + + + + Checks if a value is not null. + + The value to check for null + The name of the property that belongs to. + + + + + + + + + Only static methods! + + + + + Convert the given numeric value (passed as string) of the base specified by baseIn + to the value specified by baseOut. + + Numeric value to be converted, as string. + Base of input value. + Base to use for conversion. + Converted value, as string. + + + + Utility functions to report memory usage. + + mbdavis + + + + Gets a value indicating the total memory used. + + + + + Gets a string describing the total memory used + + + + + Number of bytes in a kilo-byte + + + + + Number of bytes in mega-byte + + + + + Number of bytes in a giga-byte + + + + + Formats a number of bytes + + The number of bytes + A string describing a number of bytes + + + + Rounds a double to 2 decimal places + + The number to round + The rounded number + + + + A priority queue over a set of objects. + + Objects to add + Martin Davis + + + + Creates an instance of this class + + + + + Creates an instance of this class + + The capacity of the queue + The comparer to use for computing priority values + + + Insert into the priority queue. Duplicates are allowed. + + The item to insert. + + + + Test if the priority queue is logically empty. + + true if empty, false otherwise. + + + + Returns size. + + + + + Make the priority queue logically empty. + + + + + Remove the smallest item from the priority queue. + + The smallest item, or default(T) if empty. + + + + Gets the smallest item without removing it from the queue + + + + + > + + + + A container for a prioritized node that sites in an + . + + + The type to use for the priority of the node in the queue. + + + The type to use for the data stored by the node in the queue. + + + + + Initializes a new instance of the class. + + + The to store in this node. + + + + + Gets the that is stored in this node. + + + + + Gets the of this node in the queue. + + + The queue may update this priority while the node is still in the queue. + + + + + Gets or sets the index of this node in the queue. + + + This should only be read and written by the queue itself. + It has no "real" meaning to anyone else. + + + + + Converts radians to degress. + + + + + Converts radians to degress. + + Angle in radians. + The angle in degrees. + + + + + + + + + + + + + + + + + A + that extracts a unique array ofCoordinate s. + The array of coordinates contains no duplicate points. + + It preserves the order of the input points. + + + + + Convenience method which allows running the filter over an array of s. + + an array of coordinates + an array of the unique coordinates + + + + Returns the gathered s. + + The Coordinates collected by this ICoordinateArrayFilter + + + + + + + Buffer for characters. This approximates StringBuilder + but is designed to be faster for specific operations. + This is about 30% faster for the operations I'm interested in + (Append, Clear, Length, ToString). + This trades off memory for speed. + + + To make Remove from the head fast, this is implemented + as a ring buffer. + This uses head and tail indices into a fixed-size + array. This will grow the array as necessary. + + + + + Gets/Sets the number of characters in the character buffer. + Increasing the length this way provides indeterminate results. + + + + + Returns the capacity of this character buffer. + + + + + Default constructor. + + + + + Construct with a specific capacity. + + + + + + Reallocate the buffer to be larger. For the new size, this + uses the max of the requested length and double the current + capacity. + This does not shift, meaning it does not change the head or + tail indices. + + The new requested length. + + + + Ensure that we're set for the requested length by + potentially growing or shifting contents. + + + + + + Move the buffer contents such that headIndex becomes 0. + + + + + Overwrite this object's underlying buffer with the specified + buffer. + + The character array. + The number of characters to consider filled + in the input buffer. + + + + Append a character to this buffer. + + + + + + Append a string to this buffer. + + The string to append. + + + + Append a string to this buffer. + + The string to append. + + + + Remove a character at the specified index. + + The index of the character to remove. + + + + + Remove a specified number of characters at the specified index. + + The index of the characters to remove. + The number of characters to remove. + + + + Find the first instance of a character in the buffer, and + return its index. This returns -1 if the character is + not found. + + The character to find. + The index of the specified character, or -1 + for not found. + + + + Empty the buffer. + + + + + Indexer. + + + + + Return the current contents as a string. + + The new string. + + + + Exception class for unterminated tokens. + + + + + Construct with a particular message. + + The message to store in this object. + + + + Exception class for unterminated quotes. + + + + + Construct with a particular message. + + The message to store in this object. + + + + Exception class for unterminated block comments. + + + + + Construct with a particular message. + + The message to store in this object. + + + + Bitwise enumeration for character types. + + + + word characters (usually alpha, digits, and domain specific) + + + # or something for line comments + + + whitespace + + + ' or " type + + + usually 0 to 9 + + + usually 0 to 9, a-f and A-F + + + eof char + + + + This contains the settings that control the behavior of the tokenizer. + This is separated from the StreamTokenizer so that common settings + are easy to package and keep together. + + + + + This is the character type table. Each byte is bitwise encoded + with the character attributes, such as whether that character is + word or whitespace. + + + + + Whether or not to return whitespace tokens. If not, they're ignored. + + + + + Whether or not to return EolTokens on end of line. Eol tokens will not + break up other tokens which can be multi-line. For example block comments + and quotes will not be broken by Eol tokens. Therefore the number of + Eol tokens does not give you the line count of a stream. + + + + + Whether or not to look for // comments + + + + + Whether or not to look for /* */ block comments. + + + + + Whether or not to return comments. + + + + + Whether or not to check for unterminated quotes and block comments. + If true, and one is encoutered, an exception is thrown of the appropriate type. + + + + + Whether or not digits are specified as Digit type in the + character table. + This setting is based on the character types table, so this + setting interacts with character type table manipulation. + This setting may become incorrect if you modify the character + types table directly. + + + + + Whether or not to parse Hex (0xABCD...) numbers. + This setting is based on the character types table, so this + setting interacts with character type table manipulation. + + + + + Default constructor. + + + + + Copy constructor. + + + + + Sets this object to be the same as the specified object. + Note that some settings which are entirely embodied by the character + type table. + + + + + Setup default parse behavior. + This resets to same behavior as on construction. + + bool - true for success. + + + + Apply settings which are commonly used for code parsing + C-endCapStyle code, including C++, C#, and Java. + + + + + + Clear the character type settings. This leaves them unset, + as opposed to the default. Use SetDefaults() for default + settings. + + + + + Specify that a particular character is a word character. + Character table type manipulation method. + This adds the type to the char(s), rather + than overwriting other types. + + The character. + + + + Specify that a range of characters are word characters. + Character table type manipulation method. + This adds the type to the char(s), rather + than overwriting other types. + + First character. + Last character. + + + + Specify that a string of characters are word characters. + Character table type manipulation method. + This adds the type to the char(s), rather + than overwriting other types. + + + + + + Specify that a character is a whitespace character. + Character table type manipulation method. + This type is exclusive with other types. + + The character. + + + + Specify that a range of characters are whitespace characters. + Character table type manipulation method. + This adds the characteristic to the char(s), rather + than overwriting other characteristics. + + First character. + Last character. + + + + Remove other type settings from a range of characters. + Character table type manipulation method. + + + + + + + Remove other type settings from a character. + Character table type manipulation method. + + + + + + Specify that a particular character is a comment-starting character. + Character table type manipulation method. + + + + + + Specify that a particular character is a quote character. + Character table type manipulation method. + + + + + + Return a string representation of a character type setting. + Since the type setting is bitwise encoded, a character + can have more than one type. + + The character type byte. + The string representation of the type flags. + + + + Check whether the specified char type byte has a + particular type flag set. + + The char type byte. + The CharTypeBits entry to compare to. + bool - true or false + + + + Check whether the specified char has a + particular type flag set. + + The character. + The CharTypeBits entry to compare to. + bool - true or false + + + + Check whether the specified char has a + particular type flag set. + + The character. + The CharTypeBits entry to compare to. + bool - true or false + + + + Display the state of this object. + + + + + Display the state of this object, with a per-line prefix. + + The pre-line prefix. + + + + A StreamTokenizer similar to Java's. This breaks an input stream + (coming from a TextReader) into Tokens based on various settings. The settings + are stored in the TokenizerSettings property, which is a + StreamTokenizerSettings instance. + + + + This is configurable in that you can modify TokenizerSettings.CharTypes[] array + to specify which characters are which type, along with other settings + such as whether to look for comments or not. + + + WARNING: This is not internationalized. This treats all characters beyond + the 7-bit ASCII range (decimal 127) as Word characters. + + + There are two main ways to use this: 1) Parse the entire stream at + once and get an ArrayList of Tokens (see the Tokenize* methods), + and 2) call NextToken() successively. + This reads from a TextReader, which you can set directly, and this + also provides some convenient methods to parse files and strings. + This returns an Eof token if the end of the input is reached. + + + Here's an example of the NextToken() endCapStyle of use: + + StreamTokenizer tokenizer = new StreamTokenizer(); + tokenizer.GrabWhitespace = true; + tokenizer.Verbosity = VerbosityLevel.Debug; // just for debugging + tokenizer.TextReader = File.OpenText(fileName); + Token token; + while (tokenizer.NextToken(out token)) log.Info("Token = '{0}'", token); + + + + Here's an example of the Tokenize... endCapStyle of use: + + StreamTokenizer tokenizer = new StreamTokenizer("some string"); + ArrayList tokens = new ArrayList(); + if (!tokenizer.Tokenize(tokens)) + { + // error handling + } + foreach (Token t in tokens) Console.WriteLine("t = {0}", t); + + + + Comment delimiters are hardcoded (// and /*), not affected by char type table. + + + This sets line numbers in the tokens it produces. These numbers are normally + the line on which the token starts. + There is one known caveat, and that is that when GrabWhitespace setting + is true, and a whitespace token contains a newline, that token's line number + will be set to the following line rather than the line on which the token + started. + + + + + + This is the number of characters in the character table. + + + + + This is the TextReader that this object will read from. + Set this to set the input reader for the parse. + + + + + The settings which govern the behavior of the tokenization. + + + + + Default constructor. + + + + + Construct and set this object's TextReader to the one specified. + + The TextReader to read from. + + + + Construct and set this object's TextReader to the one specified. + + The TextReader to read from. + Tokenizer settings. + + + + Construct and set a string to tokenize. + + The string to tokenize. + + + + Utility function, things common to constructors. + + + + + Clear the stream settings. + + + + + Display the state of this object. + + + + + Display the state of this object, with a per-line prefix. + + The pre-line prefix. + + + + The states of the state machine. + + + + + Pick the next state given just a single character. This is used + at the start of a new token. + + The type of the character. + The character. + The state. + + + + Pick the next state given just a single character. This is used + at the start of a new token. + + The type of the character. + The character. + Exclude this state from the possible next state. + The state. + + + + Read the next character from the stream, or from backString + if we backed up. + + The next character. + + + + Get the next token. The last token will be an EofToken unless + there's an unterminated quote or unterminated block comment + and Settings.DoUntermCheck is true, in which case this throws + an exception of type StreamTokenizerUntermException or sub-class. + + The output token. + bool - true for success, false for failure. + + + + Starting from current stream location, scan forward + over an int. Determine whether it's an integer or not. If so, + push the integer characters to the specified CharBuffer. + If not, put them in backString (essentially leave the + stream as it was) and return false. + + If it was an int, the stream is left 1 character after the + end of the int, and that character is output in the thisChar parameter. + + The formats for integers are: 1, +1, and -1 + The + and - signs are included in the output buffer. + + The CharBuffer to append to. + Whether or not to consider + to be part + of an integer. + The last character read by this method. + true for parsed an int, false for not an int + + + + Parse the rest of the stream and put all the tokens + in the input ArrayList. This resets the line number to 1. + + The ArrayList to append to. + bool - true for success + + + + Parse all tokens from the specified TextReader, put + them into the input ArrayList. + + The TextReader to read from. + The ArrayList to append to. + bool - true for success, false for failure. + + + + Parse all tokens from the specified file, put + them into the input ArrayList. + + The file to read. + The ArrayList to put tokens in. + bool - true for success, false for failure. + + + + Tokenize a file completely and return the tokens in a Token[]. + + The file to tokenize. + A Token[] with all tokens. + + + + Parse all tokens from the specified string, put + them into the input ArrayList. + + + The ArrayList to put tokens in. + bool - true for success, false for failure. + + + + Parse all tokens from the specified Stream, put + them into the input ArrayList. + + + The ArrayList to put tokens in. + bool - true for success, false for failure. + + + + Gibt einen Enumerator zurück, der die Auflistung durchläuft. + + + Ein , der zum Durchlaufen der Auflistung verwendet werden kann. + + 1 + + + + Gibt einen Enumerator zurück, der eine Auflistung durchläuft. + + + Ein -Objekt, das zum Durchlaufen der Auflistung verwendet werden kann. + + 2 + + + + Token class used by StreamTokenizer. + This represents a single token in the input stream. + This is subclassed to provide specific token types, + such as CharToken, FloatToken, etc. + + + + + The line number in the input stream where this token originated. + This is base-1. + + + + + The line number where this token was found. This is base-1. + + + + + A storage object for the data of this token. + + + + + The Object stored by this token. This will be + a primitive C# type. + + + + + Backer for UntermError. + + + + + Whether or not there was an unterminated token problem + when creating this token. See UntermErrorMessage for + a message associated with the problem. + + + + An error message associated with unterm error. + + + + The error message if there was an unterminated token error + creating this token. + + + + + Construct a Token with the specified line number. + + The line number where this + token comes from. + + + + Equals override. + + The object to compare to. + bool - true for equals, false otherwise. + + + + Equals overload. + + The string to compare to. + bool + + + + Equals overload. + + The char to compare to. + bool + + + + Operator== overload. Compare a token and an object. + + The token to compare. + The other object. + bool + + + + Operator!= overload. Compare a token and an object. + + The token to compare. + The other object. + bool + + + + Operator== overload. Compare a token and a char. + + The token to compare. + The char. + bool + + + + Operator!= overload. Compare a token and a char. + + The token to compare. + The char. + bool + + + + Operator== overload. Compare a token and a string. + + The token to compare. + The string. + bool + + + + Operator!= overload. Compare a token and a string. + + The token to compare. + The string. + bool + + + + Override. Returns the ToString().GetHashCode(). + + The hash code. + + + + Return this token's value as a string. + + This token's value as a string. + + + + Produce a string which includes the line number. + + + + + + Produce a string which includes the token type. + + + + + + Create an object of the specified type corresponding to + this token. + + The type of object to create. + The new object, or null for error. + + + + Represents end-of-lines (line separator characters). + + + + Default constructor. + + + Constructor that takes line number. + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + + Represents end of file/stream. + + + + Default constructor. + + + Constructor that takes line number. + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + + Abstract base class for string tokens. + + + + Default constructor. + + + Constructor with the specified value + and line number. + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + + Token type for words, meaning sequences of word + characters. + + + + Constructor with the specified value. + + + Constructor with the specified value + and line number. + + + + Token type for Quotes such as "this is a quote". + + + + Constructor with the specified value. + + + Constructor with the specified value + and line number. + + + + Token type for comments, including line and block + comments. + + + + Constructor with the specified value. + + + Constructor with the specified value + and line number. + + + + Token type for whitespace such as spaces and tabs. + + + + Constructor with the specified value. + + + Constructor with the specified value + and line number. + + + + Token type for characters, meaning non-word characters. + + + + Constructor with the specified value + and line number. + + + Constructor with the specified value. + + + Constructor with the specified value. + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + + Token type for floating point numbers, stored internally as a Double. + + + + + Constructor with the specified value. + + + + + Constructor with the specified value. + + + + + Constructor with the specified value. + + + + + Constructor with the specified value and line number. + + + + + Constructor with the specified value and line number. + + + + + Override, see base + + + + + Override, see base + + + + + Override, see base + + + + + Override, see base + + + + + Override, see base + + + + + Token type for integer tokens. This handles both Int32 and Int64. + + + + Constructor with the specified value. + + + Constructor with the specified value. + + + Constructor with the specified value. + + + Constructor with the specified value + and line number. + + + Constructor with the specified value + and line number. + + + + Constructor for a 64 bit int + + + + + Parse a string known to be a hex string. This is faster + than Parse which doesn't assume the number is Hex. This will + throw an exception if the input number isn't hex. + + The hex number as a string. + The line where this token was found. + A new IntToken set to the value in the input string. + + + + Convert the input string to an integer, if possible + + The string to parse. + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + + This enumerates verbosity levels. + + + + For error messages. + + + For warn messages. + + + For info messages. + + + For debug messages. + + + diff --git a/PerfApp/nts_patch_595/NetTopologySuite.deps.json b/PerfApp/nts_patch_595/NetTopologySuite.deps.json new file mode 100644 index 0000000..46b678c --- /dev/null +++ b/PerfApp/nts_patch_595/NetTopologySuite.deps.json @@ -0,0 +1,152 @@ +{ + "runtimeTarget": { + "name": ".NETStandard,Version=v2.0/", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETStandard,Version=v2.0": {}, + ".NETStandard,Version=v2.0/": { + "NetTopologySuite/2.5.0-pre.190390492+local": { + "dependencies": { + "Microsoft.DotNet.ApiCompat": "6.0.0-beta.21159.11", + "Microsoft.SourceLink.GitHub": "1.1.1", + "NETStandard.Library": "2.0.3", + "System.Memory": "4.5.4" + }, + "runtime": { + "NetTopologySuite.dll": {} + } + }, + "Microsoft.Build.Tasks.Git/1.1.1": {}, + "Microsoft.DotNet.ApiCompat/6.0.0-beta.21159.11": {}, + "Microsoft.NETCore.Platforms/1.1.0": {}, + "Microsoft.SourceLink.Common/1.1.1": {}, + "Microsoft.SourceLink.GitHub/1.1.1": { + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + }, + "NETStandard.Library/2.0.3": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, + "System.Buffers/4.5.1": { + "runtime": { + "lib/netstandard2.0/System.Buffers.dll": { + "assemblyVersion": "4.0.3.0", + "fileVersion": "4.6.28619.1" + } + } + }, + "System.Memory/4.5.4": { + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.4.0", + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + }, + "runtime": { + "lib/netstandard2.0/System.Memory.dll": { + "assemblyVersion": "4.0.1.1", + "fileVersion": "4.6.28619.1" + } + } + }, + "System.Numerics.Vectors/4.4.0": { + "runtime": { + "lib/netstandard2.0/System.Numerics.Vectors.dll": { + "assemblyVersion": "4.1.3.0", + "fileVersion": "4.6.25519.3" + } + } + }, + "System.Runtime.CompilerServices.Unsafe/4.5.3": { + "runtime": { + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll": { + "assemblyVersion": "4.0.4.1", + "fileVersion": "4.6.28619.1" + } + } + } + } + }, + "libraries": { + "NetTopologySuite/2.5.0-pre.190390492+local": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Microsoft.Build.Tasks.Git/1.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==", + "path": "microsoft.build.tasks.git/1.1.1", + "hashPath": "microsoft.build.tasks.git.1.1.1.nupkg.sha512" + }, + "Microsoft.DotNet.ApiCompat/6.0.0-beta.21159.11": { + "type": "package", + "serviceable": true, + "sha512": "sha512-SVX3OOq+Jx+DbPETmOjZO4OlHtrJBkAK7+O99crSJYFndveqTLiIIPMI6v5E2xOBEnWQQPwtiFxaVhEtuqHwtA==", + "path": "microsoft.dotnet.apicompat/6.0.0-beta.21159.11", + "hashPath": "microsoft.dotnet.apicompat.6.0.0-beta.21159.11.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/1.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==", + "path": "microsoft.netcore.platforms/1.1.0", + "hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512" + }, + "Microsoft.SourceLink.Common/1.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg==", + "path": "microsoft.sourcelink.common/1.1.1", + "hashPath": "microsoft.sourcelink.common.1.1.1.nupkg.sha512" + }, + "Microsoft.SourceLink.GitHub/1.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", + "path": "microsoft.sourcelink.github/1.1.1", + "hashPath": "microsoft.sourcelink.github.1.1.1.nupkg.sha512" + }, + "NETStandard.Library/2.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", + "path": "netstandard.library/2.0.3", + "hashPath": "netstandard.library.2.0.3.nupkg.sha512" + }, + "System.Buffers/4.5.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "path": "system.buffers/4.5.1", + "hashPath": "system.buffers.4.5.1.nupkg.sha512" + }, + "System.Memory/4.5.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==", + "path": "system.memory/4.5.4", + "hashPath": "system.memory.4.5.4.nupkg.sha512" + }, + "System.Numerics.Vectors/4.4.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ==", + "path": "system.numerics.vectors/4.4.0", + "hashPath": "system.numerics.vectors.4.4.0.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/4.5.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3TIsJhD1EiiT0w2CcDMN/iSSwnNnsrnbzeVHSKkaEgV85txMprmuO+Yq2AdSbeVGcg28pdNDTPK87tJhX7VFHw==", + "path": "system.runtime.compilerservices.unsafe/4.5.3", + "hashPath": "system.runtime.compilerservices.unsafe.4.5.3.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/PerfApp/nts_patch_595/NetTopologySuite.dll b/PerfApp/nts_patch_595/NetTopologySuite.dll new file mode 100644 index 0000000000000000000000000000000000000000..7d51b4813ed199de6c365a5f9eb4d9c4df37c2b7 GIT binary patch literal 759808 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 T3n+?}fYAL|B58*IU=unJ- z(s8-yu5EOWWp^-qzZ5Xjr>*AGr_FQHJtqgnzdm*_r;61FT*cMsG{=B8pkO{zYF~bH z2T@^*D#=({@&wZ-2-HHCn7IAApq8 zi6T{3>DWeIs3XIIfe7ayom5SI-%&^FW86TapK~?(H`u5I*SJeogG7Ar(vCvmG_g1i zdgy?2cCLd2$N3VNMD)1O7k{9J?BJ+~E~Ela9g@mXV*^|CqZZ&OJZLh0`->dPk}4mt zX7!1LG~)CM?$C&Qr!=u|kAlDbM4sstLAJJA(IF#`;b|UQpe0SL$@GeFwa@ISVJNFH zM%8f@mfQ%m^p+VOirYZI#W`6#gqsC;OTxMpz}gMHv_506=@kV6mls4^u{LKN|44x0 zbwhRx3D2eUIw7R6j$r#*X=G)30jS>WH5~Q9(q5X3j(42Z#qkPpTD=rOnqz^#tbyP! z=0Zs)E(nYuw|=xJ5asHJ+Im?L4rQx*^iu9YPpd*iOPUYv3C$WaYN?O-P*89Sd?9>H z6d{eXt2vwsJZ;W-hh%WBHIx*aAevrr#udFcLjv|RLq$GT3u0Mo z$Z0y=2!uymK|)?A`ld)r>XT-;zQk{UvmXPmvZ;sn*5<35&u+;ydq127v{ zvH+j#H=M+8{1Jo*F^NPo|<0Cnng0PT2DgtUGkmb(Ew1I%?8xN zchO30r5UU(bSR-wNlLyGU9E#8t`eniTvS$JPR7@861ePvOGXky4|x4}Mxf&VEzkR<)Np!vjvyW$`!k#o9}p%zT40aPlJ-wnQ5XqO&=Z zV#?6GkKa(kZfl}i6K;4M2Ww-=1FB>Y8T6dER6)&0ynTeT4h9j*R&9|=OlFJ^F5LKT zDhQ%Yb)lgCDC=~G%E^Xt}Ll+o{A;u)CH?=9x}GqtF`jGW$T{jD4zZjxRmpXYN?1!6^jn(f#<13c*W}Lf5)J zf;653(bw!m7PYWgvv6l_Q^`z=JGx|2X}r`|@mlhix-)!d{B?*I2uXmH(%W!mn+b>` zu*`wvj1EiC00L78x>hLIwX=wViVZ$90$SR8Mz&21BHU&51EhY|eQ??0mMYg|XrmhT zbJK`Zyp3mkSUL_O3ySbK7NZ4vJeSnXpI@TTDCri1!vT9oWpVoc{3_nCh1>8 ztS#1B{;9?_`q_JLi?k7D{!PY>)?Q=>GTdw5X+-JKO&S^$T||DlmeoXBdk}r8H@|9d z(hsZGo05^qq6NsoT&*pX8l8$vW7FGL7A=K1rPWJ$AW{JV!S$Bisg|W#j4(QAYh$i# zFlD}UW}j{ciII5WRZ6l#$AwF9^WLB;dkk-m2S_|}e>|uk!^W)#Gs#2vX7&kw|*~$OLQlN;S>wQvu5IctRC`V&E-fm96YQMBOrfOy0X6j<<>Brx};^O}A(G#3t&%ZlL;L)7olX?ZPj z;jp-lLk0e3iNu22--VIrSWVK?_ILB<2wHA|-ub&ukMELMlG)xT(k&b|xtl+OoO<8R z*AqQqgK2Jc0Cqwm!)YP$j+^_qz0D0dBk*?xP%}GFDY${}U4pu8h(Vj~49ydoSayLL z!M}NDF{G)hVPWuIL1WSJpQWSLYY?ycy?pYbdD2Clg6J4$USU>D8VYiRvfSqI zvI^!xdzoG;V5;wl;}QH=`YTbJ#Mc(gO1)Y{wBhwB6J;cfgLbOSkzh{nV zm>r7dAX3D4{*1}$%(ASug;N<-*f&2T100ofd{o+*Lu50OK{fdqXM;1&EF2T_Njp0) zX8a@9N?wLd^#oZJTw{y*4{%BCvLLD73?{ua0uF2D&>e@e-lxwM2cf=Q(==o|ON~H_ zwQqoo%A^)Fp7uKebHe#qh+%3KckxR6HJr~a#t)hz1;#DVGq)fl>*%r|pMDSloo+Op%zAzW9q-l|2_R|N()m=1w=Dgq z0=3>P$qmjjoh(A^O*2)?M{$}0BD_}4jK!%6V+jd-l^U2sgL89~;R?mXKVwX4H0VPO z1rL%5MIk4H8J;0IxVn8Z>4}-*5xIO!m(KRW4QM8rPb{(zCoD_w%{Ta`D!W~LgcHR; zt=tN;9LU}(RROYn=M2Q_Dp=QgD=!DX&V{WKmoF~CF5lag11^*oNQAJ zAH@)dgsKN|Zp+BWeFl)t{jXD?Tf6g#^WBmn6E zWFk`r-vw+~C2`2D?l62KOUYw?vx!n`?-Pzmt&3eIlLD5*4H;om-#G6r=QnhZ@1BXr=C zpIV9}lVT7B;Z=*lLVAH~S`-MwvL*qf)#x|TC$$KPgJr!7mkSZ4!Tl_2p zj@Aq?tz+i3Xul=kPV&Gf>|*gcqh2VdPMYoxfR$aaH}zy%XFgFK7v6^%p%PC~N2HNH z^^Ygg6;Ki-@(n^S5_XRgWgqHN@59K(ln@!y`6RPnG`W-y|JwAhECCsdf`fH@bW+~; zSy!d(u4dzHR&jT5$c z)l3ONTpvxEzQ@fWN;QB!v`Al2M5^ZZmukPAlmH!D!RbU3f$eG*8*XILK#`PKE+|HO z(X}O3nf+=Xgf~nkF>Kh68@kc!$ff?M*n~cA3nXw)$YUjFe1e<;8VC9GZ0}>=C@6#m z)j2w~;&OPekRCv)DH;S16K~Q`GUuHyBo;?DK-+@1?4t8|0IgywWj zDo&f3(j>@}m6L`DFL z3mx59yh@TpGSpWK&@aw13}AB6Ol0$BF`_{sMiT-ej(Co{Y%BtanOF6U0s-|;i zk6FjaB*N^mi;Zo(Knga)UEwu}s&L?g7FjB>rSR@dWq4&8;9SW>zM5&LY9i&{-Z^3Bh~Ut-*bWo;-Hi(@ z2vSJ)#d+HJE1%NbIs2-d0&XsgmTNVSUM>d>rEmsgY8_lF0oF2sxif~M zI##f2djnDFO{@kjQo8|nQdLo%8aT{wTW0ExPQXHzA&zUsWh-12A8pw>ueB0x#D+T# zeBeL3q$-W4B-TCBuX~6zgoWquAz^!h>DvYEba8N993m0Ax;_Mfl6LgDA6FQFm=cr zqZoq=Z(IxG6l$5rOav3ZvMI$(L{=kn%`UVkKb292>m$UA_IW{V+f(m_!aZd#B4fv0qa=+(jPq0hj6ab@I>)LL z6vwg_sR&d!!pX~sXLZMbu*AkPvL?*21UJ>Plm@e*4^xVg>Fj$7m|#W0&i98P8Vk=%Flkr4sZJdEghz_XTq8qB{7K*2TNy$0=Hnhoyj@p14|Ss zaMFljg{r|_3RFeA_YK7tOggT^J{(`@)CsK2SQSmb13$x z{`RNsq|nv8=X?wYCI$qUG4T zOlxzkn{+%^i+m}Ek4Y5f_!)QamQrZ^42go*}sL&}5~O|JnPaonjZ z=iC7~J<*n+j|~|To0@8EAwAt8-!=q9bQ5cp(LH^Z!t&(vnHEO>A1cMh06y@w%Ui^H zdAx3{)^iy$F*)&*di#L&I&(HJ(eToIM zE95N?cD);HR;CXODY!841%1;fF2Jp^n%lre#n>E~k(O7vgGMdyms%qf$K^1)oUA*n zU3Z8<`Ai`(wk$_KHaUFiSMc;I0Uo5m<7f|;)3mEv!Sfq@&%8^ypw!mqFt+lPu*GNj+TaApT_#oQ1Z183mWXEW>BGU_RsjH?LeFsr1qaX!A zZA6c+>7hO|-3`~DRG`bAO91)+O7qn{7)tXld`wR=yB|m3d*cKO<69g~A`{{m>P;}> zHAP(bx?U#3W`cyug>g993fUV$t}Igrd3IzS2Bh7A#7K%qbT&l7>nAf}Cy|jJiI8FB zD$eq83Y-mBg!5#3tX{UIhBtjPPktt%;Xb1QNrv3gmb{n=^s{;Z!Y1kJl!rXD~Vkvy6e&_i|yGUD=JxBH`+Q* zUDDPGWS3_!R8QcPjnO(mD(c}5&!|x20VM(uPwxUwm_RC2q=1h@Y-s-z0S+)*CqPQ+ zGM7B68E<}u(Md~xGHvNct$14XC{R@(wW`3+HSq~E{4KE|buu8K5oV~X!4aSEv)T!= zVR8~of(u8$M6qO62BBivc-jb=Zfq)To#!Wo65T48{t|=;;;V-u&Uy3lk{%Qy_-Pjs zcn#Dc(n~5pk?vGqC@fS2kO&Me%{g1r)_H3KVc^6*52{ss*2spC5B^y4wYmxrDhI&+ zqs^GF0~u`Ls!g{FS(8yxOql~TrhqQ646bCm4FmWPx2oC_+GxG*#rNq2*vIq1P!%%C^Nm)Sq zoS1?$OExy+O@#LP-~vNVyV_PKNI>g;T{+UZ%_uJvz;0S_ienF%o5G5|=1akxcuffb z#_YvQeT-Q9v@O2s2RIH?#0XP-3(eku2#)59R#@{zENo7ArOg-hEyj^5=(BzK4IPDn z&IH%}D8f#h_Nhd4O8Y#~^im>A^F<{!&rMiI9h_xdD(|A^LO{C|3wPl?BQb0?%ZDa)rP{S)g2+gR%Ol1~BUstfE)& z9&+!Y;MKAtv1fw!lzUGF?`ij*4&GJwt_JV2dzXWE#l0(KR4oNJ=bZ7j8U?4n&7nRL zFk?LzLf*(+FXGC^25SD7)P?e*541UQ|4<_@W%sZ*lHt z*!oGj&PhB>8Z*zJNxbQ|BrdkMDfgS6!+W>O7!&*FZO?{MfQH0jr=nE)w0g#xzqp~; zy2SQ*9MoKXnm`y?3|7MQTYLggjLiml49g>cG4FDxcd65Ry3@Pb={?oyWp`Z>@}bNN zqIO2ZUOUmQ^6`_-oc>-qpU5%CTuY)(X-omc$`J!sW1t){5QPW{0ge)M$C>Cjgag{qKyT_>qU3;l zN9YYiYxSCUE2BUKcBU5JAEd&Xpup)oP8Sqh)IYeuKe#|TxWF{HKrgsJF1WxhxIizs z!0-F6fx=aAR^Z%`bdE(`ZRnlT*F5RhaM)7|xCmo-9kOXWzGXv(Lz?@o)yDaXmMni= z9>kRp(yehri6rG&dOFWC%`)h9URd4Qt2|KfyO@^9aRn@JYuDBXVj7oK|}9 z#>!b(23iTQ2Le3#I^j8h9=mbRKH~JU1Kq?v@il=}@rVpOi2GelhhWMkcyug5!o^p_ zRFZvPjB%vc#aNvnUD7x9|F?IpF?L0PH9FpSM3$PtrBIs}C{nYQ| z<&7t=*yQBoWfbSijdWV1%Gi;DYXd$?m;~7owK=JE^Pp#T&ASxFSWds7QFB1QOLvnF znj67Z#)8du1=RK#L9PPC6Sk<~})=~>oFa>e62vDglH^4|$3fC&flw3hy&lYC< z-mfsTU;|D3_3c@Ir-J`#*;YI2pom)I(whJbcix*_ z?UGJ#1*x#t@Agn?*qx-&M9334_K1O}(+UcFb7E$?Hwfz{lE4L0o*cFrSh zL(WLInWrK>D+7SpJ)eI=Lxfz(U(;IcN30|_QxA@|=rs~Q;|wt(!Fog`gTjD7;a#BR zVQ7=A^?gy+Gs;4l%AKYD25C2a2&Vx~rWrZ-=QsidT6lrL3u)jP0?+7G8x1f%Pm8_! zk>r-D#o#as@n*qM_jA5wZBP_?qR6Atp#28#%cjJyAPE@e zG22l?P~7kNe!m(uT^d0S#rOdw$Kcob*ik}=m$6ETY#pGZl3k=3<>uDp1^}B^7`$La zmv*aLp4YsVGLi}AGa62;Hmu$>u<&f*Sj8m4VGi1(7@fZ)iJXE!07Wl)=ZoHX+&f?O z&J!p~w$+qawK8EvY>%qpevQ03$TF9;GDT_%XIm|&CynQqEQ>2sEJxd zv<6L<%Lr*_wu+&T)8QEFW@tX~rczJ*N_`Qd=9`|Z>6LKc$T~Q-k*T5td&GJnAMi~x zx#MgBR1FsXtX2HIM3^dbV2|v7;r6Iu92t zN|tFn)LEinww(kh)=n37EZ_m{_`>oMb=LB}0u=kA)JZ;%&=F`DsQS_#xsoZfKaC(OTPEegrwXfnf%rD006FxzTAC7F%*b`x4o;3db+cV@K8Vu#zz9C*rTu9_ zg6z-XpjGFLIp=(sC);k;@1`lJrU!xdx;O@>>%hENYou7mqa1WG>V32 zNgOZ!+g@sKoXE%H^{rhm=wdS+VZ^zWm;HCKtRS)10*6@xbX^#QgJ}U)Bjm177%*gbhU0n zui!0gQtyZ^m=7A{(!2VERbsokQbpUFGM3S2_fM(*!X~C2J_pDohy^ZgZlcG~R&2eH zASuMs0ZR%&=jsT3%{Jj^8}}9`to6jYN7urZ#v9iX$QG-Nq^f^^PVqH_g*rxTA81l) z!PQjO+xr3rU)mh$Yq=51p9#u0AZ~YRzLb2F#qSvkq_IV6?TmXv3HGGnac^j81n3$^ z_#y+6D9*r7bF6^>vi=gk%D{iKO*D1(W{{vX?~VR@|7kRc(-akRvz1*>Oq1yGGRe13 z*b%Z;8EIpmk}p{sf|gfOkM9zR;ru;ioI>x@IM5i1(mJLt$IEp}t&;T)&q68oi>YT) z`@U8+nUk;Qt@B&rO?dS5yVI#^qXXS|`sunL=)MT1H*!utosyKYnO>#Na=Pxip9Wj^ z(;3zMx>BCzMH86(&(SovW-TuUr_Xz^s?%~ewK_D z=F`E9el5du^n`TOn{`LT+|4aq&QHC1BU<2kJEK1E^qH(w z3|v|0^PX%HwJwbU1sivnt1K5~-^(Gtrozo1-AX^XbrV|N^erxq-C3FVPaLHnL|u*Y zdTbOychb3->7)&4?814U(?8crJW0$gsC(*fhS{u+ZAq@?R6jyofX|pfT3qj4-5=4S zVR1e6x7EWH>d%n9qw2&r zG$~Pp4L5elHw`4nxP@e;`qx_RD`%$mGK<4_t?H9m?}&*jc(G3+zM1YVylxToc`qi5 z{J4O^FI-e>7cH;zXE;Sy16Cvwp<$LJ^g>5S%_REYDxy zO)+aki(2|=O2s7H-fT}_Atv35@iPr7aLHI=7DLFd=?ZVTEuPV_PvWB&F)!~5`*`7{ zVP3F~fx9^-a>C6sz6;vNO%#A6uP=7v%@elRiVHukNam&~Cb-v3P7AMjO;fT(EUpyQ zX21xJ`W}Qg>=GWqU3;I-R%}AE2wUJAGE13m@`hfNj6dlnRp5_(8r~#9NP4Hn7u8B$ z0#ZlsnZKf*M>&l@Br>fswdXT-(C3o8;{Q!>+mnaXua|i7HKRV-#A3mK~1F=_j(HbQR(7dn{y^O62IAG^3)wP z5)LLMV%SOT3P&>%bA*<8iX3g2;f^xe*XMT|ZF0O}aZ>Zt6}VD|#Yz4cba;Y@r>3}a znA;|)stqyxSrQilfYe&K>E6VAu!8IN>OSg!Fg?*pj$tUHl6Ivg+?x5{b*?m zV&e6wFUHQ*9=8^~gt%SlC#`F2Ki1~2kO@)bU{NX_JkFng>!E>N4O}lBM5-L~pLAY_ z4J^c`p_?2Hs)@OY0mv6+xDm6rqOBDhvwte2Yy!d#NDJ)d(x8X5cvvWNOpqz`5=C7% z*zK_n&PO9|TASq*{ep%%lq!wYzDdG^CfG|&{_{=#vrRd*s8;)i@e%+881kTHL$K2O z8qce)hLS+BRFN5!-@?&5G1`V~kmai;VjHoS>$SX0Et59}`M{6Ay7QC_DEZEVPkpIc z7PM%oCPC)5DM0FS=QQ0}JbnofKXp!1{W@2+k@QM};iH)WXkXhAG7CbNS#Q!O#?otl zhOItpB*eCZjZbtrgihS*H)*t8YB6fL4f>^0*jM6%W0ZUP=h^Igm~ozJOM1%{zVz=8+5OEi&KaTQ>V%`lRj% z2tPwFJ^HEFG`HCJ=obE%w4^(ZDpNw>E2%!+?$P1p$_?K1LLR3ngoTi0gui^C zWFseux#VNy&>_{2E;NMsZde{^q{W;~Jt(k`c_sB|acM9Y@qmh_{T=hid(Bqn*NbJ% z5jQizYFet8pXE>*jkh^jI@RL&?gt&s7uc>cJ>lMSI>@P0`e*(`K|L4T+BPYPSwG8M4-z#R0r}@B`CG2b@}15sc-lAs)x)i}OyB0B zhrvdA@@-5#U(%DW-w7i5G^PR5`|)W^^U@xUzit`N`3TZ{d3^3(xi{G}fmY%3mWy!D1hcrV9?4q7NYYl#d1ZKXQzPQi znyjQ^uk9-Bk#>8Eu8ohh*)t)R?7UtpO!m&6hnN(^qr$59PxL%rFPB$NQdaQsY2h=% z7hbkJ?)o;dJ8OZ-IwW_|mFeUWolIKVs72V`N?;M)9vInjrCh~(0{soxRaqh~ps2hX zBkxNF@iU%W5z}-2b$k9ysmH(P)$1!Xe8F*AujjG#3EkF-=q%n;H#v$oKWE=|MlZnh z9DH3GQ2%3y?VQ>Bbi6F&^XsU$9Y85?Nwl1v^sON>jznr;G@>k|z91qOoSyT8NLI{B zV&{*qZDV$mZ0#H7?UtXuEe)ctd{H{ffD0eiJFn91GMe;WhJTvu)|p&U^SaK16!Jdky3u zPbO7jCI z_py9DEjuD3la=z(D(19gtA(Fc*ln>V?j0GorFUoF?w!3o{oDEmI(KjD?&#~^wzI#d zYg_-0-MAe+9bG#HoI6p{)@0@6p7!?6 z?solj_nR}|L+$Oo?VT2pr1y08bai)hbqLbp<>No@2?u%y`r@vrtFJ$byT_uaqqn_p zY#{87!@mCh?*2}a2HFS4N$u$w>*)hcZ!{1_W9?zw*%QZOd6L`vqP~u>ud}m1-_zb6 z^~U|(y-`nhl+SnOqkaH-dh=cV`S!3U?(ZGz>uMhWM|)3u_jq4VR~+{CS*S z-q}CUk?$Mm?xxtzsIMmsd)mkPdZLc*elm`Cbhmdz`LT}vv3y4_wB-AGyF>Whn{l`0 zhIWq(r&eZCBQvvDnL*AsZrW1`r{bgK%EN<&>U1%j8zSghGwznFg%oTHM&fYFxpf(L z!=bnsht=3Qri$+Ple@~(bCtrxWG(o|X9Gmj3vg$9XJ_yhNVW!pg?OSId~Bu=6}ATV zl_yKYRI5ST(W6ImrTFMXr92zw^5v;Jwg!9RV&PbDU<{)=VIi(~n8NJrwlK_3#-&^o z12j^OqTs$T|8TWj62dsxF%_3;Ar!s>h5tM<83#in!@zmH3rz8XLNy3W!H$Fbg7I=C zm?}qcu~;Zg5E%tiVW}`ZQ^bl65uMwj0tjWGCoBfQ#9<|vh|5!PtumJj_SJ%ENG?Qi zH7LzY#g+0*HBBz$NsFTb_IOAY=JA{I(z!UxT|{{^&9UV=;`W+2I6qMzqiY|cW2!CtL5k1A7@<4 zp?JDnE!4`Dxx*{RRMC1T=ZXn~j4~>+|#p*-ICU>}2 zDCUN16|~F@92GtrSMJ>YvADL|SQ=8`N1}%w>gsl`E#v;+fkLqujKx7Eo^M(7rI@91P%M`w(D<2Z93l7HGp=>NRTV|qziVG9ijN&E7fQ9^QaC*w zSG+QeOp+J1oGeGd(GWB-%z!zy82Cs!2G6Fc0eUHAJo+|ltoUY5*~g!u6@9%K_Yw-L zGt<-MO3h0_I!v>nPfz6#l*g~_3Va)z3-TfL3ua33G4xz0#^T9vwotC*f&guR1;x2w zJe-9qGgY<4WvWj7Fu@gyOSz1@BUO#5Fru!N!YtG*ryqc8>`KAkMw5U{r5y$|*lMjZ zV}i1lW>MpX2~;l%hHBMBZRUpK%4{J|6Bc=4DIbGobH?2&rP+m^*Wv?-R_>t#2x$_j zPKt+!x>78M$ZRsK1z}zzF&#*gMh(ZGnTbK$RQ>H4*LQXE%bBX=K0Xshw5~WeL_fEa z?)yl`o!dV?6IbTctU5cKdnn^RCEDl{moI#ZUSE9@qA^{lL;Y@Al(xpbVRdMxSlnHV zt-Wj?`G~VIXIDs*PMMcGB+aeHZ8VXc8FvqTEIKE~7)XGE8{;+fVGj6X!`_ew1ktDZ^ z0UJAjZ#i5v4;>9Z^xT$ln-Yo*A)TeAH+mPeb$@uQFf}tZSYSqn2B;Y^d%x~Lk)e-H zNYnULJJdLC989M+yUH^qI-xB-b={%x=wMh2t@mgES=0{I&s|pj-{~K8z$f zrw)njT$Y}(c}Xe zxA|>hocn0T-R*_pXM=k}4GeR;kNH{Hfr>gStI&b*-N%pw($ah*xF^`P>j7h=HHm9_ z?PWA9>Bb=XcY#)EHf5#zOB>$X<7$=i8HPSHAW?drdib~2*=gkQdm0XYt+iyV6QdB+*?gq8y$2yN~R;u*7|tj*h_IY zHuG`!G3U}zM?>Q>Is+k06dPLIKr&dUFyo>pdT^PzPdfMgb1%R6PtTwF`7e(2{=>N+ zefF@U9jpO5|`{+Ivyz>mT=ayQ+wF!GZ^lAlAvgTsIOH+Nlm&znCU`qJ@< z$KT^d=?tCQb@yl#&yF&!7%j!MTCz;6YI|a|TFH-I-EKz9W1k*Pmch!A+HqxJb`5N9 zIvR7sdv|p9^tz<%&$lFHQ@?1){`~NB>yA)|^yjnk2We=jTWo@3;N^55}Zr73t)DG6;*XFT5?dub#O!o| z)RLt;cV^|4Rl?D1j`~_muNq7{_4dEr*!6}7?pv83kXJ^jr}*`T#TmLV20lqBFpKKL zxH1kt&3}>q33`Qq@@AkzHo;|dyvkD)25tu?*7xD61{K^X+z6;5zus83hm^7MDa%s; zv#e+Pn#r7Y;5ywlaupJqs`ymn5U3!*6B82t32=-0*vxUyVQ)O3{2I?`(#vj^yeeN5 zmMBM%il4EVrMU|j<@WhvD?M*C`Mj!~XdWkLsmXY^ESxv^B5tTFtWB zM!6$EDUWmaxeee;^<|LwDy7P-`80SMdiG9uRdzc)S_9W7z*PZT14k#EYOnvR>~{k% zZI>2Ra3$YHZQiNO9P*G>>F2@Bli<1^JQIdR8a)kfRFesK&&-OP2)=7lJeSqZEc5Rlo&!&< + + + NetTopologySuite + + + +

+ Utility functions for working with angles. + Unless otherwise noted, methods in this class express angles in radians. + + + + + Value of 2 * Pi + + + + + Value of Pi / 2 + + + + + Value of Pi / 4 + + + + + Converts from radians to degrees. + + An angle in radians + The angle in degrees + + + + Converts from degrees to radians. + + An angle in degrees + The angle in radians + + + + Returns the angle of the vector from p0 to p1, relative to the positive X-axis. + + The angle is normalized to be in the range [ -Pi, Pi ]. + The initial point of the vector. + The terminal point of the vector. + The normalized angle (in radians) that p0-p1 makes with the positive X-axis + + + + Returns the angle of the vector from (0,0) to p, relative to the positive X-axis. + + + The angle is normalized to be in the range ( -Pi, Pi ]. + + The terminal point of the vector. + The normalized angle (in radians) that (0,0)-p makes with the positive X-axis. + + + + Tests whether the angle between p0-p1-p2 is acute. + + + An angle is acute if it is less than 90 degrees. + Note: this implementation is not precise (deterministic) for angles very close to 90 degrees. + + An endpoint of the angle + The base of the angle + Another endpoint of the angle + if the angle is acute. + + + + Tests whether the angle between p0-p1-p2 is obtuse + + + An angle is obtuse if it is greater than 90 degrees. + Note: this implementation is not precise (deterministic) for angles very close to 90 degrees. + + An endpoint of the angle + The base of the angle + Another endpoint of the angle + if the angle is obtuse. + + + + Returns the unoriented smallest angle between two vectors. + + + The computed angle will be in the range [0, Pi). + + The tip of one vector + The tail of each vector + The tip of the other vector + + + + Returns the oriented smallest angle between two vectors. + The computed angle will be in the range (-Pi, Pi]. + A positive result corresponds to a rotation (CCW) from v1 to v2; + a negative result corresponds to a (CW) rotation; + a zero result corresponds to no rotation. + + The tip of v1 + The tail of each vector + The tip of v2 + The angle between v1 and v2, relative to v1 + + + + Computes the angle of the unoriented bisector + of the smallest angle between two vectors. + + The computed angle will be in the range (-Pi, Pi]. + The tip of v1 + The tail of each vector + The tip of v2 + The angle of the bisector between v1 and v2 + + + + Computes the interior angle between two segments of a ring. + The ring is assumed to be oriented in a clockwise direction. + + The computed angle will be in the range [0, 2Pi] + A point of the ring + The next point of the ring + The next point of the ring + The interior angle based at + + + + Returns whether an angle must turn clockwise or counterclockwise to overlap another angle. + + An angle (in radians) + An angle (in radians) + Whether a1 must turn , or to overlap a2. + + + + Computes the normalized value of an angle, which is the equivalent angle in the range ( -Pi, Pi ]. + + The angle to normalize + An equivalent angle in the range (-Pi, Pi] + + + + Computes the normalized positive value of an angle, which is the equivalent angle in the range [ 0, 2*Pi ). + + E.g. + + Function callResult + NormalizePositive(0.0)0.0 + NormalizePositive(-PI) + NormalizePositive(-2PI)0.0 + NormalizePositive(-3PI) + NormalizePositive(-4PI)0.0 + NormalizePositive(PI) + NormalizePositive(2PI)0.0 + NormalizePositive(3PI) + NormalizePositive(4PI)0.0 + + + + The angle to normalize, in radians. + An equivalent positive angle + + + + Computes the unoriented smallest difference between two angles. + + + + The angles are assumed to be normalized to the range [-Pi, Pi]. + The result will be in the range [0, Pi]. + + + The angle of one vector (in [-Pi, Pi] ) + The angle of the other vector (in range [-Pi, Pi] ) + The angle (in radians) between the two vectors (in range [0, Pi] ) + + + + Projects a point by a given angle and distance. + + The point to project + The angle at which to project + The distance to project + The projected point + + + + Functions for computing area. + + Martin Davis + + + + Computes the area for a ring. + + The coordinates forming the ring + The area of the ring + + + + Computes the area for a ring. + + The coordinates forming the ring + The area of the ring + + + + Computes the signed area for a ring. The signed area is positive if the + ring is oriented CW, negative if the ring is oriented CCW, and zero if the + ring is degenerate or flat. + + The coordinates forming the ring + The signed area of the ring + + + + Computes the signed area for a ring. The signed area is positive if the + + + value + meaning + + > 0 + The ring is oriented clockwise (CW) + < 0 + The ring is oriented counter clockwise (CCW) + == 0 + The ring is degenerate or flat + + ring is oriented CW, negative if the ring is oriented CCW, and zero if the + ring is degenerate or flat. + + The coordinates forming the ring + The signed area of the ring + + + + An interface for rules which determine whether node points + which are in boundaries of geometry components + are in the boundary of the parent geometry collection. + The SFS specifies a single kind of boundary node rule, + the rule. + However, other kinds of Boundary Node Rules are appropriate + in specific situations (for instance, linear network topology + usually follows the .) + Some JTS operations + (such as , and ) + allow the BoundaryNodeRule to be specified, + and respect the supplied rule when computing the results of the operation. + + An example use case for a non-SFS-standard Boundary Node Rule is + that of checking that a set of s have + valid linear network topology, when turn-arounds are represented + as closed rings. In this situation, the entry road to the + turn-around is only valid when it touches the turn-around ring + at the single (common) endpoint. This is equivalent + to requiring the set of LineStrings to be + simple under the . + The SFS-standard is not + sufficient to perform this test, since it + states that closed rings have no boundary points. + + This interface and its subclasses follow the Strategy design pattern. + + Martin Davis + + + + + + + + Tests whether a point that lies in boundaryCount + geometry component boundaries is considered to form part of the boundary + of the parent geometry. + + boundaryCount the number of component boundaries that this point occurs in + true if points in this number of boundaries lie in the parent boundary + + + + Provides access to static instances of common s. + + + + + The Mod-2 Boundary Node Rule (which is the rule specified in the OGC SFS). + + + + + The Endpoint Boundary Node Rule. + + + + The MultiValent Endpoint Boundary Node Rule. + + + + The Monovalent Endpoint Boundary Node Rule. + + + + + The Boundary Node Rule specified by the OGC Simple Features Specification, + which is the same as the Mod-2 rule. + + + + + + A specifies that points are in the + boundary of a lineal geometry if + the point lies on the boundary of an odd number + of components. + Under this rule s and closed + s have an empty boundary. + + + This is the rule specified by the OGC SFS, + and is the default rule used in JTS. + + Martin Davis + + + + A which specifies that any points which are endpoints + of lineal components are in the boundary of the + parent geometry. + This corresponds to the "intuitive" topological definition + of boundary. + Under this rule s have a non-empty boundary + (the common endpoint of the underlying LineString). + + + This rule is useful when dealing with linear networks. + For example, it can be used to check + whether linear networks are correctly noded. + The usual network topology constraint is that linear segments may touch only at endpoints. + In the case of a segment touching a closed segment (ring) at one point, + the Mod2 rule cannot distinguish between the permitted case of touching at the + node point and the invalid case of touching at some other interior (non-node) point. + The EndPoint rule does distinguish between these cases, + so is more appropriate for use. + + Martin Davis + + + + A which determines that only + endpoints with valency greater than 1 are on the boundary. + This corresponds to the boundary of a + being all the "attached" endpoints, but not + the "unattached" ones. + + Martin Davis + + + + A which determines that only + endpoints with valency of exactly 1 are on the boundary. + This corresponds to the boundary of a + being all the "unattached" endpoints. + + Martin Davis + + + + Computes the centroid of a of any dimension. + For collections the centroid is computed for the collection of + non-empty elements of highest dimension. + The centroid of an empty geometry is null + + +

Algorithm

+ + Dimension 2 - the centroid ic computed + as a weighted sum of the centroids + of a decomposition of the area into (possibly overlapping) triangles. + Holes and multipolygons are handled correctly. + See http://www.faqs.org/faqs/graphics/algorithms-faq/ + for further details of the basic approach. + Dimension 1 - Computes the average of the midpoints + of all line segments weighted by the segment length. + Zero-length lines are treated as points. + + Dimension 0 - Compute the average coordinate over all points. + Repeated points are all included in the average + + + If the input geometries are empty, a null Coordinate is returned. +
+ + + + 1.7 +
+ + + Computes the centroid point of a geometry. + + The geometry to use + + The centroid point, or null if the geometry is empty + + + + + the point all triangles are based at + + + + + temporary variable to hold centroid of triangle + + + + + Partial area sum + + + + + partial centroid sum + + + + + Creates a new instance for computing the centroid of a geometry + + + + + Adds a to the centroid total. + + >The to add. + + + + Gets the computed centroid. + + The computed centroid, or null if the input is empty + + + + Computes three times the centroid of the triangle p1-p2-p3. + The factor of 3 is + left in to permit division to be avoided until later. + + + + + Returns twice the signed area of the triangle p1-p2-p3. + The area is positive if the triangle is oriented CCW, and negative if CW. + + + + + Adds the line segments defined by an array of coordinates + to the linear centroid accumulators. + + An array of s + + + + Adds a point to the point centroid accumulator. + + A + + + + Basic computational geometry algorithms + for geometry and coordinates defined in 3-dimensional Cartesian space. + + Martin Davis + + + + Computes the distance between the points and + in 3D space + + The first point + The second point + The distance between the two points + + + + Computes the distance between the point and the + segment from to in 3D space + + The point + The start point of the segment + The end point of the segment + + + + Computes the distance between two 3D segments. + The start point of the first segment + The end point of the first segment + The start point of the second segment + The end point of the second segment + The distance between the segments + + + + Implements basic computational geometry algorithms using arithmetic. + + Martin Davis + + + + Returns the index of the direction of the point q relative to + a vector specified by p1-p2. + + The origin point of the vector + The final point of the vector + the point to compute the direction to + + + 1 if q is counter-clockwise (left) from p1-p2 + -1 if q is clockwise (right) from p1-p2 + 0 if q is collinear with p1-p2 + + + + + Returns the index of the direction of the point q relative to + a vector specified by p1-p2. + + The x-ordinate of the origin point of the vector + The y-ordinate of the origin point of the vector + The x-ordinate of the final point of the vector + The y-ordinate of the final point of the vector + The x-ordinate of the point to compute the direction to + The y-ordinate of the point to compute the direction to + + + 1 if q is counter-clockwise (left) from p1-p2 + -1 if q is clockwise (right) from p1-p2 + 0 if q is collinear with p1-p2 + + + + + Computes the sign of the determinant of the 2x2 matrix + with the given entries. + + + + + + + + -1 if the determinant is negative, + 1 if the determinant is positive, + 0 if the determinant is 0. + + + + + + A value which is safely greater than the + relative round-off error in double-precision numbers + + + + + A filter for computing the orientation index of three coordinates. + + If the orientation can be computed safely using standard DP + arithmetic, this routine returns the orientation index. + Otherwise, a value i > 1 is returned. + In this case the orientation index must + be computed using some other more robust method. + The filter is fast to compute, so can be used to + avoid the use of slower robust methods except when they are really needed, + thus providing better average performance. + + Uses an approach due to Jonathan Shewchuk, which is in the public domain. + + The x-ordinate of point A + The y-ordinate of point A + The x-ordinate of point B + The y-ordinate of point B + The x-ordinate of point C + The y-ordinate of point C + + + The orientation index if it can be computed safely + > 1 if the orientation index cannot be computed safely> + + + + + + Computes an intersection point between two lines + using DD arithmetic. + If the lines are parallel (either identical + or separate) a null value is returned. + + An endpoint of line segment 1 + An endpoint of line segment 1 + An endpoint of line segment 2 + An endpoint of line segment 2 + An intersection point if one exists, or null if lines are parallel. + + + + Constructs the Largest Empty Circle for a set + of obstacle geometries, up to a specified tolerance. + The obstacles are point and line geometries. + + The Largest Empty Circle is the largest circle which + has its center in the convex hull of the obstacles (the boundary), + and whose interior does not intersect with any obstacle. + The circle center is the point in the interior of the boundary + which has the farthest distance from the obstacles (up to tolerance). + The circle is determined by the center point + and a point lying on an obstacle indicating the circle radius. + + The implementation uses a successive-approximation technique + over a grid of square cells covering the obstacles and boundary. + The grid is refined using a branch-and-bound algorithm. + Point containment and distance are computed in a performant + way by using spatial indexes. + +

Future Enhancements

+ + Support polygons as obstacles + Support a client-defined boundary polygon + +
+ Martin Davis + + + +
+ + + Computes the center point of the Largest Empty Circle + within a set of obstacles, up to a given tolerance distance. + + A geometry representing the obstacles (points and lines) + The distance tolerance for computing the center point + The center point of the Largest Empty Circle + + + + Computes a radius line of the Largest Empty Circle + within a set of obstacles, up to a given distance tolerance. + + A geometry representing the obstacles (points and lines) + The distance tolerance for computing the center point + A line from the center of the circle to a point on the edge + + + + Creates a new instance of a Largest Empty Circle construction. + + A geometry representing the obstacles (points and lines) + The distance tolerance for computing the center point + + + + Sets the area boundary as the convex hull + of the obstacles. + + + + + Gets the center point of the Largest Empty Circle + (up to the tolerance distance). + + The center point of the Largest Empty Circle + + + + Gets a point defining the radius of the Largest Empty Circle. + This is a point on the obstacles which is + nearest to the computed center of the Largest Empty Circle. + The line segment from the center to this point + is a radius of the constructed circle, and this point + lies on the boundary of the circle. + + A point defining the radius of the Largest Empty Circle + + + + Gets a line representing a radius of the Largest Empty Circle. + + A line from the center of the circle to a point on the edge + + + + Computes the signed distance from a point to the constraints + (obstacles and boundary). + Points outside the boundary polygon are assigned a negative distance. + Their containing cells will be last in the priority queue + (but will still end up being tested since they may be refined). + + The point to compute the distance for + The signed distance to the constraints (negative indicates outside the boundary) + + + + Tests whether a cell may contain the circle center, + and thus should be refined (split into subcells + to be investigated further.) + + The cell to test + true if the cell might contain the circle center + + + + Initializes the queue with a grid of cells covering + the extent of the area. + + The area extent to cover + The queue to initialize + + + + A square grid cell centered on a given point + with a given side half-length, + and having a given distance from the center point to the constraints. + The maximum possible distance from any point in the cell to the + constraints can be computed. + This is used as the ordering and upper-bound function in + the branch-and-bound algorithm. + + + + + Constructs the Maximum Inscribed Circle for a + polygonal , up to a specified tolerance. + The Maximum Inscribed Circle is determined by a point in the interior of the area + which has the farthest distance from the area boundary, + along with a boundary point at that distance. + + In the context of geography the center of the Maximum Inscribed Circle + is known as the Pole of Inaccessibility. + A cartographic use case is to determine a suitable point + to place a map label within a polygon. + + The radius length of the Maximum Inscribed Circle is a + measure of how "narrow" a polygon is. It is the + distance at which the negative buffer becomes empty. + + The class supports polygons with holes and multipolygons. + + The implementation uses a successive-approximation technique + over a grid of square cells covering the area geometry. + The grid is refined using a branch-and-bound algorithm. + Point containment and distance are computed in a performant + way by using spatial indexes. +

Future Enhancements

+ + Support a polygonal constraint on placement of center + +
+ Martin Davis + + + +
+ + + Computes the center point of the Maximum Inscribed Circle + of a polygonal geometry, up to a given tolerance distance. + + A polygonal geometry + The distance tolerance for computing the center point + The center point of the maximum inscribed circle + + + + Computes a radius line of the Maximum Inscribed Circle + of a polygonal geometry, up to a given tolerance distance. + + A polygonal geometry + The distance tolerance for computing the center point + A line from the center to a point on the circle + + + + Creates a new instance of a Maximum Inscribed Circle computation. + + An areal geometry + The distance tolerance for computing the centre point + (must be positive) + Thrown if the tolerance is non-positive + Thrown if the input geometry is non-polygonal or empty + + + + Gets the center point of the maximum inscribed circle + (up to the tolerance distance). + The center point of the maximum inscribed circle + + + + Gets a point defining the radius of the Maximum Inscribed Circle. + This is a point on the boundary which is + nearest to the computed center of the Maximum Inscribed Circle. + The line segment from the center to this point + is a radius of the constructed circle, and this point + lies on the boundary of the circle. + + A point defining the radius of the Maximum Inscribed Circle + + + + Gets a line representing a radius of the Largest Empty Circle. + + A line from the center of the circle to a point on the edge + + + + Computes the signed distance from a point to the area boundary. + Points outside the polygon are assigned a negative distance. + Their containing cells will be last in the priority queue + (but may still end up being tested since they may need to be refined). + + The point to compute the distance for + The signed distance to the area boundary (negative indicates outside the area) + + + + Initializes the queue with a grid of cells covering + the extent of the area. + + The area extent to cover + The queue to initialize + + + + A square grid cell centered on a given point + with a given side half-length, + and having a given distance from the center point to the constraints. + The maximum possible distance from any point in the cell to the + constraints can be computed. + This is used as the ordering and upper-bound function in + the branch-and-bound algorithm. + + + + + Computes the convex hull of a . + The convex hull is the smallest convex Geometry that contains all the + points in the input Geometry. + Uses the Graham Scan algorithm. + + + + + Computes the convex hull for the given sequence of instances. + + + The instances whose convex hull to compute. + + + The convex hull of . + + + + + Create a new convex hull construction for the input Geometry. + + + + + + Create a new convex hull construction for the input array. + + + + + + + Returns a Geometry that represents the convex hull of the input point. + The point will contain the minimal number of points needed to + represent the convex hull. In particular, no more than two consecutive + points will be collinear. + + + If the convex hull contains 3 or more points, a Polygon; + 2 points, a LineString; + 1 point, a Point; + 0 points, an empty GeometryCollection. + + + + + Uses a heuristic to reduce the number of points scanned to compute the hull. + The heuristic is to find a polygon guaranteed to + be in (or on) the hull, and eliminate all points inside it. + A quadrilateral defined by the extremal points + in the four orthogonal directions + can be used, but even more inclusive is + to use an octilateral defined by the points in the 8 cardinal directions. + Note that even if the method used to determine the polygon vertices + is not 100% robust, this does not affect the robustness of the convex hull. + + To satisfy the requirements of the Graham Scan algorithm, + the returned array has at least 3 entries. + + + The coordinates to reduce + The reduced array of coordinates + + + + Pre sorts the coordinates + + + + + + + + + + + + + + + + + + + + Whether the three coordinates are collinear + and c2 lies between c1 and c3 inclusive. + + + + + + + + + + + + + + + + + + + + + The vertices of a linear ring, which may or may not be flattened (i.e. vertices collinear). + A 2-vertex LineString if the vertices are collinear; + otherwise, a Polygon with unnecessary (collinear) vertices removed. + + + + + + The vertices of a linear ring, which may or may not be flattened (i.e. vertices collinear). + The coordinates with unnecessary (collinear) vertices removed. + + + + Compares s for their angle and distance + relative to an origin. + + + + + Initializes a new instance of the class. + + + + + + + + + + + + + + + + + + + + + + + Functions to compute distance between basic geometric structures. + + Martin Davis + + + + Computes the distance from a line segment AB to a line segment CD + + Note: NON-ROBUST! + + The first point of the first line + The second point of the first line (must be different to A) + The first point of the second line + The second point of the second line (must be different to C) + The distance from a line segment AB to a line segment CD + + + + Computes the distance from a point to a sequence of line segments. + + A point + A sequence of contiguous line segments defined by their vertices + The minimum distance between the point and the line segments + + + + Computes the distance from a point to a sequence of line segments. + + A point + A sequence of contiguous line segments defined by their vertices + The minimum distance between the point and the line segments + + + + Computes the distance from a point p to a line segment AB + + Note: NON-ROBUST! + + The point to compute the distance for + The first point of the first line + The second point of the first line (must be different to A) + The distance from p to line segment AB + + + + Computes the perpendicular distance from a point p to the (infinite) line + containing the points AB + + The point to compute the distance for + The first point of the first line + The second point of the first line (must be different to A) + The perpendicular distance from p to line segment AB + + + + + Computes the Discrete Fréchet Distance between two s + using a cartesian distance computation function. + + The 1st geometry + The 2nd geometry + The cartesian distance between and + + + + Creates an instance of this class using the provided geometries. + + A geometry + A geometry + + + + Computes the Discrete Fréchet Distance between the input geometries + + The Discrete Fréchet Distance + + + + Creates a matrix to store the computed distances + + The number of rows + The number of cols + A matrix storage + + + + Gets the pair of s at which the distance is obtained. + + The pair of Coordinates at which the distance is obtained + + + + Computes the Fréchet Distance for the given distance matrix. + + An array of Coordinates + An array of Coordinates + An array of alternating col/row index values for the diagonal of the distance matrix + The distance matrix + A lookup for coordinate pairs based on a distance + + + + + Returns the minimum distance at the corner (, }). + + A (sparse) matrix + The row index + The column index + The minimum distance + + + + Computes relevant distances between pairs of s for the + computation of the Discrete Fréchet Distance. + + An array of Coordinates + An array of Coordinates + An array of alternating col/row index values for the diagonal of the distance matrix + The distance matrix + A lookup for coordinate pairs based on a distance + + +
+ Computes the indices for the diagonal of a numCols x numRows grid + using the + Bresenham's line algorithm. + + The number of columns + The number of rows + A packed array of column and row indices. + + + + Abstract base class for storing 2d matrix data + + + + + Gets a value indicating the number of rows + + + + + Gets a value indicating the number of columns + + + + + Gets a value indicating the default value + + + + Creates an instance of this class + The number of rows + The number of columns + A default value + + + + Gets or sets a value for the cell , + + The row index + The column index + The value of the cell , + + + + Gets a flag indicating if the matrix has a set value, e.g. one that is different + than . + + A flag indicating if the matrix has a set value + + + Straight forward implementation of a rectangular matrix + + + + Creates an instance of this matrix using the given number of rows and columns. + A default value can be specified. + + The number of rows + The number of columns + A default value + + + + A matrix implementation that adheres to the + + Compressed sparse row format.
+ Note: Unfortunately not as fast as expected. +
+
+ + + Creates an instance of this matrix using the given number of rows and columns. + A default value can be specified. + + The number of rows + The number of columns + A default value + + + + Creates an instance of this matrix using the given number of rows and columns. + A default value can be specified as well as the number of values expected. + + The number of rows + The number of columns + A default value + The amount of expected values + + + + Computes an initial value for the number of expected values + + The number of rows + The number of columns + The expected number of values in the sparse matrix + + + + Ensures that the column index vector (ci) and value vector (v) are sufficiently large. + + The number of items to store in the matrix + + + + A sparse matrix based on . + + + + + Creates an instance of this matrix using the given number of rows and columns. + A default value can be specified. + + The number of rows + The number of columns + A default value + + + + An algorithm for computing a distance metric + which is an approximation to the Hausdorff Distance + based on a discretization of the input . + + + + The algorithm computes the Hausdorff distance restricted to discrete points + for one of the geometries. + The points can be either the vertices of the geometries (the default), + or the geometries with line segments densified by a given fraction. + Also determines two points of the Geometries which are separated by the computed distance. + + + This algorithm is an approximation to the standard Hausdorff distance. + Specifically, + + for all geometries a, b: DHD(a, b) <= HD(a, b) + + The approximation can be made as close as needed by densifying the input geometries. + In the limit, this value will approach the true Hausdorff distance: + + DHD(A, B, densifyFactor) -> HD(A, B) as densifyFactor -> 0.0 + + The default approximation is exact or close enough for a large subset of useful cases. + + + Examples of these are: + + + computing distance between Linestrings that are roughly parallel to each other, + and roughly equal in length. This occurs in matching linear networks. + + Testing similarity of geometries. + + + + An example where the default approximation is not close is: + + A = LINESTRING (0 0, 100 0, 10 100, 10 100) + B = LINESTRING (0 100, 0 10, 80 10) + + DHD(A, B) = 22.360679774997898 + HD(A, B) ~= 47.8 + + + + + + + Computes the Discrete Hausdorff Distance of two s. + + A geometry + A geometry + The Discrete Hausdorff Distance + + + + Computes the Discrete Hausdorff Distance of two s. + + A geometry + A geometry + The densify fraction. A value of 0 indicates, that no densification should take place + The Discrete Hausdorff Distance + + + + Value of 0.0 indicates that no densification should take place + + + + + Creates an instance of this class using the provided geometries + + A geometry + Another geometry + + + + Gets or sets the fraction by which to densify each segment. + + + Each segment will be (virtually) split into a number of equal-length + sub-segments, whose fraction of the total length is closest + to the given fraction. + + + + + Computes the discrete hausdorff distance between the two assigned geometries. + + The discrete hausdorff distance + + + + Computes the discrete hausdorff distance between the 1st and the 2nd assigned geometry + + The discrete hausdorff distance. + + + + Gets a value indicating the + + + + + A coordinate filter that computes the maximum between points of + an assigned Geometry and all filtered geometries. + + + + + Creates an instance of this class + + A geometry + + + + + + + Gets a value indicating the maximum distance between + an assigned Geometry and the filtered one. + + + + + A coordinate filter that computes the maximum between points of + an assigned Geometry and all filtered geometries. The filtered geometries' line segments + are + + + + + Creates an instance of this filter class + + The geometry to densify + The densification fraction + + + + + + + As this filter does not change the geometry, the return value is always false + + + + As this filter does not end prematurely, the return value is always false + + + + Gets a value indicating the maximum distance between p + + + + + Computes the Euclidean distance (L2 metric) from a to a . + + + Also computes two points on the geometry which are separated by the distance found. + + + + + Computes the Euclidean distance (L2 metric) from a to a . + + The geometry + The Point + The PointPairDistance + + + + Computes the Euclidean distance (L2 metric) from a to a . + + The LineString + The Point + The PointPairDistance + + + + Computes the Euclidean distance (L2 metric) from a to a . + + The LineSegment + The Point + The PointPairDistance + + + + Computes the Euclidean distance (L2 metric) from a to a . + + The Polygon + The Point + The PointPairDistance + + + + Contains a pair of points and the distance between them. + + + Provides methods to update with a new point pair with either maximum or minimum distance. + + + + + Initializes this instance to null. + + + + + Initializes the points, computing the distance between them. + + 1st coordinate + 2nd coordinate + + + + Initializes the points, avoiding recomputing the distance. + + 1st coordinate + 2nd coordinate + the distance between and + + + + The distance between the paired coordinates + + The distance between the paired coordinates + + + + Gets a value indicating the paired coordinates. + + An array containing the paired points + + + + Gets the value of one of the paired points + + An index, valid are [0, 1]. + The Coordinate at index i. + + + + Updates this PointPairDistance if + has greater than this instance. + + The PointPairDistance to test. + + + + Updates this PointPairDistance if the distance between + and is greater than the + of this instance. + + The 1st point's coordinate + The 2nd point's coordinate + + + + Updates this PointPairDistance if + has a smaller than this instance. + + The PointPairDistance to test. + + + + Updates this PointPairDistance if the distance between + and is smaller than the + of this instance. + + The 1st point's coordinate + The 2nd point's coordinate + + + + + + + Represents a homogeneous coordinate in a 2-D coordinate space. + In NTS s are used as a clean way + of computing intersections between line segments. + + David Skea + + + + Computes the (approximate) intersection point between two line segments using homogeneous coordinates. + + + Note that this algorithm is + not numerically stable; i.e. it can produce intersection points which + lie outside the envelope of the line segments themselves. In order + to increase the precision of the calculation input points should be normalized + before passing them to this routine. + + 1st Coordinate of 1st linesegment + 2nd Coordinate of 1st linesegment + 1st Coordinate of 2nd linesegment + 2nd Coordinate of 2nd linesegment + + + + Computes the (approximate) intersection point between two line segments + using homogeneous coordinates. + Note that this algorithm is + not numerically stable; i.e. it can produce intersection points which + lie outside the envelope of the line segments themselves. In order + to increase the precision of the calculation input points should be normalized + before passing them to this routine. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Constructs a homogeneous coordinate which is the intersection of the lines s. + define by the homogeneous coordinates represented by two + + A coordinate + A coordinate + + + + Creates an instance of this + + + + + + + + + Constructs a concave hull of a set of points. + The hull is constructed by removing the longest outer edges + of the Delaunay Triangulation of the points + until a target criterion is reached. + + The target criteria are: + + Maximum Edge Length Ratiothe length of the longest edge of the hull is no larger + than this value. + Maximum Edge Length Factordetermine the Maximum Edge Length + as a fraction of the difference between the longest and shortest edge lengths + in the Delaunay Triangulation. + This normalizes the Maximum Edge Length to be scale-free. + A value of 1 produces the convex hull; a value of 0 produces maximum concaveness. + + The preferred criterion is the Maximum Edge Length Ratio, since it is + scale-free and local(so that no assumption needs to be made about the + total amount of concaveness present). + Other length criteria can be used by setting the Maximum Edge Length directly. + For example, use a length relative to the longest edge length + in the Minimum Spanning Tree of the point set. + Or, use a length derived from the value. + + The computed hull is always a single connected + (unless it is degenerate, in which case it will be a or a ). + This constraint may cause the concave hull to fail to meet the target criteria. + + Optionally the concave hull can be allowed to contain holes. + Note that when using the area-based criterion + this may result in substantially slower computation. + + Martin Davis + + + + Computes the approximate edge length of + a uniform square grid having the same number of + points as a geometry and the same area as its convex hull. + This value can be used to determine a suitable length threshold value + for computing a concave hull. + A value from 2 to 4 times the uniform grid length + seems to produce reasonable results. + + A geometry + The approximate uniform grid length + + + + Computes the concave hull of the vertices in a geometry + using the target criterion of maximum edge length. + + The input geometry + The target maximum edge length + The concave hull + + + + Computes the concave hull of the vertices in a geometry + using the target criterion of maximum edge length, + and optionally allowing holes. + + The input geometry + The target maximum edge length + A flag whether holes are allowed in the result + The concave hull + + + + Computes the concave hull of the vertices in a geometry + using the target criterion of maximum edge length ratio. + The edge length ratio is a fraction of the length difference + between the longest and shortest edges + in the Delaunay Triangulation of the input points. + + The input geometry + The target edge length ratio + The concave hull + + + + Computes the concave hull of the vertices in a geometry + using the target criterion of maximum edge length ratio, + and optionally allowing holes. + The edge length factor is a fraction of the length difference + between the longest and shortest edges + in the Delaunay Triangulation of the input points. + + The input geometry + The target edge length ratio + A flag whether holes are allowed in the result + The concave hull + + + + Creates a new instance for a given geometry. + + The input geometry + + + Gets or sets the target maximum edge length for the concave hull. + The length value must be zero or greater. + + The value 0.0 produces the concave hull of smallest area + that is still connected. + Larger values produce less concave results. + A value equal or greater than the longest Delaunay Triangulation edge length + produces the convex hull. + + The value may be used as + the basis for estimating an appropriate target maximum edge length. + + + The target maximum edge length for the concave hull + + + + Gets or sets the target maximum edge length ratio for the concave hull. + The edge length ratio is a fraction of the difference + between the longest and shortest edge lengths + in the Delaunay Triangulation of the input points. + It is a value in the range 0 to 1. + + The value 0.0 produces a concave hull of minimum area + that is still connected. + The value 1.0 produces the convex hull. + + + The target maximum edge length factor for the concave hull + + + + Gets or sets whether holes are allowed in the concave hull polygon. + + + + + Gets the computed concave hull. + + The concave hull + + + Computes the concave hull using edge length as the target criteria. + + + The erosion is done in two phases: first the border, then any + internal holes (if required). + This allows an fast connection check to be used + when eroding holes, + which makes this much more efficient than the area-based algorithm. + + The triangulation + + + + Adds a Tri to the queue. + Only add tris with a single border edge, + sice otherwise that would risk isolating a vertex. + Sets the ordering size to the length of the border edge. + + The Tri to add + The priority queue to add to + + + + Finds tris which may be the start of holes. + + + Only tris which have a long enough edge and which do not touch the current hull + boundary are included.
+ This avoids the risk of disconnecting the result polygon. + The list is sorted in decreasing order of edge length. +
+ The triangulation + The minimum length of edges to consider + A list of candidate tris that may start a hole +
+ + + Erodes a hole starting at a given triangle, + and eroding all adjacent triangles with boundary edge length above target. + + The triangulation + A tri which is a hole + + + + Tris which are used to form a concave hull. + If a Tri has an edge (or edges) with no adjacent tri + the tri is on the boundary of the triangulation. + The edge is a boundary edge. + The union of those edges + forms the (linear) boundary of the triangulation. + The triangulation area may be a Polygon or MultiPolygon, and may or may not contain holes. + + Martin Davis + + + + Sets the size to be the length of the boundary edges. + This is used when constructing hull without holes, + by erosion from the triangulation boundary. + + + + + Gets an index of a boundary edge, if there is one. + + A boundary edge index, or -1 + + + + Gets the most CCW boundary edge index. + This assumes there is at least one non-boundary edge. + + The CCW boundary edge index + + + + Gets the most CW boundary edge index. + This assumes there is at least one non-boundary edge. + + The CW boundary edge index + + + + Tests if this tri is the only one connecting its 2 adjacents. + Assumes that the tri is on the boundary of the triangulation + and that the triangulation does not contain holes + + true if the tri is the only connection + + + + Gets the index of a vertex which is adjacent to two other tris (if any). + + The vertex index or -1 + + + + Tests whether some vertex of this Tri has degree = 1. + In this case it is not in any other Tris. + + The triangulation + true if any vertex of this tri has a degree of 1 + + + + PriorityQueues sort in ascending order. + To sort with the largest at the head, + smaller sizes must compare as greater than larger sizes. + (i.e. the normal numeric comparison is reversed). + If the sizes are identical (which should be an infrequent case), + the areas are compared, with larger areas sorting before smaller. + (The rationale is that larger areas indicate an area of lower point density, + which is more likely to be in the exterior of the computed shape.) + This improves the determinism of the queue ordering. + + + + + Tests if this tri has a vertex which is in the boundary, + but not in a boundary edge. + + true if the tri touches the boundary at a vertex + + + + Tests if a triangulation is edge-connected, if a triangle is removed.
+ NOTE: this is a relatively slow operation. +
+ The triangulation + The triangle to remove + true if the triangulation is still connected +
+ + + Functions to operate on triangulations represented as + lists of s. + + + + + Creates a polygonal geometry representing the area of a triangulation + which may be disconnected or contain holes. + + The triangulation + The geometry factory + The area polygonal geometry + + + + Creates a Polygon representing the area of a triangulation + which is connected and contains no holes. + + The triangulation + The geometry factory to use + The area polygon + + + + Extracts the coordinates of the edgees along the boundary of a triangulation, + by tracing CW around the border triangles.
+ Assumption: there are at least 2 tris, they are connected, + and there are no holes. + So each tri has at least one non-border edge, and there is only one border. +
+ The triangulation + The border of the triangulation +
+ + + Computes an interior point of a . + An interior point is guaranteed to lie in the interior of the Geometry, + if it possible to calculate such a point exactly. + For collections the interior point is computed for the collection of + non-empty elements of highest dimension. + Otherwise, the point may lie on the boundary of the geometry. + + The interior point of an empty geometry is POINT EMPTY. +

Algorithm

+ The point is chosen to be "close to the center" of the geometry. + The location depends on the dimension of the input: + + Dimension 2the interior point is constructed in the middle of the longest interior segment + of a line bisecting the area. + Dimension 1the interior point is the interior or boundary vertex closest to the centroid. + Dimension 0the point is the point closest to the centroid. + + + + +
+
+ + + Computes a location of an interior point in a . + + Handles all geometry types. + + A geometry in which to find an interior point + the location of an interior point, or POINT EMPTY if the input is empty + + + + + Computes a location of an interior point in a . + + Handles all geometry types. + + + This function is called GetInteriorPoint in JTS. + It has been renamed to GetInteriorCoord to prevent a breaking change. + A geometry in which to find an interior point + the location of an interior point, or null if the input is empty + + + + + Computes a point in the interior of an areal geometry. + The point will lie in the geometry interior + in all except certain pathological cases. + + +

Algorithm:

+ For each input polygon: + + + Determine a horizontal scan line on which the interior + point will be located. + To increase the chance of the scan line + having non-zero-width intersection with the polygon + the scan line Y ordinate is chosen to be near the centre of the polygon's + Y extent but distinct from all of vertex Y ordinates. + + + Compute the sections of the scan line + which lie in the interior of the polygon. + + + Choose the widest interior section + and take its midpoint as the interior point. + + + The final interior point is chosen as + the one occurring in the widest interior section. + + This algorithm is a tradeoff between performance + and point quality (where points further from the geometry + boundary are considered to be higher quality) + Priority is given to performance. + This means that the computed interior point + may not be suitable for some uses + (such as label positioning). + + + The algorithm handles some kinds of invalid/degenerate geometry, + including zero-area and self-intersecting polygons. + + + Empty geometry is handled by returning a point. + +

KNOWN BUGS

+ + + If a fixed precision model is used, + in some cases this method may return a point + which does not lie in the interior. + + + If the input polygon is extremely narrow the computed point + may not lie in the interior of the polygon. + + +
+
+ + + Computes an interior point for the + polygonal components of a Geometry. + + The geometry to compute. + + The computed interior point, + or if the geometry has no polygonal components. + + + + + + + + + + + + + Creates a new interior point finder + for an areal geometry. + + An areal geometry + + + + Gets the computed interior point + or if the input geometry is empty. + + + + + Processes a geometry to determine + the best interior point for + all component polygons. + + The geometry to process. + + + + Computes an interior point of a component Polygon + and updates current best interior point + if appropriate. + + The polygon to process. + + + + Computes an interior point in a single , + as well as the width of the scan-line section it occurs in + to allow choosing the widest section occurrence. + + + + + Initializes a new instance of the class. + + The polygon to test. + + + + Gets the computed interior point, + or if the input geometry is empty. + + + + + Gets the width of the scanline section containing the interior point. + Used to determine the best point to use. + + + + + Compute the interior point. + + + + + Finds the midpoint of the widest interior section. + Sets the location and the + + + The list of scan-line X ordinates + + + + Tests if an edge intersection contributes to the crossing count. + Some crossing situations are not counted, + to ensure that the list of crossings + captures strict inside/outside topology. + + An endpoint of the segment. + An endpoint of the segment. + The Y-ordinate of the horizontal line. + if the edge crossing is counted. + + + + Computes the intersection of a segment with a horizontal line. + The segment is expected to cross the horizontal line + - this condition is not checked. + Computation uses regular double-precision arithmetic. + Test seems to indicate this is as good as using DD arithmetic. + + An endpoint of the segment. + An endpoint of the segment. + The Y-ordinate of the horizontal line + + + + + Tests if an envelope intersects a horizontal line. + + The envelope to test. + The Y-ordinate of the horizontal line. + if the envelope and line intersect. + + + + Tests if a line segment intersects a horizontal line. + + A segment endpoint. + A segment endpoint. + The Y-ordinate of the horizontal line. + if the segment and line intersect. + + + + Finds a safe scan line Y ordinate by projecting + the polygon segments + to the Y axis and finding the + Y-axis interval which contains the centre of the Y extent. + The centre of + this interval is returned as the scan line Y-ordinate. + + Note that in the case of (degenerate, invalid) + zero-area polygons the computed Y value + may be equal to a vertex Y-ordinate. + + + Martin Davis + + + + Computes a point in the interior of an linear point. + Algorithm: + Find an interior vertex which is closest to + the centroid of the linestring. + If there is no interior vertex, find the endpoint which is + closest to the centroid. + + + + + Computes an interior point for the + linear components of a Geometry. + + The geometry to compute. + + The computed interior point, + or if the geometry has no linear components. + + + + + + + + + + + + + + + + Tests the interior vertices (if any) + defined by a linear Geometry for the best inside point. + If a Geometry is not of dimension 1 it is not tested. + + The point to add. + + + + + + + + + + Tests the endpoint vertices + defined by a linear Geometry for the best inside point. + If a Geometry is not of dimension 1 it is not tested. + + The point to add. + + + + + + + + + + + + + + + + Computes a point in the interior of an point point. + Algorithm: + Find a point which is closest to the centroid of the point. + + + + + Computes an interior point for the + puntal components of a Geometry. + + The geometry to compute. + + The computed interior point, + or if the geometry has no puntal components. + + + + + + + + + + + Tests the point(s) defined by a Geometry for the best inside point. + If a Geometry is not of dimension 0 it is not tested. + + The point to add. + + + + + + + + + + + + + + + Functions to compute intersection points between lines and line segments. + + In general it is not possible to compute + the intersection point of two lines exactly, due to numerical roundoff. + This is particularly true when the lines are nearly parallel. + These routines uses numerical conditioning on the input values + to ensure that the computed value is very close to the correct value. + + The Z-ordinate is ignored, and not populated. + + mdavis + + + + Computes the intersection point of two lines. + If the lines are parallel or collinear this case is detected + and null is returned. + + An endpoint of line 1 + An endpoint of line 1 + An endpoint of line 2 + An endpoint of line 2 + + + NOTE: In JTS this function is called Intersection. + + The intersection point between the lines, if there is one, + or null if the lines are parallel or collinear + + + + + Computes the intersection point of a line and a line segment (if any). + There will be no intersection point if: + + the segment does not intersect the line + the line or the segment are degenerate (have zero length) + + If the segment is collinear with the line the first segment endpoint is returned. + + The intersection point, or null if it is not possible to find an intersection + + + + An interface for classes which determine the of points in a + + Martin Davis + + + + Determines the of a point in the . + + The point to test + the location of the point in the geometry + + + + Functions for computing length. + + + Martin Davis + + + + + Computes the length of a LineString specified by a sequence of points. + + The points specifying the LineString + The length of the LineString + + + + A LineIntersector is an algorithm that can both test whether + two line segments intersect and compute the intersection point(s) + if they do. + + There are three possible outcomes when determining whether two line segments intersect: + + - the segments do not intersect + - the segments intersect in a single point + - the segments are collinear and they intersect in a line segment + + + + For segments which intersect in a single point, the point may be either an endpoint + or in the interior of each segment. + If the point lies in the interior of both segments, + this is termed a proper intersection. + The property test for this situation. + + The intersection point(s) may be computed in a precise or non-precise manner. + Computing an intersection point precisely involves rounding it + via a supplied . + + LineIntersectors do not perform an initial envelope intersection test + to determine if the segments are disjoint. + This is because this class is likely to be used in a context where + envelope overlap is already known to occur (or be likely). + + + + + + Indicates that line segments do not intersect + + + + + Indicates that line segments intersect in a single point + + + + + Indicates that line segments intersect in a line segment + + + + + Computes the "edge distance" of an intersection point p along a segment. + The edge distance is a metric of the point along the edge. + The metric used is a robust and easy to compute metric function. + It is not equivalent to the usual Euclidean metric. + It relies on the fact that either the x or the y ordinates of the + points in the edge are unique, depending on whether the edge is longer in + the horizontal or vertical direction. + NOTE: This function may produce incorrect distances + for inputs where p is not precisely on p1-p2 + (E.g. p = (139,9) p1 = (139,10), p2 = (280,1) produces distance 0.0, which is incorrect. + My hypothesis is that the function is safe to use for points which are the + result of rounding points which lie on the line, but not safe to use for truncated points. + + + + + This function is non-robust, since it may compute the square of large numbers. + Currently not sure how to improve this. + + + + + A value indicating the intersection result + + Possible values are: + + + + + + + + + + Array of coordinate arrays forming the lines + + + + + Array of + + + + + The indexes of the endpoints of the intersection lines, in order along + the corresponding line + + + + + Alias the [0] for ease of reference + + + + + Alias the [1] for ease of reference + + + + + If MakePrecise is true, computed intersection coordinates will be made precise + using Coordinate.MakePrecise. + + + + + Creates an instance of this class + + + + + Force computed intersection to be rounded to a given precision model. + No getter is provided, because the precision model is not required to be specified. + + + + + Gets an endpoint of an input segment. + + the index of the input segment (0 or 1) + the index of the endpoint (0 or 1) + The specified endpoint + + + + Compute the intersection of a point p and the line p1-p2. + This function computes the bool value of the hasIntersection test. + The actual value of the intersection (if there is one) + is equal to the value of p. + + + + + Gets a value indicating if the computed intersection is collinear + + + + + Computes the intersection of the lines p1-p2 and p3-p4. + This function computes both the bool value of the hasIntersection test + and the (approximate) value of the intersection point itself (if there is one). + + The 1st point of the 1st segment + The 2nd point of the 1st segment + The 1st point of the 2nd segment + The 2nd point of the 2nd segment + + + + Computes the intersection of two line segments, one defined by and , + the other by and . + + The 1st point of the 1st segment + The 2nd point of the 1st segment + The 1st point of the 2nd segment + The 2nd point of the 2nd segment + + + Don't use this function directly, it is not meant for public use. + Please call + and test or along with and + . + + + + + + + + Gets a value indicating if the intersection is an end-point intersection + + + + + Tests whether the input geometries intersect. + + true if the input geometries intersect. + + + + Returns the number of intersection points found. This will be either 0, 1 or 2. + + The number of intersection points found (0, 1, or 2) + + + + Returns the intIndex'th intersection point. + + is 0 or 1. + The intIndex'th intersection point. + + + + Computes the values. + + + + + Test whether a point is a intersection point of two line segments. + Note that if the intersection is a line segment, this method only tests for + equality with the endpoints of the intersection segment. + It does not return true if the input point is internal to the intersection segment. + + true if the input point is one of the intersection points. + + + + Tests whether either intersection point is an interior point of one of the input segments. + + + true if either intersection point is in the interior of one of the input segment. + + + + + Tests whether either intersection point is an interior point of the specified input segment. + + + true if either intersection point is in the interior of the input segment. + + + + + Tests whether an intersection is proper. + The intersection between two line segments is considered proper if + they intersect in a single point in the interior of both segments + (e.g. the intersection is a single point and is not equal to any of the endpoints). + The intersection between a point and a line segment is considered proper + if the point lies in the interior of the segment (e.g. is not equal to either of the endpoints). + + true if the intersection is proper. + + + + Computes the intIndex'th intersection point in the direction of + a specified input line segment. + + is 0 or 1. + is 0 or 1. + + The intIndex'th intersection point in the direction of the specified input line segment. + + + + + Computes the index (order) of the intIndex'th intersection point in the direction of + a specified input line segment. + + is 0 or 1. + is 0 or 1. + + The index of the intersection point along the segment (0 or 1). + + + + + Computes the intersection line index + + The segment index + + + + Computes the "edge distance" of an intersection point along the specified input line segment. + + is 0 or 1. + is 0 or 1. + The edge distance of the intersection point. + + + + Determines the of s relative to + an areal geometry, using indexing for efficiency. + This algorithm is suitable for use in cases where + many points will be tested against a given area. + + The Location is computed precisely, th that points + located on the geometry boundary or segments will + return . + + and geometries are supported. + + The index is lazy-loaded, which allows + creating instances even if they are not used. + + Thread-safe and immutable. + + Martin Davis + + + + Creates a new locator for a given . + and geometries are supported + + The Geometry to locate in + + + + Determines the of a point in an areal . + + The point to test + The location of the point in the geometry + + + + + Creates the indexed geometry, creating it if necessary. + + + + + An interface for classes which determine the of + points in areal geometries. + + Martin Davis + + + + Determines the of a point in an areal . + + The point to test + The location of the point in the geometry + + + + Static methods for classes + + + + + Convenience method to test a point for intersection with a geometry + + The geometry is wrapped in a class. + + The locator to use. + The coordinate to test. + true if the point is in the interior or boundary of the geometry. + + + + Computes the location of points + relative to an areal , + using a simple O(n) algorithm. + + The algorithm used reports + if a point lies in the interior, exterior, + or exactly on the boundary of the Geometry. + + + Instance methods are provided to implement + the interface . + However, they provide no performance + advantage over the class methods. + + + This algorithm is suitable for use in cases where + only a few points will be tested. + If many points will be tested, + may provide better performance. + + + The algorithm used is only guaranteed to return correct results for points which are not on the boundary of the Geometry. + + + + Determines the of a point in an areal . + The return value is one of: + + if the point is in the geometry interior + if the point lies exactly on the boundary + if the point is outside the geometry + + + The point to test + The areal geometry to test + The Location of the point in the geometry + + + + Determines whether a point is contained in a , + or lies on its boundary. + This is a convenience method for + + Location.Exterior != Locate(p, geom) + + + The point to test. + The geometry to test. + if the point lies in or on the geometry. + + + + Determines whether a point lies in a . + If the point lies on the polygon boundary it is + considered to be inside. + + The point to test + The areal geometry to test + true if the point lies in the polygon + + + + Determines whether a point lies in a LinearRing, using the ring envelope to short-circuit if possible. + + The point to test + A linear ring + true if the point lies inside the ring + + + + Initializes a new instance of the class, + using the provided areal geometry. + + The areal geometry to locate in. + + + + Determines the of a point in an areal . + The return value is one of: + + if the point is in the geometry interior + if the point lies exactly on the boundary + if the point is outside the geometry + + + The point to test + The Location of the point in the geometry. + + + + Measures the degree of similarity between two s + using the area of intersection between the geometries. + The measure is normalized to lie in the range [0, 1]. + Higher measures indicate a great degree of similarity. + + + NOTE: Currently experimental and incomplete. + + mbdavis + + + + Computes the similarity measure between two geometries + + A geometry. + A geometry. + + The value of the similarity measure, in [0.0, 1.0]. + + + + + Measures the degree of similarity between two + s using the Fréchet distance metric. + The measure is normalized to lie in the range [0, 1]. + Higher measures indicate a great degree of similarity. + + The measure is computed by computing the Fréchet distance + between the input geometries, and then normalizing + this by dividing it by the diagonal distance across + the envelope of the combined geometries. + + Note: the input should be normalized, especially when + measuring geometries because for the + Fréchet distance the order of {@link Coordinate}s is + important. + + Felix Obermaier + + + + Creates an instance of this class + + + + + + + + Measures the degree of similarity between two s using the Hausdorff distance metric. + + + + The measure is normalized to lie in the range [0, 1]. Higher measures indicate a great degree of similarity. + + + The measure is computed by computing the Hausdorff distance between the input geometries, and then normalizing + this by dividing it by the diagonal distance across the envelope of the combined geometries. + + + mbdavis + + + + + + + + + + + An interface for classes which measures the degree of similarity between two {@link Geometry}s. + + + The computed measure lies in the range [0, 1]. + Higher measures indicate a great degree of similarity. + A measure of 1.0 indicates that the input geometries are identical + A measure of 0.0 indicates that the geometries have essentially no similarity. + The precise definition of "identical" and "no similarity" may depend on the exact algorithm being used. + + mbdavis + + + + Function to measure the similarity between two s. + + A geometry + A geometry + The similarity value between two s + + + + Provides methods to mathematically combine values. + + Martin Davis + + + + + + + + + + + + Computes the Minimum Bounding Circle (MBC) for the points in a . + The MBC is the smallest circle which covers all the input points + (this is also sometimes known as the Smallest Enclosing Circle). + This is equivalent to computing the Maximum Diameter of the input point set. + + + + The computed circle can be specified in two equivalent ways, + both of which are provide as output by this class: + + As a centre point and a radius + By the set of points defining the circle. + Depending on the number of points in the input + and their relative positions, this set + contains from 0 to 3 points. + + 0 or 1 points indicate an empty or trivial input point arrangement. + 2 points define the diameter of the minimum bounding circle. + 3 points define an inscribed triangle of the minimum bounding circle. + + + + The class can also output a which approximates the + shape of the Minimum Bounding Circle (although as an approximation + it is not guaranteed to cover all the input points.) + + The Maximum Diameter of the input point set can + be computed as well. The Maximum Diameter is + defined by the pair of input points with maximum distance between them. + The points of the maximum diameter are two of the extremal points of the Minimum Bounding Circle. + They lie on the convex hull of the input. + However, that the maximum diameter is not a diameter + of the Minimum Bounding Circle in the case where the MBC is + defined by an inscribed triangle. + + Martin Davis + + + + Creates a new object for computing the minimum bounding circle for the + point set defined by the vertices of the given geometry. + + The geometry to use to obtain the point set + + + + Gets a geometry which represents the Minimum Bounding Circle. + + + + If the input is degenerate (empty or a single unique point), + this method will return an empty geometry or a single Point geometry. + Otherwise, a Polygon will be returned which approximates the + Minimum Bounding Circle. (Note that because the computed polygon is only an approximation, it may not precisely contain all the input points.) + + + A Geometry representing the Minimum Bounding Circle. + + + Gets a geometry representing the maximum diameter of the + input. The maximum diameter is the longest line segment + between any two points of the input. + + The points are two of the extremal points of the Minimum Bounding Circle. + They lie on the convex hull of the input. + + + The result is + + a LineString between the two farthest points of the input + a empty LineString if the input is empty + a Point if the input is a point + + + + + + Gets a geometry representing a line between the two farthest points + in the input. + + These points are two of the extremal points of the Minimum Bounding Circle + They lie on the convex hull of the input. + + A LineString between the two farthest points of the input + An empty LineString if the input is empty + A Point if the input is a point + + + + Finds the farthest pair out of 3 extremal points + + The array of extremal points + The pair of farthest points + + + + Gets a geometry representing the diameter of the computed Minimum Bounding Circle. + + + + the diameter line of the Minimum Bounding Circle + an empty line if the input is empty + a Point if the input is a point + + + + + + Gets the extremal points which define the computed Minimum Bounding Circle. + There may be zero, one, two or three of these points, depending on the number + of points in the input and the geometry of those points. + + 0 or 1 points indicate an empty or trivial input point arrangement. + 2 points define the diameter of the Minimum Bounding Circle. + 3 points define an inscribed triangle of which the Minimum Bounding Circle is the circumcircle. + The longest chords of the circle are the line segments [0-1] and[1 - 2] + + + The points defining the Minimum Bounding Circle + + + + Gets the centre point of the computed Minimum Bounding Circle. + + + + The centre point of the Minimum Bounding Circle or + null if the input is empty + + + + + + Gets the radius of the computed Minimum Bounding Circle. + + The radius of the Minimum Bounding Circle + + + + Computes the minimum diameter of a . + + + + The minimum diameter is defined to be the + width of the smallest band that contains the point, + where a band is a strip of the plane defined + by two parallel lines. + This can be thought of as the smallest hole that the point can be + moved through, with a single rotation. + + + The first step in the algorithm is computing the convex hull of the Geometry. + If the input Geometry is known to be convex, a hint can be supplied to + avoid this computation. + + + This class can also be used to compute a line segment representing + the minimum diameter, the supporting line segment of the minimum diameter, + and a minimum rectangle enclosing the input geometry. + This rectangle will + have width equal to the minimum diameter, and have one side + parallel to the supporting segment. + + + + + + + Gets the minimum rectangle enclosing a geometry. + + The geometry + The minimum rectangle enclosing the geometry + + + + Gets the minimum diameter enclosing a geometry. + + The geometry + The length of the minimum diameter of the geometry + + + + Compute a minimum diameter for a given . + + a Geometry. + + + + Compute a minimum diameter for a giver Geometry, + with a hint if + the Geometry is convex + (e.g. a convex Polygon or LinearRing, + or a two-point LineString, or a Point). + + a Geometry which is convex. + true if the input point is convex. + + + + Gets the length of the minimum diameter of the input Geometry. + + The length of the minimum diameter. + + + + Gets the Coordinate forming one end of the minimum diameter. + + A coordinate forming one end of the minimum diameter. + + + + Gets the segment forming the base of the minimum diameter. + + The segment forming the base of the minimum diameter. + + + + Gets a LineString which is a minimum diameter. + + A LineString which is a minimum diameter. + + + + + + + + + + + + + + + Compute the width information for a ring of Coordinates. + Leaves the width information in the instance variables. + + + + + + + + + + + + + + + + + + + + + + + Gets the minimum rectangular which encloses the input geometry. + + + + The rectangle has width equal to the minimum diameter, and a longer length. + If the convex hull of the input is degenerate (a line or point) a or is returned. + + + The minimum rectangle can be used as an extremely generalized representation for the given geometry. + + + The minimum rectangle enclosing the input (or a line or point if degenerate) + + + + + + + + + + + + + + Functions to compute the orientation of basic geometric structures + including point triplets(triangles) and rings. + Orientation is a fundamental property of planar geometries + (and more generally geometry on two-dimensional manifolds). + + Determining triangle orientation + is notoriously subject to numerical precision errors + in the case of collinear or nearly collinear points. + NTS uses extended-precision arithmetic to increase + the robustness of the computation. + + + Martin Davis + + + + + Returns the orientation index of the direction of the point relative to + a directed infinite line specified by p1->p2. + The index indicates whether the point lies to the + or of the line, or lies on it . + The index also indicates the orientation of the triangle formed by the three points + (, , or + ) + + The origin point of the line vector + The final point of the line vector + The point to compute the direction to + + The of q in regard to the vector p1->p2 + + + ValueDescription + + + , + is collinear with p1->p2 + + + , + is clockwise (right) from p1->p2 + + + , + is counter-clockwise (left) from p1->p2 + + + + + + + Tests if a ring defined by an array of s is + oriented counter-clockwise. + + The list of points is assumed to have the first and last points equal. + This handles coordinate lists which contain repeated points. + This handles rings which contain collapsed segments (in particular, along the top of the ring). + + This algorithm is guaranteed to work with valid rings. + It also works with "mildly invalid" rings + which contain collapsed(coincident) flat segments along the top of the ring. + If the ring is "more" invalid (e.g.self-crosses or touches), + the computed result may not be correct. + + An array of Coordinates forming a ring (with first and last point identical) + true if the ring is oriented counter-clockwise. + + + + Tests if a ring defined by a is + oriented counter-clockwise. + + The list of points is assumed to have the first and last points equal. + This handles coordinate lists which contain repeated points. + This handles rings which contain collapsed segments (in particular, along the top of the ring). + + This algorithm is guaranteed to work with valid rings. + It also works with "mildly invalid" rings + which contain collapsed(coincident) flat segments along the top of the ring. + If the ring is "more" invalid (e.g.self-crosses or touches), + the computed result may not be correct. + + A CoordinateSequences forming a ring (with first and last point identical). + true if the ring is oriented counter-clockwise. + + + + Tests if a ring defined by an array of s is + oriented counter-clockwise, using the signed area of the ring. + + The list of points is assumed to have the first and last points equal. + This handles coordinate lists which contain repeated points. + This handles rings which contain collapsed segments + (in particular, along the top of the ring). + This handles rings which are invalid due to self-intersection + + This algorithm is guaranteed to work with valid rings. + For invalid rings (containing self-intersections), + the algorithm determines the orientation of + the largest enclosed area (including overlaps). + This provides a more useful result in some situations, such as buffering. + + However, this approach may be less accurate in the case of + rings with almost zero area. + (Note that the orientation of rings with zero area is essentially + undefined, and hence non-deterministic.) + + An array of Coordinates forming a ring (with first and last point identical) + true if the ring is oriented counter-clockwise. + + + + Tests if a ring defined by a is + oriented counter-clockwise, using the signed area of the ring. + + The list of points is assumed to have the first and last points equal. + This handles coordinate lists which contain repeated points. + This handles rings which contain collapsed segments + (in particular, along the top of the ring). + This handles rings which are invalid due to self-intersection + + This algorithm is guaranteed to work with valid rings. + For invalid rings (containing self-intersections), + the algorithm determines the orientation of + the largest enclosed area (including overlaps). + This provides a more useful result in some situations, such as buffering. + + However, this approach may be less accurate in the case of + rings with almost zero area. + (Note that the orientation of rings with zero area is essentially + undefined, and hence non-deterministic.) + + An array of Coordinates forming a ring (with first and last point identical) + true if the ring is oriented counter-clockwise. + + + + Re-orients an orientation. + + The orientation + + + + + Angle orientation + + + + A value that indicates an orientation of collinear, or no turn (straight) + + + A value that indicates an orientation of collinear, or no turn (straight) + + + A value that indicates an orientation of collinear, or no turn (straight) + + + A value that indicates an orientation of counterclockwise, or a left turn. + + + A value that indicates an orientation of counterclockwise, or a left turn. + + + A value that indicates an orientation of clockwise or a right turn. + + + A value that indicates an orientation of clockwise or a right turn. + + + + Functions for locating points within basic geometric + structures such as lines and rings. + + Martin Davis + + + + Tests whether a point lies on the line defined by a list of + coordinates. + + The point to test + The line coordinates + + true if the point is a vertex of the line or lies in the interior + of a line segment in the line + + + + + Tests whether a point lies on the line defined by a list of + coordinates. + + The point to test + The line coordinates + + true if the point is a vertex of the line or lies in the interior + of a line segment in the line + + + + + Tests whether a point lies inside or on a ring. The ring may be oriented in + either direction. A point lying exactly on the ring boundary is considered + to be inside the ring. + + This method does not first check the point against the envelope of + the ring. + + The point to check for ring inclusion + An array of coordinates representing the ring (which must have + first point identical to last point) + true if p is inside ring + + + + + Tests whether a point lies inside or on a ring. The ring may be oriented in + either direction. A point lying exactly on the ring boundary is considered + to be inside the ring. + + This method does not first check the point against the envelope of + the ring. + + The point to check for ring inclusion + A CoordinateSequence representing the ring (which must have + first point identical to last point) + true if p is inside ring + + + + Determines whether a point lies in the interior, on the boundary, or in the + exterior of a ring.The ring may be oriented in either direction. + + This method does not first check the point against the envelope of + the ring. + + The point to check for ring inclusion + A CoordinateSequence representing the ring (which must have + first point identical to last point) + the of p relative to the ring + + + + Determines whether a point lies in the interior, on the boundary, or in the + exterior of a ring.The ring may be oriented in either direction. + + This method does not first check the point against the envelope of + the ring. + + The point to check for ring inclusion + A CoordinateSequence representing the ring (which must have + first point identical to last point) + + + + Computes the topological relationship () of a single point to a Geometry. + + + A may be specified to control the evaluation of whether the point lies on the boundary or not + The default rule is to use the SFS Boundary Determination Rule + + Notes: + + s do not enclose any area - points inside the ring are still in the EXTERIOR of the ring. + + Instances of this class are not reentrant. + + + + + + Initializes a new instance of the class. + The default boundary rule is . + + + + + Initializes a new instance of the class using the provided + boundary rule. + + The boundary rule to use. + + + + Convenience method to test a point for intersection with a Geometry + + The coordinate to test. + The Geometry to test. + true if the point is in the interior or boundary of the Geometry. + + + + Computes the topological relationship ({Location}) of a single point to a Geometry. + It handles both single-element and multi-element Geometries. + The algorithm for multi-part Geometries takes into account the boundaryDetermination rule. + + The Location of the point relative to the input Geometry. + + + + Counts the number of segments crossed by a horizontal ray extending to the right + from a given point, in an incremental fashion. + This can be used to determine whether a point lies in a geometry. + The class determines the situation where the point lies exactly on a segment. + When being used for Point-In-Polygon determination, this case allows short-circuiting the evaluation. + + + This class handles polygonal geometries with any number of shells and holes. + The orientation of the shell and hole rings is unimportant. + In order to compute a correct location for a given polygonal geometry, + it is essential that all segments are counted which + + touch the ray + lie in in any ring which may contain the point + + + The only exception is when the point-on-segment situation is detected, in which + case no further processing is required. + The implication of the above rule is that segments which can be a priori determined to not touch the ray + (i.e. by a test of their bounding box or Y-extent) do not need to be counted. This allows for optimization by indexing. + + + This implementation uses the extended-precision orientation test, + to provide maximum robustness and consistency within + other algorithms. + + + Martin Davis + + + + Determines the of a point in a ring. + This method is an exemplar of how to use this class. + + The point to test + An array of Coordinates forming a ring + The location of the point in the ring + + + + Determines the of a point in a ring. + + The point to test + A coordinate sequence forming a ring + The location of the point in the ring + + + + Creates an instance of this class + + A coordinate. + + + + Counts a segment + + An endpoint of the segment + Another endpoint of the segment + + + + Reports whether the point lies exactly on one of the supplied segments. + + + This method may be called at any time as segments are processed. If the result of this method is true, + no further segments need be supplied, since the result will never change again. + + + + + Gets the of the point relative to the ring, polygon + or multipolygon from which the processed segments were provided. + + + This property only determines the correct location + if all relevant segments have been processed. + + + + + Tests whether the point lies in or on + the ring, polygon or multipolygon from which the processed + segments were provided. + + + This property only determines the correct location + if all relevant segments have been processed + + + + + Computes whether a rectangle intersects line segments. + + + Rectangles contain a large amount of inherent symmetry + (or to put it another way, although they contain four + coordinates they only actually contain 4 ordinates + worth of information). + The algorithm used takes advantage of the symmetry of + the geometric situation + to optimize performance by minimizing the number + of line intersection tests. + + Martin Davis + + + + Creates a new intersector for the given query rectangle, + specified as an . + + The query rectangle, specified as an Envelope + + + + Tests whether the query rectangle intersects a given line segment. + + The first endpoint of the segment + The second endpoint of the segment + true if the rectangle intersects the segment + + + + Implements an algorithm to compute the + sign of a 2x2 determinant for double precision values robustly. + It is a direct translation of code developed by Olivier Devillers. + + The original code carries the following copyright notice: + ************************************************************************ + Author : Olivier Devillers + Olivier.Devillers@sophia.inria.fr + http:/www.inria.fr:/prisme/personnel/devillers/anglais/determinant.html + + Olivier Devillers has allowed the code to be distributed under + the LGPL (2012-02-16) saying "It is ok for LGPL distribution." + + ************************************************************************* + ************************************************************************* + Copyright (c) 1995 by INRIA Prisme Project + BP 93 06902 Sophia Antipolis Cedex, France. + All rights reserved + ************************************************************************* + + + + + Computes the sign of the determinant of the 2x2 matrix with the given entries, in a robust way. + + + + + + + + -1 if the determinant is negative, + 1 if the determinant is positive, + 0 if the determinant is null. + + + + + + Returns the index of the direction of the point q relative to + a vector specified by p1-p2. + + The origin point of the vector + The final point of the vector + the point to compute the direction to + + + 1 if q is counter-clockwise (left) from p1-p2 + -1 if q is clockwise (right) from p1-p2 + 0 if q is collinear with p1-p2 + + + + + A robust version of . + + + + + + + + + + + + + + + + This method computes the actual value of the intersection point. + To obtain the maximum precision from the intersection calculation, + the coordinates are normalized by subtracting the minimum + ordinate values (in absolute value). This has the effect of + removing common significant digits from the calculation to + maintain more bits of precision. + + + + + + + + + + Computes a segment intersection using homogeneous coordinates. + Round-off error can cause the raw computation to fail, + (usually due to the segments being approximately parallel). + If this happens, a reasonable approximation is computed instead. + + + + + Tests whether a point lies in the envelopes of both input segments. + A correctly computed intersection point should return true + for this test. + Since this test is for debugging purposes only, no attempt is + made to optimize the envelope test. + + + true if the input point lies within both input segment envelopes. + + + + Finds the endpoint of the segments P and Q which + is closest to the other segment. + This is a reasonable surrogate for the true + intersection points in ill-conditioned cases + (e.g. where two segments are nearly coincident, + or where the endpoint of one segment lies almost on the other segment). + + + This replaces the older CentralEndpoint heuristic, + which chose the wrong endpoint in some cases + where the segments had very distinct slopes + and one endpoint lay almost on the other segment. + + an endpoint of segment P + an endpoint of segment P + an endpoint of segment Q + an endpoint of segment Q + the nearest endpoint to the other segment + + + + Gets the Z value of a coordinate if present, or + interpolates it from the segment it lies on. + If the segment Z values are not fully populate + NaN is returned. + + A coordinate, possibly with Z + A segment endpoint, possibly with Z + A segment endpoint, possibly with Z + The extracted or interpolated Z value (may be NaN) + + + + Interpolates a Z value for a point along + a line segment between two points. + The Z value of the interpolation point (if any) is ignored. + If either segment point is missing Z, + returns NaN. + + A coordinate, possibly with Z + A segment endpoint, possibly with Z + A segment endpoint, possibly with Z + The extracted or interpolated Z value (may be NaN) + + + + Interpolates a Z value for a point along + two line segments and computes their average. + The Z value of the interpolation point (if any) is ignored. + If one segment point is missing Z that segment is ignored + if both segments are missing Z, returns NaN. + + A coordinate + A segment endpoint, possibly with Z + A segment endpoint, possibly with Z + A segment endpoint, possibly with Z + A segment endpoint, possibly with Z + The averaged interpolated Z value (may be NaN) + + + + Structure for a closed 1-dimensional ℝ-interval + + + + + The lower bound of the interval + + + + + The upper bound of the interval + + + + + Initializes this structure with = = + + The value for min and max + + + + Initializes this structure with and values + + The minimum interval values + The maximum interval values + + + + Method to expand + + + + + + + Gets a value if this interval is empty/undefined + + + + + + + + + + + + + + + + + Gets a value indicating the width of the + + + + + Gets a value indicating the centre of the interval (Min + Width * 0.5) + + + + + Function to compute an interval that contains this and + + The interval + An interval + + + + Function to test if this overlaps . + + The interval to test + true if this interval overlaps + + + + Function to test if this overlaps the interval ℝ[, ]. + + The minimum value of the interval + The maximum value of the interval + true if this interval overlaps the interval ℝ[, ] + + + + Function to test if this contains . + + This is more rigid than + The interval to test + true if this interval contains + + + + Function to test if this contains the interval ℝ[, ]. + + This is more rigid than + The minimum value of the interval + The maximum value of the interval + true if this interval contains the interval ℝ[, ] + + + + Function to test if this contains the value . + + The value to test + true if this interval contains the value + + + + Function to test if this intersects the interval . + + + + true if this interval intersects + + + + Function to test if this intersects the interval ℝ[, ]. + + The minimum value of the interval + The maximum value of the interval + true if this interval intersects the interval ℝ[, ]. + + + + Creates an empty or uninitialized Interval + + An empty or uninitialized + + + + Creates an interval with the range ℝ[,] + + The value + An + + + + Creates an interval with the range ℝ[,].
+ If necessary, val1 and val2 are exchanged. +
+ The minimum value + The maximum value + An +
+ + + Creates an interval with the range ℝ[,]. + + The template interval + An + + + + Equality operator for s + + The left-hand-side + The right-hand-side + true if the s are equal. + + + + Inequality operator for s + + The left-hand-side + The right-hand-side + true if the s are not equal. + + + + Densifies a geometry by inserting extra vertices along the line segments + contained in the geometry. + All segments in the created densified geometry will be no longer + than the given distance tolerance + (that is, all segments in the output will have length less than or equal to + the distance tolerance). + + + Densified polygonal geometries are guaranteed to be topologically correct. + + The coordinates created during densification respect the input geometry's . + + By default polygonal results are processed to ensure they are valid. + This processing is costly, and it is very rare for results to be invalid. + Validation processing can be disabled by setting the property to false. + + Note: At some future point this class will offer a variety of densification strategies. + + Martin Davis + + + + Densifies a geometry using a given distance tolerance, and respecting the input geometry's . + + The geometry densify + The distance tolerance () + The densified geometry + + + + Densifies a list of coordinates. + + The coordinate list + The densify tolerance + The precision model to apply on the new coordinates + The densified coordinate sequence + + + + Indicates whether areas should be topologically validated. +
Note: JTS name _isValidated +
+
+ + Creates a new densifier instance + The geometry to densify + + + + Gets or sets the distance tolerance for the densification. All line segments + in the densified geometry will be no longer than the distance tolerance. + The distance tolerance must be positive. + + + + + Gets or sets whether polygonal results are processed to ensure they are valid. + + true if polygonal input is validated. + + + + Gets the densified geometry. + + The densified geometry + + + + Indicates whether areas should be topologically validated. +
Note: JTS name _isValidated +
+
+ + + Creates a valid area geometry from one that possibly has bad topology + (i.e. self-intersections). Since buffer can handle invalid topology, but + always returns valid geometry, constructing a 0-width buffer "corrects" + the topology. Note this only works for area geometries, since buffer + always returns areas. This also may return empty geometries, if the input + has no actual area. + + An area geometry possibly containing self-intersections + A valid area geometry + + + + A graph containing s. + + + + + A HalfEdge which carries information + required to support . + + + + + Tests whether this edge is the starting segment + in a LineString being dissolved. + + true if this edge is a start segment + + + + Sets this edge to be the start segment of an input LineString. + + + + + Dissolves the linear components + from a collection of s. + into a set of maximal-length s + in which every unique segment appears once only. + The output linestrings run between node vertices + of the input, which are vertices which have + either degree 1, or degree 3 or greater. + + + Use cases for dissolving linear components + include generalization + (in particular, simplifying polygonal coverages), + and visualization + (in particular, avoiding symbology conflicts when + depicting shared polygon boundaries). + + + This class does NOT node the input lines. + If there are line segments crossing in the input, + they will still cross in the output. + + + + + Dissolves the linear components in a geometry. + + the geometry to dissolve + the dissolved lines + + + + Creates an instance of this class + + + + + Adds a to be dissolved. + Any number of geometries may be added by calling this method multiple times. + Any type of Geometry may be added. The constituent linework will be + extracted to be dissolved. + + geometry to be line-merged + + + + Adds a collection of Geometries to be processed. May be called multiple times. + Any dimension of Geometry may be added; the constituent linework will be + extracted. + + the geometries to be line-merged + + + + Gets the dissolved result as a . + + the dissolved lines + + + + For each edge in stack + (which must originate at a node) + extracts the line it initiates. + + + + + Updates the tracked ringStartEdge + if the given edge has a lower origin + (using the standard ordering). + + + Identifying the lowest starting node meets two goals: + * It ensures that isolated input rings are created using the original node and orientation. + * For isolated rings formed from multiple input linestrings, + it provides a canonical node and orientation for the output + (rather than essentially random, and thus hard to test). + + + + + + Builds a line starting from the given edge. + The start edge origin is a node (valence = 1 or >= 3), + unless it is part of a pure ring. + + + A pure ring has no other incident lines. + In this case the start edge may occur anywhere on the ring. + + + The line is built up to the next node encountered, + or until the start edge is re-encountered + (which happens if the edges form a ring). + + + + + + Adds edges around this node to the stack. + + + + + + A graph comprised of s. + It supports tracking the vertices in the graph + via edges incident on them, + to allow efficient lookup of edges and vertices. + + + This class may be subclassed to use a + different subclass of HalfEdge, + by overriding . + If additional logic is required to initialize + edges then + can be overridden as well. + + + + + Creates a single HalfEdge. + Override to use a different HalfEdge subclass. + + the origin location + a new with the given origin + + + + Creates a pair, using the HalfEdge type of the graph subclass + + + + A pair + + + + Adds an edge between the coordinates orig and dest + to this graph. + + + Only valid edges can be added (in particular, zero-length segments cannot be added) + + the edge origin location + the edge destination location + The created edge + null if the edge was invalid and not added + + + + + Test if an the coordinates for an edge form a valid edge (with non-zero length) + + The start coordinate + The end coordinate + true of the edge formed is valid + + + + Inserts an edge not already present into the graph. + + the edge origin location + the edge destination location + an existing edge with same orig (if any) + the created edge + + + + Gets all s in the graph. + Both edges of edge pairs are included. + + An enumeration of the graph edges + + + + Finds an edge in this graph with the given origin + and destination, if one exists. + + the origin location + the destination location + an edge with the given orig and dest, or null if none exists + + + + Builds an edge graph from geometries containing edges. + + + + + Adds the edges of a Geometry to the graph. + May be called multiple times. + Any dimension of Geometry may be added; the constituent edges are extracted. + + geometry to be added + + + + Adds the edges in a collection of s to the graph. + May be called multiple times. + Any dimension of may be added. + + the geometries to be added + + + + Represents a directed component of an edge in an . + HalfEdges link vertices whose locations are defined by s. + HalfEdges start at an origin vertex, + and terminate at a destination vertex. + HalfEdges always occur in symmetric pairs, with the method + giving access to the oppositely-oriented component. + HalfEdges and the methods on them form an edge algebra, + which can be used to traverse and query the topology + of the graph formed by the edges. + + To support graphs where the edges are sequences of coordinates + each edge may also have a direction point supplied. + This is used to determine the ordering + of the edges around the origin. + HalfEdges with the same origin are ordered + so that the ring of edges formed by them is oriented CCW. + + By design HalfEdges carry minimal information + about the actual usage of the graph they represent. + They can be subclassed to carry more information if required. + + HalfEdges form a complete and consistent data structure by themselves, + but an is useful to allow retrieving edges + by vertex and edge location, as well as ensuring + edges are created and linked appropriately. + + Martin Davis + + + + Creates a HalfEdge pair representing an edge + between two vertices located at coordinates p0 and p1. + + a vertex coordinate + a vertex coordinate + the HalfEdge with origin at p0 + + + + Initialize a symmetric pair of halfedges. + Intended for use by + subclasses. + + The edges are initialized to have each other + as the edge, and to have + pointers which point to edge other. + This effectively creates a graph containing a single edge. + + A halfedge + A symmetric halfedge + The initialized edge e0 + + + + Creates an edge originating from a given coordinate. + + the origin coordinate + + + + Links this edge with its sym (opposite) edge. + This must be done for each pair of edges created. + + The sym edge to link. + + + + Initializes this edge with as edge. + + A symmetric half edge. + + + + Gets the origin coordinate of this edge. + + + + + Gets the destination coordinate of this edge. + + + + + Gets a value indicating the X component of the direction vector. + + The X component of the direction vector + + + + Gets a value indicating the Y component of the direction vector. + + The Y component of the direction vector + + + + Gets a value indicating the direction point of this edge. + In the base case this is the dest coordinate + of the edge. + + Subclasses may override to + allow a HalfEdge to represent an edge with more than two coordinates. + + The direction point for the edge + + + + Gets or sets the symmetric (opposite) edge of this edge. + + + + + Gets the next edge CCW around the destination vertex of this edge. + If the destination vertex has degree 1 then this is the Sym edge. + + The next outgoing edge CCW around the destination vertex + + + + Gets the previous edge CW around the origin + vertex of this edge, + with that vertex being its destination. + + It is always true that e.Next.Prev == e + + Note that this requires a scan of the origin edges, + so may not be efficient for some uses. + + The previous edge CW around the origin vertex + + + + Gets the next edge CCW around the origin of this edge, + with the same origin.
+ If the origin vertex has degree 1 then this is the edge itself. + + e.ONext is equal to e.Sym.Next() +
+ The next edge around the origin +
+ + + Finds the edge starting at the origin of this edge + with the given dest vertex, if any. + + the dest vertex to search for + + the edge with the required dest vertex, + if it exists, or null + + + + + Tests whether this edge has the given orig and dest vertices. + + the origin vertex to test + the destination vertex to test + true if the vertices are equal to the ones of this edge + + + + Inserts an edge + into the ring of edges around the origin vertex of this edge, + ensuring that the edges remain ordered CCW. + The inserted edge must have the same origin as this edge. + + the edge to insert + + + + Finds the insertion edge for a edge + being added to this origin, + ensuring that the star of edges + around the origin remains fully CCW. + + The edge being added + The edge to insert after + + + + Insert an edge with the same origin after this one. + Assumes that the inserted edge is in the correct + position around the ring. + + the edge to insert (with same origin) + + + + Tests whether the edges around the origin + are sorted correctly. + Note that edges must be strictly increasing, + which implies no two edges can have the same direction point. + + true if the origin edges are sorted correctly + + + + + Finds the lowest edge around the origin, + using the standard edge ordering. + + The lowest edge around the origin + + + + Compares edges which originate at the same vertex + based on the angle they make at their origin vertex with the positive X-axis. + This allows sorting edges around their origin vertex in CCW order. + + + + + Implements the total order relation. + The angle of edge a is greater than the angle of edge b, + where the angle of an edge is the angle made by + the first segment of the edge with the positive x-axis. + When applied to a list of edges originating at the same point, + this produces a CCW ordering of the edges around the point. + Using the obvious algorithm of computing the angle is not robust, + since the angle calculation is susceptible to round off error. + + + A robust algorithm is: + 1. compare the quadrants the edge vectors lie in. + If the quadrants are different, + it is trivial to determine which edge has a greater angle. + 2. If the vectors lie in the same quadrant, the + function + can be used to determine the relative orientation of the vectors. + + + + + The X component of the distance between the orig and dest vertices. + + + + + The Y component of the distance between the orig and dest vertices. + + + + + Computes a string representation of a HalfEdge. + + + + + Provides a string representation of the edges around + the origin node of this edge. + + + Uses the subclass representation for each edge. + + A string showing the edges around the origin + + + + Computes the degree of the origin vertex. + The degree is the number of edges + originating from the vertex. + + the degree of the origin vertex + + + + Finds the first node previous to this edge, if any. + If no such node exists (i.e. the edge is part of a ring) + then null is returned. + + + an edge originating at the node prior to this edge, if any, + or null if no node exists + + + + + A which supports + marking edges with a boolean flag. + Useful for algorithms which perform graph traversals. + + + + + Sets the mark for the given edge pair to a boolean value. + + an edge of the pair to update + the mark value to set + + + + Marks the edges in a pair. + + an edge of the pair to mark + + + + Creates a new marked edge. + + the coordinate of the edge origin + + + + Marks this edge. + + + + + A Depth object records the topological depth of the sides + of an Edge for up to two Geometries. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Calls GetDepth and SetDepth. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A Depth object is null (has never been initialized) if all depths are null. + + true if depth is null (has never been initialized) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Normalize the depths for each point, if they are non-null. + A normalized depth + has depth values in the set { 0, 1 }. + Normalizing the depths + involves reducing the depths by the same amount so that at least + one of them is 0. If the remaining value is > 0, it is set to 1. + + + + + + + + + + + + + + + + Computes the factor for the change in depth when moving from one location to another. + E.g. if crossing from the to the + the depth decreases, so the factor is -1. + + The current location + The next location + Change of depth moving from to + + + + The depth of each side (position) of this edge. + The 0 element of the array is never used. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Set depth for a position + + The position to update + The depth at the provided position + + + + + + + + + Gets or sets a value indicating if both Visited + and Sym.Visited are true. + + Setting the property marks both DirectedEdges attached to a given Edge. + + This is used for edges corresponding to lines, which will only + appear oriented in a single direction in the result. + + + + + + + + + + + + + + + + + + + + + + + + + + Gets a value indicating if this edge is a line edge. + It is if + + at least one of the labels is a line label + any labels which are not line labels have all Location = Exterior. + + + true if edge is a line edge + + + + This is an interior Area edge if + its label is an Area label for both Geometries + and for each Geometry both sides are in the interior. + + true if this is an interior Area edge. + + + + Compute the label in the appropriate orientation for this DirEdge. + + + + + Set both edge depths. + One depth for a given side is provided. + The other is computed depending on the Location + transition and the depthDelta of the edge. + + The position to update + The depth at the provided position + + + + Set both edge depths. + One depth for a given side is provided. + The other is computed depending on the Location + transition and the depthDelta of the edge. + + The position to update + The depth at the provided position + + + + + + + + + + + + + + + + A DirectedEdgeStar is an ordered list of outgoing DirectedEdges around a node. + It supports labelling the edges as well as linking the edges to form both + MaximalEdgeRings and MinimalEdgeRings. + + + + + A list of all outgoing edges in the result, in CCW order. + + + + + Insert a directed edge in the list. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Compute the labelling for all dirEdges in this star, as well + as the overall labelling. + + + + + + For each dirEdge in the star, merge the label . + + + + + Update incomplete dirEdge labels from the labeling for the node. + + The label to apply + + + + + + + + + + Traverse the star of DirectedEdges, linking the included edges together. + To link two dirEdges, the next pointer for an incoming dirEdge + is set to the next outgoing edge. + DirEdges are only linked if: + they belong to an area (i.e. they have sides) + they are marked as being in the result + Edges are linked in CCW order (the order they are stored). + This means that rings have their face on the Right + (in other words, the topological location of the face is given by the RHS label of the DirectedEdge). + PRECONDITION: No pair of dirEdges are both marked as being in the result. + + + + + + + + + + + + + + + + Traverse the star of edges, maintaining the current location in the result + area at this node (if any). + If any L edges are found in the interior of the result, mark them as covered. + + + + + + + + + + + Compute the DirectedEdge depths for a subsequence of the edge array. + + The last depth assigned (from the R side of the last edge visited). + + + + + + + + + + + + + + + Updates an IM from the label for an edge. + Handles edges from both L and A geometries. + + An intersection matrix + A label + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The depthDelta is the change in depth as an edge is crossed from R to L. + + The change in depth as the edge is crossed from R to L. + + + + + + + + + + + + + + + + + + + + + + + + An Edge is collapsed if it is an Area edge and it consists of + two segments which are equal and opposite (eg a zero-width V). + + true if edge is consisting of two segments + which are equal and of oppose orientation (Zero-width V area edge) + + + + + + + + + + + + + + + + + + + + Adds EdgeIntersections for one or both + intersections found for a segment of an edge to the edge intersection list. + + A line intersector + A segment index + A geometry index + + + + Add an EdgeIntersection for intersection intIndex. + An intersection that falls exactly on a vertex of the edge is normalized + to use the higher of the two possible segmentIndexes. + + A line intersector + A segment index + A geometry index + The intersection index (0 or 1) + + + + Update the IM with the contribution for this component. + A component only contributes if it has a labelling for both parent geometries. + + + + + + Equals is defined to be: + e1 equals e2 + if + the coordinates of e1 are the same or the reverse of the coordinates in e2. + + + + + + + + + Equals is defined to be: + e1 equals e2 + if + the coordinates of e1 are the same or the reverse of the coordinates in e2. + + + + + + + + + + + + + + + + + + + + + + Check if coordinate sequences of the Edges are identical. + + The edge to test + + true if the coordinate sequences of the Edges are identical. + + + + > + + + + + + + + + + + + + + + + Models the end of an edge incident on a node. + + + + EdgeEnds have a direction determined by the direction of the ray from the initial + point to the next point. + + + EdgeEnds are IComparable under the ordering "a has a greater angle with the x-axis than b". + This ordering is used to sort EdgeEnds around a node. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Implements the total order relation: + a has a greater angle with the positive x-axis than b. + + Using the obvious algorithm of simply computing the angle is not robust, + since the angle calculation is obviously susceptible to round off. + + A robust algorithm is: + + first compare the quadrant. If the quadrants + are different, it it trivial to determine which vector is "greater". + if the vectors lie in the same quadrant, the computeOrientation function + can be used to decide the relative orientation of the vectors. + + + An EdgeEnd + The of compared to this . + + + + Subclasses should override this if they are using labels + + + + + + + + + + + + + + + A EdgeEndStar is an ordered list of EdgeEnds around a node. + They are maintained in CCW order (starting with the positive x-axis) around the node + for efficient lookup and topology building. + + + + + A map which maintains the edges in sorted order around the node. + + + + + A list of all outgoing edges in the result, in CCW order. + + + + + The location of the point for this star in Geometry i Areas. + + + + + Insert a EdgeEnd into this EdgeEndStar. + + An EdgeEnd + + + + Insert an EdgeEnd into the map, and clear the edgeList cache, + since the list of edges has now changed. + + An EdgeEnd + An EdgeEnd + + + + The coordinate for the node this star is based at. + + + + + + + + + + Iterator access to the ordered list of edges is optimized by + copying the map collection to a list. (This assumes that + once an iterator is requested, it is likely that insertion into + the map is complete). + + Access to ordered list of edges. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + > + + + + An EdgeIntersection represents a point on an + edge which intersects with another edge. + The intersection may either be a single point, or a line segment + (in which case this point is the start of the line segment) + The label attached to this intersection point applies to + the edge from this point forwards, until the next + intersection or the end of the edge. + The intersection point must be precise. + + + + + The point of intersection. + + + + + The index of the containing line segment in the parent edge. + + + + + The edge distance of this point along the containing line segment. + + + + + Creates an instance of this class + + The point of intersection + The index of the containing line segment in the parent edge + The edge distance or this point along the containing line segment + + + + + + + Comparison with segment and distance. + + The index of the containing line segment + The distance of this point along the containing line segment + + -1 this EdgeIntersection is located before the argument location, + 0 this EdgeIntersection is at the argument location, + 1 this EdgeIntersection is located after the argument location. + + + + + + + + + + + + + + + + + + + + + A list of edge intersections along an Edge. + + + + + + + + + + + + + + + + Adds an intersection into the list, if it isn't already there. + The input segmentIndex and dist are expected to be normalized. + + The point of intersection + The index of the containing line segment in the parent edge + The edge distance of this point along the containing line segment + The EdgeIntersection found or added. + + + + Returns an iterator of EdgeIntersections. + + + + + + + + + + + + Adds entries for the first and last points of the edge to the list. + + + + + Creates new edges for all the edges that the intersections in this + list split the parent edge into. + Adds the edges to the input list (this is so a single list + can be used to accumulate all split edges for a Geometry). + + + + + + Create a new "split edge" with the section of points between + (and including) the two intersections. + The label for the new edge is the same as the label for the parent edge. + + + + + + + + + + + + + A EdgeList is a list of Edges. It supports locating edges + that are point-wise equals to a target edge. + + + + + An index of the edges, for fast lookup. + + + + + Remove the selected Edge element from the list if present. + + Edge element to remove from list + + + + Insert an edge unless it is already in the list. + + An Edge + + + + + + + + + + + + + + + If there is an edge equal to e already in the list, return it. + Otherwise return null. + + An Edge + + The equal edge, if there is one already in the list, + null otherwise. + + + + + + + + + + + + + + + + + + + + + + + + + If the edge e is already in the list, return its index. + + An Edge + + The index, if e is already in the list, + -1 otherwise. + + + + + + + + + + + Validates that a collection of is correctly noded. + Throws an appropriate exception if an noding error is found. + + Uses to perform the validation. + + + + + + Checks whether the supplied s are correctly noded. + + an enumeration of Edges. + If the SegmentStrings are not correctly noded + + + + Creates a new validator for the given collection of s. + + + + + Checks whether the supplied edges are correctly noded. + + If the SegmentStrings are not correctly noded + + + + + + + + + The directed edge which starts the list of edges for this EdgeRing. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Compute a LinearRing from the point list previously collected. + Test if the ring is a hole (i.e. if it is CCW) and set the hole flag + accordingly. + + + + + + + + + + + + + + + + + + + Returns the list of DirectedEdges that make up this EdgeRing. + + A list of DirectedEdges + + + + Collect all the points from the DirectedEdges of this ring into a contiguous list. + + + + + + + + + + + + + + + + + + + + + + + + + + + Merge the RHS label from a DirectedEdge into the label for this EdgeRing. + The DirectedEdge label may be null. This is acceptable - it results + from a node which is NOT an intersection node between the Geometries + (e.g. the end node of a LinearRing). In this case the DirectedEdge label + does not contribute any information to the overall labelling, and is simply skipped. + + + + + + + + + + + + + + + This method will cause the ring to be computed. + It will also check any holes, if they have been assigned. + + The point to test + true if the ring contains point + + + + A GeometryGraph is a graph that models a given Geometry. + + + + + Determine boundary + + The boundary node rule to apply for determination of the boundary + The number of component boundaries that a point occurs in. + or + + + + The lineEdgeMap is a map of the linestring components of the + parentGeometry to the edges which are derived from them. + This is used to efficiently perform findEdge queries + + + + + If this flag is true, the Boundary Determination Rule will used when deciding + whether nodes are in the boundary or not + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gets the used with this geometry graph. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Add a Point to the graph. + + + + + + Adds a polygon ring to the graph. Empty rings are ignored. + The left and right topological location arguments assume that the ring is oriented CW. + If the ring is in the opposite orientation, + the left and right locations must be interchanged. + + + + + + + + + + + + + + + + + + + + Add an Edge computed externally. The label on the Edge is assumed + to be correct. + + An Edge + + + + Add a point computed externally. The point is assumed to be a + Point Geometry part, which has a location of INTERIOR. + + A Coordinate + + + + Compute self-nodes, taking advantage of the Geometry type to + minimize the number of intersection tests. (E.g. rings are + not tested for self-intersection, since they are assumed to be valid). + + The LineIntersector to use. + If false, intersection checks are optimized to not test rings for self-intersection. + The computed SegmentIntersector, containing information about the intersections found. + + + + Compute self-nodes, taking advantage of the Geometry type to + minimize the number of intersection tests. (E.g.rings are + not tested for self-intersection, since they are assumed to be valid). + + The LineIntersector to use + If false, intersection checks are optimized to not test rings for self-intersection + Short-circuit the intersection computation if a proper intersection is found + + + + + + + + + + + + + + + + + + + + + Adds candidate boundary points using the current . + This is used to add the boundary + points of dim-1 geometries (Curves/MultiCurves). + + + + + + + + + + + + + Add a node for a self-intersection. + If the node is a potential boundary node (e.g. came from an edge which + is a boundary) then insert it as a potential boundary node. + Otherwise, just add it as a regular node. + + + + + + + + Determines the of the given in this geometry. + + The point to test + + The location of the point in the geometry + + + + + A GraphComponent is the parent class for the objects' + that form a graph. Each GraphComponent can carry a + Label. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IsInResult indicates if this component has already been included in the result. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A coordinate in this component (or null, if there are none). + + + + + Compute the contribution to an IM for this component. + + An IntersectionMatrix + + + + An isolated component is one that does not intersect or touch any other + component. This is the case if the label has valid locations for + only a single Geometry. + + true if this component is isolated. + + + + Update the IM with the contribution for this component. + A component only contributes if it has a labelling for both parent geometries. + + An IntersectionMatrix + + + + An EdgeSetIntersector computes all the intersections between the + edges in the set. It adds the computed intersections to each edge + they are found on. It may be used in two scenarios: + determining the internal intersections between a single set of edges + determining the mutual intersections between two different sets of edges + It uses a SegmentIntersector to compute the intersections between + segments and to record statistics about what kinds of intersections were found. + + + + + Computes all self-intersections between edges in a set of edges, + allowing client to choose whether self-intersections are computed. + + A list of edges to test for intersections. + The SegmentIntersector to use + true if self-intersections are to be tested as well. + + + + Computes all mutual intersections between two sets of edges. + + A set of edges + A set of edges + The SegmentIntersector to use + + + + + + + + + + + + + + + + + + + + + + + MonotoneChains are a way of partitioning the segments of an edge to + allow for fast searching of intersections. + They have the following properties: + the segments within a monotone chain will never intersect each other, and + the envelope of any contiguous subset of the segments in a monotone chain + is simply the envelope of the endpoints of the subset. + Property 1 means that there is no need to test pairs of segments from within + the same monotone chain for intersection. + Property 2 allows + binary search to be used to find the intersection points of two monotone chains. + For many types of real-world data, these properties eliminate a large number of + segment comparisons, producing substantial speed gains. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tests whether the envelopes of two chain sections overlap (intersect). + + true if the section envelopes overlap + + + + MonotoneChains are a way of partitioning the segments of an edge to + allow for fast searching of intersections. + + Specifically, a sequence of contiguous line segments + is a monotone chain if all the vectors defined by the oriented segments + lies in the same quadrant. + + Monotone Chains have the following useful properties: + the segments within a monotone chain will never intersect each other, and + the envelope of any contiguous subset of the segments in a monotone chain + is simply the envelope of the endpoints of the subset. + Property 1 means that there is no need to test pairs of segments from within + the same monotone chain for intersection. + Property 2 allows + binary search to be used to find the intersection points of two monotone chains. + For many types of real-world data, these properties eliminate a large number of + segment comparisons, producing substantial speed gains. + + + Note that due to the efficient intersection test, there is no need to limit the size + of chains to obtain fast performance. + + + + + + + + + + + + + The index of the last point in the monotone chain. + + + + + + Computes the intersection of line segments, + and adds the intersection to the edges containing the segments. + + + + + + + + + + + + + Testing only. + + + + + + + + + + + + + + + + + + + + The proper intersection point, or null if none was found. + + + + + + + + + + A proper intersection is an intersection which is interior to at least two + line segments. Note that a proper intersection is not necessarily + in the interior of the entire Geometry, since another edge may have + an endpoint equal to the intersection, which according to SFS semantics + can result in the point being on the Boundary of the Geometry. + + Indicates a proper intersection with an interior to at least two line segments + + + + A proper interior intersection is a proper intersection which is not + contained in the set of boundary nodes set for this SegmentIntersector. + + Indicates a proper interior intersection + + + + A trivial intersection is an apparent self-intersection which in fact + is simply the point shared by adjacent line segments. + Note that closed edges require a special check for the point shared by the beginning + and end segments. + + An Edge + The segment index of + Another Edge + The segment index of + + + + This method is called by clients of the EdgeIntersector class to test for and add + intersections for two segments of the edges being intersected. + Note that clients (such as MonotoneChainEdges) may choose not to intersect + certain pairs of segments for efficiency reasons. + + + + + + + + + + + + + + + + + + + + + + + + + Finds all intersections in one or two sets of edges, + using the straightforward method of + comparing all segments. + This algorithm is too slow for production use, but is useful for testing purposes. + + + + + + + + + + + + + + + + + + + + + Performs a brute-force comparison of every segment in each Edge. + This has n^2 performance, and is about 100 times slower than using + monotone chains. + + + + + + + + Finds all intersections in one or two sets of edges, + using an x-axis sweepline algorithm in conjunction with Monotone Chains. + While still O(n^2) in the worst case, this algorithm + drastically improves the average-case time. + The use of MonotoneChains as the items in the index + seems to offer an improvement in performance over a sweep-line alone. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Because Delete Events have a link to their corresponding Insert event, + it is possible to compute exactly the range of events which must be + compared to a given Insert event object. + + + + + + + + + + + + + + + + + + + + Finds all intersections in one or two sets of edges, + using a simple x-axis sweepline algorithm. + While still O(n^2) in the worst case, this algorithm + drastically improves the average-case time. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Because DELETE events have a link to their corresponding INSERT event, + it is possible to compute exactly the range of events which must be + compared to a given INSERT event object. + + + + + + + + + + + + + + + + + + + + + + + + + Creates an INSERT event. + + The edge set label for this object. + The event location + the object being inserted + + + + Creates a DELETE event. + + The event location + The corresponding INSERT event + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Events are ordered first by their x-value, and then by their eventType. + Insert events are sorted before Delete events, so that + items whose Insert and Delete events occur at the same x-value will be + correctly handled. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A Label indicates the topological relationship of a component + of a topology graph to a given Geometry. + This class supports labels for relationships to two Geometrys, + which is sufficient for algorithms for binary operations. + Topology graphs support the concept of labeling nodes and edges in the graph. + The label of a node or edge specifies its topological relationship to one or + more geometries. (In fact, since NTS operations have only two arguments labels + are required for only two geometries). A label for a node or edge has one or + two elements, depending on whether the node or edge occurs in one or both of the + input Geometrys. Elements contain attributes which categorize the + topological location of the node or edge relative to the parent + Geometry; that is, whether the node or edge is in the interior, + boundary or exterior of the Geometry. Attributes have a value + from the set {Interior, Boundary, Exterior}. In a node each + element has a single attribute On. For an edge each element has a + triplet of attributes Left, On, Right. + It is up to the client code to associate the 0 and 1 TopologyLocations + with specific geometries. + + + + + Converts a Label to a Line label (that is, one with no side Location). + + Label to convert. + Label as Line label. + + + + Construct a Label with a single location for both Geometries. + Initialize the locations to Null. + + A location value + + + + Construct a Label with a single location for both Geometries. + Initialize the location for the Geometry index. + + A geometry index, 0, or 1. + A location value for On + + + + Construct a Label with On, Left and Right locations for both Geometries. + Initialize the locations for both Geometries to the given values. + + A location value for On + A location value for Left + A location value for Right + + + + Construct a Label with On, Left and Right locations for both Geometries. + Initialize the locations for the given Geometry index. + + A geometry index, 0, or 1. + A location value for On + A location value for Left + A location value for Right + + + + Construct a Label with the same values as the argument Label. + + A Label + + + + Performs on both + s of this Label + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Merge this label with another one. + Merging updates any null attributes of this label with the attributes from . + + The Label to merge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Converts one GeometryLocation to a Line location. + + The index of the TopologyLocation to convert (0 or 1) + + + + + + + + + + + + + + + Only non-null if this node is precise. + + + + + + + + + + + + Gets a value indicating the position of this + + The position of this Node + + + + Gets a value indicating the EdgeEndStar of this Node + + The EdgeEndStar of this Node + + + + Tests whether any incident edge is flagged as + being in the result. + This test can be used to determine if the node is in the result, + since if any incident edge is in the result, the node must be in the result as well. + + true if any incident edge in the in the result + + + + + + + + + Basic nodes do not compute IMs. + + + + + Add the edge to the list of edges at this node. + + An EdgeEnd + + + + Merges 's with this Node's Label. + + A Node + + + + To merge labels for two nodes, + the merged location for each LabelElement is computed. + The location for the corresponding node LabelElement is set to the result, + as long as the location is non-null. + + The Label to merge + + + + + + + + + + + Updates the label of a node to BOUNDARY, + obeying the mod-2 boundaryDetermination rule. + + An index for a (0 or 1) + + + + The location for a given eltIndex for a node will be one + of { Null, Interior, Boundary }. + A node may be on both the boundary and the interior of a point; + in this case, the rule is that the node is considered to be in the boundary. + The merged location is the maximum of the two input values. + + + + + + + + + + + + + + + + + + + A Factory to create s. + + + + + The basic node constructor does not allow for incident edges. + + A Coordinate + The created Node + + + + A map of nodes, indexed by the coordinate of the node. + + + + + Creates an instance of this class using the provided . + + A factory to create Nodes + + + + This method expects that a node has a coordinate value. + + A Coordinate + The Node for the provided Coordinate + + + + Adds a Node to this NodeMap. + If a Node with the same + is already present in this NodeMap, + their s are merged. + + The Node to add + Either or a Node with merged Labels + + + + Adds a node for the start point of this EdgeEnd + (if one does not already exist in this map). + Adds the EdgeEnd to the (possibly new) node. + + An EdgeEnd + + + + Searches for a Node at position. + + A Coordinate + + The node if found; null otherwise. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The computation of the IntersectionMatrix relies on the use of a structure + called a "topology graph". The topology graph contains nodes and edges + corresponding to the nodes and line segments of a Geometry. Each + node and edge in the graph is labeled with its topological location relative to + the source point. + Note that there is no requirement that points of self-intersection be a vertex. + Thus to obtain a correct topology graph, Geometrys must be + self-noded before constructing their graphs. + Two fundamental operations are supported by topology graphs: + Computing the intersections between all the edges and nodes of a single graph + Computing the intersections between the edges and nodes of two different graphs + + + + + For nodes in the Collection, link the DirectedEdges at the node that are in the result. + This allows clients to link only a subset of nodes in the graph, for + efficiency (because they know that only a subset is of interest). + + A collection of Nodes + + + + + + + + + + + + + + + + + + + Creates an instance of this class using the provided + + A factory to create Nodes + + + + Creates an instance of this class using the default . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Searches for a Node at Coordinate position + + A Coordinate position + + The node if found; null otherwise + + + + + Add a set of edges to the graph. For each edge two DirectedEdges + will be created. DirectedEdges are NOT linked by this method. + + A set of Edges to add. + + + + Link the DirectedEdges at the nodes of the graph. + This allows clients to link only a subset of nodes in the graph, for + efficiency (because they know that only a subset is of interest). + + + + + Link the DirectedEdges at the nodes of the graph. + This allows clients to link only a subset of nodes in the graph, for + efficiency (because they know that only a subset is of interest). + + + + + Returns the EdgeEnd which has edge e as its base edge + (MD 18 Feb 2002 - this should return a pair of edges). + + An Edge + The edge, if found null if the edge was not found. + + + + Returns the edge whose first two coordinates are p0 and p1. + + The 1st Coordinate + The 2nd Coordinate + The edge, if found null if the edge was not found. + + + + Returns the edge which starts at p0 and whose first segment is + parallel to p1. + + Starting Coordinate + Coordinate used to establish direction + The matching edge, if found null if the edge was not found. + + + + The coordinate pairs match if they define line segments lying in the same direction. + E.g. the segments are parallel and in the same quadrant + (as opposed to parallel and opposite!). + + + + + + + + + + + + + + + + + + + + An indicator that a Location is on a GraphComponent (0) + + + + + An indicator that a Location is to the left of a GraphComponent (1) + + + + + An indicator that a Location is to the right of a GraphComponent (2) + + + + + An indicator that a Location is is parallel to x-axis of a GraphComponent (-1) + /// + + + + A Position indicates the position of a Location relative to a graph component + (Node, Edge, or Area). + + + + + Returns Positions.Left if the position is Positions.Right, + Positions.Right if the position is Left, or the position + otherwise. + + + + + + Utility functions for working with quadrants, which are numbered as follows: + + 1 | 0 + --+-- + 2 | 3 + + + + + + North-East + + + + + North-West + + + + + South-West + + + + + South-East + + + + + Only static methods! + + + + + Returns the quadrant of a directed line segment (specified as x and y + displacements, which cannot both be 0). + + + + If the displacements are both 0 + + + + Returns the quadrant of a directed line segment from p0 to p1. + + + + if the points are equal + + + + Returns true if the quadrants are 1 and 3, or 2 and 4. + + + + + + + Returns the right-hand quadrant of the halfplane defined by the two quadrants, + or -1 if the quadrants are opposite, or the quadrant if they are identical. + + + + + + + Returns whether the given quadrant lies within the given halfplane (specified + by its right-hand quadrant). + + + + + + + Returns true if the given quadrant is 0 or 1. + + + + + + A TopologyLocation is the labelling of a + GraphComponent's topological relationship to a single Geometry. + + + If the parent component is an area edge, each side and the edge itself + have a topological location. These locations are named: + + Onon the edge + Leftleft-hand side of the edge + Rightright-hand side + + + If the parent component is a line edge or node, there is a single + topological relationship attribute, On. + + The possible values of a topological location are + { , , , } + + The labelling is stored in an array _location[j] where + where j has the values On, Left, Right. + + + + + + + + + + + + Constructs a TopologyLocation specifying how points on, to the left of, and to the + right of some GraphComponent relate to some Geometry. Possible values for the + parameters are Location.Null, Location.Exterior, Location.Boundary, + and Location.Interior. + + Location for On position + Location for Left position + Location for Right position + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Get calls Get(Positions posIndex), + Set calls SetLocation(Positions locIndex, Location locValue) + + + + + + + Get calls Get(Positions posIndex), + Set calls SetLocation(Positions locIndex, Location locValue) + + + + + + + true if all locations are Null. + + + + + true if any locations are Null. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Merge updates only the Null attributes of this object + with the attributes of another. + + + + + + + + + + + A lightweight class used to store coordinates on the 2-dimensional Cartesian plane. + + The base data object is suitable for use with coordinate sequences with + dimension = 2 and measures = 0. + + + + It is distinct from , which is a subclass of . + Unlike objects of type (which contain additional + information such as an envelope, a precision model, and spatial reference + system information), a Coordinate only contains ordinate values + and properties. + + Implementations may optionally support Z-ordinate and M-measure values + as appropriate for a . Use of + and setters or indexer are recommended. + + + + + The value used to indicate a null or missing ordinate value. + In particular, used for the value of ordinates for dimensions + greater than the defined dimension of a coordinate. + + + + + Gets or sets the X-ordinate value. + + + + + Gets or sets the Y-ordinate value. + + + + + Gets or sets the Z-ordinate value, if supported. + If no Z value is present, returns . + + + Thrown if an attempt is made to set the Z-ordinate value on an instance where + the Z-ordinate value is not supported. + + + + + Gets or sets the value of the measure, if supported. + If no measure value is present, returns . + + + Thrown if an attempt is made to set the measure value on an instance where + measures are not supported. + + + + + Constructs a Coordinate at (x,y). + + The X value + The Y value + + + + Constructs a Coordinate at (0,0). + + + + + Constructs a Coordinate having the same (x,y,z) values as + . + + Coordinate to copy. + + + + Gets or sets the value for the given ordinate. + + The ordinate. + The ordinate value + Thrown if is not one of , , , or . + + + + Gets or sets the ordinate value for the given index. + + + The base implementation supports 0 (X) and 1 (Y) as values for the index. + + The ordinate index + The ordinate value + Thrown if is not in the valid range. + + + + Gets/Sets Coordinates (x,y,z) values. + + + + Gets a value indicating if the Coordinate + has valid x- and y ordinate values + + An ordinate value is valid if it is finite. + + true if the coordinate is valid + + + + + + Predicate to check if a value is finite. + + It is finite if both and return false + + The value to test + value + + + + Returns whether the planar projections of the two Coordinates are equal. + + Coordinate with which to do the 2D comparison. + + true if the x- and y-coordinates are equal; + the Z coordinates do not have to be equal. + + + + + Tests if another Coordinate has the same values for the X and Y ordinates, + within a specified tolerance value. The Z ordinate is ignored. + + A . + The tolerance value to use. + true if the X and Y ordinates are within the given tolerance. + The Z ordinate is ignored. + + + + + + + + + + + Compares this object with the specified object for order. + Since Coordinates are 2.5D, this routine ignores the z value when making the comparison. + Returns + -1 : this.x < other.x || ((this.x == other.x) AND (this.y < other.y)) + 0 : this.x == other.x AND this.y = other.y + 1 : this.x > other.x || ((this.x == other.x) AND (this.y > other.y)) + + Coordinate with which this Coordinate is being compared. + + A negative integer, zero, or a positive integer as this Coordinate + is less than, equal to, or greater than the specified Coordinate. + + + + + Compares this object with the specified object for order. + Since Coordinates are 2.5D, this routine ignores the z value when making the comparison. + Returns + -1 : this.x < other.x || ((this.x == other.x) AND (this.y < other.y)) + 0 : this.x == other.x AND this.y = other.y + 1 : this.x > other.x || ((this.x == other.x) AND (this.y > other.y)) + + Coordinate with which this Coordinate is being compared. + + A negative integer, zero, or a positive integer as this Coordinate + is less than, equal to, or greater than the specified Coordinate. + + + + + Create a copy of this . + + A copy of this coordinate. + + + + Create a Coordinate of the same type as this Coordinate, using the provided values. + + Depending on the actual type the following limitations are in place: + + Coordinate (Sub-)ClassLimitation + Coordinate-parameter and -parameter are silently dropped. + CoordinateZ-parameter is silently dropped. + CoordinateM-parameter is silently dropped. + CoordinateZMNo parameter is dropped. + + + The x-ordinate value, if not provided, it is 0d. + The y-ordinate value, if not provided, it is 0d. + The z-ordinate value, if not provided, it is . + The m-ordinate value, if not provided, it is . + A new + + + + Computes the 2-dimensional Euclidean distance to another location. + + A with which to do the distance comparison. + the 2-dimensional Euclidean distance between the locations. + The Z-ordinate is ignored. + + + + Returns true if other has the same values for the x and y ordinates. + Since Coordinates are 2.5D, this routine ignores the z value when making the comparison. + + Coordinate with which to do the comparison. + true if other is a Coordinate with the same values for the x and y ordinates. + + + + Gets a hashcode for this coordinate. + + A hashcode for this coordinate. + + + + Returns a string of the form (x,y,z) . + + string of the form (x,y,z) + + + + Useful utility functions for handling Coordinate arrays. + + + + + Determine dimension based on subclass of . + + pts supplied coordinates + number of ordinates recorded + + + + Determine number of measures based on subclass of . + + supplied coordinates + number of measures recorded + + + + Utility method ensuring array contents are of consistent dimension and measures. + + Array is modified in place if required, coordinates are replaced in the array as required + to ensure all coordinates have the same dimension and measures. The final dimension and + measures used are the maximum found when checking the array. + + Modified in place to coordinates of consistent dimension and measures. + + + + Utility method ensuring array contents are of the specified dimension and measures. + + Array is returned unmodified if consistent, or a copy of the array is made with + each inconsistent coordinate duplicated into an instance of the correct dimension and measures. + + A coordinate array + + + Input array or copy created if required to enforce consistency. + + + + Tests whether an array of s forms a ring, by checking length and closure. + Self-intersection is not checked. + + An array of Coordinates + true if the coordinate form a ring. + + + + Finds a in a list of s + which is not contained in another list of s. + + The s to test. + An array of s to test the input points against. + + A from + which is not in , or null. + + + + + Compares two arrays + in the forward direction of their coordinates, + using lexicographic ordering. + + + + + + + + Determines which orientation of the array is (overall) increasing. + In other words, determines which end of the array is "smaller" + (using the standard ordering on ). + Returns an integer indicating the increasing direction. + If the sequence is a palindrome, it is defined to be + oriented in a positive direction. + + The array of Coordinates to test. + + 1 if the array is smaller at the start or is a palindrome, + -1 if smaller at the end. + + + + + Determines whether two arrays of equal length + are equal in opposite directions. + + + + + + + + Creates a deep copy of the argument Coordinate array. + + Array of Coordinates. + Deep copy of the input. + + + + Creates a deep copy of a given section of a source array into a destination Coordinate array. + The destination array must be an appropriate size to receive the copied coordinates. + + An array of Coordinates + The index to start copying from + The array to receive the deep-copied coordinates + The destination index to start copying to + The number of items to copy + + + + Converts the given of + s into a array. + + of coordinates. + + + + + Returns whether returns true + for any two consecutive coordinates in the given array. + + An array of Coordinates. + true if coord has repeated points; false otherwise. + + + + Returns either the given coordinate array if its length is greater than + the given amount, or an empty coordinate array. + + Length amount. + Array of Coordinates. + New Coordinate array. + + + + If the coordinate array argument has repeated points, + constructs a new array containing no repeated points. + Otherwise, returns the argument. + + An array of Coordinates + The array with repeated coordinates removed + + + + Tests whether an array has any repeated or invalid coordinates. + + An array of coordinates + true if the array contains repeated or invalid coordinates + + + + + If the coordinate array argument has repeated or invalid points, + constructs a new array containing no repeated points. + Otherwise, returns the argument. + + An array of coordinates + The array with repeated or invalid coordinates removed. + + + + + + Collapses a coordinate array to remove all null elements. + + The coordinate array to collapse + An Array containing only non-null elements + + + + Reverses the coordinates in an array in-place. + + Array of Coordinates. + + + + Returns true if the two arrays are identical, both null, or pointwise + equal (as compared using Coordinate.Equals). + + First array of Coordinates. + Second array of Coordinates. + true if two Coordinates array are equals; false otherwise + + + + Compares two arrays + in the forward direction of their coordinates, + using lexicographic ordering. + + + + + Compares the specified s arrays. + + An array of coordinates + An array of coordinates + + + + A comparator for arrays modulo their directionality. + E.g. if two coordinate arrays are identical but reversed + they will compare as equal under this ordering. + If the arrays are not equal, the ordering returned + is the ordering in the forward direction. + + + + + Compares the specified s arrays. + + An array of coordinates + An array of coordinates + + + + + + + Returns true if the two arrays are identical, both null, or pointwise + equal, using a user-defined + for s. + + An array of s. + Another array of s. + + A for s. + + + + + + Returns the minimum coordinate, using the usual lexicographic comparison. + + Array to search. + The minimum coordinate in the array, found using CompareTo. + + + + Shifts the positions of the coordinates until firstCoordinate is first. + + Array to rearrange. + Coordinate to make first. + + + + Shifts the positions of the coordinates until the coordinate + at indexOfFirstCoordinate is first. + + The array of coordinates to arrange + The index of the coordinate to make first + + + + Shifts the positions of the coordinates until the coordinate + at indexOfFirstCoordinate is first. + + + If is true, first and last + coordinate of the returned array are equal. + + The array of coordinates to arrange + The index of the coordinate to make first + A flag indicating if returned array should form a ring. + + + + Returns the index of in . + The first position is 0; the second is 1; etc. + + A to search for. + A array to search. + The position of coordinate, or -1 if it is not found. + + + + Extracts a subsequence of the input array + from indices to (inclusive). + The input indices are clamped to the array size; + If the end index is less than the start index, + the extracted array will be empty. + + The input array. + The index of the start of the subsequence to extract. + The index of the end of the subsequence to extract. + A subsequence of the input array. + + + + Computes the of the coordinates. + + the array to scan. + the of the . + + + + Extracts the coordinates which intersect an . + + The coordinates to scan + The envelope to intersect with + An array of coordinates which intersect with the envelope + + + + A class that can be used to test coordinates for equality. + + It uses the algorithm that was default for NTS prior to v2.2, + i.e. checks if the 2d distance between coordinates x + and y is less than or equal to a tolerance value. + + + + + + + + Compares s and for equality allowing for a . + + A Coordinate + A Coordinate + A tolerance value. + true if and can be considered equal; otherwise false. + + + + + + + Method to test 2 s for equality, allowing a tolerance. + + The 1st Coordinate + The 2nd Coordinate + A tolerance value + true if and can be considered equal. + + + + A class that can be used to test coordinates for equality. + + This class test for each ordinate if the distance is less + than a tolerance value. + + + + + Method to test 2 s for equality, allowing a tolerance. + + The 1st Coordinate + The 2nd Coordinate + A tolerance value + true if and can be considered equal. + + + + Computes the distance between two values + + 1st double + 2nd double + The distance between and + + + + A list of Coordinates, which may + be set to prevent repeated coordinates from occurring in the list. + + + + + Constructs a new list without any coordinates + + + + + Constructs a new list without any coordinates but an initial capacity + + The initial capacity of the list. + + + + Constructs a new list from an array of Coordinates, allowing repeated points. + (I.e. this constructor produces a with exactly the same set of points + as the input array.) + + Initial coordinates + + + + Constructs a new list from a collection of Coordinates, + allows repeated points. + + Collection of coordinates to load into the list. + + + + Constructs a new list from a collection of Coordinates, + allowing caller to specify if repeated points are to be removed. + + Collection of coordinates to load into the list. + If false, repeated points are removed. + + + + Constructs a new list from an array of Coordinates, + allowing caller to specify if repeated points are to be removed. + + Array of coordinates to load into the list. + If false, repeated points are removed. + + + + Returns the coordinate at specified index. + + Coordinate index. + Coordinate specified. + + + + Adds a section of an array of coordinates to the list. + + The coordinates + If set to false, repeated coordinates are collapsed + The index to start from + The index to add up to but not including + true (as by general collection contract) + + + + Adds an array of coordinates to the list. + + Coordinates to be inserted. + If set to false, repeated coordinates are collapsed. + If false, the array is added in reverse order. + Return true. + + + + Adds an array of coordinates to the list. + + Coordinates to be inserted. + If set to false, repeated coordinates are collapsed. + Return true. + + + + Adds a coordinate to the list. + + Coordinate to be inserted, as object. + If set to false, repeated coordinates are collapsed. + Return true. + + + + Adds a coordinate to the end of this list. + + Coordinate to be inserted. + If set to false, repeated coordinates are collapsed. + Return true if all ok. + + + + Inserts the specified coordinate at the specified position in this list. + + The position at which to insert + the coordinate to insert + if set to false, repeated coordinates are collapsed + + + + Add an array of coordinates. + + Coordinates collection to be inserted. + If set to false, repeated coordinates are collapsed. + Return true if at least one element has added (IList not empty). + + + + Ensure this coordList is a ring, by adding the start point if necessary. + + + + + Returns the Coordinates in this collection. + + Coordinates as Coordinate[] array. + + + + Creates an array containing the coordinates in this list, + oriented in the given direction (forward or reverse). + + The direction value: true for forward, false for reverse + An oriented array of coordinates + + + + Returns a deep copy of this collection. + + The copied object. + + + + A lightweight class used to store coordinates on the 2-dimensional Cartesian plane + and an additional measure () value. + + This data object is suitable for use with coordinate sequences with + dimension = 3 and measures = 1. + + + + It is distinct from , which is a subclass of . + Unlike objects of type (which contain additional + information such as an envelope, a precision model, and spatial reference + system information), a CoordinateM only contains ordinate values + and properties. + + CoordinateMs are two-dimensional points, with an additional M-ordinate. + If an M-ordinate value is not specified or not defined, + constructed coordinates have a M-ordinate of NaN + (which is also the value of ). + Apart from the basic accessor functions, NTS supports + only specific operations involving the M-ordinate. + + Implementations may optionally support Z-ordinate and M-measure values + as appropriate for a . Use of + and setters or indexer are recommended. + + + + + Gets or sets the M-ordinate value. + + + + + Constructs a CoordinateM at (x,y,z). + + The X value + The Y value + The measure value + + + + Constructs a CoordinateM at (0,0,NaN). + + + + + Constructs a CoordinateM having the same (x,y) values as + . + + Coordinate to copy. + + + + Constructs a CoordinateM at (x,y,NaN). + + X value. + Y value. + + + + Gets or sets the ordinate value for the given index. + + + The base implementation supports 0 (X), 1 (Y) and 2 (M) as values for the index. + + The ordinate index + The ordinate value + Thrown if is not in the valid range. + + + + Gets/Sets CoordinateMs (x,y,z) values. + + + + + Create a Coordinate of the same type as this Coordinate, + using the provided values for , and . + + A provided value for will be silently dropped. + The x-ordinate value, if not provided, it is 0d. + The y-ordinate value, if not provided, it is 0d. + The z-ordinate value, if not provided, it is . + The m-ordinate value, if not provided, it is . + A new + + + + Returns a string of the form (x, y, m=m). + + string of the form (x, y, m=m) + + + + Useful utility functions for handling Coordinate objects. + + + + + Factory method providing access to common Coordinate implementations. + + + created coordinate + + + + Factory method providing access to common Coordinate implementations. + + + + created coordinate + + + + Determine dimension based on subclass of . + + supplied coordinate + number of ordinates recorded + + + + Determine number of measures based on subclass of . + + supplied coordinate + number of measures recorded + + + + + + + Initializes a new instance of the class. + + The value for . + The value for . + The value for . + + Thrown when any argument is negative. + + + Thrown when and specify fewer + than two (2) spatial dimensions. + + + + + Returns the dimension (number of ordinates in each coordinate) for this sequence. + + This total includes any measures, indicated by non-zero . + + + + + + Gets the number of measures included in for each coordinate for this + sequence. + + + For a measured coordinate sequence a non-zero value is returned. + + For sequence measures is zero + For sequence measure is one + For sequence measure is zero + For sequence measure is one + Values greater than one are supported + + + + + + Gets the number of non-measure dimensions included in for each + coordinate for this sequence. + + Equivalent to Dimension - Measures. + + + + + + Gets the kind of ordinates this sequence supplies. + + + + + Gets a value indicating if is supported. + + + + + Gets a value indicating if is supported. + + + + + Gets the index of the Z ordinate (for use with or + ), or -1 if is + . + + + It's just a cache for with . + + + + + Gets the index of the M ordinate (for use with or + ), or -1 if is + . + + + It's just a cache for with . + + + + + Creates a coordinate for use in this sequence. + + + The coordinate is created supporting the same number of and + as this sequence and is suitable for use with . + + A coordinate for use with this sequence + + + + Returns (possibly a copy of) the ith Coordinate in this collection. + Whether or not the Coordinate returned is the actual underlying + Coordinate or merely a copy depends on the implementation. + Note that in the future the semantics of this method may change + to guarantee that the Coordinate returned is always a copy. Callers are + advised not to assume that they can modify a CoordinateSequence by + modifying the Coordinate returned by this method. + + + + + + + Returns a copy of the i'th coordinate in this sequence. + This method optimizes the situation where the caller is + going to make a copy anyway - if the implementation + has already created a new Coordinate object, no further copy is needed. + + The index of the coordinate to retrieve. + A copy of the i'th coordinate in the sequence + + + + Copies the i'th coordinate in the sequence to the supplied Coordinate. + At least the first two dimensions must be copied. + + The index of the coordinate to copy. + A Coordinate to receive the value. + + + + Returns ordinate X (0) of the specified coordinate. + + + The value of the X ordinate in the index'th coordinate. + + + + Returns ordinate Y (1) of the specified coordinate. + + + The value of the Y ordinate in the index'th coordinate. + + + + Returns ordinate Z of the specified coordinate if available. + + + + The value of the Z ordinate in the index'th coordinate, or + if not defined. + + + + + Returns ordinate M of the specified coordinate if available. + + + + The value of the M ordinate in the index'th coordinate, or + if not defined. + + + + + Sets ordinate X (0) of the specified coordinate to the specified value. + + + The index of the coordinate whose X value to set. + + + The value to set the coordinate's X value to. + + + + + Sets ordinate Y (1) of the specified coordinate to the specified value. + + + The index of the coordinate whose Y value to set. + + + The value to set the coordinate's Y value to. + + + + + Sets ordinate Z of the specified coordinate to the specified value if present. + + + The index of the coordinate whose Z value to set if present. + + + The value to set the coordinate's Z value to if present. + + + + + Sets ordinate M of the specified coordinate to the specified value if present. + + + The index of the coordinate whose M value to set if present. + + + The value to set the coordinate's M value to if present. + + + + + Returns the ordinate of a coordinate in this sequence. + Ordinate indices 0 and 1 are assumed to be X and Y. + + Ordinate indices greater than 1 have user-defined semantics + (for instance, they may contain other dimensions or measure + values as described by and . + + + If the sequence does not provide value for the required ordinate, the implementation must not throw an exception, it should return . + + The coordinate index in the sequence. + The ordinate index in the coordinate (in range [0, dimension-1]). + The ordinate value, or if the sequence does not provide values for "/> + + + + Returns the ordinate of a coordinate in this sequence. + + The coordinate index in the sequence. + The ordinate value to get. + The ordinate value, or if the sequence does not provide values for "/> + + + + Gets a value indicating the first Coordinate in this sequence.
+ For LineStrings e.g. this is the starting point. +
+ First Coordinate in sequence or null if empty. +
+ + + Gets a value indicating the last Coordinate in this sequence.
+ For LineStrings e.g. this is the ending point. +
+ Last Coordinate in sequence or null if empty. +
+ + + Gets a value indicating the number of coordinates in this sequence. + + + + + Sets the value for a given ordinate of a coordinate in this sequence. + + + If the sequence can't store the ordinate value, the implementation must not throw an exception, it should simply ignore the call. + + The coordinate index in the sequence. + The ordinate index in the coordinate (in range [0, dimension-1]). + The new ordinate value. + + + + Sets the value for a given ordinate of a coordinate in this sequence. + + The coordinate index in the sequence. + The ordinate value to set. + The new ordinate value. + + + + Returns (possibly copies of) the Coordinates in this collection. + Whether or not the Coordinates returned are the actual underlying + Coordinates or merely copies depends on the implementation. Note that + if this implementation does not store its data as an array of Coordinates, + this method will incur a performance penalty because the array needs to + be built from scratch. + + + + + + Expands the given Envelope to include the coordinates in the sequence. + Allows implementing classes to optimize access to coordinate values. + + The envelope to expand. + A reference to the expanded envelope. + + + + Returns a deep copy of this collection. + + A copy of the coordinate sequence containing copies of all points + + + + Returns a reversed copy of this . + + + A reversed copy of this . + + + Thrown when returned . + + + + + Retrieves the index at which this sequence stores a particular 's + values, if that ordinate is present in . + + + The value whose index to retrieve. + + + When this method returns, contains the index of the requested ordinate, if the ordinate + is present in this sequence; otherwise, -1. This parameter is passed uninitialized. + + + if this sequence contains ; otherwise, + . + + + + + Compares two s. + + + For sequences of the same dimension, the ordering is lexicographic. + Otherwise, lower dimensions are sorted before higher. + The dimensions compared can be limited; if this is done + ordinate dimensions above the limit will not be compared. + + + If different behaviour is required for comparing size, dimension, + or coordinate values, any or all methods can be overridden. + + + + + Compare two doubles, allowing for NaN values. + NaN is treated as being less than any valid number. + + A double + A double + -1, 0, or 1 depending on whether a is less than, equal to or greater than b + + + + The number of dimensions to test + + + + + Creates a comparator which will test all dimensions. + + + + + Creates a comparator which will test only the specified number of dimensions. + + The number of dimensions to test + + + + Compares two s for relative order. + + A coordinate sequence + A coordinate sequence + -1, 0, or 1 depending on whether o1 is less than, equal to, or greater than o2 + + + + Compares the same coordinate of two s + + A coordinate sequence + A coordinate sequence + The index of the coordinate to test + the number of dimensions to test + + + + Compares two s for relative order. + + A coordinate sequence + A coordinate sequence + -1, 0, or 1 depending on whether s1 is less than, equal to, or greater than s2 + + + + An object that knows how to build a particular implementation of + CoordinateSequence from an array of Coordinates. + + + + + + Initializes a new instance of the class.` + + + + + Initializes a new instance of the class. + + + The maximum set of flags that this instance will be + able to create sequences for. + + + + + Gets the Ordinate flags that sequences created by this factory can maximal cope with. + + + + + Returns a based on the given array; + whether or not the array is copied is implementation-dependent. + + A coordinates array, which may not be null nor contain null elements + A coordinate sequence. + + + + Creates a which is a copy + of the given . + This method must handle null arguments by creating an empty sequence. + + + A coordinate sequence + + + + Creates a of the specified size and dimension. + For this to be useful, the implementation must be mutable. + + + If the requested dimension is larger than the CoordinateSequence implementation + can provide, then a sequence of maximum possible dimension should be created. + An error should not be thrown. + + + the dimension of the coordinates in the sequence + (if user-specifiable, otherwise ignored) + A coordinate sequence + + + + Creates a of the specified size and dimension + with measure support. For this to be useful, the + implementation must be mutable. + + + If the requested dimension or measures are larger than the CoordinateSequence implementation + can provide, then a sequence of maximum possible dimension should be created. + An error should not be thrown. + + The number of coordinates in the sequence + The dimension of the coordinates in the sequence (if user-specifiable, + otherwise ignored) + The number of measures of the coordinates in the sequence (if user-specifiable, + otherwise ignored) + + + + Creates a of the specified size and ordinates. + For this to be useful, the implementation must be mutable. + + The number of coordinates. + + The ordinates each coordinate has. is fix, and can be set. + + A coordinate sequence. + + + + Gets the three parameters needed to create any instance + (, , and + ) such that the sequence can store all the data + from a given array of instances. + + + The array of instances that the sequence will be created from. + + + The values of the three parameters to use for creating the sequence. + + + + + Utility functions for manipulating s. + + + + + Reverses the coordinates in a sequence in-place. + + The coordinate sequence to reverse. + + + + Swaps two coordinates in a sequence. + + seq the sequence to modify + the index of a coordinate to swap + the index of a coordinate to swap + + + + Copies a section of a to another . + The sequences may have different dimensions; + in this case only the common dimensions are copied. + + The sequence to copy coordinates from + The starting index of the coordinates to copy + The sequence to which the coordinates should be copied to + The starting index of the coordinates in + The number of coordinates to copy + + + + Copies a section of a to another . + The sequences must have same dimensions. + + The sequence to copy coordinates from + The starting index of the coordinates to copy + The sequence to which the coordinates should be copied to + The starting index of the coordinates in + The number of coordinates to copy + + + + Copies a section of a to another . + The sequences must have same dimensions. + + The sequence to copy coordinates from + The starting index of the coordinates to copy + The sequence to which the coordinates should be copied to + The starting index of the coordinates in + The number of coordinates to copy + + + + Copies a section of a to another . + The sequences must have same dimensions. + + The sequence to copy coordinates from + The starting index of the coordinates to copy + The sequence to which the coordinates should be copied to + The starting index of the coordinates in + The number of coordinates to copy + + + + Copies a coordinate of a to another . + The sequences may have different dimensions; + in this case only the common dimensions are copied. + + The sequence to copy coordinate from + The index of the coordinate to copy + The sequence to which the coordinate should be copied to + The index of the coordinate in + + + + Copies a coordinate of a to another . + The sequences may have different dimensions; + in this case only the common dimensions are copied. + + The sequence to copy coordinate from + The index of the coordinate to copy + The sequence to which the coordinate should be copied to + The index of the coordinate in + The number of spatial ordinates to copy + The number of measure ordinates to copy + + + + Tests whether a forms a valid , + by checking the sequence length and closure + (whether the first and last points are identical in 2D). + Self-intersection is not checked. + + The sequence to test + True if the sequence is a ring + + + + + Ensures that a CoordinateSequence forms a valid ring, + returning a new closed sequence of the correct length if required. + If the input sequence is already a valid ring, it is returned + without modification. + If the input sequence is too short or is not closed, + it is extended with one or more copies of the start point. + + The CoordinateSequenceFactory to use to create the new sequence + The sequence to test + The original sequence, if it was a valid ring, or a new sequence which is valid. + + + + Extends a given . + + Because coordinate sequences are fix in size, extending is done by + creating a new coordinate sequence of the requested size. + + The new, trailing coordinate entries (if any) are filled with the last + coordinate of the input sequence + + The factory to use when creating the new sequence. + The sequence to extend. + The required size of the extended sequence + The extended sequence + + + + Tests whether two s are equal. + To be equal, the sequences must be the same length. + They do not need to be of the same dimension, + but the ordinate values for the smallest dimension of the two + must be equal. + Two NaN ordinates values are considered to be equal. + + a CoordinateSequence + a CoordinateSequence + true if the sequences are equal in the common dimensions + + + + Tests whether two Coordinates s are equal. + They do not need to be of the same dimension, + but the ordinate values for the common ordinates of the two + must be equal. + Two NaN ordinates values are considered to be equal. + + A CoordinateSequence + The index of the Coordinate in . + a CoordinateSequence + The index of the Coordinate in . + true if the sequences are equal in the common dimensions + + + + Tests whether two Coordinates s are equal. + They do not need to be of the same dimension, + but the ordinate values for the common ordinates of the two + must be equal. + Two NaN ordinates values are considered to be equal. + + A CoordinateSequence + The index of the Coordinate in . + a CoordinateSequence + The index of the Coordinate in . + The number of spatial ordinates to compare + The number of measure ordinates to compare + true if the sequences are equal in the common dimensions + + + + Creates a string representation of a . + The format is: + + ( ord0,ord1.. ord0,ord1,... ... ) + + + the sequence to output + the string representation of the sequence + + + + Returns the minimum coordinate, using the usual lexicographic comparison. + + The coordinate sequence to search + The minimum coordinate in the sequence, found using + + + + Returns the index of the minimum coordinate of the whole + coordinate sequence, using the usual lexicographic comparison. + + The coordinate sequence to search + The index of the minimum coordinate in the sequence, found using + + + + Returns the index of the minimum coordinate of a part of + the coordinate sequence (defined by + and ), using the usual lexicographic + comparison. + + The coordinate sequence to search + The lower search index + The upper search index + The index of the minimum coordinate in the sequence, found using + + + + Shifts the positions of the coordinates until firstCoordinate is first. + + The coordinate sequence to rearrange + The coordinate to make first"> + + + + Shifts the positions of the coordinates until the coordinate at firstCoordinateIndex + is first. + + The coordinate sequence to rearrange + The index of the coordinate to make first + + + + Shifts the positions of the coordinates until the coordinate at firstCoordinateIndex + is first. + + The coordinate sequence to rearrange + The index of the coordinate to make first + Makes sure that will be a closed ring upon exit + + + + Returns the index of coordinate in a + The first position is 0; the second, 1; etc. + + The Coordinate to search for + The coordinate sequence to search + + The position of coordinate, or -1 if it is not found + + + + + A lightweight class used to store coordinates on the 2-dimensional Cartesian plane + and an additional z-ordinate () value. + + This base data object is suitable for use with coordinate sequences with + dimension = 3 and measures = 0. + + + It is distinct from , which is a subclass of . + Unlike objects of type (which contain additional + information such as an envelope, a precision model, and spatial reference + system information), a CoordinateZ only contains ordinate values + and properties. + + CoordinateZs are two-dimensional points, with an additional Z-ordinate. + If an Z-ordinate value is not specified or not defined, + constructed coordinates have a Z-ordinate of NaN + (which is also the value of ). + + Apart from the basic accessor functions, NTS supports + only specific operations involving the Z-ordinate. + + Implementations may optionally support Z-ordinate and M-measure values + as appropriate for a . Use of + and setters or indexer are recommended. + + + + + Gets or sets the Z-ordinate value. + + + + + Constructs a CoordinateZ at (x,y,z). + + The X value + The Y value + The Z value + + + + Constructs a CoordinateZ at (0,0,NaN). + + + + + Constructs a CoordinateZ having the same (x,y) values as + . + + Coordinate to copy. + + + + Constructs a CoordinateZ at (x,y,NaN). + + X value. + Y value. + + + + Gets or sets the ordinate value for the given index. + + + The base implementation supports 0 (X), 1 (Y) and 2 (Z) as values for the index. + + The ordinate index + The ordinate value + Thrown if is not in the valid range. + + + + Gets/Sets CoordinateZs (x,y,z) values. + + + + + Create a Coordinate of the same type as this Coordinate, + using the provided values for , and . + + A provided value for will be silently dropped. + The x-ordinate value, if not provided, it is 0d. + The y-ordinate value, if not provided, it is 0d. + The z-ordinate value, if not provided, it is . + The m-ordinate value, if not provided, it is . + A new + + + + Returns true if + has the same values for X, Y and Z. + + A with which to do the 3D comparison. + + true if is a + with the same values for X, Y and Z. + + + + + Tests if another CoordinateZ has the same value for Z, within a tolerance. + + A . + The tolerance value. + true if the Z ordinates are within the given tolerance. + + + + Returns a string of the form (x, y, z) . + + string of the form (x, y, z) + + + + Computes the 3-dimensional Euclidean distance to another location. + + A with which to do the distance comparison. + the 3-dimensional Euclidean distance between the locations. + + + + A lightweight class used to store coordinates on the 2-dimensional Cartesian plane + and additional z- and m-ordinate values (, ). + + This data object is suitable for use with coordinate sequences with + dimension = 4 and measures = 1. + + + + It is distinct from , which is a subclass of . + Unlike objects of type (which contain additional + information such as an envelope, a precision model, and spatial reference + system information), a CoordinateZM only contains ordinate values + and properties. + + CoordinateZMs are two-dimensional points, with an additional Z-ordinate. + If an Z-ordinate value is not specified or not defined, + constructed coordinates have a Z-ordinate of NaN + (which is also the value of ). + + Apart from the basic accessor functions, NTS supports + only specific operations involving the Z- and/or M-ordinate. + + Implementations may optionally support Z-ordinate and M-measure values + as appropriate for a . Use of + and setters or indexer are recommended. + + + + + Gets or sets the measure-ordinate value. + + + + + Constructs a CoordinateZM at (x,y,z). + + The X value + The Y value + The Z value + The Measure value + + + + Constructs a CoordinateZM at (0,0,NaN,NaN). + + + + + Constructs a CoordinateZM having the same (x,y) values as + . + + Coordinate to copy. + + + + Constructs a CoordinateZM at (x,y,NaN). + + X value. + Y value. + + + + Gets or sets the ordinate value for the given index. + + + The base implementation supports 0 (X), 1 (Y) and 2 (Z) as values for the index. + + The ordinate index + The ordinate value + Thrown if is not in the valid range. + + + + Gets/Sets CoordinateZMs (x,y,z) values. + + + + + Create a Coordinate of the same type as this Coordinate, + using the provided values for , , and . + + The x-ordinate value, if not provided, it is 0d. + The y-ordinate value, if not provided, it is 0d. + The z-ordinate value, if not provided, it is . + The m-ordinate value, if not provided, it is . + A new + + + + Returns a string of the form (x, y, z, m=m) . + + string of the form (x, y, z, m=m) + + + + Provides constants representing the dimensions of a point, a curve and a surface. + + + Also provides constants representing the dimensions of the empty geometry and + non-empty geometries, and the wildcard constant meaning "any dimension". + These constants are used as the entries in s. + + + + + Dimension value of a point (0). + + + + + Dimension value of a point (0). + + + + + Dimension value of a curve (1). + + + + + Dimension value of a curve (1). + + + + + Dimension value of a surface (2). + + + + + Dimension value of a surface (2). + + + + + Dimension value of a empty point (-1). + + + + + Dimension value of non-empty geometries (= {Point,Curve,Surface}). + + + + + Dimension value for any dimension (= {False, True}). + + + + + Dimension value for a unknown spatial object + + + + + Dimension value for a collapsed surface or curve + + + + + Class containing static methods for conversions + between dimension values and characters. + + + + + Symbol for the FALSE pattern matrix entry + + + + + Symbol for the TRUE pattern matrix entry + + + + + Symbol for the DONTCARE pattern matrix entry + + + + + Symbol for the P (dimension 0) pattern matrix entry + + + + + Symbol for the L (dimension 1) pattern matrix entry + + + + + Symbol for the A (dimension 2) pattern matrix entry + + + + + Converts the dimension value to a dimension symbol, + for example, True => 'T' + + Number that can be stored in the IntersectionMatrix. + Possible values are True, False, Dontcare, 0, 1, 2. + Character for use in the string representation of an IntersectionMatrix. + Possible values are T, F, * , 0, 1, 2. + + + + Converts the dimension symbol to a dimension value, + for example, '*' => Dontcare + + Character for use in the string representation of an IntersectionMatrix. + Possible values are T, F, * , 0, 1, 2. + Number that can be stored in the IntersectionMatrix. + Possible values are True, False, Dontcare, 0, 1, 2. + + + + Defines a rectangular region of the 2D coordinate plane. + + + It is often used to represent the bounding box of a Geometry, + e.g. the minimum and maximum x and y values of the Coordinates. + Note that Envelopes support infinite or half-infinite regions, by using the values of + Double.PositiveInfinity and Double.NegativeInfinity. + When Envelope objects are created or initialized, + the supplied extent values are automatically sorted into the correct order. + + + + + Test the point q to see whether it intersects the Envelope + defined by p1-p2. + + One extremal point of the envelope. + Another extremal point of the envelope. + Point to test for intersection. + true if q intersects the envelope p1-p2. + + + + Tests whether the envelope defined by p1-p2 + and the envelope defined by q1-q2 + intersect. + + One extremal point of the envelope Point. + Another extremal point of the envelope Point. + One extremal point of the envelope Q. + Another extremal point of the envelope Q. + true if Q intersects Point + + + + The minimum x-coordinate + + + + + The maximum x-coordinate + + + + + The minimum y-coordinate + + + + + The maximum y-coordinate + + + + + Creates a null Envelope. + + + + + Creates an Envelope for a region defined by maximum and minimum values. + + The first x-value. + The second x-value. + The first y-value. + The second y-value. + + + + Creates an Envelope for a region defined by two Coordinates. + + The first Coordinate. + The second Coordinate. + + + + Creates an Envelope for a region defined by a single Coordinate. + + The Coordinate. + + + + Creates an Envelope for a region defined by an enumeration of Coordinates. + + The Coordinates. + + + + Creates an Envelope for a region defined by a CoordinateSequences. + + The CoordinateSequence. + + + + Create an Envelope from an existing Envelope. + + The Envelope to initialize from. + + + + Initialize to a null Envelope. + + + + + Initialize an Envelope for a region defined by maximum and minimum values. + + The first x-value. + The second x-value. + The first y-value. + The second y-value. + + + + Initialize an Envelope for a region defined by two Coordinates. + + The first Coordinate. + The second Coordinate. + + + + Initialize an Envelope for a region defined by a single Coordinate. + + The Coordinate. + + + + Initialize an Envelope from an existing Envelope. + + The Envelope to initialize from. + + + + Makes this Envelope a "null" envelope.. + + + + + Returns true if this Envelope is a "null" envelope. + + + true if this Envelope is uninitialized + or is the envelope of the empty point. + + + + + Returns the difference between the maximum and minimum x values. + + max x - min x, or 0 if this is a null Envelope. + + + + Returns the difference between the maximum and minimum y values. + + max y - min y, or 0 if this is a null Envelope. + + + + Gets the length of the diameter (diagonal) of the envelope. + + The diameter length + + + + Returns the Envelopes minimum x-value. min x > max x + indicates that this is a null Envelope. + + The minimum x-coordinate. + + + + Returns the Envelopes maximum x-value. min x > max x + indicates that this is a null Envelope. + + The maximum x-coordinate. + + + + Returns the Envelopes minimum y-value. min y > max y + indicates that this is a null Envelope. + + The minimum y-coordinate. + + + + Returns the Envelopes maximum y-value. min y > max y + indicates that this is a null Envelope. + + The maximum y-coordinate. + + + + Gets the area of this envelope. + + The area of the envelope, or 0.0 if envelope is null + + + + Expands this envelope by a given distance in all directions. + Both positive and negative distances are supported. + + The distance to expand the envelope. + + + + Expands this envelope by a given distance in all directions. + Both positive and negative distances are supported. + + The distance to expand the envelope along the the X axis. + The distance to expand the envelope along the the Y axis. + + + + Gets the minimum extent of this envelope across both dimensions. + + + + + + Gets the maximum extent of this envelope across both dimensions. + + + + + + Enlarges this Envelope so that it contains + the given . + Has no effect if the point is already on or within the envelope. + + The Coordinate. + + + + Enlarges this Envelope so that it contains + the given . + + Has no effect if the point is already on or within the envelope. + The value to lower the minimum x to or to raise the maximum x to. + The value to lower the minimum y to or to raise the maximum y to. + + + + Enlarges this Envelope so that it contains + the other Envelope. + Has no effect if other is wholly on or + within the envelope. + + the Envelope to expand to include. + + + + Enlarges this Envelope so that it contains + the other Envelope. + Has no effect if other is wholly on or + within the envelope. + + the Envelope to expand to include. + + + + Translates this envelope by given amounts in the X and Y direction. + + The amount to translate along the X axis. + The amount to translate along the Y axis. + + + + Computes the coordinate of the centre of this envelope (as long as it is non-null). + + + The centre coordinate of this envelope, + or null if the envelope is null. + . + + + + Computes the intersection of two s. + + The envelope to intersect with + + A new Envelope representing the intersection of the envelopes (this will be + the null envelope if either argument is null, or they do not intersect + + + + + Check if the region defined by other + intersects the region of this Envelope. + + The Envelope which this Envelope is + being checked for intersecting. + + + true if the Envelopes intersect. + + + + + Check if the point p overlaps (lies inside) the region of this Envelope. + + the Coordinate to be tested. + true if the point overlaps this Envelope. + + + + Check if the point (x, y) overlaps (lies inside) the region of this Envelope. + + the x-ordinate of the point. + the y-ordinate of the point. + true if the point overlaps this Envelope. + + + + Tests if the extent defined by two extremal points + intersects the extent of this Envelope. + + A point + Another point + true if the extents intersect + + + + Tests if the region defined by other + is disjoint from the region of this Envelope. + + The Envelope being checked for disjointness + true if the Envelopes are disjoint + + + + + Tests if the Envelope other lies wholely inside this Envelope (inclusive of the boundary). + + + Note that this is not the same definition as the SFS contains, + which would exclude the envelope boundary. + + The Envelope to check + true if other is contained in this Envelope + + + + + Tests if the given point lies in or on the envelope. + + + Note that this is not the same definition as the SFS contains, + which would exclude the envelope boundary. + + the point which this Envelope is being checked for containing + true if the point lies in the interior or on the boundary of this Envelope. + + + + + Tests if the given point lies in or on the envelope. + + + Note that this is not the same definition as the SFS contains, which would exclude the envelope boundary. + + the x-coordinate of the point which this Envelope is being checked for containing + the y-coordinate of the point which this Envelope is being checked for containing + + true if (x, y) lies in the interior or on the boundary of this Envelope. + + + + + + Tests if the given point lies in or on the envelope. + + the x-coordinate of the point which this Envelope is being checked for containing + the y-coordinate of the point which this Envelope is being checked for containing + true if (x, y) lies in the interior or on the boundary of this Envelope. + + + + Tests if the given point lies in or on the envelope. + + the point which this Envelope is being checked for containing + true if the point lies in the interior or on the boundary of this Envelope. + + + + Tests if the Envelope other lies wholely inside this Envelope (inclusive of the boundary). + + the Envelope to check + true if this Envelope covers the other + + + + Computes the distance between this and another + Envelope. + The distance between overlapping Envelopes is 0. Otherwise, the + distance is the Euclidean distance between the closest points. + + The distance between this and another Envelope. + + + + + + + + + + Compares two envelopes using lexicographic ordering. + The ordering comparison is based on the usual numerical + comparison between the sequence of ordinates. + Null envelopes are less than all non-null envelopes. + + An envelope + + + + Compares two envelopes using lexicographic ordering. + The ordering comparison is based on the usual numerical + comparison between the sequence of ordinates. + Null envelopes are less than all non-null envelopes. + + An envelope + + + + + + + Function to get a textual representation of this envelope + + A textual representation of this envelope + + + + Creates a deep copy of the current envelope. + + + + + + Method to parse an envelope from its value + + The envelope string + The envelope + + + + A representation of a planar, linear vector geometry. + + + +

Binary Predicates:

+ Because it is not clear at this time what semantics for spatial + analysis methods involving GeometryCollections would be useful, + GeometryCollections are not supported as arguments to binary + predicates or the Relate method. +
+ +

Overlay Methods:

+ The spatial analysis methods will + return the most specific class possible to represent the result. If the + result is homogeneous, a Point, LineString, or + Polygon will be returned if the result contains a single + element; otherwise, a MultiPoint, MultiLineString, + or MultiPolygon will be returned. If the result is + heterogeneous a GeometryCollection will be returned. +
+ + Representation of Computed Geometries: + The SFS states that the result + of a set-theoretic method is the "point-set" result of the usual + set-theoretic definition of the operation (SFS 3.2.21.1). However, there are + sometimes many ways of representing a point set as a Geometry. + The SFS does not specify an unambiguous representation of a given point set + returned from a spatial analysis method. One goal of NTS is to make this + specification precise and unambiguous. NTS uses a canonical form for + Geometrys returned from overlay methods. The canonical + form is a Geometry which is simple and noded: + Simple means that the Geometry returned will be simple according to + the NTS definition of IsSimple. + Noded applies only to overlays involving LineStrings. It + means that all intersection points on LineStrings will be + present as endpoints of LineStrings in the result. + This definition implies that non-simple geometries which are arguments to + spatial analysis methods must be subjected to a line-dissolve process to + ensure that the results are simple. + + + Constructed Points And The Precision Model: + The results computed by the set-theoretic methods may + contain constructed points which are not present in the input Geometrys. + These new points arise from intersections between line segments in the + edges of the input Geometrys. In the general case it is not + possible to represent constructed points exactly. This is due to the fact + that the coordinates of an intersection point may contain twice as many bits + of precision as the coordinates of the input line segments. In order to + represent these constructed points explicitly, NTS must truncate them to fit + the PrecisionModel. + Unfortunately, truncating coordinates moves them slightly. Line segments + which would not be coincident in the exact result may become coincident in + the truncated representation. This in turn leads to "topology collapses" -- + situations where a computed element has a lower dimension than it would in + the exact result. + When NTS detects topology collapses during the computation of spatial + analysis methods, it will throw an exception. If possible the exception will + report the location of the collapse. + + + +

Geometry Equality

+ There are two ways of comparing geometries for equality: + structural equality and topological equality. +

Structural Equality

+ Structural Equality is provided by the + method. + This implements a comparison based on exact, structural pointwise + equality. + The is a synonym for this method, + to provide structural equality semantics for + use in collections. + It is important to note that structural pointwise equality + is easily affected by things like + ring order and component order. In many situations + it will be desirable to normalize geometries before + comparing them (using the + or methods). + is provided + as a convenience method to compute equality over + normalized geometries, but it is expensive to use. + Finally, + allows using a tolerance value for point comparison. + +

Topological Equality

+ Topological Equality is provided by the + method. + It implements the SFS definition of point-set equality + defined in terms of the DE-9IM matrix. + To support the SFS naming convention, the method + is also provided as a synonym. + However, due to the potential for confusion with + its use is discouraged. +
+ + Since and are overridden, + Geometries can be used effectively in .Net collections. + +
+
+ + + An enumeration of sort values for geometries + + + NOTE:
+ For JTS v1.17 the values in this enum have been renamed to 'TYPECODE...' + In order not to break binary compatibility we did not follow. +
+
+ + Sort hierarchy value of a + + + Sort hierarchy value of a + + + Sort hierarchy value of a + + + Sort hierarchy value of a + + + Sort hierarchy value of a + + + Sort hierarchy value of a + + + Sort hierarchy value of a + + + Sort hierarchy value of a + + + + The name of point geometries + + + + + The name of multi-point geometries + + + + + The name of linestring geometries + + + + + The name of linearring geometries + + + + + The name of multi-linestring geometries + + + + + The name of polygon geometries + + + + + The name of multi-polygon geometries + + + + + The name of geometry collection geometries. + + + + + Gets the factory which contains the context in which this point was created. + + The factory for this point. + + + + Gets/Sets the user data object for this point, if any. + + + A simple scheme for applications to add their own custom data to a Geometry. + An example use might be to add an object representing a Coordinate Reference System. + Note that user data objects are not present in geometries created by + construction methods. + + + + + The bounding box of this Geometry. + + + + + Sets the ID of the Spatial Reference System used by the Geometry. + + + + NOTE: This method should only be used for exceptional circumstances or + for backwards compatibility. Normally the SRID should be set on the + used to create the geometry. + SRIDs set using this method will change the . + + + + + + + Creates a new Geometry via the specified GeometryFactory. + + The factory + + + + Returns the name of this Geometry's actual class. + + The name of this Geometrys actual class. + + + + Gets the OGC geometry type + + + + + Returns true if the array contains any non-empty Geometrys. + + an array of Geometrys; no elements may be null + + true if any of the Geometrys + IsEmpty methods return false. + + + + + Returns true if the array contains any null elements. + + an array to validate. + true if any of arrays elements are null. + + + + Returns true if the array contains any null elements. + + an array to validate. + true if any of arrays elements are null. + + + + Returns the PrecisionModel used by the Geometry. + + + the specification of the grid of allowable points, for this + Geometry and all other Geometrys. + + + + + Returns a vertex of this Geometry + (usually, but not necessarily, the first one). + + + The returned coordinate should not be assumed to be an actual Coordinate object used in the internal representation. + + a Coordinate which is a vertex of this Geometry. + null if this Geometry is empty. + + + + + Returns an array containing the values of all the vertices for + this geometry. + + + If the geometry is a composite, the array will contain all the vertices + for the components, in the order in which the components occur in the geometry. + + In general, the array cannot be assumed to be the actual internal + storage for the vertices. Thus modifying the array + may not modify the geometry itself. + Use the or + method + (possibly on the components) to modify the underlying data. + If the coordinates are modified, + must be called afterwards. + + + The vertices of this Geometry. + + + + + + + Gets an array of ordinate values + + The ordinate index + An array of ordinate values + + + + Returns the count of this Geometrys vertices. The Geometry + s contained by composite Geometrys must be + Geometry's; that is, they must implement NumPoints. + + The number of vertices in this Geometry. + + + + Returns the number of Geometryes in a GeometryCollection, + or 1, if the geometry is not a collection. + + + + + Returns an element Geometry from a GeometryCollection, + or this, if the geometry is not a collection. + + The index of the geometry element. + The n'th geometry contained in this geometry. + + + + Tests whether this is simple. + + The SFS definition of simplicity + follows the general rule that a Geometry is simple if it has no points of + self-tangency, self-intersection or other anomalous points. + + Simplicity is defined for each subclass as follows: + + Valid polygonal geometries are simple, since their rings + must not self-intersect. IsSimple + tests for this condition and reports false if it is not met. + (This is a looser test than checking for validity). + Linear rings have the same semantics. + Linear geometries are simple if they do not self-intersect at points + other than boundary points. + Zero-dimensional geometries (points) are simple if they have no + repeated points. + Empty Geometrys are always simple. + + + true if this Geometry is simple + + + + + Tests whether this Geometry is topologically + valid, according to the OGC SFS specification. + For validity rules see the documentation for the specific geometry subclass. + + true if this Geometry is valid. + + + + Tests whether the set of points covered in this Geometry is empty. + + Note this test is for topological emptiness, not structural emptiness.
+ A collection containing only empty elements is reported as empty.
+ To check structural emptiness use . +
+ true if this Geometry does not cover any points. +
+ + + Returns the minimum distance between this Geometry + and another Geometry g. + + The Geometry from which to compute the distance. + The distance between the geometries + 0 if either input geometry is empty + if g is null + + + + Tests whether the distance from this Geometry + to another is less than or equal to a specified value. + + the Geometry to check the distance to. + the distance value to compare. + true if the geometries are less than distance apart. + + + + Returns the area of this Geometry. + Areal Geometries have a non-zero area. + They override this function to compute the area. + Others return 0.0 + + The area of the Geometry. + + + + Gets a value indicating if the value for has been set. + + + + + Returns the length of this Geometry. + Linear geometries return their length. + Areal geometries return their perimeter. + They override this function to compute the length. + Others return 0.0 + + The length of the Geometry. + + + + Gets a value indicating if the value for has been set. + + + + + Computes the centroid of this Geometry. + The centroid + is equal to the centroid of the set of component Geometries of highest + dimension (since the lower-dimension geometries contribute zero + "weight" to the centroid). + + The centroid of an empty geometry is POINT EMPTY. + + A Point which is the centroid of this Geometry. + + + + Computes an interior point of this Geometry. + + + An interior point is guaranteed to lie in the interior of the Geometry, + if it possible to calculate such a point exactly. Otherwise, + the point may lie on the boundary of the point. + + The interior point of an empty geometry is POINT EMPTY. + + A Point which is in the interior of this Geometry. + + + + + + + + + Returns the dimension of this geometry. + + + The dimension of a geometry is is the topological + dimension of its embedding in the 2-D Euclidean plane. + In the NTS spatial model, dimension values are in the set {0,1,2}. + + Note that this is a different concept to the dimension of + the vertex s. + The geometry dimension can never be greater than the coordinate dimension. + For example, a 0-dimensional geometry (e.g. a Point) + may have a coordinate dimension of 3 (X,Y,Z). + + + + The topological dimensions of this geometry + + + + + Returns the boundary, or an empty geometry of appropriate dimension + if this Geometry is empty. + For a discussion of this function, see the OpenGIS Simple + Features Specification. As stated in SFS Section 2.1.13.1, "the boundary + of a Geometry is a set of Geometries of the next lower dimension." + + The closure of the combinatorial boundary of this Geometry. + + + + Returns the dimension of this Geometrys inherent boundary. + + + The dimension of the boundary of the class implementing this + interface, whether or not this object is the empty point. Returns + Dimension.False if the boundary is the empty point. + + + + + Gets a geometry representing the envelope (bounding box) of this Geometry. + + If this Geometry is + + empty, returns an empty Point + a point, returns a Point + a line parallel to an axis, a two-vertex LineString, + otherwise, returns a + Polygon whose vertices are (minx, miny), (maxx, miny), + (maxx, maxy), (minx, maxy), (minx, miny). + + + + A Geometry representing the envelope of this Geometry + + + + + + Gets an containing + the minimum and maximum x and y values in this Geometry. + If the geometry is empty, an empty Envelope + is returned. + + + The returned object is a copy of the one maintained internally, + to avoid aliasing issues. + For best performance, clients which access this + envelope frequently should cache the return value. + the envelope of this Geometry. + An empty Envelope if this Geometry is empty + + + + Notifies this geometry that its coordinates have been changed by an external + party (for example, via a ). + + + When this method is called the geometry will flush + and/or update any derived information it has cached (such as its ). + The operation is applied to all component Geometries. + + + + + Notifies this Geometry that its Coordinates have been changed by an external + party. When GeometryChanged is called, this method will be called for + this Geometry and its component Geometries. + + + + + Tests whether this geometry is disjoint from the argument geometry. + + + The Disjoint predicate has the following equivalent definitions: + + The DE-9IM intersection matrix for the two geometries matches FF*FF****. + !g.intersects(this) == true
(Disjoint is the inverse of Intersects)
+
+
+ The Geometry with which to compare this Geometry. + true if the two Geometrys are disjoint. + +
+ + + Tests whether this geometry touches the argument geometry + + + The Touches predicate has the following equivalent definitions: + + The geometries have at least one point in common, + but their interiors do not intersect + The DE-9IM Intersection Matrix for the two geometries matches + at least one of the following patterns + + FT*******, + F**T***** or + F***T****. + + + If both geometries have dimension 0, the predicate returns false, + since points have only interiors. + This predicate is symmetric. + + The Geometry with which to compare this Geometry. + + true if the two Geometrys touch; + Returns false if both Geometrys are points. + + + + + Tests whether this geometry intersects the argument geometry. + + + The Intersects predicate has the following equivalent definitions: + + The two geometries have at least one point in common + The DE-9IM Intersection Matrix for the two geometries matches
+ [T********] or
+ [*T*******] or
+ [***T*****] or
+ [****T****]
+ !g.disjoint(this)
+ (Intersects is the inverse of Disjoint)
+
+ The Geometry with which to compare this Geometry. + true if the two Geometrys intersect. + +
+ + + Tests whether this geometry crosses the specified geometry. + + + The Crosses predicate has the following equivalent definitions: + + The geometries have some but not all interior points in common. + The DE-9IM Intersection Matrix for the two geometries matches + one of the following patterns: + + CodeDescription + [T*T******]for P/L, P/A, and L/A situations + [T*****T**]for L/P, A/P, and A/L situations) + [0********]for L/L situations + + + + For the A/A and P/P situations this predicate returns false. + + The SFS defined this predicate only for P/L, P/A, L/L, and L/A situations. + To make the relation symmetric, + NTS extends the definition to apply to L/P, A/P and A/L situations as well. + + + The Geometry with which to compare this Geometry + true if the two Geometrys cross. + + + + Tests whether this geometry is within the specified geometry. + + + The within predicate has the following equivalent definitions: + + + Every point of this geometry is a point of the other geometry, + and the interiors of the two geometries have at least one point in common. + + The DE-9IM Intersection Matrix for the two geometries matches [T*F**F***] + g.contains(this) == true
(Within is the converse of )
+
+ + An implication of the definition is that "The boundary of a geometry is not within the Polygon". + In other words, if a geometry A is a subset of the points in the boundary of a geometry B, A.within(B) == false + (As a concrete example, take A to be a LineString which lies in the boundary of a Polygon B.) + For a predicate with similar behaviour but avoiding + this subtle limitation, see . + +
+ The Geometry with which to compare this Geometry. + true if this Geometry is within other. + + +
+ + + Tests whether this geometry contains the argument geometry. + + + The Contains predicate has the following equivalent definitions: + + Every point of the other geometry is a point of this geometry, + and the interiors of the two geometries have at least one point in common. + The DE-9IM Intersection Matrix for the two geometries matches the pattern + [T*****FF*] + g.within(this)
+ (Contains is the converse of )
+
+ + An implication of the definition is that "Geometries do not + contain their boundary". In other words, if a geometry A is a subset of + the points in the boundary of a geometry B, B.Contains(A) == false. + (As a concrete example, take A to be a LineString which lies in the boundary of a Polygon B.) + For a predicate with similar behaviour but avoiding + this subtle limitation, see . + +
+ the Geometry with which to compare this Geometry + true if this Geometry contains g + + +
+ + + Tests whether this geometry overlaps the specified geometry. + + + The Overlaps predicate has the following equivalent definitions: + + The geometries have at least one point each not shared by the other (or equivalently neither covers the other), + they have the same dimension, + and the intersection of the interiors of the two geometries has + the same dimension as the geometries themselves. + The DE-9IM Intersection Matrix for the two geometries matches + [T*T***T**] (for two points or two surfaces) + or [1*T***T**] (for two curves) + + If the geometries are of different dimension this predicate returns false. + + The Geometry with which to compare this Geometry. + + true if the two Geometrys overlap. + For this function to return true, the Geometry + s must be two points, two curves or two surfaces. + + + + + Tests whether this geometry covers the argument geometry + + + The covers predicate has the following equivalent definitions: + + Every point of the other geometry is a point of this geometry. + The DE-9IM Intersection Matrix for the two geometries matches at least + one of the following patterns: + + [T*****FF*] or
+ [*T****FF*] or
+ [***T**FF*] or
+ [****T*FF*] +
+
+ g.CoveredBy(this) == true
+ (covers is the converse of )
+
+ If either geometry is empty, the value of this predicate is false. + + This predicate is similar to , + but is more inclusive (i.e. returns true for more cases). + In particular, unlike Contains it does not distinguish between + points in the boundary and in the interior of geometries. + For most situations, Covers should be used in preference to Contains. + As an added benefit, Covers is more amenable to optimization, + and hence should be more performant. + +
+ The Geometry with which to compare this Geometry + true if this Geometry covers + + +
+ + Tests whether this geometry is covered by the specified geometry. + + The CoveredBy predicate has the following equivalent definitions: + + Every point of this geometry is a point of the other geometry. + The DE-9IM Intersection Matrix for the two geometries matches + at least one of the following patterns: + + [T*F**F***] + [*TF**F***] + [**FT*F***] + [**F*TF***] + g.Covers(this) == true
+ (CoveredBy is the converse of ) +
+
+ If either geometry is empty, the value of this predicate is false. + + This predicate is similar to , + but is more inclusive (i.e. returns true for more cases). + +
+ the Geometry with which to compare this Geometry + true if this Geometry is covered by g + + +
+ + + Tests whether the elements in the DE-9IM + for the two Geometrys match the elements in intersectionPattern. + + + The pattern is a 9-character string, with symbols drawn from the following set: + + 0(dimension 0) + 1(dimension 1) + 2(dimension 2) + T( matches 0, 1 or 2) + F( matches FALSE) + *( matches any value) + + For more information on the DE-9IM, see the OpenGIS Simple Features + Specification. + + the Geometry with which to compare this Geometry + the pattern against which to check the + intersection matrix for the two Geometrys + true if the DE-9IM intersection + matrix for the two Geometrys match intersectionPattern + + + + + Returns the DE-9IM intersection matrix for the two Geometrys. + + The Geometry with which to compare this Geometry + + A matrix describing the intersections of the interiors, + boundaries and exteriors of the two Geometrys. + + + + + Tests whether this geometry is + topologically equal to the argument geometry. + + This method is included for backward compatibility reasons. + It has been superseded by the method, + which has been named to clearly denote its functionality. + + This method should NOT be confused with the method + , which implements + an exact equality comparison. + + The Geometry with which to compare this Geometry + true if the two Geometrys are topologically equal. + + + + + Tests whether this geometry is topologically equal to the argument geometry + as defined by the SFS Equals predicate. + + + The SFS equals predicate has the following equivalent definitions: + + The two geometries have at least one point in common, + and no point of either geometry lies in the exterior of the other geometry. + The DE-9IM Intersection Matrix for the two geometries matches + the pattern T*F**FFF* +
+            T*F
+            **F
+            FF*
+            
+
+ Note that this method computes topologically equality. + For structural equality, see {@link #equalsExact(Geometry)}. +
+ the Geometry with which to compare this Geometry + true if the two Geometrys are topologically equal +
+ + + Tests whether this geometry is structurally and numerically equal + to a given Object. + + + If the argument Object is not a Geometry, + the result is false. + Otherwise, the result is computed using + . + + This method is provided to fulfill the Java contract + for value-based object equality. + In conjunction with + it provides semantics which are most useful + for using + Geometrys as keys and values in Java collections. + + Note that to produce the expected result the input geometries + should be in normal form. It is the caller's + responsibility to perform this where required + (using + or as appropriate). + + The object to compare + true if this geometry is exactly equal to the argument + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gets a hash code for the Geometry. + + + An integer value suitable for use as a hashcode + + + + + Returns the Well-known Text representation of this Geometry. + For a definition of the Well-known Text format, see the OpenGIS Simple + Features Specification. + + + The Well-known Text representation of this Geometry. + + + + + Returns the Well-known Text representation of this Geometry. + For a definition of the Well-known Text format, see the OpenGIS Simple + Features Specification. + + + The Well-known Text representation of this Geometry. + + + + + + + + + + + Returns the Well-known Binary representation of this Geometry. + For a definition of the Well-known Binary format, see the OpenGIS Simple + Features Specification. + + The Well-known Binary representation of this Geometry. + + + + + + + + + + Returns the feature representation as GML 2.1.1 XML document. + This XML document is based on Geometry.xsd schema. + NO features or XLink are implemented here! + + + + + Computes a buffer area around this geometry having the given width. The + buffer of a Geometry is the Minkowski sum or difference of the geometry + with a disc of radius Abs(distance). + + Mathematically-exact buffer area boundaries can contain circular arcs. + To represent these arcs using linear geometry they must be approximated with line segments. + The buffer geometry is constructed using 8 segments per quadrant to approximate + the circular arcs. + The end cap style is EndCapStyle.Round. + + The buffer operation always returns a polygonal result. The negative or + zero-distance buffer of lines and points is always an empty . + This is also the result for the buffers of degenerate (zero-area) polygons. + + + + The width of the buffer (may be positive, negative or 0), interpreted according to the + PrecisionModel of the Geometry. + + + a polygonal geometry representing the buffer region (which may be empty) + + If a robustness error occurs + + + + + + + + Computes a buffer region around this Geometry having the given width. + The buffer of a Geometry is the Minkowski sum or difference of the geometry + with a disc of radius Abs(distance). + + + The end cap style specifies the buffer geometry that will be + created at the ends of linestrings. The styles provided are: +
    +
  • - (default) a semi-circle
  • +
  • - a straight line perpendicular to the end segment
  • +
  • - a half-square
  • +
+ The buffer operation always returns a polygonal result. The negative or + zero-distance buffer of lines and points is always an empty . +
+ + The width of the buffer, interpreted according to the + PrecisionModel of the Geometry. + + Cap Style to use for compute buffer. + + a polygonal geometry representing the buffer region (which may be empty) + + If a robustness error occurs + + + + +
+ + + Computes a buffer region around this Geometry having the given + width and with a specified accuracy of approximation for circular arcs. + The buffer of a Geometry is the Minkowski sum of the Geometry with + a disc of radius distance. Curves in the buffer polygon are + approximated with line segments. This method allows specifying the + accuracy of that approximation. + + Mathematically-exact buffer area boundaries can contain circular arcs. + To represent these arcs using linear geometry they must be approximated with line segments. + The quadrantSegments argument allows controlling the accuracy of + the approximation by specifying the number of line segments used to + represent a quadrant of a circle + The buffer operation always returns a polygonal result. The negative or + zero-distance buffer of lines and points is always an empty . + This is also the result for the buffers of degenerate (zero-area) polygons. + + + + The width of the buffer (may be positive, negative or 0), interpreted according to the + PrecisionModel of the Geometry. + + The number of segments to use to approximate a quadrant of a circle. + + a polygonal geometry representing the buffer region (which may be empty) + + If a robustness error occurs + + + + + + + + Computes a buffer region around this Geometry having the given + width and with a specified number of segments used to approximate curves. + The buffer of a Geometry is the Minkowski sum of the Geometry with + a disc of radius distance. Curves in the buffer polygon are + approximated with line segments. This method allows specifying the + accuracy of that approximation. + + Mathematically-exact buffer area boundaries can contain circular arcs. + To represent these arcs using linear geometry they must be approximated with line segments. + The quadrantSegments argument allows controlling the accuracy of + the approximation by specifying the number of line segments used to + represent a quadrant of a circle + The end cap style specifies the buffer geometry that will be + created at the ends of linestrings. The styles provided are: +
    +
  • - (default) a semi-circle
  • +
  • - a straight line perpendicular to the end segment
  • +
  • - a half-square
  • +
+ The buffer operation always returns a polygonal result. The negative or + zero-distance buffer of lines and points is always an empty . + This is also the result for the buffers of degenerate (zero-area) polygons. + +
+ + The width of the buffer, interpreted according to the + PrecisionModel of the Geometry. + + The number of segments to use to approximate a quadrant of a circle. + Cap Style to use for compute buffer. + + a polygonal geometry representing the buffer region (which may be empty) + + If a robustness error occurs + + + + +
+ + + Computes a buffer region around this Geometry having the given + width and with a specified number of segments used to approximate curves. + The buffer of a Geometry is the Minkowski sum of the Geometry with + a disc of radius distance. Curves in the buffer polygon are + approximated with line segments. This method allows specifying the + accuracy of that approximation. + + Mathematically-exact buffer area boundaries can contain circular arcs. + To represent these arcs using linear geometry they must be approximated with line segments. + The bufferParameters argument has a property QuadrantSegments controlling the accuracy of + the approximation by specifying the number of line segments used to + represent a quadrant of a circle + The EndCapStyle property of the bufferParameters argument specifies the buffer geometry that will be + created at the ends of linestrings. The styles provided are: +
    +
  • - (default) a semi-circle
  • +
  • - a straight line perpendicular to the end segment
  • +
  • - a half-square
  • +
+ The buffer operation always returns a polygonal result. The negative or + zero-distance buffer of lines and points is always an empty . + This is also the result for the buffers of degenerate (zero-area) polygons. + +
+ + The width of the buffer, interpreted according to the + PrecisionModel of the Geometry. + + This argument type has a number of properties that control the construction of the + buffer, including QuadrantSegments, EndCapStyle, JoinStyle, and MitreLimit + + a polygonal geometry representing the buffer region (which may be empty) + + If a robustness error occurs + + + + +
+ + + Returns the smallest convex Polygon that contains all the + points in the Geometry. This obviously applies only to Geometry + s which contain 3 or more points. + + the minimum-area convex polygon containing this Geometry's points. + + + + Computes a new geometry which has all component coordinate sequences + in reverse order (opposite orientation) to this one. + + A reversed geometry + Don't override this function, implement . + + + + The actual implementation of the function + + A reversed geometry + In JTS this function is abstract, but that would break binary compatibility of current version. + + + + Computes a Geometry representing the point-set which is + common to both this Geometry and the other Geometry. + + The intersection of two geometries of different dimension produces a result + geometry of dimension less than or equal to the minimum dimension of the input + geometries. + The result geometry may be a heterogeneous . + If the result is empty, it is an atomic geometry + with the dimension of the lowest input dimension. + + Intersection of s is supported + only for homogeneous collection types. + + Non-empty heterogeneous arguments are not supported. + + The Geometry with which to compute the intersection. + A geometry representing the point-set common to the two Geometrys. + if a robustness error occurs. + if the argument is a non-empty heterogeneous GeometryCollection + if the argument has a factory with a different GeometryOverlay object assigned + + + + Computes a Geometry representing the point-set + which is contained in both this + Geometry and the other Geometry. + + + The method may be used on arguments of different dimension, but it does not + support arguments. + + The union of two geometries of different dimension produces a result + geometry of dimension equal to the maximum dimension of the input + geometries. + The result geometry may be a heterogeneous + . + If the result is empty, it is an atomic geometry + with the dimension of the highest input dimension. + + Unioning s has the effect of + noding and dissolving the input linework. In this context + "noding" means that there will be a node or endpoint in the result for + every endpoint or line segment crossing in the input. "Dissolving" means + that any duplicate (i.e. coincident) line segments or portions of line + segments will be reduced to a single line segment in the result. + If merged linework is required, the + class can be used. + + Non-empty arguments are not supported. + the Geometry with which to compute the union + A point-set combining the points of this Geometry and the + points of other + Thrown if a robustness error occurs + Thrown if either input is a non-empty GeometryCollection + if the argument has a factory with a different GeometryOverlay object assigned + + + + + Computes a Geometry representing the closure of the point-set + of the points contained in this Geometry that are not contained in + the other Geometry. + + If the result is empty, it is an atomic geometry + with the dimension of the left-hand input. + + Non-empty arguments are not supported. + + The Geometry with which to compute the difference. + A Geometry representing the point-set difference of this Geometry with other. + if the argument has a factory with a different GeometryOverlay object assigned + + + + Computes a Geometry representing the closure of the point-set + which is the union of the points in this Geometry which are not + contained in the other Geometry, + with the points in the other Geometry not contained in this + Geometry. + If the result is empty, it is an atomic geometry + with the dimension of the highest input dimension. + + Non-empty arguments are not supported. + + The Geometry with which to compute the symmetric difference. + a Geometry representing the point-set symmetric difference of this Geometry with other. + if the argument has a factory with a different GeometryOverlay object assigned + + + + Computes the union of all the elements of this geometry. + + + This method supports s (which the other overlay operations currently do not). + + The result obeys the following contract: + + Unioning a set of s has the effect of fully noding and dissolving the linework. + Unioning a set of s always returns a geometry + (unlike ), which may return geometries of lower dimension if a topology + collapse occurred). + + + Thrown if a robustness error occurs + + + + Returns true if the two Geometrys are exactly equal, + up to a specified tolerance. + Two Geometries are exactly within a tolerance equal if: + + they have the same class, + they have the same values of Coordinates, + within the given tolerance distance, in their internal + Coordinate lists, in exactly the same order. + + This method does not + test the values of the GeometryFactory, the SRID, + or the UserData fields. + + To properly test equality between different geometries, + it is usually necessary to them first. + + The Geometry with which to compare this Geometry + have identical structure and point values, up to the distance tolerance. + Distance at or below which two Coordinates will be considered equal. + + true if this and the other Geometry + are of the same class and have equal internal data. + + + + + + + + Returns true if the two Geometrys are exactly equal. + Two Geometries are exactly equal if: + + they have the same class, + they have the same values of Coordinates in their internal + Coordinate lists, in exactly the same order. + + This provides a stricter test of equality than + , which is more useful + in certain situations + (such as using geometries as keys in collections). + + This method does not + test the values of the GeometryFactory, the SRID, + or the UserData fields. + + To properly test equality between different geometries, + it is usually necessary to them first. + + The Geometry with which to compare this Geometry. + + true if this and the other Geometry have identical structure and point values. + + + + + Tests whether two geometries are exactly equal + in their normalized forms. + + This is a convenience method which creates normalized + versions of both geometries before computing + . + This method is relatively expensive to compute. + For maximum performance, the client + should instead perform normalization on the individual geometries + at an appropriate point during processing. + + + A geometry + true if the input geometries are exactly equal in their normalized form + + + + + Performs an operation with or on this Geometry's coordinates. + + + If this method modifies any coordinate values, + must be called to update the geometry state. + Note that you cannot use this method to + modify this Geometry if its underlying CoordinateSequence's #get method + returns a copy of the Coordinate, rather than the actual Coordinate stored + (if it even stores Coordinate objects at all). + + The filter to apply to this Geometry's coordinates + + + + Performs an operation on the coordinates in this Geometry's s. + + + If the filter reports that a coordinate value has been changed, + will be called automatically. + + The filter to apply + + + + Performs an operation on this Geometry's s. + + + If the filter reports that a coordinate value has been changed, + will be called automatically. + + The filter to apply + + + + Performs an operation with or on this Geometry and its + subelement Geometrys (if any). + Only GeometryCollections and subclasses + have subelement Geometry's. + + + The filter to apply to this Geometry (and + its children, if it is a GeometryCollection). + + + + + Performs an operation with or on this Geometry and its + component Geometry's. Only GeometryCollections and + Polygons have component Geometry's; for Polygons they are the LinearRings + of the shell and holes. + + The filter to apply to this Geometry. + + + + Creates a deep copy of this object. + Coordinate sequences contained in it are copied. + All instance fields are copied + (i.e. the SRID, EnvelopeInternal and UserData). + + + NOTE: The UserData object reference (if present) is copied, + but the value itself is not copied. + If a deep copy is required this must be performed by the caller. + + A deep copy of this geometry + + + + An internal method to copy subclass-specific geometry data. + + A copy of the target geometry object. + + + + Converts this Geometry to normal form (or canonical form ). + + + + Normal form is a unique representation for Geometrys. + It can be used to test whether two Geometrys are equal + in a way that is independent of the ordering of the coordinates within + them. Normal form equality is a stronger condition than topological + equality, but weaker than pointwise equality. + + The definitions for normal + form use the standard lexicographical ordering for coordinates. "Sorted in + order of coordinates" means the obvious extension of this ordering to + sequences of coordinates. + + + NOTE that this method mutates the value of this geometry in-place. + If this is not safe and/or wanted, the geometry should be + cloned prior to normalization. + + + + + + Creates a new Geometry which is a normalized copy of this Geometry. + + A normalized copy of this geometry. + + + + + Returns whether this Geometry is greater than, equal to, + or less than another Geometry. + + If their classes are different, they are compared using the following + ordering: + + Point (lowest), + MultiPoint, + LineString, + LinearRing, + MultiLineString, + Polygon, + MultiPolygon, + GeometryCollection (highest). + + If the two Geometrys have the same class, their first + elements are compared. If those are the same, the second elements are + compared, etc. + + A Geometry with which to compare this Geometry + + A positive number, 0, or a negative number, depending on whether + this object is greater than, equal to, or less than o, as + defined in "Normal Form For Geometry" in the NTS Technical + Specifications. + + + + + Returns whether this Geometry is greater than, equal to, + or less than another Geometry. + + If their classes are different, they are compared using the following + ordering: + + Point (lowest), + MultiPoint, + LineString, + LinearRing, + MultiLineString, + Polygon, + MultiPolygon, + GeometryCollection (highest). + /// + If the two Geometrys have the same class, their first + elements are compared. If those are the same, the second elements are + compared, etc. + + A Geometry with which to compare this Geometry + + A positive number, 0, or a negative number, depending on whether + this object is greater than, equal to, or less than o, as + defined in "Normal Form For Geometry" in the NTS Technical + Specifications. + + + + + Returns whether this Geometry is greater than, equal to, + or less than another Geometry, using the given . + + If their classes are different, they are compared using the following + ordering: + + Point (lowest), + MultiPoint, + LineString, + LinearRing, + MultiLineString, + Polygon, + MultiPolygon, + GeometryCollection (highest). + + If the two Geometrys have the same class, their first + elements are compared. If those are the same, the second elements are + compared, etc. + + A Geometry with which to compare this Geometry + A IComparer<CoordinateSequence> + + A positive number, 0, or a negative number, depending on whether + this object is greater than, equal to, or less than o, as + defined in "Normal Form For Geometry" in the NTS Technical + Specifications. + + + + + Returns whether the two Geometrys are equal, from the point + of view of the EqualsExact method. Called by EqualsExact + . In general, two Geometry classes are considered to be + "equivalent" only if they are the same class. An exception is LineString + , which is considered to be equivalent to its subclasses. + + The Geometry with which to compare this Geometry for equality. + + true if the classes of the two Geometry + s are considered to be equal by the equalsExact method. + + + + + Throws an exception if g's type is a GeometryCollection. + (Its subclasses do not trigger an exception). + + The Geometry to check. + + if g is a GeometryCollection, but not one of its subclasses. + + + + + Tests whether this is an instance of a general {@link GeometryCollection}, + rather than a homogeneous subclass. + + true if this is a heterogeneous GeometryCollection + + + + Returns the minimum and maximum x and y values in this Geometry, + or a null Envelope if this Geometry is empty. + Unlike EnvelopeInternal, this method calculates the Envelope + each time it is called; EnvelopeInternal caches the result + of this method. + + + This Geometrys bounding box; if the Geometry + is empty, Envelope.IsNull will return true. + + + + + Returns whether this Geometry is greater than, equal to, + or less than another Geometry having the same class. + + A Geometry having the same class as this Geometry. + + A positive number, 0, or a negative number, depending on whether + this object is greater than, equal to, or less than o, as + defined in "Normal Form For Geometry" in the NTS Technical + Specifications. + + + + + Returns whether this Geometry is greater than, equal to, + or less than another Geometry of the same class. + using the given . + + A Geometry having the same class as this Geometry + The comparer + + A positive number, 0, or a negative number, depending on whether + this object is greater than, equal to, or less than o, as + defined in "Normal Form For Geometry" in the JTS Technical + Specifications + + + + + Returns the first non-zero result of CompareTo encountered as + the two Collections are iterated over. If, by the time one of + the iterations is complete, no non-zero result has been encountered, + returns 0 if the other iteration is also complete. If b + completes before a, a positive number is returned; if a + before b, a negative number. + + A Collection of IComparables. + A Collection of IComparables. + The first non-zero compareTo result, if any; otherwise, zero. + + + + + + + + + + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + + + + + + + + + Tests whether this is a rectangular . + + true if the geometry is a rectangle. + Polygon overrides to check for actual rectangle. + + + + A predefined with == . + + + + + + + Basic implementation of GeometryCollection. + + + + + Represents an empty GeometryCollection. + + + + + Internal representation of this GeometryCollection. + + + + + + + + The Geometrys for this GeometryCollection, + or null or an empty array to create the empty + point. Elements may be empty Geometrys, + but not nulls. + + + For create this is used a standard + with == . + + + + + + + + The Geometrys for this GeometryCollection, + or null or an empty array to create the empty + point. Elements may be empty Geometrys, + but not nulls. + + + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + + + + + + Collects all coordinates of all subgeometries into an Array. + Note that while changes to the coordinate objects themselves + may modify the Geometries in place, the returned Array as such + is only a temporary container which is not synchronized back. + + The collected coordinates. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Returns the name of this object's interface. + + "GeometryCollection" + + + + Gets the OGC geometry type + + + + + + + + + + Returns the area of this GeometryCollection. + + + + + Returns the length of this GeometryCollection. + + + + + + + + + + + + + + + + + + + + + + + + + + + > + + + + + + + + + + + + + + + + + + + + + Return true if all features in collection are of the same type. + + + + + + + + Returns the iTh element in the collection. + + + + + + + Creates a with + every component reversed. + The order of the components in the collection are not reversed. + + A in the reverse order + + + + The actual implementation of the function for GeometryCollections. + + A reversed geometry + + + + Returns the number of geometries contained by this . + + + + + Iterates over all Geometry's in a GeometryCollection. + Implements a pre-order depth-first traversal of the GeometryCollection + (which may be nested). The original GeometryCollection is + returned as well (as the first object), as are all sub-collections. It is + simple to ignore the GeometryCollection objects if they are not + needed. + + + + + The GeometryCollection being iterated over. + + + + + Indicates whether or not the first element (the GeometryCollection) + has been returned. + + + + + The number of Geometrys in the the GeometryCollection. + + + + + The index of the Geometry that will be returned when next + is called. + + + + + The iterator over a nested GeometryCollection, or null + if this GeometryCollectionIterator is not currently iterating + over a nested GeometryCollection. + + + + + Constructs an iterator over the given GeometryCollection. + + + The collection over which to iterate; also, the first + element returned by the iterator. + + + + > + + + > + The parent GeometryCollection is the first object returned! + + + + + + + + + + + + + + + + + + + Delegate function declaration to handle filter operation + + The geometry to filter + + + + An implementation that applies filtering with the provided + + + + + Creates an instance of this class + + The filter method to be used + + + + Supplies a set of utility methods for building Geometry objects + from lists of Coordinates. + + + Note that the factory constructor methods do not change the input coordinates in any way. + In particular, they are not rounded to the supplied PrecisionModel. + It is assumed that input Coordinates meet the given precision. + + Instances of this class are thread-safe. + + + + + A predefined with c + == . + + + + + A predefined with + == . + + A shortcut for . + + + + A predefined with + == . + + + + + A predefined with + == . + + + + + Returns the PrecisionModel that Geometries created by this factory + will be associated with. + + + + + + + + + + The SRID value defined for this factory. + + + + + Gets a value indicating the geometry overlay function set to use + + A geometry overlay function set. + + + + Gets a value indicating the geometry overlay function set to use + + A geometry overlay function set. + + + + Gets a value indicating the object that created this factory. + + + + + + + + + + + + + Constructs a GeometryFactory that generates Geometries having the given + precision model, spatial-reference ID, + CoordinateSequence and + NtsGeometryServices. + + A precision model + A spatial reference id + A coordinate sequence factory + NtsGeometryServices object creating this factory + + + + Constructs a GeometryFactory that generates Geometries having the given + PrecisionModel, spatial-reference ID, and CoordinateSequence implementation. + + + + + Constructs a GeometryFactory that generates Geometries having the given + CoordinateSequence implementation, a double-precision floating PrecisionModel and a + spatial-reference ID of 0. + + + + + Constructs a GeometryFactory that generates Geometries having the given + {PrecisionModel} and the default CoordinateSequence + implementation. + + The PrecisionModel to use. + + + + Constructs a GeometryFactory that generates Geometries having the given + PrecisionModel and spatial-reference ID, and the default CoordinateSequence + implementation. + + The PrecisionModel to use. + The SRID to use. + + + + Constructs a GeometryFactory that generates Geometries having a floating + PrecisionModel and a spatial-reference ID of 0. + + + + + Converts the IEnumerable to an array. + + The IEnumerable of Points to convert. + The IEnumerable in array format. + + + + Converts the IEnumerable to an array. + + The IEnumerable of Geometry's to convert. + The IEnumerable in array format. + + + + Converts the IEnumerable to an array. + + The IEnumerable of LineStrings to convert. + The IEnumerable in array format. + + + + Converts the IEnumerable to an array. + + The IEnumerable of LinearRings to convert. + The IEnumerable in array format. + + + + Converts the IEnumerable to an array. + + The IEnumerable of Polygons to convert. + The IEnumerable in array format. + + + + Converts the IEnumerable to an array. + + The IEnumerable of MultiPoints to convert. + The IEnumerable in array format. + + + + Converts the IEnumerable to an array. + + The IEnumerable of MultiLineStrings to convert. + The IEnumerable in array format. + + + + Converts the IEnumerable to an array. + + The IEnumerable of MultiPolygons to convert. + The IEnumerable in array format. + + + + Creates a with the same extent as the given envelope. + + + + The Geometry returned is guaranteed to be valid. + To provide this behavior, the following cases occur: + + + If the Envelope is: +
    +
  • null returns an empty
  • +
  • a point returns a non-empty
  • +
  • a line returns a two-point
  • +
  • a rectangle returns a whose points are (minx, maxy), (minx, maxy), (maxx, maxy), (maxx, miny).
  • +
+
+
+ The Envelope + + An empty Point (for null Envelopes), a Point (when min x = max x and min y = max y) or a Polygon (in all other cases) + +
+ + + Creates an empty Point + + + An empty Point + + + + + Creates a Point using the given Coordinate. + A null coordinate creates an empty Geometry. + + a Coordinate, or null + A object + + + + Creates a Point using the given CoordinateSequence; a null or empty + CoordinateSequence will create an empty Point. + + a CoordinateSequence (possibly empty), or null + A object + + + + Creates an empty LineString + + An empty LineString + + + + Creates a LineString using the given Coordinates. + A null or empty array creates an empty LineString. + + An array without null elements, or an empty array, or null. + A object + + + + Creates a LineString using the given CoordinateSequence. + A null or empty CoordinateSequence creates an empty LineString. + + A CoordinateSequence (possibly empty), or null. + A object + + + Creates an empty LinearRing + An empty LinearRing + + + + Creates a LinearRing using the given Coordinates; a null or empty array + creates an empty LinearRing. The points must form a closed and simple + linestring. Consecutive points must not be equal. + + An array without null elements, or an empty array, or null. + A object + If the ring is not closed, or has too few points + + + + Creates a LinearRing using the given CoordinateSequence; a null or empty CoordinateSequence + creates an empty LinearRing. The points must form a closed and simple + linestring. Consecutive points must not be equal. + + A CoordinateSequence (possibly empty), or null. + A object + If the ring is not closed, or has too few points + + + Creates an empty Polygon + An empty Polygon + + + + Constructs a Polygon with the given exterior boundary and + interior boundaries. + + + The outer boundary of the new Polygon, or + null or an empty LinearRing if + the empty point is to be created. + + + The inner boundaries of the new Polygon, or + null or empty LinearRing s if + the empty point is to be created. + + A object + + + + Constructs a Polygon with the given exterior boundary. + + the outer boundary of the new Polygon, or + null or an empty LinearRing if + the empty geometry is to be created. + A object + If the boundary ring is invalid + + + + Constructs a Polygon with the given exterior boundary. + + the outer boundary of the new Polygon, or + null or an empty LinearRing if + the empty geometry is to be created. + A object + If the boundary ring is invalid + + + + Constructs a Polygon with the given exterior boundary. + + the outer boundary of the new Polygon, or + null or an empty LinearRing if + the empty geometry is to be created. + the created Polygon + If the boundary ring is invalid + + + Creates an empty MultiPoint + An empty MultiPoint + + + + Creates a using the given Points. + A null or empty array will create an empty MultiPoint. + + An array (without null elements), or an empty array, or null. + A object + + + + Creates a using the given Coordinates. + A null or empty array will create an empty MultiPoint. + + An array (without null elements), or an empty array, or null + A object + + + + Creates a using the given CoordinateSequence. + A null or empty CoordinateSequence will create an empty MultiPoint. + + A CoordinateSequence (possibly empty), or null. + A object + + + Creates an empty MultiLineString + An empty MultiLineString + + + + Creates a MultiLineString using the given LineStrings; a null or empty + array will create an empty MultiLineString. + + LineStrings, each of which may be empty but not null- + A object + + + Creates an empty MultiPolygon + An empty MultiPolygon + + + + Creates a MultiPolygon using the given Polygons; a null or empty array + will create an empty Polygon. The polygons must conform to the + assertions specified in the OpenGIS Simple Features + Specification for SQL. + + Polygons, each of which may be empty but not null. + A object + + + Creates an empty GeometryCollection + An empty GeometryCollection + + + + Creates a GeometryCollection using the given Geometries; a null or empty + array will create an empty GeometryCollection. + + an array of Geometries, each of which may be empty but not null, or null + A object + + + + Build an appropriate Geometry, MultiGeometry, or + GeometryCollection to contain the Geometrys in + it. + + + If geomList contains a single Polygon, + the Polygon is returned.
+ If geomList contains several Polygons, a + MultiPolygon is returned.
+ If geomList contains some Polygons and + some LineStrings, a GeometryCollection is + returned.
+ If geomList is empty, an empty GeometryCollection + is returned. + Note that this method does not "flatten" Geometries in the input, and hence if + any MultiGeometries are contained in the input a GeometryCollection containing + them will be returned. +
+ The Geometry to combine. + + A of the "smallest", "most type-specific" + class that can contain the elements of geomList. + +
+ + + Creates an empty atomic geometry of the given dimension. + If passed a dimension of + will create an empty . + + The required dimension (, , or ) + An empty atomic geometry of given dimension + + + + Creates a deep copy of the input . + The defined for this factory + is used to copy the s + of the input geometry. + + This is a convenient way to change the CoordinateSequence + used to represent a geometry, or to change the + factory used for a geometry. + + can also be used to make a deep copy, + but it does not allow changing the CoordinateSequence type. + + The geometry + A deep copy of the input geometry, using the CoordinateSequence type of this factory + + + + + Returns a new whose is + the given value and whose other values and behavior are, as near as we possibly can make + it, the same as our own. + + + The for the result. + + + The cloned instance. + + + + + + + + An extended that is capable of enforcing a ring orientation for polygons. + + + + + Gets or sets the default polygon shell ring orientation that is used when nothing else has been set. + + + + + Gets or sets the default precision model to use with these geometry factories + + + + + Gets or sets the default coordinate sequence factory to use with these geometry factories + + + + + Gets or sets the default spatial reference id. + + + + + Constructs a GeometryFactory that generates Geometries having the given + PrecisionModel, spatial-reference ID, and CoordinateSequence implementation. + + + + + Constructs a GeometryFactory that generates Geometries having the given + PrecisionModel, spatial-reference ID, and CoordinateSequence implementation. + + + + + Constructs a GeometryFactory that generates Geometries having the given + CoordinateSequence implementation, a double-precision floating PrecisionModel and a + spatial-reference ID of 0. + + + + + Constructs a GeometryFactory that generates Geometries having the given + {PrecisionModel} and the default CoordinateSequence + implementation. + + The PrecisionModel to use. + + + + Constructs a GeometryFactory that generates Geometries having the given + PrecisionModel and spatial-reference ID, and the default CoordinateSequence + implementation. + + The PrecisionModel to use. + The SRID to use. + + + + Constructs a GeometryFactory that generates Geometries having a floating + PrecisionModel and a spatial-reference ID of 0. + + + + + The polygon shell ring orientation enforced by this factory + + + + + Gets or sets a value indicating the ring orientation of the + Polygon's exterior rings. + If its value is , this + factory behaves just like the base . + + + + The setter of this property has to be used prior to any call + to CreatePolygon, CreateMultiPolygon, or + ReplaceSRID + + + + + + + + + Gets a value indicating the ring orientation for the interior rings + + + This value is always opposite of , + except when its value is . + + + + + Constructs a Polygon with the given exterior boundary and + interior boundaries. + + The is enforced on the constructed polygon. + + + The outer boundary of the new Polygon, or + null or an empty LinearRing if + the empty point is to be created. + + + The inner boundaries of the new Polygon, or + null or empty LinearRing s if + the empty point is to be created. + + A object + + + + Creates a MultiPolygon using the given Polygons; a null or empty array + will create an empty Polygon. The polygons must conform to the + assertions specified in the OpenGIS Simple Features + Specification for SQL. + The is enforced on each polygon. + + Polygons, each of which may be empty but not null. + A object + + + + + + + Utility function to enforce a specific ring orientation on a linear ring + + The ring + The required orientation + A ring + + + + A class that encapsulates geometry overlay functionality + + + + + Gets a value indicating a geometry overlay operation class that uses old NTS overlay operation set. + + + + + Gets a value indicating a geometry overlay operation class that uses next-generation NTS overlay operation set. + + + + + Computes a Geometry representing the overlay of geometries a and b + using the spatial function defined by opCode. + + The 1st geometry + The 2nd geometry + The spatial function for the overlay operation + The computed geometry + + + + Computes a Geometry representing the point-set which is + common to both a and b Geometry. + + The 1st Geometry + The 2nd Geometry + A geometry representing the point-set common to the two Geometrys. + + + + + Computes a Geometry representing the point-set + which is contained in both input Geometrys . + + The 1st Geometry + The 2nd Geometry + A point-set combining the points of + Geometry's a and b. + + + + + + Computes a Geometry representing the closure of the point-set + of the points contained in this Geometry that are not contained in + the other Geometry. + + The 1st Geometry + The 2nd Geometry + + A Geometry representing the point-set difference + of Geometry's a and b. + + + + + + Computes a Geometry representing the closure of the point-set + which is the union of the points in Geometry a which are not + contained in the Geometry b, + with the points in the b Geometry not contained in the Geometry a. + + The 1st Geometry + The 2nd Geometry + + A Geometry representing the point-set symmetric difference + of Geometry's a and b. + + + + + + Computes the union of all the elements in the Geometry a. + + The Geometry + The union of a + + + + + A spatial object in an AbstractSTRtree. + + + + + Returns a representation of space that encloses this Boundable, preferably + not much bigger than this Boundable's boundary yet fast to test for intersection + with the bounds of other Boundables. The class of object returned depends + on the subclass of AbstractSTRtree. + + + An Envelope (for STRtrees), an Interval (for SIRtrees), or other object + (for other subclasses of AbstractSTRtree). + + + + + Gets the item that is bounded + + + + + An interface for classes which use the values of the coordinates in a . + Coordinate filters can be used to implement centroid and + envelope computation, and many other functions. + + ICoordinateFilter is + an example of the Gang-of-Four Visitor pattern. + + Note: it is not recommended to use these filters to mutate the coordinates. + There is no guarantee that the coordinate is the actual object stored in the source geometry. + In particular, modified values may not be preserved if the source Geometry uses a non-default . + If in-place mutation is required, use . + + + + + + + Performs an operation with the provided coord. + Note that there is no guarantee that the input coordinate + is the actual object stored in the source geometry, + so changes to the coordinate object may not be persistent. + + A Coordinate to which the filter is applied. + + + + An interface for classes which process the coordinates in a . + A filter can either record information about each coordinate, + or change the value of the coordinate. + Filters can be + used to implement operations such as coordinate transformations, centroid and + envelope computation, and many other functions. + classes support the concept of applying a + CoordinateSequenceFilter to each + s they contain. + + For maximum efficiency, the execution of filters can be short-circuited by using the property. + + + + CoordinateSequenceFilter is an example of the Gang-of-Four Visitor pattern. + Note: In general, it is preferable to treat Geometrys as immutable. + Mutation should be performed by creating a new Geometry object (see + and for convenient ways to do this). + An exception to this rule is when a new Geometry has been created via . + In this case mutating the Geometry will not cause aliasing issues, + and a filter is a convenient way to implement coordinate transformation. + + + Martin Davis + + + + + + + Performs an operation on a coordinate in a . + + the CoordinateSequence to which the filter is applied + i the index of the coordinate to apply the filter to + + + + Reports whether the application of this filter can be terminated. + + + Once this method returns true, it must + continue to return true on every subsequent call. + + + + + Reports whether the execution of this filter has modified the coordinates of the geometry. + If so, will be executed + after this filter has finished being executed. + + Most filters can simply return a constant value reflecting whether they are able to change the coordinates. + + + + A variant of , except it receives each + just once, instead of once for each of its coordinates. + + + + + Reports whether the application of this filter can be terminated. + + + Once this method returns it must continue to return + on every subsequent call. + + + + + Reports whether the execution of this filter has modified the coordinates of the geometry. + If so, will be executed + after this filter has finished being executed. + + + Most filters can simply return a constant value reflecting whether they are able to + change the coordinates. + + + + + Performs an operation on a . + + + The . + + + + + Interface describing objects that can expand themselves by objects of type . + + The type of objects that can expand clients + + + + Method to expand this object by + + The object to expand with + + + + Function to expand compute a new object that is this object by expanded by . + + The object to expand with + The expanded object + + + + Geometry classes support the concept of applying + an IGeometryComponentFilter filter to the Geometry. + + + The filter is applied to every component of the Geometry + which is itself a Geometry + and which does not itself contain any components. + (For instance, all the LinearRings in Polygons are visited, + but in a MultiPolygon the Polygons themselves are not visited.) + Thus the only classes of Geometry which must be + handled as arguments to + are s, s and s. + An IGeometryComponentFilter filter can either + record information about the Geometry + or change the Geometry in some way. + IGeometryComponentFilter is an example of the Gang-of-Four Visitor pattern. + > + + + + Performs an operation with or on geom. + + A Geometry to which the filter is applied. + + + + GeometryCollection classes support the concept of + applying a IGeometryFilter to the Geometry. + The filter is applied to every element Geometry. + A IGeometryFilter can either record information about the Geometry + or change the Geometry in some way. + IGeometryFilter is an example of the Gang-of-Four Visitor pattern. + + + + + Performs an operation with or on geom. + + A Geometry to which the filter is applied. + + + + Interface describing objects that can perform an intersects predicate with objects. + + The type of the component that can intersect + + + + Predicate function to test if intersects with this object. + + The object to test + true if this objects intersects with + + + + Interface to identify all Geometry subclasses that have a Dimension of + and have components which are s. + + Martin Davis + + + + + + A backed by an array of s. + This is the implementation that s use by default. + + Coordinates returned by , and are live -- + modifications to them are actually changing the + CoordinateSequence's underlying data. + A dimension may be specified for the coordinates in the sequence, + which may be 2 or 3. + The actual coordinates will always have 3 ordinates, + but the dimension is useful as metadata in some situations. + + + + + Array of coordinates in sequence + + + + + Constructs a sequence based on the given array of s. + The coordinate dimension defaults to 2 + + + The array is not copied. + + The coordinate array that will be referenced. + + + + Constructs a sequence based on the given array + of s. + + The Array is not copied + The coordinate array that will be referenced. + The dimension of the coordinates + + + + Constructs a sequence based on the given array + of s. + + The Array is not copied + + It is your responsibility to ensure the array contains Coordinates of the + indicated dimension and measures (See ). + + The coordinate array that will be referenced. + The dimension of the coordinates + The number of measure ordinate values. + + + + Constructs a sequence of a given size, populated with new Coordinates. + + The size of the sequence to create. + + + + Constructs a sequence of a given , populated + with new s of the given . + + The size of the sequence to create. + the dimension of the coordinates + + + + Constructs a sequence of a given , populated + with new s of the given + with the given number of + + The size of the sequence to create. + the dimension of the coordinates + the number of measures of the coordinates + + + + Creates a new sequence based on a deep copy of the given . + + The coordinate sequence that will be copied + + + + Ensure array contents of the same type, making use of as needed. + + A new array will be created if needed to return a consistent result. + + + array containing consistent coordinate instances + + + + Get the Coordinate with index i. + + The index of the coordinate. + The requested Coordinate instance. + + + + Get a copy of the Coordinate with index i. + + The index of the coordinate. + A copy of the requested Coordinate. + + + + Copies the i'th coordinate in the sequence to the supplied Coordinate. + + The index of the coordinate to copy. + A Coordinate to receive the value. + + + + Returns ordinate X (0) of the specified coordinate. + + + + The value of the X ordinate in the index'th coordinate. + + + + + Returns ordinate Y (1) of the specified coordinate. + + + + The value of the Y ordinate in the index'th coordinate. + + + + + Returns ordinate Z of the specified coordinate if available. + + + + The value of the Z ordinate in the index'th coordinate, or Double.NaN if not defined. + + + + + Returns ordinate M of the specified coordinate if available. + + + + The value of the M ordinate in the index'th coordinate, or Double.NaN if not defined. + + + + + Returns the ordinate of a coordinate in this sequence. + Ordinate indices 0 and 1 are assumed to be X and Y. + Ordinate indices greater than 1 have user-defined semantics + (for instance, they may contain other dimensions or measure values). + + The coordinate index in the sequence. + The ordinate index in the coordinate (in range [0, dimension-1]). + + + + + Creates a deep copy of the CoordinateArraySequence. + + The deep copy. + + + + + + + + + + Sets the value for a given ordinate of a coordinate in this sequence. + + The coordinate index in the sequence. + The ordinate index in the coordinate (in range [0, dimension-1]). + The new ordinate value. + + + + This method exposes the internal Array of Coordinate Objects. + + + + + + Expands the given Envelope to include the coordinates in the sequence. + Allows implementing classes to optimize access to coordinate values. + + The envelope to expand. + A reference to the expanded envelope. + + + + + + + Returns the string representation of the coordinate array. + + + + + + Creates CoordinateSequences represented as an array of Coordinates. + + + + + Returns the singleton instance of CoordinateArraySequenceFactory. + + + + + Returns a CoordinateArraySequence based on the given array (the array is not copied). + + the coordinates, which may not be null nor contain null elements. + + + + + + + + + + + A coordinate sequence that follows the dotspatial shape range + + + + + Creates an instance of this class + + The coordinates + + + + + Constructs a sequence of a given size, populated with new Coordinates. + + The size of the sequence to create. + The number of dimensions. + The number of measures. + + + + Constructs a sequence of a given size, populated with new Coordinates. + + The size of the sequence to create. + The kind of ordinates. + + + + Creates a sequence based on the given coordinate sequence. + + The coordinate sequence. + The ordinates to copy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a reversed version of this coordinate sequence with cloned s + + A reversed version of this sequence + + + + Gets the vector with x- and y-ordinate values; + + If you modify the values of this vector externally, you need to call ! + + + + Gets the vector with z-ordinate values + + If you modify the values of this vector externally, you need to call ! + + + + Gets the vector with measure values + + If you modify the values of this vector externally, you need to call ! + + + + Releases the weak reference to the weak referenced coordinate array + + This is necessary if you modify the values of the , , arrays externally. + + + + A coordinate sequence factory class that creates DotSpatial's Shape/ShapeRange like coordinate sequences. + + + + + Returns the singleton instance of DotSpatialAffineCoordinateSequenceFactory. + + + + + + Returns a CoordinateArraySequence based on the given array (the array is not copied). + + the coordinates, which may not be null nor contain null elements. + + + + + Creates a which is a copy + of the given . + This method must handle null arguments by creating an empty sequence. + + + A coordinate sequence + + + + + + + Creates a of the specified size and ordinates. + For this to be useful, the implementation must be mutable. + + The number of coordinates. + + The ordinates each coordinate has. is fix, + and can be set. + + A coordinate sequence. + + + + Creates an instance of this class using the provided array for x- and y ordinates + + The x- and y-ordinates + A coordinate sequence + + + + Creates an instance of this class using the provided array for x- and y ordinates, + the array for either z-ordinates or measure values. This is indicated by . + + The x- and y-ordinates + An array of z- or measure values + A value indicating if contains z-ordinates or measure values. + A coordinate sequence + + + + Creates an instance of this class using the provided array for x- and y ordinates, + the array for z ordinates and for measure values. + + The x- and y-ordinates + An array of z- or measure values + An array of measure values. + A coordinate sequence + + + + A CoordinateSequence implementation based on a packed arrays. + + + + + A soft reference to the Coordinate[] representation of this sequence. + Makes repeated coordinate array accesses more efficient. + + + + + Creates an instance of this class + + The number of s in the sequence. + The total number of ordinates that make up a in this sequence. + the number of measure-ordinates each { in this sequence has. + + + + Returns (possibly a copy of) the ith Coordinate in this collection. + Whether or not the Coordinate returned is the actual underlying + Coordinate or merely a copy depends on the implementation. + Note that in the future the semantics of this method may change + to guarantee that the Coordinate returned is always a copy. Callers are + advised not to assume that they can modify a CoordinateSequence by + modifying the Coordinate returned by this method. + + + + + + + Returns (possibly copies of) the Coordinates in this collection. + Whether or not the Coordinates returned are the actual underlying + Coordinates or merely copies depends on the implementation. + Note that if this implementation does not store its data as an array of Coordinates, + this method will incur a performance penalty because the array needs to + be built from scratch. + + + + + + Releases the weak reference to the coordinate array. + + + This is necessary if you directly modify the array from GetRawCoordinates. + + + + + + + + Returns a Coordinate representation of the specified coordinate, by always + building a new Coordinate object. + + The coordinate index + The at the given index + + + + Packed coordinate sequence implementation based on doubles. + + + + + The packed coordinate array + + + + + Initializes a new instance of the class. + + An array of double values that contains the ordinate values of the sequence. + The total number of ordinates that make up a in this sequence. + The number of measure-ordinates each in this sequence has. + + + + Initializes a new instance of the class. + + An array of float values that contains the ordinate values of the sequence. + The total number of ordinates that make up a in this sequence. + The number of measure-ordinates each in this sequence has. + + + + Initializes a new instance of the class. + + An array of s. + + + + Initializes a new instance of the class. + + An array of s. + The total number of ordinates that make up a in this sequence. + + + + Initializes a new instance of the class. + + An array of s. + The total number of ordinates that make up a in this sequence. + The number of measure-ordinates each in this sequence has. + + + + Initializes a new instance of the class. + + The number of coordinates in this sequence + The total number of ordinates that make up a in this sequence. + The number of measure-ordinates each in this sequence has. + + + + Gets the underlying array containing the coordinate values. + + The array of coordinate values + + + + + + + Returns the ordinate of a coordinate in this sequence. + Ordinate indices 0 and 1 are assumed to be X and Y. + Ordinate indices greater than 1 have user-defined semantics + (for instance, they may contain other dimensions or measure values). + + + Beware, for performance reasons the ordinate index is not checked, if + it's over dimensions you may not get an exception but a meaningless + value. + + The coordinate index in the sequence. + The ordinate index in the coordinate (in range [0, dimension-1]). + + + + + Sets the ordinate of a coordinate in this sequence. + + The coordinate index. + The ordinate index in the coordinate, 0 based, + smaller than the number of dimensions. + The new ordinate value. + + Warning: for performance reasons the ordinate index is not checked. + If it is larger than the dimension a meaningless value may be returned. + + + + + Expands the given Envelope to include the coordinates in the sequence. + Allows implementing classes to optimize access to coordinate values. + + The envelope to expand. + A reference to the expanded envelope. + + + + Packed coordinate sequence implementation based on floats. + + + + + The packed coordinate array + + + + + Initializes a new instance of the class. + + An array of float values that contains the ordinate values of the sequence. + The total number of ordinates that make up a in this sequence. + The number of measure-ordinates each in this sequence has. + + + + Initializes a new instance of the class. + + An array of double values that contains the ordinate values of the sequence. + The total number of ordinates that make up a in this sequence. + The number of measure-ordinates each in this sequence has. + + + + Initializes a new instance of the class. + + An array of s. + + + + Initializes a new instance of the class. + + An array of s. + The total number of ordinates that make up a in this sequence. + + + + Initializes a new instance of the class. + + An array of s. + The total number of ordinates that make up a in this sequence. + The number of measure-ordinates each in this sequence has. + + + + Initializes a new instance of the class. + + + + + + + + Gets the underlying array containing the coordinate values. + + The array of coordinate values + + + + + + + Returns the ordinate of a coordinate in this sequence. + Ordinate indices 0 and 1 are assumed to be X and Y. + Ordinate indices greater than 1 have user-defined semantics + (for instance, they may contain other dimensions or measure values). + + + Beware, for performance reasons the ordinate index is not checked, if + it's over dimensions you may not get an exception but a meaningless + value. + + The coordinate index in the sequence. + The ordinate index in the coordinate (in range [0, dimension-1]). + + + + + Sets the ordinate of a coordinate in this sequence. + + The coordinate index. + The ordinate index in the coordinate, 0 based, + smaller than the number of dimensions. + The new ordinate value. + + Warning: for performance reasons the ordinate index is not checked: + if it is over dimensions you may not get an exception but a meaningless value. + + + + + Expands the given Envelope to include the coordinates in the sequence. + Allows implementing classes to optimize access to coordinate values. + + The envelope to expand. + A reference to the expanded envelope. + + + + Builds packed array coordinate sequences. + The array data type can be either + double or float, + and defaults to double. + + + + + An enumeration of valid type codes + + + + + Type code for arrays of type double. + + + + + Type code for arrays of type float. + + + + + A factory creating coordinate sequences + + + + + A factory creating coordinate sequences + + + + + Initializes a new instance of the class, + using double values. + + + + + Initializes a new instance of the class. + + The type. + + + + Gets the type of packed coordinate sequence this factory builds, either + or + + The type of packed array built. + + + + Returns a CoordinateSequence based on the given array; whether or not the + array is copied is implementation-dependent. + + Coordinates array, which may not be null nor contain null elements + + + + + Returns a CoordinateSequence based on the given coordinate sequence; whether or not the + array is copied is implementation-dependent. + + + + + + + Creates a packed coordinate sequence of type from the provided double array + using the provided dimension and a measure of 0. + + The array containing coordinate values + The coordinate dimension + A packed coordinate sequence of + + + + Creates a packed coordinate sequence of type from the provided double array + using the provided dimension and a measure of 0. + + The array containing coordinate values + The coordinate dimension + The coordinate measure count + A packed coordinate sequence of + + + + Creates a packed coordinate sequence of type from the provided float array + using the provided dimension and a measure of 0. + + The array containing coordinate values + The coordinate dimension + A packed coordinate sequence of + + + + Creates a packed coordinate sequence of type from the provided float array + using the provided dimension and a measure of 0. + + The array containing coordinate values + The coordinate dimension + The coordinate measure count + A packed coordinate sequence of + + + + + + + An implementation of that packs its contents in a way that + can be customized by the creator. + + + + + Initializes a new instance of the class. + + + Contains the raw data for this sequence. + + + Contains a pair of indexes to tell us, for each dimension, where to find its data in + . + + + The value for . + + + + + Gets the underlying for the ordinates at the given index, along + with a "stride" value that represents how many slots there are between elements. + + + The index of the ordinate whose values to get, from + . + + + The underlying and stride. + + + Assuming is nonzero, the first element of the + returned array holds the first coordinate's value for the requested ordinate, and the + last element of the returned array holds the last coordinate's value for the requested + ordinate. + + + + + + + + + + + + + + + + + + + + + + + Factory for creating instances. + + + + + Initializes a new instance of the class. + + + A sequence of zero or more flags representing ordinate values + that should be allocated together. + + + Thrown when is . + + + Thrown when a given flag appears in more than one element of + . + + + Any flags not represented in , and any spatial or + measure dimensions beyond the 16th, will be allocated together, SoA-style. + + Elements without any bits set will be silently ignored. + + + + + Creates a new that uses the given arrays for reading + and writing X and Y data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X values, laid out as + [x0, x1, x2, ..., xn]. + + + An array of Y values, laid out as + [y0, y1, y2, ..., yn]. + + + A instance that's backed by the given arrays. + + + Thrown when the input arrays do not contain data for the same number of coordinates. + + + + + Creates a new that uses the given array for reading + and writing X and Y data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X and Y values, laid out as + [x0, y0, x1, y1, x2, y2, ..., xn, yn]. + + + A instance that's backed by the given array. + + + The resulting instance is essentially a + with slightly more overhead, so the main reason to prefer this over that one would be if + you really need to avoid copying the data to fit it into that format. + + + Thrown when the length of is not a multiple of 2. + + + + + Creates a new that uses the given arrays for reading + and writing X, Y, and Z data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X values, laid out as + [x0, x1, x2, ..., xn]. + + + An array of Y values, laid out as + [y0, y1, y2, ..., yn]. + + + An array of Z values, laid out as + [z0, z1, z2, ..., zn]. + + + A instance that's backed by the given arrays. + + + Thrown when the input arrays do not contain data for the same number of coordinates. + + + + + Creates a new that uses the given array for reading + and writing X, Y, and Z data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X and Y values, laid out as + [x0, y0, x1, y1, x2, y2, ..., xn, yn]. + + + An array of Z values, laid out as + [z0, z1, z2, ..., zn]. + + + A instance that's backed by the given array. + + + The resulting instance is essentially a + with slightly more overhead, so the main reason to prefer this over that one would be if + you really need to avoid copying the data to fit it into that format. + + + Thrown when the length of is not a multiple of 2, or when the + input arrays do not contain data for the same number of coordinates. + + + + + Creates a new that uses the given array for reading + and writing X, Y, and Z data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X, Y, and Z values, laid out as + [x0, y0, z0, x1, y1, z1, x2, y2, z2, ..., xn, yn, zn]. + + + A instance that's backed by the given array. + + + The resulting instance is essentially a + with slightly more overhead, so the main reason to prefer this over that one would be if + you really need to avoid copying the data to fit it into that format. + + + Thrown when the length of is not a multiple of 3. + + + + + Creates a new that uses the given arrays for reading + and writing X, Y, and M data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X values, laid out as + [x0, x1, x2, ..., xn]. + + + An array of Y values, laid out as + [y0, y1, y2, ..., yn]. + + + An array of M values, laid out as + [m0, m1, m2, ..., mn]. + + + A instance that's backed by the given arrays. + + + Thrown when the input arrays do not contain data for the same number of coordinates. + + + + + Creates a new that uses the given array for reading + and writing X, Y, and M data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X and Y values, laid out as + [x0, y0, x1, y1, x2, y2, ..., xn, yn]. + + + An array of M values, laid out as + [m0, m1, m2, ..., mn]. + + + A instance that's backed by the given array. + + + The resulting instance is essentially a + with slightly more overhead, so the main reason to prefer this over that one would be if + you really need to avoid copying the data to fit it into that format. + + + Thrown when the length of is not a multiple of 2, or when the + input arrays do not contain data for the same number of coordinates. + + + + + Creates a new that uses the given array for reading + and writing X, Y, and M data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X, Y, and M values, laid out as + [x0, y0, m0, x1, y1, m1, x2, y2, m2, ..., xn, yn, mn]. + + + A instance that's backed by the given array. + + + The resulting instance is essentially a + with slightly more overhead, so the main reason to prefer this over that one would be if + you really need to avoid copying the data to fit it into that format. + + + Thrown when the length of is not a multiple of 3. + + + + + Creates a new that uses the given arrays for reading + and writing X, Y, Z, and M data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X values, laid out as + [x0, x1, x2, ..., xn]. + + + An array of Y values, laid out as + [y0, y1, y2, ..., yn]. + + + An array of Z values, laid out as + [z0, z1, z2, ..., zn]. + + + An array of M values, laid out as + [m0, m1, m2, ..., mn]. + + + A instance that's backed by the given arrays. + + + Thrown when the input arrays do not contain data for the same number of coordinates. + + + + + Creates a new that uses the given array for reading + and writing X, Y, Z, and M data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X and Y values, laid out as + [x0, y0, x1, y1, x2, y2, ..., xn, yn]. + + + An array of Z values, laid out as + [z0, z1, z2, ..., zn]. + + + An array of M values, laid out as + [m0, m1, m2, ..., mn]. + + + A instance that's backed by the given array. + + + The resulting instance is essentially a + with slightly more overhead, so the main reason to prefer this over that one would be if + you really need to avoid copying the data to fit it into that format. + + + Thrown when the length of is not a multiple of 2, or when the + input arrays do not contain data for the same number of coordinates. + + + + + Creates a new that uses the given array for reading + and writing X, Y, Z, and M data ignoring the flags that were passed + into the constructor for this factory instance. + + + An array of X, Y, Z, and M values, laid out as + [x0, y0, z0, m0, x1, y1, z1, m1, x2, y2, z2, m2, ..., xn, yn, zn, mn]. + + + A instance that's backed by the given array. + + + The resulting instance is essentially a + with slightly more overhead, so the main reason to prefer this over that one would be if + you really need to avoid copying the data to fit it into that format. + + + Thrown when the length of is not a multiple of 4. + + + + + + + + Models a Dimensionally Extended Nine-Intersection Model (DE-9IM) matrix. + + + DE-9IM matrix values (such as "212FF1FF2") + specify the topological relationship between two s. + This class can also represent matrix patterns (such as "T*T******") + which are used for matching instances of DE-9IM matrices. + + DE-9IM matrices are 3x3 matrices with integer entries. + The matrix indices {0,1,2} + represent the topological locations + that occur in a geometry(Interior, Boundary, Exterior). + These are provided by the constants + , , and . + + When used to specify the topological relationship between two geometries, + the matrix entries represent the possible dimensions of each intersection: + = 2, = 1, = 0 and = -1.
+ When used to represent a matrix pattern entries can have the additional values + ("T") and ("*"). + + For a description of the DE-9IM and the spatial predicates derived from it, see the following references: + + OGC 99-049 OpenGIS Simple Features Specification for SQL. + + OGC 06-103r4 OpenGIS Implementation Standard for Geographic information - Simple feature access - Part 1: Common architecture, + Section 6.1.15 (which provides some further details on certain predicate specifications). + Wikipedia article on DE-9IM + + + Methods are provided to: + + set and query the elements of the matrix in a convenient fashion + convert to and from the standard string representation(specified in SFS Section 2.1.13.2). + test if a matrix matches a given pattern string. + test if a matrix(possibly with geometry dimensions) matches a standard named spatial predicate + +
+
+ + + Internal representation of this . + + + + + Creates an with null location values. + + + + + Creates an with the given dimension + symbols. + + A string of nine dimension symbols in row major order. + + + + Creates an with the same elements as + other. + + An to copy. + + + + Adds one matrix to another. + Addition is defined by taking the maximum dimension value of each position + in the summand matrices. + + The matrix to add. + + + + Tests if the dimension value matches TRUE + (i.e. has value 0, 1, 2 or TRUE). + + A number that can be stored in the IntersectionMatrix. + Possible values are {, , , , , } + true if the dimension value matches + + + + Tests if the dimension value satisfies the dimension symbol. + + + a number that can be stored in the IntersectionMatrix. + Possible values are {True, False, Dontcare, 0, 1, 2}. + + + A character used in the string + representation of an . + Possible values are T, F, * , 0, 1, 2. + + + true if the dimension symbol encompasses the dimension value. + + + + + Tests if each of the actual dimension symbols in a matrix string satisfies the + corresponding required dimension symbol in a pattern string. + + + Nine dimension symbols to validate. + Possible values are T, F, * , 0, 1, 2. + + + Nine dimension symbols to validate + against. Possible values are T, F, * , 0, 1, 2. + + + true if each of the required dimension + symbols encompass the corresponding actual dimension symbol. + + + + + Changes the value of one of this elements. + + + The row of this , + indicating the interior, boundary or exterior of the first + + + The column of this , + indicating the interior, boundary or exterior of the second + + The new value of the element + + + + Changes the elements of this to the + dimension symbols in dimensionSymbols. + + + Nine dimension symbols to which to set this + s elements. Possible values are {T, F, * , 0, 1, 2} + + + + + Changes the specified element to minimumDimensionValue if the element is less. + + + The row of this , + indicating the interior, boundary or exterior of the first . + + + The column of this , + indicating the interior, boundary or exterior of the second . + + + The dimension value with which to compare the + element. The order of dimension values from least to greatest is + True, False, Dontcare, 0, 1, 2. + + + + + If row >= 0 and column >= 0, changes the specified element to minimumDimensionValue + if the element is less. Does nothing if row is smaller to 0 or column is smaller to 0. + + + + + + + + For each element in this , changes the + element to the corresponding minimum dimension symbol if the element is + less. + + + Nine dimension symbols with which to + compare the elements of this . The + order of dimension values from least to greatest is Dontcare, True, False, 0, 1, 2. + + + + + Changes the elements of this to dimensionValue. + + + The dimension value to which to set this + s elements. Possible values True, False, Dontcare, 0, 1, 2}. + + + + + Returns the value of one of this s + elements. + + + The row of this , indicating + the interior, boundary or exterior of the first . + + + The column of this , + indicating the interior, boundary or exterior of the second . + + The dimension value at the given matrix position. + + + + See methods Get(int, int) and Set(int, int, int value) + + + + + Tests if this matrix matches [FF*FF****]. + + + true if the two 's related by + this matrix are disjoint. + + + + + Tests if isDisjoint returns . + + + true if the two 's related by + this matrix intersect. + + + + + Tests if this matrix matches + [FT*******], [F**T*****] or [F***T****]. + + The dimension of the first . + The dimension of the second . + + true if the two + s related by this matrix touch; Returns false + if both s are points. + + + + + Tests whether this geometry crosses the + specified geometry. + + + The crosses predicate has the following equivalent definitions: + + The geometries have some but not all interior points in common. + The DE-9IM Intersection Matrix for the two geometries matches + + [T*T******] (for P/L, P/A, and L/A situations) + [T*****T**] (for L/P, L/A, and A/L situations) + [0********] (for L/L situations) + + + For any other combination of dimensions this predicate returns false. + + The SFS defined this predicate only for P/L, P/A, L/L, and L/A situations. + JTS extends the definition to apply to L/P, A/P and A/L situations as well. + This makes the relation symmetric. + + The dimension of the first . + The dimension of the second . + + true if the two + s related by this matrix cross. + + + + + Tests whether this matrix matches [T*F**F***]. + + true if the first is within the second. + + + + Tests whether this matrix matches [T*****FF*] + + true if the first contains the second. + + + + Tests if this matrix matches + [T*****FF*] + or [*T****FF*] + or [***T**FF*] + or [****T*FF*]. + + true if the first covers the second + + + + Tests if this matrix matches + [T*F**F***] + or [*TF**F***] + or [**FT*F***] + or [**F*TF***]. + + true if the first is covered by the second + + + + Tests whether the argument dimensions are equal and + this matrix matches the pattern [T*F**FFF*]. + + Note: This pattern differs from the one stated in + Simple feature access - Part 1: Common architecture. + That document states the pattern as [TFFFTFFFT]. This would + specify that + two identical POINTs are not equal, which is not desirable behaviour. + The pattern used here has been corrected to compute equality in this situation. + + The dimension of the first . + The dimension of the second . + + true if the two s + related by this matrix are equal; the + s must have the same dimension to be equal. + + + + + Tests if this matrix matches + + [T*T***T**] (for two points or two surfaces) + [1*T***T**] (for two curves) + + + The dimension of the first . + The dimension of the second . + + true if the two + s related by this matrix overlap. For this + function to return true, the s must + be two points, two curves or two surfaces. + + + + + Tests whether this matrix matches the given matrix pattern + + + A pattern containing nine dimension symbols with which to + compare the entries of this matrix.Possible + symbol values are { T, F, * , 0, 1, 2}. + + + true if this + matches the required dimension symbols. + + + + + Transposes this IntersectionMatrix. + + This as a convenience, + + + + Returns a nine-character String representation of this . + + + The nine dimension symbols of this + in row-major order. + + + + + Interface to identify all Geometry subclasses that have a Dimension of + and have components that are s. + + Martin Davis + + + + + + Interface to identify all Geometry subclasses that have a Dimension of + and have components that ar s. + + Martin Davis + + + + + + Models an OGC SFS LinearRing. + + + A LinearRing is a which is both closed and simple. + In other words, + the first and last coordinate in the ring must be equal, + and the ring must not self-intersect. + Either orientation of the ring is allowed. + + A ring must have either 0 or 3 or more points. + The first and last points must be equal (in 2D). + If these conditions are not met, the constructors throw + an
+ A ring with 3 points is invalid, because it is collapsed + and thus has a self-intersection. It is allowed to be constructed + so that it can be represented, and repaired if needed. +
+
+ + + The minimum number of vertices allowed in a valid non-empty ring. + Empty rings with 0 vertices are also valid. + + + + + Constructs a LinearRing with the vertices specified + by the given . + + A sequence points forming a closed and simple linestring, + or null to create the empty geometry. + The factory that creates this LinearRing + If the ring is not closed, or has too few points + + + + + + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + Returns Dimensions.False, since by definition LinearRings do not have a boundary. + + + + + + + + + + Returns the name of this object's interface. + + "LinearRing" + + + > + + + + + + + The actual implementation of the function for LINEARRINGs. + + A reversed geometry + + + + Gets a value indicating if this LINEARRING is oriented + + + + + Initializes a new instance of the class. + + The points used for create this instance. + + For create this is used a standard + with == . + + If the ring is not closed, or has too few points + + + + An enumeration of ring orientation values + + + + + The orientation of the ring's coordinates is counter-clockwise. + + + + + The orientation of the ring's coordinates follows the left-hand-rule, + saying that if you follow the ring in the direction of its coordinates + your left hand will be inside the ring. + + + + + + The orientation of the ring's coordinates is counter-clockwise. + + + + + The orientation of the rings coordinates does not matter. + + + + + The default orientation of the rings coordinates. + Set to + + + + + The orientation of the ring's coordinates is clockwise. + + + + + The orientation of the ring's coordinates follows the right-hand-rule, + saying that if you follow the ring in the direction of its coordinates + your right hand will be inside the ring. + + + + + + The orientation of the ring's coordinates is clockwise. + + + + + Represents a line segment defined by two Coordinates. + Provides methods to compute various geometric properties + and relationships of line segments. + This class is designed to be easily mutable (to the extent of + having its contained points public). + This supports a common pattern of reusing a single LineSegment + object as a way of computing segment properties on the + segments defined by arrays or lists of Coordinates. + + + + + The end-point + + + + + The start-point + + + + + Creates an instance of this class using two coordinates + + The start-point + The end-point + + + + Creates an instance of this class using another instance + + + + + + + + + + + Creates an instance of this class + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gets the minimum X ordinate + + + + + Gets the maximum X ordinate + + + + + Gets the minimum Y ordinate + + + + + Gets the maximum Y ordinate + + + + + Computes the length of the line segment. + + The length of the line segment. + + + + Tests whether the segment is horizontal. + + true if the segment is horizontal. + + + + Tests whether the segment is vertical. + + true if the segment is vertical. + + + + Determines the orientation of a LineSegment relative to this segment. + The concept of orientation is specified as follows: + Given two line segments A and L, + A is to the left of a segment L if A lies wholly in the + closed half-plane lying to the left of L + A is to the right of a segment L if A lies wholly in the + closed half-plane lying to the right of L + otherwise, A has indeterminate orientation relative to L. This + happens if A is collinear with L or if A crosses the line determined by L. + + The LineSegment to compare. + + 1 if seg is to the left of this segment, + -1 if seg is to the right of this segment, + 0 if seg is collinear to or crosses this segment. + + + + + Determines the orientation index of a relative to this segment. + The orientation index is as defined in . + + + + + 1if p is to the left of this segment + -1if p is to the right of this segment + 0if p is collinear with this segment + " + + + + + + Reverses the direction of the line segment. + + + + + Puts the line segment into a normalized form. + This is useful for using line segments in maps and indexes when + topological equality rather than exact equality is desired. + + + + + The angle this segment makes with the x-axis (in radians). + + + + The midpoint of the segment + + + + Computes the distance between this line segment and another one. + + + + + + + Computes the distance between this line segment and a point. + + + + + Computes the perpendicular distance between the (infinite) line defined + by this line segment and a point. + + + + + + + Computes the that lies a given + fraction along the line defined by this segment. + + + A fraction of 0.0 returns the start point of the segment; + A fraction of 1.0 returns the end point of the segment. + If the fraction is < 0.0 or > 1.0 the point returned + will lie before the start or beyond the end of the segment. + + the fraction of the segment length along the line + the point at that distance + + + + Computes the that lies a given + + + A fraction along the line defined by this segment and offset from + the segment by a given distance. + A fraction of 0.0 offsets from the start point of the segment; + A fraction of 1.0 offsets from the end point of the segment. + The computed point is offset to the left of the line if the offset distance is + positive, to the right if negative. + + the fraction of the segment length along the line + the distance the point is offset from the segment + (positive is to the left, negative is to the right) + the point at that distance and offset + if the segment has zero length + + + Computes the Projection Factor for the projection of the point p + onto this LineSegment. The Projection Factor is the constant r + by which the vector for this segment must be multiplied to + equal the vector for the projection of p on the line + defined by this segment. + + The projection factor will lie in the range (-inf, +inf), + or be NaN if the line segment has zero length. + + The point to compute the factor for + The projection factor for the point + + + + Computes the fraction of distance (in [0.0, 1.0]) + that the projection of a point occurs along this line segment. + If the point is beyond either ends of the line segment, + the closest fractional value (0.0 or 1.0) is returned. + + + Essentially, this is the clamped to + the range [0.0, 1.0]. + + the point + the fraction along the line segment the projection of the point occurs + + + + Compute the projection of a point onto the line determined + by this line segment. + Note that the projected point may lie outside the line segment. + If this is the case, the projection factor will lie outside the range [0.0, 1.0]. + + + + + + + Project a line segment onto this line segment and return the resulting + line segment. The returned line segment will be a subset of + the target line line segment. This subset may be null, if + the segments are oriented in such a way that there is no projection. + Note that the returned line may have zero length (i.e. the same endpoints). + This can happen for instance if the lines are perpendicular to one another. + + The line segment to project. + The projected line segment, or null if there is no overlap. + + + + Computes the that is offset from + the segment by a given distance. + The computed segment is offset to the left of the line if the offset distance is + positive, to the right if negative. + + The distance the point is offset from the segment + (positive is to the left, negative is to the right) + A line segment offset by the specified distance + Thrown if the segment has zero length + + + + Computes the closest point on this line segment to another point. + + The point to find the closest point to. + + A Coordinate which is the closest point on the line segment to the point p. + + + + + Computes the closest points on a line segment. + + + + A pair of Coordinates which are the closest points on the line segments. + + + + + Computes the reflection of a point in the line defined + by this line segment. + + The point to reflect + The reflected point + + + + Computes an intersection point between two segments, if there is one. + There may be 0, 1 or many intersection points between two segments. + If there are 0, null is returned. If there is 1 or more, a single one + is returned (chosen at the discretion of the algorithm). If + more information is required about the details of the intersection, + the class should be used. + + A line segment + An intersection point, or null if there is none. + + + + + Computes the intersection point of the lines defined by two segments, if there is one. + + + There may be 0, 1 or an infinite number of intersection points between two lines. + If there is a unique intersection point, it is returned. + Otherwise, null is returned. + If more information is required about the details of the intersection, + the class should be used. + + A line segment defining a straight line + An intersection point, or null if there is none or an infinite number + + + + + Creates a LineString with the same coordinates as this segment + + the geometry factory to use + A LineString with the same geometry as this segment + + + + Returns true if o has the same values for its points. + + A LineSegment with which to do the comparison. + + true if o is a LineSegment + with the same values for the x and y ordinates. + + + + + + + + + + + + + + + + + + + + + Compares this object with the specified object for order. + Uses the standard lexicographic ordering for the points in the LineSegment. + + + The LineSegment with which this LineSegment + is being compared. + + + A negative integer, zero, or a positive integer as this LineSegment + is less than, equal to, or greater than the specified LineSegment. + + + + + Returns true if other is + topologically equal to this LineSegment (e.g. irrespective + of orientation). + + + A LineSegment with which to do the comparison. + + + true if other is a LineSegment + with the same values for the x and y ordinates. + + + + + + + + + + + + Return HashCode. + + + + + Models an OGC-style LineString + + + A LineString consists of a sequence of two or more vertices, + along with all points along the linearly-interpolated curves + (line segments) between each + pair of consecutive vertices. + Consecutive vertices may be equal. + The line segments in the line may intersect each other (in other words, + the LineString may "curl back" in itself and self-intersect. + LineStrings with exactly two identical points are invalid. + A LineString must have either 0 or 2 or more points. + If these conditions are not met, the constructors throw an . + + + + + + Represents an empty LineString. + + + + + The points of this LineString. + + + + + Initializes a new instance of the class. + + + For create this is used a standard + with == . + + The coordinates used for create this . + If too few points are provided + + + + Initializes a new instance of the class. + + + The points of the LineString, or null + to create the empty point. Consecutive points may not be equal. + + + If too few points are provided + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + Returns an array containing the values of all the vertices for + this geometry. + + + If the geometry is a composite, the array will contain all the vertices + for the components, in the order in which the components occur in the geometry. + + In general, the array cannot be assumed to be the actual internal + storage for the vertices. Thus modifying the array + may not modify the geometry itself. + Use the method + (possibly on the components) to modify the underlying data. + If the coordinates are modified, + must be called afterwards. + + + The vertices of this Geometry. + + + + + + + Gets an array of ordinate values + + The ordinate index + An array of ordinate values + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gets + + + + + + + Gets a value indicating the start point of this LINESTRING + + + + + Gets a value indicating the end point of this LINESTRING + + + + + Gets a value indicating if this LINESTRING is closed. + + + + + Gets a value indicating if this LINESTRING forms a ring. + + + + + Returns the name of this object's interface. + + "LineString" + + + + Gets the OGC geometry type + + + + + Returns the length of this LineString + + The length of the polygon. + + + + Returns the boundary, or an empty geometry of appropriate dimension + if this Geometry is empty. + For a discussion of this function, see the OpenGIS Simple + Features Specification. As stated in SFS Section 2.1.13.1, "the boundary + of a Geometry is a set of Geometries of the next lower dimension." + + The closure of the combinatorial boundary of this Geometry. + + + + Creates a whose coordinates are in the reverse order of this objects. + + A with coordinates in the reverse order. + + + + The actual implementation of the function for LINESTRINGs. + + A reversed geometry + + + + Returns true if the given point is a vertex of this LineString. + + The Coordinate to check. + true if pt is one of this LineString's vertices. + + + + + + + + + + + + + + + + + + + + + + + + Performs an operation on the coordinates in this Geometry's s. + + + If the filter reports that a coordinate value has been changed, + will be called automatically. + + The filter to apply + + + + + + + Performs an operation with or on this Geometry and its + subelement Geometrys (if any). + Only GeometryCollections and subclasses + have subelement Geometry's. + + + The filter to apply to this Geometry (and + its children, if it is a GeometryCollection). + + + + + Performs an operation with or on this Geometry and its + component Geometry's. Only GeometryCollections and + Polygons have component Geometry's; for Polygons they are the LinearRings + of the shell and holes. + + The filter to apply to this Geometry. + + + > + + + + Normalizes a LineString. A normalized LineString + has the first point which is not equal to it's reflected point + less than the reflected point. + + + + + + + + + + + + + + + + + + + + + + + + + + + The location of a relative to a + + + + + DE-9IM row index of the interior of the first point and column index of + the interior of the second point. Location value for the interior of a + point. + + int value = 0; + + + + DE-9IM row index of the boundary of the first point and column index of + the boundary of the second point. Location value for the boundary of a + point. + + int value = 1; + + + + DE-9IM row index of the exterior of the first point and column index of + the exterior of the second point. Location value for the exterior of a + point. + + int value = 2; + + + + Used for uninitialized location values. + + int value = 1; + + + + Utility class for enumeration + + + + + Converts the location value to a location symbol, for example, EXTERIOR => 'e'. + + + Either 'e', 'b', 'i' or '-'. + + + + Models a collection of s. + + Any collection of LineStrings is a valid MultiLineString. + + + + + Represents an empty MultiLineString. + + + + + Constructs a MultiLineString. + + + The LineStrings for this MultiLineString, + or null or an empty array to create the empty + point. Elements may be empty LineStrings, + but not nulls. + + + + + + Constructs a MultiLineString. + + + The LineStrings for this MultiLineString, + or null or an empty array to create the empty + point. Elements may be empty LineStrings, + but not nulls. + + + For create this is used a standard + with == . + + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + + + + + + + + + + + + + Returns the name of this object's interface. + + "MultiLineString" + + + + Gets the OGC geometry type + + + + + Gets a value indicating whether this instance is closed. + + true if this instance is closed; otherwise, false. + + + + Creates a in the reverse order to this object. + Both the order of the component LineStrings + and the order of their coordinate sequences are reversed. + + a in the reverse order. + + + + + + > + + + + + + + + + + + + Models a collection of Points. + + + + + Represents an empty MultiPoint. + + + + + Constructs a MultiPoint. + + + The Points for this MultiPoint + , or null or an empty array to create the empty point. + Elements may be empty Points, but not nulls. + + + + + + Constructs a MultiPoint. + + + The Points for this MultiPoint + , or null or an empty array to create the empty point. + Elements may be empty Points, but not nulls. + + + For create this is used a standard + with == . + + + + > + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + + + + + + + + + + + Returns the name of this object's interface. + + "MultiPoint" + + + + Gets the boundary of this geometry. + Zero-dimensional geometries have no boundary by definition, + so an empty GeometryCollection is returned. + + + + + + + + + + + + + + + + + + + Returns the Coordinate at the given position. + + The index of the Coordinate to retrieve, beginning at 0. + + The nth Coordinate. + + + + Basic implementation of MultiPolygon. + + + + + Represents an empty MultiPolygon. + + + + + Constructs a MultiPolygon. + + + The Polygons for this MultiPolygon + , or null or an empty array to create the empty point. + Elements may be empty Polygons, but not null + s. The polygons must conform to the assertions specified in the + OpenGIS Simple Features + Specification for SQL. + + + For create this is used a standard + with == . + + + + + Constructs a MultiPolygon. + + + The Polygons for this MultiPolygon + , or null or an empty array to create the empty point. + Elements may be empty Polygons, but not null + s. The polygons must conform to the assertions specified in the + OpenGIS Simple Features + Specification for SQL. + + + + + > + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + + + + + + + + + + + Returns the name of this object's interface. + + "MultiPolygon" + + + > + + + + + + + + + + + + + + + + + Creates a with every component reversed. + + The order of the components in the collection are not reversed. + An in the reverse order + + + + + + + A bounding container for a which is in the shape of a general octagon. + + + The OctagonalEnvelope of a geometric object + is a geometry which is tight bound along the (up to) four extremal rectilinear parallels + and along the (up to) four extremal diagonal parallels. + Depending on the shape of the contained + geometry, the octagon may be degenerate to any extreme + (e.g. it may be a rectangle, a line, or a point). + + + + + Gets the octagonal envelope of a geometry + + The geometry + The octagonal envelope of the geometry + + + + Creates a new null bounding octagon + + + + + Creates a new null bounding octagon bounding a + + The coordinate to bound + + + + Creates a new null bounding octagon bounding a pair of s + + A coordinate to bound + A coordinate to bound + + + + Creates a new null bounding octagon bounding an + + + + + Creates a new null bounding octagon bounding an + (the copy constructor). + + + + + Creates a new null bounding octagon bounding a + + + + + Gets a value indicating the minimal x-ordinate value + + + + + Gets a value indicating the maximal x-ordinate value + + + + + Gets a value indicating the minimal y-ordinate value + + + + + Gets a value indicating the maximal y-ordinate value + + + + + Gets a value indicating the minimal a value + + + + + Gets a value indicating the maximal a value + + + + + Gets a value indicating the minimal b value + + + + + Gets a value indicating the maximal b value + + + + + Gets a value indicating that this object is null + + + + + Method to expand this to include the provided geometry. + + The geometry + + + + Method to expand this to include the provided coordinate sequence. + + The coordinate sequence + A reference to this octagonal envelope, expanded by + + + + Method to expand this to include the provided OctogonalEnvelope. + + The OctogonalEnvelope + A reference to this octagonal envelope, expanded by + + + + Function to expand this to include the provided coordinate. + + The coordinate + A reference to this octagonal envelope, expanded by + + + + Function to expand this to include the provided envelope. + + The envelope + A reference to this octagonal envelope, expanded by + + + + Function to expand this to include the provided - and ordinates. + + A x-ordinate value + A y-ordinate value + A reference to this octagonal envelope, expanded by and + + + + Gets a value indicating if the extremal values for this octagon are valid. + + true if this object has valid values + + + + Function to test if this octagonal envelope intersects octagonal envelope . + + An octagonal envelope + true if this octagonal envelope intersects octagonal envelope . + + + + Function to test if this octagonal envelope contains coordinate. + + A coordinate + true if this octagonal envelope contains coordinate. + + + + Function to test if this octagonal envelope contains octagonal envelope. + + An octagonal envelope + true if this octagonal envelope contains octagonal envelope. + + + + Function to convert this octagonal envelope into a geometry + + The factory to create the geometry + A geometry + + + + OGC compliant geometry factory + + + + + Creates an instance of this class using the default + values for , + and + . + + + + + Creates an instance of this class using the default + values for , + , + but the specified . + + + + Creates an instance of this class using the default + values for , + but the + specified . + + + + + + + + The is guaranteed to be orientated counter-clockwise. + + + + + + The is guaranteed to be orientated counter-clockwise. + + + + + + The is guaranteed to be orientated counter-clockwise. + + + + + + The is guaranteed to be orientated counter-clockwise. +
The are guaranteed to be orientated clockwise. +
+
+ + + Enumeration of OGC Geometry Types + + + + + Point. + + + + + LineString. + + + + + Polygon. + + + + + MultiPoint. + + + + + MultiLineString. + + + + + MultiPolygon. + + + + + GeometryCollection. + + + + + CircularString + + + + + CompoundCurve + + + + + CurvePolygon + + + + + MultiCurve + + + + + MultiSurface + + + + + Curve + + + + + Surface + + + + + PolyhedralSurface + + + + + TIN + + + + + Identifies the different well-supported components of coordinate values. + + All supported coordinates define values for at least the X and the Y components. + + + The first 16 spatial and 16 measure dimensions may also be accessed this way. + + + + + + The 1st spatial dimension. + + + + + The "X" ordinate. + + + + + The 2nd spatial dimension. + + + + + The "Y" ordinate. + + + + + The 3rd spatial dimension. + + + + + The "Z" ordinate. + + + + + The 4th spatial dimension. + + + + + The 5th spatial dimension. + + + + + The 6th spatial dimension. + + + + + The 7th spatial dimension. + + + + + The 8th spatial dimension. + + + + + The 9th spatial dimension. + + + + + The 10th spatial dimension. + + + + + The 11th spatial dimension. + + + + + The 12th spatial dimension. + + + + + The 13th spatial dimension. + + + + + The 14th spatial dimension. + + + + + The 15th spatial dimension. + + + + + The 16th spatial dimension. + + + + + The 1st measure dimension. + + + + + The "M" ordinate. + + + + + The 2nd measure dimension. + + + + + The 3rd measure dimension. + + + + + The 4th measure dimension. + + + + + The 5th measure dimension. + + + + + The 6th measure dimension. + + + + + The 7th measure dimension. + + + + + The 8th measure dimension. + + + + + The 9th measure dimension. + + + + + The 10th measure dimension. + + + + + The 11th measure dimension. + + + + + The 12th measure dimension. + + + + + The 13th measure dimension. + + + + + The 14th measure dimension. + + + + + The 15th measure dimension. + + + + + The 16th measure dimension. + + + + + Flags for Ordinate values + + + + + No ordinates + + + + + Flag for the x-ordinate + + + + + Flag for the y-ordinate + + + + + Flag for the z-ordinate + + + + + Flag for the m-ordinate + + + + + Flag for both x- and y-ordinate + + + + + Flag for x-, y- and z-ordinate + + + + + Flag for x-, y- and m-ordinate + + + + + Flag for x-, y-, z- and m-ordinate + + + + + Flag for the 1st spatial dimension. + + + + + Flag for the 2nd spatial dimension. + + + + + Flag for the 3rd spatial dimension. + + + + + Flag for the 4th spatial dimension. + + + + + Flag for the 5th spatial dimension. + + + + + Flag for the 6th spatial dimension. + + + + + Flag for the 7th spatial dimension. + + + + + Flag for the 8th spatial dimension. + + + + + Flag for the 9th spatial dimension. + + + + + Flag for the 10th spatial dimension. + + + + + Flag for the 11th spatial dimension. + + + + + Flag for the 12th spatial dimension. + + + + + Flag for the 13th spatial dimension. + + + + + Flag for the 14th spatial dimension. + + + + + Flag for the 15th spatial dimension. + + + + + Flag for the 16th spatial dimension. + + + + + Flags for all spatial ordinates. + + + + + Flag for the 1st measure dimension. + + + + + Flag for the 2nd measure dimension. + + + + + Flag for the 3rd measure dimension. + + + + + Flag for the 4th measure dimension. + + + + + Flag for the 5th measure dimension. + + + + + Flag for the 6th measure dimension. + + + + + Flag for the 7th measure dimension. + + + + + Flag for the 8th measure dimension. + + + + + Flag for the 9th measure dimension. + + + + + Flag for the 10th measure dimension. + + + + + Flag for the 11th measure dimension. + + + + + Flag for the 12th measure dimension. + + + + + Flag for the 13th measure dimension. + + + + + Flag for the 14th measure dimension. + + + + + Flag for the 15th measure dimension. + + + + + Flag for the 16th measure dimension. + + + + + Flags for all non-spatial ordinates. + + + + + Flags for all recognized ordinates. + + + + + Static utility functions for dealing with and dimension + + + + + Translates the -flag to a number of dimensions. + + The ordinates flag + The number of dimensions + + + + Translates the -flag to a number of measures. + + The ordinates flag + The number of measures + + + + Represents a single point. + + A Point is topologically valid if and only if: + + The coordinate which defines it if any) is a valid coordinate + (i.e. does not have an NaN X- or Y-ordinate + + + + + + + Represents an empty Point. + + + + + The Coordinate wrapped by this Point. + + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + + + + + + Initializes a new instance of the class. + + The coordinate used for create this . + + For create this is used a standard + with == . + + + + + Constructs a Point with the given coordinate. + + + Contains the single coordinate on which to base this Point, + or null to create the empty point. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Returns the name of this object's interface. + + "Point" + + + + Gets the OGC geometry type + + + + + Gets the boundary of this geometry. + Zero-dimensional geometries have no boundary by definition, + so an empty GeometryCollection is returned. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + > + + + + + + + The actual implementation of the function for POINTs. + + A reversed geometry + + + + + + + + + + + + + + + + + + + + + + Initializes a new instance of the class. + + The x coordinate. + The y coordinate. + The z coordinate. + /// + For create this is used a standard + with set to . + + + + + Initializes a new instance of the class. + + The x coordinate. + The y coordinate. + /// + For create this is used a standard + with set to . + + + + + + + + + + Represents a polygon with linear edges, which may include holes. + The outer boundary (shell) + and inner boundaries (holes) of the polygon are represented by {@link LinearRing}s. + The boundary rings of the polygon may have any orientation. + Polygons are closed, simple geometries by definition. + + The polygon model conforms to the assertions specified in the + OpenGIS Simple Features + Specification for SQL. + + A Polygon is topologically valid if and only if: + + the coordinates which define it are valid coordinates + the linear rings for the shell and holes are valid + (i.e. are closed and do not self-intersect) + holes touch the shell or another hole at at most one point + (which implies that the rings of the shell and holes must not cross) + the interior of the polygon is connected, + or equivalently no sequence of touching holes + makes the interior of the polygon disconnected + (i.e. effectively split the polygon into two pieces). + + + + + + Represents an empty Polygon. + + + + + The exterior boundary, or null if this Polygon + is the empty point. + + + + + The interior boundaries, if any. + + + + + Initializes a new instance of the class. + + + The outer boundary of the new Polygon, + or null or an empty LinearRing if the empty + point is to be created. + + + The inner boundaries of the new Polygon + , or null or empty LinearRings if the empty + point is to be created. + + + For create this is used a standard + with == . + + + + + Constructs a Polygon with the given exterior boundary and + interior boundaries. + + + The outer boundary of the new Polygon, + or null or an empty LinearRing if the empty + point is to be created. + + + The inner boundaries of the new Polygon + , or null or empty LinearRings if the empty + point is to be created. + + + + + + Gets a value to sort the geometry + + + NOTE:
+ For JTS v1.17 this property's getter has been renamed to getTypeCode(). + In order not to break binary compatibility we did not follow. +
+
+ + + Returns a vertex of this Geometry + (usually, but not necessarily, the first one). + + + The returned coordinate should not be assumed to be an actual Coordinate object used in the internal representation. + + a Coordinate which is a vertex of this Geometry. + null if this Geometry is empty. + + + + + Returns an array containing the values of all the vertices for + this geometry. + + + If the geometry is a composite, the array will contain all the vertices + for the components, in the order in which the components occur in the geometry. + + In general, the array cannot be assumed to be the actual internal + storage for the vertices. Thus modifying the array + may not modify the geometry itself. + Use the method + (possibly on the components) to modify the underlying data. + If the coordinates are modified, + must be called afterwards. + + + The vertices of this Geometry. + + + + + + + Gets an array of ordinate values + + The ordinate index + An array of ordinate values + + + + Returns the count of this Geometrys vertices. The Geometry + s contained by composite Geometrys must be + Geometry's; that is, they must implement NumPoints. + + The number of vertices in this Geometry. + + + + Returns the dimension of this geometry. + + + The dimension of a geometry is is the topological + dimension of its embedding in the 2-D Euclidean plane. + In the NTS spatial model, dimension values are in the set {0,1,2}. + + Note that this is a different concept to the dimension of + the vertex s. + The geometry dimension can never be greater than the coordinate dimension. + For example, a 0-dimensional geometry (e.g. a Point) + may have a coordinate dimension of 3 (X,Y,Z). + + + + The topological dimensions of this geometry + + + + + Returns the dimension of this Geometrys inherent boundary. + + + The dimension of the boundary of the class implementing this + interface, whether or not this object is the empty point. Returns + Dimension.False if the boundary is the empty point. + + NOTE: make abstract and remove setter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Returns the name of this object's interface. + + "Polygon" + + + + + + + Returns the area of this Polygon + + + + + + Returns the perimeter of this Polygon. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tests whether this is a rectangular . + + true if the geometry is a rectangle. + + + + + + + The actual implementation of the function for POLYGONs + + A reversed geometry + + + + Constructs a Polygon with the given exterior boundary. + + + The outer boundary of the new Polygon, + or null or an empty LinearRing if the empty + polygon is to be created. + + + + + + Constructs a Polygon with the given exterior boundary. + + + The outer boundary of the new Polygon, + or null or an empty LinearRing if the empty + polygon is to be created. + + + + + + + + + + + + + + + Indicates the position of a location relative to a + node or edge component of a planar topological structure. + + + + + Specifies that a location is on a component + + 0 + + + + Specifies that a location is to the left of a component + + 1 + + + + Specifies that a location is to the right of a component + + 2 + + + + Specifies that a location is is parallel to x-axis of a component + + -1 + + + + Creates a new position index + + A position index + + + + Gets a value indicating the position index + + + + + Returns if the position is , + if the position is , or the position + otherwise. + + + + + Equality comparer for indices + + The position index on the left-hand-side + The position index on the right-hand-side + true if both indices are equal. + + + + Inequality comparer for indices + + The position index on the left-hand-side + The position index on the right-hand-side + true if both indices are not equal. + + + + Implicit conversion operator for to conversion. + + The position index + + + + Specifies the precision model of the Coordinates in a Geometry. + In other words, specifies the grid of allowable points for a Geometry. + A precision model may befloating ( or ), + in which case normal floating-point value semantics apply. + + + For a precision model the + method allows rounding a + coordinate to a "precise" value; that is, one whose precision + is known exactly. + + Coordinates are assumed to be precise in geometries. + That is, the coordinates are assumed to be rounded to the + precision model given for the geometry. + + All internal operations + assume that coordinates are rounded to the precision model. + Constructive methods (such as bool operations) always round computed + coordinates to the appropriate precision model.
+ Three types of precision model are supported: + + FloatingRepresents full double precision floating point. + This is the default precision model used in NTS + FloatingSingleRepresents single precision floating point + FixedRepresents a model with a fixed number of decimal places. + A Fixed Precision Model is specified by a scale factor. + The scale factor specifies the size of the grid which numbers are rounded to. + + Input coordinates are mapped to fixed coordinates according to the following + equations: + + jtsPt.X = Math.Round( inputPt.X * scale, MidPointRounding.AwayFromZero ) / scale ) + jtsPt.Y = Math.Round( inputPt.Y * scale, MidPointRounding.AwayFromZero ) / scale ) + + + For example, to specify 3 decimal places of precision, use a scale factor + of 1000. To specify -3 decimal places of precision (i.e. rounding to + the nearest 1000), use a scale factor of 0.001. + + It is also supported to specify a precise grid size + by providing it as a negative scale factor. + This allows setting a precise grid size rather than using a fractional scale, + which provides more accurate and robust rounding. + For example, to specify rounding to the nearest 1000 use a scale factor of -1000. + + Coordinates are represented internally as Java double-precision values. + .NET uses the IEEE-394 floating point standard, which + provides 53 bits of precision. (Thus the maximum precisely representable + integer is 9,007,199,254,740,992 - or almost 16 decimal digits of precision). +
+
+ + + Determines which of two s is the most precise + + A precision model + A precision model + The PrecisionModel which is most precise + + + + The maximum precise value representable in a double. Since IEE754 + double-precision numbers allow 53 bits of mantissa, the value is equal to + 2^53 - 1. This provides almost 16 decimal digits of precision. + + + + + The type of PrecisionModel this represents. + + + + + The scale factor which determines the number of decimal places in fixed precision. + + + + + If non-zero, the precise grid size specified. + In this case, the scale is also valid and is computed from the grid size. + If zero, the scale is used to compute the grid size where needed. + + + + + Gets a value indicating a precision model with double precision. + + A double precision model + + + + Gets a value indicating a precision model with single precision. + + A single precision model + + + + Gets a value indicating a precision model with a scale of 1. + + A fixed precision model + + + + Creates a PrecisionModel with a default precision + of Floating. + + + + + Creates a PrecisionModel that specifies + an explicit precision model type. + If the model type is Fixed the scale factor will default to 1. + + + The type of the precision model. + + + + + Creates a PrecisionModel that specifies Fixed precision. + Fixed-precision coordinates are represented as precise internal coordinates, + which are rounded to the grid defined by the scale factor. + + The provided scale may be negative, to specify an exact grid size. + The scale is then computed as the reciprocal. + + + Amount by which to multiply a coordinate, to obtain a precise coordinate. + Must be non-zero + + + + + Copy constructor to create a new PrecisionModel + from an existing one. + + + + + + Tests whether the precision model supports floating point. + + true if the precision model supports floating point. + + + + Returns the maximum number of significant digits provided by this + precision model. + Intended for use by routines which need to print out precise values. + + + The maximum number of decimal places provided by this precision model. + + + + + Returns the scale factor used to specify a fixed precision model. + + + The number of decimal places of precision is + equal to the base-10 logarithm of the scale factor. + Non-integral and negative scale factors are supported. + Negative scale factors indicate that the places + of precision is to the left of the decimal point. + + + The scale factor for the fixed precision model + + + + + Computes the grid size for a fixed precision model. + This is equal to the reciprocal of the scale factor. + If the grid size has been set explicity (via a negative scale factor) + it will be returned. + + The grid size at a fixed precision scale. + + + + Gets the type of this PrecisionModel. + + + + + + Rounds a numeric value to the PrecisionModel grid. + Symmetric Arithmetic Rounding is used, to provide + uniform rounding behaviour no matter where the number is + on the number line. + + + This method has no effect on NaN values + + + + + + Rounds a Coordinate to the PrecisionModel grid. + + + + + + + + + + + + + + + + + + > + + + + + + + + + + + + + + + + + + + + + + + + + + + Compares this PrecisionModel object with the specified object for order. + A PrecisionModel is greater than another if it provides greater precision. + The comparison is based on the value returned by the + {getMaximumSignificantDigits) method. + This comparison is not strictly accurate when comparing floating precision models + to fixed models; however, it is correct when both models are either floating or fixed. + + + The PrecisionModel with which this PrecisionModel + is being compared. + + + A negative integer, zero, or a positive integer as this PrecisionModel + is less than, equal to, or greater than the specified PrecisionModel. + + + + + + + + + + + + + + + + + Floating precision corresponds to the standard + double-precision floating-point representation, which is + based on the IEEE-754 standard + + + + + Floating single precision corresponds to the standard + single-precision floating-point representation, which is + based on the IEEE-754 standard + + + + + Fixed Precision indicates that coordinates have a fixed number of decimal places. + The number of decimal places is determined by the log10 of the scale factor. + + + + + A base class containing the logic for computes the contains + and covers spatial relationship predicates + for a relative to all other classes. + Uses short-circuit tests and indexing to improve performance. + + + + Contains and covers are very similar, and differ only in how certain + cases along the boundary are handled. These cases require + full topological evaluation to handle, so all the code in + this class is common to both predicates. + + + It is not possible to short-circuit in all cases, in particular + in the case where line segments of the test geometry touches the polygon linework. + In this case full topology must be computed. + (However, if the test geometry consists of only points, this + can be evaluated in an optimized fashion. + + + Martin Davis + + + + This flag controls a difference between contains and covers. + For contains the value is true. + For covers the value is false. + + + + + Creates an instance of this operation. + + The PreparedPolygon to evaluate + + + + Evaluate the contains or covers relationship + for the given geometry. + + the test geometry + true if the test geometry is contained + + + + Evaluation optimized for Point geometries. + This provides about a 2x performance increase, and less memory usage. + + A Point or MultiPoint geometry + The value of the predicate being evaluated + + + + Tests whether a geometry consists of a single polygon with no holes. + + True if the geometry is a single polygon with no holes + + + + Computes the full topological predicate. + Used when short-circuit tests are not conclusive. + + The test geometry + true if this prepared polygon has the relationship with the test geometry + + + + A base class for subclasses. + + + Contains default implementations for methods, which simply delegate to the equivalent methods. + This class may be used as a "no-op" class for Geometry types which do not have a corresponding implementation. + + Martin Davis + + + + Gets the list of representative points for this geometry. + One vertex is included for every component of the geometry + (i.e. including one for every ring of polygonal geometries). + + Do not modify the returned list! + + + + + Tests whether any representative of the target geometry intersects the test geometry. + This is useful in A/A, A/L, A/P, L/P, and P/P cases. + + The test geometry + true if any component intersects the areal test geometry + + + + Determines whether a Geometry g interacts with this geometry by testing the geometry envelopes. + + A geometry + true if the envelopes intersect + + + + Determines whether the envelope of this geometry covers the Geometry g. + + A geometry + true if g is contained in this envelope + + + + Tests whether the base contains a given geometry. + + The Geometry to test + true if this Geometry contains the given Geometry + + Default implementation. + + + + Tests whether the base properly contains a given geometry. + + The ContainsProperly predicate has the following equivalent definitions: + + Every point of the other geometry is a point of this geometry's interior. + The DE-9IM Intersection Matrix for the two geometries matches >[T**FF*FF*] + + In other words, if the test geometry has any interaction with the boundary of the target + geometry the result of ContainsProperly is false. + This is different semantics to the predicate, + in which test geometries can intersect the target's boundary and still be contained. + + The advantage of using this predicate is that it can be computed + efficiently, since it avoids the need to compute the full topological relationship + of the input boundaries in cases where they intersect. + + An example use case is computing the intersections + of a set of geometries with a large polygonal geometry. + Since intersection is a fairly slow operation, it can be more efficient + to use to filter out test geometries which lie + wholly inside the area. In these cases the intersection is + known a priori to be simply the original test geometry. + + The geometry to test + true if this geometry properly contains the given geometry + + Default implementation. + + + + + Tests whether the base is covered by a given geometry. + + The geometry to test + true if this geometry is covered by the given geometry + + Default implementation. + + + + Tests whether the base covers a given geometry. + + The geometry to test + true if this geometry covers the given geometry + + Default implementation. + + + + Tests whether the base crosses a given geometry. + + The geometry to test + true if this geometry crosses the given geometry + + Default implementation. + + + + Tests whether the base is disjoint from given geometry. + + The geometry to test + true if this geometry is disjoint from the given geometry + + Standard implementation for all geometries. + + + + Tests whether the base intersects a given geometry. + + The geometry to test + true if this geometry intersects the given geometry + + Default implementation. + + + + Tests whether the base overlaps a given geometry. + + The geometry to test + true if this geometry overlaps the given geometry + + Default implementation. + + + + Tests whether the base touches a given geometry. + + The geometry to test + true if this geometry touches the given geometry + + Default implementation. + + + + Tests whether the base is within a given geometry. + + The geometry to test + true if this geometry is within the given geometry + + Default implementation. + + + + + + + An interface for classes which prepare s + in order to optimize the performance of repeated calls to specific geometric operations. + + + + A given implementation may provide optimized implementations + for only some of the specified methods, and delegate the remaining + methods to the original operations. + + + An implementation may also only optimize certain situations, and delegate others. + See the implementing classes for documentation about which methods and situations + they optimize. + + Subclasses are intended to be thread-safe, to allow IPreparedGeometry + to be used in a multi-threaded context + (which allows extracting maximum benefit from the prepared state). + + + Martin Davis + + + + Gets the original which has been prepared. + + + + + Tests whether the base contains a given geometry. + + The Geometry to test + true if this Geometry contains the given Geometry + + + + + Tests whether the base contains a given geometry. + + + + The ContainsProperly predicate has the following equivalent definitions: + + Every point of the other geometry is a point of this geometry's interior. + The DE-9IM Intersection Matrix for the two geometries matches >[T**FF*FF*] + + The advantage to using this predicate is that it can be computed + efficiently, with no need to compute topology at individual points. + + + An example use case for this predicate is computing the intersections + of a set of geometries with a large polygonal geometry. + Since intersection is a fairly slow operation, it can be more efficient + to use containsProperly to filter out test geometries which lie + wholly inside the area. In these cases the intersection + known a priori to be simply the original test geometry. + + + The geometry to test + true if this geometry properly contains the given geometry + + + + Tests whether the base is covered by a given geometry. + + The geometry to test + true if this geometry is covered by the given geometry + + + + + Tests whether the base covers a given geometry. + + The geometry to test + true if this geometry covers the given geometry + + + + + Tests whether the base crosses a given geometry. + + The geometry to test + true if this geometry crosses the given geometry + + + + + Tests whether the base is disjoint from given geometry. + + + This method supports s as input + + The geometry to test + true if this geometry is disjoint from the given geometry + + + + + Tests whether the base intersects a given geometry. + + + This method supports s as input + + The geometry to test + true if this geometry intersects the given geometry + + + + + Tests whether the base overlaps a given geometry. + + The geometry to test + true if this geometry overlaps the given geometry + + + + + Tests whether the base touches a given geometry. + + The geometry to test + true if this geometry touches the given geometry + + + + + Tests whether the base is within a given geometry. + + The geometry to test + true if this geometry is within the given geometry + + + + + A factory for creating s. It chooses an appropriate implementation of PreparedGeometry + based on the geometric type of the input geometry. + + In the future, the factory may accept hints that indicate + special optimizations which can be performed. + + Instances of this class are thread-safe. + + Martin Davis + + + + Creates a new appropriate for the argument . + + The geometry to prepare + + the prepared geometry + + + + + Creates a new appropriate for the argument . + + The geometry to prepare + + the prepared geometry + + + + + A prepared version for geometries. + Instances of this class are thread-safe. + + mbdavis + + + + Computes the intersects spatial relationship predicate + for a target relative to other classes. + + + Uses short-circuit tests and indexing to improve performance. + + Martin Davis + + + + Computes the intersects predicate between a + and a . + + The prepared linestring + A test geometry + true if the linestring intersects the geometry + + + + Creates an instance of this operation. + + The target PreparedLineString + + + + Tests whether this geometry intersects a given geometry. + + The test geometry + true if the test geometry intersects + + + + Tests whether any representative point of the test Geometry intersects + the target geometry. + + + Only handles test geometries which are Puntal (dimension 0) + + A Puntal geometry to test + true if any point of the argument intersects the prepared geometry + + + + A prepared version for geometries. + Instances of this class are thread-safe. + + Martin Davis + + + + Tests whether this point intersects a . + + + The optimization here is that computing topology for the test geometry + is avoided. This can be significant for large geometries. + + + + + A prepared version for geometries. + This class supports both s and s. + This class does not support MultiPolygons which are non-valid + (e.g. with overlapping elements). + + + Instances of this class are thread-safe and immutable. + + mbdavis + + + + Computes the contains spatial relationship predicate for a relative to all other classes. + Uses short-circuit tests and indexing to improve performance. + + + + It is not possible to short-circuit in all cases, in particular + in the case where the test geometry touches the polygon linework. + In this case full topology must be computed. + + + Martin Davis + + + + Computes the contains spatial relationship predicate between a and a . + + The prepared polygon + A test geometry + true if the polygon contains the geometry + + + + Creates an instance of this operation. + + the PreparedPolygon to evaluate + + + + Tests whether this PreparedPolygon contains a given geometry. + + The test geometry + true if the test geometry is contained + + + + Computes the full topological contains predicate.
+ Used when short-circuit tests are not conclusive. +
+ The test geometry + true if this prepared polygon contains the test geometry +
+ + + Computes the containsProperly spatial relationship predicate for s relative to all other {@link Geometry} classes.
+ Uses short-circuit tests and indexing to improve performance. +
+ + + A Geometry A containsProperly another Geometry B if + all points of B are contained in the Interior of A. + Equivalently, B is contained in A AND B does not intersect + the Boundary of A. + + + The advantage to using this predicate is that it can be computed + efficiently, with no need to compute topology at individual points. + In a situation with many geometries intersecting the boundary + of the target geometry, this can make a performance difference. + + + Martin Davis +
+ + Computes the containsProperly predicate between a and a . + + The prepared polygon + A test geometry + true if the polygon properly contains the geometry + + + + Creates an instance of this operation. + + The PreparedPolygon to evaluate + + + + Tests whether this PreparedPolygon containsProperly a given geometry. + + The test geometry + true if the polygon properly contains the geometry + + + + Computes the Covers spatial relationship predicate for a relative to all other classes. + + + Uses short-circuit tests and indexing to improve performance. + + It is not possible to short-circuit in all cases, in particular in the case where the test geometry touches the polygon linework. + In this case full topology must be computed. + + Martin Davis + + + + Computes the Covers spatial relationship predicate for a relative to all other classes. + + The prepared polygon + A test geometry + true if the polygon covers the geometry + + + + Creates an instance of this operation. + + The PreparedPolygon to evaluate + + + + Tests whether this PreparedPolygon covers a given geometry. + + The test geometry + true if the test geometry is covered + + + + Computes the full topological covers predicate. Used when short-circuit tests are not conclusive. + + The test geometry + true if this prepared polygon covers the test geometry + + + + Computes the intersects spatial relationship predicate + for s relative to all other classes. + + Uses short-circuit tests and indexing to improve performance. + Martin Davis + + + + Computes the intersects predicate between a + and a . + + The prepared polygon + A test geometry + true if the polygon intersects the geometry + + + + Creates an instance of this operation. + + The prepared polygon + + + + Tests whether this PreparedPolygon intersects a given geometry. + + The test geometry + true if the test geometry intersects + + + + A base class for predicate operations on s. + + mbdavis + + + + Creates an instance of this operation. + + the PreparedPolygon to evaluate + + + + Tests whether all components of the test Geometry are contained in the target geometry. + + Handles both linear and point components. + A geometry to test + + true if all components of the argument are contained in the target geometry + + + + + Tests whether all components of the test Geometry are contained in the interior of the target geometry. + + Handles both linear and point components. + A geometry to test + true if all components of the argument are contained in the target geometry interior + + + + Tests whether any component of the test Geometry intersects + the area of the target geometry. + Handles test geometries with both linear and point components. + + A geometry to test + true if any component of the argument intersects the prepared area geometry + + + + Tests whether any point of the test Geometry intersects the interior of the target geometry. + + Handles test geometries with both linear and point components. + A geometry to test + true if any point of the argument intersects the prepared area geometry + + + + Tests whether any point of the test Geometry intersects the interior of the target geometry. + + A geometry to test + true if any point of the argument intersects the prepared area geometry interior + + + + Tests whether any component of the test Geometry intersects the interior of the target geometry. + + Handles test geometries with both linear and point components. + A geometry to test + true if any component of the argument intersects the prepared area geometry interior + + + + Tests whether all points of the test Pointal geometry + are contained in the target geometry. + + A geometry to test + true if all points of the argument are contained in the target geometry + + + + Tests whether any component of the target geometry intersects the test geometry (which must be an areal geometry) + + The test geometry + The representative points of the target geometry + true if any component intersects the areal test geometry + + + + Quadrant values + + + The quadants are numbered as follows: + + + 1 - NW | 0 - NE
+ -------+-------
+ 2 - SW | 3 - SE +
+
+
+
+ + + Undefined + + + + + North-East + + + + + North-West + + + + + South-West + + + + + South-East + + + + + Creates a quadrant with t + + + + + + Creates a quadrant of a directed line segment (specified as x and y + displacements, which cannot both be 0). + + + + If the displacements are both 0 + + + + Returns the quadrant of a directed line segment from p0 to p1. + + + + if the points are equal + + + + + + + + + + + + + Returns true if the quadrants are 1 and 3, or 2 and 4. + + A quadrant + + + + Returns the right-hand quadrant of the halfplane defined by the two quadrants, + or -1 if the quadrants are opposite, or the quadrant if they are identical. + + + + + + + Returns whether this quadrant lies within the given halfplane (specified + by its right-hand quadrant). + + + + + + Returns true if the given quadrant is 0 or 1. + + + + + Equality operator for quadrants + + Quadrant value on the left-hand-side + Quadrant value on the right-hand-side + true if quadrant value of and are equal. + + + + Inequality operator for quadrants + + Quadrant value on the left-hand-side + Quadrant value on the right-hand-side + true if quadrant value of and are not equal. + + + + Greater than (>) operator for quadrants + + Quadrant value on the left-hand-side + Quadrant value on the right-hand-side + true if quadrant value of and are not equal. + + + + Less than (<) operator for quadrants + + Quadrant value on the left-hand-side + Quadrant value on the right-hand-side + true if quadrant value of and are not equal. + + + + Indicates an invalid or inconsistent topological situation encountered during processing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Represents a planar triangle, and provides methods for calculating various + properties of triangles. + + + + + A corner point of the triangle + + + + + A corner point of the triangle + + + + + A corner point of the triangle + + + + + Tests whether a triangle is acute. A triangle is acute if all interior + angles are acute. This is a strict test - right triangles will return + false A triangle which is not acute is either right or obtuse. + + Note: this implementation is not robust for angles very close to 90 degrees. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + True if the triangle is acute. + + + + Tests whether a triangle is oriented counter-clockwise. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + true if the triangle orientation is counter-clockwise + + + + Tests whether a triangle intersects a point. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point to test + true if the triangle intersects the point + + + + Computes the line which is the perpendicular bisector of the + + A point + Another point + The perpendicular bisector, as an HCoordinate line segment a-b. + + + Computes the circumcentre of a triangle. + + The circumcentre is the centre of the circumcircle, + the smallest circle which encloses the triangle. + It is also the common intersection point of the + perpendicular bisectors of the sides of the triangle, + and is the only point which has equal distance to all three + vertices of the triangle. + + The circumcentre does not necessarily lie within the triangle. For example, + the circumcentre of an obtuse isosceles triangle lies outside the triangle. + + This method uses an algorithm due to J.R.Shewchuk which uses normalization + to the origin to improve the accuracy of computation. (See Lecture Notes + on Geometric Robustness, Jonathan Richard Shewchuk, 1999). + + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The circumcentre of the triangle + + + + Computes the circumcentre of a triangle. The circumcentre is the centre of + the circumcircle, the smallest circle which encloses the triangle.It is + also the common intersection point of the perpendicular bisectors of the + sides of the triangle, and is the only point which has equal distance to + all three vertices of the triangle. + + The circumcentre does not necessarily lie within the triangle. For example, + the circumcentre of an obtuse isosceles triangle lies outside the triangle. + + This method uses extended-precision arithmetic to + provide more accurate results than + + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The circumcentre of the triangle + + + + Computes the determinant of a 2x2 matrix. Uses standard double-precision + arithmetic, so is susceptible to round-off error. + + the [0,0] entry of the matrix + the [0,1] entry of the matrix + the [1,0] entry of the matrix + the [1,1] entry of the matrix + The determinant + + + + Computes the incentre of a triangle. + + + The InCentre of a triangle is the point which is equidistant + from the sides of the triangle. + It is also the point at which the bisectors of the triangle's angles meet. + It is the centre of the triangle's InCircle, which is the unique circle + that is tangent to each of the triangle's three sides. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point which is the incentre of the triangle + + + Computes the centroid (centre of mass) of a triangle. + + This is also the point at which the triangle's three + medians intersect (a triangle median is the segment from a vertex of the triangle to the + midpoint of the opposite side). + The centroid divides each median in a ratio of 2:1. + The centroid always lies within the triangle. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The centroid of the triangle + + + + Compute the length of the perimeter of a triangle + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The length of the perimeter of the triangle + + + Computes the length of the longest side of a triangle + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The length of the longest side of the triangle + + + Computes the point at which the bisector of the angle ABC cuts the segment AC. + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The angle bisector cut point + + + + Computes the 2D area of a triangle. + The area value is always non-negative. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The area of the triangle + + + + + Computes the signed 2D area of a triangle. + + + + The area value is positive if the triangle is oriented CW, + and negative if it is oriented CCW. + + + The signed area value can be used to determine point orientation, but + the implementation in this method is susceptible to round-off errors. + Use for robust orientation + calculation. + + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The area of the triangle + + + + + + Computes the 3D area of a triangle. + The value computed is always non-negative. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The 3D area of the triangle + + + + Computes the Z-value (elevation) of an XY point + on a three-dimensional plane defined by a triangle + whose vertices have Z-values. + The defining triangle must not be degenerate + (in other words, the triangle must enclose a + non-zero area), + and must not be parallel to the Z-axis. + + This method can be used to interpolate + the Z-value of a point inside a triangle + (for example, of a TIN facet with elevations on the vertices). + + The point to compute the Z-value of + A vertex of a triangle, with a Z ordinate + A vertex of a triangle, with a Z ordinate + A vertex of a triangle, with a Z ordinate + The computed Z-value (elevation) of the point + + + + Creates a new triangle with the given vertices. + + A vertex + A vertex + A vertex + + + + Computes the InCentre of this triangle + + The InCentre of a triangle is the point which is equidistant + from the sides of the triangle. + This is also the point at which the bisectors of the angles meet. + It is the centre of the triangle's InCircle, + which is the unique circle that is tangent to each of the triangle's three sides. + + + The point which is the InCentre of the triangle. + + + + + Tests whether this triangle is acute. A triangle is acute if all interior + angles are acute. This is a strict test - right triangles will return + false A triangle which is not acute is either right or obtuse. + + Note: this implementation is not robust for angles very close to 90 + degrees. + + true if this triangle is acute + + + + Tests whether this triangle is oriented counter-clockwise. + + true if the triangle orientation is counter-clockwise + + + + Computes the circumcentre of this triangle. The circumcentre is the centre + of the circumcircle, the smallest circle which encloses the triangle. It is + also the common intersection point of the perpendicular bisectors of the + sides of the triangle, and is the only point which has equal distance to + all three vertices of the triangle. + + The circumcentre does not necessarily lie within the triangle. + + This method uses an algorithm due to J.R.Shewchuk which uses normalization + to the origin to improve the accuracy of computation. (See Lecture Notes + on Geometric Robustness, Jonathan Richard Shewchuk, 1999). + + The circumcentre of this triangle + + + + Computes the centroid (centre of mass) of this triangle. This is also the + point at which the triangle's three medians intersect (a triangle median is + the segment from a vertex of the triangle to the midpoint of the opposite + side). The centroid divides each median in a ratio of 2:1. + + The centroid always lies within the triangle. + + The centroid of this triangle + + + + Computes the length of the perimeter of this triangle. + + The length of the perimeter + + + + Computes the length of the longest side of this triangle + + The length of the longest side of this triangle + + + + Computes the 2D area of this triangle. The area value is always + non-negative. + + The area of this triangle + + + + + Computes the signed 2D area of this triangle. The area value is positive if + the triangle is oriented CW, and negative if it is oriented CCW. + + The signed area value can be used to determine point orientation, but the + implementation in this method is susceptible to round-off errors. Use + + for robust orientation calculation. + + The signed 2D area of this triangle + + + + + Computes the 3D area of this triangle. The value computed is always + non-negative. + + The 3D area of this triangle + + + + Computes the Z-value (elevation) of an XY point on a three-dimensional + plane defined by this triangle (whose vertices must have Z-values). This + triangle must not be degenerate (in other words, the triangle must enclose + a non-zero area), and must not be parallel to the Z-axis. + + This method can be used to interpolate the Z-value of a point inside this + triangle (for example, of a TIN facet with elevations on the vertices). + + The point to compute the Z-value of + The computed Z-value (elevation) of the point + + + + Represents an affine transformation on the 2D Cartesian plane. + + + + It can be used to transform a or . + An affine transformation is a mapping of the 2D plane into itself + via a series of transformations of the following basic types: +
    +
  • reflection (through a line)
  • +
  • rotation (around the origin)
  • +
  • scaling (relative to the origin)
  • +
  • shearing (in both the X and Y directions)
  • +
  • translation
  • +
+
+ + In general, affine transformations preserve straightness and parallel lines, + but do not preserve distance or shape. + + + An affine transformation can be represented by a 3x3 + matrix in the following form: +
+ T = | m00 m01 m02 |
+ | m10 m11 m12 |
+ | 0 0 1 | +
+ A coordinate P = (x, y) can be transformed to a new coordinate P' = (x', y') + by representing it as a 3x1 matrix and using matrix multiplication to compute: +
+ | x' | = T x | x |
+ | y' | | y |
+ | 1 | | 1 | +
+
+

Transformation Composition

+ + Affine transformations can be composed using the method. + Composition is computed via multiplication of the + transformation matrices, and is defined as: +
+            A.compose(B) = TB x TA
+            
+
+ + This produces a transformation whose effect is that of A followed by B. + The methods , , + , , and + have the effect of composing a transformation of that type with + the transformation they are invoked on. + The composition of transformations is in general not commutative. + +

Transformation Inversion

+ + Affine transformations may be invertible or non-invertible. + If a transformation is invertible, then there exists + an inverse transformation which when composed produces + the identity transformation. + The method + computes the inverse of a transformation, if one exists. + + + @author Martin Davis + +
+
+ + + Creates a transformation for a reflection about the + line (x0,y0) - (x1,y1). + + the x-ordinate of a point on the reflection line + the y-ordinate of a point on the reflection line + the x-ordinate of a another point on the reflection line + the y-ordinate of a another point on the reflection line + a transformation for the reflection + + + + Creates a transformation for a reflection about the + line (0,0) - (x,y). + + the x-ordinate of a point on the reflection line + the y-ordinate of a point on the reflection line + a transformation for the reflection + + + + Creates a transformation for a rotation + about the origin + by an angle theta. + + + Positive angles correspond to a rotation + in the counter-clockwise direction. + + the rotation angle, in radians + a transformation for the rotation + + + + Creates a transformation for a rotation + by an angle theta, + specified by the sine and cosine of the angle. + + + This allows providing exact values for sin(theta) and cos(theta) + for the common case of rotations of multiples of quarter-circles. + + the sine of the rotation angle + the cosine of the rotation angle + a transformation for the rotation + + + + Creates a transformation for a rotation + about the point (x,y) by an angle theta. + + + Positive angles correspond to a rotation + in the counter-clockwise direction. + + the rotation angle, in radians + the x-ordinate of the rotation point + the y-ordinate of the rotation point + a transformation for the rotation + + + + Creates a transformation for a rotation + about the point (x,y) by an angle theta, + specified by the sine and cosine of the angle. + + + This allows providing exact values for sin(theta) and cos(theta) + for the common case of rotations of multiples of quarter-circles. + + the sine of the rotation angle + the cosine of the rotation angle + the x-ordinate of the rotation point + the y-ordinate of the rotation point + a transformation for the rotation + + + + Creates a transformation for a scaling relative to the origin. + + the value to scale by in the x direction + the value to scale by in the y direction + a transformation for the scaling + + + + Creates a transformation for a scaling relative to the point (x,y). + + The value to scale by in the x direction + The value to scale by in the y direction + The x-ordinate of the point to scale around + The y-ordinate of the point to scale around + A transformation for the scaling + + + + Creates a transformation for a shear. + + the value to shear by in the x direction + the value to shear by in the y direction + a transformation for the shear + + + + Creates a transformation for a translation. + + the value to translate by in the x direction + the value to translate by in the y direction + a transformation for the translation + + + + Constructs a new identity transformation + + + + + Constructs a new transformation whose + matrix has the specified values. + + an array containing the 6 values { m00, m01, m02, m10, m11, m12 } + if matrix is null + if matrix is too small + + + + Constructs a new transformation whose + matrix has the specified values. + + the entry for the [0, 0] element in the transformation matrix + the entry for the [0, 1] element in the transformation matrix + the entry for the [0, 2] element in the transformation matrix + the entry for the [1, 0] element in the transformation matrix + the entry for the [1, 1] element in the transformation matrix + the entry for the [1, 2] element in the transformation matrix + + + + Constructs a transformation which is + a copy of the given one. + + the transformation to copy + + + + Constructs a transformation + which maps the given source + points into the given destination points. + + source point 0 + source point 1 + source point 2 + the mapped point for source point 0 + the mapped point for source point 1 + the mapped point for source point 2 + + + + Sets this transformation to be the identity transformation. + + + The identity transformation has the matrix: +
+ | 1 0 0 |
+ | 0 1 0 |
+ | 0 0 1 | +
+
+ this transformation, with an updated matrix +
+ + + Sets this transformation's matrix to have the given values. + + the entry for the [0, 0] element in the transformation matrix + the entry for the [0, 1] element in the transformation matrix + the entry for the [0, 2] element in the transformation matrix + the entry for the [1, 0] element in the transformation matrix + the entry for the [1, 1] element in the transformation matrix + the entry for the [1, 2] element in the transformation matrix + this transformation, with an updated matrix + + + + Sets this transformation to be a copy of the given one + + a transformation to copy + this transformation, with an updated matrix + + + + Gets an array containing the entries + of the transformation matrix. + + + Only the 6 non-trivial entries are returned, + in the sequence: +
+            m00, m01, m02, m10, m11, m12
+            
+
+ an array of length 6 +
+ + + Computes the determinant of the transformation matrix. + + + + The determinant is computed as: +
+ | m00 m01 m02 |
+ | m10 m11 m12 | = m00 * m11 - m01 * m10
+ | 0 0 1 | +
+
+ + If the determinant is zero, + the transform is singular (not invertible), + and operations which attempt to compute + an inverse will throw a . + +
+ the determinant of the transformation + + + The determinant of the transformation + +
+ + + Computes the inverse of this transformation, if one + exists. + + + + The inverse is the transformation which when + composed with this one produces the identity + transformation. + A transformation has an inverse if and only if it + is not singular (i.e. its + determinant is non-zero). + Geometrically, an transformation is non-invertible + if it maps the plane to a line or a point. + If no inverse exists this method + will throw a . + + + The matrix of the inverse is equal to the + inverse of the matrix for the transformation. + It is computed as follows: +
+ 1 + inverse(A) = --- x adjoint(A) + det + + + = 1 | m11 -m01 m01*m12-m02*m11 | + --- x | -m10 m00 -m00*m12+m10*m02 | + det | 0 0 m00*m11-m10*m01 | + + + + = | m11/det -m01/det m01*m12-m02*m11/det | + | -m10/det m00/det -m00*m12+m10*m02/det | + | 0 0 1 | +
+
+
+ A new inverse transformation + + +
+ + + Explicitly computes the math for a reflection. May not work. + + The x-ordinate of one point on the reflection line + The y-ordinate of one point on the reflection line + The x-ordinate of another point on the reflection line + The y-ordinate of another point on the reflection line + This transformation with an updated matrix + + + + Sets this transformation to be a reflection about the line defined by a line (x0,y0) - (x1,y1). + + The x-ordinate of one point on the reflection line + The y-ordinate of one point on the reflection line + The x-ordinate of another point on the reflection line + The y-ordinate of another point on the reflection line + This transformation with an updated matrix + + + + Sets this transformation to be a reflection + about the line defined by vector (x,y). + + + The transformation for a reflection + is computed by: +
+ d = sqrt(x2 + y2) + sin = x / d; + cos = x / d; + Tref = Trot(sin, cos) x Tscale(1, -1) x Trot(-sin, cos) +
+
+ the x-component of the reflection line vector + the y-component of the reflection line vector + this transformation, with an updated matrix +
+ + + Sets this transformation to be a rotation around the orign. + + + A positive rotation angle corresponds + to a counter-clockwise rotation. + The transformation matrix for a rotation + by an angle theta + has the value: +
+            |  cos(theta)  -sin(theta)   0 |
+            |  sin(theta)   cos(theta)   0 |
+            |           0            0   1 |
+            
+
+ the rotation angle, in radians + this transformation, with an updated matrix +
+ + + Sets this transformation to be a rotation around the origin + by specifying the sin and cos of the rotation angle directly. + + + The transformation matrix for the rotation + has the value: +
+            |  cosTheta  -sinTheta   0 |
+            |  sinTheta   cosTheta   0 |
+            |         0          0   1 |
+            
+
+ the sine of the rotation angle + the cosine of the rotation angle + this transformation, with an updated matrix +
+ + + Sets this transformation to be a rotation + around a given point (x,y). + + + A positive rotation angle corresponds + to a counter-clockwise rotation. + The transformation matrix for a rotation + by an angle + has the value: +
+            |  cosTheta  -sinTheta   x-x*cos+y*sin |
+            |  sinTheta   cosTheta   y-x*sin-y*cos |
+            |           0            0   1 |
+            
+
+ the rotation angle, in radians + the x-ordinate of the rotation point + the y-ordinate of the rotation point + this transformation, with an updated matrix +
+ + + Sets this transformation to be a rotation + around a given point (x,y) + by specifying the sin and cos of the rotation angle directly. + + + The transformation matrix for the rotation + has the value: +
+            |  cosTheta  -sinTheta   x-x*cos+y*sin |
+            |  sinTheta   cosTheta   y-x*sin-y*cos |
+            |         0          0         1       |
+            
+
+ the sine of the rotation angle + the cosine of the rotation angle + the x-ordinate of the rotation point + the y-ordinate of the rotation point + this transformation, with an updated matrix +
+ + + Sets this transformation to be a scaling. + + + The transformation matrix for a scale + has the value: +
+            |  xScale      0  dx |
+            |  0      yScale  dy |
+            |  0           0   1 |
+            
+
+ the amount to scale x-ordinates by + the amount to scale y-ordinates by + this transformation, with an updated matrix +
+ + + Sets this transformation to be a shear. + + + The transformation matrix for a shear + has the value: +
+            |  1      xShear  0 |
+            |  yShear      1  0 |
+            |  0           0  1 |
+            
+ Note that a shear of (1, 1) is not + equal to shear(1, 0) composed with shear(0, 1). + Instead, shear(1, 1) corresponds to a mapping onto the + line x = y. +
+ the x component to shear by + the y component to shear by + this transformation, with an updated matrix +
+ + + Sets this transformation to be a translation. + + + For a translation by the vector (x, y) + the transformation matrix has the value: +
+            |  1  0  dx |
+            |  1  0  dy |
+            |  0  0   1 |
+            
+
+ the x component to translate by + the y component to translate by + this transformation, with an updated matrix +
+ + + Updates the value of this transformation + to that of a reflection transformation composed + with the current value. + + the x-ordinate of a point on the line to reflect around + the y-ordinate of a point on the line to reflect around + the x-ordinate of a point on the line to reflect around + the y-ordinate of a point on the line to reflect around + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a reflection transformation composed + with the current value. + + the x-ordinate of the line to reflect around + the y-ordinate of the line to reflect around + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a rotation transformation composed + with the current value. + + + Positive angles correspond to a rotation + in the counter-clockwise direction. + + the angle to rotate by in radians + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a rotation around the origin composed + with the current value, + with the sin and cos of the rotation angle specified directly. + + the sine of the angle to rotate by + the cosine of the angle to rotate by + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a rotation around a given point composed + with the current value. + + + Positive angles correspond to a rotation + in the counter-clockwise direction. + + the angle to rotate by, in radians + the x-ordinate of the rotation point + the y-ordinate of the rotation point + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a rotation around a given point composed + with the current value, + with the sin and cos of the rotation angle specified directly. + + the sine of the angle to rotate by + the cosine of the angle to rotate by + the x-ordinate of the rotation point + the y-ordinate of the rotation point + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a scale transformation composed + with the current value. + + the value to scale by in the x direction + the value to scale by in the y direction + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a shear transformation composed + with the current value. + + the value to shear by in the x direction + the value to shear by in the y direction + this transformation, with an updated matrix + + + + Updates the value of this transformation + to that of a translation transformation composed + with the current value. + + the value to translate by in the x direction + the value to translate by in the y direction + this transformation, with an updated matrix + + + + Updates this transformation to be + the composition of this transformation with the given . + + + This produces a transformation whose effect + is equal to applying this transformation + followed by the argument transformation. + Mathematically, +
+            A.compose(B) = TB x TA
+            
+
+ an affine transformation + this transformation, with an updated matrix +
+ + + Updates this transformation to be the composition + of a given with this transformation. + + + This produces a transformation whose effect + is equal to applying the argument transformation + followed by this transformation. + Mathematically, +
+            A.composeBefore(B) = TA x TB
+            
+
+ an affine transformation + this transformation, with an updated matrix +
+ + + Applies this transformation to the coordinate + and places the results in the coordinate + (which may be the same as the source). + + the coordinate to transform + the coordinate to accept the results + the dest coordinate + + + + + Creates a new which is the result of this transformation applied to the input Geometry. + + A Geometry + The transformed Geometry + + + + Applies this transformation to the i'th coordinate + in the given CoordinateSequence. + + a CoordinateSequence + the index of the coordinate to transform + + + + Transforms the i'th coordinate in the input sequence + + A CoordinateSequence + The index of the coordinate to transform + + + + Reports that this filter should continue to be executed until + all coordinates have been transformed. + + false + + + Tests if this transformation is the identity transformation. + + + + Tests if an object is an AffineTransformation and has the same matrix as this transformation. + + An object to test + true if the given object is equal to this object + + + + + + + Gets a text representation of this transformation. + The string is of the form: + + AffineTransformation[[m00, m01, m02], [m10, m11, m12]] + + + A string representing this transformation + + + + Clones this transformation + + A copy of this transformation + + + + Builds an defined by a set of control vectors. + + + + A control vector consists of a source point and a destination point, + which is the image of the source point under the desired transformation. + + + A transformation is well-defined + by a set of three control vectors + if and only if the source points are not collinear. + (In particular, the degenerate situation + where two or more source points are identical will not produce a well-defined transformation). + A well-defined transformation exists and is unique. + If the control vectors are not well-defined, the system of equations + defining the transformation matrix entries is not solvable, + and no transformation can be determined. + + No such restriction applies to the destination points. + However, if the destination points are collinear or non-unique, + a non-invertible transformations will be generated. + + + This technique of recovering a transformation + from its effect on known points is used in the Bilinear Interpolated Triangulation + algorithm for warping planar surfaces. + + + Martin Davis + + + + Constructs a new builder for the transformation defined by the given set of control point mappings. + + A control point + A control point + A control point + The image of under the required transformation + The image of under the required transformation + The image of under the required transformation + + + + Computes the + determined by the control point mappings, + or null if the control vectors do not determine a well-defined transformation. + + + An affine transformation, or if the control vectors do not + determine a well-defined transformation. + + + + + Computes the transformation matrix by + solving the two systems of linear equations + defined by the control point mappings, + if this is possible. + + True if the transformation matrix is solvable + + + + Solves the transformation matrix system of linear equations + for the given right-hand side vector. + + The vector for the right-hand side of the system + The solution vector, or if no solution could be determined. + + + + Supports creating s defined by various kinds of inputs and transformation mapping rules. + + Martin Davis + + + + Creates a transformation from a set of three control vectors. A control + vector consists of a source point and a destination point, which is the + image of the source point under the desired transformation. Three control + vectors allows defining a fully general affine transformation. + + + + + + + + The computed transformation + + + + Creates an AffineTransformation defined by a pair of control vectors. A + control vector consists of a source point and a destination point, which is + the image of the source point under the desired transformation. The + computed transformation is a combination of one or more of a uniform scale, + a rotation, and a translation (i.e. there is no shear component and no + reflection) + + + + + + The computed transformation + null if the control vectors do not determine a well-defined transformation + + + + Creates an AffineTransformation defined by a single control vector. A + control vector consists of a source point and a destination point, which is + the image of the source point under the desired transformation. This + produces a translation. + + The start point of the control vector + The end point of the control vector + The computed transformation + + + + Creates an AffineTransformation defined by a set of control vectors. + Between one and three vectors must be supplied. + + The source points of the vectors + The destination points of the vectors + The computed transformation + if the control vector arrays are too short, long or of different lengths + + + + Creates an AffineTransformation defined by a mapping between two baselines. + The computed transformation consists of: + + a translation from the start point of the source baseline to the start point of the destination baseline, + a rotation through the angle between the baselines about the destination start point, + and a scaling equal to the ratio of the baseline lengths. + + If the source baseline has zero length, an identity transformation is returned. + + The start point of the source baseline + The end point of the source baseline + The start point of the destination baseline + The end point of the destination baseline + + + + + Extracts a representative + from each connected component of a . + + 1.9 + + + + Extracts a representative + from each connected component in a geometry. + + If more than one geometry is to be processed, it is more + efficient to create a single + instance and pass it to each geometry. + + The Geometry from which to extract + A list of representative Coordinates + + + + Constructs a LineExtracterFilter with a list in which to store LineStrings found. + + + + + Utility to combine just the s of a list of geometries. + + + + + Gets the smallest within which all input geometries fit, or a + null envelope if no non-empty geometries were found in + the input list. + + + The list of input geometries. + + + The smallest within which all input geometries fit, or a + null envelope if no non-empty geometries were found in + the input list. + + + + + Gets the smallest within which all input geometries fit, or a + null envelope if no non-empty geometries were found in + the input list. + + + The list of input geometries. + + + The smallest within which all input geometries fit, or a + null envelope if no non-empty geometries were found in + the input list. + + + + + Initializes a new instance of the class. + + + The instances to combine. + + + + + Initializes a new instance of the class. + + + The instances to combine. + + + + + Gets the smallest within which all input geometries fit, or a + null envelope if no non-empty geometries were found in + the input list. + + + The smallest within which all input geometries fit, or a + null envelope if no non-empty geometries were found in + the input list. + + + + + Maps the members of a + into another GeometryCollection via a defined + mapping function. + + Martin Davis + + + + + + + + + + + + Creates an instance of this class + + + + + + + + + + + + + Combines s to produce a of the most appropriate type. + + + Input geometries which are already collections will have their elements extracted first. + No validation of the result geometry is performed. + (The only case where invalidity is possible is where geometries are combined and result in a self-intersection). + + mbdavis + + + + Combines a collection of geometries. + The geometries to combine + The combined geometry + + + + Combines two geometries. + + A geometry to combine + A geometry to combine + The combined geometry + + + + Combines three geometries. + + A geometry to combine + A geometry to combine + A geometry to combine + The combined geometry + + + + Creates a list from two items + + + + A list from two geometries + + + + Creates a list from three items + + + + + A list from three geometries + + + + Value indicating whether empty geometries should be skipped + + + + + Creates a new combiner for a collection of geometries + + The geometries to combine + + + + Extracts the GeometryFactory used by the geometries in a collection + + + a GeometryFactory + + + + Computes the combination of the input geometries to produce the most appropriate or + + A Geometry which is the combination of the inputs + + + + + A class which supports creating new s + which are modifications of existing ones, + maintaining the same type structure. + + + Geometry objects are intended to be treated as immutable. + This class allows you to "modifies" a Geometrys + by traversing them, applying a user-defined + , or + and creating a new Geometrys with the same structure but + (possibly) modified components. + + Examples of the kinds of modifications which can be made are: + + + The values of the coordinates may be changed. + The editor does not check whether changing coordinate values makes the result Geometry invalid + + + The coordinate lists may be changed (e.g. by adding, deleting or modifying coordinates). + The modified coordinate lists must be consistent with their original parent component + (e.g. a LinearRing must always have at least 4 coordinates, and the first and last + coordinate must be equal). + + + Components of the original point may be deleted + (e.g. holes may be removed from a Polygon, or LineStrings removed from a MultiLineString). + Deletions will be propagated up the component tree appropriately. + + + + All changes must be consistent with the original Geometry's structure + (e.g. a Polygon cannot be collapsed into a LineString). + If changing the structure is required, use a . + + + This class supports creating an edited Geometry + using a different via the + constructor. + Examples of situations where this is required is if the geometry is + transformed to a new SRID and/or a new PrecisionModel. + + Usage notes + + The resulting Geometry is not checked for validity. + If validity needs to be enforced, the new Geometry's + method should be called. + By default the UserData of the input geometry is not copied to the result. + + + + + + + + + The factory used to create the modified Geometry. + + + If null the GeometryFactory of the input is used. + + + + + Creates a new GeometryEditor object which will create + edited with the same as the input Geometry. + + + + + Creates a new GeometryEditor object which will create + edited s with the given . + + The GeometryFactory to create the edited Geometry with. + + + + Gets or sets a value indicating if the User Data is copied to the edit result. + If so, only the object reference is copied. + + + + + Edit the input Geometry with the given edit operation. + Clients can create subclasses of GeometryEditorOperation or + CoordinateOperation to perform required modifications. + + The Geometry to edit. + The edit operation to carry out. + A new Geometry which is the result of the editing (which may be empty). + + + + A interface which specifies an edit operation for Geometries. + + + + + Edits a Geometry by returning a new Geometry with a modification. + The returned Geometry may be the input geometry itself. + It may be null if the geometry is to be deleted. + + The Geometry to modify. + + The factory with which to construct the modified Geometry + (may be different to the factory of the input point). + + A new Geometry which is a modification of the input Geometry. + null if the Geometry is to be deleted completely + + + + A GeometryEditorOperation which does not modify + the input geometry. + This can be used for simple changes of + (including PrecisionModel and SRID). + + mbdavis + + + + A GeometryEditorOperation which edits the coordinate list of a Geometry. + Operates on Geometry subclasses which contains a single coordinate list. + + + + + + + + + + + + + Edits the array of Coordinates from a Geometry. + + The coordinate array to operate on. + The point containing the coordinate list. + An edited coordinate array (which may be the same as the input). + + + + A which edits the + of a . + + Operates on Geometry subclasses which contains a single coordinate list. + + + + An edited coordinate sequence (which may be the same as the input) + + + + Extracts the components of a given type from a . + + + + + Extracts the T components from an and adds them to the provided . + + the geometry from which to extract + the list to add the extracted elements to + The geometry type to extract + + + + Extracts the T elements from a single and returns them in a . + + the geometry from which to extract + + + + Extracts the components of geometryType from a + + The geometry from which to extract + Geometry type to extract (null or all white-space means all types) + + + + Extracts the components of geometryType from a + and adds them to the provided + + The geometry from which to extract + Geometry type to extract (null or all white-space means all types) + The list to add the extracted elements to + + + + Extracts the components of type T from a . + + + + + Constructs a filter with a list in which to store the elements found. + + Geometry type to extract (null means all types) + The list to extract into + + + + Y + + + + + + + + + + + Extracts the components of type T from a . + + + + + Constructs a filter with a list in which to store the elements found. + + The list to extract into + + + + Fixes a geometry to be a valid geometry, while preserving as much as + possible of the shape and location of the input. + Validity is determined according to . + + Input geometries are always processed, so even valid inputs may + have some minor alterations.The output is always a new geometry object. +

Semantic Rules

+ + Vertices with non-finite X or Y ordinates are removed (as per ) + Repeated points are reduced to a single point + Empty atomic geometries are valid and are returned unchanged + Empty elements are removed from collections + Point: keep valid coordinate, or EMPTY + LineString: coordinates are fixed + LinearRing: coordinates are feixed, keep valid ring or else convert into LineString + Polygon: transform into a valid polygon, + preserving as much of the extent and vertices as possible. + + Rings are fixed to ensure they are valid + Holes intersection the shell are subtracted from the shell + Holes outside the shell are converted into polygons + + MultiPolygon: each polygon is fixed, + then result made non - overlapping (via union) + GeometryCollection: each element is fixed + Collapsed lines and polygons are handled as follows, + depending on the keepCollapsed setting: + + false: (default) collapses are converted to empty geometries + (and removed if they are elements of collections) + true: collapses are converted to a valid geometry of lower dimension + + +
+ Martin Davis + +
+ + + Fixes a geometry to be valid. + + The geometry to be fixed + The valid fixed geometry + + + + Fixes a geometry to be valid, allowing to set a flag controlling how + single item results from fixed MULTI geometries should be + returned. + + The geometry to be fixed + A flag indicating if MULTI geometries should not + be converted to single instance types if they consist of only one item. + The valid fixed geometry + + + Creates a new instance to fix a given geometry + The geometry to be fixed + + + + Gets or sets a value indicating whether collapsed + geometries are converted to empty, + (which will be removed from collections), + or to a valid geometry of lower dimension. + The default is to convert collapses to empty geometries (false). + + + + + Gets or sets a value indicating whether collapsed + geometries are converted to empty, + (which will be removed from collections), + or to a valid geometry of lower dimension. + The default is to convert collapses to empty geometries (false). + + + + + Gets the fixed geometry. + + The fixed geometry + + + + Returns a clean copy of the input coordinate array. + + Coordinates to clean + An array of clean coordinates + + + Subtracts a list of polygonal geometries from a polygonal geometry. + polygonal geometry for shell + polygonal geometries for holes + The result geometry + + + + Unions a list of polygonal geometries. + Optimizes case of zero or one input geometries. + Requires that the inputs are net new objects. + + The polygonal geometries to union + The union of the inputs + + + + Methods to map various collections + of s + via defined mapping functions. + + Martin Davis + + + + Maps the members of a + (which may be atomic or composite) + into another Geometry of most specific type. + null results are skipped. + In the case of hierarchical s, + only the first level of members are mapped. + + The input atomic or composite geometry + The mapping operation delegate + A result collection or geometry of most specific type + + + + Maps the members of a + (which may be atomic or composite) + into another Geometry of most specific type. + null results are skipped. + In the case of hierarchical s, + only the first level of members are mapped. + + The input atomic or composite geometry + The mapping operation + A result collection or geometry of most specific type + + + + Maps the atomic elements of a + (which may be atomic or composite) + using a mapping operation + into an atomic Geometry or a flat collection + of the most specific type. + null and empty values returned from the mapping operation + are discarded. + + The geometry to map + The dimension of empy geometry to create + The mapping operation + The mapped result + + + + An interface for geometry functions used for mapping. + + Martin Davis + + + + Computes a new geometry value. + + The input geometry + A result geometry + + + + Standard implementation of a geometry mapping + + + + + Creates an instance of this class using the provided mapping operation function + + A mapping operation function + + + + Computes a new geometry value. + + The input geometry + A result geometry + + + + A framework for processes which transform an input Geometry into + an output , possibly changing its structure and type(s). + + + + This class is a framework for implementing subclasses + which perform transformations on + various different Geometry subclasses. + + + It provides an easy way of applying specific transformations + to given point types, while allowing unhandled types to be simply copied. + Also, the framework handles ensuring that if subcomponents change type + the parent geometries types change appropriately to maintain valid structure. + Subclasses will override whichever TransformX methods + they need to to handle particular Geometry types. + + + A typically usage would be a transformation that may transform Polygons into + Polygons, LineStrings or Points, depending on the geometry of the input + (For instance, a simplification operation). + This class would likely need to override the + method to ensure that if input Polygons change type the result is a GeometryCollection, + not a MultiPolygon. + + The default behaviour of this class is simply to recursively transform + each Geometry component into an identical object by deep copying down + to the level of, but not including, coordinates. + + + Note that all TransformXXX methods may return null, + to avoid creating empty point objects. This will be handled correctly + by the transformer. TransformXXX methods should always return valid + geometry - if they cannot do this they should return null + (for instance, it may not be possible for a transformLineString implementation + to return at least two points - in this case, it should return null). + The method itself will always + return a non-null Geometry object (but this may be empty). + > + + + + The geometry factory + + + + + true if empty geometries should not be included in the result. + + + + + true if a homogenous collection result + from a GeometryCollection should still + be a general GeometryCollection. + + + + + true if the type of the input should be preserved. + + + + + Makes the input geometry available + + + + + + + + + + + + Convenience method which provides standard way of + creating a CoordinateSequence. + + The coordinate array to copy. + A coordinate sequence for the array. + + + + Convenience method which provides a standard way of copying s. + + The sequence to copy. + A deep copy of the sequence. + + + + Transforms a . + This method should always return a valid coordinate list for + the desired result type. (E.g. a coordinate list for a LineString + must have 0 or at least 2 points). + If this is not possible, return an empty sequence - + this will be pruned out. + + The coordinates to transform + The parent geometry + The transformed coordinates + + + + Transforms a geometry. + + The Point to transform + The parent geometry + A Point + + + + Transforms a geometry. + + The MultiPoint to transform + The parent geometry + A MultiPoint + + + + Transforms a . + + The transformation of a LinearRing may result in a coordinate sequence + which does not form a structurally valid ring (i.e. a degenerate ring of 3 or fewer points). + In this case a LineString is returned. + Subclasses may wish to override this method and check for this situation + (e.g.a subclass may choose to eliminate degenerate linear rings) + + The LinearRing to transform + The parent geometry + + A LinearRing if the transformation resulted in a structurally valid ring, otherwise, + if the transformation caused the LinearRing to collapse to 3 or fewer points, a LineString + + + + + Transforms a geometry. + + The LineString to transform + The parent geometry + A LineString + + + + Transforms a geometry. + + The MultiLineString to transform + The parent geometry + A MultiLineString + + + + Transforms a geometry. + + The Polygon to transform + The parent geometry + A Polygon + + + + Transforms a geometry. + + The MultiPolygon to transform + The parent geometry + A MultiPolygon + + + + Transforms a geometry. + + The GeometryCollection to transform + The parent geometry + A GeometryCollection + + + + Extracts all the 1-dimensional () components from a . + For polygonal geometries, this will extract all the component s. + If desired, s can be forced to be returned as s. + + + + + Extracts the linear components from a + and adds them to the provided . + + The geometry from which to extract linear components + The Collection to add the extracted linear components to + The Collection of linear components (LineStrings or LinearRings) + + + + Extracts the linear components from a + and adds them to the provided . + + The geometry from which to extract linear components + The Collection to add the extracted linear components to + + The Collection of linear components (LineStrings or LinearRings) + + + + Extracts the linear components from a single + and adds them to the provided . + + The geometry from which to extract linear components + The Collection to add the extracted linear components to + The Collection of linear components (LineStrings or LinearRings) + + + + Extracts the linear components from a single + and adds them to the provided . + + The geometry from which to extract linear components + The Collection to add the extracted linear components to + + The Collection of linear components (LineStrings or LinearRings) + + + + Extracts the linear components from a single point. + If more than one point is to be processed, it is more + efficient to create a single LineExtracterFilter instance + and pass it to multiple geometries. + + The point from which to extract linear components. + The list of linear components. + + + + Extracts the linear components from a single geometry. + If more than one geometry is to be processed, it is more + efficient to create a single instance + and pass it to multiple geometries. + + The geometry from which to extract linear components + true if s should be converted to s + The list of linear components + + + + Extracts the linear components from a single + and returns them as either a or . + + The geometry from which to extract + A linear geometry + + + + Extracts the linear components from a single + and returns them as either a or . + + The geometry from which to extract + true if s should be converted to s + A linear geometry + + + + Constructs a LineExtracterFilter with a list in which to store LineStrings found. + + + + + + Constructs a LineExtracterFilter with a list in which to store LineStrings found. + + + + + + + + + + + + + + + + + + Extracts all the elements from a . + + + + + + Extracts the elements from a single + and adds them to the. + + The geometry from which to extract + The list to add the extracted elements to + The list argument + + + + Extracts the elements from a single + and returns them in a . + + The geometry from which to extract + A list containing the linear elements + + + + Extracts the elements from a single + and returns them as either a or . + + The geometry from which to extract + A linear geometry + + + + Constructs a filter with a list in which to store the elements found. + + + + + Implements some 2D matrix operations (in particular, solving systems of linear equations). + + Martin Davis + + + + Solves a system of equations using Gaussian Elimination.
+ In order to avoid overhead the algorithm runs in-place + on A - if A should not be modified the client must supply a copy. +
+ A an nxn matrix in row/column order )modified by this method) + A vector of length n + if the matrix is the wrong size + + + A vector containing the solution (if any) + null if the system has no or no unique solution + + +
+ + + Indicates that an is non-invertible. + + Martin Davis + + + + Extracts all the 0-dimensional (Point) components from a Geometry. + + + + + + Extracts the elements from a single and adds them to the provided . + + The geometry from which to extract + The list to add the extracted elements to + + + + + Extracts the elements from a single and returns them in a . + + the geometry from which to extract + + + + Constructs a PointExtracterFilter with a list in which to store Points found. + + + + + + + + + + + + Extracts all the elements from a . + + + + + + Extracts the elements from a single and adds them to the provided . + + The geometry from which to extract + The list to add the extracted elements to + + + + + Extracts the elements from a single and returns them in a . + + The geometry from which to extract + + + + Constructs a PolygonExtracterFilter with a list in which to store Polygons found. + + + + + + + + + + + + A visitor to elements which components, which + allows short-circuiting when a defined condition holds. + + + + + + + + + + + + + + + + + Reports whether visiting components can be terminated. + Once this method returns , it must + continue to return on every subsequent call. + + + if visiting can be terminated. + + + + + Creates geometries which are shaped like multi-armed stars with each arm shaped like a sine wave. + These kinds of geometries are useful as a more complex geometry for testing algorithms. + + + Martin Davis + + + + + Creates a sine star with the given parameters. + + The origin point. + The size of the star. + The number of points in the star. + The number of arms to generate. + The arm length ratio. + A sine star shape. + + + + Creates a factory which will create sine stars using the default + + + + + Creates a factory which will create sine stars using the given + + The factory to use + + + Gets/Sets the number of arms in the star + + + + Gets or sets the ratio of the length of each arm to the radius of the star. + A smaller number makes the arms shorter. + + Value should be between 0.0 and 1.0 + + + + Generates the geometry for the sine star + + The geometry representing the sine star + + + + Builds an array of all visited items. + + + + + Builds an array of all visited items. + + + + + Visits an item. + + The item to visit. + + + + Gets the array of visited items. + + + + + An BinTree (or "Binary Interval Tree") + is a 1-dimensional version of a quadtree. + It indexes 1-dimensional intervals (which may + be the projection of 2-D objects on an axis). + It supports range searching + (where the range may be a single point). + + + + This structure is dynamic - + new items can be added at any time, + and it will support deletion of items + (although this is not currently implemented). + + + This implementation does not require specifying the extent of the inserted + items beforehand. It will automatically expand to accommodate any extent + of dataset. + This index is different to the Interval Tree of Edelsbrunner + or the Segment Tree of Bentley. + + + + + Ensure that the Interval for the inserted item has non-zero extents. + Use the current minExtent to pad it, if necessary. + + + + + + + + + + + + + + + + + + + + Compute the total number of nodes in the tree. + + The number of nodes in the tree. + + + + + + + + + + + Removes a single item from the tree. + + itemEnv the Envelope of the item to be removed + the item to remove + true if the item was found (and thus removed) + + + + + + + + + + + + + + + + + Queries the tree to find all candidate items which + may overlap the query interval. + If the query interval is null, all items in the tree are found. + min and max may be the same value. + + The interval to query for or null + + + + Adds items in the tree which potentially overlap the query interval + to the given collection. + If the query interval is null, add all items in the tree. + + A query interval, or null + The candidate items found + + + + + + + + + + Represents an (1-dimensional) closed interval on the Real number line. + + + + + Gets or sets a value indicating the minimum value of the closed interval. + + + + + Gets or sets a value indicating the maximum value of the closed interval. + + + + + Gets the width of the interval ( - ) + + + + + Gets the centre of the interval ( + * 0.5d) + + + + + Creates a new interval instance, setting ==0d; + + + + + Creates a new interval instance, setting = and =; + + The minimum value + The maximum value + + + + Creates a new interval instance, setting = and =. + + + + + + Method to initialize the interval with the given and values.
+ If < , their values are exchanged. +
+ The minimum value + The maximum value +
+ + + Method to expand this interval to contain . + + The interval to contain. + + + + Function to test if this overlaps . + + The interval to test + true if this interval overlaps + + + + Function to test if this overlaps the interval R[, ]. + + The mimimum value of the interval + The maximum value of the interval + true if this interval overlaps the interval R[, ] + + + + Function to test if this contains . + + This is more rigid than + The interval to test + true if this interval contains + + + + Function to test if this contains the interval R[, ]. + + This is more rigid than + The mimimum value of the interval + The maximum value of the interval + true if this interval contains the interval R[, ] + + + + Function to test if this contains the value . + + The value to test + true if this interval contains the value + + + + A Key is a unique identifier for a node in a tree. + It contains a lower-left point and a level number. The level number + is the power of two for the size of the node envelope. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Return a square envelope containing the argument envelope, + whose extent is a power of two and which is based at a power of 2. + + + + + + + + + + + + + A node of a Bintree. + + + + + Creates a node + + The interval of the node item + A new node + + + + Creates a larger node, that contains both and + If is null, a node for is created. + + The original node + The additional interval + A new node + + + + Creates a new node instance + + The node's interval + The node's level + + + + Gets the node's + + + + + + + + + + + + Returns the subnode containing the envelope. + Creates the node if + it does not already exist. + + + + + + Returns the smallest existing + node containing the envelope. + + + + + + + + + + + + Get the subnode for the index. + If it doesn't exist, create it. + + + + + + + + + + + + The base class for nodes in a Bintree. + + + + + Returns the index of the subnode that wholely contains the given interval. + If none does, returns -1. + + + + + + + + + + + + Subnodes are numbered as follows: + 0 | 1 + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Adds items in the tree which potentially overlap the query interval + to the given collection. + If the query interval is null, add all items in the tree. + + A query interval, or null + The candidate items found + + + + Removes a single item from this subtree. + + The envelope containing the item + The item to remove + true if the item was found and removed + + + + Gets whether this node is prunable + + + + + Gets whether this node has any children + + + + + + + + + + Gets whether this node has any subnodes + + + + + + + + + + + + + + + The root node of a single Bintree. + It is centred at the origin, + and does not have a defined extent. + + + + + Insert an item into the tree this is the root of. + + + + + + + Insert an item which is known to be contained in the tree rooted at + the given Node. Lower levels of the tree will be created + if necessary to hold the item. + + + + + + + + The root node matches all searches. + + + + + + MonotoneChains are a way of partitioning the segments of a linestring to + allow for fast searching of intersections. + + + + They have the following properties: + + the segments within a monotone chain never intersect each other + the envelope of any contiguous subset of the segments in a monotone chain + is equal to the envelope of the endpoints of the subset. + + + + Property 1 means that there is no need to test pairs of segments from within + the same monotone chain for intersection. + Property 2 allows an efficient + binary search to be used to find the intersection points of two monotone chains. + For many types of real-world data, these properties eliminate a large number of + segment comparisons, producing substantial speed gains. + + One of the goals of this implementation of MonotoneChains is to be + as space and time efficient as possible. One design choice that aids this + is that a MonotoneChain is based on a subarray of a list of points. + This means that new arrays of points (potentially very large) do not + have to be allocated. + + MonotoneChains support the following kinds of queries: + + Envelope selectdetermine all the segments in the chain which + intersect a given envelope. + Overlapdetermine all the pairs of segments in two chains whose + envelopes overlap. + + + + This implementation of MonotoneChains uses the concept of internal iterators + ( and ) + to return the resultsets for the above queries. + This has time and space advantages, since it + is not necessary to build lists of instantiated objects to represent the segments + returned by the query. + Queries made in this manner are thread-safe. + + + MonotoneChains support being assigned an integer id value + to provide a total ordering for a set of chains. + This can be used during some kinds of processing to + avoid redundant comparisons + (i.e.by comparing only chains where the first id is less than the second). + + + MonotoneChains support using an tolerance distance for overlap tests. + This allows reporting overlap in situations where + intersection snapping is being used. + If this is used the chain envelope must be computed + providing an expansion distance using . + + + + + + Creates a new MonotoneChain based on the given array of points. + + The points containing the chain + The index of the first coordinate in the chain + The index of the last coordinate in the chain + A user-defined data object + + + + Gets or sets the Id of this chain + + + Useful for assigning an ordering to a set of + chains, which can be used to avoid redundant processing. + + + + + Gets or sets the overlap distance used in overlap tests + with other chains. + + + + + Gets the chain's user-defined context data value. + + + + + Gets the envelope of this chain + + + + + Gets the envelope for this chain, + expanded by a given distance. + + Distance to expand the envelope by + The expanded envelope of the chain + + + + Gets the index of the start of the monotone chain + in the underlying array of points. + + + + + Gets the index of the end of the monotone chain + in the underlying array of points. + + + + + Gets the line segment starting at + + The index of the segment + The line segment to extract to + + + + Return the subsequence of coordinates forming this chain. + Allocates a new array to hold the Coordinates. + + + + + Determine all the line segments in the chain whose envelopes overlap + the searchEnvelope, and process them. + + + The monotone chain search algorithm attempts to optimize + performance by not calling the select action on chain segments + which it can determine are not in the search envelope. + However, it *may* call the select action on segments + which do not intersect the search envelope. + This saves on the overhead of checking envelope intersection + each time, since clients may be able to do this more efficiently. + + The search envelope + The select action to execute on selected segments + + + + + + + + + + + + + Determines the line segments in two chains which may overlap, + and passes them to an overlap action. + + + The monotone chain search algorithm attempts to optimize + performance by not calling the overlap action on chain segments + which it can determine do not overlap. + However, it* may* call the overlap action on segments + which do not actually interact. + This saves on the overhead of checking intersection + each time, since clients may be able to do this more efficiently. + + The chain to compare to + The overlap action to execute on selected segments + + + + Determines the line segments in two chains which may overlap, + using an overlap distance tolerance, + and passes them to an overlap action. + + The chain to compare to + The overlap tolerance distance (may be 0) + The overlap action to execute on selected segments + + + + Uses an efficient mutual binary search strategy + to determine which pairs of chain segments + may overlap, and calls the given overlap action on them. + + The start index of this chain section + The end index of this chain section + The target monotone chain + The start index of the target chain section + The end index of the target chain section + The overlap tolerance distance (may be 0) + The overlap action to execute on selected segments + + + + Tests whether the envelope of a section of the chain + overlaps(intersects) the envelope of a section of another target chain. + This test is efficient due to the monotonicity property + of the sections(i.e.the envelopes can be are determined + from the section endpoints + rather than a full scan). + + The start index of this chain section + The end index of this chain section + The target monotone chain + The start index of the target chain section + The end index of the target chain section + The overlap tolerance distance (may be 0) + true if the section envelopes overlap + + + The 1st coordinate of the 1st segment + The 2nd coordinate of the 1st segment + The 1st coordinate of the 2nd segment + The 2nd coordinate of the 2nd segment + The overlap tolerance distance (may be 0) + + + + Constructs s + for sequences of s. + + + + + Only static methods! + + + + + Computes a list of the s + for a list of coordinates. + + The list of points to compute chains for + A list of the monotone chains for the points + + + + Return a list of the MonotoneChains + for the given list of coordinates. + + The list of points to compute chains for + A data object to attach to each chain + A list of the monotone chains for the points + + + + Return an array containing lists of start/end indexes of the monotone chains + for the given list of coordinates. + The last entry in the array points to the end point of the point array, + for use as a sentinel. + + + + + + Finds the index of the last point in a monotone chain + starting at a given point. + Any repeated points (0-length segments) will be included + in the monotone chain returned. + + The coordinates + The start index + + The index of the last point in the monotone chain starting at start. + + + + + The action for the internal iterator for performing + overlap queries on a MonotoneChain. + + + + + + + + + + + + + + + This function can be overridden if the original chains are needed. + + + The index of the start of the overlapping segment from mc1. + + The index of the start of the overlapping segment from mc2. + + + + This is a convenience function which can be overridden to obtain the actual + line segments which overlap. + + + + + + + The action for the internal iterator for performing + envelope select queries on a MonotoneChain. + + + + + + + + + + This method is overridden to process a segment + in the context of the parent chain. + + The parent chain + The index of the start vertex of the segment being processed + + + + This is a convenience method which can be overridden to obtain the actual + line segment which is selected. + + + + + + A Hilbert-Packed R-tree. This is a static R-tree + which is packed by using the Hilbert ordering + of the tree items. + + The tree is constructed by sorting the items + by the Hilbert code of the midpoint of their envelope. + Then, a set of internal layers is created recursively + as follows: + + The items/nodes of the previous are partitioned into blocks of size nodeCapacity + For each block a layer node is created with range equal to the envelope of the items/nodess in the block + + The internal layers are stored using an array to + store the node bounds. + The link between a node and its children is + stored implicitly in the indexes of the array. + For efficiency, the offsets to the layers + within the node array are pre-computed and stored. + + NOTE: Based on performance testing, + the HPRtree is somewhat faster than the STRtree. + It should also be more memory-efficent, + due to fewer object allocations. + + However, it is not clear whether this + will produce a significant improvement + for use in JTS operations. + + + Martin Davis + + + + Creates a new index with the default node capacity. + + + + + Creates a new index with the given node capacity. + + The node capacity to use + + + Gets the number of items in the index. + The number of items + + + + + + + + + + + + + Tests whether two envelopes intersect. + Avoids the null check in . + An envelope + An envelope + true if the envelopes intersect + + + + Not supported, will always return false + + + + Builds the index, if not already built. + + + + + Computes the number of blocks (nodes) required to + cover a given number of children. + + + + the number of nodes needed to cover the children + + + + Gets the extents of the internal index nodes + + A list of the internal node extents + + + + This property is named Item in JTS + + + + + + + + A visitor for nodes and items in an index. + + + + + + + + + + + A visitor for items in a . + + + + + Visits an item in the index. + + The index item to be visited. + + + + A visitor for items in a + Not used, commited by accident! + + The type of the items in the index + [Obsolete] + + + + Gets a value indicating if no more items need to be visited + + + + + + + + A static index on a set of 1-dimensional intervals, + using an R-Tree packed based on the order of the interval midpoints. + + + It supports range searching, + where the range is an interval of the real line (which may be a single point). + A common use is to index 1-dimensional intervals which + are the projection of 2-D objects onto an axis of the coordinate system. + + This index structure is static + - items cannot be added or removed once the first query has been made. + The advantage of this characteristic is that the index performance + can be optimized based on a fixed set of items. + + Martin Davis + + + + + If root is null that indicates + that the tree has not yet been built, + OR nothing has been added to the tree. + In both cases, the tree is still open for insertions. + + + + + Adds an item to the index which is associated with the given interval + + The lower bound of the item interval + The upper bound of the item interval + The item to insert + if the index has already been queried + + + + Search for intervals in the index which intersect the given closed interval + and apply the visitor to them. + + The lower bound of the query interval + The upper bound of the query interval + The visitor to pass any matched items to + + + + The basic insertion and query operations supported by classes + implementing spatial index algorithms. + A spatial index typically provides a primary filter for range rectangle queries. A + secondary filter is required to test for exact intersection. Of course, this + secondary filter may consist of other tests besides intersection, such as + testing other kinds of spatial relationships. + + + + + Adds a spatial item with an extent specified by the given Envelope to the index. + + + + + Queries the index for all items whose extents intersect the given search Envelope + Note that some kinds of indexes may also return objects which do not in fact + intersect the query envelope. + + The envelope to query for. + A list of the items found by the query. + + + + Queries the index for all items whose extents intersect the given search , + and applies an to them. + Note that some kinds of indexes may also return objects which do not in fact + intersect the query envelope. + + The envelope to query for. + A visitor object to apply to the items found. + + + + Removes a single item from the tree. + + The Envelope of the item to remove. + The item to remove. + true if the item was found. + + + + A visitor for s in a index. + + 1.7 + + + + Visits a node. + + The node to visit + + + + A node of a , which represents one or more points in the same location. + + The type of the object + dskea + + + + Creates a new KdNode. + + coordinate of point + coordinate of point + A data objects to associate with this node + + + + Creates a new KdNode. + + The point location of new node + A data objects to associate with this node + + + + Gets x-ordinate of this node + + The x-ordinate + + + + Gets y-ordinate of this node + + The y-ordinate + + + + Gets the split value at a node, depending on + whether the node splits on X or Y. + The X (or Y) ordinates of all points in the left subtree + are less than the split value, and those + in the right subtree are greater than or equal to the split value. + + A flag whether the node splits a X or Y + The splitting value + + + + Gets the location of this node + + The Coordinate + + + + Gets the user data object associated with this node. + + The user data + + + + Gets or sets the left node of the tree + + The left node + + + + Gets or sets the right node of the tree + + The right node + + + + Gets the number of inserted points that are coincident at this location. + + + + + Gets whether more than one point with this value have been inserted (up to the tolerance) + + + + + + Tests whether the node's left subtree may contain values + in a given range envelope. + + A flag whether the node splits on X or Y + The range envelope + true if the left subtree is in range + + + + Tests whether the node's right subtree may contain values + in a given range envelope. + + A flag whether the node splits on X or Y + The range envelope + trueif the right subtree is in range + + + + Tests whether a point is strictly to the left + of the splitting plane for this node. + If so it may be in the left subtree of this node, + Otherwise, the point may be in the right subtree. + The point is to the left if its X (or Y) ordinate + is less than the split value. + + A flag whether the node splits on X or Y + The query point + true if the point is strictly to the left. + + + + + An implementation of a + KD - Tree + over two dimensions(X and Y). + KD-trees provide fast range searching and fast lookup for point data. + The tree is built dynamically by inserting points. + The tree supports queries by range and for point equality. + For querying an internal stack is used instead of recursion to avoid overflow. + + + This implementation supports detecting and snapping points which are closer + than a given distance tolerance. + If the same point (up to tolerance) is inserted + more than once , it is snapped to the existing node. + In other words, if a point is inserted which lies + within the tolerance of a node already in the index, + it is snapped to that node. + When an inserted point is snapped to a node then a new node is not created + but the count of the existing node is incremented. + If more than one node in the tree is within tolerance of an inserted point, + the closest and then lowest node is snapped to. + + The structure of a KD-Tree depends on the order of insertion of the points. + A tree may become umbalanced if the inserted points are coherent + (e.g.monotonic in one or both dimensions). + A perfectly balanced tree has depth of only log2(N), + but an umbalanced tree may be much deeper. + This has a serious impact on query efficiency. + One solution to this is to randomize the order of points before insertion + (e.g. by using Fisher - Yates shuffling). + + The type of the user data object + David Skea + Martin Davis + + + + Converts a collection of s to an array of s. + + A collection of nodes + An array of the coordinates represented by the nodes + + + + Converts a collection of {@link KdNode}s + to an array of s, + specifying whether repeated nodes should be represented + by multiple coordinates. + + a collection of nodes + true if repeated nodes should + be included multiple times + An array of the coordinates represented by the nodes + + + + Creates a new instance of a KdTree with a snapping tolerance of 0.0. + (I.e. distinct points will not be snapped) + + + + + Creates a new instance of a KdTree with a snapping distance + tolerance. Points which lie closer than the tolerance to a point already + in the tree will be treated as identical to the existing point. + + The tolerance distance for considering two points equal + + + + Tests whether the index contains any items. + + + + + Gets a value indicating the root node of the tree + + The root node of the tree + + + + Inserts a new point in the kd-tree, with no data. + + The point to insert + The kdnode containing the point + + + + Inserts a new point into the kd-tree. + + The point to insert + A data item for the point + + A new KdNode if a new point is inserted, else an existing + node is returned with its counter incremented. This can be checked + by testing returnedNode.getCount() > 1. + + + + + Finds the node in the tree which is the best match for a point + being inserted. + The match is made deterministic by returning the lowest of any nodes which + lie the same distance from the point. + There may be no match if the point is not within the distance tolerance of any + existing node. + + The point being inserted + + + the best matching node + null if no match was found + + + + + + Inserts a point known to be beyond the distance tolerance of any existing node. + The point is inserted at the bottom of the exact splitting path, + so that tree shape is deterministic. + + The point to insert + The data associated with + + + The data for the point + The created node + + + + + + Performs a range search of the points in the index and visits all nodes found. + + The range rectangle to query + A visitor to visit all nodes found by the search + + + + Performs a range search of the points in the index. + + The range rectangle to query + A collection of the KdNodes found + + + + Performs a range search of the points in the index. + + The range rectangle to query + A collection to accumulate the result nodes into + + + + Searches for a given point in the index and returns its node if found. + + the point to query + the point node, if it is found in the index, or if not + + + + Gets a value indicating the depth of the tree + + The depth of the tree + + + + Gets a value indicating the number of items in the tree. + + The number of items in the tree. + + + + Extensions methods for the . + + + + + Performs a nearest neighbor search of the points in the index. + + The KdTree to look for the nearest neighbor + The point to search the nearset neighbor for + + + + DoubleBits manipulates Double numbers + by using bit manipulation and bit-field extraction. + For some operations (such as determining the exponent) + this is more accurate than using mathematical operations + (which suffer from round-off error). + The algorithms and constants in this class + apply only to IEEE-754 double-precision floating point format. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Determines the exponent for the number. + + + + + Determines the exponent for the number. + + + + + + + + + + + + + + + + + + This computes the number of common most-significant bits in the mantissa. + It does not count the hidden bit, which is always 1. + It does not determine whether the numbers have the same exponent - if they do + not, the value computed by this function is meaningless. + + + The number of common most-significant mantissa bits. + + + + A representation of the Double bits formatted for easy readability. + + + + + Provides a test for whether an interval is + so small it should be considered as zero for the purposes of + inserting it into a binary tree. + The reason this check is necessary is that round-off error can + cause the algorithm used to subdivide an interval to fail, by + computing a midpoint value which does not lie strictly between the + endpoints. + + + + + Only static methods! + + + + + This value is chosen to be a few powers of 2 less than the + number of bits available in the double representation (i.e. 53). + This should allow enough extra precision for simple computations to be correct, + at least for comparison purposes. + + + + + Computes whether the interval [min, max] is effectively zero width. + I.e. the width of the interval is so much less than the + location of the interval that the midpoint of the interval cannot be + represented precisely. + + + + + A Key is a unique identifier for a node in a quadtree. + It contains a lower-left point and a level number. The level number + is the power of two for the size of the node envelope. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Return a square envelope containing the argument envelope, + whose extent is a power of two and which is based at a power of 2. + + + + + + + + + + + + + Represents a node of a Quadtree. Nodes contain + items which have a spatial extent corresponding to the node's position + in the quadtree. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Returns the subquad containing the envelope . + Creates the subquad if + it does not already exist. + + The envelope to search for + The subquad containing the search envelope. + + + + Returns the smallest existing + node containing the envelope. + + + + + + + + + + + + Get the subquad for the index. + If it doesn't exist, create it. + + + + + + + + + + + + + Gets a value indicating the level of this node + + The level of this node + + + + The base class for nodes in a Quadtree. + + + + + Gets the index of the subquad that wholly contains the given envelope. + If none does, returns -1. + + The index of the subquad that wholly contains the given envelope
+ or -1 if no subquad wholly contains the envelope
+
+ + + + + + + + subquads are numbered as follows: + 2 | 3 + --+-- + 0 | 1 + + + + + + + + + + + + + + + + + + + + + Removes a single item from this subtree. + + The envelope containing the item. + The item to remove. + true if the item was found and removed. + + + + + + + + + + + + + + Gets a value indicating that this node is empty, i.e. it does not contain an items or sub-nodes. + + + + + Insert items in this into the parameter! + + IList for adding items. + Parameter IList with this items. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A Quadtree is a spatial index structure for efficient range querying + of items bounded by 2D rectangles.
+ s can be indexed by using their s.
+ Any type of object can also be indexed, as long as it has an extent that can be + represented by an . + + This Quadtree index provides a primary filter + for range rectangle queries. The various query methods return a list of + all items which may intersect the query rectangle. Note that + it may thus return items which do not in fact intersect the query rectangle. + A secondary filter is required to test for actual intersection + between the query rectangle and the envelope of each candidate item. + The secondary filter may be performed explicitly, + or it may be provided implicitly by subsequent operations executed on the items + (for instance, if the index query is followed by computing a spatial predicate + between the query geometry and tree items, + the envelope intersection check is performed automatically. + + This implementation does not require specifying the extent of the inserted + items beforehand. It will automatically expand to accommodate any extent + of dataset. + + This data structure is also known as an MX-CIF quadtree + following the terminology usage of Samet and others. +
+
+ + + Ensure that the envelope for the inserted item has non-zero extents. + Use the current minExtent to pad the envelope, if necessary. + + + + + + + minExtent is the minimum envelope extent of all items + inserted into the tree so far. It is used as a heuristic value + to construct non-zero envelopes for features with zero X and/or Y extent. + Start with a non-zero extent, in case the first feature inserted has + a zero extent in both directions. This value may be non-optimal, but + only one feature will be inserted with this value. + + + + + Constructs a Quadtree with zero items. + + + + + Returns the number of levels in the tree. + + + + + Tests whether the index contains any items. + + + + + Returns the number of items in the tree. + + + + + + + + + + + + Removes a single item from the tree. + + The Envelope of the item to be removed. + The item to remove. + true if the item was found (and thus removed). + + + + Queries the tree and returns items which may lie in the given search envelope. + + + Precisely, the items that are returned are all items in the tree + whose envelope may intersect the search Envelope. + Note that some items with non-intersecting envelopes may be returned as well; + the client is responsible for filtering these out. + In most situations there will be many items in the tree which do not + intersect the search envelope and which are not returned - thus + providing improved performance over a simple linear scan. + + The envelope of the desired query area. + A List of items which may intersect the search envelope + + + + Queries the tree and visits items which may lie in the given search envelope. + + + Precisely, the items that are visited are all items in the tree + whose envelope may intersect the search Envelope. + Note that some items with non-intersecting envelopes may be visited as well; + the client is responsible for filtering these out. + In most situations there will be many items in the tree which do not + intersect the search envelope and which are not visited - thus + providing improved performance over a simple linear scan. + + The envelope of the desired query area. + A visitor object which is passed the visited items + + + + Return a list of all items in the Quadtree. + + + + + + + + + + + Gets a value indicating the root node of this QuadTree + + The root node of this QuadTree + + + + Item visitor that specifically excludes a predefined area. + + The type of the items to visit + + + + Initialize with + + + + + > + + + + Get a value indicating the gathered items + + + + + QuadRoot is the root of a single Quadtree. + It is centred at the origin, + and does not have a defined extent. + + + + + Insert an item into the quadtree this is the root of. + + + + + Insert an item which is known to be contained in the tree rooted at + the given QuadNode root. Lower levels of the tree will be created + if necessary to hold the item. + + + + + + + + + + + + A node of an . A node is one of: + + empty + an interior node containing child s + a leaf node containing data items (s). + + A node stores the bounds of its children, and its level within the index tree. + + + + + Constructs an AbstractNode at the given level in the tree + + + 0 if this node is a leaf, 1 if a parent of a leaf, and so on; the + root node will have the highest level. + + + + + Returns either child s, or if this is a leaf node, real data (wrapped + in s). + + + + + Returns a representation of space that encloses this Boundable, + preferably not much bigger than this Boundable's boundary yet fast to + test for intersection with the bounds of other Boundables. The class of + object returned depends on the subclass of AbstractSTRtree. + + + An Envelope (for STRtrees), an Interval (for SIRtrees), or other + object (for other subclasses of AbstractSTRtree). + + + + + Gets the bounds of this node + + + + + Returns 0 if this node is a leaf, 1 if a parent of a leaf, and so on; the + root node will have the highest level. + + + + + Gets the count of the s at this node. + + + + + Tests whether there are any s at this node. + + + + + Adds either an AbstractNode, or if this is a leaf node, a data object + (wrapped in an ItemBoundable). + + The child to add. + + + + Base class for STRtree and SIRtree. STR-packed R-trees are described in: + P. Rigaux, Michel Scholl and Agnes Voisard. Spatial Databases With + Application To GIS. Morgan Kaufmann, San Francisco, 2002. + + This implementation is based on s rather than just s, + because the STR algorithm operates on both nodes and + data, both of which are treated as s. + + + + + + A test for intersection between two bounds, necessary because subclasses + of AbstractSTRtree have different implementations of bounds. + + + + + For STRtrees, the bounds will be Envelopes; + for SIRtrees, Intervals; + for other subclasses of AbstractSTRtree, some other class. + + The bounds of one spatial object. + The bounds of another spatial object. + Whether the two bounds intersect. + + + + Constructs an AbstractSTRtree with the specified maximum number of child + nodes that a node may have. + + + + + + Constructs an AbstractSTRtree with the specified maximum number of child + nodes that a node may have, and the root node + + The maximum number of child nodes in a node + The root node that links to all other nodes in the tree + + + + Constructs an AbstractSTRtree with the specified maximum number of child + nodes that a node may have, and all leaf nodes in the tree + + The maximum number of child nodes in a node + The list of leaf nodes in the tree + + + + Creates parent nodes, grandparent nodes, and so forth up to the root + node, for the data that has been inserted into the tree. Can only be + called once, and thus can be called only after all of the data has been + inserted into the tree. + + + + + + + + + + + + Sorts the childBoundables then divides them into groups of size M, where + M is the node capacity. + + + + + + + Creates the levels higher than the given level. + + The level to build on. + the level of the Boundables, or -1 if the boundables are item + boundables (that is, below level 0). + The root, which may be a ParentNode or a LeafNode. + + + + Gets the root node of the tree. + + + + + Gets the maximum number of child nodes that a node may have. + + + + + Tests whether the index contains any items. + This method does not build the index, + so items can still be inserted after it has been called. + + + + + Gets the number of elements in the tree + + + + + Also builds the tree, if necessary. + + + + + + Gets a tree structure (as a nested list) + corresponding to the structure of the items and nodes in this tree. + The returned Lists contain either Object items, + or Lists which correspond to subtrees of the tree + Subtrees which do not contain any items are not included. + Builds the tree if necessary. + + a List of items and/or Lists + + + + A test for intersection between two bounds, necessary because subclasses + of AbstractSTRtree have different implementations of bounds. + + + + + Removes an item from the tree. + (Builds the tree, if necessary.) + + + + + Gets a value indicating the boundable items that have to be included in the index + + A list of boundable items + + + + A pair of s, whose leaf items + support a distance metric between them. + Used to compute the distance between the members, + and to expand a member relative to the other + in order to produce new branches of the + Branch-and-Bound evaluation tree. + Provides an ordering based on the distance between the members, + which allows building a priority queue by minimum distance. + + Martin Davis + + + + Creates an instance of this class with the given s and the function. + + The first boundable + The second boundable + The item distance function + + + + Gets one of the member s in the pair + (indexed by [0, 1]). + + The index of the member to return (0 or 1) + The chosen member + + + + Computes the maximum distance between any + two items in the pair of nodes. + + the maximum distance between items in the pair + + + + Computes the distance between the s in this pair. + The boundables are either composites or leaves. + If either is composite, the distance is computed as the minimum distance + between the bounds. + If both are leaves, the distance is computed by . + + The distance between the s in this pair. + + + + Gets the minimum possible distance between the Boundables in + this pair. + If the members are both items, this will be the + exact distance between them. + Otherwise, this distance will be a lower bound on + the distances between the items in the members. + + The exact or lower bound distance for this pair + + + + Compares two pairs based on their minimum distances + + + + + Tests if both elements of the pair are leaf nodes + + + + + For a pair which is not a leaf + (i.e. has at least one composite boundable) + computes a list of new pairs + from the expansion of the larger boundable + with distance less than minDistance + and adds them to a priority queue. + + Note that expanded pairs may contain + the same item/node on both sides. + This must be allowed to support distance + functions which have non-zero distances + between the item and itself (non-zero reflexive distance). + + The priority queue to add the new pairs to. + The limit on the distance between added pairs. + + + + The Class BoundablePairDistanceComparator. It implements .Net and is used + as a parameter to sort the BoundablePair list. + + + + The normal order + + + + Instantiates a new boundable pair distance comparator. + + + A value of true puts the lowest record at the head of this queue. + This is the natural order. will get the least element. + + + + + + + + Utility functions for working with s. + + mdavis + + + + Computes the maximum distance between the points defining two envelopes. + This is the distance between the two corners which are farthest apart. + + Note that this is NOT the MinMax distance, which is a tighter bound on + the distance between the points in the envelopes. + + An envelope + An envelope + The maximum distance between the points defining the envelopes + + + + Computes the Min-Max Distance between two s. + It is equal to the minimum of the maximum distances between all pairs of + edge segments from the two envelopes. + This is the tight upper bound on the distance between + geometric items bounded by the envelopes. + + Theoretically this bound can be used in the R-tree nearest-neighbour branch-and-bound search + instead of . + However, little performance improvement is observed in practice. + + An envelope + An envelope + The min-max-distance between the envelopes + + + + Computes the maximum distance between two line segments. + + x-ordinate of first endpoint of segment 1 + y-ordinate of first endpoint of segment 1 + x-ordinate of second endpoint of segment 1 + y-ordinate of second endpoint of segment 1 + x-ordinate of first endpoint of segment 2 + y-ordinate of first endpoint of segment 2 + x-ordinate of second endpoint of segment 2 + y-ordinate of second endpoint of segment 2 + Maximum distance between the segments + + + + An function for + items which are using the method. + + To make this distance function suitable for + using to query a single index tree, + the distance metric is anti-reflexive. + That is, if the two arguments are the same Geometry object, + the distance returned is . + + Martin Davis + + + + Computes the distance between two items, + using the method. + + An item which is a geometry. + An item which is a geometry. + if either item is not a Geometry + The distance between the two items. + + + + A function method which computes the distance + between two s in an . + Used for Nearest Neighbour searches. + + To make a distance function suitable for + querying a single index tree + via , + the function should have a non-zero reflexive distance. + That is, if the two arguments are the same object, + the distance returned should be non-zero. + If it is required that only pairs of distinct items be returned, + the distance function must be anti-reflexive, + and must return for identical arguments. + + Martin Davis + + + + Computes the distance between two items. + + The first item. + The second item. + If the metric is not applicable to the arguments + The distance between and . + + + + A contiguous portion of 1D-space. Used internally by SIRtree. + + + + + + + + + + + + + + + + + + Gets the centre of the interval. + + + + + + + + this + + + + + + + this + + + + + + + + + + + + + + + + + + + + + Boundable wrapper for a non-Boundable spatial object. Used internally by + AbstractSTRtree. + + + + + + + + + + + + The bounds + + + + + The item + + + + + One-dimensional version of an STR-packed R-tree. SIR stands for + "Sort-Interval-Recursive". STR-packed R-trees are described in: + P. Rigaux, Michel Scholl and Agnes Voisard. Spatial Databases With + Application To GIS. Morgan Kaufmann, San Francisco, 2002. + + + + + + + + + + + + + + + + + Constructs an SIRtree with the default (10) node capacity. + + + + + Constructs an SIRtree with the given maximum number of child nodes that + a node may have. + + + + + + + + + + + + Inserts an item having the given bounds into the tree. + + + + + + + + Returns items whose bounds intersect the given value. + + + + + + Returns items whose bounds intersect the given bounds. + + Possibly equal to x2. + Possibly equal to x1. + + + + + + + + + + + + + + + A query-only R-tree created using the Sort-Tile-Recursive (STR) algorithm. + For two-dimensional spatial data. + + The STR packed R-tree is simple to implement and maximizes space + utilization; that is, as many leaves as possible are filled to capacity. + Overlap between nodes is far less than in a basic R-tree. + However, the index is semi-static; once the tree has been built + (which happens automatically upon the first query), items may + not be added.
+ Items may be removed from the tree using . + + Described in: P. Rigaux, Michel Scholl and Agnes Voisard. Spatial Databases With + Application To GIS. Morgan Kaufmann, San Francisco, 2002. + + Note that inserting items into a tree is not thread-safe. + Inserting performed on more than one thread must be synchronized externally. + + Querying a tree is thread-safe. The building phase is done synchronously, + and querying is stateless. +
+
+ + + Constructs an STRtree with the default (10) node capacity. + + + + + Constructs an STRtree with the given maximum number of child nodes that + a node may have. + + The minimum recommended capacity setting is 4. + + + + Constructs an AbstractSTRtree with the specified maximum number of child + nodes that a node may have, and the root node + + The minimum recommended capacity setting is 4 + The maximum number of child nodes in a node + The root node that links to all other nodes in the tree + + + + Constructs an AbstractSTRtree with the specified maximum number of child + nodes that a node may have, and all leaf nodes in the tree + + The minimum recommended capacity setting is 4 + The maximum number of child nodes in a node + The list of leaf nodes in the tree + + + + + + + + + + + + + + + + + + + + + + + + + + Creates the parent level for the given child level. First, orders the items + by the x-values of the midpoints, and groups them into vertical slices. + For each slice, orders the items by the y-values of the midpoints, and + group them into runs of size M (the node capacity). For each run, creates + a new (parent) node. + + + + + + + + + + + + + + + + + + + + + + + + + Must be sorted by the x-value of the envelope midpoints. + + + + + + + + + + + + + + + + + Inserts an item having the given bounds into the tree. + + + + + + + Returns items whose bounds intersect the given envelope. + + + + + + Returns items whose bounds intersect the given envelope. + + + + + + + Removes a single item from the tree. + + The Envelope of the item to remove. + The item to remove. + true if the item was found. + + + + + + + + + + Finds the two nearest items in the tree, + using as the distance metric. + A Branch-and-Bound tree traversal algorithm is used + to provide an efficient search. + + If the tree is empty, the return value is null. + If the tree contains only one item, the return value is a pair containing that item. + If it is required to find only pairs of distinct items, + the function must be anti-reflexive. + + A distance metric applicable to the items in this tree + The pair of the nearest items or null if the tree is empty + + + + Finds the item in this tree which is nearest to the given , + using as the distance metric. + A Branch-and-Bound tree traversal algorithm is used + to provide an efficient search. + + The query does not have to be + contained in the tree, but it does + have to be compatible with the + distance metric. + + The envelope of the query item + The item to find the nearest neighbour of + A distance metric applicable to the items in this tree and the query item + The nearest item in this tree or null if the tree is empty + + + + Finds the two nearest items from this tree + and another tree, + using as the distance metric. + A Branch-and-Bound tree traversal algorithm is used + to provide an efficient search. + The result value is a pair of items, + the first from this tree and the second + from the argument tree. + + Another tree + A distance metric applicable to the items in the trees + The pair of the nearest items, one from each tree or null if no pair of distinct items can be found. + + + + Tests whether some two items from this tree and another tree + lie within a given distance. + is used as the distance metric. + A Branch-and-Bound tree traversal algorithm is used + to provide an efficient search. + + Another tree + A distance metric applicable to the items in the trees + The distance limit for the search + true if there are items within the distance + + + + Performs a withinDistance search on the tree node pairs. + This is a different search algorithm to nearest neighbour. + It can utilize the between + tree nodes to confirm if two internal nodes must + have items closer than the maxDistance, + and short-circuit the search. + + The initial pair containing the tree root nodes + The maximum distance to search for + true if two items lie within the given distance + + + + Finds k items in this tree which are the top k nearest neighbors to the given item, + using itemDist as the distance metric. + A Branch-and-Bound tree traversal algorithm is used + to provide an efficient search. + This method implements the KNN algorithm described in the following paper: + + Roussopoulos, Nick, Stephen Kelley, and Frédéric Vincent. "Nearest neighbor queries." + ACM sigmod record. Vol. 24. No. 2. ACM, 1995. + + The query item does not have to be + contained in the tree, but it does + have to be compatible with the itemDist + distance metric. + + The envelope of the query item + The item to find the nearest neighbour of + A distance metric applicable to the items in this tree and the query item + The K nearest items in kNearestNeighbour + K nearest items in this tree + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ProjectionEvents are ordered first by their x-value, and then by their eventType. + It is important that Insert events are sorted before Delete events, so that + items whose Insert and Delete events occur at the same x-value will be + correctly handled. + + + + + + A sweepline implements a sorted index on a set of intervals. + It is used to compute all overlaps between the interval in the index. + + + + + + + + + + + Because Delete Events have a link to their corresponding Insert event, + it is possible to compute exactly the range of events which must be + compared to a given Insert event object. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Extends the class to allow writing values in the BigEndian format. + + + While extends + adding methods for writing integer values () + and double values () in the BigEndian format, + this implementation overrides methods, such + and and more, + for writing values in the BigEndian format. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The supplied stream. + output is null. + + The stream does not support writing, or the stream is already closed. + + + + Initializes a new instance of the class. + + The supplied stream. + The character encoding. + output or encoding is null. + + The stream does not support writing, or the stream is already closed. + + + + Writes a two-byte signed integer to the current stream using BigEndian encoding + and advances the stream position by two bytes. + + The two-byte signed integer to write. + The stream is closed. + An I/O error occurs. + + + + Writes a two-byte unsigned integer to the current stream using BigEndian encoding + and advances the stream position by two bytes. + + The two-byte unsigned integer to write. + The stream is closed. + An I/O error occurs. + + + + Writes a four-byte signed integer to the current stream using BigEndian encoding + and advances the stream position by four bytes. + + The four-byte signed integer to write. + The stream is closed. + An I/O error occurs. + + + + Writes a four-byte unsigned integer to the current stream using BigEndian encoding + and advances the stream position by four bytes. + + The four-byte unsigned integer to write. + The stream is closed. + An I/O error occurs. + + + + Writes an eight-byte signed integer to the current stream using BigEndian encoding + and advances the stream position by eight bytes. + + The eight-byte signed integer to write. + The stream is closed. + An I/O error occurs. + + + + Writes an eight-byte unsigned integer to the current stream using BigEndian encoding + and advances the stream position by eight bytes. + + The eight-byte unsigned integer to write. + The stream is closed. + An I/O error occurs. + + + + Writes a four-byte floating-point value to the current stream using BigEndian encoding + and advances the stream position by four bytes. + + The four-byte floating-point value to write. + The stream is closed. + An I/O error occurs. + + + + Writes an eight-byte floating-point value to the current stream using BigEndian encoding + and advances the stream position by eight bytes. + + The eight-byte floating-point value to write. + The stream is closed. + An I/O error occurs. + + + + Extends the class to allow reading values in the specified format. + + + While extends + adding methods for reading integer values () + and double values () in the specified format, + this implementation overrides methods, such + and and more, + for reading values in the specified by format. + + + + + Initializes a new instance of the class. + + The stream. + + + + Initializes a new instance of the class. + + The supplied stream. + The byte order. + The stream does not support reading, the stream is null, or the stream is already closed. + + + + Encoding type + + + + + Reads a 2-byte signed integer from the current stream using the specified encoding + and advances the current position of the stream by two bytes. + + + A 2-byte signed integer read from the current stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads a 2-byte unsigned integer from the current stream using the specified encoding + and advances the position of the stream by two bytes. + + + A 2-byte unsigned integer read from this stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads a 4-byte signed integer from the current stream using the specified encoding + and advances the current position of the stream by four bytes. + + + A 4-byte signed integer read from the current stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads a 4-byte unsigned integer from the current stream using the specified encoding + and advances the position of the stream by four bytes. + + + A 4-byte unsigned integer read from this stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads an 8-byte signed integer from the current stream using the specified encoding + and advances the current position of the stream by eight bytes. + + + An 8-byte signed integer read from the current stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads an 8-byte unsigned integer from the current stream using the specified encoding + and advances the position of the stream by eight bytes. + + + An 8-byte unsigned integer read from this stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads a 4-byte floating point value from the current stream using the specified encoding + and advances the current position of the stream by four bytes. + + + A 4-byte floating point value read from the current stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads an 8-byte floating point value from the current stream using the specified encoding + and advances the current position of the stream by eight bytes. + + + An 8-byte floating point value read from the current stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads a string from the current stream. + The string is prefixed with the length, encoded as an integer seven bits at a time. + + The string being read. + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Reads a decimal value from the current stream + and advances the current position of the stream by sixteen bytes. + + + A decimal value read from the current stream. + + The stream is closed. + An I/O error occurs. + The end of the stream is reached. + + + + Byte order + + + + + BigEndian + + + + + LittleEndian + + + + + Lightweight class that handles OGC Geometry type declaration + + + + + Initializes this instance + + The value describing the + + + + Inititalizes this instance based on a geometry and an Ordinates flag. + + The geometry. + The ordinates flag. + + + + Inititalizes this instance based on an + + The OGC geometry type + + + + Inititalizes this instance based on an and an SRID indicator + + The OGC geometry type + Indicator if a SRID is supplied. + + + + Inititalizes this instance based on an and an SRID indicator + + The OGC geometry type + The ordinates flag. + Indicator if a SRID is supplied. + + + + Gets or sets the base geometry type + + + + + Gets the OGC Well-Known-Binary type code + + + + + Gets the PostGIS Enhanced Well-Known-Binary type code + + + + + Gets or sets whether z-ordinate values are stored along with the geometry. + + + + + Gets or sets whether m-ordinate values are stored along with the geometry. + + + + + Gets whether SRID value is stored along with the geometry. + + + + + Gets or sets whether z-ordinate values are stored along with the geometry. + + + + + Gets or sets whether m-ordinate values are stored along with the geometry. + + + + + Gets or sets whether z-ordinates are stored along with the geometry. + PostGis EWKB format. + + + + + Gets or sets whether z-ordinates are stored along with the geometry. + PostGis EWKB format. + + + + + Gets or sets whether z-ordinates are stored along with the geometry. + PostGis EWKB format. + + + + + Reads a GML document and creates a representation of the features based on NetTopologySuite model. + Uses GML 2.1.1 Geometry.xsd schema for base for features. + + + + + builder. + + + + + Initialize reader with a standard . + + + + + Initialize reader with the given . + + + + + Read a GML document and returns relative . + + + + + + + Read a GML document and returns relative . + + + + + + + Reads the coordinate. + + The reader. + + + + + Extract a from a x,y string value. + + + + + + + Extract a from a pos entity string value. + + + + + + + Extract a from a x,y string value. + + + + + Identifies a version of the GML specification. + + + + + Version 2.1.1 (OGC 02-009). + + + + + Version 3.2.2 (OGC 07-036r1 / ISO 19136:2007). + + + + + Writes the GML representation of the features of NetTopologySuite model. + Uses GML 2.1.1 Geometry.xsd schema for base for features. + + Thanks to rstuven for improvements :) + + + + + + Formatter for double values of coordinates + + + + + Initializes a new instance of the class. + + + + + Returns an XmlReader with feature informations. + Use XmlDocument.Load(XmlReader) for obtain a XmlDocument to work. + + + + + + + Writes a GML feature into a generic Stream, such a FileStream or other streams. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sets corrent length for Byte Stream. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Provides the EPSG code exposing the SRID of the geometry + + The SRID of the geometry + + + + + Writes the GML representation of the features of NetTopologySuite model. + Uses GML 3.2.2 gml.xsd schema for base for features. + + + + + Initializes a new instance of the class. + + + + + Constructs objects from the OGC KML representation. + Works only with KML geometry elements and may also parse attributes within these elements + + + + + Creates a reader that creates objects using the default . + + + + + Creates a reader that creates objects using the given . + + The factory used to create Geometrys. + + + + Creates a reader that creates objects using the default . + + Names of attributes that should be parsed (i.e. extrude, altitudeMode, tesselate, etc). + + + + Creates a reader that creates objects using the given . + + The factory used to create Geometrys. + Names of attributes that should be parsed (i.e. extrude, altitudeMode, tesselate, etc). + + + + Reads a KML representation of a from a . + + If any attribute names were specified during {@link KMLReader} construction, + they will be stored as in . + + The string that specifies kml representation of geometry. + A Geometry + Thrown if a parsing problem occurs. + + + + Reads a KML representation of a from a . + + If any attribute names were specified during {@link KMLReader} construction, + they will be stored as in . + + The text stream reader. + A Geometry + Thrown if a parsing problem occurs. + + + + Writes a formatted string containing the KML representation + of a JTS . + The output is KML fragments which can be substituted + wherever the KML abstract + element can be used. + + + Output elements are indented to provide a + nicely-formatted representation. + An output line prefix and maximum + number of coordinates per line can be specified. + + + The Z ordinate value output can be forced to be a specific value. + The and modes can be set. + If set, the corresponding sub-elements will be output. + + + + + The KML standard value clampToGround for use in . + + + + + The KML standard value relativeToGround for use in . + + + + + The KML standard value absolute for use in . + + + + + Writes a Geometry as KML to a string, using + a specified Z value. + + the geometry to write + the Z value to use + a string containing the KML geometry representation + + + + Writes a Geometry as KML to a string, using + a specified Z value, precision, extrude flag, + and altitude mode code. + + the geometry to write + the Z value to use + the maximum number of decimal places to write + the extrude flag to write + the altitude model code to write + a string containing the KML geometry representation + + + + A tag string which is prefixed to every emitted text line. + This can be used to indent the geometry text in a containing document. + + + + + The maximum number of coordinates to output per line. + + + + + The Z value to be output for all coordinates. + This overrides any Z value present in the Geometry coordinates. + + + + + The flag to be output in the extrude element. + + + + + The flag to be output in the tesselate element. + + + + + The value output in the altitudeMode element. + + + + + The maximum number of decimal places to output in ordinate values. + Useful for limiting output size. + + + negative values set the precision to , + like standard behavior. + + + + + Writes a in KML format as a string. + + the geometry to write + a string containing the KML geometry representation + + + + Writes the KML representation of a to a . + + the geometry to write + the writer to write to + + + + Appends the KML representation of a to a . + + the geometry to write + the buffer to write into + + + + Takes a list of coordinates and converts it to KML. + + + 2D and 3D aware. Terminates the coordinate output with a newline. + + + + + Formats numeric values for ordinates + in a consistent, accurate way. + + The format has the following characteristics: + + It is consistent in all locales (in particular, the decimal separator is always a period) + Scientific notation is never output, even for very large numbers. This means that it is possible that output can contain a large number of digits. + The maximum number of decimal places reflects the available precision + NaN values are represented as "NaN" + Inf values are represented as "Inf" or "-Inf" + + + mdavis + + + + The output representation of + + + + + The output representation of + + + + + The output representation of + + + + + The maximum number of fraction digits to support output of reasonable ordinate values. + + The default is chosen to allow representing the smallest possible IEEE-754 double-precision value, + although this is not expected to occur (and is not supported by other areas of the JTS/NTS code). + + + + + The default formatter using the maximum number of digits in the fraction portion of a number. + + + + + Creates an OrdinateFormat using the default maximum number of fraction digits. + + + + + Creates an OrdinateFormat using the given maximum number of fraction digits. + + The maximum number of fraction digits to output + + + + Returns a string representation of the given ordinate numeric value. + + The ordinate value + The formatted number string + + + + Thrown by a WKTReader when a parsing problem occurs. + + + + + Creates a ParseException with the given detail message. + + A description of this ParseException. + + + + Creates a ParseException with es detail message. + + An exception that occurred while a WKTReader was + parsing a Well-known Text string. + + + + Creates a ParseException with s detail message + + + The inner exception + + + + WKB Geometry Types + + + + + Point. + + + + + LineString. + + + + + Polygon. + + + + + MultiPoint. + + + + + MultiLineString. + + + + + MultiPolygon. + + + + + GeometryCollection. + + + + + Point with Z coordinate. + + + + + LineString with Z coordinate. + + + + + Polygon with Z coordinate. + + + + + MultiPoint with Z coordinate. + + + + + MultiLineString with Z coordinate. + + + + + MultiPolygon with Z coordinate. + + + + + GeometryCollection with Z coordinate. + + + + + Point with M ordinate value. + + + + + LineString with M ordinate value. + + + + + Polygon with M ordinate value. + + + + + MultiPoint with M ordinate value. + + + + + MultiLineString with M ordinate value. + + + + + MultiPolygon with M ordinate value. + + + + + GeometryCollection with M ordinate value. + + + + + Point with Z coordinate and M ordinate value. + + + + + LineString with Z coordinate and M ordinate value. + + + + + Polygon with Z coordinate and M ordinate value. + + + + + MultiPoint with Z coordinate and M ordinate value. + + + + + MultiLineString with Z coordinate and M ordinate value. + + + + + MultiPolygon with Z coordinate and M ordinate value. + + + + + GeometryCollection with Z coordinate and M ordinate value. + + + + + Reads a sequence of {@link Geometry}s in WKBHex format + from a text file. + Each WKBHex geometry must be on a single line + The geometries in the file may be separated by any amount + of whitespace and newlines. + + Martin Davis + + + + Creates a new given the + to use to parse the geometries. + + The geometry reader to use + + + + Gets or sets a value indicating the maximum number of geometries to read + + + + + Gets or sets the number of geometries to skip before storing. + + + + + Reads a sequence of geometries.
+ If an is specified, geometries read up to the offset count are skipped. + If a is specified, no more than geometries are read. +
+ The path to the file + Thrown if no filename was specified + Thrown if the filename specified does not exist + Thrown if an I/O exception was encountered + Thrown if an error occurred reading a geometry +
+ + + Reads a sequence of geometries.
+ If an is specified, geometries read up to the offset count are skipped. + If a is specified, no more than geometries are read. +
+ The path to the file + Thrown if no stream was passed + Thrown if passed stream is not readable or seekable + Thrown if an I/O exception was encountered + Thrown if an error occured reading a geometry +
+ + + Reads a sequence of geometries.
+ If an is specified, geometries read up to the offset count are skipped. + If a is specified, no more than geometries are read. +
+ The stream reader to use. + Thrown if an I/O exception was encountered + Thrown if an error occured reading a geometry +
+ + + Tests if reader has reached limit + + A collection of already read geometries + true if number of geometries has been read. + + + + Tests if reader is at EOF. + + + + + Converts a Well-Known Binary byte data to a Geometry. + + + This class reads the format describe in {@link WKBWriter}. + It partially handles theExtended WKB format used by PostGIS, + by parsing and storing optional SRID values. + If a SRID is not specified in an element geometry, it is inherited + from the parent's SRID. + The default SRID value depends on . + + Although not defined in the WKB spec, empty points + are handled if they are represented as a Point with NaN X and Y ordinates. + + The reader repairs structurally-invalid input + (specifically, LineStrings and LinearRings which contain + too few points have vertices added, + and non-closed rings are closed). + + The reader handles most errors caused by malformed or malicious WKB data. + It checks for obviously excessive values of the fields + numElems, numRings, and numCoords. + It also checks that the reader does not read beyond the end of the data supplied. + A is thrown if this situation is detected. + + + + + Converts a hexadecimal string to a byte array. + The hexadecimal digit symbols are case-insensitive. + + A string containing hex digits + An array of bytes with the value of the hex string + + + + Initialize reader with a standard . + + + + + Creates an instance of this class using the provided NtsGeometryServices + + + + + + Reads a in binary WKB format from an array of s. + + The byte array to read from + The geometry read + if the WKB data is ill-formed. + + + + Reads a in binary WKB format from an . + + The stream to read from + The geometry read + if the WKB data is ill-formed. + + + + WKB Coordinate Systems + + + + + 2D coordinate system + + + + + 3D coordinate system + + + + + 2D coordinate system with additional measure value + + + + + 3D coordinate system with additional measure value + + + + + + + + + + + + + + + + + + Function to read a coordinate sequence. + + The reader + The number of ordinates + The coordinate system + The read coordinate sequence. + + + + Function to read a coordinate sequence that is supposed to form a ring. + + The reader + The number of ordinates + The coordinate system + The read coordinate sequence. + + + + Function to read a coordinate sequence that is supposed to serve a line string. + + The reader + The number of ordinates + The coordinate system + The read coordinate sequence. + + + + Function to convert from to + + The coordinate system + The corresponding + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Reads a geometry. + + The reader + The coordinate system + The spatial reference id for the geometry. + A geometry + + + + Gets or sets a value indicating if a possibly encoded SRID value should be handled. + + + + + Gets a value indicating which ordinates can be handled. + + + + + Gets a value indicating which ordinates should be handled. + + + + + Gets or sets a value indicating if the reader should attempt to repair malformed input. + + + Malformed in this case means the ring has too few points (4), + or is not closed. + + + + + Gets or sets whether invalid linear rings should be fixed + + + + + Function to determine whether an ordinate should be handled or not. + + + + + + + Writes a Well-Known Binary byte data representation of a Geometry. + + + There are a few cases which are not specified in the standard. + The implementation uses a representation which is compatible with + other common spatial systems (notably, PostGIS). + + sare written as s. + Empty geometries are output as follows + + PointA WKBPoint with double.NaN ordinate values + LineStringA WKBLineString with zero points + Polygoncurrently output as a WKBPolygon with one LinearRing with zero points. + Note: This is different to other systems. It will change to a WKBPolygon with zero LinearRings. + Multi geometriesA WKBMulti with zero elements + GeometryCollectionA WKBGeometryCollection with zero elements + + + + This implementation supports the Extended WKB standard. + Extended WKB allows writing 3-dimensional coordinates + and the geometry SRID value. + The presence of 3D coordinates is indicated + by setting the high bit of the wkbType word. + The presence of a SRID is indicated + by setting the third bit of the wkbType word. + EWKB format is upward-compatible with the original SFS WKB format. + + SRID output is optimized, if specified. + The top-level geometry has the SRID included. Child geometries + have it included if their value differs from its parent. + + This class supports reuse of a single instance to read multiple + geometries. This class is not thread - safe; each thread should create its own + instance. + + + + Converts a byte array to a hexadecimal string. + A byte array + + + + Writes the WKB Header for the geometry + + The writer + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Gets or sets the binary encoding type + + + + + Standard byte size for each complex point. + Each complex point (LineString, Polygon, ...) contains: + 1 byte for ByteOrder and + 4 bytes for WKBType. + 4 bytes for SRID value + + + + + Calculates the number of bytes required to store (E)WKB Header information. + + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The size of the + + + + Initializes writer with LittleIndian byte order. + + + + + Initializes writer with the specified byte order. + + Encoding type + + + + Initializes writer with the specified byte order. + + Encoding type + SRID values, present or not, should be emitted. + + + + Initializes writer with the specified byte order. + + Encoding type + SRID values, present or not, should be emitted. + Z values, present or not, should be emitted + + + + Initializes writer with the specified byte order. + + Encoding type + SRID values, present or not, should be emitted. + Z values, present or not, should be emitted + M values, present or not, should be emitted + + + + Writes a WKB representation of a given point. + + + + + + + Writes a WKB representation of a given point. + + + + + + + + + + + + + + + + + + + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Writes the ByteOrder defined in . + + The writer to use + + + + Write a . + + The coordinate + The writer. + + + + Write a . + + The coordinate sequence to write + A flag indicating if the size of should be written, too. + The writer. + + + + Write a point in its WKB format + + The point + The writer + + + + Write a point in its WKB format + + The point + The writer + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Write a LineString in its WKB format + + The LineString + The writer + + + + Write a LineString in its WKB format + + The LineString + The writer + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Write LinearRing information + + The linear ring + The writer + + + + Write a Polygon in its WKB format + + The Polygon + The writer + + + + Write a Polygon in its WKB format + + The Polygon + The writer + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Write a MultiPoint in its WKB format + + The MultiPoint + The writer + + + + Write a MultiPoint in its WKB format + + The MultiPoint + The writer + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Write a MultiLineString in its WKB format + + The MultiLineString + The writer + + + + Write a MultiLineString in its WKB format + + The MultiLineString + The writer + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Write a MultiPolygon in its WKB format + + The MultiPolygon + The writer + + + + Write a MultiPolygon in its WKB format + + The MultiPolygon + The writer + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Write a GeometryCollection in its WKB format + + The GeometryCollection + The writer + + + + Write a GeometryCollection in its WKB format + + The GeometryCollection + The writer + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + + + + Gets a buffer for the to write to. + + The geometry to write + A buffer + + + + Gets a buffer for the to write to. + + The geometry to write + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + A buffer + + + + Computes the length of a buffer to write in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + The number of bytes required to store in its WKB format. + + + + Computes the length of a buffer to write the in its WKB format. + + The geometry + + A flag indicting if SRID value is of possible interest. + The value is &&-combineed with HandleSRID. + + The number of bytes required to store in its WKB format. + + + + Gets a value whether or not EWKB featues may be used. + EWKB features are + + 0x80000000 flag if geometry's z-ordinate values are written + 0x40000000 flag if geometry's m-ordinate values are written + 0x20000000 flag if geometry's SRID value is written + + + + + Gets a value indicating if only original WKT elements should be handled + + + + + Gets or sets a value indicating if an encoded SRID value should be handled or ignored. + + + + + Gets the that this class can write. + + + + + Gets or sets the maximum to write out. + The default is equivalent to . + + + + The purpose of this property is to restrict what gets written out to ensure that, + e.g., Z values are never written out even if present on a geometry instance. Ordinates + that are not present on a geometry instance will be omitted regardless of this value. + + + Flags not present in are silently ignored. + + + and are always present. + + + + + + Constants used in the WKT (Well-Known Text) format. + + Martin Davis + + + + Token text for geometries + + + + + Token text for geometries + + + + + Token text for geometries + + + + + Token text for geometries + + + + + Token text for geometries + + + + + Token text for geometries + + + + + Token text for geometries + + + + + Token text for geometries + + + + + Token text for empty geometries + + + + + Token text indicating that geometries have measure-ordinate values + + + + + Token text indicating that geometries have z-ordinate values + + + + + Token text indicating that geometries have both z- and measure-ordinate values + + + + + Reads a sequence of s in WKT format from a text file. + + The geometries in the file may be separated by any amount of whitespace and newlines. + + Martin Davis + + + + + Creates a new given the to read from and a to use to parse the geometries. + + the to read from + the geometry reader to use + + + + Creates a new , given the name of the file to read from. + + The name of the file to read from + The geometry reader to use + + + + Creates a new , given a to read from. + + The stream to read from + The geometry reader to use + + + + Creates a new , given a to read with. + + The stream reader of the file to read from + The geometry reader to use + + + + Gets/Sets the maximum number of geometries to read. + + + + + Gets/Sets allow ignoring WKT parse errors + after at least one geometry has been read, + to return a partial result. + + + + + Gets/Sets the number of geometries to skip before reading. + + + + + Reads a sequence of geometries. + + + + If an offset is specified, geometries read up to the offset count are skipped. + If a limit is specified, no more than geometries are read. + + Thrown if an I/O exception was encountered + Thrown if an error occurred reading a geometry + The list of geometries read + + + + Tests if reader is at EOF. + + + + + Converts a Well-Known Text string to a Geometry. + + The WKTReader allows + extracting Geometry objects from either input streams or + internal strings. This allows it to function as a parser to read Geometry + objects from text blocks embedded in other data formats (e.g. XML). + + The Well-known + Text format is defined in the + OpenGIS Simple Features Specification for SQL . + + As of version 2.0, NTS can read WKT syntax + which specifies coordinate dimension Z, M or ZM as modifiers(e.g.POINT Z) + or in the name of the geometry type(e.g.LINESTRINGZM). + If the coordinate dimension is specified it will be set in the created geometry. + If the coordinate dimension is not specified, the default behaviour is to + create XYZ geometry(this is backwards compatible with older JTS versions). + This can be altered to create XY geometry by + setting to false. + + NOTE: There is an inconsistency in the SFS. + The WKT grammar states that MultiPoints are represented by + MULTIPOINT ( ( x y), (x y) ), + but the examples show MultiPoints as MULTIPOINT ( x y, x y ). + Other implementations follow the latter syntax, so NTS will adopt it as well. + A WKTReader is parameterized by a GeometryFactory, + to allow it to create Geometry objects of the appropriate + implementation. In particular, the GeometryFactory will + determine the PrecisionModel and SRID that is used. + The WKTReader will convert the input numbers to the precise + internal representation. + + reads also non-standard tags. + + + + + + Creates a WKTReader that creates objects using a basic GeometryFactory. + + + + + Creates a WKTReader that creates objects using a basic GeometryFactory. + + + + + Creates a WKTReader that creates objects using the given + GeometryFactory. + + The factory used to create Geometrys. + + + + Gets or sets a value indicating whether or not coordinates may have 3 ordinate values + even though no Z or M ordinate indicator is present. The default value is + . + + + + + Gets or sets a value indicating whether or not point coordinates in a MultiPoint + geometry must not be enclosed in paren. The default value is . + + + + + Gets or sets the factory to create geometries + + + + + Gets or sets the default SRID + + + + + Gets or sets a value indicating if the reader should attempt to repair malformed input. + + + Malformed in this case means the ring has too few points (4), + or is not closed. + + + + + Converts a Well-known Text representation to a Geometry. + + + one or more Geometry Tagged Text strings (see the OpenGIS + Simple Features Specification) separated by whitespace. + + + A Geometry specified by wellKnownText + + + + + Converts a Well-known Text representation to a Geometry. + + + one or more Geometry Tagged Text strings (see the OpenGIS + Simple Features Specification) separated by whitespace. + + + A Geometry specified by wellKnownText + + + + + Converts a Well-known Text representation to a Geometry. + + + A Reader which will return a "Geometry Tagged Text" + string (see the OpenGIS Simple Features Specification). + + A Geometry read from reader. + + + + + Reads a Coordinate from a stream using the given . + + All ordinate values are read, but -depending on the + of the underlying - not necessarily all can be handled. + Those are silently dropped. + + + A geometry factory + the tokenizer to use. + a bit-mask defining the ordinates to read. + a value indicating if a starting "(" should be probed. + a of length 1 containing the read ordinate values. + if an I/O error occurs. + if an unexpected token was encountered. + + + + Reads a Coordinate from a stream using the given . + + All ordinate values are read, but -depending on the + of the underlying - not necessarily all can be handled. + Those are silently dropped. + + + A geometry factory + the tokenizer to use. + a bit-mask defining the ordinates to read. + a of length 1 containing the read ordinate values. + if an I/O error occurs. + if an unexpected token was encountered. + + + + Reads a CoordinateSequence from a stream using the given + for an old-style JTS MultiPoint (Point coordinates not enclosed in parentheses). + + All ordinate values are read, but -depending on the + of the underlying - not necessarily all can be handled. + Those are silently dropped. + + + A geometry factory + the tokenizer to use. + a bit-mask defining the ordinates to read. + a of length 1 containing the read ordinate values. + if an I/O error occurs. + if an unexpected token was encountered. + + + + Computes the required dimension based on the given ordinate bit-mask. + It is assumed that is set. + + the ordinate bit-mask. + the number of dimensions required to store ordinates for the given bit-mask. + + + + Merges an array of one-coordinate-s into one + . + + A geometry factory + an array of coordinate sequences. Each sequence contains exactly one coordinate. + a bit-mask of required ordinates. + a coordinate sequence containing all coordinate. + + + + + + + + + + + + + + + + + + Returns the next number in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next token must be a number. + + The next number in the stream. + if the next token is not a valid number + + + + Returns the next WKTConstants.EMPTY or "(" in the stream as uppercase text. + + + Tokenizer over a stream of text in Well-known Text + format. The next token must be or "(". + + + The next WKTConstants.EMPTY or "(" in the stream as uppercase text. + + + + Returns the next ordinate flag information in the stream as uppercase text. + This can be Z, M or ZM. + + tokenizer over a stream of text in Well-known Text + the next ordinate flags. + if an I/O error occurs + if the next token is not EMPTY or L_PAREN + + + + Returns the next word in the stream. + + tokenizer over a stream of text in Well-known Text format. The next token must be a word. + the next word in the stream as uppercase text + if the next token is not a word + if an I/O error occurs + + + + Returns the next ")" or "," in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next token must be ")" or ",". + + + The next ")" or "," in the stream. + + + + Returns the next ")" in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next token must be ")". + + + The next ")" in the stream. + + + + Returns the next word in the stream as uppercase text. + + + Tokenizer over a stream of text in Well-known Text + format. The next token must be a word. + + + to advance the stream, to just peek. + + The next word in the stream as uppercase text. + + + + Creates a Geometry using the next token in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a <Geometry Tagged Text. + + A Geometry specified by the next token + in the stream. + + + + Creates a Point using the next token in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a <Point Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + A Point specified by the next token in + the stream. + + + + Creates a LineString using the next token in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a <LineString Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + + A LineString specified by the next + token in the stream. + + + + Creates a LinearRing using the next token in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a <LineString Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + A LinearRing specified by the next + token in the stream. + + + + Creates a MultiPoint using the next token in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a <MultiPoint Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + + A MultiPoint specified by the next + token in the stream. + + + + Creates a Polygon using the next token in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a Polygon Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + + A Polygon specified by the next token + in the stream. + + + + + Creates a MultiLineString using the next token in the stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a MultiLineString Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + + A MultiLineString specified by the + next token in the stream. + + + + Creates a MultiPolygon using the next token in the stream. + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a MultiPolygon Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + + A MultiPolygon specified by the next + token in the stream, or if if the coordinates used to create the + Polygon shells and holes do not form closed linestrings. + + + + Creates a GeometryCollection using the next token in the + stream. + + + Tokenizer over a stream of text in Well-known Text + format. The next tokens must form a <GeometryCollection Text. + + The factory to create the geometry + A flag indicating the ordinates to expect. + + A GeometryCollection specified by the + next token in the stream. + + + + Outputs the textual representation of a . + The outputs coordinates rounded to the precision + model. No more than the maximum number of necessary decimal places will be + output. + The Well-known Text format is defined in the OpenGIS Simple Features + Specification for SQL. + A non-standard "LINEARRING" tag is used for LinearRings. The WKT spec does + not define a special tag for LinearRings. The standard tag to use is + "LINESTRING". + + + + + Generates the WKT for a Point specified by a . + + The point coordinate. + The WKT + + + + Generates the WKT for a N-point LineString specified by a . + + The sequence to write. + The WKT + + + + Generates the WKT for a LINESTRING specified by an array of s. + + An array of coordinates + The WKT + + + + Generates the WKT for a LineString specified by two s. + + The first coordinate. + The second coordinate. + The WKT + + + + Creates the NumberFormatInfo used to write doubles + with a sufficient number of decimal places. + + + The PrecisionModel used to determine + the number of decimal places to write. + + + A NumberFormatInfo that write doubles + without scientific notation. + + + + + A filter implementation to test if a coordinate sequence actually has meaningful values + for an ordinate bit-pattern + + + + + Initializes a new instance of the flag. + + + The index for the ordinates to test. + + + if implies + , otherwise. + + + + + + + + + + + + + + Gets the evaluated ordinate bit-pattern of ordinates with valid values masked by + . + + + + + Creates an instance of this class which is writing at most 2 dimensions. + + + + + Creates an instance of this class which is writing at most dimensions. + + + + + Gets/sets whether the output will be formatted + + + + + Gets/sets the maximum number of coordinates per line written in formatted output. + + If the provided coordinate number is < 0, coordinates will be written all on one line. + + + Gets/sets the tab size to use for indenting. + If the size is non-positive + + + + Gets or sets the to be written. Possible members are: + + + + + + + Values of and are always assumed and + not particularly checked for. + + + + + Gets or sets a that should be used on the ordinates written. + + If none/ is assigned, the precision model of the + is used. + + + Note: The precision model is applied to all ordinate values, not just x and y. + + + + + + Creates a new instance of the class suitable for MSSQL's non- + standard WKT format. + + + A new instance of the class suitable for MSSQL's non-standard + WKT format. + + + + + Converts a Geometry to its Well-known Text representation. + + A Geometry to process. + A Geometry Tagged Text string (see the OpenGIS Simple Features Specification). + + + + Converts a Geometry to its Well-known Text representation. + + A Geometry to process. + A Stream to write into + + + + Converts a Geometry to its Well-known Text representation. + + A Geometry to process. + + A "Geometry Tagged Text" string (see the OpenGIS Simple Features Specification) + + + + Same as write, but with newlines and spaces to make the + well-known text more readable. + + A Geometry to process + + A "Geometry Tagged Text" string (see the OpenGIS Simple + Features Specification), with newlines and spaces. + + + + + Same as write, but with newlines and spaces to make the + well-known text more readable. + + A Geometry to process + + + A Geometry Tagged Text string (see the OpenGIS Simple + Features Specification), with newlines and spaces. + + + + + Converts a Geometry to its Well-known Text representation. + + A Geometry to process + A flag indicating that the output should be formatted. + the output writer to append to. + The precision model to use. + + A "Geometry Tagged Text" string (see the OpenGIS Simple + Features Specification). + + + + + Converts a to <Geometry Tagged Text> format, then appends + it to the writer. + + the to process. + A flag indicating that the output should be formatted. + the output writer to append to. + The format to use for writing ordinate values. + + + + Converts a to <Geometry Tagged Text> format, then appends + it to the writer. + + the to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted. + The indentation level + the output writer to append to. + The format to use for writing ordinate values. + + + + Converts a Coordinate to Point Tagged Text format, + then appends it to the writer. + + The Point to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Converts a LineString to <LineString Tagged Text + format, then appends it to the writer. + + The LineString to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Converts a LinearRing to <LinearRing Tagged Text + format, then appends it to the writer. + + The LinearRing to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Converts a Polygon to Polygon Tagged Text format, + then appends it to the writer. + + The Polygon to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Converts a MultiPoint to <MultiPoint Tagged Text + format, then appends it to the writer. + + The MultiPoint to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Converts a MultiLineString to MultiLineString Tagged + Text format, then appends it to the writer. + + The MultiLineString to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Converts a MultiPolygon to MultiPolygon Tagged Text + format, then appends it to the writer. + + The MultiPolygon to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Converts a GeometryCollection to GeometryCollection + Tagged Text format, then appends it to the writer. + + The GeometryCollection to process. + A bit-pattern of ordinates to write. + flag indicating that the output should be formatted + the indentation level + The output writer to append to. + The format to use for writing ordinate values. + + + + Appends the i'th coordinate from the sequence to the writer + + If the has coordinates that are NaN, + these are not written, even though suggests this. + + + the to process + A bit pattern of output ordinates + the index of the coordinate to write + writer the output writer to append to + The format to use for writing ordinate values + + + + + Converts a to a . + + The to convert. + A + + The as a . + + + + + Appends additional ordinate information. This function may + + + + append 'Z' if in the value is included. + + + + + append 'M' if in the value is included. + + + + + append 'ZM' if in the and + values are included. + + + + + A bit-pattern of ordinates to write. + the output writer to append to. + if an error occurs while using the writer. + + + + Appends all members of a to the stream. Each + is separated from another using a colon, the ordinates of a + are separated by a space. + + the to process. + A bit-pattern of ordinates to write. + flag indicating that. + the indentation level. + flag indicating that the first of the sequence should be indented for better visibility. + the output writer to append to. + The format to use for writing ordinate values. + + + + Converts a Polygon to Polygon Text format, then + appends it to the writer. + + The Polygon to process. + A bit-pattern of ordinates to write. + flag indicating that. + the indentation level. + flag indicating that the first of the sequence should be indented for better visibility. + the output writer to append to. + The format to use for writing ordinate values. + + + + Converts a MultiPoint to <MultiPoint Text format, then + appends it to the writer. + + The MultiPoint to process. + A bit-pattern of ordinates to write. + flag indicating that. + the indentation level. + the output writer to append to. + The format to use for writing ordinate values. + + + + Converts a MultiLineString to <MultiLineString Text + format, then appends it to the writer. + + The MultiLineString to process. + A bit-pattern of ordinates to write. + flag indicating that. + the indentation level. + the output writer to append to. + The format to use for writing ordinate values. + + + + Converts a MultiPolygon to <MultiPolygon Text format, + then appends it to the writer. + + The MultiPolygon to process. + A bit-pattern of ordinates to write. + flag indicating that. + the indentation level. + the output writer to append to. + The format to use for writing ordinate values. + + + + Converts a GeometryCollection to GeometryCollectionText + format, then appends it to the writer. + + The GeometryCollection to process. + + flag indicating that. + the indentation level. + the output writer to append to. + The format to use for writing ordinate values. + + + + Extracts the subline of a linear between + two s on the line. + + + + + Computes the subline of a between + two s on the line. + If the start location is after the end location, + the computed linear geometry has reverse orientation to the input line. + + The line to use as the baseline. + The start location. + The end location. + The extracted subline. + + + + Initializes a new instance of the class. + + + + + + Extracts a subline of the input. + If is minor that , + the linear geometry computed will be reversed. + + The start location. + The end location. + A linear geometry. + + + + + + + + + + + Assumes input is valid + (e.g. minor or equals to ). + + + + + + + + Supports linear referencing along a linear + using the length along the line as the index. + Negative length values are taken as measured in the reverse direction + from the end of the geometry. + Out-of-range index values are handled by clamping + them to the valid range of values. + Non-simple lines (i.e. which loop back to cross or touch + themselves) are supported. + + + + + Constructs an object which allows a linear + to be linearly referenced using length as an index. + + The linear geometry to reference along. + + + + Computes the for the point + on the line at the given index. + If the index is out of range the first or last point on the + line will be returned. + + + The Z-ordinate of the computed point will be interpolated from + the Z-ordinates of the line segment containing it, if they exist. + + The index of the desired point. + The at the given index. + + + + Computes the for the point on the line at the given index, offset by the given distance. + + + If the index is out of range the first or last point on the line will be returned. + The computed point is offset to the left of the line if the offset distance is + positive, to the right if negative. + The Z-ordinate of the computed point will be interpolated from the Z-ordinates of the line segment containing it, if they exist. + + The index of the desired point + The distance the point is offset from the segment (positive is to the left, negative is to the right) + The Coordinate at the given index + + + + Computes the for the interval + on the line between the given indices. + If the lies before the , + the computed geometry is reversed. + + + + + + + + + + + + + + + Computes the minimum index for a point on the line. + If the line is not simple (i.e. loops back on itself) + a single point may have more than one possible index. + In this case, the smallest index is returned. + The supplied point does not necessarily have to lie precisely + on the line, but if it is far from the line the accuracy and + performance of this function is not guaranteed. + Use to compute a guaranteed result for points + which may be far from the line. + + A point on the line. + The minimum index of the point. + + + + + Finds the index for a point on the line + which is greater than the given index. + If no such index exists, returns . + This method can be used to determine all indexes for + a point which occurs more than once on a non-simple line. + It can also be used to disambiguate cases where the given point lies + slightly off the line and is equidistant from two different + points on the line. + The supplied point does not necessarily have to lie precisely + on the line, but if it is far from the line the accuracy and + performance of this function is not guaranteed. + Use to compute a guaranteed result for points + which may be far from the line. + + A point on the line. + The value the returned index must be greater than. + The index of the point greater than the given minimum index. + + + + + Computes the indices for a subline of the line. + (The subline must conform to the line; that is, + all vertices in the subline (except possibly the first and last) + must be vertices of the line and occur in the same order). + + A subLine of the line. + A pair of indices for the start and end of the subline.. + + + + Computes the index for the closest point on the line to the given point. + If more than one point has the closest distance the first one along the line is returned. + (The point does not necessarily have to lie precisely on the line.) + + + + + + + Returns the index of the start of the line. + + + + + Returns the index of the end of the line. + + + + + Tests whether an index is in the valid index range for the line. + + The index to test. + true if the index is in the valid range. + + + + Computes a valid index for this line + by clamping the given index to the valid range of index values + + A valid index value + + + + + + + + + Initializes a new instance of the class. + + A linear geometry. + + + + Find the nearest location along a linear to a given point. + + The coordinate to locate. + The location of the nearest point. + + + + Finds the nearest index along the linear + to a given after the specified minimum index. + If possible the location returned will be strictly + greater than the . + If this is not possible, the value returned + will equal . + (An example where this is not possible is when + = [end of line] ). + + The coordinate to locate. + The minimum location for the point location. + The location of the nearest point. + + + + + + + + + + + + + + + + + + + + + Computes the for a given length + along a linear + Negative lengths are measured in reverse from end of the linear geometry. + Out-of-range values are clamped. + + + + + Computes the for a + given length along a linear . + + The linear geometry to use. + The length index of the location. + The for the length. + + + + Computes the for a + given length along a linear , + with control over how the location + is resolved at component endpoints. + + The linear geometry to use + The length index of the location + If true lengths are resolved to the lowest possible index + + + + Computes the length for a given + on a linear . + + The linear geometry to use. + The index of the location. + The length for the . + + + + Initializes a new instance of the class. + + A linear geometry. + + + + Compute the corresponding to a length. + Negative lengths are measured in reverse from end of the linear geometry. + Out-of-range values are clamped. + Ambiguous indexes are resolved to the lowest possible location value. + + The length index. + The corresponding . + + + + Compute the corresponding to a length. + Negative lengths are measured in reverse from end of the linear geometry. + Out-of-range values are clamped. + Ambiguous indexes are resolved to the lowest or highest possible location value, + depending on the value of resolveLower + + The length index + + The corresponding . + + + + + + + + + + + + + + + + + + Builds a linear geometry ( or ) + incrementally (point-by-point). + + + + + Creates an instance of this class. + + The geometry factory to use. + + + + Allows invalid lines to be fixed rather than causing Exceptions. + An invalid line is one which has only one unique point. + + + + + Allows invalid lines to be ignored rather than causing Exceptions. + An invalid line is one which has only one unique point. + + + + + Adds a point to the current line. + + The to add. + + + + Adds a point to the current line. + + The to add. + If true, allows the insertions of repeated points. + + + + + + + + + Terminate the current . + + + + + + + + + + + + Builds and returns the . + + + + + + An iterator over the components and coordinates of a linear geometry + (s and s. + + + + + + + + + + + + Invariant: currentLine <> null if the iterator is pointing at a valid coordinate + + + + + Creates an iterator initialized to the start of a linear . + + The linear geometry to iterate over. + if is not + + + + Creates an iterator starting at a on a linear . + + The linear geometry to iterate over. + The location to start at. + if is not + + + + Creates an iterator starting at + a component and vertex in a linear . + + The linear geometry to iterate over. + The component to start at. + The vertex to start at. + if is not + + + + + + + + + Tests whether there are any vertices left to iterator over. + Specifically, HasNext() returns true if the + current state of the iterator represents a valid location + on the linear geometry. + + true if there are more vertices to scan. + + + + Jump to the next element of the iteration. + + + + + Checks whether the iterator cursor is pointing to the + endpoint of a component . + + + + + The component index of the vertex the iterator is currently at. + + + + + The vertex index of the vertex the iterator is currently at. + + + + + Gets the component the iterator is current at. + + + + + Gets the first of the current segment + (the coordinate of the current vertex). + + + + + Gets the second of the current segment + (the coordinate of the next vertex). + If the iterator is at the end of a line, null is returned. + + + + + Represents a location along a or .
+ The referenced geometry is not maintained within this location, + but must be provided for operations which require it. + Various methods are provided to manipulate the location value + and query the geometry it references. +
+
+ + + Gets a location which refers to the end of a linear . + + The linear geometry. + A new LinearLocation. + + + + Computes the of a point a given fraction + along the line segment (p0, p1). + + + + If the fraction is greater than 1.0 the last + point of the segment is returned. + If the fraction is less than or equal to 0.0 the first point + of the segment is returned. + + The Z ordinate is interpolated from the Z-ordinates of the given points, + if they are specified. + + The first point of the line segment. + The last point of the line segment. + The length to the desired point. + + + + + Initializes a new instance of the class: + creates a location referring to the start of a linear geometry. + + + + + Initializes a new instance of the class: + creates a location referring to the start of a linear geometry. + + Index of the segment. + The segment fraction. + + + + Initializes a new instance of the class: + creates a location referring to the start of a linear geometry. + + Index of the component. + Index of the segment. + The segment fraction. + + + + Initializes a new instance of the class: + creates a location referring to the start of a linear geometry. + + Index of the component. + Index of the segment. + The segment fraction. + If true, ensures the individual values are locally valid. + + + + Creates a new location equal to a given one. + + A linear location + + + + Ensures the individual values are locally valid. + Does not ensure that the indexes are valid for + a particular linear geometry. + + + + + Ensures the indexes are valid for a given linear . + + A linear geometry. + + + + Snaps the value of this location to + the nearest vertex on the given linear , + if the vertex is closer than . + + A linear geometry. + The minimum allowable distance to a vertex. + + + + Gets the length of the segment in the given + Geometry containing this location. + + A linear geometry. + The length of the segment. + + + + Sets the value of this location to + refer to the end of a linear geometry. + + The linear geometry to use to set the end. + + + + Gets the component index for this location. + + + + + Gets the segment index for this location. + + + + + Gets the segment fraction for this location. + + + + + Tests whether this location refers to a vertex: + returns true if the location is a vertex. + + + + + Gets the along the + given linear which is + referenced by this location. + + A linear geometry. + The at the location. + + + + Gets a representing the segment of the given linear which contains this location. + + A linear geometry + the LineSegment containing the location + + + + Tests whether this location refers to a valid + location on the given linear . + + A linear geometry. + true if this location is valid. + + + + Compares the current instance with another object of the same type. + + + The LineStringLocation with which this + Coordinate is being compared. + + + A negative integer, zero, or a positive integer as this + LineStringLocation is less than, equal to, + or greater than the specified LineStringLocation. + + + is not the same type as this instance. + + + + + Compares the current instance with another object of the same type. + + + The LineStringLocation with which this + Coordinate is being compared. + + + A negative integer, zero, or a positive integer as this + LineStringLocation is less than, equal to, + or greater than the specified LineStringLocation. + + + + + Compares this object with the specified index values for order. + + The component index. + The segment index. + The segment fraction. + + A negative integer, zero, or a positive integer as this LineStringLocation + is less than, equal to, or greater than the specified locationValues. + + + + + Compares two sets of location values for order. + + The first component index. + The first segment index. + The first segment fraction. + The second component index. + The second segment index. + The second segment fraction. + + A negative integer, zero, or a positive integer + as the first set of location values is less than, equal to, + or greater than the second set of locationValues. + + + + + Tests whether two locations are on the same segment in the parent . + + A location on the same geometry + true if the locations are on the same segment of the parent geometry + + + + Tests whether this location is an endpoint of + the linear component it refers to. + + The linear geometry referenced by this location + True if the location is a component endpoint + + + + Converts a linear location to the lowest equivalent location index. + The lowest index has the lowest possible component and segment indices. + Specifically: + * if the location point is an endpoint, a location value is returned as (nseg-1, 1.0) + * if the location point is ambiguous (i.e. an endpoint and a startpoint), the lowest endpoint location is returned + If the location index is already the lowest possible value, the original location is returned. + + The linear geometry referenced by this location. + The lowest equivalent location. + + + + + + + Gets the count of the number of line segments + in a . + This is one less than the number of coordinates. + + A LineString + The number of segments + + + + Supports linear referencing along a linear + using s as the index. + + + + + Constructs an object which allows linear referencing along + a given linear . + + The linear geometry to reference alo + + + + Computes the for the point on the line at the given index. + If the is out of range, + the first or last point on the line will be returned. + + + The Z-ordinate of the computed point will be interpolated from + the Z-ordinates of the line segment containing it, if they exist. + + The index of the desired point. + The at the given index. + + + + Computes the for the point + on the line at the given index, offset by the given distance. + If the index is out of range the first or last point on the + line will be returned. + The computed point is offset to the left of the line if the offset distance is + positive, to the right if negative. + The Z-ordinate of the computed point will be interpolated from + the Z-ordinates of the line segment containing it, if they exist. + + The index of the desired point + The distance the point is offset from the segment + (positive is to the left, negative is to the right) + The Coordinate at the given index + + + + Computes the for the point on the line at the given index, offset by the given distance. + + + If the index is out of range the first or last point on the line will be returned. + The computed point is offset to the left of the line if the offset distance is + positive, to the right if negative. + The Z-ordinate of the computed point will be interpolated from the Z-ordinates of the line segment containing it, if they exist. + + The index of the desired point + The distance the point is offset from the segment (positive is to the left, negative is to the right) + The Coordinate at the given index + + + + Computes the for the interval + on the line between the given indices. + If the start location is after the end location, + the computed linear geometry has reverse orientation to the input line. + + The index of the start of the interval. + The index of the end of the interval. + The linear interval between the indices. + + + + Computes the index for a given point on the line. + The supplied point does not necessarily have to lie precisely + on the line, but if it is far from the line the accuracy and + performance of this function is not guaranteed. + Use to compute a guaranteed result for points + which may be far from the line. + + A point on the line. + The index of the point. + + + + + Computes the indices for a subline of the line. + (The subline must conform to the line; that is, + all vertices in the subline (except possibly the first and last) + must be vertices of the line and occur in the same order). + + A subLine of the line. + A pair of indices for the start and end of the subline. + + + + Finds the index for a point on the line which is greater than the given index. + If no such index exists, returns . + + + + This method can be used to determine all indexes for + a point which occurs more than once on a non-simple line. + It can also be used to disambiguate cases where the given point lies + slightly off the line and is equidistant from two different + points on the line. + + + The supplied point does not necessarily have to lie precisely + on the line, but if it is far from the line the accuracy and + performance of this function is not guaranteed. + Use to compute a guaranteed result for points + which may be far from the line. + + + A point on the line + The value the returned index must be greater than + The index of the point greater than the given minimum index + + + + + Computes the index for the closest point on the line to the given point. + If more than one point has the closest distance the first one along the line is returned. + (The point does not necessarily have to lie precisely on the line.) + + A point on the line. + The index of the point. + + + + Returns the index of the start of the line. + + + + + Returns the index of the end of the line. + + + + + Tests whether an index is in the valid index range for the line. + + The index to test. + true if the index is in the valid range. + + + + Computes a valid index for this line by clamping + the given index to the valid range of index values. + + + A valid index value. + + + + Determines the location of a subline along a linear . + The location is reported as a pair of s. + NOTE: Currently this algorithm is not guaranteed to + return the correct substring in some situations where + an endpoint of the test line occurs more than once in the input line. + (However, the common case of a ring is always handled correctly). + + + + + + + + + + + + + Initializes a new instance of the class. + + The linear geom. + + + + + + + + + + + Computes the of the point + on a linear nearest a given . + The nearest point is not necessarily unique; this class + always computes the nearest point closest + to the start of the geometry. + + + + + + + + + + + + + Initializes a new instance of the class. + + A linear geometry. + + + + Find the nearest location along a linear to a given point. + + The coordinate to locate. + The location of the nearest point. + + + + Find the nearest along the linear + to a given after the specified minimum . + If possible the location returned will be strictly greater than the . + If this is not possible, the value returned will equal . + (An example where this is not possible is when = [end of line] ). + + The coordinate to locate. + The minimum location for the point location. + The location of the nearest point. + + + + Implements extended-precision floating-point numbers + which maintain 106 bits (approximately 30 decimal digits) of precision. + + A DoubleDouble uses a representation containing two double-precision values. + A number x is represented as a pair of doubles, x.hi and x.lo, + such that the number represented by x is x.hi + x.lo, where +
+                |x.lo| <= 0.5*ulp(x.hi)
+            
+ and ulp(y) means "unit in the last place of y". + The basic arithmetic operations are implemented using + convenient properties of IEEE-754 floating-point arithmetic. + + The range of values which can be represented is the same as in IEEE-754. + The precision of the representable numbers + is twice as great as IEEE-754 double precision. + + The correctness of the arithmetic algorithms relies on operations + being performed with standard IEEE-754 double precision and rounding. + This is the Java standard arithmetic model, but for performance reasons + Java implementations are not + constrained to using this standard by default. + Some processors (notably the Intel Pentium architecture) perform + floating point operations in (non-IEEE-754-standard) extended-precision. + A JVM implementation may choose to use the non-standard extended-precision + as its default arithmetic mode. + To prevent this from happening, this code uses the + Java strictfp modifier, + which forces all operations to take place in the standard IEEE-754 rounding model. + + The API provides both a set of value-oriented operations + and a set of mutating operations. + Value-oriented operations treat DoubleDouble values as + immutable; operations on them return new objects carrying the result + of the operation. This provides a simple and safe semantics for + writing DoubleDouble expressions. However, there is a performance + penalty for the object allocations required. + The mutable interface updates object values in-place. + It provides optimum memory performance, but requires + care to ensure that aliasing errors are not created + and constant values are not changed. + + This implementation uses algorithms originally designed variously by + Knuth, Kahan, Dekker, and Linnainmaa. + Douglas Priest developed the first C implementation of these techniques. + Other more recent C++ implementation are due to Keith M. Briggs and David Bailey et al. +

References

+ + Priest, D., Algorithms for Arbitrary Precision Floating Point Arithmetic, + in P. Kornerup and D. Matula, Eds., Proc. 10th Symposium on Computer Arithmetic, + IEEE Computer Society Press, Los Alamitos, Calif., 1991. + Yozo Hida, Xiaoye S. Li and David H. Bailey, + Quad-Double Arithmetic: Algorithms, Implementation, and Application, + manuscript, Oct 2000; Lawrence Berkeley National Laboratory Report BNL-46996. + David Bailey, High Precision Software Directory; + http://crd.lbl.gov/~dhbailey/mpdist/index.html + +
+ Martin Davis +
+ + The value nearest to the constant Pi. + + + The value nearest to the constant 2 * Pi. + + + The value nearest to the constant Pi / 2. + + + + The value nearest to the constant e (the natural logarithm base). + + + + + A value representing the result of an operation which does not return a valid number. + + + + + The smallest representable relative difference between two values + + + + + Converts the string argument to a DoubleDouble number. + + A string containing a representation of a numeric value + The extended precision version of the value + Thrown if is not a valid representation of a number + + + + Operator to parse a DoubleDouble from a string + + The DoubleDouble string + + + + Converts the double argument to a DoubleDouble number. + + A numeric value + The extended precision version of the value + + + + Operator to convert the double value to a DoubleDouble value. + + The DoubleDouble string + + + + The value to split a double-precision value on during multiplication + + + + + The high-order component of the double-double precision value. + + + + + The low-order component of the double-double precision value. + + + + + Creates a new with value x. + + The initial value + + + + Creates a new with value (hi, lo). + + The high order component + The low order component + + + + Creates a with a value equal to the argument + + The initial value + + + + Creates a new with value equal to the argument. + + The value to initialize by + if is not a valid representation of a number + + + + Creates a new with the value of the argument. + + The value to copy + A copy of + + + + Creates and returns a copy of this value. + + A copy of this value + + + + Returns the sum of and . + + The left hand side + The right hand side + The sum of and + + + + Returns the sum of and . + + The left hand side + The right hand side + The sum of and + + + + Returns the difference of and . + + The left hand side + The right hand side + The difference of and + + + + Returns the difference of and . + + The left hand side + The right hand side + The difference of and + + + + Subtracts the argument from the value of this. + + The subtrahend + The result of this - y + + + + Multiplies by . + + A DoubleDouble value. + A double value. + The result of the multiplication. + + + + Multiplies by . + + A DoubleDouble value. + A DoubleDouble value. + The result of the multiplication. + + + + Divides by . + + A DoubleDouble numerator. + A double divisor. + The result of the division. + + + + Divides by . + + A DoubleDouble numerator. + A DoubleDouble divisor. + The result of the division. + + + + Returns a whose value is 1 / this. + + The reciprocal of this value + + + + Computes the determinant of the 2x2 matrix with the given entries. + + A matrix entry + A matrix entry + A matrix entry + A matrix entry + The determinant of the matrix of values + + + + Computes the determinant of the 2x2 matrix with the given entries. + + A matrix entry + A matrix entry + A matrix entry + A matrix entry + The determinant of the matrix of values + + + + Computes the minimum of this and another DD number. + + A DD number + The minimum of the two numbers + + + + Computes the maximum of this and another DD number. + + A DD number + The maximum of the two numbers + + + + Returns the largest (closest to positive infinity) + value that is not greater than the argument + and is equal to a mathematical integer. + Special cases: + + If this value is NaN, returns NaN. + + + The largest (closest to positive infinity) + value that is not greater than the argument + and is equal to a mathematical integer. + + + + + Returns the smallest (closest to negative infinity) value + that is not less than the argument and is equal to a mathematical integer. + Special cases: + + If this value is NaN, returns NaN. + + + + The smallest (closest to negative infinity) value + that is not less than the argument and is equal to a mathematical integer. + + + + + Returns an integer indicating the sign of this value. + + + if this value is > 0, returns 1 + if this value is < 0, returns -1 + if this value is = 0, returns 0 + if this value is NaN, returns 0 + + + + An integer indicating the sign of this value + + + + Rounds this value to the nearest integer. + The value is rounded to an integer by adding 1/2 and taking the floor of the result. + Special cases: + + If this value is NaN, returns NaN. + + + This value rounded to the nearest integer + + + + Returns the integer which is largest in absolute value and not further + from zero than this value. + + Special cases: + + If this value is NaN, returns NaN. + + + + The integer which is largest in absolute value and not further from zero than this value + + + + + Returns the absolute value of this value. + + Special cases: + + if this value is NaN, it is returned. + + + The absolute value of this value + + + + Computes the square of this value. + + The square of this value + + + + Computes the square of this value. + + The square of this value. + + + + Computes the positive square root of this value. + If the number is NaN or negative, NaN is returned. + + If this is NaN or less than zero, the result is NaN. + + + + Computes the positive square root of a DoubleDouble value. + If the number is NaN or negative, NaN is returned. + + A numeric value + the positive square root of this number. + If the argument is NaN or less than zero, the result is NaN. + + + + Computes the value of this number raised to an integral power. + Follows semantics of .Net Math.Pow as closely as possible. + + The integer exponent + x raised to the integral power exp + + + + Converts this value to the nearest number. + + The nearest value + + + + Converts this value to the nearest value. + + The nearest value + + + + Gets a value indicating whether this object is zero (0) or not + + + + + Gets a value indicating whether this object is negative or not + + + + + Gets a value indicating whether this object is positive or not + + + + + Gets a value indicating whether this object is positive or not + + + + + Checks if is infinity. + + A DoubleDouble value + true if value is infinity. + + + + Tests whether this value is equal to another DoubleDouble value. + + A DoubleDouble value + true if this value == . + + + + Equality operator for DoubleDouble values + + A DoubleDouble value + A DoubleDouble value + true if == . + + + + Inequality operator for DoubleDouble values + + A DoubleDouble value + A DoubleDouble value + true if != . + + + + Tests whether this value is greater than another DoubleDouble value. + + A DoubleDouble value + true if this value > . + + + + Tests whether this value is greater than or equals to another DoubleDouble value. + + A DoubleDouble value + true if this value >= . + + + + Tests whether this value is less than another DoubleDouble value. + + A DoubleDouble value + true if this value is < + + + + Tests whether this value is less than or equal to another DoubleDouble value. + + A DoubleDouble + true if this value is <= + + + + Compares two DoubleDouble objects numerically. + + An other DoubleDouble value + + -1,0 or 1 depending on whether this value is less than, equal to + or greater than the value of + + + + + + + Dumps the components of this number to a string. + + A string showing the components of the number + + + + Returns a string representation of this number, in either standard or scientific notation. + If the magnitude of the number is in the range [ 10-3, 108 ] + standard notation will be used. Otherwise, scientific notation will be used. + + A string representation of this number + + + + Returns the string representation of this value in standard notation. + + The string representation in standard notation + + + + Returns the string representation of this value in scientific notation. + + The string representation in scientific notation + + + + Extracts the significant digits in the decimal representation of the argument. + A decimal point may be optionally inserted in the string of digits + (as long as its position lies within the extracted digits + - if not, the caller must prepend or append the appropriate zeroes and decimal point). + + + + The string containing the significant digits and possibly a decimal point + + + + Returns the string for this value if it has a known representation (e.g. NaN or 0.0). + + The string for this special number
+ or null if the number is not a special number
+
+ + + Determines the decimal magnitude of a number. + The magnitude is the exponent of the greatest power of 10 which is less than + or equal to the number. + + The number to find the magnitude of + The decimal magnitude of + + + + Converts a string representation of a real number into a DoubleDouble value. + The format accepted is similar to the standard Java real number syntax. + It is defined by the following regular expression: +
+            [+|-] {digit} [ . {digit} ] [ ( e | E ) [+|-] {digit}+
+            
+
+ The string to parse + The value of the parsed number + Thrown if str is not a valid representation of a number +
+ + + + + + + + + Various utility functions for mathematical and numerical operations. + + + + + Clamps a double value to a given range. + + The value to clamp + The minimum value of the range + The maximum value of the range + The clamped value + + + + Clamps a int value to a given range. + + The value to clamp + The minimum value of the range + The maximum value of the range + The clamped value + + + + Clamps an integer to a given maximum limit. + + The value to clamp + The maximum value of the range + The clamped value + + + + Computes the ceiling function of the dividend of two integers. + + The numerator + The denominator + The ceiling of num / denom + + + + Computes the base-10 logarithm of a double value. + + + If the argument is NaN or less than zero, then the result is NaN. + If the argument is positive infinity, then the result is positive infinity. + If the argument is positive zero or negative zero, then the result is negative infinity. + + + + A positive number + The value log a, the base-10 logarithm of the input value + + + + Computes an index which wraps around a given maximum value. + For values >= 0, this is equals to val % max. + For values < 0, this is equal to max - (-val) % max + + The index to wrap + The maximum value (or modulus) + The wrapped index + + + + Computes the average of two numbers. + + A number + A number + The average of the inputs + + + + Computes the maximum fo three values + + A number + A number + A number + The maximum value of , and + + + + Computes the maximum of four values + + A number + A number + A number + A number + The maximum value of , , and + + + + Computes the minimum of four values + + A number + A number + A number + The minimum value of , and + + + + Computes the minimum of four values + + A number + A number + A number + A number + The minimum value of , , and + + + The inverse of the Golden Ratio phi. + + + + + + Implements some 2D matrix operations + (in particular, solving systems of linear equations). + + Martin Davis + + + + Solves a system of equations using Gaussian Elimination. + In order to avoid overhead the algorithm runs in-place + on - if should not be modified the client must supply a copy. + + An nxn matrix in row/column order )modified by this method) + A vector of length n + A vector containing the solution (if any)
or null if the system has no or no unique solution +
+ If the matrix has the wrong size +
+ + + Enumeration for the 3 coordinate planes + + + + + Models a plane in 3-dimensional Cartesian space. + + Martin Davis + + + + Computes the oriented distance from a point to the plane.
+ The distance is: + + positive if the point lies above the plane (relative to the plane normal) + zero if the point is on the plane + negative if the point lies below the plane (relative to the plane normal) + +
+ The point to compute the distance for + The oriented distance to the plane +
+ + + Computes the axis plane that this plane lies closest to. + + Geometries lying in this plane undergo least distortion + (and have maximum area) + when projected to the closest axis plane. + This provides optimal conditioning for + computing a Point-in-Polygon test. + + The index of the closest axis plane + + + + A 2-dimensional mathematical vector represented by double-precision X and Y components. + + mbdavis + + + + Creates a new vector with all components set to Zero + + + + + Creates a new vector with given X and Y components. + + The x component + The y component + A new vector + + + + Creates a new vector from an existing one. + + The vector to copy + A new vector + + + + Creates a vector from a . + + The coordinate to copy + A new vector + + + Creates a vector with the direction and magnitude + of the difference between the + and s. + + The origin coordinate + The destination coordinate + A new vector + + + The X component of this vector + + + The Y component of this vector. + + + + Creates an new vector instance + + + + + Creates a new vector instance using the provided and ordinates + + The x-ordinate value + The y-ordinate value + + + + Creates a new vector instance based on . + + The vector + + + Creates a new vector with the direction and magnitude + of the difference between the + and s. + + The origin coordinate + The destination coordinate + + + + Creates a vector from a . + + The coordinate + A new vector + + + + Gets the x-ordinate value + + + + + Gets the y-ordinate value + + + + + Gets the ordinate values by index + + The index + Thrown if index < 0 or > 1 + + + + Adds to this vector instance. + + The vector to add + The result vector + + + + Subtracts from this vector instance + + The vector to subtract + The result vector + + + + Multiplies the vector by a scalar value. + + The value to multiply by + A new vector with the value v * d + + + + Divides the vector by a scalar value. + + The value to divide by + A new vector with the value v / d + + + + Negates this vector + + A new vector with [-_x, -_y] + + + + + + + + + + + + + + + + Normalizes the vector + + A new normalized vector + + + + + + + + + + + Computes the weighted sum of this vector + with another vector, + with this vector contributing a fraction + of frac to the total. + + In other words, +
+            sum = frac * this + (1 - frac) * v
+            
+
+ The vector to sum + The fraction of the total contributed by this vector + The weighted sum of the two vectors +
+ + + Computes the distance between this vector and another one. + + A vector + The distance between the vectors + + + + Computes the dot-product of two vectors + + A vector + The dot product of the vectors + + + + Computes the angle this vector describes to the horizontal axis + + The angle + + + + + + + + + + + + + + + + + + Rotates this vector by + + The angle + The rotated vector + + + + Rotates a vector by a given number of quarter-circles (i.e. multiples of 90 + degrees or Pi/2 radians). A positive number rotates counter-clockwise, a + negative number rotates clockwise. Under this operation the magnitude of + the vector and the absolute values of the ordinates do not change, only + their sign and ordinate index. + + The number of quarter-circles to rotate by + The rotated vector. + + + + + + + + + + + Gets a made of this vector translated by . + + The translation coordinate + A coordinate + + + + Gets a from this vector + + A coordinate + + + + Creates a copy of this vector + + A copy of this vector + + + + Gets a string representation of this vector + + A string representing this vector + + + + Tests if a vector has the same values for the x and y components. + + A with which to do the comparison. + true if is a with the same values for the X and Y components. + + + + Gets a hashcode for this vector. + + A hashcode for this vector + + + + Adds two vectors. + + The first vector to add. + The second vector to add. + The sum of the two vectors. + + + + Modulates a vector with another by performing component-wise multiplication"/>. + + The first vector to multiply. + The second vector to multiply. + The multiplication of the two vectors. + + + + Subtracts two vectors. + + The first vector to subtract. + The second vector to subtract. + The difference of the two vectors. + + + + Reverses the direction of a given vector. + + The vector to negate. + A vector facing in the opposite direction. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Tests for equality between two objects. + + The first value to compare. + The second value to compare. + true if has the same value as + ; otherwise, false. + + + + Tests for inequality between two objects. + + The first value to compare. + The second value to compare. + true if has a different value + than ; otherwise, false. + + + + Represents a vector in 3-dimensional Cartesian space. + + Martin Davis + + + + Creates a new vector with all components set to Zero + + + + + Computes the dot product of the 3D vectors AB and CD. + + The start point of the 1st vector + The end point of the 1st vector + The start point of the 2nd vector + The end point of the 2nd vector + The dot product + + + + Calculates the cross product of two vectors. + + First source vector. + Second source vector. + + + + Creates a new vector with given , and components. + + The x component + The y component + The z component + A new vector + + + + Creates a vector from a 3D . + + The coordinate should have the + X,Y and Z ordinates specified. + + The coordinate to copy + A new vector + + + + Computes the 3D dot-product of two s + + The 1st vector + The 2nd vector + The dot product of the (coordinate) vectors + + + + Creates a new 3D vector from a . The coordinate should have + the X,Y and Z ordinates specified. + + The coordinate to copy + + + + Creates a new vector with the direction and magnitude + of the difference between the + and s. + + The origin coordinate + The destination coordinate + + + + Creates a new vector with the given , and components + + The x component + The y component + The z component + + + + Creates a new using a plus a value for component + + A vector containing the values with which to initialize the X and Y components. + Initial value for the Z component of the vector. + + + + Gets a value indicating the x-ordinate + + + + + Gets a value indicating the y-ordinate + + + + + Gets a value indicating the z-ordinate + + + + + Computes a vector which is the sum + of this vector and the given vector. + + The vector to add + The sum of this and v + + + + Computes a vector which is the difference + of this vector and the given vector. + + The vector to subtract + The difference of this and v + + + + Creates a new vector which has the same direction + and with length equals to the length of this vector + divided by the scalar value d. + + The scalar divisor + A new vector with divided length + + + + Computes the dot-product of this and + + The 2nd vector + The dot product of the vectors + + + + Computes the cross-product of this and + + The 2nd vector + The cross product of the vectors + + + + Computes the length of this vector + + The length of this vector + + + + Computes the length of vector . + + A coordinate representing a 3D Vector + The length of + + + + Computes a vector having identical direction + but normalized to have length 1. + + A new normalized vector + + + + Computes a vector having identical direction as v + but normalized to have length 1. + + A coordinate representing a 3D vector + A coordinate representing the normalized vector + + + + + + + + + + + + + Adds two vectors. + + The first vector to add. + The second vector to add. + The sum of the two vectors. + + + + Modulates a vector with another by performing component-wise multiplication. + + The first vector to multiply. + The second vector to multiply. + The multiplication of the two vectors. + + + + Assert a vector (return it unchanged). + + The vector to assert (unchanged). + The asserted (unchanged) vector. + + + + Subtracts two vectors. + + The first vector to subtract. + The second vector to subtract. + The difference of the two vectors. + + + + Reverses the direction of a given vector. + + The vector to negate. + A vector facing in the opposite direction. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Scales a vector by the given value. + + The vector to scale. + The amount by which to scale the vector. + The scaled vector. + + + + Tests for equality between two objects. + + The first value to compare. + The second value to compare. + true if has the same value as ; otherwise, false. + + + + Tests for inequality between two objects. + + The first value to compare. + The second value to compare. + true if has a different value than ; otherwise, false. + + + + Functions for performing vector mathematics. + + + + + Computes the normal vector to the triangle p0-p1-p2. In order to compute the normal each + triangle coordinate must have a Z value. If this is not the case, the returned Coordinate + will have NaN values. The returned vector has unit length. + + A point + A point + A point + The normal vector to the triangle -- + + + + Normalizes the vector + + The normalized + + + + Computes the cross product of and + + A vector + A vector + The cross product of and + + + + Computes the dot product of and + + A vector + A vector + The dot product of and + + + + Computes the determinant of a 2x2 matrix + + The m[0,0] value + The m[0,1] value + The m[1,0] value + The m[1,1] value + The determinant + + + + Represents a read-only list of contiguous line segments. + This can be used for detection of intersections or nodes. + s can carry a context object, which is useful + for preserving topological or parentage information. + + If adding nodes is required use . + + + + + + Creates a new segment string from a list of vertices. + + the vertices of the segment string + the user-defined data of this segment string (may be null) + + + Gets the user-defined data for this segment string. + + + + + Gets the octant of the segment starting at vertex index + + the index of the vertex starting the segment. Must not be the last index in the vertex list + octant of the segment at the vertex + + + + + + + Validates that a collection of s is correctly noded. + Indexing is used to improve performance. + + + + By default validation stops after a single + non-noded intersection is detected. + Alternatively, it can be requested to detect all intersections + by using the property. + + The validator does not check for topology collapse situations + (e.g. where two segment strings are fully co-incident). + + The validator checks for the following situations which indicated incorrect noding: + + Proper intersections between segments (i.e. the intersection is interior to both segments) + Intersections at an interior vertex (i.e. with an endpoint or another interior vertex) + + + + The client may either test the condition, + or request that a suitable be thrown. + + + + + + + Gets a list of all intersections found. + Intersections are represented as s. + List is empty if none were found. + A collection of SegmentStrings + a list of + + + + + Creates a new noding validator for a given set of linework. + + A collection of s + + + + Gets or sets whether all intersections should be found. + + + + + Gets a list of all intersections found. + + Intersections are represented as s. + List is empty if none were found. + + + + + + Checks for an intersection and reports if one is found. + + + + + Returns an error message indicating the segments containing the intersection. + + an error message documenting the intersection location + + + + Checks for an intersection and throws + a TopologyException if one is found. + + if an intersection is found + + + + Finds if two sets of s intersect. + + + Uses indexing for fast performance and to optimize repeated tests + against a target set of lines. + Short-circuited to return as soon an intersection is found. + + Immutable and thread-safe. + + + + + Creates an intersection finder against a given set of segment strings. + + The segment strings to search for intersections + + + Gets the segment set intersector used by this class. + This allows other uses of the same underlying indexed structure. + + + + Tests for intersections with a given set of target s. + + The SegmentStrings to test + true if an intersection was found + + + + Tests for intersections with a given set of target s. + using a given SegmentIntersectionDetector. + + The SegmentStrings to test + The intersection detector to use + true if the detector reports intersections + + + + An interface for classes which support adding nodes to a segment string. + + + + Adds an intersection node for a given point and segment to this segment string. + + the location of the intersection + the index of the segment containing the intersection + + + + Computes all intersections between segments in a set of s. + Intersections found are represented as s and added to the + s in which they occur. + As a final step in the noding a new set of segment strings split at the nodes may be returned. + + + + + Computes the noding for a collection of s. + Some Noders may add all these nodes to the input s; + others may only add some or none at all. + + + + + + Returns a of fully noded s. + The s have the same context as their parent. + + + + + + Finds interior intersections + between line segments in s, + and adds them as nodes + using . + This class is used primarily for Snap-Rounding. + For general-purpose noding, use . + + + + + + Creates an intersection finder which finds all proper intersections. + + The to use. + + + + + + + + + This method is called by clients + of the class to process + intersections for two segments of the s being intersected.
+ Note that some clients (such as MonotoneChains) may optimize away + this call for segment pairs which they have determined do not intersect + (e.g. by an disjoint envelope test). +
+ + + + +
+ + + Always process all intersections + + + + + Computes the possible intersections between two line segments in s + and adds them to each string + using . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Initializes a new instance of the class. + + + + + + + + + + + Returns the proper intersection point, or null if none was found. + + + + + + + + + + A proper intersection is an intersection which is interior to at least two + line segments. Note that a proper intersection is not necessarily + in the interior of the entire , since another edge may have + an endpoint equal to the intersection, which according to SFS semantics + can result in the point being on the Boundary of the . + + + + + A proper interior intersection is a proper intersection which is not + contained in the set of boundary nodes set for this . + + + + + An interior intersection is an intersection which is + in the interior of some segment. + + + + + A trivial intersection is an apparent self-intersection which in fact + is simply the point shared by adjacent line segments. + Note that closed edges require a special check for the point shared by the beginning and end segments. + + + + + + + + + + This method is called by clients + of the class to process + intersections for two segments of the being intersected.
+ Note that some clients (such as MonotoneChain") may optimize away + this call for segment pairs which they have determined do not intersect + (e.g. by an disjoint envelope test). +
+ + + + +
+ + + Always process all intersections + + + + + Processes possible intersections detected by a . + + + + The is passed to a . + + The + method is called whenever the + detects that two s might intersect. + + This class may be used either to find all intersections, or + to detect the presence of an intersection. In the latter case, + Noders may choose to short-circuit their computation by calling the + property. + + + + This class is an example of the Strategy pattern. + + This class may be used either to find all intersections, or + to detect the presence of an intersection. In the latter case, + Noders may choose to short-circuit their computation by calling the + property. + + + + + + This method is called by clients + of the interface to process + intersections for two segments of the s being intersected. + + + + + + + + + Reports whether the client of this class needs to continue testing + all intersections in an arrangement. + + if there is no need to continue testing segments + + + + An interface for classes which represent a sequence of contiguous line segments. + SegmentStrings can carry a context object, which is useful + for preserving topological or parentage information. + + + + + Gets/Sets the user-defined data for this segment string. + + + + + Points that make up ISegmentString + + + + + Size of Coordinate Sequence + + + + + States whether ISegmentString is closed + + + + + Nodes a set of s completely. + The set of s is fully noded; + i.e. noding is repeated until no further intersections are detected. + + Iterated noding using a precision model is not guaranteed to converge, + due to round off error. This problem is detected and an exception is thrown. + Clients can choose to rerun the noding using a lower precision model. + + + + + + + + + + + Initializes a new instance of the class. + + + + + + Gets/Sets the maximum number of noding iterations performed before + the noding is aborted. Experience suggests that this should rarely need to be changed + from the default. The default is . + + + + + Returns a of fully noded s. + The s have the same context as their parent. + + + + + + Fully nodes a list of s, i.e. performs noding iteratively + until no intersections are found between segments. + Maintains labelling of edges correctly through the noding. + + A collection of SegmentStrings to be noded. + If the iterated noding fails to converge. + + + + Node the input segment strings once + and create the split edges between the nodes. + + + + + + + Nodes a set of s using a index based + on s and a . + The used should be something that supports + envelope (range) queries efficiently (such as a Quadtree" + or . + + The noder supports using an overlap tolerance distance. + This allows determining segment intersection using a buffer for uses + involving snapping with a distance tolerance. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The to use. + + + + Initializes a new instance of the class. + + The to use. + The expansion distance for overlap tests + + + + + + + + + + + + + + Returns a of fully noded s. + The s have the same context as their parent. + + + + + + Computes the noding for a collection of s. + Some Noders may add all these nodes to the input s; + others may only add some or none at all. + + + + + + + + + + + + + + + + + + + + + + Initializes a new instance of the class. + + The + + + + + + + + + + + + + Intersects two sets of s using a index based + on s and a . + + Thread-safe and immutable. + + + + + Constructs a new intersector for a given set of s. + + The base segment strings to intersect + + + + Gets the index constructed over the base segment strings + + NOTE: To retain thread-safety, treat returned value as immutable + + + + Calls + for all candidate intersections between + the given collection of SegmentStrings and the set of indexed segments. + + A set of segments to intersect + The SegmentIntersector to use + + + + Segment overlap action class + + + + + Creates an instance of this class using the provided + + The segment intersector to use + + + + Represents a list of contiguous line segments, and supports noding the segments. + The line segments are represented by an array of s. + Intended to optimize the noding of contiguous segments by + reducing the number of allocated objects. + s can carry a context object, which is useful + for preserving topological or parentage information. + All noded substrings are initialized with the same context object. + + For read-only applications use , + which is (slightly)more lightweight. + + + + + + Gets the s which result from splitting this string at node points. + + A collection of NodedSegmentStrings + A collection of NodedSegmentStrings representing the substrings + + + + Adds the noded s which result from splitting this string at node points. + + A collection of NodedSegmentStrings + A list which will collect the NodedSegmentStrings representing the substrings + + + + Creates an instance from a list of vertices and optional data object. + + The vertices of the segment string. + The user-defined data of this segment string (may be null). + + + + Creates a new instance from a . + + The segment string to use. + + + + Gets/Sets the user-defined data for this segment string. + + In JTS this property is called Data + + + + + + + + + + + + + + + + + + + + + + + + + + + Gets a list of coordinates with all nodes included. + + An array of coordinates including nodes + + + + + + + + + Gets the octant of the segment starting at vertex index. + + + The index of the vertex starting the segment. + Must not be the last index in the vertex list + + The octant of the segment at the vertex + + + + Adds EdgeIntersections for one or both + intersections found for a segment of an edge to the edge intersection list. + + + + + + + + Add an for intersection intIndex. + An intersection that falls exactly on a vertex + of the is normalized + to use the higher of the two possible segmentIndexes. + + + + + + + + + + + + + + + + + + + Finds non-noded intersections in a set of {@link SegmentString}s, + if any exist. + + Non-noded intersections include: + + Interior intersectionswhich lie in the interior of a segment + (with another segment interior or with a vertex or endpoint) + Vertex intersectionswhich occur at vertices in the interior of s + (with a segment string endpoint or with another interior vertex) + + The finder can be limited to finding only interior intersections + by setting . + + By default only the first intersection is found, + but all can be found by setting . + + + + + Creates a finder which tests if there is at least one intersection. + Uses short-circuiting for efficient performance. + The intersection found is recorded. + + A line intersector. + A finder which tests if there is at least one intersection. + + + + Creates a finder which tests if there is at least one intersection. + The intersections are recorded for later inspection. + + A line intersector. + A finder which finds all intersections. + + + + Creates a finder which finds all interior intersections. + The intersections are recorded for later inspection. + + A line intersector + A finder which finds all interior intersections. + + + + Creates a finder which counts all intersections. + The intersections are note recorded to reduce memory usage. + + A line intersector. + A finder which counts all intersections. + + + + Creates a finder which counts all interior intersections. + The intersections are note recorded to reduce memory usage. + + A line intersector. + A finder which counts all interior intersections. + + + + Creates an intersection finder which finds an interior intersection if one exists + + the LineIntersector to use + + + + Gets/Sets whether all intersections should be computed. + + When this is false (the default value), the value of + is true after the first intersection is found. + Default is false. + + + + + + Gets or sets a value indicating whether only interior (proper) intersections will be found. + + + + + Gets/Sets whether intersection points are recorded. + + If the only need is to count intersection points, this can be set to false. + Default is true. + + + + + + Gets/Sets whether only end segments should be tested for intersection. + This is a performance optimization that may be used if + the segments have been previously noded by an appropriate algorithm. + It may be known that any potential noding failures will occur only in + end segments. + + + + + Tests whether an intersection was found. + + + + + Gets the intersections found. + + A list of . + + + + Gets the count of intersections found. + + The intersection count. + + + + Gets the computed location of the intersection. + Due to round-off, the location may not be exact. + + + + + Gets the computed location of the intersection. + Due to round-off, the location may not be exact. + + + + + Gets the endpoints of the intersecting segments. + + + + + This method is called by clients of the class to process + intersections for two segments of the s being intersected.
+ Note that some clients (such as MonotoneChains) may optimize away + this call for segment pairs which they have determined do not intersect + (e.g. by an disjoint envelope test). +
+ + + + +
+ + + Tests if an intersection occurs between a segmentString interior vertex and another vertex. + Note that intersections between two endpoint vertices are valid noding, + and are not flagged. + + A segment vertex + A segment vertex + A segment vertex + A segment vertex + true if vertex is a segmentString endpoint + true if vertex is a segmentString endpoint + true if vertex is a segmentString endpoint + true if vertex is a segmentString endpoint + true if an intersection is found/ + + + + Tests if two vertices with at least one in a segmentString interior + are equal. + + A segment vertex + A segment vertex + true if vertex is a segmentString endpoint + true if vertex is a segmentString endpoint + true if an intersection is found + + + + Tests whether a segment in a is an end segment. + (either the first or last). + + a segment string + the index of a segment in the segment string + true if the segment is an end segment + + + + + + + + + Validates that a collection of s is correctly noded. + Throws an appropriate exception if an noding error is found. + + + + + Creates a new validator for the given collection + of s. + + The seg strings. + + + + Checks whether the supplied segment strings + are correctly noded. Throws an exception if they are not. + + + + + Checks if a segment string contains a segment pattern a-b-a (which implies a self-intersection). + + + + + Checks all pairs of segments for intersections at an interior point of a segment. + + + + + Checks for intersections between an endpoint of a segment string + and an interior vertex of another segment string + + + + + Octants in the Cartesian plane. + Octants are numbered as follows: + + \2|1/ + 3 \|/ 0 + ---+-- + 4 /|\ 7 + /5|6\ + + If line segments lie along a coordinate axis, the octant is the lower of the two possible values. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Methods for computing and working with of the Cartesian plane. + + + + + Returns the octant of a directed line segment (specified as x and y + displacements, which cannot both be 0). + + + + + + + + Returns the octant of a directed line segment from p0 to p1. + + + + + + + + Allows comparing arrays in an orientation-independent way. + + + + + Creates a new } + for the given array. + + + + + + Computes the canonical orientation for a coordinate array. + + + + true if the points are oriented forwards
+ or falseif the points are oriented in reverse. +
+
+ + + Compares two s for their relative order. + + + + -1 this one is smaller;
+ 0 the two objects are equal;
+ 1 this one is greater. +
+
+ + + + + + + + + + + + + Wraps a and transforms its input into the integer domain. + This is intended for use with Snap-Rounding noders, + which typically are only intended to work in the integer domain. + + Clients should be aware that rescaling can involve loss of precision, + which can cause zero-length line segments to be created. + These in turn can cause problems when used to build a planar graph. + This situation should be checked for and collapsed segments removed if necessary. + + + + + + Initializes a new instance of the class. + + The noder to use + The scale factor to use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A noder which extracts all line segments + as s. + This enables fast overlay of geometries which are known to be already fully noded. + In particular, it provides fast union of polygonal and linear coverages. + Unioning a noded set of lines is an effective way + to perform line merging and line dissolving. + + No precision reduction is carried out. + If that is required, another noder must be used (such as a snap-rounding noder), + or the input must be precision-reduced beforehand. + + Martin Davis + + + + Detects and records an intersection between two s, + if one exists. Only a single intersection is recorded. + + + This strategy can be configured to search for proper intersections. + In this case, the presence of any intersection will still be recorded, + but searching will continue until either a proper intersection has been found + or no intersections are detected. + + + + + Creates an intersection finder using a + + + + + Creates an intersection finder using a given + + The LineIntersector to use + + + + Gets or sets whether processing must continue until a proper intersection is found + + + + + Gets or sets whether processing can terminate once any intersection is found. + + + + + Tests whether an intersection was found. + + + + + Tests whether a proper intersection was found. + + + + + Tests whether a non-proper intersection was found. + + + + + Gets the computed location of the intersection. Due to round-off, the location may not be exact. + + + + Gets the endpoints of the intersecting segments. + + An array of the segment endpoints (p00, p01, p10, p11) + + + + This method is called by clients of the class to process + intersections for two segments of the s being intersected. + + + Note that some clients (such as MonotoneChains) may optimize away + this call for segment pairs which they have determined do not intersect + (e.g. by an disjoint envelope test). + + + + + Tests whether processing can terminate, + because all required information has been obtained + (e.g. an intersection of the desired type has been detected). + + + + + Represents an intersection point between two s. + + + + + + + + + + + + + + + Initializes a new instance of the class. + + + + + + + + + Gets the giving the location of this node. + + + + + + + + + + + + + + + + + + + + + -1 this SegmentNode is located before the argument location;
+ 0 this SegmentNode is at the argument location;
+ 1 this SegmentNode is located after the argument location. +
+
+ + + + + + + + > + + + + A list of the s present along a noded . + + + + + Initializes a new instance of the class. + + The edge. + + + + + + + + + + Adds an intersection into the list, if it isn't already there. + The input segmentIndex and dist are expected to be normalized. + + + + The SegmentIntersection found or added. + + + + Returns an iterator of SegmentNodes. + + An iterator of SegmentNodes. + + + + Adds nodes for the first and last points of the edge. + + + + + Adds nodes for any collapsed edge pairs. + Collapsed edge pairs can be caused by inserted nodes, or they can be + pre-existing in the edge vertex list. + In order to provide the correct fully noded semantics, + the vertex at the base of a collapsed pair must also be added as a node. + + + + + Adds nodes for any collapsed edge pairs + which are pre-existing in the vertex list. + + + + + + Adds nodes for any collapsed edge pairs caused by inserted nodes + Collapsed edge pairs occur when the same coordinate is inserted as a node + both before and after an existing edge vertex. + To provide the correct fully noded semantics, + the vertex must be added as a node as well. + + + + + + + + + + + + + + + Creates new edges for all the edges that the intersections in this + list split the parent edge into. + Adds the edges to the provided argument list + (this is so a single list can be used to accumulate all split edges + for a set of s). + + + + + + Create a new "split edge" with the section of points between + (and including) the two intersections. + The label for the new edge is the same as the label for the parent edge. + + + + + + + + Extracts the points for a split edge running between two nodes. + The extracted points should contain no duplicate points. + There should always be at least two points extracted + (which will be the given nodes). + + The start node of the split edge + The end node of the split edge + The points for the split edge + + + Gets the list of coordinates for the fully noded segment string, + including all original segment string vertices and vertices + introduced by nodes in this list. + Repeated coordinates are collapsed. + + An array of s + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Implements a robust method of comparing the relative position of two points along the same segment. + The coordinates are assumed to lie "near" the segment. + This means that this algorithm will only return correct results + if the input coordinates have the same precision and correspond to rounded values + of exact coordinates lying on the segment. + + + + + Compares two s for their relative position along a segment + lying in the specified . + + + + + + -1 if node0 occurs first, or
+ 0 if the two nodes are equal, or
+ 1 if node1 occurs first. +
+
+ + + + + + + + + + + + + + + + + + + An intersector for the red-blue intersection problem. + In this class of line arrangement problem, + two disjoint sets of linestrings are intersected. + + Implementing classes must provide a way + of supplying the base set of segment strings to + test against (e.g. in the constructor, + for straightforward thread-safety). + + In order to allow optimizing processing, + the following condition is assumed to hold for each set: + + the only intersection between any two linestrings occurs at their endpoints. + + Implementations can take advantage of this fact to optimize processing + (i.e. by avoiding testing for intersections between linestrings + belonging to the same set). + + + + + Computes the intersections with a given set of s, + using the supplied . + + A collection of s to node + The intersection detector to either record intersection occurrences + or add intersection nodes to the input segment strings. + + + + Dissolves a noded collection of s to produce + a set of merged linework with unique segments. + + + A custom merging strategy + can be supplied. + This strategy will be called when two identical (up to orientation) + strings are dissolved together. + The default merging strategy is simply to discard one of the merged strings. + + A common use for this class is to merge noded edges + while preserving topological labelling. + This requires a custom merging strategy to be supplied + to merge the topology labels appropriately. + + + + + + A merging strategy which can be used to update the context data of s + which are merged during the dissolve process. + + mbdavis + + + + Updates the context data of a + when an identical (up to orientation) one is found during dissolving. + + The segment string to update. + The segment string being dissolved. + + true if the strings are in the same direction, + false if they are opposite. + + + + + Creates a dissolver with a user-defined merge strategy. + + + + + + Creates a dissolver with the default merging strategy. + + + + + Dissolve all s in the input . + + + + + + + + + + + + + Dissolve the given . + + + + + + + + + Gets the collection of dissolved (i.e. unique) s + + + + + Utility methods for processing s + + Martin Davis + + + + Extracts all linear components from a given + to s.
+ The 's data item is set to be the source . +
+ The to extract from. + a list of s. +
+ + + Extracts all linear components from a given + to s.
+ The 's data item is set to be the source . +
+ The to extract from. + a list of s. +
+ + + Extracts all linear components from a given to s. + The 's data item is set to be the source Geometry. + + The to extract from. + a list of s. + + + + Converts a collection of s into a . + The geometry will be either a + or a (possibly empty). + + A collection of . + A geometry factory + A or a . + + + + Nodes a set of s by + performing a brute-force comparison of every segment to every other one. + This has n^2 performance, so is too slow for use on large numbers of segments. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + + + + + Returns a of fully noded s. + The s have the same context as their parent. + + + + + + Computes the noding for a collection of s. + Some Noders may add all these nodes to the input s; + others may only add some or none at all. + + + + + + + + + + + + + Intersects two sets of s using + brute-force comparison. + + + + + Constructs a new intersector for a given set of s. + + The base segment strings to intersect + + + + Calls + for all candidate intersections between + the given collection of SegmentStrings and the set of base segments. + + A collection of s to node + The intersection detector to either record intersection occurences + or add intersection nodes to the input segment strings. + + + + Processes all of the segment pairs in the given segment strings + using the given SegmentIntersector. + + A segment string + A segment string + The segment intersector to use + + + + Base class for s which make a single pass to find intersections. + This allows using a custom + (which for instance may simply identify intersections, rather than insert them). + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The to use. + + + + Gets/sets the to use with this noder. + A will normally add intersection nodes + to the input segment strings, but it may not - it may + simply record the presence of intersections. + However, some s may require that intersections be added. + + + + + Computes the noding for a collection of s. + Some Noders may add all these nodes to the input s; + others may only add some or none at all. + + + + + + Returns a of fully noded s. + The s have the same context as their parent. + + + + + + Nodes the linework in a list of s using Snap-Rounding + to a given . + + The input coordinates do not need to be rounded to the + precision model. + All output coordinates are rounded to the precision model. + + This class does not dissolve the output linework, + so there may be duplicate linestrings in the output. + Subsequent processing (e.g. polygonization) may require + the linework to be unique. Using UnaryUnion is one way + to do this (although this is an inefficient approach). + + + + + Creates a new noder which snap-rounds to a grid specified by the given + + The precision model for the grid to snap-round to. + + + + Gets or sets whether noding validity is checked after noding is performed. + + + + + Nodes the linework of a set of Geometrys using SnapRounding. + + A collection of Geometrys of any type + A list of LineStrings representing the noded linework of the input + + + + Implements a "hot pixel" as used in the Snap Rounding algorithm. + A hot pixel is a square region centred + on the rounded valud of the coordinate given, + and of width equal to the size of the scale factor. + It is a partially open region, which contains + the interior of the tolerance square and + the boundary + minus the top and right segments. + This ensures that every point of the space lies in a unique hot pixel. + It also matches the rounding semantics for numbers. + + The hot pixel operations are all computed in the integer domain + to avoid rounding problems. + + Hot Pixels support being marked as nodes. + This is used to prevent introducing nodes at line vertices + which do not have other lines snapped to them. + + + + The scaled x-ordinate of the hot pixel point () + + + The scaled y-ordinate of the hot pixel point () + + + + Initializes a new instance of the class. + + The coordinate at the center of the hot pixel + The scale factor determining the pixel size + The intersector to use for testing intersection with line segments + + + + Creates a new hot pixel centered on a rounded point, using a given scale factor. + The scale factor must be strictly positive(non-zero). + + The coordinate at the center of the hot pixel (already rounded) + The scale factor determining the pixel size + + + + Gets the coordinate this hot pixel is based at. + + + + + Gets the scale factor for the precision grid for this pixel. + + + + + Gets the width of the hot pixel in the original coordinate system. + + + + + Gets or sets a value indicating whether this pixel has been marked as a node. + + true if the pixel is marked as a node + + + + Scale without rounding. + This ensures intersections are checked against original + linework. + This is required to ensure that intersections are not missed + because the segment is moved by snapping. + + + + + Returns a "safe" envelope that is guaranteed to contain the hot pixel. + The envelope returned will be larger than the exact envelope of the pixel. + + An envelope which contains the pixel + + + + Tests whether a coordinate lies in (intersects) this hot pixel. + + The coordinate to test + true if the coordinate intersects this hot pixel + + + + Tests whether the line segment (p0-p1) + intersects this hot pixel. + + The first coordinate of the line segment to test + The second coordinate of the line segment to test + true if the line segment intersects this hot pixel. + + + + + + + + + + + + Test whether the given segment intersects + the closure of this hot pixel. + This is NOT the test used in the standard snap-rounding + algorithm, which uses the partially closed tolerance square instead. + This routine is provided for testing purposes only. + + + + + + + + Adds a new node (equal to the snap pt) to the specified segment + if the segment passes through the hot pixel + + + + true if a node was added to the segment + + + + An index which creates unique s for provided points, + and performs range queries on them. + The points passed to the index do not needed to be + rounded to the specified scale factor; this is done internally + when creating the HotPixels for them. + + Martin Davis + + + + Creates a new hot pixel index using the provided . + + The precision model + + + + Utility class to enumerate through a shuffled array of + s using the + Fisher-Yates shuffle algorithm + + + + + Creates an instance of this class using the provided s. + + An array of coordinates + + + + Creates an instance of this class using the provided s. + + An array of coordinates + + + + + + + + + + + + + + + + + + + Adds a series of points as non-node pixels + + The points to add + + + + Adds a list of points as node pixels. + + The points to add + + + + Adds a point as a Hot Pixel.
+ If the point has been added already, it is marked as a node. +
+ The point to add + The hot-pixel for the point +
+ + + Visits all the hot pixels which may intersect a segment (p0-p1). + The visitor must determine whether each hot pixel actually intersects + the segment. + + The segment start point + The segment end point + The visitor to apply + + + + "Snaps" all s in a containing + s to a given . + + + + + Initializes a new instance of the class. + + + + + + + + + + + + + + + + + + + + + + + Snaps (nodes) all interacting segments to this hot pixel. + The hot pixel may represent a vertex of an edge, + in which case this routine uses the optimization + of not noding the vertex itself + + The hot pixel to snap to. + The edge containing the vertex, if applicable, or null. + + true if a node was added for this pixel. + + + + Snaps (nodes) all interacting segments to this hot pixel. + The hot pixel may represent a vertex of an edge, + in which case this routine uses the optimization + of not noding the vertex itself + + The hot pixel to snap to. + true if a node was added for this pixel. + + + + Returns a "safe" envelope that is guaranteed to contain the hot pixel. + The envelope returned is larger than the exact envelope of the + pixel by a safe margin. + + An envelope which contains the hot pixel + + + + + + + + + Initializes a new instance of the class. + + + + + + + + Reports whether the HotPixel caused a node to be added in any target + segmentString(including its own). If so, the HotPixel must be added as a + node as well. + + + true if a node was added in any target segmentString. + + + + + Check if a segment of the monotone chain intersects + the hot pixel vertex and introduce a snap node if so. + Optimized to avoid noding segments which + contain the vertex (which otherwise + would cause every vertex to be noded). + + A monotone chain + A start index + + + + Adds a new node (equal to the snap pt) to the specified segment + if the segment passes through the hot pixel + + if a node was added to the segment + + + + Uses Snap Rounding to compute a rounded, + fully noded arrangement from a set of s. + Implements the Snap Rounding technique described in + papers by Hobby, Guibas and Marimont, and Goodrich et al. + Snap Rounding assumes that all vertices lie on a uniform grid; + hence the precision model of the input must be fixed precision, + and all the input vertices must be rounded to that precision. + + This implementation uses a monotone chains and a spatial index to + speed up the intersection tests. + +

KNOWN BUGS

+ This implementation is not fully robust. + instead. +
+ +
+ + + Initializes a new instance of the class. + + The to use. + + + + Returns a of fully noded s. + The s have the same context as their parent. + + + + + + Computes the noding for a collection of s. + Some Noders may add all these nodes to the input s; + others may only add some or none at all. + + + + + + + + + + + + + Computes all interior intersections in the collection of s, + and returns their s. + + Does NOT node the segStrings. + + + + A list of Coordinates for the intersections. + + + + Snaps segments to nodes created by segment intersections. + + + + + + Snaps segments to all vertices + + The list of segment strings to snap together + + + + Snaps segments to the vertices of a Segment String. + + + + + + Uses Snap Rounding to compute a rounded, + fully noded arrangement from a set of s. + + Implements the Snap Rounding technique described in + the papers by Hobby, Guibas & Marimont, and Goodrich et al. + Snap Rounding enforces that all vertices lie on a uniform grid, + which is determined by the provided . + Input vertices do not have to be rounded to this grid; + this will be done during the snap-rounding process. + + This implementation uses simple iteration over the line segments. + This is not an efficient approach for large sets of segments. + This implementation appears to be fully robust using an integer precision model. + It will function with non-integer precision models, but the + results are not 100% guaranteed to be correctly noded. + + + + + + Initializes a new instance of the class. + + The to use. + + + + Returns a of fully noded s. + The s have the same context as their parent. + + A Collection of NodedSegmentStrings representing the substrings + + + + Computes the noding for a collection of s. + Some Noders may add all these nodes to the input s; + others may only add some or none at all. + + A collection of NodedSegmentStrings + + + + + + + + + + Gets a list of the rounded coordinates. + Duplicate (collapsed) coordinates are removed. + + The coordinates to round + An array of rounded coordinates + + + + Computes all interior intersections in the collection of s, + and returns their s. + + Also adds the intersection nodes to the segments. + + + A list of s for the intersections. + + + + Computes nodes introduced as a result of snapping segments to snap points (hot pixels). + + + + + + + + + + + + This is where all the work of snapping to hot pixels gets done + (in a very inefficient brute-force way). + + + + + Computes nodes introduced as a result of + snapping segments to vertices of other segments. + + The list of segment strings to snap together + + + + Performs a brute-force comparison of every segment in each . + This has n^2 performance. + + + + + + + Finds intersections between line segments which will be snap-rounded, + and adds them as nodes to the segments. + + Intersections are detected and computed using full precision. + Snapping takes place in a subsequent phase. + + The intersection points are recorded, so that HotPixels can be created for them. + + To avoid robustness issues with vertices which lie very close to line segments + a heuristic is used: + nodes are created if a vertex lies within a tolerance distance + of the interior of a segment. + The tolerance distance is chosen to be significantly below the snap-rounding grid size. + This has empirically proven to eliminate noding failures. + + + + + Creates an intersector which finds all snapped interior intersections, + and adds them as nodes. + + The precision model to use + + + + Creates an intersector which finds all snapped interior intersections, + and adds them as nodes. + + the intersection distance tolerance + + + + Gets the created intersection nodes, + so they can be processed as hot pixels. + + A list of intersection points + + + + This method is called by clients + of the class to process + intersections for two segments of the + s being intersected. + Note that some clients (such as MonotoneChain s) may optimize away + this call for segment pairs which they have determined do not intersect + (e.g.by an disjoint envelope test). + + + + + If an endpoint of one segment is near + the interior of the other segment, add it as an intersection. + EXCEPT if the endpoint is also close to a segment endpoint + (since this can introduce "zigs" in the linework). + + This resolves situations where + a segment A endpoint is extremely close to another segment B, + but is not quite crossing.Due to robustness issues + in orientation detection, this can + result in the snapped segment A crossing segment B + without a node being introduced. + + + + + Always process all intersections + + Always false + + + + Uses Snap Rounding to compute a rounded, + fully noded arrangement from a set of s, + in a performant way, and avoiding unnecessary noding. + + Implements the Snap Rounding technique described in + the papers by Hobby, Guibas & Marimont, and Goodrich et al. + Snap Rounding enforces that all output vertices lie on a uniform grid, + which is determined by the provided . + + Input vertices do not have to be rounded to the grid beforehand; + this is done during the snap-rounding process. + In fact, rounding cannot be done a priori, + since rounding vertices by themselves can distort the rounded topology + of the arrangement (i.e. by moving segments away from hot pixels + that would otherwise intersect them, or by moving vertices + across segments). + + To minimize the number of introduced nodes, + the Snap-Rounding Noder avoids creating nodes + at edge vertices if there is no intersection or snap at that location. + However, if two different input edges contain identical segments, + each of the segment vertices will be noded. + This still provides fully-noded output. + This is the same behaviour provided by other noders, + such as + and . + + 1.17 + + + + The division factor used to determine + nearness distance tolerance for intersection detection. + + + + + Gets a Collection of NodedSegmentStrings representing the substrings + + + + + Computes the nodes in the snap-rounding line arrangement. + The nodes are added to the s provided as the input. + + A Collection of NodedSegmentStrings + + + + Detects interior intersections in the collection of {@link SegmentString}s, + and adds nodes for them to the segment strings. + Also creates HotPixel nodes for the intersection points. + + The input NodedSegmentStrings + + + + Creates HotPixels for each vertex in the input segStrings. + The HotPixels are not marked as nodes, since they will + only be nodes in the final line arrangement + if they interact with other segments(or they are already + created as intersection nodes). + + The input NodedSegmentStrings + + + + Gets a list of the rounded coordinates. + Duplicate (collapsed) coordinates are removed. + + The coordinates to round + Array of rounded coordinates + + + + Computes new segment strings which are rounded and contain + intersections added as a result of snapping segments to snap points (hot pixels). + + Segments to snap + The snapped segment strings + + + + Add snapped vertices to a segment string. + If the segment string collapses completely due to rounding, + null is returned. + + The segment string to snap + + The snapped segment string, or null if it collapses completely + + + + + Snaps a segment in a segmentString to HotPixels that it intersects. + + The segment start coordinate + The segment end coordinate + The segment string to add intersections to + The index of the segment/ + + + + Add nodes for any vertices in hot pixels that were + added as nodes during segment noding. + + A noded segment string + + + + Finds intersections between line segments which are being snapped, + and adds them as nodes. + + 1.17 + + + + Creates an intersector which finds all snapped intersections, + and adds them as nodes. + + The snapping tolerance distance + A snap index to use + + + + This method is called by clients + of the class to process + intersections for two segments of the s being intersected. + Note that some clients (such as MonotoneChains) may optimize away + this call for segment pairs which they have determined do not intersect + (e.g. by an disjoint envelope test). + + + + + If an endpoint of one segment is near + the interior of the other segment, add it as an intersection. + EXCEPT if the endpoint is also close to a segment endpoint + (since this can introduce "zigs" in the linework). + + This resolves situations where + a segment A endpoint is extremely close to another segment B, + but is not quite crossing. Due to robustness issues + in orientation detection, this can + result in the snapped segment A crossing segment B + without a node being introduced. + + + + + Test if two segments are adjacent segments on the same SegmentString. + Note that closed edges require a special check for the point shared by the beginning + and end segments. + + + + > + Always process all intersections> + false + + + + Nodes a set of segment strings + snapping vertices and intersection points together if + they lie within the given snap tolerance distance. + Vertices take priority over intersection points for snapping. + Input segment strings are generally only split at true node points + (i.e.the output segment strings are of maximal length in the output arrangement). + + The snap tolerance should be chosen to be as small as possible + while still producing a correct result. + It probably only needs to be small enough to eliminate + "nearly-coincident" segments, for which intersection points cannot be computed accurately. + This implies a factor of about 10e-12 + smaller than the magnitude of the segment coordinates. + + With an appropriate snap tolerance this algorithm appears to be very robust. + So far no failure cases have been found, + given a small enough snap tolerance. + + The correctness of the output is not verified by this noder. + If required this can be done by . + + 1.17 + + + + Creates a snapping noder using the given snap distance tolerance. + + Points are snapped if within this distance + + + > + A collection of s representing the substrings + + + Computes the noding of a set of s + A Collection of s + + + + Seeds the snap index with a small set of vertices + chosen quasi-randomly using a low-discrepancy sequence. + Seeding the snap index KdTree induces a more balanced tree. + This prevents monotonic runs of vertices + unbalancing the tree and causing poor query performance. + + The segStrings to be noded + + + + Computes all interior intersections in the collection of s, + and returns their s. + + Also adds the intersection nodes to the segments. + + A list of noded substrings + + + + An index providing fast creation and lookup of snap points. + + + + + Since points are added incrementally, this index needs to be dynamic. + This class also makes use of the KdTree support for a tolerance distance + for point equality. + + + + + Creates a snap point index using a specified distance tolerance. + + Points are snapped if within this distance + + + + Snaps a coordinate to an existing snap point, + if it is within the snap tolerance distance. + Otherwise adds the coordinate to the snap point index. + + The point to snap + The point it snapped to, or the input point + + + + Gets a value indicating the snapping tolerance value for the index + + + + + Gets a value indicating the depth of the tree + + + + + A wrapper for s which validates + the output arrangement is correctly noded. + An arrangement of line segments is fully noded if + there is no line segment + which has another segment intersecting its interior. + If the noding is not correct, a is thrown + with details of the first invalid location found. + + Martin Davis + + + + + Creates a noding validator wrapping the given + + The noder to validate + + + + Checks whether the output of the wrapped noder is fully noded. + Throws an exception if it is not. + + + + + + + + + A geometry service provider class + + + When overriding this class, you need to provide a public constructor with the following arguments: + + CoordinateSequenceFactoryA factory to create coordinate sequences + PrecisionModelA precision model + intspatial reference id (srid) + GeometryOverlayA class that bundles an overlay operation function set + CoordinateEqualityComparerA class that performs checks s for equality. + + + + + + + Creates an instance of this class, using the + as default and a precision model.
+ No is specified.
+ The function set for overlay operations is being used. +
+
+ + + Creates an instance of this class, using the + as default and a precision model. + No is specified + + The function set to perform overlay operations + + + + Creates an instance of this class, using the as default.
+ No is specified.
+ The default precision model is defined by .
+ The function set for overlay operations is being used. +
+
+ + + Creates an instance of this class, using the as default.
+ A value of is assigned to .
+ The default precision model is defined by .
+ The function set for overlay operations is being used. +
+
+ + + Creates an instance of this class, using a precision model as default.
+ No is specified.
+ The default coordinate sequence factory is defined by .
+ The function set for overlay operations is being used. +
+
+ + + Creates an instance of this class, using the provided , + and spatial reference Id (). + + The coordinate sequence factory to use. + The precision model. + The default spatial reference ID + + + + Creates an instance of this class, using the provided , + , a spatial reference Id () and + a . + + The coordinate sequence factory to use. + The precision model. + The default spatial reference ID + The geometry overlay function set to use. + The equality comparer for coordinates + + + + Gets or sets the default instance of . + + + Thrown when trying to set the value to . + + + + + Gets or sets a value indicating the operations to use for geometry overlay. + + A set of geometry overlay functions. + + + + Gets an object that is used to test 2 coordinates for equality. + + A coordinate equality tester object + + + + Gets the default spatial reference id + + + + + Gets or sets the coordiate sequence factory to use + + + + + Gets or sets the default precision model + + + + + Creates a precision model based on given precision model type + + The precision model type + + + + Creates a precision model based on given precision model. + + The precision model + + + + Creates a precision model based on the given scale factor. + + The scale factor + The precision model. + + + + Creates or retrieves a geometry factory using , and + . + + A geometry factory + + + + Creates or retrieves a geometry factory using , and + . + + A geometry factory + + + + Creates or retrieves a geometry factory using , and + . + + A geometry factory + + + + Creates or retrieves a geometry factory using , and + . + + The precision model to use. + A geometry factory + + + + Creates or retrieves a geometry factory using , and + . + + The precision model to use. + The spatial reference id. + A geometry factory + + + + Creates or retrieves a geometry factory using , and + . + + The precision model to use. + The spatial reference id. + + A geometry factory + + + + Creates a based on the given parameters. + + + The value for . + + + The value for . + + + The value for . + + + A that has the given values. + + + + This method is expected to be safe to call from any number of threads at once. + + + Implementations must make sure to use a constructor which + is properly assigning to the factory. + + + Although the result for a given set of parameters is cached, there is no guarantee that, + once this method is called with some set of parameters, it will never be called again + with an exactly equal set of parameters. When this does happen, an arbitrary result is + chosen as the winner (not necessarily the first one to start or finish), and all other + results are discarded. + + + + + + Computes the boundary of a . + Allows specifying the to be used. + This operation will always return a of the appropriate + dimension for the boundary (even if the input geometry is empty). + The boundary of zero-dimensional geometries (Points) is + always the empty . + + Martin Davis + + + + Computes a geometry representing the boundary of a geometry. + + The input geometry. + The computed boundary. + + + + Computes a geometry representing the boundary of a geometry, + using an explicit . + + The input geometry. + The Boundary Node Rule to use. + The computed boundary. + + + + Tests if a geometry has a boundary (it is non-empty).
+ The semantics are: + + Empty geometries do not have boundaries. + Points do not have boundaries. + For linear geometries the existence of the boundary + is determined by the . + Non-empty polygons always have a boundary. + +
+ The geometry providing the boundary + The Boundary Node Rule to use + true if the boundary exists +
+ + + Initializes a new instance of the class for the given geometry. + + The input geometry. + + + + Initializes a new instance of the class for the given geometry. + + The input geometry. + Tthe Boundary Node Rule to use. + + + + Gets the computed boundary. + + The boundary geometry. + + + + A map which maintains the edges in sorted order around the node. + + + + + Stores an integer count, for use as a Map entry. + + Martin Davis + + + + Builds the buffer geometry for a given input geometry and precision model. + Allows setting the level of approximation for circular arcs, + and the precision model in which to carry out the computation. + + + When computing buffers in floating point double-precision + it can happen that the process of iterated noding can fail to converge (terminate). + In this case a will be thrown. + Retrying the computation in a fixed precision + can produce more robust results. + + + + Compute the change in depth as an edge is crossed from R to L + + + + Initializes a new instance of the class using the given parameters. + + The buffer parameters to use. + + + + Sets the precision model to use during the curve computation and noding, + if it is different to the precision model of the Geometry. + + + If the precision model is less than the precision of the Geometry precision model, + the Geometry must have previously been rounded to that precision. + + + + + Sets the to use during noding. + This allows choosing fast but non-robust noding, or slower + but robust noding. + + + + + Sets whether the offset curve is generated + using the inverted orientation of input rings. + This allows generating a buffer(0) polygon from the smaller lobes + of self-crossing rings. + + + + + Inserted edges are checked to see if an identical edge already exists. + If so, the edge is not inserted, but its label is merged + with the existing edge. + + + + + Completes the building of the input subgraphs by depth-labelling them, + and adds them to the PolygonBuilder. + + + The subgraph list must be sorted in rightmost-coordinate order. + + the subgraphs to build + the PolygonBuilder which will build the final polygons + + + + Gets the standard result for an empty buffer. + Since buffer always returns a polygonal result, this is chosen to be an empty polygon. + + The empty result geometry + + + + Creates all the raw offset curves for a buffer of a Geometry. + Raw curves need to be noded together and polygonized to form the final buffer area. + + + + + + + The input geometry + The offset distance + A precision model + The buffer parameters + + + + Gets or sets a value indicating whether the offset curve is generated + using the inverted orientation of input rings. + This allows generating a buffer(0) polygon from the smaller lobes + of self-crossing rings. + + + + + Computes orientation of a ring using a signed-area orientation test. + For invalid (self-crossing) rings this ensures the largest enclosed area + is taken to be the interior of the ring. + This produces a more sensible result when + used for repairing polygonal geometry via buffer-by-zero. + For buffer use the lower robustness of orientation-by-area + doesn't matter, since narrow or flat rings + produce an acceptable offset curve for either orientation. + + The ring coordinates + true if the ring is CCW + + + + Computes the set of raw offset curves for the buffer. + Each offset curve has an attached {Label} indicating + its left and right location. + + A Collection of SegmentStrings representing the raw buffer curves. + + + + Creates a {SegmentString} for a coordinate list which is a raw offset curve, + and adds it to the list of buffer curves. + The SegmentString is tagged with a Label giving the topology of the curve. + The curve may be oriented in either direction. + If the curve is oriented CW, the locations will be: + Left: Location.Exterior. + Right: Location.Interior. + + + + + + + + + + + + + + + + + Add a Point to the graph. + + + + + + Keeps only valid coordinates, and removes repeated points. + + The coordinates to clean + An array of clean coordinates + + + + + + + + + + Adds an offset curve for a polygon ring. + The side and left and right topological location arguments + assume that the ring is oriented CW. + If the ring is in the opposite orientation, + the left and right locations must be interchanged and the side flipped. + + The coordinates of the ring (must not contain repeated points). + The distance at which to create the buffer. + The side of the ring on which to construct the buffer line. + The location on the L side of the ring (if it is CW). + The location on the R side of the ring (if it is CW). + + + + Tests whether the offset curve for a ring is fully inverted. + An inverted ("inside-out") curve occurs in some specific situations + involving a buffer distance which should result in a fully-eroded (empty) buffer. + It can happen that the sides of a small, convex polygon + produce offset segments which all cross one another to form + a curve with inverted orientation.
+ This happens at buffer distances slightly greater than the distance at + which the buffer should disappear.
+ The inverted curve will produce an incorrect non-empty buffer (for a shell) + or an incorrect hole (for a hole). + It must be discarded from the set of offset curves used in the buffer. + Heuristics are used to reduce the number of cases which area checked, + for efficiency and correctness. + + See +
+ the input ring + the buffer distance + the generated offset curve + true if the offset curve is inverted +
+ + + Computes the maximum distance out of a set of points to a linestring. + + The points + The linestring vertices + The maximum distance + + + + Tests whether a ring buffer is eroded completely (is empty) + based on simple heuristics. + + The is assumed to contain no repeated points. + It may be degenerate (i.e. contain only 1, 2, or 3 points). + In this case it has no area, and hence has a minimum diameter of 0. + + + + + + + + Tests whether a triangular ring would be eroded completely by the given + buffer distance. + This is a precise test. It uses the fact that the inner buffer of a + triangle converges on the inCentre of the triangle (the point + equidistant from all sides). If the buffer distance is greater than the + distance of the inCentre from a side, the triangle will be eroded completely. + This test is important, since it removes a problematic case where + the buffer distance is slightly larger than the inCentre distance. + In this case the triangle buffer curve "inverts" with incorrect topology, + producing an incorrect hole in the buffer. + + + + + + + + Simplifies a buffer input line to remove concavities with shallow depth. + + + + The most important benefit of doing this + is to reduce the number of points and the complexity of + shape which will be buffered. + It also reduces the risk of gores created by + the quantized fillet arcs (although this issue + should be eliminated in any case by the + offset curve generation logic). + + + A key aspect of the simplification is that it + affects inside (concave or inward) corners only. + Convex (outward) corners are preserved, since they + are required to ensure that the generated buffer curve + lies at the correct distance from the input geometry. + + + Another important heuristic used is that the end segments + of the input are never simplified. This ensures that + the client buffer code is able to generate end caps faithfully. + + + No attempt is made to avoid self-intersections in the output. + This is acceptable for use for generating a buffer offset curve, + since the buffer algorithm is insensitive to invalid polygonal + geometry. However, + this means that this algorithm + cannot be used as a general-purpose polygon simplification technique. + + + Martin Davis + + + + Simplify the input coordinate list. + If the distance tolerance is positive, + concavities on the LEFT side of the line are simplified. + If the supplied distance tolerance is negative, + concavities on the RIGHT side of the line are simplified. + + The coordinate list to simplify + simplification distance tolerance to use + The simplified coordinate list + + + + Simplify the input coordinate list. + + + If the distance tolerance is positive, concavities on the LEFT side of the line are simplified. + If the supplied distance tolerance is negative, concavities on the RIGHT side of the line are simplified. + + Simplification distance tolerance to use + + The simplified coordinates list + + + + + Uses a sliding window containing 3 vertices to detect shallow angles + in which the middle vertex can be deleted, since it does not + affect the shape of the resulting buffer in a significant way. + + + + + + Finds the next non-deleted index, or the end of the point array if none + + The start index to search from + The next non-deleted index, if any
+ or _inputLine.Length if there are no more non-deleted indices +
+
+ + + Checks for shallowness over a sample of points in the given section. + This helps to prevent the simplification from incrementally + "skipping" over points which are in fact non-shallow. + + A coordinate of section + A coordinate of section + The start index of section + The end index of section + The tolerated distance + + + + Computes the buffer of a geometry, for both positive and negative buffer distances. + + + + In GIS, the positive (or negative) buffer of a geometry is defined as + the Minkowski sum (or difference) of the geometry + with a circle of radius equal to the absolute value of the buffer distance. + In the CAD/CAM world buffers are known as offset curves. + In morphological analysis the + operation of positive and negative buffering + is referred to as erosion and dilation + + + The buffer operation always returns a polygonal result. + The negative or zero-distance buffer of lines and points is always an empty . + + + Since true buffer curves may contain circular arcs, + computed buffer polygons are only approximations to the true geometry. + The user can control the accuracy of the approximation by specifying + the number of linear segments used to approximate arcs. + This is specified via + or . + + + The of a linear buffer may be specified. + The following end cap styles are supported: +
    +
  • - the usual round end caps
  • +
  • - end caps are truncated flat at the line ends
  • +
  • - end caps are squared off at the buffer distance beyond the line ends
  • +
+
+ + The of the corners in a buffer may be specified. + The following join styles are supported: +
    +
  • - the usual round join
  • +
  • - corners are "sharp" (up to a distance limit})
  • +
  • - corners are beveled (clipped off)
  • +
+
+ + The buffer algorithm may perform simplification on the input to increase performance. + The simplification is performed a way that always increases the buffer area + (so that the simplified input covers the original input). + The degree of simplification can be specified with , + with a used otherwise. + Note that if the buffer distance is zero then so is the computed simplify tolerance, + no matter what the simplify factor. + + + Buffer results are always valid geometry. + Given this, computing a zero-width buffer of an invalid polygonal geometry is + an effective way to "validify" the geometry. + Note however that in the case of self-intersecting "bow-tie" geometries, + only the largest enclosed area will be retained. + +
+
+ + + A number of digits of precision which leaves some computational "headroom" + for floating point operations. + + + This value should be less than the decimal precision of double-precision values (16). + + + + + Compute a scale factor to limit the precision of + a given combination of Geometry and buffer distance. + The scale factor is determined by + the number of digits of precision in the (geometry + buffer distance), + limited by the supplied value. + + The scale factor is based on the absolute magnitude of the (geometry + buffer distance). + since this determines the number of digits of precision which must be handled. + + the Geometry being buffered + the buffer distance + the max # of digits that should be allowed by + the precision determined by the computed scale factor + + a scale factor for the buffer computation + + + + Computes the buffer of a geometry for a given buffer distance. + + the geometry to buffer + the buffer distance + the buffer of the input geometry + + + + Computes the buffer for a geometry for a given buffer distance + and accuracy of approximation. + + the geometry to buffer + the buffer distance + the buffer parameters to use + the buffer of the input geometry + + + + Computes the buffer for a geometry for a given buffer distance + and accuracy of approximation. + + the geometry to buffer + the buffer distance + the number of segments used to approximate a quarter circle + the buffer of the input geometry + + + + Buffers a geometry with distance zero. + The result can be computed using the maximum-signed-area orientation, + or by combining both orientations. + + This can be used to fix an invalid polygonal geometry to be valid + (i.e.with no self-intersections). + For some uses(e.g.fixing the result of a simplification) + a better result is produced by using only the max-area orientation. + Other uses (e.g.fixing geometry) require both orientations to be used. + + This function is for INTERNAL use only. + + The polygonal geometry to buffer by zero + A flag indicating if both orientations of input rings should be used + The buffered polygonal geometry + + + + Combines the elements of two polygonal geometries together. + The input geometries must be non-adjacent, to avoid + creating an invalid result. + + A polygonal geometry (which may be empty) + Another polygonal geometry (which may be empty) + A combined polygonal geometry + + + + Initializes a buffer computation for the given geometry + + the geometry to buffer + + + + Initializes a buffer computation for the given geometry + with the given set of parameters + + the geometry to buffer + the buffer parameters to use + + + + Gets or sets the number of line segments in a quarter-circle + used to approximate angle fillets for round end caps and joins. + + + + + Returns the buffer computed for a geometry for a given buffer distance. + + the buffer distance + the buffer of the input geometry + + + + A value class containing the parameters which + specify how a buffer should be constructed. + + The parameters allow control over: + + Quadrant segments (accuracy of approximation for circular arcs) + End Cap style + Join style + Mitre limit + whether the buffer is single-sided + + + Martin Davis + + + + The default number of facets into which to divide a fillet of 90 degrees.
+ A value of 8 gives less than 2% max error in the buffer distance. + For a max error of < 1%, use QS = 12. + For a max error of < 0.1%, use QS = 18. +
+
+ + + The default number of facets into which to divide a fillet of 90 degrees.
+ A value of 8 gives less than 2% max error in the buffer distance. + For a max error of < 1%, use QS = 12. + For a max error of < 0.1%, use QS = 18. +
+
+ + + The default mitre limit + Allows fairly pointy mitres. + + + + + The default simplify factor. + Provides an accuracy of about 1%, which matches + the accuracy of the parameter. + + + + + Creates a default set of parameters + + + + + Creates a set of parameters with the given quadrantSegments value. + + The number of quadrant segments to use + + + + Creates a set of parameters with the + given quadrantSegments and endCapStyle values. + + the number of quadrant segments to use + the end cap style to use + + + + Creates a set of parameters with the + given parameter values. + + the number of quadrant segments to use + the end cap style to use + the join style to use + the mitre limit to use + + + + Gets or sets the number of line segments in a quarter-circle + used to approximate angle fillets in round endcaps and joins. + The value should be at least 1. + + This determines the + error in the approximation to the true buffer curve.
+ The default value of 8 gives less than 2% error in the buffer distance. + For an error of < 1%, use QS = 12. + For an error of < 0.1%, use QS = 18. + The error is always less than the buffer distance + (in other words, the computed buffer curve is always inside the true + curve). +
+
+ + + Computes the maximum distance error due to a given level of approximation to a true arc. + + The number of segments used to approximate a quarter-circle + The error of approximation + + + + Gets or sets the end cap style of the generated buffer. + + + + The styles supported are , + , and + . + + The default is . + + + + + Gets/Sets the join style for outside (reflex) corners between line segments. + + + The styles supported are , + and + The default is + + + + + Sets the limit on the mitre ratio used for very sharp corners. + + + + The mitre ratio is the ratio of the distance from the corner + to the end of the mitred offset corner. + When two line segments meet at a sharp angle, + a miter join will extend far beyond the original geometry. + (and in the extreme case will be infinitely far.) + To prevent unreasonable geometry, the mitre limit + allows controlling the maximum length of the join corner. + Corners with a ratio which exceed the limit will be beveled. + + + + + + Gets or sets whether the computed buffer should be single-sided. + A single-sided buffer is constructed on only one side of each input line. + + The side used is determined by the sign of the buffer distance: + + a positive distance indicates the left-hand side + a negative distance indicates the right-hand side + + The single-sided buffer of point geometries is the same as the regular buffer. + + The End Cap Style for single-sided buffers is always ignored, + and forced to the equivalent of . + + + + + + Factor used to determine the simplify distance tolerance + for input simplification. + Simplifying can increase the performance of computing buffers. + Generally the simplify factor should be greater than 0. + Values between 0.01 and .1 produce relatively good accuracy for the generate buffer. + Larger values sacrifice accuracy in return for performance. + + + + + Creates a copy + + + + + + A connected subset of the graph of + DirectedEdges and Nodes. + Its edges will generate either + a single polygon in the complete buffer, with zero or more holes, or + one or more connected holes. + + + + + + + + + + + + + + + + + + + + Gets the rightmost coordinate in the edges of the subgraph. + + + + + Creates the subgraph consisting of all edges reachable from this node. + Finds the edges in the graph and the rightmost coordinate. + + A node to start the graph traversal from. + + + + Adds all nodes and edges reachable from this node to the subgraph. + Uses an explicit stack to avoid a large depth of recursion. + + A node known to be in the subgraph. + + + + Adds the argument node and all its out edges to the subgraph + + The node to add. + The current set of nodes being traversed. + + + + + + + + + + + + + + + Compute depths for all dirEdges via breadth-first traversal of nodes in graph. + + Edge to start processing with. + + + + + + + + + + + + + + + + Find all edges whose depths indicates that they are in the result area(s). + Since we want polygon shells to be + oriented CW, choose dirEdges with the interior of the result on the RHS. + Mark them as being in the result. + Interior Area edges are the result of dimensional collapses. + They do not form part of the result area boundary. + + + + + BufferSubgraphs are compared on the x-value of their rightmost Coordinate. + This defines a partial ordering on the graphs such that: + g1 >= g2 - Ring(g2) does not contain Ring(g1) + where Polygon(g) is the buffer polygon that is built from g. + This relationship is used to sort the BufferSubgraphs so that shells are guaranteed to + be built before holes. + + + + + End cap style constants + + + + + Specifies a round line buffer end cap style. + + + + + Specifies a flat line buffer end cap style. + + + + + Specifies a square line buffer end cap style. + + + + + Join style constants + + + + + Specifies a round join style. + + + + + Specifies a mitre join style. + + + + + Specifies a bevel join style. + + + + + Computes an offset curve from a geometry. + The offset curve is a linear geometry which is offset a specified distance + from the input. + If the offset distance is positive the curve lies on the left side of the input; + if it is negative the curve is on the right side. + + The offset curve of a line is a . + The offset curve of a Point is an empty . + The offset curve of a Polygon is the boundary of the polygon buffer (which + may be a . + For a collection the output is a {@link MultiLineString} of the element offset curves. + + The offset curve is computed as a single contiguous section of the geometry buffer boundary. + In some geometric situations this definition is ill-defined. + This algorithm provides a "best-effort" interpretation. + In particular: + + For self-intersecting lines, the buffer boundary includes + offset lines for both left and right sides of the input line. + Only a single contiguous portion on the specified side is returned. + If the offset corresponds to buffer holes, only the largest hole is used. + + Offset curves support setting the number of quadrant segments, + the join style, and the mitre limit(if applicable) via + the . + + Martin Davis + + + + The nearness tolerance between the raw offset linework and the buffer curve. + + + + + Computes the offset curve of a geometry at a given distance. + + A geometry + the offset distance (positive = left, negative = right) + The offset curve + + + + Computes the offset curve of a geometry at a given distance, + and for a specified quadrant segments, join style and mitre limit. + + A geometry + The offset distance (positive = left, negative = right) + The quadrant segments + The join style + The mitre limit + The offset curve + + + + Creates a new instance for computing an offset curve for a geometryat a given distance. + with default quadrant segments( + and join style (). + + The geometry + A distance value + + + Creates a new instance for computing an offset curve for a geometry at a given distance. + allowing the quadrant segments and join style and mitre limit to be set + via {@link BufferParameters}. + + @param geom + @param distance + @param bufParams + + + + Gets the computed offset curve. + + The offset curve geometry + + + + Force LinearRings to be LineStrings. + + A geometry, which may be a LinearRing + A geometry which will be a LineString or MulitLineString + + + + Gets the raw offset line. + The quadrant segments and join style and mitre limit to be set + via . + + The raw offset line may contain loops and other artifacts which are + not present in the true offset curve. + The raw offset line is matched to the buffer ring (which is clean) + to extract the offset curve. + + The LineString to offset + The offset distance + The buffer parameters to use + The raw offset line + + + + Gets the raw offset line, with default buffer parameters. + + The LineString to offset + The offset distance + The raw offset line + + + + Extracts the largest polygon by area from a geometry. + Used here to avoid issues with non-robust buffer results which have spurious extra polygons. + + A geometry + The polygon element of largest area + + + + An action to match a raw offset curve segment + to segments in the buffer ring + and mark them as being in the offset curve. + + Martin Davis + + + + Extracts a section of a ring of coordinates, starting at a given index, + and keeping coordinates which are flagged as being required. + + The ring of points + The index of the start coordinate + A flag indicating if coordinate is to be extracted + + + + Computes the raw offset curve for a + single component (ring, line or point). + A raw offset curve line is not noded - + it may contain self-intersections (and usually will).g + The final buffer polygon is computed by forming a topological graph + of all the noded raw curves and tracing outside contours. + The points in the raw curve are rounded + to a given . + + + + + Gets the buffer parameters being used to generate the curve. + + + + + This method handles single points as well as LineStrings. + LineStrings are assumed not to be closed (the function will not + fail for closed lines, but will generate superfluous line caps). + + The vertices of the line to offset + The offset distance + A Coordinate array representing the curve
+ or null if the curve is empty +
+
+ + + Tests whether the offset curve for line or point geometries + at the given offset distance is empty (does not exist). + This is the case if: + + the distance is zero + the distance is negative, except for the case of singled-sided buffers + + + The offset curve distance + true if the offset curve is empty + + + + This method handles the degenerate cases of single points and lines, + as well as rings. + + A Coordinate array representing the curve
+ or null if the curve is empty
+
+ + + This method handles the degenerate cases of single points and lines, + as well as rings. + + A Coordinate array representing the curve
+ or null if the curve is empty
+
+ + + Computes the distance tolerance to use during input + line simplification. + + The buffer distance + The simplification tolerance + + + + Creates all the raw offset curves for a buffer of a Geometry. + Raw curves need to be noded together and polygonized to form the final buffer area. + + + + + + + + + + + + + Gets or sets a value indicating whether the offset curve is generated + using the inverted orientation of input rings. + This allows generating a buffer(0) polygon from the smaller lobes + of self-crossing rings. + + + + + Computes orientation of a ring using a signed-area orientation test. + For invalid (self-crossing) rings this ensures the largest enclosed area + is taken to be the interior of the ring. + This produces a more sensible result when + used for repairing polygonal geometry via buffer-by-zero. + For buffer use the lower robustness of orientation-by-area + doesn't matter, since narrow or flat rings + produce an acceptable offset curve for either orientation. + + The ring coordinates + true if the ring is CCW + + + + Computes the set of raw offset curves for the buffer. + Each offset curve has an attached {Label} indicating + its left and right location. + + A Collection of SegmentStrings representing the raw buffer curves. + + + + Creates a {SegmentString} for a coordinate list which is a raw offset curve, + and adds it to the list of buffer curves. + The SegmentString is tagged with a Label giving the topology of the curve. + The curve may be oriented in either direction. + If the curve is oriented CW, the locations will be: + Left: Location.Exterior. + Right: Location.Interior. + + + + + + + + + + + + + + + + + Add a Point to the graph. + + + + + + Keeps only valid coordinates, and removes repeated points. + + The coordinates to clean + An array of clean coordinates + + + + + + + + + + Adds an offset curve for a polygon ring. + The side and left and right topological location arguments + assume that the ring is oriented CW. + If the ring is in the opposite orientation, + the left and right locations must be interchanged and the side flipped. + + The coordinates of the ring (must not contain repeated points). + The distance at which to create the buffer. + The side of the ring on which to construct the buffer line. + The location on the L side of the ring (if it is CW). + The location on the R side of the ring (if it is CW). + + +
+ Tests whether the offset curve for a ring is fully inverted. + An inverted ("inside-out") curve occurs in some specific situations + involving a buffer distance which should result in a fully-eroded (empty) buffer. + It can happen that the sides of a small, convex polygon + produce offset segments which all cross one another to form + a curve with inverted orientation.
+ This happens at buffer distances slightly greater than the distance at + which the buffer should disappear.
+ The inverted curve will produce an incorrect non-empty buffer (for a shell) + or an incorrect hole (for a hole). + It must be discarded from the set of offset curves used in the buffer. + Heuristics are used to reduce the number of cases which area checked, + for efficiency and correctness. + + See
+
+ the input ring + the buffer distance + the generated offset curve + true if the offset curve is inverted + + + + Computes the maximum distance out of a set of points to a linestring. + + The points + The linestring vertices + The maximum distance + + + + Tests whether a ring buffer is eroded completely (is empty) + based on simple heuristics. + + The is assumed to contain no repeated points. + It may be degenerate (i.e. contain only 1, 2, or 3 points). + In this case it has no area, and hence has a minimum diameter of 0. + + + + + + + + Tests whether a triangular ring would be eroded completely by the given + buffer distance. + This is a precise test. It uses the fact that the inner buffer of a + triangle converges on the inCentre of the triangle (the point + equidistant from all sides). If the buffer distance is greater than the + distance of the inCentre from a side, the triangle will be eroded completely. + This test is important, since it removes a problematic case where + the buffer distance is slightly larger than the inCentre distance. + In this case the triangle buffer curve "inverts" with incorrect topology, + producing an incorrect hole in the buffer. + + + + + + + + A list of the vertices in a constructed offset curve. + + Automatically removes close adjacent vertices. + Martin Davis + + + + Gets/Sets the precision model to use when adding new points. + + + + + The distance below which two adjacent points on the curve are considered to be coincident. + + This is chosen to be a small fraction of the offset distance. + + + + Function to add a point + + + The point is only added if evaluates to false. + + The point to add. + + + + Tests whether the given point duplicates the previous point in the list (up to tolerance) + + The point to test + true if the point duplicates the previous point + + + + Automatically closes the ring (if it not alread is). + + + + + Gets the Coordinates for the curve. + + + + + + + + Generates segments which form an offset curve. + Supports all end cap and join options + provided for buffering. + This algorithm implements various heuristics to + produce smoother, simpler curves which are + still within a reasonable tolerance of the + true curve. + + Martin Davis + + + + Factor which controls how close offset segments can be to + skip adding a filler or mitre. + + + + + Factor which controls how close curve vertices on inside turns can be to be snapped + + + + + Factor which controls how close curve vertices can be to be snapped + + + + + Factor which determines how short closing segs can be for round buffers + + + + + The max error of approximation (distance) between a quad segment and the true fillet curve + + + + + The angle quantum with which to approximate a fillet curve + (based on the input # of quadrant segments) + + + + + The Closing Segment Length Factor controls how long + "closing segments" are. Closing segments are added + at the middle of inside corners to ensure a smoother + boundary for the buffer offset curve. + In some cases (particularly for round joins with default-or-better + quantization) the closing segments can be made quite short. + This substantially improves performance (due to fewer intersections being created). + + A closingSegFactor of 0 results in lines to the corner vertex + A closingSegFactor of 1 results in lines halfway to the corner vertex + A closingSegFactor of 80 results in lines 1/81 of the way to the corner vertex + (this option is reasonable for the very common default situation of round joins + and quadrantSegs >= 8) + + + + + + Gets whether the input has a narrow concave angle + (relative to the offset distance). + In this case the generated offset curve will contain self-intersections + and heuristic closing segments. + This is expected behaviour in the case of buffer curves. + For pure offset curves, + the output needs to be further treated + before it can be used. + + + + + Add last offset point + + + + + Adds the offset points for an outside (convex) turn + + + + + Adds the offset points for an inside (concave) turn. + + + + + + + Compute an offset segment for an input segment on a given side and at a given distance. + The offset points are computed in full double precision, for accuracy. + + The segment to offset + The side of the segment the offset lies on + The offset distance + The points computed for the offset segment + + + + Add an end cap around point , terminating a line segment coming from + + + + + + + Adds a mitre join connecting two convex offset segments. + The mitre is beveled if it exceeds the mitre limit factor. + The mitre limit is intended to prevent extremely long corners occurring. + If the mitre limit is very small it can cause unwanted artifacts around fairly flat corners. + This is prevented by using a simple bevel join in this case. + In other words, the limit prevents the corner from getting too long, + but it won't force it to be very short/flat. + + A corner point + The first offset segment + The second offset segment + The offset distance + + + + Adds a limited mitre join connecting two convex offset segments. + A limited mitre join is beveled at the distance + determined by the mitre limit factor, + or as a standard bevel join, whichever is further. + + The first offset segment + The second offset segment + The offset distance + The mitre limit distance + + + + Projects a point to a given distance in a given direction angle. + + The point to project + The projection distance + The direction angle (in radians) + The projected point + + + + Adds a bevel join connecting the two offset segments + around a reflex corner. + + The first offset segment + The second offset segment + + + + Add points for a circular fillet around a convex corner. + Adds the start and end points + + Base point of curve + Start point of fillet curve + Endpoint of fillet curve + The orientation of the fillet + The radius of the fillet + + + + Adds points for a circular fillet arc + between two specified angles. + The start and end point for the fillet are not added - + the caller must add them if required. + + The center point + Is -1 for a angle, 1 for a angle + The start angle of the fillet + The end angle of the fillet + The radius of the fillet + + + + Creates a circle around a point + + + + + Creates a square around a point + + + + + A dynamic list of the vertices in a constructed offset curve. + Automatically removes adjacent vertices + which are closer than a given tolerance. + + Martin Davis + + + + The distance below which two adjacent points on the curve + are considered to be coincident.
+ This is chosen to be a small fraction of the offset distance. +
+
+ + + Tests whether the given point is redundant + relative to the previous + point in the list (up to tolerance). + + + true if the point is redundant + + + + Computes the raw offset curve for a single component (ring, line or point). + + + A raw offset curve line is not noded - it may contain self-intersections (and usually will). + The final buffer polygon is computed by forming a topological graph + of all the noded raw curves and tracing outside contours. + The points in the raw curve are rounded to the required precision model. + + + + + The angle quantum with which to approximate a fillet curve + (based on the input # of quadrant segments) + + + + + The max error of approximation (distance) between a quad segment and the true fillet curve + + + + + Factor which controls how close curve vertices can be to be snapped + + + + + Factor which controls how close offset segments can be to + skip adding a filler or mitre. + + + + + Factor which controls how close curve vertices on inside turns can be to be snapped + + + + + Factor which determines how short closing segs can be for round buffers + + + + + The Closing Segment Factor controls how long + "closing segments" are. Closing segments are added + at the middle of inside corners to ensure a smoother + boundary for the buffer offset curve.
+ In some cases (particularly for round joins with default-or-better + quantization) the closing segments can be made quite short. + This substantially improves performance (due to fewer intersections being created). +
+ A closingSegFactor of 0 results in lines to the corner vertex
+ A closingSegFactor of 1 results in lines halfway to the corner vertex
+ A closingSegFactor of 80 results in lines 1/81 of the way to the corner vertex + (this option is reasonable for the very common default situation of round joins + and quadrantSegs >= 8) +
+
+ + + This method handles single points as well as lines. + Lines are assumed to not be closed (the function will not + fail for closed lines, but will generate superfluous line caps). + + a List of Coordinate[] + + + + This method handles the degenerate cases of single points and lines, as well as rings. + + a List of Coordinate[] + + + + This method handles the degenerate cases of single points and lines, as well as rings. + + a List of Coordinate[] + + + + Use a value which results in a potential distance error which is + significantly less than the error due to + the quadrant segment discretization. + For QS = 8 a value of 100 is reasonable. + This should produce a maximum of 1% distance error. + + + + + Computes the distance tolerance to use during input + line simplification. + + The buffer distance + The simplification tolerance + + + + Adds the offset points for an outside (convex) turn + + + + + + + + Adds the offset points for an inside (concave) turn. + + + + + + + Add last offset point + + + + + Compute an offset segment for an input segment on a given side and at a given distance. + The offset points are computed in full double precision, for accuracy. + + The segment to offset + The side of the segment () the offset lies on + The offset distance + The points computed for the offset segment + + + + Add an end cap around point p1, terminating a line segment coming from p0 + + + + + Adds a mitre join connecting the two reflex offset segments. + The mitre will be beveled if it exceeds the mitre ratio limit. + + The base point + The first offset segment + The second offset segment + The offset distance + + + + Adds a limited mitre join connecting the two reflex offset segments. + + + A limited mitre is a mitre which is beveled at the distance + determined by the mitre ratio limit. + + The first offset segment + The second offset segment + The offset distance + The mitre limit ratio + + + + Adds a bevel join connecting the two offset segments around a reflex corner. + + The first offset segment + The second offset segment + + + + Add points for a circular fillet around a reflex corner. Adds the start and end points + + Base point of curve + Start point of fillet curve + Endpoint of fillet curve + The orientation of the fillet + The radius of the fillet + + + + Adds points for a circular fillet arc between two specified angles. + + + The start and end point for the fillet are not added - the caller must add them if required. + + The point around which to add the fillet points + The start angle (in radians) + The end angle (in radians) + Is -1 for a CW angle, 1 for a CCW angle + The radius of the fillet + + + + Adds a CW circle around a point + + + + + Adds a CW square around a point + + + + + A RightmostEdgeFinder find the DirectedEdge in a list which has the highest coordinate, + and which is oriented L to R at that point. (I.e. the right side is on the RHS of the edge.) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A spatial index over a segment sequence + using s. + + Martin Davis + + + + Locates a subgraph inside a set of subgraphs, + in order to determine the outside depth of the subgraph. + The input subgraphs are assumed to have had depths + already calculated for their edges. + + + + + + + + + + + + + + + + + + Finds all non-horizontal segments intersecting the stabbing line. + The stabbing line is the ray to the right of stabbingRayLeftPt. + + The left-hand origin of the stabbing line. + A List of {DepthSegments} intersecting the stabbing line. + + + + Finds all non-horizontal segments intersecting the stabbing line + in the list of dirEdges. + The stabbing line is the ray to the right of stabbingRayLeftPt. + + The left-hand origin of the stabbing line. + + The current list of DepthSegments intersecting the stabbing line. + + + + Finds all non-horizontal segments intersecting the stabbing line + in the input dirEdge. + The stabbing line is the ray to the right of stabbingRayLeftPt. + + The left-hand origin of the stabbing line. + + The current list of DepthSegments intersecting the stabbing line. + + + + A segment from a directed edge which has been assigned a depth value + for its sides. + + + + + Gets or sets the depth to the left of this segment + + + + + Initializes this DepthSegments + + A line segment + A depth value + + + + Defines a comparison operation on s + which orders them left to right. + + + Assumes the segments are normalized. + + The definition of ordering is: + + -1if DS1.seg is left of or below DS2.seg (DS1 < DS2). + 1if DS1.seg is right of or above DS2.seg (DS1 > DS2). + 0if the segments are identical + + Known Bugs: + + The logic does not obey the contract. + This is acceptable for the intended usage, but may cause problems if used with some + utilities in the .Net standard library (e.g. . + + + A DepthSegment + The comparison value + + + + Finds the approximate maximum distance from a buffer curve to + the originating geometry. + + The approximate maximum distance is determined by testing + all vertices in the buffer curve, as well + as midpoints of the curve segments. + Due to the way buffer curves are constructed, this + should be a very close approximation. + This is similar to the Discrete Oriented Hausdorff distance + from the buffer curve to the input. + + mbdavis + + + + Validates that a given buffer curve lies an appropriate distance + from the input generating it. + + + Useful only for round buffers (cap and join). + Can be used for either positive or negative distances. + + This is a heuristic test, and may return false positive results + (I.e. it may fail to detect an invalid result.) + It should never return a false negative result, however + (I.e. it should never report a valid result as invalid.) + + mbdavis + + + + Gets a geometry which indicates the location and nature of a validation failure. + + The indicator is a line segment showing the location and size + of the distance discrepancy. + + + A geometric error indicator + or null, if no error was found + + + + Checks that two geometries are at least a minimum distance apart. + + A geometry + A geometry + The minimum distance the geometries should be separated by + + + + Checks that the furthest distance from the buffer curve to the input + is less than the given maximum distance. + + + This uses the Oriented Hausdorff distance metric. It corresponds to finding + the point on the buffer curve which is furthest from some point on the input. + + A geometry + A geometry + The maximum distance that a buffer result can be from the input + + + + Validates that the result of a buffer operation + is geometrically correct, within a computed tolerance. + + + This is a heuristic test, and may return false positive results + (I.e. it may fail to detect an invalid result.) + It should never return a false negative result, however + (I.e. it should never report a valid result as invalid.) + This test may be (much) more expensive than the original buffer computation. + + Martin Davis + + + Checks whether the geometry buffer is valid, and returns an error message if not. + + + + + An appropriate error message
+ or nullif the buffer is valid
+ +
+ + + Gets the error message + + + + + Gets the error location + + + + + Gets a geometry which indicates the location and nature of a validation failure. + + If the failure is due to the buffer curve being too far or too close + to the input, the indicator is a line segment showing the location and size + of the discrepancy. + + + A geometric error indicator
+ or null, if no error was found
+
+ + + Computes the Euclidean distance (L2 metric) from a Point to a Geometry. + Also computes two points which are separated by the distance. + + + + + Contains a pair of points and the distance between them. + Provides methods to update with a new point pair with + either maximum or minimum distance. + + + + + Initializes the points, avoiding recomputing the distance. + + The first point + The second point + The distance between and + + + + Creates a buffer polygon with a varying buffer distance + at each vertex along a line. + + Only single lines are supported as input, since buffer widths + generally need to be specified individually for each line. + + Martin Davis + + + + Creates a buffer polygon along a line with the buffer distance interpolated + between a start distance and an end distance. + + The line to buffer + The buffer width at the start of the line + The buffer width at the end of the line + The variable-distance buffer polygon + + + + Creates a buffer polygon along a line with the buffer distance interpolated + between a start distance, a middle distance and an end distance. + The middle distance is attained at + the vertex at or just past the half-length of the line. + For smooth buffering of a (or the rings of a ) + the start distance and end distance should be equal. + + The line to buffer + The buffer width at the start of the line + The buffer width at the middle vertex of the line + The buffer width at the end of the line + The variable-distance buffer polygon + + + + Creates a buffer polygon along a line with the distance specified + at each vertex. + + The line to buffer + The buffer distance for each vertex of the line + The variable-width buffer polygon + + + + Computes a list of values for the points along a line by + interpolating between values for the start and end point. + The interpolation is + based on the distance of each point along the line + relative to the total line length. + + The line to interpolate along + The start value + The end value + The array of interpolated values + + + + Computes a list of values for the points along a line by + interpolating between values for the start, middle and end points. + The interpolation is + based on the distance of each point along the line + relative to the total line length. + The middle distance is attained at + the vertex at or just past the half-length of the line. + + The line to interpolate along + The start value + The mid value + The end value + The array of interpolated values + + + + Creates a generator for a variable-distance line buffer. + + The linestring to buffer + The buffer distance for each vertex of the line + + + + Computes the buffer polygon. + + A buffer polygon + + + + Computes a variable buffer polygon for a single segment, + with the given endpoints and buffer distances. + The individual segment buffers are unioned + to form the final buffer. + + The segment start point + The segment end point + The buffer distance at the start point + The buffer distance at the end point + The segment buffer + + + + Returns a circular polygon. + + The circle center point + The radius + A polygon, or null if the radius is 0 + + + + Adds a semi-circular cap CCW around the point . + + The centre point of the cap + The cap radius + the starting point of the cap + The ending point of the cap + The coordinate list to add to + + + + Computes the angle for the given cap point index. + + The fillet angle index + + + + Computes the canonical cap point index for a given angle. + The angle is rounded down to the next lower + index. + + In order to reduce the number of points created by overlapping end caps, + cap points are generated at the same locations around a circle. + The index is the index of the points around the circle, + with 0 being the point at (1,0). + The total number of points around the circle is + 4 * . + + The angle + The index for the angle. + + +
+ Computes the two circumference points defining the outer tangent line + between two circles. + + For the algorithm see Wikipedia. + + The centre of circle 1 + The radius of circle 1 + The centre of circle 2 + The radius of circle 2 + The outer tangent line segment, or null if none exists + + + + Snap trig values to integer values for better consistency. + + The result of a trigonometric function + snapped to the integer interval + + + + A wrapper which + projects 3D coordinates into one of the + three Cartesian axis planes, + using the standard orthonormal projection + (i.e. simply selecting the appropriate ordinates into the XY ordinates). + The projected data is represented as 2D coordinates. + + Martin Davis + + + + Creates a wrapper projecting to the XY plane. + + The sequence to be projected + A sequence which projects coordinates + + + + Creates a wrapper projecting to the XZ plane. + + The sequence to be projected + A sequence which projects coordinates + + + + Creates a wrapper projecting to the YZ plane. + + The sequence to be projected + A sequence which projects coordinates + + + + + + + Find two points on two 3D s which lie within a given distance, + or else are the nearest points on the geometries (in which case this also + provides the distance between the geometries). + + 3D geometries have vertex Z ordinates defined. + 3D s are assumed to lie in a single plane (which is enforced if not actually the case). + 3D s and s may have any configuration. + + The distance computation also finds a pair of points in the input geometries + which have the minimum distance between them. If a point lies in the interior + of a line segment, the coordinate computed is a close approximation to the + exact point. + + The algorithms used are straightforward O(n^2) comparisons. This worst-case + performance could be improved on by using Voronoi techniques or spatial + indexes. + + 1.13 + + + + Compute the distance between the nearest points of two geometries. + + A geometry + A geometry + The distance between the geometries + + + + Test whether two geometries lie within a given distance of each other. + + A geometry + A geometry + The distance to test + true if g0.distance(g1) <= + + + + Compute the the nearest points of two geometries. The points are + presented in the same order as the input Geometries. + + A geometry + A geometry + The nearest points in the geometries + + + + Constructs a DistanceOp that computes the distance and nearest points + between the two specified geometries. + + A geometry + A geometry + + + + Constructs a DistanceOp that computes the distance and nearest points + between the two specified geometries. + + A geometry + A geometry + The distance on which to terminate the search + + + + Report the distance between the nearest points on the input geometries. + + The distance between the geometries
+ or 0 if either input geometry is empty
+ Thrown if either input geometry is null. +
+ + + Report the coordinates of the nearest points in the input geometries. The + points are presented in the same order as the input Geometries. + + A pair of s of the nearest points + + + + Gets the locations of the nearest points in the input geometries. The + locations are presented in the same order as the input Geometries. + + A pair of s for the nearest points + + + + Finds the index of the "most polygonal" input geometry. + This optimizes the computation of the best-fit plane, + since it is cached only for the left-hand geometry. + + The index of the most polygonal geometry + + + + Convenience method to create a Plane3DPolygon + + + + + Computes distance between two polygons. + + + To compute the distance, compute the distance + between the rings of one polygon and the other polygon, + and vice-versa. + If the polygons intersect, then at least one ring must + intersect the other polygon. + Note that it is NOT sufficient to test only the shell rings. + A counter-example is a "figure-8" polygon A + and a simple polygon B at right angles to A, with the ring of B + passing through the holes of A. + The polygons intersect, + but A's shell does not intersect B, and B's shell does not intersect A. + + + Compute distance between a polygon and the rings of another. + + + + Computes a point at a distance along a segment + specified by two relatively proportional values. + The fractional distance along the segment is d0/(d0+d1). + + Start point of the segment. + End point of the segment + Proportional distance from start point to computed point + Proportional distance from computed point to end point + The computed point + + + + Models a polygon lying in a plane in 3-dimensional Cartesian space. + The polygon representation is supplied + by a , + containing coordinates with XYZ ordinates. + 3D polygons are assumed to lie in a single plane. + The plane best fitting the polygon coordinates is + computed and is represented by a . + + Martin Davis + + + + Creates an instance of this class using the provided . + + The polygon + + + + Finds a best-fit plane for the polygon, + by sampling a few points from the exterior ring. + + The algorithm used is Newell's algorithm: + + a base point for the plane is determined from the average of all vertices + the normal vector is determined by computing the area of the projections on each of the axis planes + + + The polygon to determine the plane for + The best-fit plane + + + + Computes an average normal vector from a list of polygon coordinates. + Uses Newell's method, which is based + on the fact that the vector with components + equal to the areas of the projection of the polygon onto + the Cartesian axis planes is normal. + + The sequence of coordinates for the polygon + A normal vector + + + + Computes a point which is the average of all coordinates + in a sequence.
+ If the sequence lies in a single plane, + the computed point also lies in the plane. +
+ A coordinate sequence + A Coordinate with averaged ordinates +
+ + + Gets a value indicating the plane + + + + + Gets a value indicating the polygon + + + + + Checks if intersects with this . + + The point to check + true if intPt intersects this PlanarPolygon3d. + + + + Checks if the point intersects with when projected to this instance's facing plane + + A point + A ring + true if point and linestring intersect + + + + A ConnectedElementPointFilter extracts a single point + from each connected element in a Geometry + (e.g. a polygon, linestring or point) + and returns them in a list. The elements of the list are + s. + Empty geometries do not provide a location item. + + + + + Returns a list containing a point from each Polygon, LineString, and Point + found inside the specified point. Thus, if the specified point is + not a GeometryCollection, an empty list will be returned. The elements of the list + are s. + + + + + + + + + + + + + + + + + Extracts a single point + from each connected element in a Geometry + (e.g. a polygon, linestring or point) + and returns them in a list + + + + + Returns a list containing a Coordinate from each Polygon, LineString, and Point + found inside the specified point. Thus, if the specified point is + not a GeometryCollection, an empty list will be returned. + + + + + + + + + + + + + + + + + Computes the distance and + closest points between two Geometrys. + The distance computation finds a pair of points in the input geometries + which have minimum distance between them. These points may + not be vertices of the geometries, but may lie in the interior of + a line segment. In this case the coordinate computed is a close + approximation to the exact point. + + Empty geometry collection components are ignored. + + The algorithms used are straightforward O(n^2) + comparisons. This worst-case performance could be improved on + by using Voronoi techniques. + + + + + Compute the distance between the closest points of two geometries. + + A Geometry. + Another Geometry. + The distance between the geometries. + + + + Test whether two geometries lie within a given distance of each other. + + + + + + + + + Compute the the closest points of two geometries. + The points are presented in the same order as the input Geometries. + + A Geometry. + Another Geometry. + The closest points in the geometries. + + + + Constructs a that computes the distance and closest points between + the two specified geometries. + + A geometry + A geometry + + + + Constructs a that computes the distance and closest points between + the two specified geometries. + + A geometry + A geometry + The distance on which to terminate the search. + + + + Report the distance between the closest points on the input geometries. + + The distance between the geometries
+ or 0 if either input geometry is empty.
+ if either input geometry is null +
+ + + Report the coordinates of the nearest points in the input geometries. + The points are presented in the same order as the input Geometries. + + A pair of Coordinates of the nearest points. + + + + Report the locations of the nearest points in the input geometries. + The locations are presented in the same order as the input Geometries. + + A pair of s for the nearest points. + + + + + + + + + + + + + + + + + + + + + + + + + + + Computes distance between facets (lines and points) of input geometries. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Represents a sequence of facets (points or line segments) of a + specified by a subsequence of a . + + Martin Davis + + + + Creates a new sequence of facets based on a + contained in the given . + + The geometry containing the facets. + The sequence containing the facet points. + The index of the start point. + The index of the end point. + + + + Creates a new sequence of facets based on a . + + The sequence containing facet points. + The index of the start point + The index of the end point + 1 + + + + Creates a new sequence for a single point from a CoordinateSequence. + + The sequence containing the facet point. + the index of the point + + + + Gets the envelope of this facet sequence + + + + + Gets the number of coordinates in this facet sequence + + + + + Gets the coordinate at the given index + + The index + The coordinate at the given index + + + + Tests if this facet sequence consists of only one point + + + + + Computes the distance between this and another + . + + The sequence to compute the distance to. + The minimum distance between the sequences. + + + + Computes the locations of the nearest points between this sequence + and another sequence. + The locations are presented in the same order as the input sequences. + + A pair of s for the nearest points. + + + + + + + Utility class to build facet sequencs STRtrees- + + + + + + + + + + + + Creates facet sequences from a given geometry + + The geometry + A list of s + + + + Represents the location of a point on a Geometry. + Maintains both the actual point location + (which may not be exact, if the point is not a vertex) + as well as information about the component + and segment index where the point occurs. + Locations inside area Geometrys will not have an associated segment index, + so in this case the segment index will have the sentinel value of . + + + + + A special value of segmentIndex used for locations inside area geometries. + These locations are not located on a segment, + and thus do not have an associated segment index. + + + + + Constructs a GeometryLocation specifying a point on a point, as well as the + segment that the point is on (or if the point is not on a segment). + + The component of the geometry containing the point + The segment index of the location, or + The coordinate of the location + + + + Constructs a GeometryLocation specifying a point inside an area point. + + The component of the geometry containing the point + The coordinate of the location + + + + Returns the geometry component on (or in) which this location occurs. + + + + + Returns the segment index for this location. If the location is inside an + area, the index will have the value . + + + + + Returns the of this location. + + + + + Tests whether this location represents a point inside an area geometry. + + + + + + + + Computes the distance between the facets (segments and vertices) + of two s + using a Branch-and-Bound algorithm. + The Branch-and-Bound algorithm operates over a + traversal of R-trees built + on the target and the query geometries. + + This approach provides the following benefits: + + + Performance is dramatically improved due to the use of the + R-tree index + and the pruning due to the Branch-and-Bound approach + + The spatial index on the target geometry is cached + which allow reuse in an repeated query situation. + + Using this technique is usually much more performant + than using the brute-force + when one or both input geometries are large, + or when evaluating many distance computations against + a single geometry. + + + This class is thread-safe. + + Martin Davis + + + + + Computes the distance between facets of two geometries. + + + For geometries with many segments or points, + this can be faster than using a simple distance + algorithm. + + A geometry + A geometry + The distance between the two geometries + + + + Tests whether the facets of two geometries lie within a given distance. + + A geometry + A geometry + The distance limit + true if two facets lie with the given distance + + + + Computes the nearest points of the facets of two geometries. + + A geometry + A geometry + The nearest points on the facets of the geometries + + + + Creates a new distance-finding instance for a given target . + + + + Distances will be computed to all facets of the input geometry. + The facets of the geometry are the discrete segments and points + contained in its components. + + In the case of and inputs, + this is equivalent to computing the conventional distance. + + In the case of inputs, this is equivalent + to computing the distance to the polygon boundaries. + + + A Geometry, which may be of any type. + + + + Computes the distance from the base geometry to the given geometry. + + The geometry to compute the distance to. + The computed distance + + + + Computes the nearest locations on the base geometry + and the given geometry. + + Ihe geometry to compute the nearest location to. + The nearest locations. + + + + Computes the nearest locations on the target geometry + and the given geometry. + + Ihe geometry to compute the nearest point to. + The nearest points. + + + + Tests whether the base geometry lies within + a specified distance of the given geometry. + + The geometry to test + The maximum distance to test + true if the geometry lies with the specified distance + + + + The base class for operations that require s. + + + + + + + + + + + + + + + The operation args into an array so they can be accessed by index. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Tests whether a is simple. + In general, the SFS specification of simplicity + follows the rule: + + + A Geometry is simple if and only if the only self-intersections are at boundary points. + + + + + Simplicity is defined for each } subclass as follows: + + Valid geometries are simple by definition, so + IsSimple trivially returns true.
+ (Note: this means that IsSimple cannot be used to test + for (invalid) self-intersections in Polygons. + In order to check if a Polygonal geometry has self-intersections, + use ).
+ geometries are simple if and only if they do not self-intersect at interior points + (i.e. points other than boundary points). + This is equivalent to saying that no two linear components satisfy the SFS + predicate. + Zero-dimensional () geometries are simple if and only if they have no + repeated points. + Empty s are always simple by definition. +
+ For geometries the evaluation of simplicity + can be customized by supplying a + to define how boundary points are determined. + The default is the SFS-standard . + Note that under the Mod-2 rule, closed LineStrings (rings) + will never satisfy the touches predicate at their endpoints, since these are + interior points, not boundary points. + If it is required to test whether a set of LineStrings touch + only at their endpoints, use IsSimpleOp with . + For example, this can be used to validate that a set of lines form a topologically valid + linear network. +
+
+ + + Creates a simplicity checker using the default SFS Mod-2 Boundary Node Rule + + The geometry to test + + + + Creates a simplicity checker using a given + + The geometry to test + The rule to use + + + + Tests whether the geometry is simple. + + true if the geometry is simple + + + + Gets a coordinate for the location where the geometry fails to be simple. + (i.e. where it has a non-boundary self-intersection). + must be called before this location is accessed + + a coordinate for the location of the non-boundary self-intersection + or null if the geometry is simple + + + + Computes simplicity for polygonal geometries. + Polygonal geometries are simple if and only if + all of their component rings are simple. + + A Polygonal geometry + true if the geometry is simple + + + Semantics for GeometryCollection is + simple if all components are simple. + A GeometryCollection + true if the geometry is simple + + + + For all edges, check if there are any intersections which are NOT at an endpoint. + The Geometry is not simple if there are intersections not at endpoints. + + + + + + + + + + + Creates an instance of this class + + The endpoint + + + + Tests that no edge intersection is the endpoint of a closed line. + This ensures that closed lines are not touched at their endpoint, + which is an interior point according to the Mod-2 rule + To check this we compute the degree of each endpoint. + The degree of endpoints of closed lines + must be exactly 2. + + + + + Add an endpoint to the map, creating an entry for it if none exists. + + + + + + + + A sequence of LineMergeDirectedEdges forming one of the lines that will + be output by the line-merging process. + + + + + Constructs an EdgeString with the given factory used to convert this EdgeString + to a LineString. + + + + + + Adds a directed edge which is known to form part of this line. + + + + + + + + + + + Converts this EdgeString into a LineString. + + + + + A com.vividsolutions.jts.planargraph.DirectedEdge of a LineMergeGraph. + + + + + Constructs a LineMergeDirectedEdge connecting the from node to the to node. + + + + + specifies this DirectedEdge's direction (given by an imaginary + line from the from node to directionPt). + + + whether this DirectedEdge's direction is the same as or + opposite to that of the parent Edge (if any). + + + + + Returns the directed edge that starts at this directed edge's end point, or null + if there are zero or multiple directed edges starting there. + + + + + An edge of a LineMergeGraph. The marked field indicates + whether this Edge has been logically deleted from the graph. + + + + + Constructs a LineMergeEdge with vertices given by the specified LineString. + + + + + + Returns the LineString specifying the vertices of this edge. + + + + + A planar graph of edges that is analyzed to sew the edges together. The + marked flag on s + and s indicates whether they have been + logically deleted from the graph. + + + + + Adds an Edge, DirectedEdges, and Nodes for the given LineString representation + of an edge. + + + + + + + + + + + + Sews together a set of fully noded LineStrings. + + + Sewing stops at nodes of degree 1 + or 3 or more -- the exception is an isolated loop, which only has degree-2 nodes, + in which case a node is simply chosen as a starting point. The direction of each + merged LineString will be that of the majority of the LineStrings from which it + was derived. + + Any dimension of Geometry is handled -- the constituent linework is extracted to + form the edges. The edges must be correctly noded; that is, they must only meet + at their endpoints. The LineMerger will still run on incorrectly noded input + but will not form polygons from incorrected noded edges. + + NOTE:once merging has been performed, no more + + + + + + + + + + + + + + + + + + + + + + Adds a Geometry to be processed. May be called multiple times. + Any dimension of Geometry may be added; the constituent linework will be + extracted. + + + + + + Adds a collection of Geometries to be processed. May be called multiple times. + Any dimension of Geometry may be added; the constituent linework will be + extracted. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Returns the LineStrings built by the merging process. + + + + + + + Builds a sequence from a set of s, + so that they are ordered end to end. + A sequence is a complete non-repeating list of the linear + components of the input. Each linestring is oriented + so that identical endpoints are adjacent in the list. + + + The input linestrings may form one or more connected sets. + The input linestrings should be correctly noded, or the results may + not be what is expected. + The output of this method is a single , + containing the ordered linestrings in the sequence. + + + The sequencing employs the classic 'Eulerian path' graph algorithm. + Since Eulerian paths are not uniquely determined, further rules are used to + make the computed sequence preserve as much as possible of the input ordering. + Within a connected subset of lines, the ordering rules are: + - If there is degree-1 node which is the start + node of an linestring, use that node as the start of the sequence. + - If there is a degree-1 node which is the end + node of an linestring, use that node as the end of the sequence. + - If the sequence has no degree-1 nodes, use any node as the start + + + Not all arrangements of lines can be sequenced. + For a connected set of edges in a graph, + Euler's Theorem states that there is a sequence containing each edge once + if and only if there are no more than 2 nodes of odd degree. + If it is not possible to find a sequence, the + property will return false. + + + + + + Tests whether a is sequenced correctly. + s are trivially sequenced. + s are checked for correct sequencing. + Otherwise, IsSequenced is defined + to be true for geometries that are not lineal. + + The to test. + + true if the is sequenced or is not lineal. + + + + + Adds a of s to be sequenced. + May be called multiple times. + Any dimension of Geometry may be added; the constituent linework will be extracted. + + A of geometries to add. + + + + Adds a to be sequenced. + May be called multiple times. + Any dimension of may be added; + the constituent linework will be extracted. + + + + + + A private implementation for + + + + + Initializes a new instance of the class. + + The sequencer. + + + + Performs an operation with or on + + + A to which the filter is applied. + + + + + Tests whether the arrangement of linestrings has a valid sequence. + + true if a valid sequence exists. + + + + Returns the or + built by the sequencing process, if one exists. + + The sequenced linestrings, + or null if a valid sequence does not exist. + + + + Tests whether a complete unique path exists in a graph + using Euler's Theorem. + + The containing the edges. + true if a sequence exists. + + + + Finds an for an unvisited edge (if any), + choosing the which preserves orientation, if possible. + + The to examine. + + The found, + or null if none were unvisited. + + + + + Computes a version of the sequence which is optimally + oriented relative to the underlying geometry. + + Heuristics used are: + - If the path has a degree-1 node which is the start + node of an linestring, use that node as the start of the sequence. + - If the path has a degree-1 node which is the end + node of an linestring, use that node as the end of the sequence. + - If the sequence has no degree-1 nodes, use any node as the start + (NOTE: in this case could orient the sequence according to the majority of the + linestring orientations). + + + A of s. + + A of s oriented appropriately. + + + + + Reverse the sequence. + This requires reversing the order of the s, + and flipping each as well. + + + A enumeration of s, + in sequential order. + + The reversed sequence. + + + + Builds a geometry ( or ) + representing the sequence. + + + An enumeration of s of s + with s as their parent edges. + + + The sequenced geometry, or null if no sequence exists. + + + + + Unions a valid coverage of polygons or lines + in an efficient way. + + A valid polygonal coverage is a collection of s + which satisfy the following conditions: + + Vector-cleanLine segments within the collection + must either be identical or intersect only at endpoints. + Non-overlappingNo two polygons + may overlap. Equivalently, polygons must be interior-disjoint. + + + A valid linear coverage is a collection of s + which satisfies the Vector-clean condition. + Note that this does not require the LineStrings to be fully noded + - i.e. they may contain coincident linework. + Coincident line segments are dissolved by the union. + Currently linear output is not merged (this may be added in a future release.) + + Currently no checking is done to determine whether the input is a valid coverage. + This is because coverage validation involves segment intersection detection, + which is much more expensive than the union phase. + If the input is not a valid coverage + then in some cases this will be detected during processing + and a is thrown. + Otherwise, the computation will produce output, but it will be invalid. + + Unioning a valid coverage implies that no new vertices are created. + This means that a precision model does not need to be specified. + The precision of the vertices in the output geometry is not changed. + + Martin Davis + + + + + Unions a valid polygonal coverage or linear network. + + A coverage of polygons or lines + The union of the coverage + Thrown in some cases if the coverage is invalid + + + + Represents the linework for edges in a topology graph, + derived from(up to) two parent geometries. + An edge may be the result of the merging of + two or more edges which have the same linework + (although possibly different orientations). + In this case the topology information is + derived from the merging of the information in the + source edges.
+ Merged edges can occur in the following situations + + Due to coincident edges of polygonal or linear geometries. + Due to topology collapse caused by snapping or rounding + of polygonal geometries. + + The source edges may have the same parent geometry, + or different ones, or a mix of the two. +
+ Martin Davis +
+ + + Tests if the given point sequence + is a collapsed line. + A collapsed edge has fewer than two distinct points. + + The point sequence to check + true if the points form a collapsed line + + + + Compares two coincident edges to determine + whether they have the same or opposite direction. + + An edge + true if the edges have the same direction, false if not + + + + Populates the label for an edge resulting from an input geometry. + + + If the edge is not part of the input, the label is left as + If input is an Area and the edge is on the boundary (which may include some collapses), edge is marked as an edge and side locations are assigned + If input is an Area and the edge is collapsed (depth delta = 0), the label is set to . The location will be determined later by evaluating the final graph topology. + If input is a Line edge is set to a edge. For line edges the line location is not significant (since there is no parent area for which to determine location). + + + + + + Tests whether the edge is part of a shell in the given geometry. + This is only the case if the edge is a boundary. + + The index of the geometry + true if this edge is a boundary and part of a shell + + + + Merges an edge into this edge, + updating the topology info accordingly. + + The edge to merge + + + + A key for sorting and comparing edges in a noded arrangement. + Relies on the fact that in a correctly noded arrangement + edges are identical (up to direction) + if they have their first segment in common. + + Martin Davis + + + + + + + + + + + + + Performs merging on the noded edges of the input geometries. + Merging takes place on edges which are coincident + (i.e.have the same coordinate list, modulo direction). + The following situations can occur: + + Coincident edges from different input geometries have their labels combined + Coincident edges from the same area geometry indicate a topology collapse. + In this case the topology locations are "summed" to provide a final + assignment of side location + Coincident edges from the same linear geometry can simply be merged + using the same ON location + + + The merging attempts to preserve the direction of linear + edges if possible(which is the case if there is + no other coincident edge, or if all coincident edges have the same direction). + This ensures that the overlay output line direction will be as consistent + as possible with input lines. + + The merger also preserves the order of the edges in the input. + This means that for polygon-line overlay + the result lines will be in the same order as in the input + (possibly with multiple result lines for a single input line). + + Martin Davis + + + + Builds a set of noded, unique, labelled Edges from + the edges of the two input geometries. + + It performs the following steps: + + Extracts input edges, and attaches topological information + if clipping is enabled, handles clipping or limiting input geometry + chooses a based on provided precision model, unless a custom one is supplied + calls the chosen Noder, with precision model + removes any fully collapsed noded edges + builds s and merges them + + + Martin Davis + + + + Creates a new builder, with an optional custom noder. + If the noder is not provided, a suitable one will + be used based on the supplied precision model. + + The precision model to use + An optional noder to use (may be null) + + + + Gets or sets a noder appropriate for the precision model supplied.
+ This is one of: + + Fixed precision:a snap-rounding noder (which should be fully robust) + Floating precision:a conventional noder (which may be non-robust). + In this case, a validation step is applied to the output from the noder. + +
+
+ + + Reports whether there are noded edges + for the given input geometry. + If there are none, this indicates that either + the geometry was empty, or has completely collapsed + (because it is smaller than the noding precision). + + index of the input geometry + true if there are edges for the geometry + + + + Creates a set of labelled {Edge}s. + representing the fully noded edges of the input geometries. + Coincident edges (from the same or both geometries) + are merged along with their labels + into a single unique, fully labelled edge. + + The first geometry + The second geometry + The noded, merged, labelled edges + + + + Nodes a set of segment strings and creates s from the result. + The input segment strings each carry a object, + which is used to provide source topology info to the constructed Edges + (and is then discarded). + + + + + Adds a polygon ring to the graph. + + Empty rings are ignored. + + + + Tests whether a geometry (represented by its envelope) + lies completely outside the clip extent(if any). + + The geometry envelope + true if the geometry envelope is outside the clip extent. + + + + If clipper is present, + clip the line to the clip extent. + + If clipping is enabled, then every ring MUST + be clipped, to ensure that holes are clipped to + be inside the shell. + This means it is not possible to skip + clipping for rings with few vertices. + + The line to clip + The points in the clipped ring + + + + Removes any repeated points from a linear component. + This is required so that noding can be computed correctly. + + The line to process + The points of the line with repeated points removed + + + + Adds a line geometry, limiting it if enabled, + and otherwise removing repeated points. + + The line to add + The index of the parent geometry + + + + Tests whether it is worth limiting a line. + Lines that have few vertices or are covered + by the clip extent do not need to be limited. + + The line to test + true if the line should be limited + + + + If limiter is provided, + limit the line to the clip envelope. + + The line to clip + the point sections in the clipped line + + + + Records topological information about an + edge representing a piece of linework (lineString or polygon ring) + from a single source geometry. + This information is carried through the noding process + (which may result in many noded edges sharing the same information object). + It is then used to populate the topology info fields + in s (possibly via merging). + That information is used to construct the topology graph s. + + Martin Davis + + + A simple elevation model used to populate missing Z values + in overlay results. + + The model divides the extent of the input geometry(s) + into an NxM grid. + The default grid size is 3x3. + If the input has no extent in the X or Y dimension, + that dimension is given grid size 1. + The elevation of each grid cell is computed as the average of the Z values + of the input vertices in that cell (if any). + If a cell has no input vertices within it, it is assigned + the average elevation over all cells. + + If no input vertices have Z values, the model does not assign a Z value. + + The elevation of an arbitrary location is determined as the + Z value of the nearest grid cell. + + An elevation model can be used to populate missing Z values + in an overlay result geometry. + + Martin Davis + + + + Creates an elevation model from two geometries (which may be null). + + An input geometry + An input geometry + The elevation model computed from the geometries + + + + Creates a new elevation model covering an extent by a grid of given dimensions. + + The XY extent to cover + The number of grid cells in the X dimension + The number of grid cells in the Y dimension + + + + Updates the model using the Z values of a given geometry. + + The geometry to scan for Z values. + + + + Gets the model Z value at a given location. + If the location lies outside the model grid extent, + this returns the Z value of the nearest grid cell. + If the model has no elevation computed (i.e. due + to empty input), the value is returned as + + x-ordinate of the location + y-ordinate of the location + The computed Z value + + + + Computes Z values for any missing Z values in a geometry, + using the computed model. + If the model has no Z value, or the geometry coordinate dimension + does not include Z, the geometry is not updated. + + The geometry to populate Z values for + + + + Locates points on a linear geometry, + using a spatial index to provide good performance. + + Martin Davis + + + + Manages the input geometries for an overlay operation. + The second geometry is allowed to be null, + to support for instance precision reduction. + + Martin Davis + + + + Gets the index of an input which is an area, + if one exists. + Otherwise returns -1. + + The index of an area input, or -1 + + + + Tests if an input geometry has edges. + This indicates that topology needs to be computed for them. + + + true if the input geometry has edges + + + + Determines the location within an area geometry. + This allows disconnected edges to be fully + located. + + The index of the geometry + The coordinate to locate + The location of the coordinate + + + + + Extracts Point resultants from an overlay graph + created by an Intersection operation + between non-Point inputs. + Points may be created during intersection + if lines or areas touch one another at single points. + Intersection is the only overlay operation which can + result in Points from non-Point inputs. + + Overlay operations where one or more inputs + are Points are handled via a different code path. + + Martin Davis + + + + + Controls whether lines created by area topology collapses + to participate in the result computation.
+ True provides the original JTS semantics. +
+
+ + + Tests if a node is a result point. + This is the case if the node is incident on edges from both + inputs, and none of the edges are themselves in the result. + + An edge originating at the node + true if the node is a result point. + + + + Finds and builds overlay result lines from the overlay graph. + Output linework has the following semantics: + + Linework is fully noded + Lines are as long as possible between nodes + + Various strategies are possible for how to + merge graph edges into lines. + This implementation uses the approach + of having output lines run contiguously from node to node. + For rings a node point is chosen arbitrarily. + + Another possible strategy would be to preserve input linework + as far as possible (i.e.any sections of input lines which are not + coincident with other linework would be preserved). + + It would also be possible to output LinearRings, + if the input is a LinearRing and is unchanged. + This will require additional info from the input linework. + + Martin Davis + + + + Indicates whether intersections are allowed to produce + heterogeneous results including proper boundary touches. + This does not control inclusion of touches along collapses.
+ True provides the original JTS semantics. +
+
+ + + Allow lines created by area topology collapses + to appear in the result.
+ True provides the original JTS semantics. +
+
+ + + Creates a builder for linear elements which may be present + in the overlay result. + + The input geometries + The topology graph + true if an area has been generated for the result + The overlay operation code + The output geometry factory + + + + Checks if the topology indicated by an edge label + determines that this edge should be part of a result line. + + Note that the logic here relies on the semantic + that for intersection lines are only returned if + there is no result area components. + + The label for an edge + true if the edge should be included in the result + + + + Determines the effective location for a line, + for the purpose of overlay operation evaluation. + Line edges and Collapses are reported as INTERIOR + so they may be included in the result + if warranted by the effect of the operation on the two edges. + (For instance, the intersection of a line edge and a collapsed boundary + is included in the result). + + The label of line + The index of parent geometry + The effective location of the line + + + + Adds lines which form rings (i.e. have only degree-2 vertices). + + + + + Traverses edges from edgeStart which + lie in a single line (have degree = 2). + + The direction of the linework is preserved as far as possible. + Specifically, the direction of the line is determined + by the start edge direction. This implies + that if all edges are reversed, the created line + will be reversed to match. + This ensures the orientation of linework is faithful to the input + in the case of polygon-line overlay. + However, this does not provide a consistent orientation + in the case of line-line intersection(where A and B might have different orientations). + (Other more complex strategies would be possible. + E.g. using the direction of the majority of segments, + or preferring the direction of the A edges.) + + + + + Finds the next edge around a node which forms + part of a result line. + + A line edge originating at the node to be scanned + The next line edge, or null if there is none + + + + + Computes the degree of the line edges incident on a node + + Node to compute degree for + Degree of the node line edges + + + + Limits the segments in a list of segments + to those which intersect an envelope. + This creates zero or more sections of the input segment sequences, + containing only line segments which intersect the limit envelope. + Segments are not clipped, since that can move + line segments enough to alter topology, + and it happens in the overlay in any case. + This can substantially reduce the number of vertices which need to be + processed during overlay. + + This optimization is only applicable to Line geometries, + since it does not maintain the closed topology of rings. + Polygonal geometries are optimized using the . + + + Martin Davis + + + + Creates a new limiter for a given envelope. + + The envelope to limit to + + + + Limits a list of segments. + + The segment sequence to limit + The sections which intersect the limit envelope + + + + Traverses the star of edges originating at a node + and links consecutive result edges together + into maximal edge rings. + To link two edges the resultNextMax pointer + for an incoming result edge + is set to the next outgoing result edge. + + Edges are linked when: + + they belong to an area (i.e.they have sides) + they are marked as being in the result + + + Edges are linked in CCW order + (which is the order they are linked in the underlying graph). + This means that rings have their face on the Right + (in other words, + the topological location of the face is given by the RHS label of the DirectedEdge). + This produces rings with CW orientation. + + PRECONDITIONS:
+ - This edge is in the result
+ - This edge is not yet linked
+ - The edge and its sym are NOT both marked as being in the result +
+
+ + + Links the edges of a around this node + into minimal edge rings (s). + Minimal ring edges are linked in the opposite orientation (CW) + to the maximal ring. + This changes self-touching rings into a two or more separate rings, + as per the OGC SFS polygon topology semantics. + This relinking must be done to each max ring separately, + rather than all the node result edges, since there may be + more than one max ring incident at the node. + + The maximal ring to link + An edge originating at this node + + + + Tests if an edge of the maximal edge ring is already linked into + a minimal . If so, this node has already been processed + earlier in the maximal edgering linking scan. + + An edge of a maximal edgering + The maximal edgering + true if the edge has already been linked into a minimal edgering. + + + + Creates a single OverlayEdge. + + + + + A new edge based on the given coordinates and direction. + + + + Gets a which sorts by the origin Coordinates. + + + + + true indicates direction is forward along segString
+ false is reverse direction
+ The label must be interpreted accordingly. +
+
+ + + Adds the coordinates of this edge to the given list, + in the direction of the edge. + Duplicate coordinates are removed + (which means that this is safe to use for a path + of connected edges in the topology graph). + + The coordinate list to add to + + + + ets the symmetric pair edge of this edge. + + The symmetric pair edge + + + + Gets the next edge CCW around the origin of this edge, + with the same origin.
+ If the origin vertex has degree 1 then this is the edge itself. +
+ + The next edge around the origin + +
+ + + Gets or sets a link to next edge in the result ring. + The origin of the edge is the dest of this edge. + + + + + Tests whether this ring is a hole. + + true if this ring is a hole + + + + Tests whether this ring has a shell assigned to it. + + true if the ring has a shell + + + + Gets or sets a value indicating the shell for this ring.
+ The shell is the ring itself if it is not a hole, otherwise its parent shell. +
+
+ + + Computes the list of coordinates which are contained in this ring. + The coordinates are computed once only and cached. + + An array of the s in this ring + + + + Finds the innermost enclosing shell OverlayEdgeRing + containing this OverlayEdgeRing, if any. + The innermost enclosing ring is the smallest enclosing ring. + The algorithm used depends on the fact that: +
+ ring A contains ring B if envelope(ring A) contains envelope(ring B) +
+ This routine is only safe to use if the chosen point of the hole + is known to be properly contained in a shell + (which is guaranteed to be the case if the hole does not touch its shell) + + To improve performance of this function the caller should + make the passed shellList as small as possible (e.g. + by using a spatial index filter beforehand). +
+ The containing EdgeRing, if there is one + or null if no containing EdgeRing is found + +
+ + + Computes the formed by this ring and any contained holes. + + The formed by this ring and its holes. + + + + A planar graph of edges, representing + the topology resulting from an overlay operation. + Each source edge is represented + by a pair of s, + with opposite(symmetric) orientation. + The pair of OverlayEdges share the edge coordinates + and a single . + + Martin Davis + + + + Gets the set of edges in this graph. + Only one of each symmetric pair of OverlayEdges is included. + The opposing edge can be found by using . + + The collection of representative edges in this graph + + + + Gets the collection of edges representing the nodes in this graph. + For each star of edges originating at a node + a single representative edge is included.
+ The other edges around the node can be found by following the next and prev links. +
+ The collection of representative node edges +
+ + + Gets an edge originating at the given node point. + + The node coordinate to query + An edge originating at the point, or null if none exists + + + + Gets the representative edges marked as being in the result area. + + The result area edges + + + + Adds an edge between the coordinates orig and dest + to this graph.
+ Only valid edges can be added (in particular, zero-length segments cannot be added) +
+ The edge to add. + The edge topology information + The created graph edge with same orientation as the linework +
+ + + Inserts a single half-edge into the graph. + The sym edge must also be inserted. + + The half-edge to insert + + + + A structure recording the topological situation + for an edge in a topology graph + used during overlay processing. + + + A label contains the topological for + one or two input geometries to an overlay operation. + An input geometry may be either a Line or an Area. + The label locations for each input geometry are populated + with the + for the edge s + when they are created or once they are computed by topological evaluation. + A label also records the(effective) dimension of each input geometry. + For area edges the role(shell or hole) + of the originating ring is recorded, to allow + determination of edge handling in collapse cases. + + In an + a single label is shared between + the two oppositely-oriented s + of a symmetric pair. + Accessors for orientation-sensitive information + are parameterized by the orientation of the containing edge. + + For each input geometry (0 and 1), the label records + that an edge is in one of the following states + (identified by thedim field). + Each state has additional information about the edge topology. + + A Boundary edge of an Area (polygon) + + dim = DIM_BOUNDARY + locLeft, locRight : the locations of the edge sides for the Area + locLine : INTERIOR + isHole : whether the edge is in a shell or a hole (the ring role) + + + + A Collapsed edge of an input Area + (formed by merging two or more parent edges) + + dim = DIM_COLLAPSE + locLine : the location of the edge relative to the effective input Area + (a collapsed spike is EXTERIOR, a collapsed gore or hole is INTERIOR) + isHole : true if all parent edges are in holes; + false if some parent edge is in a shell + + + + A Line edge from an input line + + dim = DIM_LINE + locLine : the location of the edge relative to the Line. + Initialized to LOC_UNKNOWN to simplify logic. + + + An edge which is Not Part of an input geometry + (and thus must be part of the other geometry). + + dim = NOT_PART + + + + Note that: + + an edge cannot be both a Collapse edge and a Line edge in the same input geometry, + because each input geometry must be homogeneous. + an edge may be an Boundary edge in one input geometry + and a Line or Collapse edge in the other input. + + + Martin Davis + + + + The dimension of an input geometry which is not known. + + + + + The dimension of an edge which is not part of a specified input geometry. + + + + + The dimension of an edge which is a line. + + + + + The dimension for an edge which is part of an input Area geometry boundary. + + + + + The dimension for an edge which is a collapsed part of an input Area geometry boundary. + A collapsed edge represents two or more line segments which have the same endpoints. + They usually are caused by edges in valid polygonal geometries + having their endpoints become identical due to precision reduction. + + + + + Indicates that the location is currently unknown + + + + + Creates a label for an Area edge + + The input index of the parent geometry + The location of the left side of the edge + The location of the right side of the edge + Whether the edge role is a hole or a shell + + + + Creates a label for a Line edge + + The input index of the parent geometry + + + + Creates an uninitialized label + + + + + Creates a label which is a copy of another label. + + The template label + + + + Gets the effective dimension of the given input geometry. + + The input index of the parent geometry + The dimension + + + + + + + + + Initializes the label for an input geometry which is an Area boundary. + + The input index of the parent geometry + The location of the left side of the edge + The location of the right side of the edge + Whether the edge role is a hole or a shell + + + + Initializes the label for an edge which is the collapse of + part of the boundary of an Area input geometry. + + The location of the collapsed edge relative to the + parent area geometry is initially unknown. + It must be determined from the topology of the overlay graph + + The index of the parent input geometry + Whether the dominant edge role is a hole or a shell + + + + Initializes the label for an input geometry which is a Line. + + The index of the parent input geometry + + + + Initializes the label for an edge which is not part of an input geometry. + + The index of the parent input geometry + + + + Sets the line location. +
+ This is used to set the locations for linear edges + encountered during area label propagation. +
+ The index of the input geometry + Location to set +
+ + + Sets the location of all postions for a given input. + + The index of the input geometry + The location to set + + + + Sets the location for a collapsed edge (the Line position) + for an input geometry, + depending on the ring role recorded in the label. + If the input geometry edge is from a shell, + the location is , if it is a hole + it is . + + The index of the input geometry + + + + Tests whether at least one of the sources is a Line. + + true if at least one source is a line + + + + Tests whether a source is a Line. + + The index of the input geometry + true if the input is a Line + + + + Tests whether an edge is linear (a Line or a Collapse) in an input geometry. + + The index of the input geometry + true if the edge is linear + + + + Tests whether the source of a label is known. + + The index of the input geometry + true if the source is known + + + + Tests whether a label is for an edge which is not part + of a given input geometry. + + The index of the input geometry + true if the edge is not part of the geometry + + + + Gets a value indicating if a label is for an edge which is in the boundary of either source geometry. + + true if the label is a boundary for either source + + + + Gets a value indicating if a label is for an edge which is in the boundary of both source geometries. + + true if the label is a boundary for both sources + + + + Tests if the label is a collapsed edge of one area + and is a(non-collapsed) boundary edge of the other area. + + true if the label is for a collapse coincident with a boundary + + + + Tests if a label is for an edge where two + area touch along their boundary. + + true if the edge is a boundary touch + + + + Tests if a label is for an edge which is in the boundary of a source geometry. + Collapses are not reported as being in the boundary. + + The index of the input geometry + true if the label is a boundary for the source + + + + Tests whether a label is for an edge which is a boundary of one geometry + and not part of the other. + + true if the edge is a boundary singleton + + + + Tests if the line location for a source is unknown. + + The index of the input geometry + true if the line location is unknown + + + + Tests if a line edge is inside a source geometry + (i.e.it has location ). + + The index of the input geometry + true if the line is inside the source geometry + + + + Tests if the ring role of an edge is a hole. + + The index of the input geometry + true if the ring role is a hole + + + + Tests if an edge is a Collapse for a source geometry. + + The index of the input geometry + true if the label indicates the edge is a collapse for the source + + + + Tests if a label is a Collapse has location {@link Location#INTERIOR}, + to at least one source geometry. + + true if the label is an Interior Collapse to a source geometry + + + + Tests if a label is a Collapse + and NotPart with location {@link Location#INTERIOR} for the other geometry. + + true if the label is a Collapse and a NotPart with Location Interior + + + + Gets the line location for a source geometry. + + The index of the input geometry + The line location for the source + + + + Tests if a line is in the interior of a source geometry. + + The index of the source geometry + true if the label is a line and is interior + + + + Gets the location for a of an edge of a source + for an edge with given orientation. + + The index of the input geometry + The position to get the location for + true if the orientation of the containing edge is forward + The location of the oriented position in the source + + + + Gets the location for this label for either + a Boundary or a Line edge. + This supports a simple determination of + whether the edge should be included as a result edge. + + The source index + The position for a boundary label + The direction for a boundary label + The location for the specified position + + + + Gets the linear location for the given source. + + The source geometry index + The linear location for the source + + + + Tests whether this label has side position information + for a source geometry. + + The index of the input geometry + true if at least one side position is known + + + + Creates a copy of this label + + A copy of this label + + + + Gets a symbol for the a ring role (Shell or Hole). + + true for a hole, false for a shell + The ring role symbol character + + + + Gets the symbol for the dimension code of an edge. + + The dimension code + The dimension symbol character + + + + Implements the logic to compute the full labeling + for the edges in an . + + Martin Davis + + + + Computes the topological labeling for the edges in the graph. + + + + + Labels edges around nodes based on the arrangement + of incident area boundary edges. + Also propagates the labeling to connected linear edges. + + The nodes to label + + + + Scans around a node CCW, propagating the side labels + for a given area geometry to all edges (and their sym) + with unknown locations for that geometry. + + + The geometry to propagate locations for + + + + Finds a boundary edge for this geom originating at the given + node, if one exists. + A boundary edge should exist if this is a node on the boundary + of the parent area geometry. + + An edge for this node + The parent geometry index + A boundary edge, or null if no boundary edge exists + + + + At this point collapsed edges with unknown location + must be disconnected from the boundary edges of the parent + (because otherwise the location would have + been propagated from them).
+ They can be now located based on their parent ring role(shell or hole). + (This cannot be done earlier, because the location + based on the boundary edges must take precedence.
+ There are situations where a collapsed edge has a location + which is different to its ring role - + e.g.a narrow gore in a polygon, which is in + the interior of the reduced polygon, but whose + ring role would imply the location EXTERIOR.) + + Note that collapsed edges can NOT have location determined via a PIP location check, + because that is done against the unreduced input geometry, + which may give an invalid result due to topology collapse. + + The labeling is propagated to other connected linear edges, + since there may be NOT_PART edges which are connected, + and they can be labeled in the same way. + (These would get labeled anyway during subsequent disconnected labeling pass, + but may be more efficient and accurate to do it here.) +
+
+ + + There can be edges which have unknown location + but are connected to a linear edge with known location. + In this case linear location is propagated to the connected edges. + + + + + Performs a breadth-first graph traversal to find and label + connected linear edges. + + The index of the input geometry to label. + + + + Finds all OverlayEdges which are linear + (i.e.line or collapsed) and have a known location + for the given input geometry. + + The index of the input geometry + A list of linear edges with known location + + + + At this point there may still be edges which have unknown location + relative to an input geometry.
+ This must be because they are NOT_PART edges for that geometry, + and are disconnected from any edges of that geometry. + An example of this is rings of one geometry wholly contained + in another geometry.
+ The location must be fully determined to compute a + correct result for all overlay operations. + + If the input geometry is an Area the edge location can + be determined via a PIP test. + If the input is not an Area the location is EXTERIOR. +
+
+ + + Determines the location of an edge relative to a target input geometry. + The edge has no location information + because it is disconnected from other + edges that would provide that information. + The location is determined by checking + if the edge lies inside the target geometry area(if any). + + The edge to label + The input geometry to label against + + + + Determines the for an edge within an Area geometry + via point-in-polygon location. + + NOTE this is only safe to use for disconnected edges, + since the test is carried out against the original input geometry, + and precision reduction may cause incorrect results for edges + which are close enough to a boundary to become connected. + + The parent geometry index + The edge to locate + The location of the edge. + + + + Determines the {@link Location} for an edge within an Area geometry + via point-in-polygon location, + by checking that both endpoints are interior to the target geometry. + Checking both endpoints ensures correct results in the presence of topology collapse. + + NOTE this is only safe to use for disconnected edges, + since the test is carried out against the original input geometry, + and precision reduction may cause incorrect results for edges + which are close enough to a boundary to become connected. + + The parent geometry index + The edge to locate + The location of the edge + + + + Marks an edge which forms part of the boundary of the result area. + This is determined by the overlay operation being executed, + and the location of the edge. + The relevant location is either the right side of a boundary edge, + or the line location of a non-boundary edge. + + The edge to mark + The overlay operation + + + + Unmarks result area edges where the sym edge + is also marked as in the result. + This has the effect of merging edge-adjacent result areas, + as required by polygon validity rules. + + + + + Computes an overlay where one input is Point(s) and one is not. + This class supports overlay being used as an efficient way + to find points within or outside a polygon. + + Input semantics are: + + Duplicates are removed from Point output + Non-point output is rounded and noded using the given precision model + + Output semantics are: + + An empty result is an empty atomic geometry + with dimension determined by the inputs and the operation as per overlay semantics + + + For efficiency the following optimizations are used: + + Input points are not included in the noding of the non-point input geometry + (in particular, they do not participate in snap-rounding if that is used). + If the non-point input geometry is not included in the output + it is not rounded and noded.This means that points + are compared to the non-rounded geometry. + This will be apparent in the result. + + This means that overlay is efficient to use for finding points + within or outside a polygon. + + Martin Davis + + + + Copy the non-point input geometry if not + already done by precision reduction process. + + A copy of the non-point geometry + + + + Computes the geometric overlay of two s, + using an explicit precision model to allow robust computation. + + The overlay can be used to determine any of the + following set-theoretic operations (boolean combinations) of the geometries: + + all points which lie in both geometries + all points which lie in at least one geometry + all points which lie in the first geometry but not the second + all points which lie in one geometry but not both + + Input geometries may have different dimension. + Input collections must be homogeneous (all elements must have the same dimension). + + The precision model used for the computation can be supplied + independent of the precision model of the input geometry. + The main use for this is to allow using a fixed precision + for geometry with a floating precision model. + This does two things: ensures robust computation; + and forces the output to be validly rounded to the precision model. + + For fixed precision models noding is performed using a . + This provides robust computation(as long as precision is limited to + around 13 decimal digits). + + For floating precision an is used. + This is not fully robust, so can sometimes result in + s being thrown. + For robust full-precision overlay see . + + A custom can be supplied. + This allows using a more performant noding strategy in specific cases, + for instance in . + + Note: If a is used + it is best to specify a fairly small snap tolerance, + since the intersection clipping optimization can + interact with the snapping to alter the result. + + Optionally the overlay computation can process using strict mode + (via = true). + In strict mode result semantics are: + + Lines and Points resulting from topology collapses are not included in the result + Result geometry is homogeneous + for the and operations. + Result geometry is homogeneous + for the and operations + if the inputs have the same dimension + + Strict mode has the following benefits: + + Results are simpler + Overlay operations are easily chainable + without needing to remove lower-dimension elements + + The original JTS overlay semantics corresponds to non-strict mode. + + If a robustness error occurs, a is thrown. + These are usually caused by numerical rounding causing the noding output + to not be fully noded. + For robust computation with full-precision + can be used. + + + + + The code for the Intersection overlay operation. + + + + + The code for the Union overlay operation. + + + + + The code for the Difference overlay operation. + + + + + The code for the Symmetric Difference overlay operation. + + + + + The default setting for Strict Mode. + + The original JTS overlay semantics used non-strict result + semantics, including;
+ - An Intersection result can be mixed-dimension, + due to inclusion of intersection components of all dimensions
+ - Results can include lines caused by Area topology collapse +
+
+ + + Tests whether a point with a given topological + relative to two geometries is contained in + the result of overlaying the geometries using + a given overlay operation. + + The method handles arguments of correctly + + The topological label of the point + The code for the overlay operation to test + true if the label locations correspond to the overlay + + + + Tests whether a point with given s + relative to two geometries would be contained in + the result of overlaying the geometries using + a given overlay operation. + This is used to determine whether components + computed during the overlay process should be + included in the result geometry. + + The method handles arguments of correctly. + + The code for the overlay operation to test + The code for the location in the first geometry + The code for the location in the second geometry + true if a point with given locations is in the result of the overlay operation + + + + Computes an overlay operation for + the given geometry operands, with the + noding strategy determined by the precision model. + + The first geometry argument + The second geometry argument + The code for the desired overlay operation + The precision model to use + The result of the overlay operation + + + + Computes an overlay operation for + the given geometry operands, using a supplied . + + The first geometry argument + The second geometry argument + The code for the desired overlay operation + The precision model to use (which may be null if the noder does not use one) + The noder to use + The result of the overlay operation + + + + Computes an overlay operation on the given geometry operands, + using a supplied . + + The first geometry argument + The second geometry argument + The code for the desired overlay operation + The noder to use + The result of the overlay operation + + + + Computes an overlay operation on + the given geometry operands, + using the precision model of the geometry. + and an appropriate noder. + + The noder is chosen according to the precision model specified. + + For + a snap-rounding noder is used, and the computation is robust. + For + a non-snapping noder is used, + and this computation may not be robust. + If errors occur a is thrown. + + + The first geometry argument + The second geometry argument + The code for the desired overlay operation + The result of the overlay operation + + + + Computes a union operation on + the given geometry, with the supplied precision model. + + The input must be a valid geometry. + Collections must be homogeneous. + + To union an overlapping set of polygons in a more performant way use . + To union a polygonal coverage or linear network in a more performant way, + use . + + The geometry + The precision model to use + The result of the union operation + + + + + Computes a union of a single geometry using a custom noder. + + The primary use of this is to support coverage union. + Because of this the overlay is performed using strict mode. + + The geometry to union + The precision model to use (maybe be null) + The noder to use + the result geometry + + + + + Creates an overlay operation on the given geometries, + with a defined precision model. + + The A operand geometry + The B operand geometry (may be null) + The precision model to use + The overlay opcode + + + + Creates an overlay operation on the given geometries + using the precision model of the geometries. + + The noder is chosen according to the precision model specified. + + For + a snap - rounding noder is used, and the computation is robust. + For a non - snapping noder is used, + and this computation may not be robust. + If errors occur a is thrown. + + + The A operand geometry + The B operand geometry (may be null) + The overlay opcode + + + + Creates a union of a single geometry with a given precision model. + + The geometry + The precision model to use + + + + Gets or sets whether the overlay results are computed according to strict mode + semantics. + + Lines resulting from topology collapse are not included + Result geometry is homogeneous for the + and + operations. + Result geometry is homogeneous for the + and + operations if the inputs have the same dimension + + + + + + + Gets or sets a value indicating whether overlay processing optimizations are enabled. + + It may be useful to disable optimizations + for testing purposes. + + Default is true (optimization enabled). + + + + + Gets or sets whether the result can contain only components. + This is used if it is known that the result must be an (possibly empty) area. + + true if the result should contain only area components + + + + Gets the result of the overlay operation. + e + The result of the overlay operation. + Thrown, if the input is not supported (e.g. a mixed-dimension geometry) + Thrown, if a robustness error occurs + + + + Extracts the result geometry components from the fully labelled topology graph. + + This method implements the semantic that the result of an + intersection operation is homogeneous with highest dimension. + In other words, + if an intersection has components of a given dimension + no lower-dimension components are output. + For example, if two polygons intersect in an area, + no linestrings or points are included in the result, + even if portions of the input do meet in lines or points. + This semantic choice makes more sense for typical usage, + in which only the highest dimension components are of interest. + + The overlay operation + The topology graph + The result geometry + + + + Performs an overlay operation using , + increasing robustness by using a series of + increasingly robust (but slower) noding strategies. + + The noding strategies used are: + + A simple fast noder using precision + A using an automatically-determined snap tolerance + First snapping each geometry to itself, and then overlaying them wih a + The above two strategies are repeated with increasing snap tolerance, up to a limit + Finally a is used with a automatically-determined scale factor. + + If all of the above heuristics fail to compute a valid overlay, + the original is thrown. + In practice this should be extremely unlikely to occur. + + This algorithm relies on each overlay operation execution + throwing a if it is unable + to compute the overlay correctly. + Generally this occurs because the noding phase does + not produce a valid noding. + This requires the use of a + in order to check the results of using a floating noder. + + Martin Davis + + + + Computes the unary union of a geometry using robust computation. + + The geometry to union + The union result + + + + Computes the unary union of a collection of geometries using robust computation. + + An enumeration of geometries to union + The union result + + + + Computes the unary union of a collection of geometries using robust computation. + + An enumeration of geometries to union + The geometry factory to use + The union of the geometries + + + + Overlay two geometries, using heuristics to ensure + computation completes correctly. + In practice the heuristics are observed to be fully correct. + + A geometry + A geometry + The overlay operation code + The overlay result geometry + + + + Attempt overlay using snapping with repeated tries with increasing snap tolerances. + + + + + The computed overlay result, or null if the overlay fails + + + + Attempt overlay using a . + + + + + + The computed overlay result, or null if the overlay fails + + + + Attempt overlay with first snapping each geometry individually. + + + + + + The computed overlay result, or null if the overlay fails + + + + Self-snaps a geometry by running a union operation with it as the only input. + This helps to remove narrow spike/gore artifacts to simplify the geometry, + which improves robustness. + Collapsed artifacts are removed from the result to allow using + it in further overlay operations. + + Geometry to self-snap + Snap tolerance + The snapped geometry (homogenous) + + + + A factor for a snapping tolerance distance which + should allow noding to be computed robustly. + + + + + Computes a heuristic snap tolerance distance + for overlaying a pair of geometries using a . + + + + + + + + Computes the largest magnitude of the ordinates of a geometry, + based on the geometry envelope. + + + The magnitude of the largest ordinate + + + + Attempt Overlay using Snap-Rounding with an automatically-determined + scale factor. + + + + + the computed overlay result, or null if the overlay fails + + + + Performs an overlay operation on inputs which are both point geometries. + + Semantics are: + + Points are rounded to the precision model if provided + Points with identical XY values are merged to a single point + Extended ordinate values are preserved in the output, apart from merging + An empty result is returned as POINT EMPTY + + + Martin Davis + + + + Performs an overlay operation on inputs which are both point geometries. + + The code for the desired overlay operation + The first geometry argument + The second geometry argument + The precision model to use + The result of the overlay operation + + + + Creates an instance of an overlay operation on inputs which are both point geometries. + + The code for the desired overlay operation + The first geometry argument + The second geometry argument + The precision model to use + + + + Gets the result of the overlay. + + + + + Round the key point if precision model is fixed. + Note: return value is only copied if rounding is performed. + + + + + Utility methods for overlay processing. + + Martin Davis + + + + A null-handling wrapper for + + A precision model + true if the provided precision model is floating + + + + Computes a clipping envelope for overlay input geometries. + The clipping envelope encloses all geometry line segments which + might participate in the overlay, with a buffer to + account for numerical precision + (in particular, rounding due to a precision model. + The clipping envelope is used in both the + and in the . + + Some overlay operations (i.e. and ) + cannot use clipping as an optimization, + since the result envelope is the full extent of the two input geometries. + In this case the returned + envelope is null to indicate this. + + The overlay op code + The input geometries + The precision model being used + An envelope for clipping and line limiting, or null if no clipping is performed + + + + Computes an envelope which covers the extent of the result of + a given overlay operation for given inputs. + The operations which have a result envelope smaller than the extent of the inputs + are: + + + result envelope is the intersection of the input envelopes + + result envelope is the envelope of the A input geometry + + Otherwise, null is returned to indicate full extent. + + The overlay op code + The input geometries + The precision model being used + The result envelope, or null if the full extent + + + + Determines a safe geometry envelope for clipping, + taking into account the precision model being used. + + A safe geometry envelope for clipping + The precision model + A safe envelope to use for clipping + + + + Tests if the result can be determined to be empty + based on simple properties of the input geometries + (such as whether one or both are empty, + or their envelopes are disjoint). + + The overlay operation + The A operand geometry + The B operand geometry + The precision model to use + true if the overlay result is determined to be empty + + + + Tests if the geometry envelopes are disjoint, or empty. + The disjoint test must take into account the precision model + being used, since geometry coordinates may shift under rounding. + + The A operand geometry + The B operand geometry + The precision model to use + true if the geometry envelopes are disjoint or empty + + + + Tests for disjoint envelopes adjusting for rounding + caused by a fixed precision model. + Assumes envelopes are non-empty. + + The A operand envelope + The B operand envelope + The precision model to use + true if the envelopes are disjoint + + + + Creates an empty result geometry of the appropriate dimension, + based on the given overlay operation and the dimensions of the inputs. + The created geometry is an atomic geometry, + not a collection(unless the dimension is , + in which case a GEOMETRYCOLLECTION EMPTY is created. + + The dimension of the empty geometry + The geometry factory being used for the operation + An empty atomic geometry of the appropriate dimension + + + + Computes the dimension of the result of + applying the given operation to inputs + with the given dimensions. + This assumes that complete collapse does not occur. + + The result dimension is computed using the following rules: + + result has the dimension of the lowest input dimension + result has the dimension of the highest input dimension + result has the dimension of the left-hand input + result has the dimension of the highest input dimension + (since the Symmetric Difference is the Union of the Differences). + + + The overlay operation + Dimension of the LH input + Dimension of the RH input + + + + + Creates an overlay result geometry for homogeneous or mixed components. + + An enumeration of result polygons (may be empty or null) + An enumeration of result lines (may be empty or null) + An enumeration of result points (may be empty or null) + The geometry factory to use. + A geometry structured according to the overlay result semantics + + + + Round the key point if precision model is fixed. + Note: return value is only copied if rounding is performed. + + The point to round + The precision model to use + The rounded point coordinate, or null if empty + + + + A heuristic check for overlay result correctness + comparing the areas of the input and result. + The heuristic is necessarily coarse, but it detects some obvious issues.
+ (e.g. ) + + Note: - this check is only safe if the precision model is floating. + It should also be safe for snapping noding if the distance tolerance is reasonably small. + (Fixed precision models can lead to collapse causing result area to expand.) +
+ Input geometry 0 + Input geometry 1 + The overlay opcode + The overlay result + true if the result area is consistent +
+ + + For all OverlayEdges in result, form them into MaximalEdgeRings + + + + + Finds the single shell, if any, out of + a list of minimal rings derived from a maximal ring. + The other possibility is that they are a set of (connected) holes, + in which case no shell will be found. + + The shell ring, if there is one + or null, if all rings are holes + + + + + For the set of minimal rings comprising a maximal ring, + assigns the holes to the shell known to contain them. + Assigning the holes directly to the shell serves two purposes: + + it is faster than using a point-in-polygon check later on. + it ensures correctness, since if the PIP test was used the point + chosen might lie on the shell, which might return an incorrect result from the + PIP test + + + + + + Place holes have not yet been assigned to a shell. + These "free" holes should + all be properly contained in their parent shells, so it is safe to use the + findEdgeRingContaining method. + (This is the case because any holes which are NOT + properly contained (i.e. are connected to their + parent shell) would have formed part of a MaximalEdgeRing + and been handled in a previous step). + + If a hole cannot be assigned to a shell + + + + Functions to reduce the precision of a geometry + by rounding it to a given precision model. + + This class handles only polygonal and linear inputs. + For full functionality . + + + Martin Davis + + + + Reduces the precision of a geometry by rounding and snapping it to the + supplied .
+ The input geometry must be polygonal or linear. + + The output is always a valid geometry. This implies that input components + may be merged if they are closer than the grid precision. + if merging is not desired, then the individual geometry components + should be processed separately. + + The output is fully noded (i.e. coincident lines are merged and noded). + This provides an effective way to node / snap-round a collection of s. +
+ The geometry to reduce + The precision model to use + The precision-reduced geometry +
+ + + Functions for computing precision model scale factors + that ensure robust geometry operations. + In particular, these can be used to + automatically determine appropriate scale factors for operations + using limited-precision noding (such as ). + + WARNING: the inherentScale and robustScale + functions can be very slow, due to the method used to determine + number of decimal places of a number. + These are not recommended for production use. + + Martin Davis + + + + A number of digits of precision which leaves some computational "headroom" + to ensure robust evaluation of certain double-precision floating point geometric operations. + + This value should be less than the maximum decimal precision of double-precision values (16). + + + + + Computes a safe scale factor for a numeric value. + A safe scale factor ensures that rounded + number has no more than + digits of precision. + + A numeric value. + A safe scale factor for the value + + + + Computes a safe scale factor for a geometry. + A safe scale factor ensures that rounded + number has no more than + digits of precision. + + A geometry. + A safe scale factor for the geometry ordinates + + + + Computes a safe scale factor for two geometry. + A safe scale factor ensures that rounded + number has no more than + digits of precision. + + A geometry. + A geometry (which may be null). + A safe scale factor for the geometry ordinates + + + + Determines the maximum magnitude (absolute value) of the bounds of an + of an envelope. + This is equal to the largest ordinate value + which must be accommodated by a scale factor. + + An envelope + The value of the maximum bound magnitude + + + + Computes the scale factor which will + produce a given number of digits of precision(significant digits) + when used to round the given number. + + For example: to provide 5 decimal digits of precision + for the number 123.456 the precision scale factor is 100; + for 3 digits of precision the scale factor is 1; + for 2 digits of precision the scale factor is 0.1. + + Rounding to the scale factor can be performed with + + A number to be rounded + The number of digits of precision required + The scale factor which provides the required number of digits of precision + + + + + Computes the inherent scale of a number. + The inherent scale is the scale factor for rounding + which preserves all digits of precision + (significant digits) + present in the numeric value. + In other words, it is the scale factor which does not + change the numeric value when rounded: + + num = round( num, inherentScale(num) ) + + + A number + The inherent scale factor of the number + + + + Computes the inherent scale of a geometry. + The inherent scale is the scale factor for rounding + which preserves all digits of precision + (significant digits) + present in the geometry ordinates. + + This is the maximum inherent scale + of all ordinate values in the geometry. + + WARNING: this is very slow. + + A geometry + The inherent scale factor in the geometry's ordinates + + + + Computes the inherent scale of two geometries. + The inherent scale is the scale factor for rounding + which preserves all digits of precision + (significant digits) + present in the geometry ordinates. + + This is the maximum inherent scale + of all ordinate values in the geometries. + + A geometry + A geomety (which may be null) + The inherent scale factor in the geometries' ordinates + + + + Determines the + number of decimal places represented in a double-precision + number (as determined by .NET). + This uses the .NET double-precision print routine + to determine the number of decimal places, + This is likely not optimal for performance, + but should be accurate and portable. + + A numeric value + The number of decimal places in the value + + + + Applies the inherent scale calculation + to every ordinate in a geometry. + + WARNING: this is very slow. + + Martin Davis + + + + Determines a precision model to + use for robust overlay operations for one geometry. + The precision scale factor is chosen to maximize + output precision while avoiding round-off issues. + + NOTE: this is a heuristic determination, so is not guaranteed to + eliminate precision issues. + + WARNING: this is very slow. + + A geometry + A suitable precision model for overlay + + + + Determines a scale factor which maximizes + the digits of precision and is + safe to use for overlay operations. + The robust scale is the minimum of the + inherent scale and the safe scale factors. + + WARNING: this is very slow. + + A geometry + A geometry + A scale factor for use in overlay operations + + + + Determines a scale factor which maximizes + the digits of precision and is + safe to use for overlay operations. + The robust scale is the minimum of the + inherent scale and the safe scale factors. + + A geometry + A scale factor for use in overlay operations + + + + Clips a ring of points to an rectangle. + Uses a variant of Cohen-Sutherland clipping. + + In general the output is not topologically valid. + In particular, the output may contain coincident non-noded line segments + along the clip rectangle sides. + However, the output is sufficiently well-structured + that it can be used as input to the algorithm + (which is able to process coincident linework due + to the need to handle topology collapse under precision reduction). + + Because of the likelihood of creating + extraneous line segments along the clipping rectangle sides, + this class is not suitable for clipping linestrings. + + The clipping envelope should be generated using , + to ensure that intersecting line segments are not perturbed + by clipping. + This is required to ensure that the overlay of the + clipped geometry is robust and correct (i.e. the same as + if clipping was not used). + + + Martin Davis + + + + Creates a new clipper for the given envelope. + + The clipping envelope + + + + Clips a list of points to the clipping rectangle box. + + The points of the ring + The points of the clipped ring + + + + Clips line to the axis-parallel line defined by a single box edge. + + The coordinates + An edge index + A flag indicating whether to close the ring. + The clipped coordinates + + + + Computes the intersection point of a segment + with an edge of the clip box. + The segment must be known to intersect the edge. + + First endpoint of the segment + Second endpoint of the segment + Index of box edge + + The intersection point with the box edge + + + + + Computes a robust clipping envelope for a pair of polygonal geometries. + The envelope is computed to be large enough to include the full + length of all geometry line segments which intersect + a given target envelope. + This ensures that line segments which might intersect are + not perturbed when clipped using . + + Martin Davis + + + + Adds a polygon ring to the graph. Empty rings are ignored. + + + + + Unions a collection of geometries in an + efficient way, using + to ensure robust computation. + + This class is most useful for performing UnaryUnion using + a fixed-precision model.
+ For unary union using floating precision, + should be used. +
+ Martin Davis +
+ + + Unions a geometry (which is often a collection) + using a given precision model. + + The geometry to union + The precision model to use + The union of the geometry + + + + + Unions a geometry (which is often a collection) + using a given precision model. + + The geometries to union + The precision model to use + The union of the geometries + + + + + Unions a geometry (which is often a collection) + using a given precision model. + + The geometries to union + The geometry factory to use + The precision model to use + The union of the geometries + + + + + Nodes a set of edges. + Takes one or more sets of edges and constructs a + new set of edges consisting of all the split edges created by + noding the input edges together. + + + + + + + + + + + + + + + + + + + + + + Forms NTS LineStrings out of a the graph of DirectedEdges + created by an OverlayOp. + + + + + + + + + + + + + + + + + A list of the LineStrings in the result of the specified overlay operation. + + + + + Find and mark L edges which are "covered" by the result area (if any). + L edges at nodes which also have A edges can be checked by checking + their depth at that node. + L edges at nodes which do not have A edges can be checked by doing a + point-in-polygon test with the previously computed result areas. + + + + + + + + + + + + + + + + + + + Collect edges from Area inputs which should be in the result but + which have not been included in a result area. + This happens ONLY: + during an intersection when the boundaries of two + areas touch in a line segment + OR as a result of a dimensional collapse. + + + + + + + + + + + + + + + + + + + + Label an isolated node with its relationship to the target point. + + + + + + + A ring of edges which may contain nodes of degree > 2. + A MaximalEdgeRing may represent two different spatial entities: + a single polygon possibly containing inversions (if the ring is oriented CW) + a single hole possibly containing exversions (if the ring is oriented CCW) + If the MaximalEdgeRing represents a polygon, + the interior of the polygon is strongly connected. + These are the form of rings used to define polygons under some spatial data models. + However, under the OGC SFS model, MinimalEdgeRings are required. + A MaximalEdgeRing can be converted to a list of MinimalEdgeRings using the + BuildMinimalRings() method. + + + + + + + + + + + + + + + + + + + + + + + + + + For all nodes in this EdgeRing, + link the DirectedEdges at the node to form minimalEdgeRings + + + + + + + + + + + A ring of edges with the property that no node + has degree greater than 2. These are the form of rings required + to represent polygons under the OGC SFS spatial data model. + + + + + + + + + + + + + + + + + + + + + + + + + + Creates nodes for use in the PlanarGraphs constructed during + overlay operations. + + + + + + + + + + + + The spatial functions supported by this class. + These operations implement various bool combinations of the resultants of the overlay. + + + + + The code for the Intersection overlay operation + + + + + The code for the Union overlay operation + + + + + The code for the Difference overlay operation + + + + + The code for the Symmetric Difference overlay operation + + + + + Computes the geometric overlay of two s. The overlay + can be used to determine any bool combination of the geometries. + + + + + Disable + when an intersection is made (), + so performances are dramatically improved but failures are not managed. + + + Use ay your own risk! + + + + + Computes an overlay operation + for the given geometry arguments. + + The first geometry argument + The second geometry argument + The code for the desired overlay operation + The result of the overlay operation + Thrown if a robustness problem is encountered. + + + + Tests whether a point with a given topological + relative to two geometries is contained in + the result of overlaying the geometries using + a given overlay operation. + + The method handles arguments of correctly + + The topological label of the point + The code for the overlay operation to test + true if the label locations correspond to the overlayOpCode + + + + Tests whether a point with given s + relative to two geometries is contained in + the result of overlaying the geometries using + a given overlay operation. + + The method handles arguments of correctly + + the code for the location in the first geometry + the code for the location in the second geometry + the code for the overlay operation to test + true if the locations correspond to the overlayOpCode. + + + + Constructs an instance to compute a single overlay operation + for the given geometries. + + The first geometry argument + The second geometry argument + + + + Gets the result of the overlay for a given overlay operation. + + Note: this method can be called once only. + + The code of the overlay operation to perform + The computed result geometry + Thrown if a robustness problem is encountered + + + + Gets the graph constructed to compute the overlay. + + + + + Insert an edge from one of the noded input graphs. + Checks edges that are inserted to see if an + identical edge already exists. + If so, the edge is not inserted, but its label is merged + with the existing edge. + + The edge to insert + + + + Update the labels for edges according to their depths. + For each edge, the depths are first normalized. + Then, if the depths for the edge are equal, + this edge must have collapsed into a line edge. + If the depths are not equal, update the label + with the locations corresponding to the depths + (i.e. a depth of 0 corresponds to a Location of Exterior, + a depth of 1 corresponds to Interior) + + + + + If edges which have undergone dimensional collapse are found, + replace them with a new edge which is a L edge + + + + + Copy all nodes from an arg point into this graph. + The node label in the arg point overrides any previously computed + label for that argIndex. + (E.g. a node may be an intersection node with + a previously computed label of Boundary, + but in the original arg Geometry it is actually + in the interior due to the Boundary Determination Rule) + + + + + + Compute initial labelling for all DirectedEdges at each node. + In this step, DirectedEdges will acquire a complete labelling + (i.e. one with labels for both Geometries) + only if they + are incident on a node which has edges for both Geometries + + + + + For nodes which have edges from only one Geometry incident on them, + the previous step will have left their dirEdges with no labelling for the other + Geometry. However, the sym dirEdge may have a labelling for the other + Geometry, so merge the two labels. + + + + + Incomplete nodes are nodes whose labels are incomplete. + (e.g. the location for one Geometry is null). + These are either isolated nodes, + or nodes which have edges from only a single Geometry incident on them. + Isolated nodes are found because nodes in one graph which don't intersect + nodes in the other are not completely labelled by the initial process + of adding nodes to the nodeList. + To complete the labelling we need to check for nodes that lie in the + interior of edges, and in the interior of areas. + When each node labelling is completed, the labelling of the incident + edges is updated, to complete their labelling as well. + + + + + Label an isolated node with its relationship to the target point. + + + + + Find all edges whose label indicates that they are in the result area(s), + according to the operation being performed. Since we want polygon shells to be + oriented CW, choose dirEdges with the interior of the result on the RHS. + Mark them as being in the result. + Interior Area edges are the result of dimensional collapses. + They do not form part of the result area boundary. + + + + + If both a dirEdge and its sym are marked as being in the result, cancel + them out. + + + + + Tests if a point node should be included in the result or not. + + The point coordinate + true if the coordinate point is covered by a result Line or Area geometry. + + + + Tests if an L edge should be included in the result or not. + + The point coordinate + true if the coordinate point is covered by a result Area geometry. + + + + true if the coord is located in the interior or boundary of + a point in the list. + + + + + Creates an empty result geometry of the appropriate dimension, + based on the given overlay operation and the dimensions of the inputs. + The created geometry is always an atomic geometry, + not a collection. + + The empty result is constructed using the following rules: + + - result has the dimension of the lowest input dimension + - result has the dimension of the highest input dimension + - result has the dimension of the left-hand input + - result has the dimension of the highest input dimension + (since symDifference is the union of the differences). + + + The overlay operation being performed + An input geometry + An input geometry + The geometry factory being used for the operation + An empty atomic geometry of the appropriate dimension + + + + Constructs Points from the nodes of an overlay graph. + + + + + Creates an instance of this class + + The operation + The geometry factory + + + + Computes the Point geometries which will appear in the result, + given the specified overlay operation. + + The spatial function + + A list of the Points in the result. + + + + + Determines nodes which are in the result, and creates s for them. + + + This method determines nodes which are candidates for the result via their + labelling and their graph topology. + + The overlay operation + + + + Converts non-covered nodes to Point objects and adds them to the result. + + + A node is covered if it is contained in another element Geometry + with higher dimension (e.g. a node point might be contained in a polygon, + in which case the point can be eliminated from the result). + + The node to test + + + + Forms Polygons out of a graph of {DirectedEdge}s. + The edges to use are marked as being in the result Area. + + + + + + + + + + + Add a complete graph. + The graph is assumed to contain one or more polygons, + possibly with holes. + + + + + + Add a set of edges and nodes, which form a graph. + The graph is assumed to contain one or more polygons, + possibly with holes. + + + + + + + + + + + + For all DirectedEdges in result, form them into MaximalEdgeRings. + + + + + + + + + + + + + + + + This method takes a list of MinimalEdgeRings derived from a MaximalEdgeRing, + and tests whether they form a Polygon. This is the case if there is a single shell + in the list. In this case the shell is returned. + The other possibility is that they are a series of connected holes, in which case + no shell is returned. + + The shell EdgeRing, if there is one
or + null, if all the rings are holes.
+
+ + + This method assigns the holes for a Polygon (formed from a list of + MinimalEdgeRings) to its shell. + Determining the holes for a MinimalEdgeRing polygon serves two purposes: + it is faster than using a point-in-polygon check later on. + it ensures correctness, since if the PIP test was used the point + chosen might lie on the shell, which might return an incorrect result from the + PIP test. + + + + + + + For all rings in the input list, + determine whether the ring is a shell or a hole + and add it to the appropriate list. + Due to the way the DirectedEdges were linked, + a ring is a shell if it is oriented CW, a hole otherwise. + + + + + + + + This method determines finds a containing shell for all holes + which have not yet been assigned to a shell. + These "free" holes should + all be properly contained in their parent shells, so it is safe to use the + findEdgeRingContaining method. + (This is the case because any holes which are NOT + properly contained (i.e. are connected to their + parent shell) would have formed part of a MaximalEdgeRing + and been handled in a previous step). + + + + + + + Find the innermost enclosing shell EdgeRing containing the argument EdgeRing, if any. + The innermost enclosing ring is the smallest enclosing ring. + The algorithm used depends on the fact that: + ring A contains ring B if envelope(ring A) contains envelope(ring B). + This routine is only safe to use if the chosen point of the hole + is known to be properly contained in a shell + (which is guaranteed to be the case if the hole does not touch its shell). + + + + Containing EdgeRing, if there is one
or + null if no containing EdgeRing is found.
+
+ + + + + + + + + + Snaps the vertices and segments of a + to another Geometry's vertices. + A snap distance tolerance is used to control where snapping is performed. + Snapping one geometry to another can improve + robustness for overlay operations by eliminating + nearly-coincident edges + (which cause problems during noding and intersection calculation). + It can also be used to eliminate artifacts such as narrow slivers, spikes and gores. + Too much snapping can result in invalid topology + beging created, so the number and location of snapped vertices + is decided using heuristics to determine when it + is safe to snap. + This can result in some potential snaps being omitted, however. + + Martin Davis + + + + Estimates the snap tolerance for a Geometry, taking into account its precision model. + + + The estimated snap tolerance + + + + + + + + + + + + + + + + + + + Snaps two geometries together with a given tolerance. + + + + + + + + + Snaps a geometry to itself. + Allows optionally cleaning the result to ensure it is topologically valid + (which fixes issues such as topology collapses in polygonal inputs). + Snapping a geometry to itself can remove artifacts such as very narrow slivers, gores and spikes. + + the geometry to snap + the snapping tolerance + whether the result should be made valid + a new snapped + + + + Creates a new snapper acting on the given geometry + + the geometry to snap + + + + Snaps the vertices in the component s + of the source geometry to the vertices of the given snap geometry. + + a geometry to snap the source to + + a new snapped Geometry + + + Snaps the vertices in the component s + of the source geometry to the vertices of the same geometry. + Allows optionally cleaning the result to ensure it is topologically valid + (which fixes issues such as topology collapses in polygonal inputs). + The snapping tolerance + Whether the result should be made valid + The geometry snapped to itself + + + + + + + + + + + Computes the snap tolerance based on the input geometries. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Snaps the vertices and segments of a + to a set of target snap vertices. + A snap distance tolerance is used to control where snapping is performed. + The implementation handles empty geometry and empty snap vertex sets. + + + + + Creates a new snapper using the points in the given + as target snap points. + + A LineString to snap (may be empty) + the snap tolerance to use + + + + Creates a new snapper using the given points + as source points to be snapped. + + + + + + + Snaps the vertices and segments of the source LineString + to the given set of snap points. + + the vertices to snap to + list of the snapped points + + + + Snap source vertices to vertices in the target. + + the points to snap + the points to snap to + + + + + + + + + + + + Snap segments of the source to nearby snap vertices. + Source segments are "cracked" at a snap vertex. + A single input segment may be snapped several times + to different snap vertices. + For each distinct snap vertex, at most one source segment + is snapped to. This prevents "cracking" multiple segments + at the same point, which would likely cause + topology collapse when being used on polygonal linework. + + The coordinates of the source linestring to snap + The target snap vertices + + + + Finds a src segment which snaps to (is close to) the given snap point + Only a single segment is selected for snapping. + This prevents multiple segments snapping to the same snap vertex, + which would almost certainly cause invalid geometry + to be created. + (The heuristic approach of snapping used here + is really only appropriate when + snap pts snap to a unique spot on the src geometry) + Also, if the snap vertex occurs as a vertex in the src coordinate list, + no snapping is performed. + + The point to snap to + The source segment coordinates + The index of the snapped segment
+ or -1 if no segment snaps to the snap point.
+
+ + + Performs an overlay operation using snapping and enhanced precision + to improve the robustness of the result. + This class only uses snapping + if an error is detected when running the standard JTS overlay code. + Errors detected include thrown exceptions + (in particular, ) + and invalid overlay computations. + + + + + Performs an overlay operation using snapping and enhanced precision + to improve the robustness of the result. + This class always uses snapping. + This is less performant than the standard JTS overlay code, + and may even introduce errors which were not present in the original data. + For this reason, this class should only be used + if the standard overlay code fails to produce a correct result. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Finds the most likely of a point relative to + the polygonal components of a geometry, using a tolerance value. + + + If a point is not clearly in the Interior or Exterior, + it is considered to be on the Boundary. + In other words, if the point is within the tolerance of the Boundary, + it is considered to be on the Boundary; otherwise, + whether it is Interior or Exterior is determined directly. + + Martin Davis + + + + Extracts linework for polygonal components. + + The geometry from which to extract + A lineal geometry containing the extracted linework + + + + Extracts the LineStrings in the boundaries of all the polygonal elements in the target . + + Martin Davis + + + + Filters out all linework for polygonal elements + + + + + Gets the list of polygonal linework. + + + + + Generates points offset by a given distance from both sides of the midpoint of all segments in a . + + + + Can be used to generate probe points for determining whether a polygonal overlay result is incorrect. + + + The input geometry may have any orientation for its rings, + but is + only meaningful if the orientation is known. + + + Martin Davis + + + + Set the sides on which to generate offset points. + + + + + + + Gets the computed offset points. + + + + + Generates the two points which are offset from the + midpoint of the segment (p0, p1) by the offsetDistance + + The first point of the segment to offset from. + The second point of the segment to offset from + + + + + + Validates that the result of an overlay operation is geometrically correct within a determined tolerance. + Uses fuzzy point location to find points which are + definitely in either the interior or exterior of the result + geometry, and compares these results with the expected ones. + + + This algorithm is only useful where the inputs are polygonal. + This is a heuristic test, and may return false positive results + (I.e. it may fail to detect an invalid result.) + It should never return a false negative result, however + (I.e. it should never report a valid result as invalid.) + + Martin Davis + + + + + Represents a ring of s which form + a ring of a polygon. The ring may be either an outer shell or a hole. + + + + + Find the innermost enclosing shell EdgeRing containing the argument EdgeRing, if any. + The innermost enclosing ring is the smallest enclosing ring. + The algorithm used depends on the fact that: + ring A contains ring B if envelope(ring A) contains envelope(ring B). + This routine is only safe to use if the chosen point of the hole + is known to be properly contained in a shell + (which is guaranteed to be the case if the hole does not touch its shell). + + To improve performance of this function the caller should + make the passed shellList as small as possible(e.g. + by using a spatial index filter beforehand). + + + + Containing EdgeRing, if there is one
+ or null if no containing EdgeRing is found.
+
+ + + Traverses a ring of DirectedEdges, accumulating them into a list. + This assumes that all dangling directed edges have been removed + from the graph, so that there is always a next dirEdge. + + The DirectedEdge to start traversing at + A list of DirectedEdges that form a ring + + + + + + + + + + Adds a DirectedEdge which is known to form part of this ring. + + The DirectedEdge to add. + + + + Tests whether this ring is a hole. + Due to the way the edges in the polygonization graph are linked, + a ring is a hole if it is oriented counter-clockwise. + + true if this ring is a hole. + + + + Computes whether this ring is a hole. + Due to the way the edges in the polygonization graph are linked, + a ring is a hole if it is oriented counter-clockwise. + + + + + Adds a hole to the polygon formed by this ring. + + The LinearRing forming the hole. + + + + Adds a hole to the polygon formed by this ring. + + the forming the hole. + + + + Computes and returns the Polygon formed by this ring and any contained holes. + + + + + Tests if the ring formed by this edge ring is topologically valid. + + true if the ring is valid. + + + + Computes and returns the list of coordinates which are contained in this ring. + The coordinates are computed once only and cached. + + + + + Gets the coordinates for this ring as a LineString. + Used to return the coordinates in this ring + as a valid point, when it has been detected that the ring is topologically + invalid. + + + + + Returns this ring as a LinearRing, or null if an Exception occurs while + creating it (such as a topology problem). Details of problems are written to + standard output. + + + + + + + + + + + + + Gets or sets a value indicating the containing shell ring of a ring that has been determined to be a hole. + + + + + Gets a value indicating whether this ring has a shell assigned to it. + + + + + Tests whether this ring is an outer hole. + A hole is an outer hole if it is not contained by a shell. + + + + + Tests whether this ring is an outer shell. + + + + + Gets the outer hole of a shell, if it has one. + An outer hole is one that is not contained + in any other shell. + Each disjoint connected group of shells + is surrounded by an outer hole. + + The outer hole edge ring, or null + + + + Updates the included status for currently non-included shells + based on whether they are adjacent to an included shell. + + + + + Gets a string representation of this object. + + + + + Gets or sets a value indicating whether this ring has been processed. + + + + + Compares EdgeRings based on their envelope, + using the standard lexicographic ordering. + This ordering is sufficient to make edge ring sorting deterministic. + + mbdavis + + + + Assigns hole rings to shell rings + during polygonization. + Uses spatial indexing to improve performance + of shell lookup. + + mdavis + + + + Assigns hole rings to shell rings. + + An enumeration of hole rings to assign + An enumeration of shell rings + + + + Creates a new hole assigner. + + An enumeration of shell rings to assign holes to + + + + Assigns holes to the shells. + + An enumeration of holes to assign to shells + + + + Find the innermost enclosing shell EdgeRing containing the argument EdgeRing, if any. + The innermost enclosing ring is the smallest enclosing ring. + The algorithm used depends on the fact that: + + ring A contains ring B if envelope(ring A) contains envelope(ring B) + + This routine is only safe to use if the chosen point of the hole + is known to be properly contained in a shell + (which is guaranteed to be the case if the hole does not touch its shell) + + An edge ring to test + + The containing shell EdgeRing, if there is one + or null if no containing EdgeRing is found + + + + + A DirectedEdge of a PolygonizeGraph, which represents + an edge of a polygon formed by the graph. + May be logically deleted from the graph by setting the marked flag. + + + + + Constructs a directed edge connecting the from node to the + to node. + + + + + Specifies this DirectedEdge's direction (given by an imaginary + line from the from node to directionPt). + + + Whether this DirectedEdge's direction is the same as or + opposite to that of the parent Edge (if any). + + + + + Returns the identifier attached to this directed edge. + Attaches an identifier to this directed edge. + + + + + Returns the next directed edge in the EdgeRing that this directed edge is a member of. + Sets the next directed edge in the EdgeRing that this directed edge is a member of. + + + + + Returns the ring of directed edges that this directed edge is + a member of, or null if the ring has not been set. + + + + + Gets/Sets the ring of directed edges that this directed edge is + a member of. + + + + + An edge of a polygonization graph. + + + + + + + + + + + + + + + + Represents a planar graph of edges that can be used to compute a + polygonization, and implements the algorithms to compute the + s formed by the graph. + The marked flag on DirectedEdges is used to indicate that a directed edge + has be logically deleted from the graph. + + + + + + + + + + + + + + + + + + + + Deletes all edges at a node. + + + + + + Create a new polygonization graph. + + + + + + Add a LineString forming an edge of the polygon graph. + + The line to add. + + + + + + + + + + + + + + + + Convert the maximal edge rings found by the initial graph traversal + into the minimal edge rings required by NTS polygon topology rules. + + The list of start edges for the edgeRings to convert. + + + + Finds all nodes in a maximal edgering which are self-intersection nodes + + + + + The list of intersection nodes found, + or null if no intersection nodes were found. + + + + + Computes the minimal EdgeRings formed by the edges in this graph. + + A list of the{EdgeRings found by the polygonization process. + + + + Finds and labels all edgerings in the graph. + The edge rings are labeling with unique integers. + The labeling allows detecting cut edges. + + A List of the DirectedEdges in the graph. + A List of DirectedEdges, one for each edge ring found. + + + + Finds and removes all cut edges from the graph. + + A list of the LineStrings forming the removed cut edges. + + + + + + + + + + + + + + + + + Computes the next edge pointers going CCW around the given node, for the + given edgering label. + This algorithm has the effect of converting maximal edgerings into minimal edgerings + + + + + + + + + + + + + + Marks all edges from the graph which are "dangles". + Dangles are which are incident on a node with degree 1. + This process is recursive, since removing a dangling edge + may result in another edge becoming a dangle. + In order to handle large recursion depths efficiently, + an explicit recursion stack is used. + + A List containing the s that formed dangles. + + + + Traverses the polygonized edge rings in the graph + and computes the depth parity (odd or even) + relative to the exterior of the graph. + + If the client has requested that the output + be polygonally valid, only odd polygons will be constructed. + + + + + Traverses all connected edges, computing the depth parity of the associated polygons. + + + + + + Polygonizes a set of s which contain linework that + represents the edges of a planar graph. + + + All types of Geometry are accepted as input; + the constituent linework is extracted as the edges to be polygonized. + The processed edges must be correctly noded; that is, they must only meet + at their endpoints. Polygonization will accept incorrectly noded input + but will not form polygons from non-noded edges, + and reports them as errors. + + The Polygonizer reports the follow kinds of errors: + + Danglesedges which have one or both ends which are not incident on another edge endpoint + edges which are connected at both ends but which do not form part of polygon + edges which form rings which are invalid + (e.g. the component lines contain a self-intersection) + + + + The constructor allows + extracting only polygons which form a valid polygonal result. + The set of extracted polygons is guaranteed to be edge-disjoint. + This is useful for situations where it is known that the input lines form a + valid polygonal geometry (which may include holes or nested polygons). + + + + + + The default polygonizer output behavior + + + + + Adds every linear element in a into the polygonizer graph. + + + + + Filters all geometry instances + + The geometry instance + + + + Default linestring adder. + + + + + Allows disabling the valid ring checking, + to optimize situations where invalid rings are not expected. + + The default is true + + + + Creates a polygonizer that extracts all polygons. + + + + + Creates a polygonizer, specifying whether a valid polygonal geometry must be created. + If the argument is true + then areas may be discarded in order to + ensure that the extracted geometry is a valid polygonal geometry. + + true if a valid polygonal geometry should be extracted + + + + Adds a collection of s to be polygonized. + May be called multiple times. + Any dimension of Geometry may be added; + the constituent linework will be extracted and used. + + A list of Geometrys with linework to be polygonized. + + + + Adds a to the linework to be polygonized. + May be called multiple times. + Any dimension of Geometry may be added; + the constituent linework will be extracted and used + + A Geometry with linework to be polygonized. + + + + Adds a to the graph of polygon edges. + + The to add. + + + + Gets the list of polygons formed by the polygonization. + + + + + Gets a geometry representing the polygons formed by the polygonization. + If a valid polygonal geometry was extracted the result is a geometry. + + A geometry containing the polygons + + + + Gets the list of dangling lines found during polygonization. + + + + + Gets the list of cut edges found during polygonization. + + + + + Gets the list of lines forming invalid rings found during polygonization. + + + + + Performs the polygonization, if it has not already been carried out. + + + + + For each outer hole finds and includes a single outer shell. + This seeds the traversal algorithm for finding only polygonal shells. + + The list of shell EdgeRings + + + + Optimized implementation of spatial predicate "contains" + for cases where the first Geometry is a rectangle. + As a further optimization, + this class can be used directly to test many geometries against a single rectangle. + + + + + + + + + + + + + Create a new contains computer for two geometries. + + A rectangular geometry. + + + + + + + + + + + + + + + + + + + + + + + + + Tests if a point is contained in the boundary of the target rectangle. + + the point to test + true if the point is contained in the boundary + + + + Tests if a linestring is completely contained in the boundary of the target rectangle. + + the linestring to test + true if the linestring is contained in the boundary + + + + Tests if a line segment is contained in the boundary of the target rectangle. + + an endpoint of the segment + an endpoint of the segment + true if the line segment is contained in the boundary + + + I + Implementation of the Intersects spatial predicate + optimized for the case where one is a rectangle. + + + This class works for all input geometries, including s. + + As a further optimization, this class can be used in batch style + to test many geometries against a single rectangle. + + + + + Crossover size at which brute-force intersection scanning + is slower than indexed intersection detection. + Must be determined empirically. Should err on the + safe side by making value smaller rather than larger. + + + + + Tests whether a rectangle intersects a given geometry. + + A rectangular polygon + A geometry of any kind + true if the geometries intersect. + + + + Create a new intersects computer for a rectangle. + + A rectangular polygon. + + + + Tests whether the given Geometry intersects the query rectangle. + + The Geometry to test (may be of any type) + true if an intersection must occur + or false if no conclusion about intersection can be made + + + + Tests whether it can be concluded that a rectangle intersects a geometry, + based on the relationship of the envelope(s) of the geometry. + + Martin Davis + + + + Creates an instance of this class using the provided Envelope + + The query envelope + + + + Reports whether it can be concluded that an intersection occurs, + or whether further testing is required. + + true if an intersection must occur
+ or false if no conclusion about intersection can be made
+
+ + + + + + + + + + + + + + + A visitor which tests whether it can be + concluded that a geometry contains a vertex of + a query geometry. + + Martin Davis + + + + + + + + + + Gets a value indicating whether it can be concluded that a corner point of the rectangle is + contained in the geometry, or whether further testing is required. + + true if a corner point is contained + or false if no conclusion about intersection can be made + + + + + + + + + + + + + + + + + A visitor to test for intersection between the query rectangle and the line segments of the geometry. + + Martin Davis + + + + Creates a visitor for checking rectangle intersection with segments + + the query rectangle + + + Reports whether any segment intersection exists. + true if a segment intersection exists or + false if no segment intersection exists + + + + Tests if any line segments in two sets of intersect. + Optimized for use when at least one input is of small size. + Short-circuited to return as soon an intersection is found. + + + + + + + + + + + + + + + + + + + + + An EdgeEndBuilder creates EdgeEnds for all the "split edges" + created by the intersections determined for an Edge. + Computes the EdgeEnds which arise from a noded Edge. + + + + + + + + + + + + Creates stub edges for all the intersections in this + Edge (if any) and inserts them into the graph. + + + + + + + Create a EdgeStub for the edge before the intersection eiCurr. + The previous intersection is provided + in case it is the endpoint for the stub edge. + Otherwise, the previous point from the parent edge will be the endpoint. + eiCurr will always be an EdgeIntersection, but eiPrev may be null. + + + + + + + + + Create a StubEdge for the edge after the intersection eiCurr. + The next intersection is provided + in case it is the endpoint for the stub edge. + Otherwise, the next point from the parent edge will be the endpoint. + eiCurr will always be an EdgeIntersection, but eiNext may be null. + + + + + + + + + A collection of EdgeStubs which obey the following invariant: + They originate at the same node and have the same direction. + Contains all EdgeEnds which start at the same point and are parallel. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This computes the overall edge label for the set of + edges in this EdgeStubBundle. It essentially merges + the ON and side labels for each edge. + These labels must be compatible + + + + + + Compute the overall ON location for the list of EdgeStubs. + (This is essentially equivalent to computing the self-overlay of a single Geometry) + edgeStubs can be either on the boundary (e.g. Polygon edge) + OR in the interior (e.g. segment of a LineString) + of their parent Geometry. + In addition, GeometryCollections use the to determine + whether a segment is on the boundary or not. + Finally, in GeometryCollections it can occur that an edge is both + on the boundary and in the interior (e.g. a LineString segment lying on + top of a Polygon edge.) In this case the Boundary is given precedence. + These observations result in the following rules for computing the ON location: + if there are an odd number of Bdy edges, the attribute is Bdy + if there are an even number >= 2 of Bdy edges, the attribute is Int + if there are any Int edges, the attribute is Int + otherwise, the attribute is Null. + + + + + + + Compute the labelling for each side + + + + + + To compute the summary label for a side, the algorithm is: + FOR all edges + IF any edge's location is Interior for the side, side location = Interior + ELSE IF there is at least one Exterior attribute, side location = Exterior + ELSE side location = Null + Note that it is possible for two sides to have apparently contradictory information + i.e. one edge side may indicate that it is in the interior of a point, while + another edge side may indicate the exterior of the same point. This is + not an incompatibility - GeometryCollections may contain two Polygons that touch + along an edge. This is the reason for Interior-primacy rule above - it + results in the summary label having the Geometry interior on both sides. + + + + + + + Update the IM with the contribution for the computed label for the EdgeStubs. + + + + + + + + + + + + An ordered list of EdgeEndBundles around a RelateNode. + They are maintained in CCW order (starting with the positive x-axis) around the node + for efficient lookup and topology building. + + + + + Insert a EdgeEnd in order in the list. + If there is an existing EdgeStubBundle which is parallel, the EdgeEnd is + added to the bundle. Otherwise, a new EdgeEndBundle is created + to contain the EdgeEnd. + + + + + + Update the IM with the contribution for the EdgeStubs around the node. + + + + + + Computes the topological relationship between two Geometries. + RelateComputer does not need to build a complete graph structure to compute + the IntersectionMatrix. The relationship between the geometries can + be computed by simply examining the labelling of edges incident on each node. + RelateComputer does not currently support arbitrary GeometryCollections. + This is because GeometryCollections can contain overlapping Polygons. + In order to correct compute relate on overlapping Polygons, they + would first need to be noded and merged (if not explicitly, at least + implicitly). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Copy all nodes from an arg point into this graph. + The node label in the arg point overrides any previously computed + label for that argIndex. + (E.g. a node may be an intersection node with + a computed label of Boundary, + but in the original arg Geometry it is actually + in the interior due to the Boundary Determination Rule) + + + + + + Insert nodes for all intersections on the edges of a Geometry. + Label the created nodes the same as the edge label if they do not already have a label. + This allows nodes created by either self-intersections or + mutual intersections to be labelled. + Endpoint nodes will already be labelled from when they were inserted. + + + + + + For all intersections on the edges of a Geometry, + label the corresponding node IF it doesn't already have a label. + This allows nodes created by either self-intersections or + mutual intersections to be labelled. + Endpoint nodes will already be labelled from when they were inserted. + + + + + + If the Geometries are disjoint, we need to enter their dimension and + boundary dimension in the Ext rows in the IM + + An intersection matrix + The Boundary Node Rule to use + + + + Compute the IM entry for the intersection of the boundary + of a geometry with the Exterior. + This is the nominal dimension of the boundary + unless the boundary is empty, in which case it is . + For linear geometries the Boundary Node Rule determines + whether the boundary is empty. + + The geometry providing the boundary + The Boundary Node Rule to use + The IM dimension entry + + + + + + + + + Update the IM with the sum of the IMs for each component. + + + + + + Processes isolated edges by computing their labelling and adding them + to the isolated edges list. + Isolated edges are guaranteed not to touch the boundary of the target (since if they + did, they would have caused an intersection to be computed and hence would + not be isolated). + + + + + + + Label an isolated edge of a graph with its relationship to the target point. + If the target has dim 2 or 1, the edge can either be in the interior or the exterior. + If the target has dim 0, the edge must be in the exterior. + + + + + + + + Isolated nodes are nodes whose labels are incomplete + (e.g. the location for one Geometry is null). + This is the case because nodes in one graph which don't intersect + nodes in the other are not completely labelled by the initial process + of adding nodes to the nodeList. + To complete the labelling we need to check for nodes that lie in the + interior of edges, and in the interior of areas. + + + + + Label an isolated node with its relationship to the target point. + + + + + + + A RelateNode is a Node that maintains a list of EdgeStubs + for the edges that are incident on it. + + + + + + + + + + + + Update the IM with the contribution for this component. + A component only contributes if it has a labelling for both parent geometries. + + + + + Update the IM with the contribution for the EdgeEnds incident on this node. + + + + + + Used by the NodeMap in a RelateNodeGraph to create RelateNodes. + + + + + + + + + + + + Implements the simple graph of Nodes and EdgeEnd which is all that is + required to determine topological relationships between Geometries. + Also supports building a topological graph of a single Geometry, to + allow verification of valid topology. + It is not necessary to create a fully linked + PlanarGraph to determine relationships, since it is sufficient + to know how the Geometries interact locally around the nodes. + In fact, this is not even feasible, since it is not possible to compute + exact intersection points, and hence the topology around those nodes + cannot be computed robustly. + The only Nodes that are created are for improper intersections; + that is, nodes which occur at existing vertices of the Geometries. + Proper intersections (e.g. ones which occur between the interior of line segments) + have their topology determined implicitly, without creating a Node object + to represent them. + + + + + + + + + + + + + + + + + Insert nodes for all intersections on the edges of a Geometry. + Label the created nodes the same as the edge label if they do not already have a label. + This allows nodes created by either self-intersections or + mutual intersections to be labelled. + Endpoint nodes will already be labelled from when they were inserted. + Precondition: edge intersections have been computed. + + + + + + + Copy all nodes from an arg point into this graph. + The node label in the arg point overrides any previously computed + label for that argIndex. + (E.g. a node may be an intersection node with + a computed label of Boundary, + but in the original arg Geometry it is actually + in the interior due to the Boundary Determination Rule). + + + + + + + + + + + + + Implements the SFS relate() generalized spatial predicate on two s. +
+ The class supports specifying a custom + to be used during the relate computation. +
+ + If named spatial predicates are used on the result + of the RelateOp, the result may or not be affected by the + choice of BoundaryNodeRule, depending on the exact nature of the pattern. + For instance, is insensitive + to the choice of BoundaryNodeRule, + whereas is affected by the rule chosen. + + Note: custom Boundary Node Rules do not (currently) + affect the results of other methods (such + as . The results of + these methods may not be consistent with the relationship computed by + a custom Boundary Node Rule. + +
+ + + Computes the for the spatial relationship + between two s, using the default (OGC SFS) Boundary Node Rule + + A geometry to test + A geometry to test + The IntersectionMatrix for the spatial relationship between the geometries + + + + Computes the for the spatial relationship + between two s, using the specified Boundary Node Rule + + A geometry to test + A geometry to test + The Boundary Node Rule to use + The IntersectionMatrix for the spatial relationship between the geometries + + + + Creates a new Relate operation, using the default (OGC SFS) Boundary Node Rule. + + a Geometry to relate + another Geometry to relate + + + + Creates a new Relate operation, using the default (OGC SFS) Boundary Node Rule. + + a Geometry to relate + another Geometry to relate + The Boundary Node Rule to use + + + + Gets the IntersectionMatrix for the spatial relationship + between the input geometries. + + + + + Provides an efficient method of unioning a collection of + geometries. + The geometries are indexed using a spatial index, + and unioned recursively in index order. + For geometries with a high degree of overlap, + this has the effect of reducing the number of vertices + early in the process, which increases speed + and robustness. + + This algorithm is faster and more robust than + the simple iterated approach of + repeatedly unioning each polygon to a result geometry. + + The buffer(0) trick is sometimes faster, but can be less robust and + can sometimes take a long time to complete. + This is particularly the case where there is a high degree of overlap + between the polygons. In this case, buffer(0) is forced to compute + with all line segments from the outset, + whereas cascading can eliminate many segments + at each stage of processing. + The best situation for using buffer(0) is the trivial case + where there is no overlap between the input geometries. + However, this case is likely rare in practice. + + Martin Davis + + + + + A union strategy that uses the classic NTS , + and for polygonal geometries a robustness fallback using Buffer(0). + + + + + An alternative way of unioning polygonal geometries + by using Buffer(0). + Only worth using if regular overlay union fails. + + A polygonal geometry + A polygonal geometry + The union of the geometries + + + + Computes the union of + a collection of s. + + A collection of s. + The union of the + + + + Computes the union of + a collection of s. + + A collection of s. + A strategy to perform the unioning. + The union of the + + + + Creates a new instance to union + the given collection of s. + + A collection of s + + + + Creates a new instance to union + the given collection of s. + + A collection of s + + + + + The effectiveness of the index is somewhat sensitive + to the node capacity. + Testing indicates that a smaller capacity is better. + For an STRtree, 4 is probably a good number (since + this produces 2x2 "squares"). + + + + + Computes the union of the input geometries. + + + + This method discards the input geometries as they are processed. + In many input cases this reduces the memory retained + as the operation proceeds. + Optimal memory usage is achieved + by disposing of the original input collection + before calling this method. + + The union of the input geometries, + or null if no input geometries were provided + + if this method is called more than once + + + + Unions a list of geometries + by treating the list as a flattened binary tree, + and performing a cascaded union on the tree. + + The list of geometries to union + The union of the list + + + + Unions a section of a list using a recursive binary union on each half + of the section. + + The list of geometries containing the section to union + The start index of the section + The index after the end of the section + The union of the list section + + + + Gets the element at a given list index, or + null if the index is out of range. + + The list of geometries + The index + The geometry at the given index or + null if the index is out of range + + + + Reduces a tree of geometries to a list of geometries + by recursively unioning the subtrees in the list. + + A tree-structured list of geometries + A list of Geometrys + + + + Computes the union of two geometries, + either or both of which may be null. + + A Geometry + A Geometry + The union of the input(s) or + null if both inputs are null + + + + Encapsulates the actual unioning of two polygonal geometries. + + A geometry to union + A geometry to union + A + The union of the inputs + + + Computes a containing only components. + Extracts the s from the input + and returns them as an appropriate geometry. + + If the input is already Polygonal, it is returned unchanged. + + A particular use case is to filter out non-polygonal components + returned from an overlay operation. + + The geometry to filter + A polygonal geometry + + + + Extracts atomic elements from + input geometries or collections, + recording the dimension found. + Empty geometries are discarded since they + do not contribute to the result of . + + Martin Davis + + + + Extracts elements from an enumeration of geometries. + + An enumeration of geometries + An extracter over the geometries. + + + + Extracts elements from a geometry. + + An geometry to extract from + An extracter over the geometry. + + + The default dimension for an empty GeometryCollection + + + + Gets a value indicating if there were any non-empty geometries extracted + + + + + Gets a value indicating the maximum extracted. + + + + + Gets a value indicating the geometry factory from the extracted geometry, + if there is one. + If an empty collection was extracted, will return null. + + + + + Gets the extracted atomic geometries of the given dimension dim. + + The dimension of geometry to return + A list of the extracted geometries of dimension dim. + + + + Unions MultiPolygons efficiently by + using full topological union only for polygons which may overlap, + and combining with the remaining polygons. + Polygons which may overlap are those which intersect the common extent of the inputs. + Polygons wholly outside this extent must be disjoint to the computed union. + They can thus be simply combined with the union result, + which is much more performant. + (There is one caveat to this, which is discussed below). + + This situation is likely to occur during cascaded polygon union, + since the partitioning of polygons is done heuristically + and thus may group disjoint polygons which can lie far apart. + It may also occur in real world data which contains many disjoint polygons + (e.g. polygons representing parcels on different street blocks). + + +

Algorithm

+ The overlap region is determined as the common envelope of intersection. + The input polygons are partitioned into two sets: + + OverlappingPolygons which intersect the overlap region, and thus potentially overlap each other + DisjointPolygons which are disjoint from (lie wholly outside) the overlap region + + The Overlapping set is fully unioned, and then combined with the Disjoint set. + Performing a simple combine works because + the disjoint polygons do not interact with each + other(since the inputs are valid MultiPolygons). + They also do not interact with the Overlapping polygons, + since they are outside their envelope. +

Discussion

+ In general the Overlapping set of polygons will + extend beyond the overlap envelope. This means that the union result + will extend beyond the overlap region. + There is a small chance that the topological + union of the overlap region will shift the result linework enough + that the result geometry intersects one of the Disjoint geometries. + This situation is detected and if it occurs + is remedied by falling back to performing a full union of the original inputs. + Detection is done by a fairly efficient comparison of edge segments which + extend beyond the overlap region. If any segments have changed + then there is a risk of introduced intersections, and full union is performed. + + This situation has not been observed in JTS using floating precision, + but it could happen due to snapping. It has been observed + in other APIs(e.g.GEOS) due to more aggressive snapping. + It is more likely to happen if a Snap - Rounding overlay is used. + + NOTE: Test has shown that using this heuristic impairs performance. +
+ Martin Davis +
+ + + Union a pair of geometries, + using the more performant overlap union algorithm if possible. + + A geometry to union + A geometry to union + The union of the inputs + + + + Union a pair of geometries, + using the more performant overlap union algorithm if possible. + + A geometry to union + A geometry to union + Function to union two geometries + The union of the inputs + + + + Creates a new instance for unioning the given geometries. + + A geometry to union + A geometry to union + + + + Creates a new instance for unioning the given geometries. + + A geometry to union + A geometry to union + Function to union two geometries + + + + Union a pair of geometries, + using the more performant overlap union algorithm if possible. + + The union of the inputs + + + + Gets a value indicating whether the optimized + or full union was performed. + + Used for unit testing.> + true if the optimized union was performed + + + + Implements union using the buffer-by-zero trick. + This seems to be more robust than overlay union, + for reasons somewhat unknown. + + A geometry + A geometry + The union of the geometries + + + + Computes the union of a geometry with + another arbitrary . + Does not copy any component geometries. + + + + + + + + Unions a Collection of s or a single Geometry (which may be a ) together. + + + + By using this special-purpose operation over a collection of geometries + it is possible to take advantage of various optimizations to improve performance. + + + Heterogeneous s are fully supported. + + + The result obeys the following contract: + + Unioning a set of s has the effect of merging the areas (i.e. the same effect as iteratively unioning all individual polygons together). + Unioning a set of s has the effect of fully noding + and dissolving the input linework. + In this context "fully noded" means that there will be + an endpoint or node in the result + for every endpoint or line segment crossing in the input. + "Dissolved" means that any duplicate (e.g. coincident) line segments or portions + of line segments will be reduced to a single line segment in the output. + This is consistent with the semantics of the + operation. + If merged linework is required, the class can be used. + Unioning a set of s has the effect of merging all identical points (producing a set with no duplicates). + + + UnaryUnion always operates on the individual components of MultiGeometries. + So it is possible to use it to "clean" invalid self-intersecting MultiPolygons + (although the polygon components must all still be individually valid.) + + + + mbdavis + + + + + Computes the geometric union of a + + A collection of geometries + The union of the geometries, + or null if the input is empty + + + + Computes the geometric union of a + If no input geometries were provided but a was provided, + an empty is returned. + + A collection of geometries + The geometry factory to use if the collection is empty + The union of the geometries + or an empty GEOMETRYCOLLECTION + + + Constructs a unary union operation for a + (which may be a ). + + A geometry to union + The union of the elements of the geometry + or an empty GEOMETRYCOLLECTION + + + + Constructs a unary union operation for an enumeration + of s, using the + of the input geometries. + + An enumeration of geometries + + + + Constructs a unary union operation for an enumeration + of s. + If no input geometries were provided but a was provided, + + An enumeration of geometries + The geometry factory to use if the enumeration is empty + + + + Constructs a unary union operation for a + (which may be a ). + + A geometry to union + + + + Named setter named setUnionFun[ction] in JTS + + + + + Gets the union of the input geometries. + + The result of empty input is determined as follows: + + If the input is empty and a dimension can be + determined (i.e. an empty geometry is present), + an empty atomic geometry of that dimension is returned. + If no input geometries were provided but a was provided, + an empty is returned. + Otherwise, the return value is null. + + + + A Geometry containing the union, + or an empty atomic geometry, or an empty GEOMETRYCOLLECTION, + ornull if no GeometryFactory was provided + + + + + Computes the union of two geometries, either of both of which may be null. + + + + + The union of the input(s) + or null if both inputs are null + + + + + Computes a unary union with no extra optimization, and no short-circuiting. + + + Due to the way the overlay operations are implemented, this is still efficient in the case of linear and puntal geometries. + + A geometry + The union of the input geometry + + + + Experimental code to union MultiPolygons with processing limited to the elements which actually interact. + + Not currently used, since it doesn't seem to offer much of a performance advantage. + mbdavis + + + + An strategy class that allows UnaryUnion to adapt to different + kinds of overlay algorithms. + + Martin Davis + + + + Computes the union of two geometries. + This method may throw a + if one is encountered. + + A geometry + A geometry + The union of the input + + + + Indicates whether the union function operates using + a floating(full) precision model. + If this is the case, then the unary union code + can make use of the { @link OverlapUnion} + performance optimization, + and perhaps other optimizations as well. + Otherwise, the union result extent may not be the same as the extent of the inputs, + which prevents using some optimizations. + + + + + This class tests that the interior of an area + ( or ) + is connected. An area Geometry is invalid if the interior is disconnected. + This can happen if: + - a shell self-intersects, + - one or more holes form a connected chain touching a shell at two different points, + - one or more holes form a ring around a subset of the interior. + If a disconnected situation is found the location of the problem is recorded. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Form s in graph into Minimal EdgeRings. + (Minimal Edgerings must be used, because only they are guaranteed to provide + a correct isHole computation). + + + + + + + Mark all the edges for the edgeRings corresponding to the shells of the input polygons. + Only ONE ring gets marked for each shell - if there are others which remain unmarked + this indicates a disconnected interior. + + + + + + + + + + + + + + + + + + + + Check if any shell ring has an unvisited edge. + A shell ring is a ring which is not a hole and which has the interior + of the parent area on the RHS. + (Note that there may be non-hole rings with the interior on the LHS, + since the interior of holes will also be polygonized into CW rings + by the LinkAllDirectedEdges() step). + + + true if there is an unvisited edge in a non-hole ring. + + + + Checks that a {GeometryGraph} representing an area + (a Polygon or MultiPolygon ) + is consistent with the SFS semantics for area geometries. + Checks include: + Testing for rings which self-intersect (both properly and at nodes). + Testing for duplicate rings. + If an inconsistency if found the location of the problem is recorded. + + + + + + + + + + + Returns the intersection point, or null if none was found. + + + + + + + + + + Check all nodes to see if their labels are consistent. + If any are not, return false. + + + + + Checks for two duplicate rings in an area. + Duplicate rings are rings that are topologically equal + (that is, which have the same sequence of points up to point order). + If the area is topologically consistent (determined by calling the + isNodeConsistentArea, + duplicate rings can be found by checking for EdgeBundles which contain more than one EdgeEnd. + (This is because topologically consistent areas cannot have two rings sharing + the same line segment, unless the rings are equal). + The start point of one of the equal rings will be placed in invalidPoint. + Returns true if this area Geometry is topologically consistent but has two duplicate rings. + + + + + Tests whether any holes of a Polygon are + nested inside another hole, using a spatial + index to speed up the comparisons. + + The logic assumes that the holes do not overlap and have no collinear segments + (so they are properly nested, and there are no duplicate holes). + + The situation where every vertex of a hole touches another hole + is invalid because either the hole is nested, + or else it disconnects the polygon interior. + This class detects the nested situation. + The disconnected interior situation must be checked elsewhere. + + + + + Gets a value indicating a point on a nested hole, if one exists. + + A point on a nested hole, or null if none are nested + + + + Tests if any hole is nested (contained) within another hole. + This is invalid. + The will be set to reflect this. + + true if some hole is nested. + + + + Tests whether a MultiPolygon has any element polygon + nested inside another polygon, using a spatial + index to speed up the comparisons. + + The logic assumes that the polygons do not overlap and have no collinear segments + (so they are properly nested, and there are no duplicate rings). + + + + + Gets a point on a nested polygon, if one exists. + + A point on a nested polygon, or null if none are nested + + + + Tests if any polygon is nested (contained) within another polygon. + This is invalid. + The nested point will be set to reflect this. + + true if some polygon is nested + + + + Finds a point of a shell segment which lies inside a polygon, if any. + The shell is assume to touch the polyon only at shell vertices, + and does not cross the polygon. + + The shell to test + The polygon to test against + An interior segment point, or null if the shell is nested correctly + + + + Tests whether any of a set of s are + nested inside another ring in the set, using a spatial + index to speed up the comparisons. + + + + + Tests whether a Geometry is simple as defined by the OGC SFS specification. + + Simplicity is defined for each + type as follows: + + Pointgeometries are simple. + MultiPointgeometries are simple if every point is unique + LineStringgeometries are simple if they do not self-intersect at interior points + (i.e.points other than the endpoints). + MultiLineStringgeometries are simple if + their elements are simple and they intersect only at points + which are boundary points of both elements. + (The notion of boundary points can be user-specified - see below). + Polygonalgeometries have no definition of simplicity. + The IsSimple code checks if all polygon rings are simple. + (Note: this means thatIsSimple cannot be used to test + for all self-intersections in Polygon s. + In order to check if a IPolygonal geometry has self-intersections, + use . + GeometryCollectiongeometries are simple if all their elements are simple. + Empty geometries are simple + + For geometries the evaluation of simplicity + can be customized by supplying a + to define how boundary points are determined. + The default is the SFS-standard . + + Note that under the Mod-2 rule, closed LineStrings (rings) + have no boundary. + This means that an intersection at their endpoints makes the geometry non-simple. + If it is required to test whether a set of LineStrings touch + only at their endpoints, use . + For example, this can be used to validate that a collection of lines + form a topologically valid linear network. + + By default this class finds a single non-simple location. + To find all non-simple locations, set + before calling , and retrieve the locations + via . + This can be used to find all intersection points in a linear network. + + + + + + + Tests whether a geometry is simple. + + The input geometry + true if the geometry is simple + + + + Gets a non-simple location in a geometry, if any. + + The input geometry + A non-simple location, or null if the geometry is simple + + + + Creates a simplicity checker using the default SFS Mod-2 Boundary Node Rule + + The geometry to test + + + + Creates a simplicity checker using a given + + The geometry to test + The boundary node rule to use + + + Gets or sets a value indicating if all non-simple points should be reported. + + + + Tests whether the geometry is simple. + + true if the geometry is simple. + + + + Gets the coordinate for an location where the geometry + fails to be simple (i.e. where it has a non-boundary + self-intersection). + + A Coordinate for the location of the non-boundary self-intersection + or null if the geometry is simple + + + + Gets all non-simple intersection locations. + + A list of the Coordinates of non-simple locations. + + + + Computes simplicity for polygonal geometries. + Polygonal geometries are simple if and only if + all of their component rings are simple. + + A geometry + true if the geometry is simple + + + + Semantics for GeometryCollection is + simple if all components are simple. + + A geometry collection + true if the geometry is simple + + + + Creates an instance of this class + + A flag indicating if closed endpoints belong to the interior + A flag indicating that all non-simple intersection points should be found + A list to add the non-simple intersection points to. + + + + Tests whether an intersection was found. + + true if an intersection was found. + + + + + + + Tests whether an intersection vertex is an endpoint of a segment string. + + The segment string + The index of the segment in + The line intersector + The index of the segment in intersector + true if the intersection vertex is an endpoint + + + + Finds the vertex index in a segment of an intersection + which is known to be a vertex. + + The line intersector + The intersection segment index + + The vertex index (0 or 1) in the segment vertex of the intersection point + + + + + + + + Implements the algorithms required to compute the + method for s. + See the documentation for the various geometry types for a specification of validity. + + + + + Tests whether a is valid. + + The geometry to test + true if the geometry is valid + In JTS this function is called IsValid + + + + Checks whether a coordinate is valid for processing. + Coordinates are valid if their x and y ordinates are in the + range of the floating point representation. + + The coordinate to validate + true if the coordinate is valid + + + + The geometry being validated + + + + + If the following condition is TRUE JTS will validate inverted shells and exverted holes + (the ESRI SDE model) + + + + + Creates a new validator for a geometry + + The geometry to validate + + + + Gets or sets a value indicating whether polygons using Self-Touching Rings to form + holes are reported as valid. + If this flag is set, the following Self-Touching conditions + are treated as being valid: + + the shell ring self-touches to create a hole touching the shell + a hole ring self-touches to create two holes touching at a point + + + The default (following the OGC SFS standard) + is that this condition is not valid (false). + + Self-Touching Rings which disconnect the + the polygon interior are still considered to be invalid + (these are invalid under the SFS, and many other + spatial models as well). + This includes: + + exverted ("bow-tie") shells which self-touch at a single point + inverted shells with the inversion touching the shell at another point + exverted holes with exversion touching the hole at another point + inverted ("C-shaped") holes which self-touch at a single point causing an island to be formed + inverted shells or exverted holes which form part of a chain of touching rings + (which disconnect the interior) + + + + + + + Gets/Sets whether polygons using Self-Touching Rings to form + holes are reported as valid. + If this flag is set, the following Self-Touching conditions + are treated as being valid:
+ - The shell ring self-touches to create a hole touching the shell.
+ - A hole ring self-touches to create two holes touching at a point.
+
+ + The default (following the OGC SFS standard) + is that this condition is not valid (false). + + + This does not affect whether Self-Touching Rings + disconnecting the polygon interior are considered valid + (these are considered to be invalid under the SFS, and many other + spatial models as well). + This includes "bow-tie" shells, + which self-touch at a single point causing the interior to be disconnected, + and "C-shaped" holes which self-touch at a single point causing an island to be formed. + +
+ States whether geometry with this condition is valid. +
+ + + Tests the validity of the input geometry. + + true if the geometry is valid. + + + + Gets a value indicating the validity of the geometry + If not valid, returns the validation error for the geometry, + or null if the geometry is valid. + + The validation error, if the geometry is invalid + or null if the geometry is valid + + + + Tests validity of a Point. + + The Point to test + true if the Point is valid + In JTS this function is called IsValid + + + + Tests validity of a MultiPoint. + + The MultiPoint to test + true if the MultiPoint is valid + In JTS this function is called IsValid + + + + Tests validity of a LineString.
+ Almost anything goes for LineStrings! +
+ The LineString to test + In JTS this function is called IsValid +
+ + + Tests validity of a LinearRing.
+
+ The LinearRing to test + In JTS this function is called IsValid +
+ + + Tests validity of a Polygon.
+
+ The Polygon to test + In JTS this function is called IsValid +
+ + + Tests validity of a MultiPolygon.
+
+ The MultiPolygon to test + In JTS this function is called IsValid +
+ + + Tests validity of a GeometryCollection.
+
+ The GeometryCollection to test + In JTS this function is called IsValid +
+ + + Check the number of non-repeated points is at least a given size. + + The line to test + The minimum number of points in + true if the line has the required number of points + + + + Test if the number of non-repeated points in a line + is at least a given minimum size. + + The line to test + The minimum number of points in + true if the line has the required number of non-repeated points + + + + Check whether a ring self-intersects (except at its endpoints). + + The linear ring to check + + + + Tests that each hole is inside the polygon shell. + This routine assumes that the holes have previously been tested + to ensure that all vertices lie on the shell or on the same side of it + (i.e. that the hole rings do not cross the shell ring). + Given this, a simple point-in-polygon test of a single point in the hole can be used, + provided the point is chosen such that it does not lie on the shell. + + The polygon to be tested for hole inclusion + + + + Checks if a polygon hole lies inside its shell + and if not returns a point indicating this. + The hole is known to be wholly inside or outside the shell, + so it suffices to find a single point which is interior or exterior, + or check the edge topology at a point on the boundary of the shell. + + The hole to test + The polygon shell to test against + A hole point outside the shell, or null if it is inside. + + + + Checks if any polygon hole is nested inside another. + Assumes that holes do not cross (overlap), + This is checked earlier. + + The polygon with holes to test + + + + Checks that no element polygon is in the interior of another element polygon. + Preconditions: + + shells do not partially overlap + shells do not touch along an edge + no duplicate rings exist + These have been confirmed by the . + + + + + Find a point from the list of testCoords + that is NOT a node in the edge for the list of searchCoords. + + + + + The point found, or null if none found. + + + Finds and analyzes intersections in and between polygons, + to determine if they are valid. + + The s which are analyzed can have s + attached. If so they will be updated with intersection information + to support further validity analysis which must be done after + basic intersection validity has been confirmed. + + Martin Davis + + + + Creates a new finder, allowing for the mode where inverted rings are valid. + + true if inverted rings are valid. + + + + For a segment string for a ring, gets the coordinate + previous to the given index (wrapping if the index is 0) + + The ring segment string + The segment index + The coordinate previous to the given segment + + + + Tests if two segments in a closed are adjacent. + This handles determining adjacency across the start/end of the ring. + + The segment string + A segment index + A segment index + true if the segments are adjacent + + + + Functions to compute topological information + about nodes (ring intersections) in polygonal geometry. + + Martin Davis + + + + Check if the edges at a node between two rings (or one ring) cross. + The node is topologically valid if the ring edges do not cross. + This function assumes that the edges are not collinear. + + The node location + The previous edge endpoint in a ring + The next edge endpoint in a ring + The previous edge endpoint in the other ring + The next edge endpoint in the other ring + + true if the edges cross at the node + + + + + Tests whether an edge node-b lies in the interior or exterior + of a corner of a ring given by a0-node-a1. + The ring interior is assumed to be on the right of the corner (a CW ring). + The edge must not be collinear with the corner segments. + + The node location + The first vertex of the corner + The second vertex of the corner + The destination vertex of the edge + true if the edge is interior to the ring corner + + + + Tests if an edge p is between edges e0 and e1, + where the edges all originate at a common origin. + The "inside" of e0 and e1 is the arc which does not include the origin. + The edges are assumed to be distinct (non-collinear). + + the origin + the destination point of edge p + the destination point of edge e0 + the destination point of edge e1 + true if p is between e0 and e1 + + + + Tests if the angle with the origin of a vector P is greater than that of the + vector Q. + + The origin of the vectors + The endpoint of the vector P + The endpoint of the vector Q + true if vector P has angle greater than Q + + + + A ring of a polygon being analyzed for topological validity. + The shell and hole rings of valid polygons touch only at discrete points. + The "touch" relationship induces a graph over the set of rings. + The interior of a valid polygon must be connected. + This is the case if there is no "chain" of touching rings + (which would partition off part of the interior). + This is equivalent to the touch graph having no cycles. + Thus the touch graph of a valid polygon is a forest - a set of disjoint trees. + + Also, in a valid polygon two rings can touch only at a single location, + since otherwise they disconnect a portion of the interior between them. + This is checked as the touches relation is built + (so the touch relation representation for a polygon ring does not need to support + more than one touch location for each adjacent ring). + + The cycle detection algorithm works for polygon rings which also contain self-touches + (inverted shells and exverted holes). + + Polygons with no holes do not need to be checked for + a connected interior, unless self-touches are allowed. + + The class also records the topology at self-touch nodes, + to support checking if an invalid self-touch disconnects the polygon. + + Martin Davis + + + + Tests if a polygon ring represents a shell. + + The ring to test (may be null) + true if the ring represents a shell + + + + Records a touch location between two rings, + and checks if the rings already touch in a different location. + + A polygon ring + A polygon ring + The location where they touch + true if the polygons already touch + + + + Finds a location (if any) where a chain of holes forms a cycle + in the ring touch graph. + The shell may form part of the chain as well. + This indicates that a set of holes disconnects the interior of a polygon. + + The list of rings to check + A vertex contained in a ring cycle or null if none is found. + + + + Finds a location of an interior self-touch in a list of rings, + if one exists. + This indicates that a self-touch disconnects the interior of a polygon, + which is invalid. + + The list of rings to check + The location of an interior self-touch node, or null if there are none + + + + The root of the touch graph tree containing this ring. + Serves as the id for the graph partition induced by the touch relation. + + + + + The set of links + for this ring. + The set of all touches in the rings of a polygon + forms the polygon touch graph. + This supports detecting touch cycles, which + reveal the condition of a disconnected interior. + + Only a single touch is recorded between any two rings, + since more than one touch between two rings + indicates interior disconnection as well. + + + + + The set of self-nodes in this ring. + This supports checking valid ring self-touch topology. + + + + + Creates a ring for a polygon shell. + + The polygon shell + + + + Creates a ring for a polygon hole. + + The ring geometry + The index of the hole + The parent polygon shell + + + + Adds a point where a touches another one. + + The other + The touch location + + + + Adds the node (intersection point) + and the endpoints of the four adjacent segments. + + The node + The 1st position of the 1st edge + The 2nd position of the 1st edge + The 1st position of the 2nd edge + The 2nd position of the 2nd edge + + + + Tests if this ring touches a given ring at + the single point specified. + + The other polygon ring + The touch point + true if the rings touch only at the given point. + + + + Detects whether the subgraph of holes linked by touch to this ring + contains a hole cycle. + If no cycles are detected, the set of touching rings is a tree. + The set is marked using this ring as the root. + + A vertex om a hole cycle or null if no cycle found + + + + Scans for a hole cycle starting at a given touch. + + The touch to investigate + The root of the touch subgraph + The queue of rings to scan + + + + Finds the location of an invalid interior self-touch in this ring, + if one exists. + + The location of an interior self-touch node, or null if there are none + + + + + + + + Records a point where a touches another one. + This forms an edge in the induced ring touch graph. + + Martin Davis + + + + Creates an instance of this item + + The polygon ring + The touch position + + + + Represents a ring self-touch node, recording the node (intersection point) + and the endpoints of the four adjacent segments. + + This is used to evaluate validity of self-touching nodes, + when they are allowed. + + Martin Davis + + + + Creates an instance of this point + + The self touch position + The 1st position of the 1st edge + The 2nd position of the 1st edge + The 1st position of the 2nd edge + The 2nd position of the 2nd edge + + + + Gets a value indicating the node point + + + + + Tests if a self-touch has the segments of each half of the touch + lying in the exterior of a polygon. + This is a valid self-touch. + It applies to both shells and holes. + Only one of the four possible cases needs to be tested, + since the situation has full symmetry. + + A flag indicating if the interior is to the right of the parent ring + true if the self-touch is on the exterior. + + + + Analyzes the topology of polygonal geometry + to determine whether it is valid. + + Martin Davis + + + + Finds a self-intersection (if any) in a . + + The ring to analyze + A self-intersection point if one exists, or null + + + + Tests whether a segment p0-p1 is inside or outside a ring. + + Preconditions: + + The segment intersects the ring only at the endpoints + One, none or both of the segment endpoints may lie on the ring + The ring does not self-cross, but it may self-touch + + + A segment vertex + A segment vertex + The ring to test + true if the segment lies inside the ring + + + + Tests whether a touching segment is interior to a ring. + + Preconditions: + + The segment does not intersect the ring other than at the endpoints + The segment vertex p0 lies on the ring + The ring does not self-cross, but it may self-touch + + This works for both shells and holes, but the caller must know + the ring role. + + The first vertex of the segment + The second vertex of the segment + The points of the ring + true if the segment is inside the ring. + + + + Computes the index of the segment which intersects a given point. + + The ring points + The intersection point + The intersection segment index, or -1 if not intersection is found. + + + + Tests whether the interior of the polygonal geometry is + disconnected.
+ If true, the disconnection location is available from + . +
+ true if the interior is disconnected +
+ + + Gets a location where the polyonal interior is disconnected.
+ must be called first. +
+ The location of an interior disconnection, or null +
+ + + Tests whether any polygon with holes has a disconnected interior + by virtue of the holes (and possibly shell) forming a touch cycle. + + This is a global check, which relies on determining + the touching graph of all holes in a polygon. + + If inverted rings disconnect the interior + via a self-touch, this is checked by the . + If inverted rings are part of a disconnected ring chain + this is detected here. + + true if a polygon has a disconnected interior. + + + + Tests if an area interior is disconnected by a self-touching ring. + This must be evaluated after other self-intersections have been analyzed + and determined to not exist, since the logic relies on + the rings not self-crossing (winding). + + true if an area interior is disconnected by a self-touch + + + + Implements the appropriate checks for repeated points + (consecutive identical coordinates) as defined in the + NTS spec. + + + + + Gets a value indicating the location of the repeated point + + + + + Checks if a geometry has a repeated point + + The geometry to test + true if the geometry has a repeated point, otherwise false + + + + Checks if an array of Coordinates has a repeated point + + An array of coordinates + true if has a repeated point, otherwise false + + + + Checks if an array of Coordinates has a repeated point + + A coordinate sequence + true if has a repeated point, otherwise false + + + + Contains information about the nature and location of + a validation error. + + + + + + + + + Indicates that a hole of a polygon lies partially + or completely in the exterior of the shell. + + + + + Indicates that a hole lies + in the interior of another hole in the same polygon. + + + + + Indicates that the interior of a polygon is disjoint + (often caused by set of contiguous holes splitting + the polygon into two parts). + + + + + Indicates that two rings of a polygonal geometry intersect. + + + + + Indicates that a ring self-intersects. + + + + + Indicates that a polygon component of a + lies inside another polygonal component. + + + + + Indicates that a polygonal geometry + contains two rings which are identical. + + + + + Indicates that either: + - A contains a single point. + - A contains 2 or 3 points. + + + + + Indicates that the X or Y ordinate of + a is not a valid + numeric value (e.g. ). + + + + + Indicates that a ring is not correctly closed + (the first and the last coordinate are different). + + + + + Contains information about the nature and location of a Geometry + validation error. + + + + + These messages must synch up with the indexes above + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Finds all connected s of a . + + + + + Initializes a new instance of the class. + + The . + + + + Adds all nodes and edges reachable from this node to the subgraph. + Uses an explicit stack to avoid a large depth of recursion. + + + + + + + Adds the argument node and all its out edges to the subgraph. + + + + + + + + Represents a directed edge in a PlanarGraph. A DirectedEdge may or + may not have a reference to a parent Edge (some applications of + planar graphs may not require explicit Edge objects to be created). Usually + a client using a PlanarGraph will subclass DirectedEdge + to add its own application-specific data and methods. + + + + + Returns a List containing the parent Edge (possibly null) for each of the given + DirectedEdges. + + + + + + + Constructs a DirectedEdge connecting the from node to the + to node. + + + + + Specifies this DirectedEdge's direction (given by an imaginary + line from the from node to directionPt). + + + Whether this DirectedEdge's direction is the same as or + opposite to that of the parent Edge (if any). + + + + + Returns this DirectedEdge's parent Edge, or null if it has none. + Associates this DirectedEdge with an Edge (possibly null, indicating no associated + Edge). + + + + + Returns 0, 1, 2, or 3, indicating the quadrant in which this DirectedEdge's + orientation lies. + + + + + Returns 0, 1, 2, or 3, indicating the quadrant in which this DirectedEdge's + orientation lies. + + + + + Returns a point to which an imaginary line is drawn from the from-node to + specify this DirectedEdge's orientation. + + + + + Returns whether the direction of the parent Edge (if any) is the same as that + of this Directed Edge. + + + + + Returns the node from which this DirectedEdge leaves. + + + + + Returns the node to which this DirectedEdge goes. + + + + + Returns the coordinate of the from-node. + + + + + Returns the angle that the start of this DirectedEdge makes with the + positive x-axis, in radians. + + + + + Returns the symmetric DirectedEdge -- the other DirectedEdge associated with + this DirectedEdge's parent Edge. + Sets this DirectedEdge's symmetric DirectedEdge, which runs in the opposite + direction. + + + + + Returns 1 if this DirectedEdge has a greater angle with the + positive x-axis than b", 0 if the DirectedEdges are collinear, and -1 otherwise. + Using the obvious algorithm of simply computing the angle is not robust, + since the angle calculation is susceptible to round off. A robust algorithm + is: + first compare the quadrants. If the quadrants are different, it it + trivial to determine which vector is "greater". + if the vectors lie in the same quadrant, the robust + RobustCGAlgorithms.ComputeOrientation(Coordinate, Coordinate, Coordinate) + function can be used to decide the relative orientation of the vectors. + + + + + + + Returns 1 if this DirectedEdge has a greater angle with the + positive x-axis than b", 0 if the DirectedEdges are collinear, and -1 otherwise. + Using the obvious algorithm of simply computing the angle is not robust, + since the angle calculation is susceptible to round off. A robust algorithm + is: + first compare the quadrants. If the quadrants are different, it it + trivial to determine which vector is "greater". + if the vectors lie in the same quadrant, the robust + RobustCGAlgorithms.ComputeOrientation(Coordinate, Coordinate, Coordinate) + function can be used to decide the relative orientation of the vectors. + + + + + + + Writes a detailed string representation of this DirectedEdge to the given PrintStream. + + + + + + Tests whether this component has been removed from its containing graph. + + + + + + Removes this directed edge from its containing graph. + + + + + + + + A sorted collection of DirectedEdges which leave a Node + in a PlanarGraph. + + + + + The underlying list of outgoing DirectedEdges. + + + + + Adds a new member to this DirectedEdgeStar. + + + + + + Drops a member of this DirectedEdgeStar. + + + + + + Returns an Iterator over the DirectedEdges, in ascending order by angle with the positive x-axis. + + + + + Returns the number of edges around the Node associated with this DirectedEdgeStar. + + + + + Returns the coordinate for the node at which this star is based. + + + + + Returns the DirectedEdges, in ascending order by angle with the positive x-axis. + + + + + + + + + + Returns the zero-based index of the given Edge, after sorting in ascending order + by angle with the positive x-axis. + + + + + + + Returns the zero-based index of the given DirectedEdge, after sorting in ascending order + by angle with the positive x-axis. + + + + + + + Returns the remainder when i is divided by the number of edges in this + DirectedEdgeStar. + + + + + + + Returns the on the left-hand + side of the given + (which must be a member of this DirectedEdgeStar). + + + + + + + Returns the on the right-hand (CW) + side of the given + (which must be a member of this DirectedEdgeStar). + + + + + Represents an undirected edge of a {PlanarGraph}. An undirected edge + in fact simply acts as a central point of reference for two opposite + DirectedEdges. + Usually a client using a PlanarGraph will subclass Edge + to add its own application-specific data and methods. + + + + + The two DirectedEdges associated with this Edge. + + + + + Constructs an Edge whose DirectedEdges are not yet set. Be sure to call + SetDirectedEdges(DirectedEdge, DirectedEdge). + + + + + Constructs an Edge initialized with the given DirectedEdges, and for each + DirectedEdge: sets the Edge, sets the symmetric DirectedEdge, and adds + this Edge to its from-Node. + + + + + + + Initializes this Edge's two DirectedEdges, and for each DirectedEdge: sets the + Edge, sets the symmetric DirectedEdge, and adds this Edge to its from-Node. + + + + + + + Returns one of the DirectedEdges associated with this Edge. + + 0 or 1. + + + + + Returns the DirectedEdge that starts from the given node, or null if the + node is not one of the two nodes associated with this Edge. + + + + + + + If node is one of the two nodes associated with this Edge, + returns the other node; otherwise returns null. + + + + + + + Removes this edge from its containing graph. + + + + + Tests whether this component has been removed from its containing graph. + + + + + + The base class for all graph component classes. + Maintains flags of use in generic graph algorithms. + Provides two flags: + marked - typically this is used to indicate a state that persists + for the course of the graph's lifetime. For instance, it can be + used to indicate that a component has been logically deleted from the graph. + visited - this is used to indicate that a component has been processed + or visited by an single graph algorithm. For instance, a breadth-first traversal of the + graph might use this to indicate that a node has already been traversed. + The visited flag may be set and cleared many times during the lifetime of a graph. + + + + + Sets the state + for all s in an . + + A to scan. + The state to set the flag to. + + + + Sets the state + for all s in an . + + A to scan. + The state to set the flag to. + + + + Finds the first + in a set + which has the specified state. + + A to scan. + The state to test. + The first found, or null if none found. + + + + Tests if a component has been visited during the course of a graph algorithm. + + + + + Gets/Sets the visited flag for this component. + + + + + Tests if a component has been marked at some point during the processing + involving this graph. + + + + + Gets/Sets the marked flag for this component. + + + + + Tests whether this component has been removed from its containing graph. + + + + + Gets or sets user defined data for this component + + + + + A node in a PlanarGraph is a location where 0 or more Edges + meet. A node is connected to each of its incident Edges via an outgoing + DirectedEdge. Some clients using a PlanarGraph may want to + subclass Node to add their own application-specific + data and methods. + + + + + Returns all Edges that connect the two nodes (which are assumed to be different). + + + + + + + + The location of this Node. + + + + + The collection of DirectedEdges that leave this Node. + + + + + Constructs a Node with the given location. + + + + + + Constructs a Node with the given location and collection of outgoing DirectedEdges. + + + + + + + Returns the location of this Node. + + + + + Adds an outgoing DirectedEdge to this Node. + + + + + + Returns the collection of DirectedEdges that leave this Node. + + + + + Returns the number of edges around this Node. + + + + + Returns the zero-based index of the given Edge, after sorting in ascending order + by angle with the positive x-axis. + + + + + + + Removes a incident on this node. Does not change the state of the directed edge. + + + + + Removes this node from its containing graph. + + + + + Tests whether this component has been removed from its containing graph. + + + + + + + + + + + + A map of nodes, indexed by the coordinate of the node. + + + + + Adds a node to the map, replacing any that is already at that location. + + + The added node. + + + + Removes the Node at the given location, and returns it (or null if no Node was there). + + + + + + + Returns the Node at the given location, or null if no Node was there. + + + + + + + Returns an Iterator over the Nodes in this NodeMap, sorted in ascending order + by angle with the positive x-axis. + + + + + Returns the Nodes in this NodeMap, sorted in ascending order + by angle with the positive x-axis. + + + + + Returns the number of Nodes in this NodeMap. + + + + + Represents a directed graph which is embeddable in a planar surface. + This class and the other classes in this package serve as a framework for + building planar graphs for specific algorithms. This class must be + subclassed to expose appropriate methods to construct the graph. This allows + controlling the types of graph components ({DirectedEdge}s, + Edges and Nodes) which can be added to the graph. An + application which uses the graph framework will almost always provide + subclasses for one or more graph components, which hold application-specific + data and graph algorithms. + + + + + + + + + + + + + + + + + + + + Returns the at the given location, or null if no was there. + + The location + The node found
+ or null if this graph contains no node at the location +
+
+ + + Adds a node to the map, replacing any that is already at that location. + Only subclasses can add Nodes, to ensure Nodes are of the right type. + + + The added node. + + + + Adds the Edge and its DirectedEdges with this PlanarGraph. + Assumes that the Edge has already been created with its associated DirectEdges. + Only subclasses can add Edges, to ensure the edges added are of the right class. + + + + + + Adds the Edge to this PlanarGraph; only subclasses can add DirectedEdges, + to ensure the edges added are of the right class. + + + + + + Returns an IEnumerator over the Nodes in this PlanarGraph. + + + + + + Returns the Nodes in this PlanarGraph. + + + + + Returns an Iterator over the DirectedEdges in this PlanarGraph, in the order in which they + were added. + + + + + + Returns an Iterator over the Edges in this PlanarGraph, in the order in which they + were added. + + + + + + Returns the Edges that have been added to this PlanarGraph. + + + + + Removes an Edge and its associated DirectedEdges from their from-Nodes and + from this PlanarGraph. Note: This method does not remove the Nodes associated + with the Edge, even if the removal of the Edge reduces the degree of a + Node to zero. + + + + + + Removes a from its from- and from this PlanarGraph. + + + This method does not remove the s associated with the DirectedEdge, + even if the removal of the DirectedEdge reduces the degree of a Node to zero. + + + + + + Removes a node from the graph, along with any associated DirectedEdges and + Edges. + + + + + + Returns all Nodes with the given number of Edges around it. + + + + + + + A subgraph of a . + A subgraph may contain any subset of s + from the parent graph. + It will also automatically contain all s + and s associated with those edges. + No new objects are created when edges are added - + all associated components must already exist in the parent graph. + + + + + + + + + + + + + + + + + + + + + + + + + Creates a new subgraph of the given . + + + + + + Gets the which this subgraph is part of. + + + + + + Adds an to the subgraph. + The associated s and s are also added. + + The to add. + + + + Returns an over the s in this graph, + in the order in which they were added. + + + + + + Returns an over the s in this graph, + in the order in which they were added. + + + + + + Returns an over the s in this graph. + + + + + + Tests whether an is contained in this subgraph. + + The to test. + true if the is contained in this subgraph. + + + + Determines the maximum number of common most-significant + bits in the mantissa of one or numbers. + Can be used to compute the double-precision number which + is represented by the common bits. + If there are no common bits, the number computed is 0.0. + + + + + Computes the bit pattern for the sign and exponent of a + double-precision number. + + + The bit pattern for the sign and exponent. + + + + This computes the number of common most-significant bits in the mantissas + of two double-precision numbers. + It does not count the hidden bit, which is always 1. + It does not determine whether the numbers have the same exponent - if they do + not, the value computed by this function is meaningless. + + + /// + The number of common most-significant mantissa bits. + + + + Zeroes the lower n bits of a bitstring. + + The bitstring to alter. + the number of bits to zero. + The zeroed bitstring. + + + + Extracts the i'th bit of a bitstring. + + The bitstring to extract from. + The bit to extract. + The value of the extracted bit. + + + + + + + + + + + + + + + A representation of the Double bits formatted for easy readability + + + + + + + Provides versions of Geometry spatial functions which use + common bit removal to reduce the likelihood of robustness problems. + In the current implementation no rounding is performed on the + reshifted result point, which means that it is possible + that the returned Geometry is invalid. + Client classes should check the validity of the returned result themselves. + + + + + Creates a new instance of class, which reshifts result Geometrys. + + + + + Creates a new instance of class, specifying whether + the result Geometrys should be reshifted. + + + + + + Computes the set-theoretic intersection of two Geometrys, using enhanced precision. + + The first Geometry. + The second Geometry. + The Geometry representing the set-theoretic intersection of the input Geometries. + + + + Computes the set-theoretic union of two Geometrys, using enhanced precision. + + The first Geometry. + The second Geometry. + The Geometry representing the set-theoretic union of the input Geometries. + + + + Computes the set-theoretic difference of two Geometrys, using enhanced precision. + + The first Geometry. + The second Geometry, to be subtracted from the first. + The Geometry representing the set-theoretic difference of the input Geometries. + + + Computes the set-theoretic symmetric difference of two geometries, + using enhanced precision. + + The first Geometry. + The second Geometry. + The Geometry representing the set-theoretic symmetric difference of the input Geometries. + + + + Computes the buffer a point, using enhanced precision. + + The Geometry to buffer. + The buffer distance. + The Geometry representing the buffer of the input Geometry. + + + + If required, returning the result to the original precision if required. + In this current implementation, no rounding is performed on the + reshifted result point, which means that it is possible + that the returned Geometry is invalid. + + The result Geometry to modify. + The result Geometry with the required precision. + + + + Computes a copy of the input Geometry with the calculated common bits + removed from each coordinate. + + The Geometry to remove common bits from. + A copy of the input Geometry with common bits removed. + + + + Computes a copy of each input Geometrys with the calculated common bits + removed from each coordinate. + + A Geometry to remove common bits from. + A Geometry to remove common bits from. + + An array containing copies + of the input Geometry's with common bits removed. + + + + + Removes common most-significant mantissa bits + from one or more s. + + The CommonBitsRemover "scavenges" precision + which is "wasted" by a large displacement of the geometry + from the origin. + For example, if a small geometry is displaced from the origin + by a large distance, + the displacement increases the significant figures in the coordinates, + but does not affect the relative topology of the geometry. + Thus the geometry can be translated back to the origin + without affecting its topology. + In order to compute the translation without affecting + the full precision of the coordinate values, + the translation is performed at the bit level by + removing the common leading mantissa bits. + + If the geometry envelope already contains the origin, + the translation procedure cannot be applied. + In this case, the common bits value is computed as zero. + + If the geometry crosses the Y axis but not the X axis + (and mutatis mutandum), + the common bits for Y are zero, + but the common bits for X are non-zero. + + + + + Add a point to the set of geometries whose common bits are + being computed. After this method has executed the + common coordinate reflects the common bits of all added + geometries. + + A Geometry to test for common bits. + + + + The common bits of the Coordinates in the supplied Geometries. + + + + + Removes the common coordinate bits from a Geometry. + The coordinates of the Geometry are changed. + + The Geometry from which to remove the common coordinate bits. + The shifted Geometry. + + + + Adds the common coordinate bits back into a Geometry. + The coordinates of the Geometry are changed. + + The Geometry to which to add the common coordinate bits. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The coordinate sequence + + + + Reduces the precision of the s in a + to match the supplied . + + + Uses . + The input is modified in-place, so + it should be cloned beforehand if the + original should not be modified. + + mbdavis + + + + Creates a new precision reducer filter. + + The PrecisionModel to use + + + + Rounds the Coordinates in the sequence to match the PrecisionModel + + + + + Always runs over all geometry components. + + + + + Always reports that the geometry has changed + + + + + Provides versions of Geometry spatial functions which use + enhanced precision techniques to reduce the likelihood of robustness problems. + + + + + Only static methods! + + + + + Computes the set-theoretic intersection of two Geometrys, using enhanced precision. + + The first Geometry. + The second Geometry. + The Geometry representing the set-theoretic intersection of the input Geometries. + + + + Computes the set-theoretic union of two Geometrys, using enhanced precision. + + The first Geometry. + The second Geometry. + The Geometry representing the set-theoretic union of the input Geometries. + + + + Computes the set-theoretic difference of two Geometrys, using enhanced precision. + + The first Geometry. + The second Geometry. + The Geometry representing the set-theoretic difference of the input Geometries. + + + + Computes the set-theoretic symmetric difference of two Geometrys, using enhanced precision. + + The first Geometry. + The second Geometry. + The Geometry representing the set-theoretic symmetric difference of the input Geometries. + + + + Reduces the precision of a + according to the supplied , + ensuring that the result is valid (unless specified otherwise). + + By default the geometry precision model is not changed. + This can be overridden by using . +

Topological Precision Reduction

+ The default mode of operation ensures the reduced result is topologically valid + (i.e. is true). + To ensure this polygonal geometry is reduced in a topologically valid fashion + (technically, by using snap-rounding). + Note that this may change polygonal geometry structure + (e.g.two polygons separated by a distance below the specified precision + will be merged into a single polygon). + Duplicate vertices are removed. + This mode is invoked by the static method . + + Normally, collapsed linear components(e.g.lines collapsing to a point) + are not included in the result. + This behavior can be changed + by setting to false, + or by using the static method . + + In general input must be valid geometry, or an + will be thrown. However if the invalidity is "mild" or very small then it + may be eliminated by precision reduction. +

Pointwise Precision Reduction

+ Alternatively, geometry can be reduced pointwise by using {@link #setPointwise(boolean)}. + Linear and point geometry are always reduced pointwise(i.e.without further change to + topology or structure), since this does not change validity. + Invalid inputs are allowed. + Duplicate vertices are preserved. + Collapsed components are always included in the result. + The result geometry may be invalid. + + This mode is invoked by the static method . +
+
+ + + Reduces precision of a geometry, ensuring output geometry is valid. + Collapsed linear and polygonal components are removed. + The geometry precision model is not changed. + Invalid input geometry may cause an error, + unless the invalidity is below the scale of the precision reduction. + + The geometry to reduce + The precision model to use + The reduced geometry + Thrwon if the reduction fails due to invalid input geometry + + + + Reduces precision of a geometry, ensuring output polygonal geometry is valid, + and preserving collapsed linear elements. + The geometry precision model is not changed. + Invalid input geometry may cause an error, + unless the invalidity is below the scale of the precision reduction. + + The geometry to reduce + The precision model to use + The reduced geometry + Thrwon if the reduction fails due to invalid input geometry + + + + Reduce precision of a geometry in a pointwise way. + All input geometry elements are preserved in the output, + including invalid polygons and collapsed polygons and linestrings. + The output may not be valid, due to collapse or self-intersection. + The geometry precision model is not changed. + Invalid input geometry is allowed. + + The geometry to reduce + The precision model to use + The reduced geometry + + + Gets or sets whether the reduction will result in collapsed components + being removed completely, or simply being collapsed to an (invalid) + Geometry of the same type. + The default is to remove collapsed components. + + + + + Gets or sets whether the of the new reduced Geometry + will be changed to be the supplied to + specify the precision reduction. + + The default is to not change the precision model + + + + + Gets or sets whether the precision reduction will be done + in pointwise fashion only. + Pointwise precision reduction reduces the precision + of the individual coordinates only, but does + not attempt to recreate valid topology. + This is only relevant for geometries containing polygonal components. + + + + + Reduces the precision of a geometry, + according to the specified strategy of this reducer. + + The geometry to reduce + The precision-reduced geometry + if the reduction fails + due to input geometry is invalid. + + + + Duplicates a geometry to one that uses a different PrecisionModel, + without changing any coordinate values. + + The geometry to duplicate + The precision model to use + The geometry value with a new precision model + + + + Computes the Minimum Clearance of a . + + The Minimum Clearance is a measure of + what magnitude of perturbation of + the vertices of a geometry can be tolerated + before the geometry becomes topologically invalid. + The smaller the Minimum Clearance distance, + the less vertex perturbation the geometry can tolerate + before becoming invalid. + + + The concept was introduced by Thompson and Van Oosterom + [TV06], based on earlier work by Milenkovic [Mi88]. + + The Minimum Clearance of a geometry G + is defined to be the value r + such that "the movement of all points by a distance + of r in any direction will + guarantee to leave the geometry valid" [TV06]. + An equivalent constructive definition [Mi88] is that + r is the largest value such: + + No two distinct vertices of G are closer than r. + No vertex of G is closer than r to an edge of G of which the vertex is not an endpoint + + The following image shows an example of the Minimum Clearance + of a simple polygon. + +
minimum clearance
+ + If G has only a single vertex (i.e. is a + ), the value of the minimum clearance + is . + + If G is a or geometry, + then in fact no amount of perturbation + will render the geometry invalid. + In this case a Minimum Clearance is still computed + based on the vertex and segment distances + according to the constructive definition. + + It is possible for no Minimum Clearance to exist. + For instance, a with all members identical + has no Minimum Clearance + (i.e. no amount of perturbation will cause + the member points to become non-identical). + Empty geometries also have no such distance. + The lack of a meaningful MinimumClearance distance is detected + and suitable values are returned by + and . + + The computation of Minimum Clearance utilizes + the + method to provide good performance even for + large inputs. + + An interesting note is that for the case of s, + the computed Minimum Clearance line + effectively determines the Nearest Neighbours in the collection. +

References

+ + [Mi88] Milenkovic, V. J., + Verifiable implementations of geometric algorithms + using finite precision arithmetic. + in Artificial Intelligence, 377-401. 1988 + [TV06] Thompson, Rod and van Oosterom, Peter, + Interchange of Spatial Data-Inhibiting Factors, + Agile 2006, Visegrad, Hungary. 2006 + +
+ /// Martin Davis +
+ + + Computes the Minimum Clearance distance for + the given Geometry. + + The input geometry + The minimum clearance + + + + Gets a LineString containing two points + which are at the Minimum Clearance distance + for the given Geometry. + + The input geometry + The value of the minimum clearance distance
+ or LINESTRING EMPTY if no minimum clearance distance exists.
+
+ + + Creates an object to compute the Minimum Clearance for the given Geometry + + The input geometry + + + + Gets the Minimum Clearance distance. + If no distance exists + (e.g. in the case of two identical points) + is returned. + + + The value of the minimum clearance distance
+ or if no Minimum Clearance distance exists +
+
+ + + Gets a LineString containing two points + which are at the Minimum Clearance distance. + If no distance could be found + (e.g. in the case of two identical points) + LINESTRING EMPTY is returned. + + The value of the minimum clearance distance,
+ or LINESTRING EMPTY if no minimum clearance distance exists.
+
+ + + Implements the MinimumClearance distance function: + + dist(p1, p2) = + p1 != p2 : p1.distance(p2) + p1 == p2 : Double.MAX + + dist(p, seg) = + p != seq.p1 && p != seg.p2 + ? seg.distance(p) + : Double.MaxValue + + Also computes the values of the nearest points, if any. + + Martin Davis + + + + A transformer to reduce the precision of a geometry pointwise. + + Martin Davis + + + + A transformer to reduce the precision of geometry in a + topologically valid way.
+ Repeated points are removed. + If geometry elements collapse below their valid length, + they may be removed + by specifying isRemoveCollapsed as true. +
+ Martin Davis +
+ + + + + + + + + Computes the minimum clearance of a geometry or + set of geometries. + The Minimum Clearance is a measure of + what magnitude of perturbation of its vertices can be tolerated + by a geometry before it becomes topologically invalid. + + This class uses an inefficient O(N^2) scan. + It is primarily for testing purposes. + + + Martin Davis + + + + Creates a curved geometry by replacing the segments + of the input with Cubic Bezier Curves. + + + The Bezier control points are determined from the segments of the geometry + and the alpha control parameter controlling curvedness, and + the optional skew parameter controlling the shape of the curve at vertices. + The Bezier Curves are created to be C2-continuous (smooth) + at each input vertex. + + Alternatively, the Bezier control points can be supplied explicitly. + + The result is not guaranteed to be valid, since large alpha values + may cause self-intersections. + + + + + Creates a geometry of linearized Cubic Bezier Curves + defined by the segments of the input and a parameter + controlling how curved the result should be. + + The geometry defining the curve + A curvedness parameter (0 is linear, 1 is round, >1 is increasingly curved) + The linearized curved geometry + + + + Creates a geometry of linearized Cubic Bezier Curves + defined by the segments of the inputand a parameter + controlling how curved the result should be, with a skew factor + affecting the curve shape at each vertex. + + The geometry defining the curve + The curvedness parameter (0 is linear, 1 is round, >1 is increasingly curved) + The skew parameter (0 is none, positive skews towards longer side, negative towards shorter + The linearized curved geometry + + + + Creates a geometry of linearized Cubic Bezier Curves + defined by the segments of the input + and a list (or lists) of control points. + + + Typically the control point geometry + is a or + containing an element for each line or ring in the input geometry. + The list of control points for each linear element must contain two + vertices for each segment (and thus 2 * npts - 2). + + The geometry defining the curve + A geometry containing the control point elements. + The linearized curved geometry + + + + Creates a new instance producing a Bezier curve defined by a geometry + and an alpha curvedness value. + + The geometry defining curve + A curvedness parameter (0 = linear, 1 = round, 2 = distorted) + + + + Creates a new instance producing a Bezier curve defined by a geometry, + an alpha curvedness value, and a skew factor. + + The geometry defining curve + curvedness parameter (0 is linear, 1 is round, >1 is increasingly curved) + The skew parameter (0 is none, positive skews towards longer side, negative towards shorter + + + + Creates a new instance producing a Bezier curve defined by a geometry, + and a list (or lists) of control points. + + + Typically the control point geometry + is a or + containing an element for each line or ring in the input geometry. + The list of control points for each linear element must contain two + vertices for each segment (and thus 2 * npts - 2). + + + + + Gets the computed Bezier curve geometry + + The curved geometry + + + + Creates control points for each vertex of curve. + The control points are collinear with each vertex, + thus providing C1-continuity. + By default the control vectors are the same length, + which provides C2-continuity(same curvature on each + side of vertex. + The alpha parameter controls the length of the control vectors. + Alpha = 0 makes the vectors zero-length, and hence flattens the curves. + Alpha = 1 makes the curve at right angles roughly circular. + Alpha > 1 starts to distort the curve and may introduce self-intersections. + + The control point array contains a pair of coordinates for each input segment. + + + + + Sets the end control points for a line. + Produce a symmetric curve for the first and last segments + by using mirrored control points for start and end vertex. + + The coordinates + The control points + + + + Creates a control point aimed at the control point at the opposite end of the segment. + + + + + Calculates vertices along a cubic Bezier curve. + + The start point + The end point + The first control point + The second control point + A set of interpolation parameters + An array to hold generated points. + + + + Gets the interpolation parameters for a Bezier curve approximated by a + given number of vertices. + + The number of vertices + An array of double[4] holding the parameter values + + + + Encodes points as the index along finite planar Hilbert curves. + + The planar Hilbert Curve is a continuous space-filling curve. + In the limit the Hilbert curve has infinitely many vertices and fills + the space of the unit square. + A sequence of finite approximations to the infinite Hilbert curve + is defined by the level number. + The finite Hilbert curve at level n Hₙ contains 2ⁿ⁺¹ points. + Each finite Hilbert curve defines an ordering of the + points in the 2-dimensional range square containing the curve. + Curves fills the range square of side 2ˡᵉᵛᵉˡ. + Curve points have ordinates in the range [0, 2ˡᵉᵛᵉˡ - 1]. + The index of a point along a Hilbert curve is called the Hilbert code. + The code for a given point is specific to the level chosen. + + + This implementation represents codes using 32-bit integers. + This allows levels 0 to 16 to be handled. + The class supports encoding points in the range of a given level curve + and decoding the point for a given code value. + + + The Hilbert order has the property that it tends to preserve locality. + This means that codes which are near in value will have spatially proximate + points. The converse is not always true - the delta between + codes for nearby points is not always small. But the average delta + is small enough that the Hilbert order is an effective way of linearizing space + to support range queries. + + + + Martin Davis + + + + + + + The maximum curve level that can be represented. + + + + + The number of points in the curve for the given level. + The number of points is 2²ˡᵉᵛᵉˡ. + + The level of the curve + The number of points. + + + + The maximum ordinate value for points + in the curve for the given level. + The maximum ordinate is 2ˡᵉᵛᵉˡ - 1. + + The level of the curve. + The maximum ordinate value. + + + + The level of the finite Hilbert curve which contains at least + the given number of points. + + The number of points required. + The level of the curve. + + + + Encodes a point (x,y) + in the range of the the Hilbert curve at a given level + as the index of the point along the curve. + The index will lie in the range [0, 2ˡᵉᵛᵉˡ⁺¹]. + + The level of the Hilbert curve. + The x ordinate of the point. + The y ordinate of the point. + The index of the point along the Hilbert curve. + + + + Clamps a level to the range valid for + the index algorithm used. + + The level of a Hilbert curve. + A valid level. + + + + Computes the point on a Hilbert curve + of given level for a given code index. + The point ordinates will lie in the range [0, 2ˡᵉᵛᵉˡ - 1]. + + The Hilbert curve level. + The index of the point on the curve. + The point on the Hilbert curve. + + + + Generates a representing the Hilbert Curve + at a given level. + + + + + Initializes a new instance of the class + using the provided . + + The geometry factory to use. + + + + Gets or sets the level of curve to generate. + The level must be in the range [0 - 16]. + This determines the + number of points in the generated curve. + + + + + + + + The height of an equilateral triangle of side one + + + + + Encodes points as the index along the planar Morton (Z-order) curve. + + The planar Morton (Z-order) curve is a continuous space-filling curve. + The Morton curve defines an ordering of the + points in the positive quadrant of the plane. + The index of a point along the Morton curve is called the Morton code. + + + A sequence of subsets of the Morton curve can be defined by a level number. + Each level subset occupies a square range. + The curve at level n Mₙ contains 2ⁿ⁺¹ points. + It fills the range square of side 2ˡᵉᵛᵉˡ. + Curve points have ordinates in the range [0, 2ˡᵉᵛᵉˡ - 1]. + The code for a given point is identical at all levels. + The level simply determines the number of points in the curve subset + and the size of the range square. + + + This implementation represents codes using 32-bit integers. + This allows levels 0 to 16 to be handled. + The class supports encoding points + and decoding the point for a given code value. + + + The Morton order has the property that it tends to preserve locality. + This means that codes which are near in value will have spatially proximate + points. The converse is not always true - the delta between + codes for nearby points is not always small. But the average delta + is small enough that the Morton order is an effective way of linearizing space + to support range queries. + + + + Martin Davis + + + + + + + The maximum curve level that can be represented. + + + + + The number of points in the curve for the given level. + The number of points is 2²ˡᵉᵛᵉˡ. + + The level of the curve + The number of points. + + + + The maximum ordinate value for points + in the curve for the given level. + The maximum ordinate is 2ˡᵉᵛᵉˡ - 1. + + The level of the curve. + The maximum ordinate value. + + + + The level of the finite Morton curve which contains at least + the given number of points. + + The number of points required. + The level of the curve. + + + + Computes the index of the point (x,y) + in the Morton curve ordering. + + The x ordinate of the point. + The y ordinate of the point. + The index of the point along the Morton curve. + + + + Computes the point on the Morton curve + for a given index. + + The index of the point on the curve. + The point on the curve. + + + + Generates a representing the Morton Curve + at a given level. + + + + + Initializes a new instance of the class + using the provided . + + The geometry factory to use. + + + + Gets or sets the level of curve to generate. + The level must be in the range [0 - 16]. + + + + + + + + Gets or sets the total number of points in the created . + The created geometry will have no more than this number of points, + unless more are needed to create a valid geometry. + + + + + Creates random point sets contained in a + region defined by either a rectangular or a polygonal extent. + + mbdavis + + + + Create a shape factory which will create shapes using the default + . + + + + + Create a shape factory which will create shapes using the given + + + The factory to use + + + + Sets a polygonal mask. + + if the mask is not polygonal + + + + Creates random point sets where the points + are constrained to lie in the cells of a grid. + + mbdavis + + + + Create a builder which will create shapes using the default + . + + + + + Create a builder which will create shapes using the given + . + + The factory to use + + + + Gets or sets whether generated points are constrained to lie + within a circle contained within each grid cell. + This provides greater separation between points + in adjacent cells. + + The default is to not be constrained to a circle. + + + + + Gets or sets the fraction of the grid cell side which will be treated as + a gutter, in which no points will be created. + + The provided value is clamped to the range [0.0, 1.0]. + + + + + Gets the containing the generated point + + A MultiPoint + + + + Simplifies a line (sequence of points) using + the standard Douglas-Peucker algorithm. + + + + + + + + + + + + + Creates an instance of this class using the provided array of coordinates + + An array of coordinates + + + + The distance tolerance for the simplification. + + + + + + + + + + + Simplifies a using the Douglas-Peucker algorithm. + + + Ensures that any polygonal geometries returned are valid. + Simple lines are not guaranteed to remain simple after simplification. + All geometry types are handled. + Empty and point geometries are returned unchanged. + Empty geometry components are deleted. + + Note that in general D-P does not preserve topology - + e.g. polygons can be split, collapse to lines or disappear + holes can be created or disappear, + and lines can cross. + To simplify point while preserving topology use TopologySafeSimplifier. + (However, using D-P is significantly faster). + + KNOWN BUGS: + In some cases the approach used to clean invalid simplified polygons + can distort the output geometry severely. + + + + + + Simplifies a geometry using a given tolerance. + + The geometry to simplify. + The tolerance to use. + A simplified version of the geometry. + + + + Creates a simplifier for a given geometry. + + The geometry to simplify. + + + + The distance tolerance for the simplification. + + + All vertices in the simplified geometry will be within this + distance of the original geometry. + The tolerance value must be non-negative. + + + + + Controls whether simplified polygons will be "fixed" + to have valid topology. + + + The caller may choose to disable this because: + + valid topology is not required + fixing topology is a relative expensive operation + in some pathological cases the topology fixing operation may either fail or run for too long + + The default is to fix polygon topology. + + + + + Gets the simplified geometry. + + The simplified geometry. + + + + The transformer class + + + + + + + + Simplifies a polygon, fixing it if required. + + The geometry to transform + The parent geometry + + + + + Simplifies a LinearRing. If the simplification results in a degenerate ring, remove the component. + + null if the simplification results in a degenerate ring + + + + + + + Creates a valid area point from one that possibly has + bad topology (i.e. self-intersections). + Since buffer can handle invalid topology, but always returns + valid point, constructing a 0-width buffer "corrects" the + topology. + Note this only works for area geometries, since buffer always returns + areas. This also may return empty geometries, if the input + has no actual area.
+ If the input is empty or is not polygonal, + this ensures that POLYGON EMPTY is returned. +
+ An area point possibly containing self-intersections. + A valid area point. +
+ + + An index of LineSegments. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ItemVisitor subclass to reduce volume of query results. + + + + + + + + + + + + + + + + + + + + + + Simplifies a linestring (sequence of points) using the + Visvalingam-Whyatt algorithm. + The Visvalingam-Whyatt algorithm simplifies geometry + by removing vertices while trying to minimize the area changed. + + 1.7 + + + + A LineSegment which is tagged with its location in a Geometry. + Used to index the segments in a point and recover the segment locations + from the index. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Simplifies a collection of TaggedLineStrings, preserving topology + (in the sense that no new intersections are introduced). + This class is essentially just a container for the common + indexes used by . + + + + + Gets or sets the distance tolerance for the simplification.
+ Points closer than this tolerance to a simplified segment may + be removed. +
+
+ + + Simplifies a collection of TaggedLineStrings. + + The collection of lines to simplify. + + + + Represents a which can be modified to a simplified shape. + This class provides an attribute which specifies the minimum allowable length + for the modified result. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Simplifies a TaggedLineString, preserving topology + (in the sense that no new intersections are introduced). + Uses the recursive Douglas-Peucker algorithm. + + + + + Sets the distance tolerance for the simplification. + All vertices in the simplified geometry will be within this + distance of the original geometry. + + + + + Simplifies the given + using the distance tolerance specified. + + The linestring to simplify. + + + + Flattens a section of the line between + indexes and , + replacing them with a line between the endpoints. + The input and output indexes are updated + to reflect this. + + The start index of the flattened section. + The end index of the flattened section. + The new segment created. + + + + Tests whether a segment is in a section of a . + + + + + + + + + Remove the segs in the section of the line. + + + + + + + + Simplifies a point and ensures that + the result is a valid point having the + same dimension and number of components as the input, + and with the components having the same topological + relationship. + + If the input is a polygonal geometry + ( or ): + + The result has the same number of shells and holes as the input, + with the same topological structure + The result rings touch at no more than the number of touching points in the input + (although they may touch at fewer points). + The key implication of this statement is that if the + input is topologically valid, so is the simplified output. + + For linear geometries, if the input does not contain + any intersecting line segments, this property + will be preserved in the output. + + For all geometry types, the result will contain + enough vertices to ensure validity. For polygons + and closed linear geometries, the result will have at + least 4 vertices; for open LineStrings the result + will have at least 2 vertices. + + All geometry types are handled. + Empty and point geometries are returned unchanged. + Empty geometry components are deleted. + + The simplification uses a maximum-distance difference algorithm + similar to the Douglas-Peucker algorithm. + + +

KNOWN BUGS

+ + May create invalid topology if there are components which are small + relative to the tolerance value. + In particular, if a small hole is very near an edge, + it is possible for the edge to be moved by a relatively large tolerance value + and end up with the hole outside the result shell (or inside another hole). + Similarly, it is possible for a small polygon component to end up inside + a nearby larger polygon. + A workaround is to test for this situation in post-processing and remove + any invalid holes or polygons. + +
+ +
+ + + + + + + + + + + Creates an instance of this class for the provided geometry + + The geometry to simplify + + + + Gets or sets the distance tolerance for the simplification.
+ Points closer than this tolerance to a simplified segment may + be removed. +
+
+ + + + + + + + + A LineString transformer + + + + > + + + + A filter to add linear geometries to the LineString map + with the appropriate minimum size constraint. + Closed s (including s + have a minimum output size constraint of 4, + to ensure the output is valid. + For all other LineStrings, the minimum size is 2 points. + + Martin Davis + + + + Filters linear geometries. + + A geometry of any type + + + + Simplifies a linestring (sequence of points) using the + Visvalingam-Whyatt algorithm. + The Visvalingam-Whyatt algorithm simplifies geometry + by removing vertices while trying to minimize the area changed. + + 1.7 + + + + Simplifies a using the Visvalingam-Whyatt area-based algorithm. + Ensures that any polygonal geometries returned are valid. Simple lines are not + guaranteed to remain simple after simplification. All geometry types are + handled. Empty and point geometries are returned unchanged. Empty geometry + components are deleted. + The simplification tolerance is specified as a distance. + This is converted to an area tolerance by squaring it. + + Known Bugs + * Not yet optimized for performance. + * Does not simplify the endpoint of rings. + To Do + * Allow specifying desired number of vertices in the output. + + + + Note that in general this algorithm does not preserve topology - e.g. polygons can be split, + collapse to lines or disappear holes can be created or disappear, and lines + can cross. + + 1.7 + + + + Simplifies a using a given tolerance. + + The to simplify. + The tolerance to use. + A simplified version of the . + + + + Creates a simplifier for a given . + + The to simplify. + + + + Sets the distance tolerance for the simplification. All vertices in the + simplified will be within this distance of the original geometry. + The tolerance value must be non-negative. + + + + + Controls whether simplified polygons will be "fixed" to have valid + topology. The caller may choose to disable this because: + * valid topology is not required. + * fixing topology is a relative expensive operation. + * in some pathological cases the topology fixing operation may either + fail or run for too long. + + The default is to fix polygon topology. + + + + Gets the simplified . + + The simplified . + + + + Simplifies a , fixing it if required. + + + + + + + + Simplifies a . If the simplification results in a degenerate + ring, remove the component. + + + + null if the simplification results in a degenerate ring. + + + + Simplifies a , fixing it if required. + + + + + + + + Creates a valid area geometry from one that possibly has bad topology + (i.e. self-intersections). Since buffer can handle invalid topology, but + always returns valid geometry, constructing a 0-width buffer "corrects" + the topology. Note this only works for area geometries, since buffer + always returns areas. This also may return empty geometries, if the input + has no actual area. + + An area geometry possibly containing self-intersections. + A valid area geometry. + + + + A utility class which creates Conforming Delaunay Triangulations + from collections of points and linear constraints, and extract the resulting + triangulation edges or triangles as geometries. + + Martin Davis + + + + Sets the sites (point or vertices) which will be triangulated. + All vertices of the given geometry will be used as sites. + The site vertices do not have to contain the constraint + vertices as well; any site vertices which are + identical to a constraint vertex will be removed + from the site vertex set. + + The geometry from which the sites will be extracted. + + + + Sets the linear constraints to be conformed to. + All linear components in the input will be used as constraints. + The constraint vertices do not have to be disjoint from + the site vertices. + The constraints must not contain duplicate segments (up to orientation). + + + + + Sets the snapping tolerance which will be used + to improved the robustness of the triangulation computation. + A tolerance of 0.0 specifies that no snapping will take place. + + + + + Gets the QuadEdgeSubdivision which models the computed triangulation. + + The subdivision containing the triangulation + + + + Gets the edges of the computed triangulation as a . + + The geometry factory to use to create the output + the edges of the triangulation + + + + Gets the faces of the computed triangulation as a + of . + + the geometry factory to use to create the output + the faces of the triangulation + + + + Computes a Conforming Delaunay Triangulation over a set of sites and a set of + linear constraints. + + + + A conforming Delaunay triangulation is a true Delaunay triangulation. In it + each constraint segment is present as a union of one or more triangulation + edges. Constraint segments may be subdivided into two or more triangulation + edges by the insertion of additional sites. The additional sites are called + Steiner points, and are necessary to allow the segments to be faithfully + reflected in the triangulation while maintaining the Delaunay property. + Another way of stating this is that in a conforming Delaunay triangulation + every constraint segment will be the union of a subset of the triangulation + edges (up to tolerance). + + + A Conforming Delaunay triangulation is distinct from a Constrained Delaunay triangulation. + A Constrained Delaunay triangulation is not necessarily fully Delaunay, + and it contains the constraint segments exactly as edges of the triangulation. + + + A typical usage pattern for the triangulator is: + + ConformingDelaunayTriangulator cdt = new ConformingDelaunayTriangulator(sites, tolerance); + + // optional + cdt.SplitPointFinder = splitPointFinder; + cdt.VertexFactory = vertexFactory; + + cdt.SetConstraints(segments, new List<Vertex>(vertexMap.Values)); + cdt.FormInitialDelaunay(); + cdt.EnforceConstraints(); + subdiv = cdt.Subdivision; + + + + David Skea + Martin Davis + + + + Creates a Conforming Delaunay Triangulation based on the given + unconstrained initial vertices. The initial vertex set should not contain + any vertices which appear in the constraint set. + + a collection of + the distance tolerance below which points are considered identical + + + + Sets the constraints to be conformed to by the computed triangulation. + The constraints must not contain duplicate segments (up to orientation). + The unique set of vertices (as es) + forming the constraints must also be supplied. + Supplying it explicitly allows the ConstraintVertexes to be initialized + appropriately (e.g. with external data), and avoids re-computing the unique set + if it is already available. + + list of the constraint s + the set of unique es referenced by the segments + + + + Gets or sets the to be + used during constraint enforcement. + Different splitting strategies may be appropriate + for special situations. + + the ConstraintSplitPointFinder to be used + + + + Gets the tolerance value used to construct the triangulation. + + a tolerance value + + + + Gets and sets the used to create new constraint vertices at split points. + + Allows the setting of a custom to be used + to allow vertices carrying extra information to be created. + + + + + Gets the which represents the triangulation. + + + + + Gets the which contains the vertices of the triangulation. + + + + + Gets the sites (vertices) used to initialize the triangulation. + + + + + Gets the s which represent the constraints. + + + + + Gets the convex hull of all the sites in the triangulation, + including constraint vertices. + Only valid after the constraints have been enforced. + + the convex hull of the sites + + + + Creates a vertex on a constraint segment + + the location of the vertex to create + the constraint segment it lies on + the new constraint vertex + + + + Inserts all sites in a collection + + a collection of ConstraintVertex + + + + Inserts a site into the triangulation, maintaining the conformal Delaunay property. + This can be used to further refine the triangulation if required + (e.g. to approximate the medial axis of the constraints, + or to improve the grading of the triangulation). + + the location of the site to insert + + + + Computes the Delaunay triangulation of the initial sites. + + + + + Enforces the supplied constraints into the triangulation. + + + if the constraints cannot be enforced + + + + Given a set of points stored in the kd-tree and a line segment defined by + two points in this set, finds a in the circumcircle of + the line segment, if one exists. This is called the Gabriel point - if none + exists then the segment is said to have the Gabriel condition. Uses the + heuristic of finding the non-Gabriel point closest to the midpoint of the + segment. + + the line segment + + A point which is non-Gabriel, + or null if no point is non-Gabriel + + + + + Indicates a failure during constraint enforcement. + + Martin Davis + 1.0 + + + + Creates a new instance with a given message. + + a string + + + + Creates a new instance with a given message and approximate location. + + a string + the location of the error + + + + Gets the approximate location of this error. + + a location + + + + A vertex in a Constrained Delaunay Triangulation. + The vertex may or may not lie on a constraint. + If it does it may carry extra information about the original constraint. + + Martin Davis + + + + Creates a new constraint vertex + + the location of the vertex + + + + Gets or sets whether this vertex lies on a constraint. + + true if the vertex lies on a constraint + + + + Gets or sets the external constraint object + + object which carries information about the constraint this vertex lies on + + + + Merges the constraint data in the vertex other into this vertex. + This method is called when an inserted vertex is + very close to an existing vertex in the triangulation. + + the constraint vertex to merge + + + + An interface for factories which create a + + Martin Davis + + + + A utility class which creates Delaunay Triangulations + from collections of points and extract the resulting + triangulation edges or triangles as geometries. + + Martin Davis + + + + Extracts the unique s from the given . + + the geometry to extract from + a List of the unique Coordinates + + + + Converts all s in a collection to es. + + the coordinates to convert + a List of Vertex objects + + + + Computes the of a collection of s. + + a List of Coordinates + the envelope of the set of coordinates + + + + Sets the sites (vertices) which will be triangulated. + All vertices of the given geometry will be used as sites. + + the geometry from which the sites will be extracted. + + + + Sets the sites (vertices) which will be triangulated + from a collection of s. + + a collection of Coordinates. + + + + Sets the snapping tolerance which will be used + to improved the robustness of the triangulation computation. + A tolerance of 0.0 specifies that no snapping will take place. + + + + + Gets the which models the computed triangulation. + + the subdivision containing the triangulation + + + + Gets the edges of the computed triangulation as a . + + the geometry factory to use to create the output + the edges of the triangulation + + + + Gets the faces of the computed triangulation as a + of . + + the geometry factory to use to create the output + the faces of the triangulation + + + + An interface for strategies for determining the location of split points on constraint segments. + The location of split points has a large effect on the performance and robustness of enforcing a + constrained Delaunay triangulation. Poorly chosen split points can cause repeated splitting, + especially at narrow constraint angles, since the split point will end up encroaching on the + segment containing the original encroaching point. With detailed knowledge of the geometry of the + constraints, it is sometimes possible to choose better locations for splitting. + + mbdavis + + + + Finds a point at which to split an encroached segment to allow the original segment to appear + as edges in a constrained Delaunay triangulation. + + the encroached segment + the encroaching point + the point at which to split the encroached segment + + + + Computes a Delaunay Triangulation of a set of es, using an + incremental insertion algorithm. + + Martin Davis + 1.0 + + + + Creates a new triangulator using the given . + The triangulator uses the tolerance of the supplied subdivision. + + a subdivision in which to build the TIN + + + + Inserts all sites in a collection. The inserted vertices MUST be + unique up to the provided tolerance value. (i.e. no two vertices should be + closer than the provided tolerance value). They do not have to be rounded + to the tolerance grid, however. + + a Collection of Vertex + if the location algorithm fails to converge in a reasonable number of iterations + + + + Inserts a new point into a subdivision representing a Delaunay + triangulation, and fixes the affected edges so that the result is still a + Delaunay triangulation. + + a quadedge containing the inserted vertex + + + + A simple split point finder which returns the midpoint of the split segment. This is a default + strategy only. Usually a more sophisticated strategy is required to prevent repeated splitting. + Other points which could be used are: +
    +
  • The projection of the encroaching point on the segment
  • +
  • A point on the segment which will produce two segments which will not be further encroached
  • +
  • The point on the segment which is the same distance from an endpoint as the encroaching
  • + point +
+
+ Martin Davis +
+ + + Gets the midpoint of the split segment + + + + + A strategy for finding constraint split points which attempts to maximise the length of the split + segments while preventing further encroachment. (This is not always possible for narrow angles). + + Martin Davis + + + + A basic strategy for finding split points when nothing extra is known about the geometry of + the situation. + + the encroached segment + the encroaching point + the point at which to split the encroached segment + + + + Computes a split point which is the projection of the encroaching point on the segment + + The segment + The enchroaching point + A split point on the segment + + + + Computes the Constrained Delaunay Triangulation of polygons. + The Constrained Delaunay Triangulation of a polygon is a set of triangles + covering the polygon, with the maximum total interior angle over all + possible triangulations. It provides the "best quality" triangulation + of the polygon. + + Holes are supported. + + Martin Davis + + + + Computes the Constrained Delaunay Triangulation of each polygon element in a geometry. + + The input geometry + A GeometryCollection of the computed triangle polygons + + + + Constructs a new Constrained Delaunay triangulator. + + The input geometry + + + + Gets the triangulation as a of triangular s. + + A collection of the result triangle polygons + + + + Gets the triangulation as a list of s. + + The list of Tris in the triangulation + + + + Computes the triangulation of a single polygon + and returns it as a list of s. + + The input polygon + A list of Tris forming the triangulation + + + + Triangulates a polygon using the Ear-Clipping technique. + The polygon is provided as a closed list of contiguous vertices + defining its boundary. + The vertices must have clockwise orientation. + + The polygon boundary must not self-cross, + but may self-touch at points or along an edge. + It may contain repeated points, which are treated as a single vertex. + By default every vertex is triangulated, + including ones which are "flat" (the adjacent segments are collinear). + These can be removed by setting . + + The polygon representation does not allow holes. + Polygons with holes can be triangulated by preparing them with . + + Martin Davis + + + + Triangulates a polygon via ear-clipping. + + The vertices of the polygon + A list of Tris + + + + The polygon vertices are provided in CW orientation. + Thus for convex interior angles + the vertices forming the angle are in CW orientation. + + + + + Indexing vertices improves ear intersection testing performance. + The polyShell vertices are contiguous, so are suitable for an SPRtree. + Note that a KDtree cannot be used because the vertex indices must be stored + and duplicates must be stored. + + + + + Creates a new instance of this class + + The vertices of the polygon to process + + + + Gets or sets whether flat corners formed by collinear adjacent line segments + are included in the triangulation. + Skipping flat corners reduces the number of triangles in the output. + However, it produces a triangulation which does not include + all input vertices. This may be undesirable for downstream processes + (such as computing a Constrained Delaunay Triangulation for + purposes of computing the medial axis). + + The default is to include all vertices in the result triangulation. + This still produces a valid triangulation, with no zero-area triangles. + + Note that repeated vertices are always skipped. + + A flag indicating if flat corners formed by collinear adjacent line segments + are included in the triangulation + + + + Finds a vertex contained in the corner triangle, if any. + Uses the vertex spatial index for efficiency. + + Also finds any vertex which is a duplicate of the corner apex vertex. + This requires a full scan of the vertices to confirm ear is valid. + This is usually a rare situation, so has little impact on performance. + + The index of the corner apex vertex + The corner vertices + The index of an intersecting or duplicate vertex, or if none + + + + Scan all vertices in current ring to check if any are duplicates + of the corner apex vertex, and if so whether the corner ear + intersects the adjacent segments and thus is invalid. + + The index of the corner apex + The corner vertices + true if the corner ia a valid ear + + + + Remove the corner apex vertex and update the candidate corner location. + + + + + Fetch the corner vertices from the indices. + + An array for the corner vertices + + + + Move to next corner. + + + + + Get the index of the next available shell coordinate starting from the given index. + + Coordinate position + Index of the next available shell coordinate + + + + Detects if a corner has repeated points (AAB or ABB), or is collapsed (ABA). + + The corner points + true if the corner is flat or collapsed + + + + Transforms a polygon with holes into a single self-touching (invalid) ring + by connecting holes to the exterior shell or to another hole. + The holes are added from the lowest upwards. + As the resulting shell develops, a hole might be added to what was + originally another hole. + + There is no attempt to optimize the quality of the join lines. + In particular, a hole which already touches at a vertex may be + joined at a different vertex. + + + + + Computes the joined ring. + + The points in the joined ring + + + + Adds a coordinate to the set and + clears the array. + + A coordinate + + + + Joins a single hole to the current shellRing. + + The hole to join + + + + Get the i'th in that the current should add after + + The coordinate of the shell vertex + The coordinate of the hole vertex + The i'th shellvertex + + + + Find the index of the coordinate in ShellCoords ArrayList, + skipping over some number of matches + + + + + + + + Gets a list of shell vertices that could be used to join with the hole. + This list contains only one item if the chosen vertex does not share the same + x value with + + The hole coordinate + A list of candidate join vertices + + + + Determine if a line segment between a hole vertex + and a shell vertex lies inside the input polygon. + + A hole coordinate + A shell coordinate + true if the line lies inside the polygon + + + + Tests whether a line segment crosses the polygon boundary. + + A vertex + A vertex + true if the line segment crosses the polygon boundary + + + + Add hole at proper position in shell coordinate list. + Also adds hole points to ordered coordinates. + + + + + + + + Sort the holes by minimum X, minimum Y. + + Polygon that contains the holes + A list of ordered hole geometry + + + + Gets a list of indices of the leftmost vertices in a ring. + + The hole ring + Index of the left most vertex + + + + Computes a triangulation of each polygon in a {@link Geometry}. + A polygon triangulation is a non-overlapping set of triangles which + cover the polygon and have the same vertices as the polygon. + The priority is on performance rather than triangulation quality, + so that the output may contain many narrow triangles. + + Holes are handled by joining them to the shell to form a + (self-touching) polygon shell with no holes. + Although invalid, this can be triangulated effectively. + + For better-quality triangulation use . + + + Martin Davis + + + + Computes a triangulation of each polygon in a geometry. + + A geometry containing polygons + A GeometryCollection containing the polygons + + + + Constructs a new triangulator. + + The input geometry + + + + Gets the triangulation as a of triangular s. + + A collection of the result triangle polygons + + + + Gets the triangulation as a list of s. + + The list of Tris in the triangulation + + + + Computes the triangulation of a single polygon + + A list of triangular polygons + + + + Improves the quality of a triangulation of s via + iterated Delaunay flipping. + This produces a Constrained Delaunay Triangulation + with the constraints being the boundary of the input triangulation. + + Martin Davis + + + + Improves the quality of a triangulation of {@link Tri}s via + iterated Delaunay flipping. + The Tris are assumed to be linked into a Triangulation + (e.g. via ). + + The list of Tris to improve + + + Improves a triangulation by examining pairs of adjacent triangles + (forming a quadrilateral) and testing if flipping the diagonal of + the quadrilateral would produce two new triangles with larger minimum + interior angles. + + The number of flips that were made + + + + Does a flip of the common edge of two Tris if the Delaunay condition is not met. + + A Tri + The index of the + true if the triangles were flipped + + + + Tests if the quadrilateral formed by two adjacent triangles is convex. + opp0-adj0-adj1 and opp1-adj1-adj0 are the triangle corners + and hence are known to be convex. + The quadrilateral is convex if the other corners opp0-adj0-opp1 + and opp1-adj1-opp0 have the same orientation (since at least one must be convex). + + The adjacent edge vertex 0 + The adjacent edge vertex 1 + The corner vertex of triangle 0 + The corner vertex of triangle 1 + true if the quadrilateral is convex + + + + Tests if either of a pair of adjacent triangles satisfy the Delaunay condition. + The triangles are opp0-adj0-adj1 and opp1-adj1-adj0. + The Delaunay condition is not met if one opposite vertex + lies is in the circumcircle of the other triangle. + + The adjacent edge vertex 0 + The adjacent edge vertex 1 + The corner vertex of triangle 0 + The corner vertex of triangle 1 + true if the triangles are Delaunay + + + + Tests whether a point p is in the circumcircle of a triangle abc + (oriented clockwise). + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point + true if the point is in the circumcircle + + + + A semi-static spatial index for points which occur + in a spatially-coherent sequence. + In particular, this is suitable for indexing the vertices + of a {@link LineString} or {@link Polygon} ring. + + The index is constructed in a batch fashion on a given sequence of coordinates. + Coordinates can be removed via the {@link #remove(int)} method. + + Note that this index queries only the individual points + of the input coordinate sequence, + not any line segments which might be lie between them. + + Martin Davis + + + + Number of items/nodes in a parent node. + Determined empirically. Performance is not too sensitive to this. + + + + + Creates a new tree over the given sequence of coordinates. + The sequence should be spatially coherent to provide query performance. + + A sequence of points + + + + Computes the level offsets. + This is the position in the bounds array of each level. + The levelOffsets array includes a sentinel value of offset[0] = 0. + The top level is always of size 1, + and so also indicates the total number of bounds. + + The level offsets + + + + Queries the index to find all items which intersect an extent. + The query result is a list of the indices of input coordinates + which intersect the extent. + + The query extent + An array of the indices of the input coordinates + + + + Removes the input item at the given index from the spatial index. + + Index the index of the item in the input + + + + A framework to visit sets of edge-connected s in breadth-first order + + Martin Davis + 1.0 + + + + Called to initialize the traversal queue with a given set of s + + a collection of QuadEdgeTriangle + + + + Subclasses call this method to perform the visiting process. + + + + + An interface for classes which locate an edge in a + which either contains a given V + or is an edge of a triangle which contains V. + Implementors may utilized different strategies for + optimizing locating containing edges/triangles. + + Martin Davis + + + + Interface for classes which process triangles visited during traversals of a + + + Martin Davis + + + + Visits a triangle during a traversal of a . An implementation of + this method may perform processing on the current triangle. It must also decide whether a + neighbouring triangle should be added to the queue so its neighbours are visited. Often it + will perform processing on the neighbour triangle as well, in order to mark it as processed + (visited) and/or to determine if it should be visited. Note that choosing not to + visit the neighbouring triangle is the terminating condition for many traversal algorithms. + In particular, if the neighbour triangle has already been visited, it should not be visited + again. + + the current triangle being processed + the index of the edge in the current triangle being traversed + a neighbouring triangle next in line to visit + true if the neighbour triangle should be visited + + + + An interface for algorithms which process the triangles in a . + + Martin Davis + 1.0 + + + + Visits the s of a triangle. + + an array of the 3 quad edges in a triangle (in CCW order) + + + + Locates s in a , + optimizing the search by starting in the + locality of the last edge found. + + Martin Davis + + + + Locates an edge e, such that either v is on e, or e is an edge of a triangle containing v. + The search starts from the last located edge and proceeds on the general direction of v. + + + + + A class that represents the edge data structure which implements the quadedge algebra. + The quadedge algebra was described in a well-known paper by Guibas and Stolfi, + "Primitives for the manipulation of general subdivisions and the computation of Voronoi diagrams", + ACM Transactions on Graphics, 4(2), 1985, 75-123. + + Each edge object is part of a quartet of 4 edges, + linked via their Rot references. + Any edge in the group may be accessed using a series of operations. + Quadedges in a subdivision are linked together via their Next references. + The linkage between the quadedge quartets determines the topology + of the subdivision. + + + The edge class does not contain separate information for vertices or faces; a vertex is implicitly + defined as a ring of edges (created using the Next field). + + + David Skea + Martin Davis + + + + Creates a new QuadEdge quartet from o to d. + + the origin Vertex + the destination Vertex + the new QuadEdge quartet + + + + Creates a new QuadEdge connecting the destination of a to the origin of + b, in such a way that all three have the same left face after the + connection is complete. Additionally, the data pointers of the new edge + are set. + + the connected edge + + + + Splices two edges together or apart. + Splice affects the two edge rings around the origins of a and b, and, independently, the two + edge rings around the left faces of a and b. + In each case, (i) if the two rings are distinct, + Splice will combine them into one, or (ii) if the two are the same ring, Splice will break it + into two separate pieces. Thus, Splice can be used both to attach the two edges together, and + to break them apart. + + an edge to splice + an edge to splice + + + + Turns an edge counterclockwise inside its enclosing quadrilateral. + + the quadedge to turn + + + + Quadedges must be made using {@link makeEdge}, + to ensure proper construction. + + + + + Gets the primary edge of this quadedge and its sym. + The primary edge is the one for which the origin + and destination coordinates are ordered + according to the standard ordering + + the primary quadedge + + + + Gets or sets the external data value for this edge. + + + an object containing external data + + + + + Marks this quadedge as being deleted. + This does not free the memory used by + this quadedge quartet, but indicates + that this edge no longer participates + in a subdivision. + + + + + Tests whether this edge has been deleted. + + true if this edge has not been deleted. + + + + Sets the connected edge + + edge + + + + Gets the dual of this edge, directed from its right to its left. + + Gets or Sets the rotated edge + + + + Gets the dual of this edge, directed from its left to its right. + + Gets the inverse rotated edge. + + + + Gets the edge from the destination to the origin of this edge. + + Gets the sym of the edge. + + + + Gets the next CCW edge around the origin of this edge. + + Gets the next linked edge. + + + + Gets the next CW edge around (from) the origin of this edge. + + Gets the previous edge. + + + + Gets the next CCW edge around (into) the destination of this edge. + + Get the next destination edge. + + + + Gets the next CW edge around (into) the destination of this edge. + + Get the previous destination edge. + + + + Gets the CCW edge around the left face following this edge. + + Gets the next left face edge. + + + + Gets the CCW edge around the left face before this edge. + + Get the previous left face edge. + + + + Gets the edge around the right face ccw following this edge. + + Gets the next right face edge. + + + + Gets the edge around the right face ccw before this edge. + + Gets the previous right face edge. + + + + Gets or sets the vertex for the edge's origin + + Gets the origin vertex + + + + Gets or sets the vertex for the edge's destination + + Gets the destination vertex + + + + Gets the length of the geometry of this quadedge. + + Gets the length of the quadedge + + + + Tests if this quadedge and another have the same line segment geometry, + regardless of orientation. + + a quadedge + true if the quadedges are based on the same line segment regardless of orientation + + + + Tests if this quadedge and another have the same line segment geometry + with the same orientation. + + a quadedge + true if the quadedges are based on the same line segment + + + + Creates a representing the + geometry of this edge. + + a LineSegment + + + + Converts this edge to a WKT two-point LINESTRING indicating + the geometry of this edge. + + a String representing this edge's geometry + + + + A class that contains the s representing a planar + subdivision that models a triangulation. + The subdivision is constructed using the + quadedge algebra defined in the class . + All metric calculations + are done in the class. + In addition to a triangulation, subdivisions + support extraction of Voronoi diagrams. + This is easily accomplished, since the Voronoi diagram is the dual + of the Delaunay triangulation. + + Subdivisions can be provided with a tolerance value. Inserted vertices which + are closer than this value to vertices already in the subdivision will be + ignored. Using a suitable tolerance value can prevent robustness failures + from happening during Delaunay triangulation. + + + Subdivisions maintain a frame triangle around the client-created + edges. The frame is used to provide a bounded "container" for all edges + within a TIN. Normally the frame edges, frame connecting edges, and frame + triangles are not included in client processing. + + + David Skea + Martin Davis + + + + Gets the edges for the triangle to the left of the given . + + + + if the edges do not form a triangle + + + + Creates a new instance of a quad-edge subdivision based on a frame triangle + that encloses a supplied bounding box. A new super-bounding box that + contains the triangle is computed and stored. + + the bounding box to surround + the tolerance value for determining if two sites are equal + + + + Gets the vertex-equality tolerance value + used in this subdivision + + Gets the tolerance value + + + + Gets the envelope of the Subdivision (including the frame). + + Gets the envelope + + + + Gets the collection of base s (one for every pair of + vertices which is connected). + + a collection of QuadEdges + + + + Sets the to use for locating containing triangles + in this subdivision. + + a QuadEdgeLocator + + + + Creates a new quadedge, recording it in the edges list. + + The origin vertex + The destination vertex + A new quadedge + + + + Creates a new QuadEdge connecting the destination of a to the origin of b, + in such a way that all three have the same left face after the connection + is complete. The quadedge is recorded in the edges list. + + A quadedge + A quadedge + A quadedge + + + + Deletes a quadedge from the subdivision. Linked quadedges are updated to + reflect the deletion. + + the quadedge to delete + + + + Locates an edge of a triangle which contains a location + specified by a Vertex v. + The edge returned has the + property that either v is on e, or e is an edge of a triangle containing v. + The search starts from startEdge amd proceeds on the general direction of v. + + + This locate algorithm relies on the subdivision being Delaunay. For + non-Delaunay subdivisions, this may loop for ever. + + the location to search for + an edge of the subdivision to start searching at + a QuadEdge which contains v, or is on the edge of a triangle containing v + + if the location algorithm fails to converge in a reasonable + number of iterations + + + + + Finds a quadedge of a triangle containing a location + specified by a , if one exists. + + the vertex to locate + a quadedge on the edge of a triangle which touches or contains the location
+ or null if no such triangle exists +
+
+ + + Finds a quadedge of a triangle containing a location + specified by a , if one exists. + + the Coordinate to locate + a quadedge on the edge of a triangle which touches or contains the location, + or null if no such triangle exists + + + + + Locates the edge between the given vertices, if it exists in the + subdivision. + + a coordinate + another coordinate + the edge joining the coordinates, if present, + or null if no such edge exists + + + + + Inserts a new site into the Subdivision, connecting it to the vertices of + the containing triangle (or quadrilateral, if the split point falls on an + existing edge). + + + + This method does NOT maintain the Delaunay condition. If desired, this must + be checked and enforced by the caller. + + + This method does NOT check if the inserted vertex falls on an edge. This + must be checked by the caller, since this situation may cause erroneous + triangulation + + + the vertex to insert + a new quad edge terminating in v + + + + Tests whether a QuadEdge is an edge incident on a frame triangle vertex. + + the edge to test + true if the edge is connected to the frame triangle + + + + Tests whether a QuadEdge is an edge on the border of the frame facets and + the internal facets. E.g. an edge which does not itself touch a frame + vertex, but which touches an edge which does. + + the edge to test + true if the edge is on the border of the frame + + + + Tests whether a vertex is a vertex of the outer triangle. + + the vertex to test + true if the vertex is an outer triangle vertex + + + + Tests whether a {@link Coordinate} lies on a {@link QuadEdge}, up to a + tolerance determined by the subdivision tolerance. + + a QuadEdge + a point + true if the vertex lies on the edge + + + + Tests whether a is the start or end vertex of a + , up to the subdivision tolerance distance. + + + + true if the vertex is a endpoint of the edge + + + + Gets the unique es in the subdivision, + including the frame vertices if desired. + + true if the frame vertices should be included + a collection of the subdivision vertices + + + + + Gets a collection of s whose origin + vertices are a unique set which includes + all vertices in the subdivision. + The frame vertices can be included if required. + + + This is useful for algorithms which require traversing the + subdivision starting at all vertices. + Returning a quadedge for each vertex + is more efficient than + the alternative of finding the actual vertices + using and then locating + quadedges attached to them. + + true if the frame vertices should be included + a collection of QuadEdge with the vertices of the subdivision as their origins + + + + Gets all primary quadedges in the subdivision. + A primary edge is a + which occupies the 0'th position in its array of associated quadedges. + These provide the unique geometric edges of the triangulation. + + true if the frame edges are to be included + a List of QuadEdges + + + + A TriangleVisitor which computes and sets the + circumcentre as the origin of the dual + edges originating in each triangle. + + mbdavis + + + + The quadedges forming a single triangle. + Only one visitor is allowed to be active at a + time, so this is safe. + + + + + Stores the edges for a visited triangle. Also pushes sym (neighbour) edges + on stack to visit later. + + + + + + the visited triangle edges,
+ or null if the triangle should not be visited (for instance, if it is outer) +
+
+ + + Gets a list of the triangles + in the subdivision, specified as + an array of the primary quadedges around the triangle. + + true if the frame triangles should be included + a List of QuadEdge[3] arrays + + + + Gets a list of the triangles in the subdivision, + specified as an array of the triangle es. + + true if the frame triangles should be included + a List of Vertex[3] arrays + + + + Gets the coordinates for each triangle in the subdivision as an array. + + true if the frame triangles should be included + a list of Coordinate[4] representing each triangle + + + + Gets the geometry for the edges in the subdivision as a + containing 2-point lines. + + the GeometryFactory to use + a MultiLineString + + + + Gets the geometry for the triangles in a triangulated subdivision as a + of triangular s. + + the GeometryFactory to use + a GeometryCollection of triangular Polygons + + + + Gets the cells in the Voronoi diagram for this triangulation. + The cells are returned as a of s + + + The userData of each polygon is set to be the + of the cell site. This allows easily associating external + data associated with the sites to the cells. + + a geometry factory + a GeometryCollection of Polygons + + + + Gets a List of s for the Voronoi cells + of this triangulation. + + + The UserData of each polygon is set to be the + of the cell site. This allows easily associating external + data associated with the sites to the cells. + + a geometry factory + a List of Polygons + + + + Gets the Voronoi cell around a site specified + by the origin of a QuadEdge. + + + The userData of the polygon is set to be the + of the site. This allows attaching external + data associated with the site to this cell polygon. + + a quadedge originating at the cell site + a factory for building the polygon + a polygon indicating the cell extent + + + + Models a triangle formed from s in a + which forms a triangulation. The class provides methods to access the + topological and geometric properties of the triangle and its neighbours in + the triangulation. Triangle vertices are ordered in CCW orientation in the + structure. + + + QuadEdgeTriangles support having an external data attribute attached to them. + Alternatively, this class can be subclassed and attributes can + be defined in the subclass. Subclasses will need to define + their own BuilderVisitor class + and CreateOn method. + + Martin Davis + 1.0 + + + + Creates s for all facets of a + representing a triangulation. + The data attributes of the s in the subdivision + will be set to point to the triangle which contains that edge. + This allows tracing the neighbour triangles of any given triangle. + + The QuadEdgeSubdivision to create the triangles on. + A List of the created QuadEdgeTriangles + + + + Tests whether the point pt is contained in the triangle defined by 3 es. + + an array containing at least 3 Vertexes + the point to test + true if the point is contained in the triangle + + + + Tests whether the point pt is contained in the triangle defined by 3 es. + + an array containing at least 3 QuadEdges + the point to test + true if the point is contained in the triangle + + + + Creates a new triangle from the given edges. + + An array of the edges of the triangle in CCW order + + + + Gets or sets the external data value for this triangle. + + + + + Gets the vertices for this triangle. + + a new array containing the triangle vertices + + + + Gets the index for the given edge of this triangle + + a QuadEdge + the index of the edge in this triangle,
+ or -1 if the edge is not an edge of this triangle +
+
+ + + Gets the index for the edge that starts at vertex v. + + the vertex to find the edge for + the index of the edge starting at the vertex,
+ or -1 if the vertex is not in the triangle +
+
+ + + + + + Tests whether this triangle is adjacent to the outside of the subdivision. + + true if the triangle is adjacent to the subdivision exterior + + + + Gets the triangles which are adjacent (include) to a + given vertex of this triangle. + + The vertex to query + A list of the vertex-adjacent triangles + + + + Gets the neighbours of this triangle. If there is no neighbour triangle, the array element is + null + + an array containing the 3 neighbours of this triangle + + + + Gets all edges which are incident on the origin of the given edge. + + the edge to start at + a List of edges which have their origin at the origin of the given + edge + + + + Algorithms for computing values and predicates + associated with triangles. + + + For some algorithms extended-precision + implementations are provided, which are more robust + (i.e. they produce correct answers in more cases). + Also, some more robust formulations of + some algorithms are provided, which utilize + normalization to the origin. + + Martin Davis + + + + Tests if a point is inside the circle defined by + the triangle with vertices a, b, c (oriented counter-clockwise). + This test uses simple + double-precision arithmetic, and thus is not 100% robust. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point to test + true if this point is inside the circle defined by the points a, b, c + + + + Tests if a point is inside the circle defined by + the triangle with vertices a, b, c (oriented counter-clockwise). + + + This test uses simple + double-precision arithmetic, and thus is not 100% robust. + However, by using normalization to the origin + it provides improved robustness and increased performance. + Based on code by J.R.Shewchuk. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point to test + true if this point is inside the circle defined by the points a, b, c + + + + Computes twice the area of the oriented triangle (a, b, c), i.e., the area is positive if the + triangle is oriented counterclockwise. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The area of the triangle defined by the points a, b, c + + + + Tests if a point is inside the circle defined by + the triangle with vertices a, b, c (oriented counter-clockwise). + + + This method uses more robust computation. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point to test + true if this point is inside the circle defined by the points a, b, c + + + + Tests if a point is inside the circle defined by + the triangle with vertices a, b, c (oriented counter-clockwise). + + + The computation uses arithmetic for robustness, but a faster approach. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point to test + true if this point is inside the circle defined by the points a, b, c + + + + Computes twice the area of the oriented triangle (a, b, c), i.e., the area + is positive if the triangle is oriented counterclockwise. + + + The computation uses {@link DD} arithmetic for robustness. + + a vertex of the triangle + a vertex of the triangle + a vertex of the triangle + The area of a triangle defined by the points a, b and c + + + + + + + + + + + + + + Computes the inCircle test using distance from the circumcentre. + Uses standard double-precision arithmetic. + + + In general this doesn't + appear to be any more robust than the standard calculation. However, there + is at least one case where the test point is far enough from the + circumcircle that this test gives the correct answer. +
+            LINESTRING (1507029.9878 518325.7547, 1507022.1120341457 518332.8225183258,
+            1507029.9833 518325.7458, 1507029.9896965567 518325.744909031)
+            
+
+ A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + The point to test + The area of a triangle defined by the points a, b and c +
+ + + Models a site (node) in a . + The sites can be points on a line string representing a + linear site. + The vertex can be considered as a vector with a norm, length, inner product, cross + product, etc. Additionally, point relations (e.g., is a point to the left of a line, the circle + defined by this point and two others, etc.) are also defined in this class. + + It is common to want to attach user-defined data to + the vertices of a subdivision. + One way to do this is to subclass Vertex + to carry any desired information. + + David Skea + Martin Davis + + + + Creates an instance of this class using the given x- and y-ordinate valuse + + x-ordinate value + y-ordinate value + + + + Creates an instance of this class using the given x-, y- and z-ordinate values + + x-ordinate value + y-ordinate value + z-ordinate value + + + + Creates an instance of this class using a clone of the given . + + The coordinate + + + + Gets the x-ordinate value + + + + + Gets the y-ordinate value + + + + + Gets the z-ordinate value + + + + + Gets the coordinate + + + + + + + + Computes the cross product k = u X v. + + a vertex + returns the magnitude of u X v + + + + Computes the inner or dot product + + A vertex + The dot product u.v + + + + Computes the scalar product c(v) + + A vertex + The scaled vector + + + + Tests if this is inside the circle defined by the points a, b, c. This test uses simple + double-precision arithmetic, and thus may not be robust. + + A vertex of the triangle + A vertex of the triangle + A vertex of the triangle + true if this vertex is inside the circumcircle (a, b, c) + + + + Tests whether the triangle formed by this vertex and two + other vertices is in CCW orientation. + + a vertex + a vertex + true if the triangle is oriented CCW + + + + Computes the value of the ratio of the circumradius to shortest edge. If smaller than some + given tolerance B, the associated triangle is considered skinny. For an equal lateral + triangle this value is 0.57735. The ratio is related to the minimum triangle angle theta by: + circumRadius/shortestEdge = 1/(2sin(theta)). + + second vertex of the triangle + third vertex of the triangle + ratio of circumradius to shortest edge. + + + + returns a new vertex that is mid-way between this vertex and another end point. + + the other end point. + the point mid-way between this and that. + + + + Computes the centre of the circumcircle of this vertex and two others. + + + + the Coordinate which is the circumcircle of the 3 points. + + + + For this vertex enclosed in a triangle defined by three vertices v0, v1 and v2, interpolate + a z value from the surrounding vertices. + + + + + Interpolates the Z-value (height) of a point enclosed in a triangle + whose vertices all have Z values. + The containing triangle must not be degenerate + (in other words, the three vertices must enclose a + non-zero area). + + The point to interpolate the Z value of + A vertex of a triangle containing the + A vertex of a triangle containing the + A vertex of a triangle containing the + The interpolated Z-value (height) of the point + + + + Computes the interpolated Z-value for a point p lying on the segment p0-p1 + + The point to interpolate the Z value of + A vertex of the segment is lying on + A vertex of the segment is lying on + The interpolated Z-value (height) of the point + + + + Models a constraint segment in a triangulation. + A constraint segment is an oriented straight line segment between a start point + and an end point. + + David Skea + Martin Davis + + + + + Creates a new instance for the given ordinates. + + + + + Creates a new instance for the given ordinates, with associated external data. + + + + + Creates a new instance for the given points, with associated external data. + + the start point + the end point + an external data object + + + + Creates a new instance for the given points. + + the start point + the end point + + + + Gets the start coordinate of the segment + + a Coordinate + + + + Gets the end coordinate of the segment + + a Coordinate + + + + Gets the start X ordinate of the segment + + the X ordinate value + + + + Gets the start Y ordinate of the segment + + the Y ordinate value + + + + Gets the start Z ordinate of the segment + + the Z ordinate value + + + + Gets the end X ordinate of the segment + + the X ordinate value + + + + Gets the end Y ordinate of the segment + + he Y ordinate value + + + + Gets the end Z ordinate of the segment + + the Z ordinate value + + + + Gets a LineSegment modelling this segment. + + a LineSegment + + + + Gets or sets the external data associated with this segment + + a data object + + + + Determines whether two segments are topologically equal. + I.e. equal up to orientation. + + a segment + true if the segments are topologically equal + + + + Computes the intersection point between this segment and another one. + + a segment + the intersection point, or null if there is none + + + + Computes a string representation of this segment. + + a string + + + + Models a constraint segment which can be split in two in various ways, + according to certain geometric constraints. + + Martin Davis + + + + Computes the {@link Coordinate} that lies a given fraction along the line defined by the + reverse of the given segment. A fraction of 0.0 returns the end point of the + segment; a fraction of 1.0 returns the start point of the segment. + + the LineSegment + the fraction of the segment length along the line + the point at that distance + + + + A memory-efficient representation of a triangle in a triangulation. + Contains three vertices, and links to adjacent Tris for each edge. + Tris are constructed independently, and if needed linked + into a triangulation using . + + An edge of a Tri in a triangulation is called a boundary edge + if it has no adjacent triangle.
+ The set of Tris containing boundary edges are called the triangulation border. +
+ Martin Davis +
+ + + Creates a of s + representing the triangles in a list. + + A list of Tris + The GeometryFactory to use + The Polygons for the triangles + + + + Computes the area of a set of Tris. + + A set of tris + The total area of the triangles + + + + Validates a list of Tris. + + The list of Tris to validate + + + + Creates a triangle with the given vertices. + The vertices should be oriented clockwise. + + The first triangle vertex + The second triangle vertex + The third triangle vertex + The created trianlge + + + + Creates a triangle from an array with three vertex coordinates. + The vertices should be oriented clockwise. + + The array of vertex coordinates + The created triangle + + + + Creates a triangle with the given vertices. + The vertices should be oriented clockwise. + + The first triangle vertex + The second triangle vertex + The third triangle vertex + + + + Sets the adjacent triangles.
+ The vertices of the adjacent triangles are + assumed to match the appropriate vertices in this triangle. +
+ The triangle adjacent to edge 0 + The triangle adjacent to edge 1 + The triangle adjacent to edge 2 +
+ + + Sets the triangle adjacent to the edge originating + at a given vertex.
+ The vertices of the adjacent triangles are + assumed to match the appropriate vertices in this triangle. +
+ The edge start point + The adjacent triangle +
+ + + Sets the triangle adjacent to an edge.
+ The vertices of the adjacent triangle are + assumed to match the appropriate vertices in this triangle. +
+ The edge triangle is adjacent to + The adjacent triangle +
+ + + Splits a triangle by a point located inside the triangle. + Creates the three new resulting triangles with adjacent links + set correctly. + Returns the new triangle whose 0'th vertex is the splitting point. + + The point to insert + The new triangle whose 0'th vertex is + + + + Interchanges the vertices of this triangle and a neighbor + so that their common edge + becomes the the other diagonal of the quadrilateral they form. + Neighbour triangle links are modified accordingly. + + The index of the adjacent tri to flip with + + + + Replaces an adjacent triangle with a different one. + + An adjacent triangle + The triangle to replace with + + + + Computes the degree of a Tri vertex, which is the number of tris containing it. + This must be done by searching the entire triangulation, + since the containing tris may not be adjacent or edge-connected. + + The vertex index + The triangulation + The degree of the vertex + + + + Removes this tri from the triangulation containing it. + All links between the tri and adjacent ones are nulled. + + The triangulation + + + + Removes this triangle from a triangulation. + All adjacent references and the references to this + Tri in the adjacent Tris are set to null. + + + + + Gets the triangles adjacent to the quadrilateral + formed by this triangle and an adjacent one. + The triangles are returned in the following order: + + Order: + + opp0-adj0 edge + opp0-adj1 edge + opp1-adj0 edge + opp1-adj1 edge + + + An adjacent triangle + The index of the common edge in this triangle + The index of the common edge in the adjacent triangle + + + + + Validates that a is correct. + Currently just checks that orientation is CW. + + Thrown if is not valid + + + + Validates that the vertices of an adjacent linked triangle are correct. + + The index of the adjacent triangle + + + + Gets the coordinate for a vertex. + This is the start vertex of the edge. + + The vertex (edge) index + The vertex coordinate + + + + Gets the index of the triangle vertex which has a given coordinate (if any). + This is also the index of the edge which originates at the vertex. + + The coordinate to find + The vertex index, or -1 if it is not in the triangle + + + + Gets the edge index which a triangle is adjacent to (if any), + based on the adjacent triangle link. + + The Tri to find + The index of the edge adjacent to the triangle, or -1 if not found + + + + Gets the triangle adjacent to an edge. + + The edge index + The adjacent triangle (may be null) + + + + Tests if this tri has any adjacent tris. + + true if there is at least one adjacent tri + + + + Tests if there is an adjacent triangle to an edge. + + The edge index + true if there is a triangle adjacent to edge + + + + Tests if a triangle is adjacent to some edge of this triangle. + + The triangle to test + true if the triangle is adjacent + + + + + Computes the number of triangle adjacent to this triangle. + This is a number in the range [0,2]. + The number of adjacent triangles + + + + Tests if a tri vertex is interior. + A vertex of a triangle is interior if it + is fully surrounded by other triangles. + + The vertex index + true if the vertex is interior + + + + Tests if a tri contains a boundary edge, + and thus on the border of the triangulation containing it. + + true if the tri is on the border of the triangulation + + + + Tests if an edge is on the boundary of a triangulation. + + The index of an edge + true if the edge is on the boundary + + + + Computes the vertex or edge index which is the next one + (counter-clockwise) around the triangle. + + The index + The next index value + + + + Computes the vertex or edge index which is the previous one + (counter-clockwise) around the triangle. + + The index + The previous index value + + + + Gets the index of the vertex opposite an edge. + + The edge index + The index of the opposite vertex + + + + Gets the index of the edge opposite a vertex. + + The index of the vertex + The index of the opposite edge + + + + Computes a coordinate for the midpoint of a triangle edge. + + The edge index + the midpoint of the triangle edge + + + Gets the area of the triangle. + The area of the triangle + + + + Gets the length of the perimeter of the triangle. + + + + + Creates a representing this triangle. + + The geometry factory + A polygon + + + + + + + Builds a triangulation from a set of s + by populating the links to adjacent triangles. + + Martin Davis + + + + Computes the triangulation of a set of s. + + An enumeration of s + + + + Creates an instance of this class and computes the triangulation of a set of s. + + An enumeration of s + + + + Represents an edge in a , + to be used as a key for looking up Tris + while building a triangulation. + The edge value is normalized to allow lookup + of adjacent triangles. + + Martin Davis + + + + Gets or sets a value indicating the start point of this + + + + + Gets or sets a value indicating the end point of this + + + + + Creates an instance of this class + + A coordinate + A coordinate + + + + Creates a map between the vertex s of a + set of s, + and the parent geometry, and transfers the source geometry + data objects to geometry components tagged with the coordinates. + + + This class can be used in conjunction with + to transfer data objects from the input site geometries + to the constructed Voronoi polygons. + + Martin Davis + + + + + Loads the vertices of a geometry and maps them with th the . + + A geometry + + + + Loads the vertices of a collection of geometries and maps them with the . + + A collection of geometry + + + + Loads the vertices of the geometries of a GeometryCollection and maps them with the . + + A GeometryCollection + + + + Gets a value indicating the coordinates. + + A list of Coordinates. + + + + Input is assumed to be a multiGeometry + in which every component has its userData + set to be a Coordinate which is the key to the output data. + The Coordinate is used to determine + the output data object to be written back into the component. + + + + + + A utility class which creates Voronoi Diagrams + from collections of points. + The diagram is returned as a of s, + representing the faces of the Voronoi diagram. + /// The faces are clipped to the larger of: + + + an envelope supplied by . + + + an envelope determined by the input sites. + + + The userData attribute of each face Polygon is set to + the Coordinate of the corresponding input site. + This allows using a Map to link faces to data associated with sites. + + Martin Davis + + + + Sets the sites (point or vertices) which will be diagrammed. + All vertices of the given geometry will be used as sites. + + geom the geometry from which the sites will be extracted. + + + + Sets the sites (point or vertices) which will be diagrammed + from a collection of s. + + a collection of Coordinates. + + + + Sets the envelope to clip the diagram to. + The diagram will be clipped to the larger + of this envelope or an envelope surrounding the sites. + + the clip envelope. + + + + Sets the snapping tolerance which will be used + to improved the robustness of the triangulation computation. + A tolerance of 0.0 specifies that no snapping will take place. + + tolerance the tolerance distance to use + + + + Gets the which models the computed diagram. + + the subdivision containing the triangulation + + + + Gets the faces of the computed diagram as a + of s, clipped as specified. + + The attribute of each face is set to + the Coordinate of the corresponding input site. + This allows using a to link faces to data associated with sites. + + the geometry factory to use to create the output + a containing the face s of the diagram + + + + An alternative implementation of the priority queue abstract data type. + This allows us to do more than , which we + got from JTS. Ultimately, this queue enables scenarios that have more + favorable execution speed characteristics at the cost of less favorable + memory and usability characteristics. + + + The type of the priority for each queue node. + + + The type of data stored in the queue. + + + When enumerating over the queue, note that the elements will not be in + sorted order. To get at the elements in sorted order, use the copy + constructor and repeatedly elements from it. + + + + + Initializes a new instance of the + class. + + + + + Initializes a new instance of the + class. + + + The initial queue capacity. + + + is less than 1. + + + + + Initializes a new instance of the + class. + + + The to use to compare priority values, + or to use the default comparer for the type. + + + + + Initializes a new instance of the + class. + + + The initial queue capacity. + + + The to use to compare priority values, + or to use the default comparer for the type. + + + is less than 1. + + + + + Initializes a new instance of the + class. + + + The to + copy from. + + + is . + + + + + Gets the number of nodes currently stored in this queue. + + + + + Gets the node at the head of the queue. + This is the node whose compares + less than or equal to the priority of all other nodes in the queue. + + + + + Removes all nodes from this queue. + + + + + Determines whether the given node is contained within this queue. + + + The node to locate in the queue. + + + if is found in the + queue, otherwise . + + + + + Adds a given node to the queue with the given priority. + + + The node to add to the queue. + + + The priority for the node. + + + is . + + + + + Removes and returns the head of the queue. + + + The removed element. + + + + + Changes the priority of the given node. + + + The node whose priority to change. + + + The new priority for the node. + + + is . + + + + + Removes the given node from this queue if it is present. + + + The node to remove if present. + + + A value indicating whether the node was removed. + + + + + + + + + + + A utility for making programming assertions. + + + + + Tests if is true + + If the test fails, with no message is thrown. + + The assertion value + + + + Tests if is true + + If the test fails, with is thrown. + + The assertion value + A message describing the failure condition. + + + + Tests if two values are equal. + + If the test fails, with no specific message is thrown. + + The expected value + The actual value + + + + Tests if two values are equal. + + If the test fails, with is thrown. + + The expected value + The actual value + A message describing the failure condition. + + + + Throws an with no specific message text. + + + + + Throws an with as specific message text. + + A text describing the failure condition + + + + + + + + + + + + + + + + + + + + A CoordinateFilter that creates an array containing every coordinate in a Geometry. + + + + + Constructs a CoordinateArrayFilter. + + The number of points that the CoordinateArrayFilter will collect. + + + + Returns the Coordinates collected by this CoordinateArrayFilter. + + + + + + + + + + + CoordinateCompare is used in the sorting of arrays of Coordinate objects. + Implements a lexicographic comparison. + + + + + Compares two object and returns a value indicating whether one is less than, equal to or greater + than the other. + + First Coordinate object to compare. + Second Coordinate object to compare. + + <table cellspacing="0" class="dtTABLE"> + <TR VALIGN="top"> + <TH width=50%>Value</TH> + <TH width=50%>Condition</TH> + </TR> + <TR VALIGN="top"> + <TD width=50%>Less than zero</TD> + <TD width=50%><I>a</I> is less than <I>b</I>.</TD> + </TR> + <TR VALIGN="top"> + <TD width=50%>Zero</TD> + <TD width=50%><I>a</I> equals <I>b</I>.</TD> + </TR> + <TR VALIGN="top"> + <TD width=50%>Greater than zero</TD> + <TD width=50%><I>a</I> is greater than <I>b</I>.</TD> + </TR> + </table> + + If a implements IComparable, then a. CompareTo (b) is returned; otherwise, if b + implements IComparable, then b. CompareTo (a) is returned. + Comparing a null reference (Nothing in Visual Basic) with any type is allowed and does not + generate an exception when using IComparable. When sorting, a null reference (Nothing) is + considered to be less than any other object. + + + + + A CoordinateFilter that counts the total number of coordinates + in a Geometry. + + + + + Returns the result of the filtering. + + + + + + + + + + + Converts degrees to radians. + + + + + Converts degrees to radians. + + The angle in degrees. + The angle in radians. + + + + A utility class to get s, s + off of s or to build aggregate geometries. + + + + + Gets a default envelope + + + + + Gets the envelope of a geometry. + + A geometry + The envelope of or if g == null. + + + + Function to get the geometry factory of a geometry. If + is null, a default geometry + factory is returned. + + A geometry + A geometry factory + + + + Function to get the geometry factory of the first + geometry in a series of geometries. + If no geometry is provided in , + a default geometry factory is returned. + + An enumeration of geometries + A geometry factory + + + + Builds a geometry from a list of geometries. + + The function returns + + nullif the list is null or empty + [0]if the list contains one single item. + a if is a GeometryCollection. + a Multi-geometry in all other cases. + + + A list of geometries. + A parent geometry + A geometry. + + + + Builds a geometry from a list of geometries. + + The function returns + + nullif the list is null or empty + [0]if the list contains one single item. + a if is a GeometryCollection. + a Multi-geometry in all other cases. + + + A list of geometries. + A parent geometry + A geometry. + + + + Method to build a geometry. + + An array of geometries + A GEOMETRYCOLLECTION containing . + + + + Method to build a geometry. + + A geometry + A geometry + A GEOMETRYCOLLECTION containing and . + + + + Computes various kinds of common geometric shapes. + Allows various ways of specifying the location and extent of the shapes, + as well as number of line segments used to form them. + + + + + A geometry factory + + + + + A precision model + + + + + + Create a shape factory which will create shapes using the default GeometryFactory. + + + + + Create a shape factory which will create shapes using the given GeometryFactory. + + The factory to use. + + + + Gets/Sets the location of the shape by specifying the base coordinate + (which in most cases is the + lower left point of the envelope containing the shape). + + + + + Gets/Sets the location of the shape by specifying the centre of + the shape's bounding box. + + + + + Gets or sets the envelope of the shape + + + + + Gets/Sets the total number of points in the created Geometry. + + + + + Gets/Sets the size of the extent of the shape in both x and y directions. + + + + + Gets/Sets the width of the shape. + + + + + Gets/Sets the height of the shape. + + + + + Gets/Sets the rotation angle, in radians, to use for the shape. + The rotation is applied relative to the centre of the shape. + + + + + Rotates a geometry by angle + + The geometry to rotate + A rotated geometry + + + + Creates a coordinate at (, ) + + The x-ordinate value + The y-ordinate value + A coordinate + + + + Creates a translated coordinate at ( + , + ) + + The x-ordinate value + The y-ordinate value + A translation vector (coordinate) + A coordinate + + + + Creates a rectangular Polygon. + + A rectangular polygon. + + + + Creates a circular Polygon. + + A circular polygon. + + + + Creates an elliptical Polygon. + If the supplied envelope is square the + result will be a circle. + + An an ellipse or circle. + + + + Creates a squircular . + + a squircle + + + + Creates a supercircular + of a given positive power. + + a supercircle + + + + Creates a elliptical arc, as a LineString. + + The arc is always created in a counter-clockwise direction. + + Start angle in radians + Size of angle in radians + + + + + Creates an elliptical arc polygon. + + + The polygon is formed from the specified arc of an ellipse + and the two radii connecting the endpoints to the centre of the ellipse. + + Start angle in radians + Size of angle in radians + An elliptical arc polygon + + + + A dimension class for s + + + + + Gets or sets a value indicating the base of the shapes to be created + + + + + Gets or sets a value indicating the centre of the shapes to be created + + + + + Gets or sets a value indicating the width of the . + + + + + Gets or sets a value indicating the height of the . + + + + + Sets and to the same value + + + + + Gets a value indicating the minimum size of the shape's + + + + + Gets or sets a value indicating the bounds of the shape to be created + + + + + + + + + + + + + + + + + + + + + + + + + + A guard class + + + + + Checks if a value is not null. + + The value to check for null + The name of the property that belongs to. + + + + + + + + + Only static methods! + + + + + Convert the given numeric value (passed as string) of the base specified by baseIn + to the value specified by baseOut. + + Numeric value to be converted, as string. + Base of input value. + Base to use for conversion. + Converted value, as string. + + + + Utility functions to report memory usage. + + mbdavis + + + + Gets a value indicating the total memory used. + + + + + Gets a string describing the total memory used + + + + + Number of bytes in a kilo-byte + + + + + Number of bytes in mega-byte + + + + + Number of bytes in a giga-byte + + + + + Formats a number of bytes + + The number of bytes + A string describing a number of bytes + + + + Rounds a double to 2 decimal places + + The number to round + The rounded number + + + + A priority queue over a set of objects. + + Objects to add + Martin Davis + + + + Creates an instance of this class + + + + + Creates an instance of this class + + The capacity of the queue + The comparer to use for computing priority values + + + Insert into the priority queue. Duplicates are allowed. + + The item to insert. + + + + Test if the priority queue is logically empty. + + true if empty, false otherwise. + + + + Returns size. + + + + + Make the priority queue logically empty. + + + + + Remove the smallest item from the priority queue. + + The smallest item, or default(T) if empty. + + + + Gets the smallest item without removing it from the queue + + + + + > + + + + A container for a prioritized node that sites in an + . + + + The type to use for the priority of the node in the queue. + + + The type to use for the data stored by the node in the queue. + + + + + Initializes a new instance of the class. + + + The to store in this node. + + + + + Gets the that is stored in this node. + + + + + Gets the of this node in the queue. + + + The queue may update this priority while the node is still in the queue. + + + + + Gets or sets the index of this node in the queue. + + + This should only be read and written by the queue itself. + It has no "real" meaning to anyone else. + + + + + Converts radians to degress. + + + + + Converts radians to degress. + + Angle in radians. + The angle in degrees. + + + + + + + + + + + + + + + + + A + that extracts a unique array ofCoordinate s. + The array of coordinates contains no duplicate points. + + It preserves the order of the input points. + + + + + Convenience method which allows running the filter over an array of s. + + an array of coordinates + an array of the unique coordinates + + + + Returns the gathered s. + + The Coordinates collected by this ICoordinateArrayFilter + + + + + + + Buffer for characters. This approximates StringBuilder + but is designed to be faster for specific operations. + This is about 30% faster for the operations I'm interested in + (Append, Clear, Length, ToString). + This trades off memory for speed. + + + To make Remove from the head fast, this is implemented + as a ring buffer. + This uses head and tail indices into a fixed-size + array. This will grow the array as necessary. + + + + + Gets/Sets the number of characters in the character buffer. + Increasing the length this way provides indeterminate results. + + + + + Returns the capacity of this character buffer. + + + + + Default constructor. + + + + + Construct with a specific capacity. + + + + + + Reallocate the buffer to be larger. For the new size, this + uses the max of the requested length and double the current + capacity. + This does not shift, meaning it does not change the head or + tail indices. + + The new requested length. + + + + Ensure that we're set for the requested length by + potentially growing or shifting contents. + + + + + + Move the buffer contents such that headIndex becomes 0. + + + + + Overwrite this object's underlying buffer with the specified + buffer. + + The character array. + The number of characters to consider filled + in the input buffer. + + + + Append a character to this buffer. + + + + + + Append a string to this buffer. + + The string to append. + + + + Append a string to this buffer. + + The string to append. + + + + Remove a character at the specified index. + + The index of the character to remove. + + + + + Remove a specified number of characters at the specified index. + + The index of the characters to remove. + The number of characters to remove. + + + + Find the first instance of a character in the buffer, and + return its index. This returns -1 if the character is + not found. + + The character to find. + The index of the specified character, or -1 + for not found. + + + + Empty the buffer. + + + + + Indexer. + + + + + Return the current contents as a string. + + The new string. + + + + Exception class for unterminated tokens. + + + + + Construct with a particular message. + + The message to store in this object. + + + + Exception class for unterminated quotes. + + + + + Construct with a particular message. + + The message to store in this object. + + + + Exception class for unterminated block comments. + + + + + Construct with a particular message. + + The message to store in this object. + + + + Bitwise enumeration for character types. + + + + word characters (usually alpha, digits, and domain specific) + + + # or something for line comments + + + whitespace + + + ' or " type + + + usually 0 to 9 + + + usually 0 to 9, a-f and A-F + + + eof char + + + + This contains the settings that control the behavior of the tokenizer. + This is separated from the StreamTokenizer so that common settings + are easy to package and keep together. + + + + + This is the character type table. Each byte is bitwise encoded + with the character attributes, such as whether that character is + word or whitespace. + + + + + Whether or not to return whitespace tokens. If not, they're ignored. + + + + + Whether or not to return EolTokens on end of line. Eol tokens will not + break up other tokens which can be multi-line. For example block comments + and quotes will not be broken by Eol tokens. Therefore the number of + Eol tokens does not give you the line count of a stream. + + + + + Whether or not to look for // comments + + + + + Whether or not to look for /* */ block comments. + + + + + Whether or not to return comments. + + + + + Whether or not to check for unterminated quotes and block comments. + If true, and one is encoutered, an exception is thrown of the appropriate type. + + + + + Whether or not digits are specified as Digit type in the + character table. + This setting is based on the character types table, so this + setting interacts with character type table manipulation. + This setting may become incorrect if you modify the character + types table directly. + + + + + Whether or not to parse Hex (0xABCD...) numbers. + This setting is based on the character types table, so this + setting interacts with character type table manipulation. + + + + + Default constructor. + + + + + Copy constructor. + + + + + Sets this object to be the same as the specified object. + Note that some settings which are entirely embodied by the character + type table. + + + + + Setup default parse behavior. + This resets to same behavior as on construction. + + bool - true for success. + + + + Apply settings which are commonly used for code parsing + C-endCapStyle code, including C++, C#, and Java. + + + + + + Clear the character type settings. This leaves them unset, + as opposed to the default. Use SetDefaults() for default + settings. + + + + + Specify that a particular character is a word character. + Character table type manipulation method. + This adds the type to the char(s), rather + than overwriting other types. + + The character. + + + + Specify that a range of characters are word characters. + Character table type manipulation method. + This adds the type to the char(s), rather + than overwriting other types. + + First character. + Last character. + + + + Specify that a string of characters are word characters. + Character table type manipulation method. + This adds the type to the char(s), rather + than overwriting other types. + + + + + + Specify that a character is a whitespace character. + Character table type manipulation method. + This type is exclusive with other types. + + The character. + + + + Specify that a range of characters are whitespace characters. + Character table type manipulation method. + This adds the characteristic to the char(s), rather + than overwriting other characteristics. + + First character. + Last character. + + + + Remove other type settings from a range of characters. + Character table type manipulation method. + + + + + + + Remove other type settings from a character. + Character table type manipulation method. + + + + + + Specify that a particular character is a comment-starting character. + Character table type manipulation method. + + + + + + Specify that a particular character is a quote character. + Character table type manipulation method. + + + + + + Return a string representation of a character type setting. + Since the type setting is bitwise encoded, a character + can have more than one type. + + The character type byte. + The string representation of the type flags. + + + + Check whether the specified char type byte has a + particular type flag set. + + The char type byte. + The CharTypeBits entry to compare to. + bool - true or false + + + + Check whether the specified char has a + particular type flag set. + + The character. + The CharTypeBits entry to compare to. + bool - true or false + + + + Check whether the specified char has a + particular type flag set. + + The character. + The CharTypeBits entry to compare to. + bool - true or false + + + + Display the state of this object. + + + + + Display the state of this object, with a per-line prefix. + + The pre-line prefix. + + + + A StreamTokenizer similar to Java's. This breaks an input stream + (coming from a TextReader) into Tokens based on various settings. The settings + are stored in the TokenizerSettings property, which is a + StreamTokenizerSettings instance. + + + + This is configurable in that you can modify TokenizerSettings.CharTypes[] array + to specify which characters are which type, along with other settings + such as whether to look for comments or not. + + + WARNING: This is not internationalized. This treats all characters beyond + the 7-bit ASCII range (decimal 127) as Word characters. + + + There are two main ways to use this: 1) Parse the entire stream at + once and get an ArrayList of Tokens (see the Tokenize* methods), + and 2) call NextToken() successively. + This reads from a TextReader, which you can set directly, and this + also provides some convenient methods to parse files and strings. + This returns an Eof token if the end of the input is reached. + + + Here's an example of the NextToken() endCapStyle of use: + + StreamTokenizer tokenizer = new StreamTokenizer(); + tokenizer.GrabWhitespace = true; + tokenizer.Verbosity = VerbosityLevel.Debug; // just for debugging + tokenizer.TextReader = File.OpenText(fileName); + Token token; + while (tokenizer.NextToken(out token)) log.Info("Token = '{0}'", token); + + + + Here's an example of the Tokenize... endCapStyle of use: + + StreamTokenizer tokenizer = new StreamTokenizer("some string"); + ArrayList tokens = new ArrayList(); + if (!tokenizer.Tokenize(tokens)) + { + // error handling + } + foreach (Token t in tokens) Console.WriteLine("t = {0}", t); + + + + Comment delimiters are hardcoded (// and /*), not affected by char type table. + + + This sets line numbers in the tokens it produces. These numbers are normally + the line on which the token starts. + There is one known caveat, and that is that when GrabWhitespace setting + is true, and a whitespace token contains a newline, that token's line number + will be set to the following line rather than the line on which the token + started. + + + + + + This is the number of characters in the character table. + + + + + This is the TextReader that this object will read from. + Set this to set the input reader for the parse. + + + + + The settings which govern the behavior of the tokenization. + + + + + Default constructor. + + + + + Construct and set this object's TextReader to the one specified. + + The TextReader to read from. + + + + Construct and set this object's TextReader to the one specified. + + The TextReader to read from. + Tokenizer settings. + + + + Construct and set a string to tokenize. + + The string to tokenize. + + + + Utility function, things common to constructors. + + + + + Clear the stream settings. + + + + + Display the state of this object. + + + + + Display the state of this object, with a per-line prefix. + + The pre-line prefix. + + + + The states of the state machine. + + + + + Pick the next state given just a single character. This is used + at the start of a new token. + + The type of the character. + The character. + The state. + + + + Pick the next state given just a single character. This is used + at the start of a new token. + + The type of the character. + The character. + Exclude this state from the possible next state. + The state. + + + + Read the next character from the stream, or from backString + if we backed up. + + The next character. + + + + Get the next token. The last token will be an EofToken unless + there's an unterminated quote or unterminated block comment + and Settings.DoUntermCheck is true, in which case this throws + an exception of type StreamTokenizerUntermException or sub-class. + + The output token. + bool - true for success, false for failure. + + + + Starting from current stream location, scan forward + over an int. Determine whether it's an integer or not. If so, + push the integer characters to the specified CharBuffer. + If not, put them in backString (essentially leave the + stream as it was) and return false. + + If it was an int, the stream is left 1 character after the + end of the int, and that character is output in the thisChar parameter. + + The formats for integers are: 1, +1, and -1 + The + and - signs are included in the output buffer. + + The CharBuffer to append to. + Whether or not to consider + to be part + of an integer. + The last character read by this method. + true for parsed an int, false for not an int + + + + Parse the rest of the stream and put all the tokens + in the input ArrayList. This resets the line number to 1. + + The ArrayList to append to. + bool - true for success + + + + Parse all tokens from the specified TextReader, put + them into the input ArrayList. + + The TextReader to read from. + The ArrayList to append to. + bool - true for success, false for failure. + + + + Parse all tokens from the specified file, put + them into the input ArrayList. + + The file to read. + The ArrayList to put tokens in. + bool - true for success, false for failure. + + + + Tokenize a file completely and return the tokens in a Token[]. + + The file to tokenize. + A Token[] with all tokens. + + + + Parse all tokens from the specified string, put + them into the input ArrayList. + + + The ArrayList to put tokens in. + bool - true for success, false for failure. + + + + Parse all tokens from the specified Stream, put + them into the input ArrayList. + + + The ArrayList to put tokens in. + bool - true for success, false for failure. + + + + Gibt einen Enumerator zurück, der die Auflistung durchläuft. + + + Ein , der zum Durchlaufen der Auflistung verwendet werden kann. + + 1 + + + + Gibt einen Enumerator zurück, der eine Auflistung durchläuft. + + + Ein -Objekt, das zum Durchlaufen der Auflistung verwendet werden kann. + + 2 + + + + Token class used by StreamTokenizer. + This represents a single token in the input stream. + This is subclassed to provide specific token types, + such as CharToken, FloatToken, etc. + + + + + The line number in the input stream where this token originated. + This is base-1. + + + + + The line number where this token was found. This is base-1. + + + + + A storage object for the data of this token. + + + + + The Object stored by this token. This will be + a primitive C# type. + + + + + Backer for UntermError. + + + + + Whether or not there was an unterminated token problem + when creating this token. See UntermErrorMessage for + a message associated with the problem. + + + + An error message associated with unterm error. + + + + The error message if there was an unterminated token error + creating this token. + + + + + Construct a Token with the specified line number. + + The line number where this + token comes from. + + + + Equals override. + + The object to compare to. + bool - true for equals, false otherwise. + + + + Equals overload. + + The string to compare to. + bool + + + + Equals overload. + + The char to compare to. + bool + + + + Operator== overload. Compare a token and an object. + + The token to compare. + The other object. + bool + + + + Operator!= overload. Compare a token and an object. + + The token to compare. + The other object. + bool + + + + Operator== overload. Compare a token and a char. + + The token to compare. + The char. + bool + + + + Operator!= overload. Compare a token and a char. + + The token to compare. + The char. + bool + + + + Operator== overload. Compare a token and a string. + + The token to compare. + The string. + bool + + + + Operator!= overload. Compare a token and a string. + + The token to compare. + The string. + bool + + + + Override. Returns the ToString().GetHashCode(). + + The hash code. + + + + Return this token's value as a string. + + This token's value as a string. + + + + Produce a string which includes the line number. + + + + + + Produce a string which includes the token type. + + + + + + Create an object of the specified type corresponding to + this token. + + The type of object to create. + The new object, or null for error. + + + + Represents end-of-lines (line separator characters). + + + + Default constructor. + + + Constructor that takes line number. + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + + Represents end of file/stream. + + + + Default constructor. + + + Constructor that takes line number. + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + + Abstract base class for string tokens. + + + + Default constructor. + + + Constructor with the specified value + and line number. + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + + Token type for words, meaning sequences of word + characters. + + + + Constructor with the specified value. + + + Constructor with the specified value + and line number. + + + + Token type for Quotes such as "this is a quote". + + + + Constructor with the specified value. + + + Constructor with the specified value + and line number. + + + + Token type for comments, including line and block + comments. + + + + Constructor with the specified value. + + + Constructor with the specified value + and line number. + + + + Token type for whitespace such as spaces and tabs. + + + + Constructor with the specified value. + + + Constructor with the specified value + and line number. + + + + Token type for characters, meaning non-word characters. + + + + Constructor with the specified value + and line number. + + + Constructor with the specified value. + + + Constructor with the specified value. + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + + Token type for floating point numbers, stored internally as a Double. + + + + + Constructor with the specified value. + + + + + Constructor with the specified value. + + + + + Constructor with the specified value. + + + + + Constructor with the specified value and line number. + + + + + Constructor with the specified value and line number. + + + + + Override, see base + + + + + Override, see base + + + + + Override, see base + + + + + Override, see base + + + + + Override, see base + + + + + Token type for integer tokens. This handles both Int32 and Int64. + + + + Constructor with the specified value. + + + Constructor with the specified value. + + + Constructor with the specified value. + + + Constructor with the specified value + and line number. + + + Constructor with the specified value + and line number. + + + + Constructor for a 64 bit int + + + + + Parse a string known to be a hex string. This is faster + than Parse which doesn't assume the number is Hex. This will + throw an exception if the input number isn't hex. + + The hex number as a string. + The line where this token was found. + A new IntToken set to the value in the input string. + + + + Convert the input string to an integer, if possible + + The string to parse. + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + Override, see base + + + + This enumerates verbosity levels. + + + + For error messages. + + + For warn messages. + + + For info messages. + + + For debug messages. + + + From 61232a54312f23b403f8d1f626a3db9aabc669ba Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Wed, 16 Feb 2022 10:27:23 +0100 Subject: [PATCH 17/19] updated perf test to use compiled tests instead of nuget packages --- NetTopologySuite.IO.ShapeFile.sln | 6 - PerfApp/PerfApp.csproj | 17 +- PerfApp/PerfApp.sln | 25 + .../NetTopologySuite.Features.deps.json | 161 + .../NetTopologySuite.Features.dll | Bin 0 -> 12800 bytes .../NetTopologySuite.Features.xml | 281 ++ .../NetTopologySuite.IO.ShapeFile.deps.json | 199 ++ .../NetTopologySuite.IO.ShapeFile.dll | Bin 0 -> 94208 bytes .../NetTopologySuite.IO.ShapeFile.xml | 2829 +++++++++++++++++ 9 files changed, 3508 insertions(+), 10 deletions(-) create mode 100644 PerfApp/PerfApp.sln create mode 100644 PerfApp/nts_features/NetTopologySuite.Features.deps.json create mode 100644 PerfApp/nts_features/NetTopologySuite.Features.dll create mode 100644 PerfApp/nts_features/NetTopologySuite.Features.xml create mode 100644 PerfApp/nts_shapefile/NetTopologySuite.IO.ShapeFile.deps.json create mode 100644 PerfApp/nts_shapefile/NetTopologySuite.IO.ShapeFile.dll create mode 100644 PerfApp/nts_shapefile/NetTopologySuite.IO.ShapeFile.xml diff --git a/NetTopologySuite.IO.ShapeFile.sln b/NetTopologySuite.IO.ShapeFile.sln index 6568473..3f4b4f8 100644 --- a/NetTopologySuite.IO.ShapeFile.sln +++ b/NetTopologySuite.IO.ShapeFile.sln @@ -16,8 +16,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetTopologySuite.IO.GDB", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetTopologySuite.IO.ShapeFile.Test", "test\NetTopologySuite.IO.ShapeFile.Test\NetTopologySuite.IO.ShapeFile.Test.csproj", "{89254B6E-F130-41F3-8956-2F790E99C6F0}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerfApp", "PerfApp\PerfApp.csproj", "{F1B36647-56E8-492B-8521-6C500ED04389}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -36,10 +34,6 @@ Global {89254B6E-F130-41F3-8956-2F790E99C6F0}.Debug|Any CPU.Build.0 = Debug|Any CPU {89254B6E-F130-41F3-8956-2F790E99C6F0}.Release|Any CPU.ActiveCfg = Release|Any CPU {89254B6E-F130-41F3-8956-2F790E99C6F0}.Release|Any CPU.Build.0 = Release|Any CPU - {F1B36647-56E8-492B-8521-6C500ED04389}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F1B36647-56E8-492B-8521-6C500ED04389}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F1B36647-56E8-492B-8521-6C500ED04389}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F1B36647-56E8-492B-8521-6C500ED04389}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PerfApp/PerfApp.csproj b/PerfApp/PerfApp.csproj index d0530cd..2867534 100644 --- a/PerfApp/PerfApp.csproj +++ b/PerfApp/PerfApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,21 +7,30 @@ + + + - - - + + nts_patch_595\NetTopologySuite.dll + + + nts_features\NetTopologySuite.Features.dll + + + nts_shapefile\NetTopologySuite.IO.ShapeFile.dll + diff --git a/PerfApp/PerfApp.sln b/PerfApp/PerfApp.sln new file mode 100644 index 0000000..977bb26 --- /dev/null +++ b/PerfApp/PerfApp.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31321.278 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerfApp", "PerfApp.csproj", "{64DBD7B8-EE86-40F3-81BF-4D1E0049662F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {64DBD7B8-EE86-40F3-81BF-4D1E0049662F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64DBD7B8-EE86-40F3-81BF-4D1E0049662F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64DBD7B8-EE86-40F3-81BF-4D1E0049662F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64DBD7B8-EE86-40F3-81BF-4D1E0049662F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4FC81A8C-F367-4B21-9955-39FFAE513605} + EndGlobalSection +EndGlobal diff --git a/PerfApp/nts_features/NetTopologySuite.Features.deps.json b/PerfApp/nts_features/NetTopologySuite.Features.deps.json new file mode 100644 index 0000000..b6da2e1 --- /dev/null +++ b/PerfApp/nts_features/NetTopologySuite.Features.deps.json @@ -0,0 +1,161 @@ +{ + "runtimeTarget": { + "name": ".NETStandard,Version=v2.0/", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETStandard,Version=v2.0": {}, + ".NETStandard,Version=v2.0/": { + "NetTopologySuite.Features/2.1.0-pre.190390561+local": { + "dependencies": { + "Microsoft.SourceLink.GitHub": "1.0.0", + "NETStandard.Library": "2.0.3", + "NetTopologySuite": "2.0.0" + }, + "runtime": { + "NetTopologySuite.Features.dll": {} + } + }, + "Microsoft.Build.Tasks.Git/1.0.0": {}, + "Microsoft.NETCore.Platforms/1.1.0": {}, + "Microsoft.SourceLink.Common/1.0.0": {}, + "Microsoft.SourceLink.GitHub/1.0.0": { + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.0.0", + "Microsoft.SourceLink.Common": "1.0.0" + } + }, + "NETStandard.Library/2.0.3": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, + "NetTopologySuite/2.0.0": { + "dependencies": { + "System.Memory": "4.5.3" + }, + "runtime": { + "lib/netstandard2.0/NetTopologySuite.dll": { + "assemblyVersion": "2.0.0.0", + "fileVersion": "2.0.0.0" + } + } + }, + "System.Buffers/4.4.0": { + "runtime": { + "lib/netstandard2.0/System.Buffers.dll": { + "assemblyVersion": "4.0.2.0", + "fileVersion": "4.6.25519.3" + } + } + }, + "System.Memory/4.5.3": { + "dependencies": { + "System.Buffers": "4.4.0", + "System.Numerics.Vectors": "4.4.0", + "System.Runtime.CompilerServices.Unsafe": "4.5.2" + }, + "runtime": { + "lib/netstandard2.0/System.Memory.dll": { + "assemblyVersion": "4.0.1.1", + "fileVersion": "4.6.27617.2" + } + } + }, + "System.Numerics.Vectors/4.4.0": { + "runtime": { + "lib/netstandard2.0/System.Numerics.Vectors.dll": { + "assemblyVersion": "4.1.3.0", + "fileVersion": "4.6.25519.3" + } + } + }, + "System.Runtime.CompilerServices.Unsafe/4.5.2": { + "runtime": { + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll": { + "assemblyVersion": "4.0.4.1", + "fileVersion": "4.6.26919.2" + } + } + } + } + }, + "libraries": { + "NetTopologySuite.Features/2.1.0-pre.190390561+local": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Microsoft.Build.Tasks.Git/1.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-z2fpmmt+1Jfl+ZnBki9nSP08S1/tbEOxFdsK1rSR+LBehIJz1Xv9/6qOOoGNqlwnAGGVGis1Oj6S8Kt9COEYlQ==", + "path": "microsoft.build.tasks.git/1.0.0", + "hashPath": "microsoft.build.tasks.git.1.0.0.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/1.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==", + "path": "microsoft.netcore.platforms/1.1.0", + "hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512" + }, + "Microsoft.SourceLink.Common/1.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-G8DuQY8/DK5NN+3jm5wcMcd9QYD90UV7MiLmdljSJixi3U/vNaeBKmmXUqI4DJCOeWizIUEh4ALhSt58mR+5eg==", + "path": "microsoft.sourcelink.common/1.0.0", + "hashPath": "microsoft.sourcelink.common.1.0.0.nupkg.sha512" + }, + "Microsoft.SourceLink.GitHub/1.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-aZyGyGg2nFSxix+xMkPmlmZSsnGQ3w+mIG23LTxJZHN+GPwTQ5FpPgDo7RMOq+Kcf5D4hFWfXkGhoGstawX13Q==", + "path": "microsoft.sourcelink.github/1.0.0", + "hashPath": "microsoft.sourcelink.github.1.0.0.nupkg.sha512" + }, + "NETStandard.Library/2.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", + "path": "netstandard.library/2.0.3", + "hashPath": "netstandard.library.2.0.3.nupkg.sha512" + }, + "NetTopologySuite/2.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3ajBClEI9wx2/DjjGmV52sHW1m52vLg8sdz1pJbTf5ySj1X90qehQs3v1DRwGo0F8UKj/Z2SjNhRN/6LroAkqg==", + "path": "nettopologysuite/2.0.0", + "hashPath": "nettopologysuite.2.0.0.nupkg.sha512" + }, + "System.Buffers/4.4.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AwarXzzoDwX6BgrhjoJsk6tUezZEozOT5Y9QKF94Gl4JK91I4PIIBkBco9068Y9/Dra8Dkbie99kXB8+1BaYKw==", + "path": "system.buffers/4.4.0", + "hashPath": "system.buffers.4.4.0.nupkg.sha512" + }, + "System.Memory/4.5.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==", + "path": "system.memory/4.5.3", + "hashPath": "system.memory.4.5.3.nupkg.sha512" + }, + "System.Numerics.Vectors/4.4.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ==", + "path": "system.numerics.vectors/4.4.0", + "hashPath": "system.numerics.vectors.4.4.0.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/4.5.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-wprSFgext8cwqymChhrBLu62LMg/1u92bU+VOwyfBimSPVFXtsNqEWC92Pf9ofzJFlk4IHmJA75EDJn1b2goAQ==", + "path": "system.runtime.compilerservices.unsafe/4.5.2", + "hashPath": "system.runtime.compilerservices.unsafe.4.5.2.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/PerfApp/nts_features/NetTopologySuite.Features.dll b/PerfApp/nts_features/NetTopologySuite.Features.dll new file mode 100644 index 0000000000000000000000000000000000000000..d34fa214f4a670df16a24b48e95f70499065696f GIT binary patch literal 12800 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 r>p*Vte8BT#3X#%U$9?>z9|y0t9j literal 0 HcmV?d00001 diff --git a/PerfApp/nts_features/NetTopologySuite.Features.xml b/PerfApp/nts_features/NetTopologySuite.Features.xml new file mode 100644 index 0000000..4ff00ca --- /dev/null +++ b/PerfApp/nts_features/NetTopologySuite.Features.xml @@ -0,0 +1,281 @@ + + + + NetTopologySuite.Features + + + + + Stores all attributes associated with a single Geometry feature. + + + + + Gets or sets a value indicating if setting with a + nonexistant index will throw an exception or if the attribute/value pair will + silently be added. + + + + + Creates an instance of this class using the default equality comparer for names. + + + + + Creates an instance of this class using the given equality comparer for names. + + The to use for comparing names, or to use the default. + + + + Creates an instance of this class using the provided enumeration of key/value pairs and + the default equality comparer for names. + + An enumeration of key/value pairs + + + + Creates an instance of this class using the provided enumeration of key/value pairs and + the given equality comparer for names. + + An enumeration of key/value pairs + The to use for comparing names, or to use the default. + + + + Creates an instance of this class using the provided enumeration of key/value pairs + + An attributes dictionary + If the attributes are null + + + + + + + + + + + + + + + + + + + + + + + + + Method to merge this attribute table with another attribute table + + The other attribute table + A value indicating if values in this attribute table are preferable + over those in . The default is true. + + + + + + + + + + + + + + Standard implementation of . + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The geometry + The attributes + + + + Gets or sets a value indicating how bounding box on should be handled + + Default is false + + + + + + + + + + + + + Represents a feature collection. + + + + + The bounding box of this + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class, given a list of IFeature. + + + + + Gets or sets the (optional) Bounding box (bbox) Object. + + + A describing the bounding box or . + + + + + Function to compute the bounding box (when it isn't set) + + A bounding box for this + + + + Defines extensions for . + + + + + Gets an ID value from this , using its + property if it happens to implement that interface (otherwise, searching through its + looking for an attribute with a specified name). + + + The whose ID to get. + + + The name of the attribute to look for in , if the + is not an instance of . + + + The ID value, or if this instance has no ID. + + + + + Interface definition for an object capable of storing 's attribute data + + + + + Method to add the attribute "" from the attribute table. + + The name (or key) of the attribute + + + + + Method to delete the attribute "" from the attribute table. + + The name (or key) of the attribute + + + + Function to query the of the Attribute "" + + The name (or key) of the attribute + The of the specified attribute + + + + Gets or sets the attribute value for the specified . + + The name (or key) of the attribute + The attribute value + + + + Function to verify if attribute data for the specified does exist. + + The name of the attribute + true if the attribute data exists, otherwise false. + + + + Gets a value indicating the number of attributes + + + + + Function to retrieve the names (or keys) of the feature's attributes + + + Returns an array of values + + + + + Function to retrieve the attribute data of the feature + + + Returns an array of values + + + + + Gets the value associated with the attribute for the specified name, or + if the attribute does not exist. + + The name (or key) of the attribute. + + The value associated with , or + if the attribute does not exist. + + + + + Contains a and a description of its metadata. + + + + + Gets or sets the of this feature. + + + + + Gets or sets an that describes the bounds of this feature. + + + + + Gets or sets a representation of this feature's metadata, tagged by user-defined strings. + + + + + Interface for things tagged by an identifier that's assumed to be unique. + + + + + Gets the identifier of this object (assumed unique). + + + + diff --git a/PerfApp/nts_shapefile/NetTopologySuite.IO.ShapeFile.deps.json b/PerfApp/nts_shapefile/NetTopologySuite.IO.ShapeFile.deps.json new file mode 100644 index 0000000..519f219 --- /dev/null +++ b/PerfApp/nts_shapefile/NetTopologySuite.IO.ShapeFile.deps.json @@ -0,0 +1,199 @@ +{ + "runtimeTarget": { + "name": ".NETStandard,Version=v2.0/", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETStandard,Version=v2.0": {}, + ".NETStandard,Version=v2.0/": { + "NetTopologySuite.IO.ShapeFile/2.0.1-pre.190390564+local": { + "dependencies": { + "Microsoft.SourceLink.GitHub": "1.0.0", + "NETStandard.Library": "2.0.3", + "NetTopologySuite": "2.0.0", + "NetTopologySuite.Features": "2.0.0", + "System.Text.Encoding.CodePages": "4.5.1" + }, + "runtime": { + "NetTopologySuite.IO.ShapeFile.dll": {} + } + }, + "Microsoft.Build.Tasks.Git/1.0.0": {}, + "Microsoft.NETCore.Platforms/1.1.0": {}, + "Microsoft.SourceLink.Common/1.0.0": {}, + "Microsoft.SourceLink.GitHub/1.0.0": { + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.0.0", + "Microsoft.SourceLink.Common": "1.0.0" + } + }, + "NETStandard.Library/2.0.3": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, + "NetTopologySuite/2.0.0": { + "dependencies": { + "System.Memory": "4.5.3" + }, + "runtime": { + "lib/netstandard2.0/NetTopologySuite.dll": { + "assemblyVersion": "2.0.0.0", + "fileVersion": "2.0.0.0" + } + } + }, + "NetTopologySuite.Features/2.0.0": { + "dependencies": { + "NetTopologySuite": "2.0.0" + }, + "runtime": { + "lib/netstandard2.0/NetTopologySuite.Features.dll": { + "assemblyVersion": "2.0.0.0", + "fileVersion": "2.0.0.0" + } + } + }, + "System.Buffers/4.4.0": { + "runtime": { + "lib/netstandard2.0/System.Buffers.dll": { + "assemblyVersion": "4.0.2.0", + "fileVersion": "4.6.25519.3" + } + } + }, + "System.Memory/4.5.3": { + "dependencies": { + "System.Buffers": "4.4.0", + "System.Numerics.Vectors": "4.4.0", + "System.Runtime.CompilerServices.Unsafe": "4.5.2" + }, + "runtime": { + "lib/netstandard2.0/System.Memory.dll": { + "assemblyVersion": "4.0.1.1", + "fileVersion": "4.6.27617.2" + } + } + }, + "System.Numerics.Vectors/4.4.0": { + "runtime": { + "lib/netstandard2.0/System.Numerics.Vectors.dll": { + "assemblyVersion": "4.1.3.0", + "fileVersion": "4.6.25519.3" + } + } + }, + "System.Runtime.CompilerServices.Unsafe/4.5.2": { + "runtime": { + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll": { + "assemblyVersion": "4.0.4.1", + "fileVersion": "4.6.26919.2" + } + } + }, + "System.Text.Encoding.CodePages/4.5.1": { + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "4.5.2" + }, + "runtime": { + "lib/netstandard2.0/System.Text.Encoding.CodePages.dll": { + "assemblyVersion": "4.1.1.0", + "fileVersion": "4.6.27129.4" + } + } + } + } + }, + "libraries": { + "NetTopologySuite.IO.ShapeFile/2.0.1-pre.190390564+local": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Microsoft.Build.Tasks.Git/1.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-z2fpmmt+1Jfl+ZnBki9nSP08S1/tbEOxFdsK1rSR+LBehIJz1Xv9/6qOOoGNqlwnAGGVGis1Oj6S8Kt9COEYlQ==", + "path": "microsoft.build.tasks.git/1.0.0", + "hashPath": "microsoft.build.tasks.git.1.0.0.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/1.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==", + "path": "microsoft.netcore.platforms/1.1.0", + "hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512" + }, + "Microsoft.SourceLink.Common/1.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-G8DuQY8/DK5NN+3jm5wcMcd9QYD90UV7MiLmdljSJixi3U/vNaeBKmmXUqI4DJCOeWizIUEh4ALhSt58mR+5eg==", + "path": "microsoft.sourcelink.common/1.0.0", + "hashPath": "microsoft.sourcelink.common.1.0.0.nupkg.sha512" + }, + "Microsoft.SourceLink.GitHub/1.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-aZyGyGg2nFSxix+xMkPmlmZSsnGQ3w+mIG23LTxJZHN+GPwTQ5FpPgDo7RMOq+Kcf5D4hFWfXkGhoGstawX13Q==", + "path": "microsoft.sourcelink.github/1.0.0", + "hashPath": "microsoft.sourcelink.github.1.0.0.nupkg.sha512" + }, + "NETStandard.Library/2.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", + "path": "netstandard.library/2.0.3", + "hashPath": "netstandard.library.2.0.3.nupkg.sha512" + }, + "NetTopologySuite/2.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3ajBClEI9wx2/DjjGmV52sHW1m52vLg8sdz1pJbTf5ySj1X90qehQs3v1DRwGo0F8UKj/Z2SjNhRN/6LroAkqg==", + "path": "nettopologysuite/2.0.0", + "hashPath": "nettopologysuite.2.0.0.nupkg.sha512" + }, + "NetTopologySuite.Features/2.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-RDbEpujDL0bsAyTMHlbKj36KIPhUrtSGUaO/jUjMnsLcixrJFwoDJ8p717FdgMHpQDrcEJAKF+QsAlYsSULkew==", + "path": "nettopologysuite.features/2.0.0", + "hashPath": "nettopologysuite.features.2.0.0.nupkg.sha512" + }, + "System.Buffers/4.4.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AwarXzzoDwX6BgrhjoJsk6tUezZEozOT5Y9QKF94Gl4JK91I4PIIBkBco9068Y9/Dra8Dkbie99kXB8+1BaYKw==", + "path": "system.buffers/4.4.0", + "hashPath": "system.buffers.4.4.0.nupkg.sha512" + }, + "System.Memory/4.5.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==", + "path": "system.memory/4.5.3", + "hashPath": "system.memory.4.5.3.nupkg.sha512" + }, + "System.Numerics.Vectors/4.4.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ==", + "path": "system.numerics.vectors/4.4.0", + "hashPath": "system.numerics.vectors.4.4.0.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/4.5.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-wprSFgext8cwqymChhrBLu62LMg/1u92bU+VOwyfBimSPVFXtsNqEWC92Pf9ofzJFlk4IHmJA75EDJn1b2goAQ==", + "path": "system.runtime.compilerservices.unsafe/4.5.2", + "hashPath": "system.runtime.compilerservices.unsafe.4.5.2.nupkg.sha512" + }, + "System.Text.Encoding.CodePages/4.5.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4J2JQXbftjPMppIHJ7IC+VXQ9XfEagN92vZZNoG12i+zReYlim5dMoXFC1Zzg7tsnKDM7JPo5bYfFK4Jheq44w==", + "path": "system.text.encoding.codepages/4.5.1", + "hashPath": "system.text.encoding.codepages.4.5.1.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/PerfApp/nts_shapefile/NetTopologySuite.IO.ShapeFile.dll b/PerfApp/nts_shapefile/NetTopologySuite.IO.ShapeFile.dll new file mode 100644 index 0000000000000000000000000000000000000000..ea3844142aea0f326724f84e5529ebbfeec7868f GIT binary patch literal 94208 zcmce<37i~7`8QtE-P1GEGkeU=?965pb~eW@otfFqW^=IN3L)W02uC2mZnzJDgri|5 ziIQbQf*8&OIRuG-NfbonPy|6mR74I%;fElg5Rpq14-`~>uNvO(_o<$qnN0xwzkdFK z?XKskr=EK1si&%*x_S;=@@Zu%r7Zlt|GrZ9YY^R-`&Og6C-#%^_lFk# zWc=dOmXS8mE6(a%dRFJWgAeOG(>wWNy$ub{B%k#m z`zWdya{imnk8&#xrw0s^6zED1OM$( z2<1BdQzYg8)wd67YIP9!9?UTKE)V<2+Sm6&Dgk)jCqrs+E&ijzoq^~=83nw5O`6{2 zAN#~|z_*?Zc@ZaNh1|9OI+Z%Uw^S~j1f<9Y8I=v-G`ws6?S<;Bli{;1`oF-+w-Ey_IDjYF5kX2Td} z1+*V8^-zeLfwqqfh%KKu17xMxent5_GYjay_ zJ4O)C=Mhyc?V3lwF-#NlCL^bOhgJpYQs6xfZxg)R9K%JMvWu3T9Yi=DgzY@ii}sFd z-xkUrs)0^w=Qw!+S;+xho%|_KV340_g&VELu!~~Z`D2Y?G5%__S6~W}#ZrI48!acv zByp&(h`63+T|tQ!!)-ua79xn~K}2KtBT33lNZ=Uuc@KcEecpHQbkQ8`M!RR8nVH(A z#Wb@+UN0EhUJGr-$mGpT|0J`f3{x^b zIp7C7+#9drSX&2RopS-#=ygicu7RWl)#)f68Lgv)#*ETYgU(?6IH)dVWm4fx${zSE z>m_MRp2_e~Dgp)BW-<~H9d@N+TavL>;Xt3! zVzZA56dDUqRgF3@B?p`${Wm1T$;es77Qb`EI})c87e~+xIwTdXeFxdD;1TNlXojSc@|8 zOrl1xhQjm~Qv^#{T9~9&D;gk?%{(Luu@eBP-OWfNqW%D)nxjPZW!*!~S-m4!IZFNi zB`a&`KbQ6U(5q9`Yn*zu+;**45kGDLWx8WNLf3E;X%SV$XBui$k4}AVi=}lR_I0m& zaNjJ@v(@Q7taWc45<^uqAXXR8(p7N}s=^vw6@Fcupbq(3wJvT!`Cu`=-T00}yv_E9 zp2|>!K3K$$YJ*-hTKEG3;mtrIjz62Lponi5o2nSG9`wsqOkE*vA6cD5f>V#BKo|2#_M%#Y{}RIN%Nf&c#$#WQ#C@szbyfwGkq;-&iIiqW_9) zepTm^<&LUBo}isJ4}*wv0{xP(LSf_|rq$}~_Vq2O^e*516aV@0vw+#smDMS?bis+F zr+0Z)&|{2YcJ&%^F>mvITSLL~VWlO_74YN@$1X+<+wDNTS;H z>o&5pnth74t={qkFj)gFSosO)sulyvcN?bVVnlS{@Oww#?e?++0FER8&)3HM!W|?9 z6AdvSiIy-l6DTI|j;cUR;T=r~$>0x5ayY?ueqX~q26z{)we4bJ=j3lQIix5X<#?u% ztjJa%$&Rdjka_0ZD#(lnka5W{IpW%B_c(}bm?IAKXILZXEv_*(AmLA(>h*RmfQ#K(j9+Vtas_=X+E?-ay02JyB0JA(M8 zAikD=E*20p2L!bYa!x>y3<&Bt!~=qsfS`^;A|OZw1YfMtVXh${NCyOU92x_H)_|Z+ zhNgfZ6A;vKXbuRfR#01yxnw|4wS&4WS^|PGK^Aocseqt8AgGfe9T1ES2F$8w#99tjquwPTsN+zz>b(Mjx?<)6O&%B!+*+GOXFzaJKyYs@!T5mS;DF#8wFDCa zf0AA|R+!bx%NWZa`31 zS-k_HNyi#jCGXk2&YiVAsrI{Jf{HT`Zjar&r0-7J!(!5?vGZ4@`QA_jNDoy!B zjNEH5+*;+67=p)VxpOfRXWWwkyL%%z#)VI>gSjKC;e5Y)3h;(^DxUczK5!a5R|vZ6^#1l*eLE?ohSB6|5J5bb)P?cS;)Sd@s^8iU$;!&}a$?fFe~vNB{`TR5XPI zSa&~1y@4Ea6S8yc+}=a`z;jfnAI<|6mWF%z^er?F}|q$_h#G?}YR;CljAv@sj9^S5Bl9!ju` z-1w2PeCypka|9DS%gC&c!tO_M2y^#k4BxC02>`KE1t9?-m@0pkei!4V-$1-Fnwql; zi6jm*m>*~^5&&Wx5qL9yG;q#kZ$rle6=0oa38d`7UIBU*+r{k54rltzY_plgq>^%N zSehLaDdU-jLXXD9Hrkwy+n98aB({;WaeL5-#43m_F)Snb5E}ktkqR?0-Yo&RG0aK3 zU4Iwvy`?XgSWFx1(Js0YnEx%kw!(!+qwoOb(NG<2toHtejba*Ij>v2usa z*vrZ-oY8IN<__(HqO0TZHw87iH-_0O@J8%zFTofGW&mO34%+Rff;?=u>p?isDabRJ z{v@3q#a4g9pMjWzh4hTwZe;qu;$h{^+HHd%%e_Yryb4TJqTF0Ae%Rs8ZAiW6Yls`W zo;_SwrZmn}XJayDV&$N;mxRYOnJzjYXG>Rm3Etb;TU_)!j=LIb$1T{Qs6wRrC(2ssXh6+VafP<>~1CclqCC)fHqr{!c-3Rb*~o%|Dmk^FBoU zn`L;bK97O(>UkdI^KALImGW}9PUuD}GiBdEmbLcw6=ww%_f5uDE3R6!j97Z370wRr z`Ab;CP8CD=aDJ%>a~q3PDGO_Y+CIjWdWhapHXxLY3N`H_w@_;!`)}9UiVtF+6{{%h zRQd@hnhfbeOaDUHbl1QF^_W%Dp8c-Eh)A!8ZZX$c=^K^|>MpVZkFeJ>>=Eg|*l$_t zd(aaGpJc0(#U2PdAM{T{(my3KvW<6|>8(Y+Iubn-`)=<7US^+xF?|?NN1_nV9Xiz-KGae+R?+yFbA12y<L1QEI9 zl@=XT8`}>YfO;ZEOhzKpyA;tHS?0nZwrlkelVbt`pjCTd%y2Vb$LmOGtw^@vs?&-7w?aH?(@6#YE!ggi!&bPaJFm`XF z$1Y!qm{o?mClN@`wRw#9^v9Co?;A*c6=-^lF^(-hhjq0k)5#KdJlKS-PK4K?OrXonlo z_i`>Sxunqi$uj0`LsG}K^a?>g7m{|A3pLU(Di2WTs~2BD(sMl|b@XMUF8jmk=*nsvP!-XZ8D zq{GntTfB5WdI9YW8QwvNEZ>Oi;t}sAyc{`Q6k*Tkya=an4rEJgjdcsN#8xHyVrb)r z>Q}Md^f@7=_EoWiRSdp#1>8QOZ6J#k}$!;ery_I8BJG6K@5vlFaBAO(T zw$qtRCYnyC%ZnkN@R|Z%$hMxBl*;rz4_VD}5Box$G!i7`*1?%5f_n}g`CYjWfjNN> z((ZoTZVXUS>SH+w?4kKH!$%F$FVgNdpeDyxh7?m5)bxy^yL*Wp@T^AEIRz4JpvfP!# zoM@OerIVgXM}Qagjv0dd+mYTa)WW2APz%<`L<(9{85s|5HDo5fyaXj0nS_w^hv@T_ ziL$dMXI6P+N4h~_dLZ`G>1|4$_aPUyQbdrAw*?HP_g#wqw;oe$)R;`h`vR!Cky;3r zBDGzK#CRi-n00kgEVNK&o|m%|`x;82BN6%LRpk>3hN78H~kWM8Fs(6K@bX z^fs5iiujVG^9`?FKDa$ZL8_|zhMYubwZ${j- ztg-qQypv(^Xy`541A8MW5Q`A5PP+91%oqdR-j_xvNHT%t-3mM>U3Re(WbT)%WZ=gB zj{b)|@G5GnLOuME)b|SYis`UMVS6(}zPNR4G2Dagit|a>g#2%2h;tshupD@g_zdvN z8S)uOc?*Xl8m^b0j3G{_?7|+vpIb?GGeebRYZ%>8+9#pT1`4eP2jpbBSyN3s8X5C$ zgA#UKzU}?@x29t&`oMy|NihQ7!*6T#br~7LX0cS(v0&T2kI8~#w!^6y%sy3`?c){`8)4wmQUJlAT_NyKbMe<2k)Y%a+0n_5a#V#dtQZBNYGBT2h6iy6V(u?50f^avrhlV|SY1!z$ocv0|#k|b!NgG-BA_VZdkT3Te zjLn-x1TO%B`O%+C;>~|XM(DOi3>R*e^CIK*n2f$X#^a(GSB&AEp?h)ICD3i;+TFF} zwkHN77jZaKFqtGEm3RB<`R#i%XayjWZJ$Oy(?Er`Nu^~qoe;9$)P548z3&I0G17I&-49UC)klyTk5r1Kf4kTYy4PCSx! ze?YVok?0;Hl9$fF@E!)b|M|4GZ$o_!{P@qvHTBIm_K6{QGXD0*-!l9i;lEK*fr&c? ze?~4ov=8f{fIrM}#6I}$C++|v*U~%7$hB%38Y`@i>l^ZJ#M{V?>&+G>80Bxmv&$Rh zhxO~r`gIpy<*)MzNoju+i2n>YO+Vv+xC!N0ReBvkqx3I4rAg`ug`R(uA`NxeY_@zD z7@F>lwCbzKsOtLDeN2L0vo*}}77`&p?thJgox-ET9IG~OCYc%}p$}Wb0GCcS)27Yx z4-HAKZXTRxM9@CXo$#KJ{k2?moig3H;qmc!Bwjyc|AjEy4jI0DIN z`A39f$>?YYtr3HX9KW``AA=;~Jwf`I_Y=Ns$-3vpt*uF0J0mzb4QIsB&IlG-BHm9y zXj39vPWaGU#JFYQyuXLO%S#q?*w;$=*gj zk11H%r7mRI7B9BC{h?&~2C{Y$W-sVn( zJVIx0!EwZ~8iDcL=fNb=ja&Q)yRg+<`kzHM%-;JQvzei@5kbx%0$n8q5sJ5nKu=~F z*^vRf^19FcE9}p#>IxQCHP{`h33hu9Suq#rz5GW4|6LV06&0X6sZoKwaf|L>v}XSc zDmc~{ri#3$VIamZl_SCYgNA!Eiq(U0^A@~y)N<5PNGw^Ws=_e9VOmfIw~rXyB+|XRtgN+X|ga8 z84o%uHX@8nIr1kSsVsBjIN)<+YSTqwPMRR!i`o2L&|Vr^Y0NAmU#uF?)Xk0htYQ1= z=aEpiS?Evf5CcrggvQCpmYgb;PK*@I#1h#HNZ9`zS6?a|_d`|?nBy1a#aIAcSH-E5 z_ZM2;3N4a-FfArUEZc%wW-|BV+}jY}0OM0~^^2f`GIx|?JW_s%v0D?~R=j09Z7ZbJ zXA^AI*{u?2L2@>Mvcq}#V0nI}<)KZXC#dLb9L$5Nwe=#T>HdiJi-lUh#V~He(*74p zhjTP}89Y|uo>xs}h<^J4IMa!1?x)O`({z1Q(Dt=t&z4Fq_OIPGHSV}4TgTDZMhcSwNjvkLm{Mta=o=kJO=xK6fXhxx*(W_u)FC9;U0GX;;#<_~|~W(|L92G|^ny zde(G>W5MbCdZI>_Z(-Ia*aHM;0JRDbf_WW2!MM_IVP^0bFbp}RzalI<&wBA$_Q@~{ zoqaXdL?W1?WU_h*(S_r|{(*O#PKB(f^`xv=V)2;EtFmA!E7xePi@_O(*=u4}pk|F8 zGhJw{K`tlK+ZPU>cOtlNO-GBkwt$Yvc@ej1{q=5S8X5;Wtk6wcq}MqO?5@l^N{4Ab zb07~oZ(kl;Ta3Y*3Eh$C#s)h^o_Nle=YjG(7*DA&@d_en+s}yY!iUw9H3`6okw_yX zfF;(|zolhi9Kel84B*uh*e-?xc68Nc*D!l_JAbKmq%hAT56t@Zl~=gD60swY&0mK+ z9F~cG41U*Bh(LdkYD9nVJ7l-Y^x%JRx3T9FI^aA<+4I9|yJtb6X0-LumHu zAAzK+C)>UHaRj#66VTqve?mrGYZ&7im{yEDh7j6BWS9ZWL0e#pBab2+_5KV}th=U4HiYGeU2Gg?Ou z;H&dZIIJTJ8PpCwENwqp+9o8%1`F@C+d9QC(+LNxah^&V4CgkiktEm@{oq%HjpXQW zPcus$bd0B3p+o7U;s2oHb=>#xxS7}yv{0*EF3PbDH$-sT=tx9vmZsX?|0g4oxjxc% zeI$E*WX$#D|3%cuK}dr2HEfcTvRk^b_WnO(3i;9H=TOD;vPL5TASi<%Bme}37lZ_W zV95j_0s0db>|h3T&ROSQstOg#)@kw5KZ*MUs26j^)!>%1RSM*DJHv|Z^~7g1es61wRm=ykL! zk$fifRStm=UIt0%;b7F~9v(h2&Zp_QGIrCl!EV|g zStebE(@}<9*v^8c^j(Ooo6@NHpE-g-hpTZs}1o5%SP$U(@l)$cr3|QD?MV~9flU3Ok470~YL3qFD4ZkYU zub?Ng4XY|&R(AGA(5pfC(%(@$5xc9$>P{DIKlX6OhDV0@GKNW8hKB5s#Tvm^CNP%| z2}pBxVSE^($g{W~*fF5l9iiFr^&hZNipq_>Ox`PMic~<^(!0gcYt*{ zOmSyj1+*?orgFSP$LQV2Ff3(h+fn#FgpfmCbUl_YIu(#v)}{}I_$Ap#ziXJW7fm8XDot^diU>8>msdZ1+WY zeb`Q6DX~5p8DSu=;fNOl3HGlmb_&~lkJUuqa}MO$74n$k(SV)9!r0=%#4UQ5wozUI z>I8-j%f;Yei&yzc1Zs~_u+DWGZ&l-GR(wfQ)=FsumMp^ZAWPD~vRfRv$Pli#I{M#& zlVReBF;_oj&I}#NoY^eqjOuQ6+p?n^(_Sjwx0y@G+t9taQ33U7l!^^51)trJf4H)C z9M-NJE+95q?9=T$zDx1~@^wsn3#Trtf{|GkH*g@AqX^t4zD!)Nj`#v-j1@M*qBZY% zO5baC_1N9=)uW0GQz66dkfDsZvfX8II%apF{b10ry1Ibp|km!38_cIlI_@Z8*7TF;lD$B!c#hA^g_fE9E_&hQ%WP8hQ5X^TOa z{jVB4c4r%0(y6#Jg%$Vx*<>6t#1X^AlNafhp9?AJB!JazpzXPRYa$tg!!C0)=f!ADru)9M5z%Qx zbov2<;T*U_^wGbIKXgGV3tcDh=0DCw&|pTQR!n%?*=g8Irr0r`e>3?TfLf883$ymez_85i|KIcLjT$i*tpvs; z`PS!-5;$oO@=F;bvTrn}u8b_3V~;9P+_bgIx-xcl=q4*tqqvA)FsOp_pRm;X-sA~0 zMw6&+gHjD9=37*Oo^OGq|8-yg9_m8;Kk~pxrRI`{)>F9^agIFWH@0_JJ{~3TV2n;rhOM#2(5EsYckU#eHHm5Bk!d5YSIt za>LM$^?7+EB6d_fJS>w4LO4mNSw`?mrg!A(^`Sxt9uOt1wNRLr53R}m3j+xf(jaF^;_-ajS9K%s82xPrR5O+td z$Tic@1A9$?n1xKs%>M6%+mCCX<{B=H$i`_FtB`Hvs^p;N%B~R*_vMn7+5cL&6BXot zV67%qSf>hCQe~OSKjnc`m@G+$qSyEDKsok9Ik3LpVd3~Jx;;G`BY>{opPKP7iOCVc z>3>0loNSnFmJ36~2&N+v1qc=4B>!^}1N=^Au8lyb5elP_~{;nkgh zIxEJ5Hku0K@U6@PWe%9M`k$`&6Yw9{#*?Pi67nV@SRg?G5*Vg+vQ;5nGxmYhEh;KsaMSZt$oR9uK!v%_h~pjg zhrQk`zB-r;Yi2rGrFxQf|EpnpxEonZkrBpVqQm(mR#xWQSOR$fjI1#(Itx4hH)~7< zO;6Zz(WYRof`fOAMJGK?x3oiu)ELu()a;L5gFYZy(i*!1My59z9I}Jk@yj?^x<3l6 zw6E;tL8h}ay#h03HgXI@J_`mb39tzq;=+n7)!`x;EQ@($rVjeZ!3t}v2J8mgC|1~w zP8jp08=BHQI;mKTj_!W|d&0i9*q{6ydcfyU|z_ApDj!viByJbLtJ!u%fu znH(rd*l;#jPjY?4@!*U)Rg|aRgIDc1h)=RSfZ(m!UW&(_QFHjmaW_4 zr8tUYi=MST=)JacP)7bUR=^1j6_duOQ!aU91&1$2@LjDeM6ln-naSmRS1V1j$m>HS znW+ti)`g2v!_JpJ$JyI3BwK|%X;Ub9+QR&>^kS^v-n4JLy64p=W4;M9iPUJ4<=7o#HTuLIwhdhjE?KqNuu_pg zbVh6T*Q_*6|F8V)Y8zyoc~K}+lvybi7Pi^Ccn#+BP$n-P1Uayyl$znOQmMNP?kCyO z*ri2P0DP56x5?hq1AdXh9DXuST9vpHY^d9%j|#JD`Zhm(;QoiD(e~dH3`nBH*^6;u zVU!+!j#6We=bRyZ8UQRmRDo@^!21Efl|GK&w%o~({lgoe2L3a(O*a@i;G&DP^QN|E zB54IK`cNXpmWgD*MQ2YWCO)AekqoeZCK3*SMl#@HI3W@~hDI{LL4ruM&=Ah8JQ=K5 zlv2rx`E#EWjhE-5lD>VI9uB?AG0iq?GfJz{dyO?_!ULMG=$eYd^M*C}^MAPQvX`uR zX$mZJ2tmIFUGVY!5<~7;o04}gGUb7m`ZScUDd0(~bFx0W##}nTYi?49bb&GS_nsxAvOhf@$G&!&IaQw@%&7FkI}4&00b6Ow0M3XQ!a23{t?671tlxmWoQ^% zjK#L?^_9_u&*~K5g*6GyO9Dp(RWOe_vRo8|2U}fCw`~tvb$F%+$xvlFnFRVZK^ZpA z20>fLTuuJr23(y?T|O^VhSL)-&1M6J1!473^2jXnPzK!aXNH;|a$8x+O#;Fn#_aRQ z%-`Y4{F`L8iL9h%onmw8FF?ZQbs=cWXTVBY5$^|d?cnU2`_hxA&sO9b|R+e~I)jd%nxruL9m!HBq z?r6lBr8Si#=+Qm}u2@MfT@0Lm+tpnnRMktdRjQghvF@=#b=wYj-Ce_LP^g~Y0oBVj zR7ZdcV@;gjve5O4BaHaebOyJ~((Yo$YP&)k(D5>tYP5=t+?{JqRqDPmT*R_myyR9f zxHQDWIC};d)Ve6pa;Xk1go?%*BT^!xF)HOZ8e=YHHyRyRq(eQft<<9gfViN7kN^;$ ztRN%+1S(Bey#!Vp!)t)(>S^tkYiXq;Ae4MwMy}RLCqx2TA}U6wlmHOxDhLTc3v6c? z()qn}tS80L_#C_Qq+4E|H)AKe^XEssTkJi}?(Cd!!pz>)8sB^Bz>}c2JLfd~^|BeQ zcITgdcG6|N=WDq4w1K-Na-V}cJNaiigjsl_rk$ui3Xy<>4m+_5-mZ4#llp>#phG7(BvMYU&ra! z3HmjpUq|W}PFV1?^0G>|<&}XLxd@8Fu|uriiXtzm=uHCs#xUbOk4ZZWZx6QOzZk=$ z_M^^1)HIxk$A*Wnk~r^dVBJ&j0GhoI!e>srd*dwXCpRf|h551p&;$6z(9gS+n5@yzA3jgK< z`yEWD_+4hmxgKQjrp{)wkRI5~OldB?46xLg22Q$6pWAWZhRq=1jFHe@0*8K?F?>05 z0@CrgdDcHp5|-ML8h19%177d$Vg%ssQb282hR`y4c`PNlD1C@POM`c5vU zXwC@5@-J&LZ%wGB)wID`Cw%UnX-6G%(h2g&h5K3i8H)Q5$uw$TiZY0z;0V<-$OYuEtCDWE}o$ypdI)4IT<-A;wmn0SOM-%vRWd43mv=Yz}s z_(ROX-bOqR+6|+d8aQ3JOP1&|c#Xy>EkuROT^$eO4;ESmVnN0rMyqpDxYHRh zN;YPajsB+tZ0NjRUB5ycxLK^WGpjvrz93U+LBH#(bvM8V9B_Acj5A)XkhE2?yWcoN}bh~vnyqH z{s!z*4ao*APQr!8o#KRK;_@>jWg#oyF=`1{FDv<<-oX6uS?E9?Vu{R7;3OVCV<75a zTbhFPVCGkYiVo@T7huq%Kd98FLzBN5GW(Iy2HkLb+I6BL_FS3Rn-6JllAVnjKLdfy z2>+%q#!&YYY$TK(_KCFu`R8{w*2opiIy`a>U+#tMEX?x7c#V7p7>uvejq(EU9=S>g z4q!Ih>`#H9ypZ8x;=KbAWRr46J`E6Cwk|1ZuM+TiuhH+^Xdpk2%$uy`pI=be`r6suQAL5dY6OHdl}Uroh6g`oh5j( z|5%MT+L@dII)vTgCR8Olvn!DpUu_y@d3lK(nxH049;M)s*F*8b=K(NfE97lx?33Wk zoA!=t0fn7y+zu-5gCRQ+mGWcd8<8V06e|+lX5$L8UB)2i@JBHUSg99jjbSPf9WiUG zd@We!Z_@d~zmZPcmyYp3ofrs=am186TZ>T^U1{lUCWICxY@iY_vf|steGw1dA5MG1 zt<`ml(HK{qwia|oQSTNIN4+mH3EU?vv)u-b^gLF(84p9GepoMhJ~LMBex#ny{7!SF z-HPR4kcSj37Eyf5$gBk;N(8)=MaAT?a%9J)g~DGn<@@}|<^#ShF!EV2#4Kn%$n`lK ztYr`()&2^qT^}O3Ua;Hjt4IgG)@dul?Qll0Vl8Jm>&D>AK=h%u#bK93z9k)N41W%M zilIF8!jR!!gIM}_l!oW#_3srO&bo20X3F8~5YvMbCM*EfI4i$c<45pE6BtuH)T0Nq zE|h45No#+hI-n8tdoP zr26ORyjWKYfIkv>l`%-dRW(L_4hFV4g3cd0VY%&LhGDs%2rSnaW+ixV*d2SDy+7Lp zTtUaR*)DV&-5-4UPxGixj^B%EMuQ1>Y*^awHx)SjXvj5D=Czi4B`b#G_*(EAgsd3H zMKUvY^0NLEzM4-{s_}W^r41DIW$6_p5*tzx+}uS~AZb8twl5p3EF5U;&ZsLKQxnq@ zOw9701#^5I1Sedu76k_Ub%=^CXQ;haRO-!?@26p{2W|O-DhSPrylttV)h{3@hXkHS zV4Hma^>`9A(6xp!ZUoxor{)Xs+69S7<+mxus)56F-iP|e952mktvHVS9v+R32a@>K zgHc)xk@BvC=yi-6dQjE$8jguL} zr*uCHspPN|TdatIHw6bQk@?=zm#B;qjR3gokpQ?cnTmpd+o*A$B2MUhz3h!Q|8W-k z4@Pbx6I~`h>r)}3E{SI2X#~YL+|Nq|Z zkpK|4R1kh(jQcZ^@+7hZSZ^`)75KAQ4#&D9Mrs`G{W)lGC_Ng+20e4ddGcp~>K$JS zXVuveIj^cw5|pnr=tIVa`zH|Mn9X`ROe1jQumP!=K8J`D?3FlU_zpai&So@ChA_?I zO9SowKdp*^h2)AvDJv%X$=tw?7g~9Er5brt<}a}c_x{Wk1>9X zDExKe??n6+P9h_nO$G_S1DllX5f4*ir?3xWlW85F#JQ@4i02!FiM+8;>d3Df5Q$l_ z2HamEPtC#1K%mwlwo}q_a3ht)F{ms@ekYki$y4ATV-MiWp3L&Yg+2#Bb{a0#X1o%G zXuu&2PWK(L!;!Cwjqs_@*}$7o=qGU2Ltk)@mkx)0`mIa$9D=*=`|F(xo~`nUJ4>g6 z*px4Ulp6f49~@&w6XcE*4}(nNVUPy_ryR~v7z3Mh^tKUBDEKEnqW#Yq z?#mE|XDGvR)D7Qmb6=^);0#*4Fu}$bFvzjG&xgJLr0s46ai#G@`(H3DHUr!JBhb2E zx5Q-Nmiqgp z{?&T?jEYo^@xfIy!RQ#>k@4Is<|F(K!uo!!dfFbpzi}S&tzKHd=T6bimP3Yow62Sb zeqqc9xBW4BBoZ8bPvgqa1YG zl59j1ZcH}fJjQDVn<>_JoVpguu_dfRsFUM9u#LhS4h3zrv((u3p)Inu?ZJa!SFTSe zyDvc@x;?QqvbkuxL=6Wmqd^-i)m=sE(_n{cOT>vV*~w2ucp_{i*z0x-025gaM2ijl z8UW_2jvOh)ho7(-0}ST2J_fsW+&Yf*e;KEc(VFVo(pa<)X-m?UoeU-rY_7G<2-m5# zb>nLy_)(J9{7jr~0r$-MZgk-oytAW>pSJ%e@I8LC?dvfd^X&g*3?F^!F`+fxHOln- zk-2J$R!dl0T#K#Wx=h7Zd?_c{g6+qO<+_+_qkg29Lc3%CA!Dca>4|sW%SsmO#uK0KmmNw8%V*?&_~vl zs}nXWi1@^}-<$BU`yPxuhOaB=0aNICKuV@FvN+pVo| zFPLsZeP0@3e>wc0nbVG3!miprvRdaK&{saKDd?4cfIH}jJ6Pkr-cktHp|v-d7)s&0w~YfAlWIHfuW5T!^_*NP*^*2)=^xCRH4*9Y z@4fd0+pMt@;XF1ao2xEkHRKz9p#j}*BH1|TVJXb%4*K4P*&aM6bUxxv`scP|v!_?x zNsQ#|(Opd0?4pBy%6$}I0sc(HeFPz%8{N>;h`Ac8Rr>G3c%YVMrzLRHGqX{nKmdm% zS0OQm#R=o@X1$31{Uj&_KQfv}v^cCzc{PG@c_#Q(tU)Yj%f~#OZ2!ItYhw4ulz<;^ zn@aC5iA3^YmMj9r=BR;!VcFa9*5FZSjMTxEQ++%rzd7Qq1xZg&RNmQXlOoZKcL9@P zNzTz{t;i(mVeu2IS#T84BMNaD%Ypo9(r6(WlVif(ML<+OET(DtUyrQ56-~~=iWGQU zf+u{m)mW~^niX6$IA#$Bc$mI`K*qa_Ad22lI4F{A5K%Z-3K{$`tW2SRtWj@0f-ctP z_)BfYu`v)|0l;Up9Da33&LQKYX$=@wur%$9bSrZIG$?mniOR+gip92N3Rof4*J(A4 zoH3?9*;MF*_t<2>%(PZ0r0|Xb!~Ck}lebhRDtG+(Zr{0Q}a zGU~m&&|l~I1r%i3!+cdOA+Q09ioiFXvBLoy*qz}TT5Sk8cU7FAu{ePx)?i0{*sfYa zgifM2GIQ~cN`68BKURnw0Fam!V>Volor!_{0MNv2&1s|5Qnh%_yCES zxm15P727%nx!efSo-0w^&bG{ypt_T>p6mz6S~*dsTgGe~#uCF4+kwpYCNSe~P8Zw; zJTPGBdNxDlmAankzsjNbR&+}$R_S7P zG{@3DNJOrnB`{^GPPn2q6RxPYtuhXSraIwrVXZcPZr5eKSpHP2GO>~$-gOG6`#zxK zpCXI%X!KEF$5BC=wLkkJ*h@yzzPnLT4I8B~r5bCJGzQduyGj)~8NC56S}8CIrGS z38UNRgs-LmyVevSnM~^Y4~+w{MB$7)23KK) zTL)P217qyZI38C0a0gm2^7GM!0zZ4*F7tN-R%^@od+%0|1s7JV{+BBwr{>xJW8P5P zDW)OJCizwOF0z+&I1DZK(X9TLV)@?kPf=%UI27i$7&4gY`IjEhQaHlRfzPN8YWa*z zSDr+&{M~x((kzC}Y;QC7Nxlq5_`tz!yz#@n@=h3$sQW+2wmah84t!Le({c8IxnS(CBKvp>WLSi_+Z4Q2 zPh5+vAr7W#)k|b|kvEoIxTncwMVSZ@2&Pt65fdjlx!M!=eP#?%5s+}A#an7l zxL5!P2g!-IgaW@>JnEtoOt#{<3PNiANhoPW{TD+NX}e#*dl~KP1Dh9YnGKHjk2-O7 zC2dDz1`ewP?L#g?;Onk((%o-R&*4Jpe28V~YY7?%OH0Pl#3EvFBSB*U-v##GY#^J$ zqvFCkZZE{~Ctk&<++VXL9gD9-_BQidkZ~i|&}-uxlQ^-N4TxSP(Vh5AWbY(W=J-v> zc9ORmIW#?{LBcWHCw!d=_cgMNZe?`5j_+@DbO)oyF}kHL`nNiI45PD*Zm5fXOGl3# zl{XC1H*2YrMer+6N1b4&2wn-!SIICqYb~nEpET-Sf&^49n+BYX;hQ~RzWE~waFMK` zFe6BivT$e+pWcZ#hGXtmQ4u)!T5N2zVv!*%x@M4l!QyQYsb#zW(aKcbmkAr$D!jnj z{j&d#Y}poY*(XDJ}U=%PV^CuUN1|92tMl%y42FqDd# z$!OaWeawV5&pqhlpx-l~UtNacO26g2eZEr(y&n&IUxP9dg*3J}??wn;W15NIV~ND3 z8?iWWUk9$|Rd}KJk^BC@3&ou_wtw8y;fojS(k9k1y?a0{sEXrm_5a4#B=*ec`R82B6ogup- z`Y*N<9X^7{jxkdUk1rnK?mia%tJ1^Z=-OKSZ{)c|-)aVnwz_own!MFEhZOiVXFv%D=C}92YQIlXXCxVY~yQM!Rq5Ma#xG;j5>zI3_sR;QJZ}7;f-M01HI# zu~7x53f;c~#6jo36N_=^?h3gCfcSa^A%W_^br13AWB4vdFgXYomJY3)Sai3Mw`(yH zvXAWx>5r@+?5{I%jdF))CK?)o??g@?KsV&MmCVu}|o{I;28N^z}J|-wbg2U)Af8 z2YJfaw1IEZ3{3YMs5$&Hd$t1Kr{T5=e7}arXxJ)t7-J=f zePptoIQi%+9{Q{M_Ut9XKX0^aLeYaE{-j6whnbyY%SW#-HYT;`Q{Q{qjDH>>gPx2O{- zH~Z7_D1PN{Z_h(;?gM^0OKkezkz-qC8b`WCP=c(nQ!oEPIxHFC*I|ueOse&1YGe5O z3?7G$q0*P289YSw1@(w5SXV^C+2KnAep-xFc3%Pq-NrzzBMgYRsoB591Zk;)NNCD!J=$IUdj>(beSj~~>=m1s* zD@UTE16cp9h`R)$^q{4&NN^42qEH`vBs$6;?(``yp%geu{(Y*HT$0V1WOLnlXt)yc z11fSWXcp$KisCwWcdSQ;8RA(Pa`VqhV@cRQE6s1S_~)e)`cU+gekb4S$5fnLa5 zPJ4H9iBun=ZqkRSQ=h$NAG!;KUjdy| zT%Qp(4|BMam3a_+27J59l%Ir>s+Hf}8(~!$ZW}u|_)&yp&z9SJ6JQK**?vfhVLth@ zMnbkd@MXrV(`53MUO%`il9gdq_T>p!Csty{Bd0Zw1B=!zIq(x4`!V%TjbZrHx|gXs zD#q|nfrNJ>Z#mppjg{GsQmu`s&njMz zAsQb$+2Lmu^Q(Qu(FgZ4!MSRw3Zh^zlW8zdfz@^f^9q)KW}p}ueAUh5HCD_jP2OC^ zmoD4~k=o*YZi!gtewP`TZVwF|x_p`pIU$h%jJ=2m!~Gtptj&m!2hnEPqzXQUd+B0ZhI>U@jG4W-WlCRbw8m z1vpO#(riF0#oYwqW{S1)PAqw2eZiYXQV6ACnG;lrcVT1=F;pnTy5YO?SOO>G|1u0p zfPqpgO#+qnyTBMmM~>SC@I)Q&hvZR-I>;FQIin0YI;{^d_m&rc@0#byt3roM>sU3m z<*03dTxrOroGF`ArtD2sxBCLBnPATCCfTckxhx{{mui`#f8nAj`ii{|TY&K$BNhH7 z@V9b$Z(r}UzG+iu5fhf*CBNYaOx9N`6+Kd^7lEI6*z(fSvrdJJrqpYn#+W@8xWf-q z<8Ie3@WlNNpHJVl2>6K(#O-~CcOr@L5B@{w$lR8A%mMI!Leu!6U*>)b{@~84H}Qvk zKXn5BAfAHm)CqWBh(EM%{;rGsuGc2KllYsCKc=_vm&RWM{=j7{ap-K6o4&tbtIx>u z&n-vgo0L%`KAgH9_*Yx_{6&g1d#5&KZFOGy=uTVRl;ZOQ34cezN6GUO^4wqWVm(R>w4aK5VP@9G`y^T}_+B@I7%ppN=f) zXjBuEO+Ah3)P|-WTit@wV>S$g&zq#YagplB6MCTG{igSHI?5SO{ze<0r(~GR&ymVe zcjSoKP4qc;8p8#7zMN(FO2pb~y67#MyToc#r%8^F6x+bF(>NC;eY5?fDYhynF38xb zO=Rd38Ln?&zMIFAL!;ogBFC#kx~3Y$uHF^N`%hoRH`K|K2V?rD4Y8q)y?dJ0l(e}KF3{McN_=j+7l<@u% z{OKftI;wCh0pT@Hthb!c*hbt9l@ zh{GxRS&U2I>zGXU&SXN(n3EG)HIY!OS}f4jlL&R9uVmbtI}@6S8Eh0eoCuyHSP-~G ztp)ViM#kmUb&}sMQwjB`&r7=5!exruB+xU$WjFO>fnFKE!s-bvP`?mpgXF#d( z1^Rs#p%rQmff5q;akWoqGvxj;;*>g99VpPn0~%TsV)_17WV&Z+A57lV_n5j>eP1ZA7s^`|JQTzok|E`n)lWscs}VO}eMLPjl%En=?pE&zw19hmK^R=SgHlQCoFlsx=+Q7IP{r?!#n~AZW^G6CGK0Q$uN;F ziLqk7dQi0*VL+z}^h2EWBjxF+rxEoC`ZhvY@EuW)5*pu(!?jHJI3c9#l5{^-6Kmq0 zQm({(bsWat(9^0Q(7ym(seY#VB)@sxytHD*TW`AlXam5F-ryUC3dr`jt8iluCWEozN?QrmF9^@1IPn+jlu2 zIbJQ8x+ob^myJCf&o%PAzGn#d!p_Iw`TL#|@w~3@bUc3-DdD-_jFri0Y7gUFaJVme zF2aAytj6=c$R*%#NYhL!r2e=08iX6BuEcYsozHuwtxO)VW)8xO*1SB1&qrH{|6LQG z@s{iGTvcHBUBu$o^W^!JJj45E&&6}F?*`<4WcOw~zuC1Jm;<_QMwqeVRoVTrj|r(? zcif5au~9xR$lrkHpL)NRJZ#M&_DVe8%B_Ut1;ie<=HBkZqlc{-*LpZM(;r8w@j^dd zy*}w12>)x+xA2@l`9VAf<@xr+A0YgriOlyCC{ajFEHIao2OjlvS+r(%Dc!0mEaO-y z@8<+_w_r9%_*x0yBH^1QT$b=92!~W^))U}A$$bi8mNBG0x62<K&9K zq;_h42G8H*S%WVOFcm4st7jo+NbMeHssna<9^pmqOL$K1VE9A{-_*1S^q1}YYdn7; zeBSO@i9NFoVb;{Trf2Y+JB?4Hjn6xBd=>=rSCirYk>?xod|RHoS;WWW*(%SO@|-Ok zE($aDaCx2}&kOJj!4CfzUcBZZ(dVu)mTQ7MKjplEaC4j*UKOQX9Ui0nI-H0R!|)Mn zE``;>x@PdXsFTl-&FAA8K5fBI!ZW0PJC2qUbNGBc#^){aJX4;R$n!CIrYHRlv7eq! zd4B2q3C}~M-hU~!w|vsOz|4%?iCTWznrV$!?@a$+X!3=26RTI}w9uAj*wGeXz-PSL zN9yJ4lNwqUt+~@|0nOS;t%%(uwRV)$LT|$u;K_5m>UU^qhsPhq^G4)8UNuKsS}L`3 z)PxBwN38k&EItpK!Dsil2}t`*XJOB|je}w@)KSv`2?&$t|P~bNKwFGXwO8fzNp5%Jc5_U0dJ@ zhYye1YK}ZFm*-vLs287KNa*Lbp|kZ0As7Zwv`A!WDHBbpF-^3p-ThJU!A!I+WsP*mAaT` z?F!7a44*}L&XnhIV~M%8W7n2LI?-jTb#2c~#@s;NA3)bby0-C^xDa;D)&$V!TP*dm zKx@?}dv0losD%@RGP-r&pPkRC0S4=#*bZGsS{D8Xp!q)3VG%mkhYGVudAf$wyq0_5iGRw6_SzXWqc-`_@hv}WX;L>$63J9Q zJj_;gj}P_CT$pH8ALqcP)~VwX&$YCw%LC{&==E%jPmKG0;jNaedIlpkp^@-8p*A(0 zJ3xS@TIYn?)n|Pu6Mm;Qo7ML5$1IY)OrWWf6KK^x%{+sR?TT9v%1Klw4|}vgpoY^#4ra1>7H)Wzn z^L*&RDP5^a>IQ+Q%P}(5%!H_0<5{Gu5Xa3ZS{Esp{We!QDHdjYNgR{~ud?aW?k?55uEq3PL^Q@g3R1=5<|T|G2FsjpRk>pnfTyL!@x ze&6^-V-NL)Kv$|CyQS2gs##WPu2g$WS(VyLohQ(>YF_i&)Espe)|tuWSCNZTd#lHN z=sAI26=+@b;l{rkd#ks6=qHV>_zv8=KIAq}jLlX5^r4x}e>3N*@NVR}F8YVQ7cdiQ z@S%V8g#cxIh^5^}b@Mp8eF~I_Q`HTA$iaU8JGt>&a_U`>QK_=)L4dK%e!YEAlVE+uY$$Gm{=p1$EjPYU$5hE!MXOR0tG z);XdxH6{15d5BuRw}!llccm7o+XLvn)M4s|d5pVKg|pvF9j+c1NZZSi>M0+hy&S1t z^C@4+Jf0d<<~~e!p*jPS4XK1c>(ql2pGqxJoA+fLdei)KsiV~G0$r`r*_QzI?Z>z` zLSLM`JMP{N2y~_T+raCoqt%50^j7K^^<9Bj53RTX_>%y7H+8&vF@XM=I#GR8P$Ye-x?Mx+x|ZhjQZ;vhaEU(I@eiEw zTc{z#Wzx&k0}B~o-$XexdN?Ik65%IKkyW~}rNif|A%U)q{=~i{eZD&0hu*Q*13FDZ zs=4{9^cr=;q0He*wQyi#dae4sK-a3_oxhO2KwWbfQQahWHX(?zX;0|5QOk2|fOlyCdc)i$AP2ARVfq5T`)Okbrw zr=i$IkrxnmlMh|dPH3}0>!PQjkGx9V?x!0v{)lwX`_PrGXBk(kH+-ml+&k%O)L(q) z_TKl>pHYAFp&z7;){W|aeduRRk=Dc4XW9P{?*&sdZRkPhjwWi+j^5a z+K1jVI$J-lF7}~^8&bw5b&n5S*6~hyvwF;jo{V(0Zc%MZbPmTg6#fQ>O7k4wHn#N+HP(mbOk8K( zsrq~?60bk06NR~n!3z~hM?WM)o1*4?D_6iHwv^adeg*%TJKgj z`_P@}!R}Uf2((tkl7}JgA%U(%?>5wWk9s12PHg>#T6PTOWZYS;-&E%X(DK%AsRTB( zb=+|4x7Cn9>!L%*;XCRCA3AwrGoWPxT^K!PmzKzbs^mlG>~dl2gKAh)N^kmIbx8m{ zk^Y{#F@T;)Kcv1IK$o@tP(7m|^n=&6KBjIsp0cb}J)tkOKCb>DkZw6YQsxPa)BXI9 z)c2svLRW>4HF0oA_^f1Nk|kgfq+E06BG~(n`9GKl5E&bfLLv_ zidL$&Qmw^WTWGb`da3qX+gfWY)!O>iUaa<_)>gjN)=Mw?t5*H0^?AR~d_KFI1k^rH zpFf`0>p^pN&Y3eaXU?2Cb7nrXpUq2Q12~5)PGKL*`l+f+Vc#hFxjLc4EtjQ!p;lQe zaNqIkfvtD2pB%p#SlGc{oA8~Y$5hn8Ou>D?;tuvSV*OvL^BwHZQ#G)Q9jp~A?BnWk z2U}mJfn8%U^zVV9C)ACdt}I13k@|+kpz9SyzgFKB%&vI9Ru9@d^{b;EM&4kTTkg?G zzgCx}us=-tttyX59(FGw|5IwZgT2(SyXYx3$6^?jpBFu?7NoFW7vUr;g*{vJtXkOZ zwy?YCkE+dLvXVTfw)RLK`mh?`L-~_n*DBw%my4cPZ>F%N9qiKliN*g%Esv5jsg5Z>y7&#X$-#WnXBEGxu5++M$IL2zTm3|^YgIvU zZSlWU-g&l#g5pMOE?ZLAsl`TrNigdpz4|sMZ`Pb8#a_L>m*p-MEoJLn4n{3y>)nFw zhL*6?*4L)6-94DL9pFw8?Z9{f`i>w^V#Cbnm=dEwd#>M2Z}57p9Qls=V<+kV7t}RbG}}D zw7zXSId`l0QQs||p}!a>b}7d8q2lB8w^Gee}bE3Vc{hum8JSzMzFcDR@-nWxw9wAlaF=akgzPdeCbRTE3*>(4uwnS4}9qi)$n z&fV&+vZG6y^i?TrR>_I_&JT2MY<;bRaTjv7-Y?i*wYA}blJ&a$Bes?w z9{W&WgPtx}GVs%5pYm+ba|HWScCz7ZwNckQdHWj*fSqFV^hnm_o^$l+4t8~DcgZ<= z*eUnP+&9c7opj25Hn&J^(w`8Fy}i6-v)=D;vW0eir(nASCzN0AY1iLz$~BZXns$BA za!Pw!G=JHe@dVr3qNiLSST@@W>th8=2H0L$R}04Wt}f}&dn^{{#l9+{_d1+Ir9~>D zKPQ;&ZMVL`V$xo>{+@%ey>9(`hm-B~=syW&+w0Mk1Ut7Nd$iTXeAH4JV=XBx$XcQ< zXK?A1&y_^=D^e$=-d}Q_4t$h#68maNzvd6mTkIPpas3s+Fk%%yF1bM8;b1RTJPPdF z4t53dF4RA8urDL;Lj4m5D?r{yHGdWyJ|r*$c^}nJI#_f0k4rwL4>{PX@<)Na_y3&ll`a_HDIu)us9(C$F~dZD991 z7$e+E_5Tr!EffLEN-F##_Grn+b-7@6zjB#gCfLP+YV3V4(;Eb{UjH(^)s|CzjZc3T#*`t5rU^^QZ0h@gZYe_2Z zo%ZNef>E+pOFp5urZ7|bN&WW}HmUT}`t1}pz4S9W=Tg>U`}bL0n!;*I_vz^=Y+>p3 zdR_{9XW|XIMKIgLbUkD*b{!`r}sW*@fqp?$-+( z>^?j}KcKrD%+wS6i-WO$2lUL#(sF)D%d03v>USo7S?`xTE6a`g7lPT=Z`6Mf%xdXI z{f4b2@Cn2=H)*v;WC@&A(NlVp-X++jYR&Pzz@Brk7iRASw%`-ex|&#jN$FSgRSs5E z`>E2e>gvmFk1B%Km3~d%=3vMA@!VY>bg-WViII=e!aR=-{N3rRCNNoORzs>v(7v9J%Sy|J~aPKJ>r#(wW+V7qM|YROXH)mNsl`-;A+_X+lp zx;pED(tGu)t61(KtnWWB{l5OrUW@(x_@hb=>gNR8t3F%vyV4)(<)3CACCkFo=Ce}R zeMJxGErQuPAJng1ZEInjKi1yQr0e`|eS%=NmPd4*lSf$|(eoXQ<$k7{GRi%s7dY6O zF%kmpt_Sv*7Pw9CM#yX$YCke(nzftr% zeTHE4A+MA^qt6!1`jBUIdj{t-daGa$s@o^LUHW^yFO`QIE&4zTyRYaE`ZmF=mY&s5 zTt`{*6p_DB8b^%gt%C{y;l{^ku=JwP1EsUe-@I*s*!}Wq;8R z9w4VZwf&p^gUSn^IV9*+29z z1+#JT>-y;wc3;u!`X#|G4RG)DPt6)(OFnA;pZYb+saBc=WpC-qFEekqx;ePG?41-R z`}bZ7WB-g{>PJsI$ua=BgC7xh!CQ>~LN+p{ESr48D;qT%#^M zAyF1IS2@_4yi3ap&8aup)}NpBwkk2p1ly~gpLBg$iRp6kor%K;eN0}F#JXLyq*-_?yoxEG8 zzKy#P{;yE7Yt^k&uP-Y%WrAG;EgdMUFw+Iwt?sS5xonEreY5Su!=CSy9b@utvDj8b zoHNZL!7dG~Df#cRndVFf8!q_;ur|RS(zNp9%qE+MasN%(EE9J)XXoGOIl-JSSTe9A z|LMR9=3*!B=DH`Pn4}ps5J*9I^o?uD*eBU>U=9(hG7;8LJR&6Sryx-LR5!kUdPhyQ4(LU|gDyucUw=&Pp{(7@ZFgvFk%>9C0 zto6yy;-sz)mvf+%9>6wE(|)&=h3DRf+YhRXH1=ZhWVX?^~{(K?0LZ+QsL4pb*6dG!3rlo9XQj>{g$h6GCKh+FOGCsyW-)1frMbe% zd$IIJ&q{NhgH=x>_7w*^dD_!~mFAmHxvR4t53Di|I@lAFzv@|Q9(OSIVVybTV4n>= z5;)7eDj0QEq&65__`*MD_h~#9ll|C6ljUICNo_RQ4kvd~=a@pl?0)PVGg&Y@4x7x; zf?cfss*az$$<$}$Z8j%6c^+Led9zt9m>tb?&E^cwb4|qI%vFt(&o%LkymoWGlh9mp~HEmK4&uTfNK>gDkw1Oi&L0xY;vIy zy2qhE1-emtgy&!pd5RiH`E64{fk!fp!gJ4Y z1qB+nDlANwVq0zvd#3Qx-cwD4=`z$+d>N7(>77=ITGlfb8fELTbesNL9yvEoAbdz_*q6ohFRBUuw}9~dTep%Q ziRXXvDb=&6-=p3udE3OOk4|PUto-N5sF9*oWr%QL zG2sem&vN1kGfHVyFY?%4TzoupZT;uUSbIg=H|3JkrY&buY{Nn;gO&XA^T}ytwrNZE zi-tcBi}gCTl*yk?dz{?N8onUC7z>U1YYqGRBJ}K4^I%av(STNCIW=xPQL6Fu@f2%m zC)Bsz=ZKxn2F5{qv^)kw&7ltkOv_{W zZSHoNp_J3kBah0YP|i#W?|Y_eu9!v-IYsQ&_Q+DSPy)xX&Kf|EBHin7t`T~t&>sap*d7hb*jagOnlcz=)0Suc9G3bP zYWAw16wtT-T4c7Gxn1Un^(TJ^r|W0lKmDfo7FxSjpO!Rhuw}^_ObXb@@sYX)HJ;zgU62JD_Aw$ zQeVj6%!U44y5+QxJn(NQh1;5kST{ ztJQw-X@o|dQ%6g)KHO58u_Ala4f<4hi#?v~j^PNQxW{*MBB)i0&gXUf@^_Hx#0jLrn=?OR^9b&vQuyY}56+T)CNC8Sht z9A(ql@cc%kMLpA*{u7`_y#xF7I`mABI$leexwk_Gqqe}8dejr+EXS^=^t48mi~q46 zgLA~4r)i4oGymOEAHIG&rvGmJqrH!1kz~l!$$28}c*>FFp})0$$)jdse7!2+W4i}s7TkFhb8VWQ(E_hLst&&D`E3z0nQpCUft{h=L;%)VS##a3R#-1n(hr7fGw zc*CRobD8^V@VGwB)U`yvZYg7~J z^f=KP(?(5{_2@`Ec1_9j+cx52S*@NCpJU_dZ;NcJj>p%ZaU=X5m8%Zo`+QI02KYhz z-GjfNo}dc#M5HHyR*G-%mEmtP{-)r&a8vP$uc_)j{2f%4_@&!Q@Kqu`4Sz@D?-*64 zr>iS)$C{s)=o9c|<`ckEg&L|*Lk;j6;I-hcMLo4B(*Q~4BRwDKMtm-izk}*Dw3)4* zn5FTpW}f+%0rFdlPs}Pn9XuCk64)#d-@F24wZIJm!vdoMw+kE=m=w4NaI$LEta-28 zNGvq0VOaBoYP;M3tuegKR%7b$e5J$IEUtY5JiPJWrg&q2 znfg-JA>2Yu7QGF4R_%MBFP-AmZR(fva`av52YH419(7ky2`Id&zriyjG*{y;P(uUY zOWuLkfF-_n(+cfLfgIf%qw@&Fd7l`I}3!J5o^L)b0(r46u!dwUaUu6z> zCY4+(@CMK)mE35qfadQu*QiYmKL%v_7Ei43NpqLydz1cPDD9t7e{<7cjrQ`s_y)9C zq#pM06m;10!y4ns_8x2sc!oVgxf1~&t|{{rdd0dtyoEu^37#^cY)_S{^-S|_o6rdU zAJ&{Kum$je<5=efQwWzgo#mP3ePpWf)Ohc$>F|{4|C+SJ6GrRjBVFW40)DCL62Jqv zH8D$1E8UA4UM{*0@PyJYc&2Hd&`r}keY-+^vgli$CdiP5XBJFTlfOW1vyOQZcO@>t zxqeueG(0I9{*~lDg*q>p_blLTRnMc3k2kz5^nZGyGA_;D3vuc;OaB@=Va-K~eVmLM zC=bSN@?>wTmlnR-dv8&Vci3~VslmHfZnp1Lm*HCncX?i$e5!X?)2=pnhw7Gi!`|yA zw}W0<8u8wORhI_p)V(fkf_@#p1dJmYB@HUl0G9zBpTfKku4hv!Rwv6#QP*D9lkJNpKq2q*z^%VYJ0DKBagRUo+!N3w^#HZ1<%#KVb6I-f6m8m z_ucHf#j_ihe2eFXqwnxt=PfGyrmxBTVfLedmlZtbdrNPr{hM!t)OMq~an^BJx5=#e zrp))-#3OwVlx11j-e-j6!;{8qGr?Ti9Ka2Fk zHDAfv?)gpO*Fky3+lt$$Gkt^}fhPjKC7OR!T7Oj9eM_I-@awF%^j|8U&zh!r@;psO z`9(eHsP!0~8;PxcIs^*6@$b~B4S)1MryiN~9w?K7 zFQSHlsjmTUDgKwAt3WUi_AK;P2M(z})SVU}r4{Mfp_NE`r>+AWs#_O$QE#q!5^uFQ zZtj!nE&We?Cv30TUK|eWHD`N!0^7~9+53?$o_llPF7MA8?g$(-r#3tUNIg%(%zY#< zP4kSMeufmD+E3Fw$)BcqzCP@EBe%nIk61;G_rWR81~@|}!vdS(Rmx=q4+-Tlsq-=O zr7U0ebg_Xl-FVC~*=2fn^~~&HtZ{Py|DHQf(oNa4&*p4e;|lO_-n}X{yl8&ka8CBC zsB>A?tLCdy!r3o+x777y|3$R=qB*S=Z|G3JZMZ)B9nor`?_krN*4cxd!oqGBGSHUuE#y}*RUEMm-DK*7H{I1B%I}dr{$FEzhgwE3x)kE z!uR-X&8Ie8pA$BFi@pW;rujZ#eUUGl@PV8<@E~#&TPpP2QRvHE0Losy0PBbsaP^cN zU5B}ONG*`rTIWFK)@fP-t?2Ar!p*q{%yY2q1Li2$^8wQ;@LhZ(j28H5@N`UlD7OXm zXQ>v{`D3$8(xjK>Et6K3N&U;D^%wOsg=eZ|nrrLq#bU~`t`&GMaIye6+rYTG0}whJ{-+cy;7gCExN)IF8gD>4iM-fepI zrqV;I7j+f~FOWJ1^?Xww9Ms=2O~Ktx+5c`>f?Rs+D}-`Lh5huXYeJ{xJ*m#~{4V&U zD#-gEKx*SjMQt2X{PyA@W#&AIw*|}yy%0R48bhxH3q9X0^yI&&6CSJ)n5`3#z83s@ zQF9R@tH&GGBNpPww&>jI9~<0lMt`pn*{%^8o{(AjgjiJA^Qoq4%)Sc*ehKjNs3)2K zc|6&?GXF-T?>09geP{kO&8JnIO@GTjXgFUE8hV(6hELnDV#=K2Q?hBAlo$2nnm6+e z;?q+L4IH!hKt7cGIg|b{It3e4Mg8SZt0DhJAAUHRG9zbs%LVC0C zdVnR@TQ~e6?JAeW87xjCKazRMVGJl{83-8zBc7z58(p>4|z#X`Uo%1B0R=VxJY29 z!2JThEbxAT#{`5&V5h)~1%6rJ0|J|K$fNTKrwMEp7#5fmctGGmfrkX@3Bq4M*eozC zFe&hW!21Or6!@&bX@%r}Hbkf<5+(&65O`4FAxptGpWc{oP~fy;rke$Z1s)K1(9$O} zH!LtIu<|HUo~I3nd+#+y9;IjhNY~c}jn!x=6?-w{y!(26w@HBy21dh~^ zvR~l+0-v>%CgDHvA1rkW)0F~81nw7jzrbfLNHYD78C9lc-j)Cw^+DT zas@tj=F94vQ@)LJfM?X7RfS%qck0jU`}EKBv-(w?W2T!~CTf0a-Zs-b%RHMrJ)S!~ zKkz)@dE4Xj2ECKKM|+ofFZX`Ndz1ISybpL^@xI}0^qt~6*BA8-`bK=8@_pHNpYON6 zKl=XROJsdK>x)_6%=&xQ8(HsUW&2D075=0BGyRSJE&faW*Z9BU_Xj2gCI@B)>I3To z{ehi&bdA3;he(U+T6z6p4^Y-elGWm zxsT_blXrRWd%>Rt-w2lFPsu+vzc#-$e{KHy{B!do`P=fpkbhtPukxSHKZLaeueMVG zyh=O|Fo>09BK*Qpz$$=E!O6^2yqjhg&RkAF&Rm?%RLfaPDb7&JaCS0Toe1ueRk=D9 z+^2ziDNbh2z{$*+IBQu3kFo-%GAq@w_^tH0Sb?hX`_r{ped_V;)%j`*PF}(|dFfE6 zz?Yn=x=_P;xN&jg{0^LWJv6Te@Ul7E01r-Oy5Bbdc(j*rZWAfj6bu6XMc|GG(sxWI zy|Ltcz%wU|0G?j38&KDfZgX#znqQMr?-X7J`hnw_duqui0b?gHJ*|xJ&jM|2UqAjD zP#&McR?hMh{!i8C0N=>k4_G0Tjg5Ri&gFiVy;>ycmA2MR`5GwerhFZ6vrxWt%r}w# z#xeH*2B#BVKL7iG&mR9E;KYK50biD0ZxR`T)5(9M@K|_;)NgzAKga%zxuSvVbJ=T~ zK5@$9NL$JuO4IaA9-Ce_Z1`K;&RI_kD%25Wx0)`N3p+j@CXHquXvB$;scu|d$S9(HAM)E=8m_=ynVj>)WZ zNJ+M}mMs%n^gP9~J`EV~!Y{EEWMSzzfI? zW=0w6IR((D(=k)`Ql0nlL99E0>KK!X#;8GvW0 znV_5vh-cZDmHd|ZETlJLc51B2Cm_8E?=jPe?B*bSF6JDbks(IJEgh`rT6F^&%&~gF zU6_Fe--c=e{o{ZJZvi_A@U!x!wS9mF@9;Vm@MhHvcq`%ng9vdk;O*#*Q4gXYIO|3a z4DM1d2mA@7Hh8DiYQSG0R?zA(K!fiMu0#59K-@n;5Ab#+K!f*4Z9w{ufJQxs9^h>{ zfOy`79^j2cfJVK99vHkwEey&lfClkqC(=GZqpEcT=^8+zYIP6N^8hgxI*N1ypi%Sn zHl!N?jXFv9A-w?5s8e(d@Kn7Wl+yr>TBH+5w*VToL=Pc-Iv{TH=$(LP>S0ip0b-=| zM*vsp3jtT_j{&aJN#vddh_}=0i;-RrXw(LM3DO$@@$6N99O+Gf_*G}U2kCPGF-C}% zwAun_aQ<~A(j97puzVkZbABsfCe%3twEKkNBSl}gEv8b9qF3^ z@f-wazql=<{|l5?0S)5lyODk!(5QdvZzKH%pi%GQd|0c00UGt5z87g_?nT;|`v8OH z2Y@B!AmCK<0N@PsBf#0_$Kad;h;cLzBRvlgGs`>zSZ{s`*kFDR*k~RDY%-67=R`oG zPBXs(Tx5O&N(*2vzS%ef^XV6O(@CXz%FFP?ibRbDS^o{8DCP@S*#;CtfNV@LUQ z^*Ze6Zk;eY%!s+w+-Kf1Q?qKbPRv@AwJqysS+)Kr{J--jvOk@DbN0dPH?pg98gtIe zxjg6HoSfW8a|`mOL6>UsgnW52<&g04 zUjA3{3@FXTbYQ{_q4Bf{xCz1MN;n~80{`$Usk8Z6k2V_cHy=K(5k9R6>;8%OI|+Xa z;MY#Z+J6e3%$y2eb{f|DW@vLEbh!wBE$}vr@wWtjr{jssQq=acn&3I4BUv|_d$Vsf zf6Bf~J`*{&nrm_%Hn-r%#U9U_>3KP?$+IDNtJx8J*u0FJ8Thy0l&1Ff+UoXdwP4{; zw6|+zcXuK(xG3DYHF8Ran{!HMdwWYXG0+ zkpye8h{GwQIZ=`cD8tb=M-#|DXiD%S2 z7$decoY=ZHGD!NeXhJ^M4ul7z;ojE%uE;LXmxa$CX7*sDkH}!OzecskYt%Y)9{1#^ zV4FHUGH4SYPA#>z|F!C@aPLs0ZD;`fu2mS@9g#Rj3hCCCsB|D4A0`F?YSD77HQ;$4 zQv35n(1to?#X};ay*kOPX>failx0JrCo5W2Fv#A-DJn4-Zzfo%PG6)rKD~+B7O86O8oVhwrL2XECEXGm!f*o->l%$g zm&jPUxVdHVn)YRjSDfCqRJFy{Z&)sH<8oUDpUW^6?0c$#U=nw3!>2QYkXk;}I~ZLR zi}nu!VW*ZWOn1O^xfHu)fK4n{TM3|yn5QCK8sQ8j zbuf|`bgGL+63v~1P;KvUYd`Z^7A|RDyuMAUX-zCzbhf0{OHJ!-m!tjbDe!uB#vz4w zt+yl8+P{8-=u}uYNU;rWu?;M?fyEqBc$a0~C>$Gwdt-(!H>OlC4AA99>T)CN*~oe} zW{!y3LE~?47vAQ0B#TQz(q93hl1!I1jEsssSdSaCdG~X-|;=b3dx;R2^Ix!~--ZhWk5JU;CnPeNg4Om%TQ9*Zvx_jmQ8!{f`W3J-1_PhA%2?>QWO zd3e{6vfzLt;lA-zak3pLPln`3nXBS4PFl?8BXP*|JW^)nBK~1`-oG+>VNUU-n9K;G z#+eW&@Zsp_#E$4;a~2N4=nqp<^B{h4p<@V6VSFp8`R^{bm2HS(;mu{yZ;LV2JODpvr#z>H z_$WzWW_GE8F4Z3yq#bvK6S)Zq}@qfXZyd{Jy*SXO7Wh#0;z!bKZp zR>sfXiscv90a9C>5Pl2IAR*pI<_?g>{RxEf))}s)6LLAyYkrChf1Reb#ZvTyTWd)t_(aVadnDD`zXR(Z%dADT z)faB#BBK^T&cO)B$>ObPOLhq9;GK~z*A*$a6FVtMj9RwEQfxqo1_vAJ7DfjXZ83*} zww;uWP-GzgV&-3^TPtQbQM5D`Xl@29pB^kDH^5$*%4n;_-v zNQV$*%1H{{cGrs~u{f=Zwjf!ebBDdxlE5wF2SvH1W$)`E?&qRd-$1M%entrG{S<_P zOTtzXX+v0MJIOFxVVD5vCRapu4X%jwrzWsvT8v#!Z)^ZlLV~6g$`a1ZPSGMRFZ;|< zr76liF1k;ZX<-17DwD=gCXLwr6y*@l*=zY_J#;FH z^+}>N!5u&nE;wXwpI*QWXAcxq3Yo=!U)j&2c0Ixew|@;Nm4s@Gme+QDzgx}SIfiOBCFz&&M4Ed#Gsp&c~9TX z@D!eWcvToNCj^$*QyN$nP7JOa=(1kPPL(mF_Mvn(r0?$puVMkmo6)dv@*q1rZe3F8 zQ68UMY5xyzm4M1K2n?NN>4nFko_ix`fNH_AAZ|c$OJGxD-H~ceBqDtsy~E3~!-izx zlvjn;`vx!=aoMs!=B{)W1L8E+66qM~>7k2F(@^-VXd*g_<~G$99n551*^z+D8O$i$ z7LG&wC2`FAow4|~bgga;w6U|W2SD&PKC`vII~MPg;56KOL@u0zbVqxJ;=(t+l9ouK zGaemac$m(V{Wp%#5>D5!lX9ae`FSsW437z~a%o!#D_fxzHxp|x9ML%m(@20LPj z4(lSGy;w>=VlA7pRW8InFA}#DN(A{Vf|-ln*feICO~_UmUfN`m1My?7 z6~y9eqvuD|+M$5~9KR-(V8Y@s0Dg?2(8_LiiNQ&4OGmfrw2{hCU*9lMnRqQOwv*?& zDQrcg2j+?s4NTx}Ds@S3xJPvpa89qmj8+)`jtCdIupIn2t|NoM{&K_a9u2wY4mPx7 z70roG#KKI$!$jf>huJZQBBhm1cuu_L|b}SXz6;t&Anyh3LqePpRZXu#Gv|aXbWtW-vg#VsRmABhGOIIq%D$ z_VN5L18+@aAie485V+fVp$sRrcBms^XmEg~s{ZeJe~S5_dQ-z^pLgps3$T zVF7VctTlDoA?izG5^8d>NR#^9gAv5;&JhWtf`zdmnbr$qF0s8=j#k7lmg6ywHIbIc z08%KhqC2W$9p`bgD$Z9ts%nppLYLS*__A2%HaCn|8;NYgR!s~*rUll;ws2ybIvu~q z81BWo(Si`F4=FT~k%YUUuas)s_}X1X$?DR?eUZ`4JmOO-d!#H=Rd`|V*2AW-_P%uT z{8Z9zk?n+$a1TA;ez#Y_r6c-Fp^kgtN-28~%S6|J2U_mq6DG%oQaET&@9e6&z|n(2 zmIr7UH5~0i>n#hpFHtLEgYqd1Vs>Hz)&iv%eXoPk?lVwKZa0UsA)}1U;*3J0aC(6Z zUdFx-nzsE^%dW4^sEiVfA-7YMF*NMFY|IQ-meCy6uu+F?)?bY!4vZyWw=|GZi*$%1 z5s7C|#V9i*&BR5)a8~Z)whXrM2Y4zmo^xyknU!;3GHV%?mr+$FJ<5o|kpjJQlL#Ae z>g7sjErLz+nVjfK64o@w8(wp7PYhwj);{c0qJ0>}SRX>Rp+4&(5L}1*)iT5_ZCjD( zbrY;#9yF+N$49bZQ0>^;^@~kdU&lZOj|G(D>{2LNa&~M9m$p3GkNr$!+e*ZzNJ2V( z(1z?@PRRy`yE@Ed9^yM>4zBZv!C8LSM!BJ}hbg0TMq|!XIC-p{D#{a>mGMzovRb=E zTN7?-z&;SSGk_1o=@8T+D6A(U4?_f}%A9yXM#W9H@35N@d$Iz@DX~1lx+omJi#d+P zdQ9h0k{hZW_BoTnQ#eYIo;)e`NVoIsIrBNRa`wyV=S?cL0mz`GM6d)FPcFa+Yw(OjDcVJ-7zYKe%!T&qd^jGMy*$_HY^Ehq_T;n%Av| zZasrKFwh&d#*ilRumUj}_T+Z+na+v!ejWEaoKT z$c$ahD3BVfv9t_a$~m|gu9L>|y>2(z7moI4vaH=Y;AUZwa*~jIG|w&v?L!#MWlQ?t zBx&kS(s}$K94Uc0Pn~?BW#D$&Wf1x#GIqF~BXugmp`;X(Ssx8}bO{F&JIE}V;=*>; zNmDgW(ym%A9m;T$Z8(T^k_)3fcqD@Zx`l`a#*={7F8J0cwuEtIw{{uZ4$#`W^9!8FR`` zi!{NRCoW+pms{&XGcMyH2qcw<^QmiJ;$7W4UA^CCCECHb=%lfB zEU`{THy@+h>f}@*VW&Q$B}+}|+sSV4uz8Foa7e|AG*R53wC5YG{b%D)CxJ&m@wgNm zO>W0-2PNckj`RQ`A^aLma8XBO7mec4UZ0Ds#gRrDV|UyfnHl1;5_m=}!Z@*q8*9ta zKx_ap&W>njB&A$8oBhIMj;Hch3?|$VG(}54jHkZrQ~ZRo4@BT@d3KPhnCoGcJC&+Z z%h34koYM-f;fZd>py+P~W!xdeIy}rpD2=k?vPPXx$fgE2ydcq_<%d~2wkM?}_*y$S zjQt|-5x_d+`33!lO>h;*Ifx7|Iw`9YU5%A`c_hpW4u=uL-7DH-n-u13UJg@$6CBms zhkv$qd#;2dHqj7HEAf{cP;xMBqJ!s^L^s+8JPGXC zd2}~upTHzk-&uSrV)YHLik-VdfC@4&)Zoz1cRqKd%gKy$?yuUKV9cY5Yj6t_*YR+( z(8dx8+zzg5Zy($mO>nVl+ZhROOV22|yMlRE#j{AvJBcQo<42%82DitOVxM44p*;Rg zArK*zUMzQt#jM1#8NoT%p~NGOBOZ2|$z*{0vlrZfIeiXZuWin+nvOwEz!h{?Q-rq?L@Zcq#jZ2SG2U#UePD#***??Kl#k*j9 zGHlqiD;r>QQY`6>0k^k&u_@-+3w#468?L3mG1_}N>BY{$6AUYyG#e7rX~sDNzYbzc z#%$U~(hhQVI69~x$)M}ocq@}q$b?!Mcb-4MzjJ?;U}mR#SgqOzU@`rJhcTyA{DZ)y z%DEfyL2P1B)@#Vfy2T)jBZUl$_(@T{bMj`>>~lKEcCs=Et%(ezk5AETIiAX4{M3Lz zkpZEGRfj|?i&Cgv?Je#+NwNqeq+?5SIuqOy=q5)Iur$cy3!B}FsLrN3r6qgg!ae&} zYjLt9bIyLHLnXFFan}$}4ikf_PaxuFBF*u5cvw>H;Z*W`Aw>HTG^yCoAU~Gl0F8*XHX!KXc( zMX3@oP>Zri1}dg(bL<0kcg?gk?8`FFyXhZ#M-eit-xkQswG@da(OW#qvV``iNRQ^0 zL=V%q@oTHZrM8Cgsu<5syZSeaP)C_X*sV-lV$MuL2Sa2>B(~QQ9>$}xRk$6F+cdNY zVCiterMRDNv}y5y zHTMszg}rzT$b&|;dMFaNl{*gzr6xCRr>Pq>xK~s&a~+S7?(bM8F5+&1K0fewk)F(C z`YM2%&0%qM<tjhmCBI$&I1b@%VRSjhij>Pdzx~DOsnuC zWR5wzO4TSv6CMb6;x>}%bQ7_Gc8S7BM7p&f8!Ln*z?>5T8yec3&agb`a?^OO9qGZt zmmNIaj>3%(D@@h@r~0;yhEm1U5L-l!|*25Y~(D)ch_06ACUYt;3s_}zJK}=d^^`- z%LSVUOczD*ewrBYM*LTg@3ziC8NGQ4B#7dDlDJif(pXRcdw{W4w%&#G0C-5NgoKp5 z68vGb+yklIoG#F#Y6rNOZ{=6#xc$HvVUUwR4j$!6-CI$T+?DvWEyYoiJOkk9ceK-k zye_;OBMdru2l1Qa14vcjOS`AzGp70g2T^iZDgPSaI~A^O<1^jTHfeJwC|f1p?In8^ zcj{dN*(2zc)q!oJQmLkMP%1NTrqi>TpdW|tK3l!d6wO<$^E=V_-u}o>*NR|+GRW-4 zAev_vIAm6_9De3-U@9RRo~)u9R7fxWV^{2;FsBn~4sQh9wkE2%L-?rz4u`F!8+5lV zwnI7!g{$EuzIr8BPw2o$X_X z1OtCkCEi_OO~Ex++d?Bs(}P)G!8$iM|1HN`Fk0}R8u>>hUfp3QHAi>{*lpL?C3kFT z)g4av6HpNavlFocTy9t0(OwP(>;g3gS5yf%R}JWnqIWqO6w)BTQ_G2Rp&ZftJ-w!)-s^5kuUzg-RTDGoXRH7#OcTOidH4e2MRO|h_ z=v>N4XDkSU8?Cw?Y1D2Sc3X!tYOg>-F;hHfY@Zo+%?xy{GvcC4muFXhJINW3 z404K(T-_#P$ikehEMh|_E zTan6K?ifnZ-Wi_R)!g-9nX2O3daUKnbaolsHR$@qD9r$n{c@GzF4ZmQu^WAJHo59l z*{tbA{Ha1pW<9ABAeOAf`)``zHx`ffTiJX^=2mD;A;rbB8^IJKh|D;iI}$fkg>RY2 z6{JJzcY{skcgp&m+Rk2t8r-nKU9zpd?Cj56;;jLU){9-v**|*oUW}0V_c`2S48jMy z>zG^jc%Khb2{MdvcX28=!|PVq6^v2V_>yYgXrt{zEi}ILT1go)&2k#FW_!L+Y=WbY z?K@;mO_7m3uGvxz)|&0IMyF_Z4zzd93L8r?&bA?>JDiNA?MBQ-MRo(`a#>ziAzb7s zQW%3vKDQ32CEHD_ktag*a4UJue(gHZHcCBD2 zN~>^(fSOZ3Z-JCM^BNCBGbJZ8!JJc6V_s!-1)l#CG9DKwP$)t&JSuDydyWeCNw0r z$qeqAU3W#bxr35+zx{B0<0l_2mg~Vbr}Q**aDxcK*n_oD=~SF`KkgpH?xwk>(Jf>S ziMyazDV@#Z1)8BM8>`k;ZcfxqxizPa%N;fbirlYQ`R#he<$@}vQDhE|>%cif?cAme zJUP&gv}Fgk4&9L7q#esM7jsSQEqN*L%U(}Z*FpjpgV3rEhNv=wlfgrkQs zWZ_2rbC1M*gb7fR?sMjZQbn#VM^Q_xM~Yw%IEr3Iqo=RpsYybPwz$);RXS$P$Of)- z6kN<`8T4Na+Gzt_qD!l3*Ho<)*;jl0ybuH3d~r#p>Y z<)-_iYF40?N;nA{!rO(Mj@@pbXiKg~wzcEUoLGFx$GW&xp$k<-c1n&}MvLq+JBB)P z3+JBew7C#;i$XYAMytb`o_j3CC4>UmL!HrHcJ!X=IGi$8<3FB@Sp%hc_Mj}MZe}fM zLr8lqPSGe%P0_7Ii=;JocwBFI_#sL6Ds%W%Q8T3G^o_!_dE!Dps3tDKCnu}jFSKI# z)b_QYk(UF+LprNIdQg_D#gXg& zGfk!kg^hFh@4+V*$@FlH&G`UjoI{JGk=S6^U3}8V^1W3J{Z+`xJYA~7q~js)GH|+w#7cEPU8%16 z`x%Rp9oc6rnt1%}%3G;*z*DKT4~fD;qJ|*fS7~&9epXRvxef*V@-gyTFqQ|3Ldh9A zl&tXK2lPhnBRVaGzMh4$p^?|U$lJgw2^E-yo~+15t)XO1VY1#SH?ogh75PMOKvt`p zXl4TKjO_DbdEV?R3Pm*Kh=BB4pI;Y_JmK}5a+9TuE-x@Xg;s81v+M9qT3rrF10KH) zu=a^6==Y#hQDIaEQO+j`aG*&z=2n2k1pK^J5!0!d8NR4ixb0&!1=I2+Gd;PG0d}uJEUOUWtWjIInhDJUEZ3dzE z9D-m@0KLqw2#x$TpdkE#!sL%oNntf=Ef1KA@@(|*VdFzFn?l0p!vNxg!}u6#M;b%I zk9_>%7(c)|a*Gs#E}?~q+EQ2w<7M!31JFlBdBBHW*ouDTSH@Q!N-4N=llF7Khz6OG~mzX7^6=WK2(L~eOZ+r4H}YJXtBZvON9dV`YS#8 zKsW#ah+-^v4!WF^Q<#jv@L5ZxL3ax#YV^UE=l8P!O5p>=w2y$5qE=Resf<*9j`HZx zMLzs5T%K&dCqFcDH>&evY_~$xEWZhD4Q-J&u4Ib=w3v@ykjR1P_mzh#Ln8;hS)q$& znJm-^X%Ap%3P&D;PGDn!kUuX!kPp^h$sdv)4(CPn(0e}EFb*=Jzsk2Co&fX*VtzTK z^aQf~Sx_JJ5D56Q*lmvod}Kf`^U?0eGXyXC{g^T%Hw66bAQCy8+pianyj2*s1N=Hr zhzANLpv+7VM7_yobP>Y6UhdBgEeIu{%lk~Aq8uNgQd&k5HhECG_9~4G`Z+-CqGm_} z=j4OpLl-TsC^tSRFFydq(V~7tEtd<+Mfgc(WAY0E-YoPOg6CK~2T9H+WCbBZVX_E4 z0u)DfS3oifNA3bwp5@95RC;xw!UH|{b(W=JOd-qiK&2;;pI>;<>U@6|JZoq=yeB0^ zZ!4^759CuR(_v1bkt=ijUa-I{LzUFuyC?W_tY=M@K@;Kyl4XT$A)vDhN1iJjc|qI@ z&}12X@HBM1EE~Ru?wHPpF4$(xa1*l(rU+eId1=?h{oVjQ7v?Jl;{fPhc;O&a<%Jmq#85^Klylkz^2_|rGVpp~8|K>x z#``{j2VHu;qGh0O6n^COZ1|C66DhDADkTpq2PQO-4bJ+sC*b!$2dhG}W%S=ALk=C^ zQi9o{PADUygR&3>r~32A9GV`efQPi&6$Md^P!5bUlw1v$jt&GW0$4#wI61UkKAS_^ z^I%EI)=;v!0)OxnF3UQw(7=-?2Sn@*OwREKt=5}UAIZhA4lb8mKCpNsn*;n~ZO#Za zW9=pvI#e-H9R$He=m1Ae*cp`z=cv)tNk*6COQ+k|}L+waq3693x0@9#qE3 z_&7Pwx=~D7(6S&r#!Wtugx5k1fSMSc%P=t4c}#W}eNn5d>%8kW9b; zCZMp;`Y>NuA4^?fN(;18#;w+tF<9@Jff+us5C3zbhBnCTzvxO`kpmk`Ch-{r9kN{s zDGM*!3(E-&7{o1rAw)Pb{q|AcNthCv%;8w($VWD~AWEK*d6-v`Q$>Fw53gF$P}q3xz{ zCJ{I{s{qTFT^Rg8ZBWS1_N#r zV)g4}0NIAQ6Ya#_qN>cplu z$ST0FG}($Nfs%l5rH}%yglk!-4~aHE*6vZFB=_o~!jV0g3e8T9jv%4rBvVwF{LI+w zG^5ySve{T8Nwx;9v0ro@OhfD}ZR|83FciRi*h(s&^Cj6j3Ebnvm@q~xu67h>qMCF# zu{>E575=m%OtT4L7Nw^V=bVw&nu{s-n93k36^o->vnu(qQn2}_-gls9Y#{`229$+}ZV4h{!gYb8vF7X$_W19edwfJm? z3PFVQY!A-JlM^s`bTfNHy#R%6*_A$7B8TA3b^gmCxPx*p`oc zuK(uCmLBu?RbRaF`E$;$D}M6!JMWnBx9>Hn3%B2V^cAau{k!|xe)q$lUVPPA4_uLR z?xo+ZzV=C<_l>nL^*ns{pQil$=}-P)LdE~SviRK3P544+Me)v$-0{v+$G>&cEzf-_ zuioq_A8uLx!{2PYDR=0xrH5jZ^zZJv{9xx5KkmB4%U^2oP9vx!$e9W70#3676=!_@ zwU1xq|B08s+u{vKCISAG_g@5>fCt}REK|xGB$z-@L{LIdMo>;Ll^~m7BEcjA=t31A z{`qwA;h#}de$bwFxuO-uLj&WR?4}rmhaH^JIlKc(MvN<1frTz!L$xu#EgROA-MvRGKX8 z53upd0m<3ZI!O?HCdg{LUjFz0@P@1Uw6 z6Z^P*fpiu5;9h{gRY;dJ=Py#V>Z z7Q{5gCOK#reG~)>5ME*zwyvPk2Tvdip8!)>nFVK+Nr9W-5|}!gL7=$~3oF(|91mfc z3K9txR0I(g%O{d>34zo{o-AqBg>FZDU?31qK@6sh_F@wf0LaM!2r?wj&IZWMpd{<>gs05{xT80J+7{Joz9Mrxp0X_VoaaDO4#tNEiV3u6Gf^2M{oGKa>wQ zCt=vgmH7y}QQ4KDUaYpr_F?ai6Fk<6QZN*hg6;UF#Za#gp9A@19YEBC%4BDYcECFT zbzm36`UY4NY13^jKSiCW{Q&lx+~vd5v!Foi){#aNFh-Hk!e=CX2*tUJ6XbaYK_f3B zi2tkLFWSr-1i3*nUu7l~YoJ7JAT&ZExMm8^tvm=YVZ?Tje*xrwH=7Ac`)&}?eG;dX zT(eUBdN&91IwZGW@3Oh1#&F2Kz(9OoP9VqGCiv`0(*b_4qfi141;CuovCI*2vdHG% zMG|HQdX)^i)nH^m#iT|nOQ9uf&nfM6?gVoccj8D;yXeYv92)_K2807DWL@atySWfs zdId(r{s>-@)6hs+KIzG_0_@H4_kxU29$G4FW75JdZ3pqKy*PqW(Ovr zNWLpCy2Jte45pS0;FX18Mw272WA^za5yG~Su^56xzhdnpSK_m9Gd|H86m=y!fKBtr zl~~Rx4H6YNI}HV-JKJI4g<((Nm`d1lQWX1<+$>mfgZ)@%Kd?Imi|lUku{wvMax;!CHWh1=&>IaDXLe$hdkqhE zc*I9bXG42Y3!peTFal)>gTW2;%0WoJF(w;@5XAHvGpQ1BEK*Dxo4_F>46j!#qZhTI zx)D~2QxhYG^|N<|j{EU?=awEHP4+xb>dLO7kW^V~-{7ftVO<|1RW{S^_hX?q@KlcT8^6s~U1|Q==g-K61ORMP} z)$<}XO_AC;HQ~DIIdzR4-E$f{>YL`&bu@Hz*VKd~;ifL7l7m_$`w#oJ0)9`O-@LDC z!;1uFSFXZurbRpP71NWet8443`LC`~KAJ36UENS!D+DLMzP5f|UCq22atfU({6*@+ zO$|-+BlEiE&2Q|A)OB=q)ihMk?`R4)M8fkM8|xZtk=0b))Q#Nw`i}bfsHUN-Dcsdj z9gfu2MHNPf2zqYoqv%b2zt0B@@*U(j8*VWls+u79!hWduid5xXb;rd8p zL&yAi)lI0Qy1u%udw%`ANVs8sXH!Rgq@gC#+1=IA80qS+?yl+T4tH1A)z?Rw!qweP zk(%1NNKM21`SUx%k?zi}aBaA|DGcc&b&cKCo%8CeYa5$tI_Edl)uGwiuKD%haD8>h z{Q9n%x<(Z2uBof8>FVsLY3%5%X@D%9^Bd~IO-eOrRaUiPaT~t0-QR^@nwjmqGVYgICKs4C}Fw&4ZEO6B2qeeuS4ykI4wRFzhJy0?!?_{13ldt<^#z zHFNNe-Kv_VY8k4!6Y!PdaBo%jyoS2!rf^fZu`UdiL3?$P&iQp1yT-bc>u{|2~wq1oEs#QV!5)a=Mi5ID^i}xT@b71H|F&fR)pyLve)!3`e;EGZN9v#7 zGimcDmppmK$JNxi%`F%FapuIr;9usg`swQ{KX!ENjfo4s`tj{`Q|COt=}dFONB>&# z$p8HQD|h{QN@G=HR>igPZkY0V^DiH`E$eH){C(>=+1oyM z?u28m+i=sy)8Zf9bNM|FynS8LymsuBl;Nnq{rqc6FJDF1@G1Q5yI8Az5%CbrhDX6g zDg0rpu4eAmYG!vj4ga!K*0!v@{<0gU&v;QUy4+uPZRbh1E?|j8CvNJB?AU~t zYix?fHpyE7_=Vw3coE5_vDzJ_%uRUf^d`q>H}$7~c?st6{spTBx;oU_rOmbV4a$*d z-Xo4g==Jf7KmF?TKeYU4Y5v!eD|eu0?!T*;u5_`{pBH8DDTO!w#9MlMmtz*Fz69P$ z6^Y2(n{Ao*W}ud_>KR?#|BwBLG@wP%rAm#AuF(G0FC5A^I{B93Z~cC)N`1uazfxZv z5@)Hk_~q@h)M8wgU5l%)yd>L>&lPG3()@Ry_wP8DqSe?%RfqtmItlN%9EB^MEO8cY zxx`VA{q967?z+g`IOI)NEY*fw-mk>_bMWcjrA7w+-Ra#077dx~tv%k88DCSI@bLDf z{jU!9hM)uWGx?Qq-qh~PxbDUl-OK&<;_x=K%R5Z=+iJX2#_x(#B71e(-qW_e6+Bges^Gh1`TbHOBSC^~66 zK|A{Y8Zb42(k{$w^q7Ukt06GWftKQf&N46rp2lFnU<@Wr8O(qi)U|>B&j+u-&H>7& z0p&oV20#^wU~B>8B?85afqQ{dfa;Qfe9(>yb0BRA6i)%4@?Z?4&4Cbj_Zg671k{lT zB!SH#Ag} + + + NetTopologySuite.IO.ShapeFile + + + + + Extends the class to allow reading of integers and doubles + in the Big Endian format. + + + The BinaryReader uses Little Endian format when reading binary streams. + + + + + Initializes a new instance of the BigEndianBinaryReader class + based on the supplied stream and using UTF8Encoding. + + + + + + Initializes a new instance of the BigEndianBinaryReader class + based on the supplied stream and a specific character encoding. + + + + + + + Reads a 4-byte signed integer using the big-endian layout + from the current stream and advances the current position of the stream by four bytes. + + + + + + Reads a 8-byte signed double using the big-endian layout + from the current stream and advances the current position of the stream by eight bytes. + + + + + + Extends the class to allow the writing of integers + and double values in the Big Endian format. + + + + + Initializes a new instance of the BigEndianBinaryWriter class. + + + + + Initializes a new instance of the BigEndianBinaryWriter class + based on the supplied stream and using UTF-8 as the encoding for strings. + + The supplied stream. + + + + Initializes a new instance of the BigEndianBinaryWriter class + based on the supplied stream and a specific character encoding. + + The supplied stream. + The character encoding. + + + + Reads a 4-byte signed integer using the big-endian layout from the current stream + and advances the current position of the stream by two bytes. + + The four-byte signed integer to write. + + + + Reads a 8-byte signed integer using the big-endian layout from the current stream + and advances the current position of the stream by two bytes. + + The four-byte signed integer to write. + + + + This class is used in conjunction with RowStructure. + + + For an explaination of PropertyDescriptor see http://www.devx.com/dotnet/Article/7874 + and the remarks for RowStructure. This class inherits from PropertyDescriptor. + The PropertyDescriptor describes a property - in this case a dynamically generated property. + + + + + Initializes a new instance of the ColumnStructure class. + + + + + + + + + + + + Gets the type of the DBase field. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The Latin1 Encoding + + + + + The default Encoding + + + + + Association of language driver id (ldid) to encoding + + + + + Association of encoding to language driver id (ldid) + + + + + Class for holding the information assicated with a dbase field. + + + + + + + + + + + + + + + + + + + + + + + + Field Name. + + + + + Field Type (C N L D or M). + + + + + Field Data Address offset from the start of the record. + + + + + Length of the data in bytes. + + + + + Field decimal count in Binary, indicating where the decimal is. + + + + + Returns the equivalent CLR type for this field. + + + + + Class for holding the information assicated with a dbase header. + + + + + The encoding + + + + + Initializes a new instance of the DbaseFileHeader class. + + + + + Initializes a new instance of the DbaseFileHeader class. + + The encoding to use for strings + + + + Sets or returns the date this file was last updated. + + + + + + Return the number of fields in the records. + + + + + + Return the number of records in the file. + + + + + + Return the length of the records in bytes. + + + + + + Return the length of the header. + + + + + + Add a column to this DbaseFileHeader. + + The name of the field to add. + The type is one of (C N L or D) character, number, logical(true/false), or date. + The Field length is the total length in bytes reserved for this column. + The decimal count only applies to numbers(N), and floating point values (F), and refers to the number of characters to reserve after the decimal point. + + + + Remove a column from this DbaseFileHeader. + + + return index of the removed column, -1 if no found. + + + + Read the header data from the DBF file. + + BinaryReader containing the header. + Filename + + + + Read the header data from the DBF file. + + BinaryReader containing the header. + A stream provider to read the contents of the CPG Encoding + + + + Function to detect the encoding to use for the data of this shapefile.
+ This function checks the following: + + + Check for a codepage file (CPG) and read the encoding from its content. + + + Try to get an encoding based on the language driver id.
+ This is based on the code pages listed in the ArcGIS v11.5, ArcPad Reference Guide + http://downloads.esri.com/support/documentation/pad_/ArcPad_RefGuide_1105.pdf +
+
+ Use the default encoding. +
+
+ Language driver id + A stream provider for the cpg file + An Encoding +
+ + + Gets or sets a value indicating the default character encoding to use. + + + + + Method to get the language driver id for an encoding + + The encoding + A language driver id + + + + Set the number of records in the file + + + + + + Write the header data to the DBF file. + + + + + + Returns the fields in the dbase file. + + + + + Method to get the encoding from a stream provider + + The stream provider + + An encoding. If is null, + the default ANSI codepage for the system is returned. + + + + + Class that allows records in a dbase file to be enumerated. + + + + + Gets the object that allows iterating through the members of the collection. + + + An object that implements the IEnumerator interface. + + + + + + + + + Sets the enumerator to its initial position, which is + before the first element in the collection. + + + The collection was modified after the enumerator was created. + + + + + Advances the enumerator to the next element of the collection. + + + true if the enumerator was successfully advanced to the next element; + false if the enumerator has passed the end of the collection. + + + The collection was modified after the enumerator was created. + + + + + Gets the current element in the collection. + + + The current element in the collection. + + The enumerator is positioned before the first element of the collection + or after the last element. + + + + + + + + + Read a single dbase record + + + The read shapefile record, + or null if there are no more records. + + + + + Initializes a new instance of the class. + + + + + + Performs application-defined tasks associated with freeing, releasing, + or resetting unmanaged resources. + + + + + Initializes a new instance of the DbaseFileReader class. + + The path to the Dbase file + + + + Initializes a new instance of the DbaseFileReader class. + + The path to the Dbase file + The encoding to use + + + + Initializes a new instance of the DbaseFileReader class. + + A stream provider registry + + + + Gets the header information for the dbase file. + + DbaseFileHeader contain header and field information. + + + + This class aids in the writing of Dbase IV files. + + + Attribute information of an ESRI Shapefile is written using Dbase IV files. + + + + + Initializes a new instance of the DbaseFileWriter class with standard windows encoding (CP1252, LATIN1) + + The path to the dbase file + + + + Initializes a new instance of the DbaseFileWriter class with the provided encoding. + + The path to the dbase file + The encoding to use + + + + Initializes a new instance of the DbaseFileWriter class using the provided and the default encoding + + The stream provider registry + + + + Initializes a new instance of the DbaseFileWriter class using the provided and the given . + + The stream provider registry + The encoding + + + + Method to write to the dbase stream + + The header to write + + + + Gets a value indicating if the header has been written or not + + + + + Method to write the column values for a dbase record + + The column values + + + + Function to determine if the is a or type. + + The type to test + true if it is either a or type, otherwise false + + + + Function to determine if is a "whole" number type. + + The type to test + true if is one of + , + , + , + , otherwise false + + + + + Write a decimal value to the file. + + The value to write. + The overall width of the column being written to. + The number of decimal places in the column. + + + + + + + + + + + + + + + + + + + + Write a character to the file. + + The character to write. + + The length of the column to write in. Writes + left justified, filling with spaces. + + + + + Write a byte to the file. + + The byte. + + + + Method to close this dbase file writer + + + + + Method to dispose this writers instance + + + + + + + + + + + Finalizer + + + + + Gets a value indicating that this dbase file writer has been disposed + + + + + Method to write the end of dbase file marker (0x1A). + + + + + Implements ICustomTypeDescriptor so we can simulate a row object having a property for every field. + + + For an explaination of ICustomTypeDescriptor see http://www.devx.com/dotnet/Article/7874 + By implementing this interface, we are able to simulate that an object has lots of properties. + These properties are determined dynamically at run-time. When enumerating throught the + ShapefileDataReader, RowStructure is the object that gets returned. + + foreach(object obj in shpDataReader) + { + if (obj.GetType().Name!="RowStructure") + { + // this proves the type returned by shpDataReader + } + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Possible ways of handling geometry creation issues. + + + + + Let the code run into exception + + + + + Create an empty geometry instead + + + + + Try to fix the geometry + + + Possible fixes are: + + For LineStrings with only one point provided, duplicate that point to have at least two points. + For LinearRings with unclosed coordinate sequence, close the sequence by adding a clone of the first coordinate + ... + For Holes in polygon, use + + + + + Ignore this geometry/feature altogether + + + + + Converts a Shapefile multi-line to a OGIS LineString/MultiLineString. + + + + + Reads a stream and converts the shapefile record to an equilivent geometry object. + + The stream to read. + Total length of the record we are about to read + The geometry factory to use when making the object. + The Geometry object that represents the shape file record. + + + + Writes to the given stream the equilivent shape file record given a Geometry object. + + The geometry object to write. + The stream to write to. + The geometry factory to use. + + + + Gets the length in bytes the Geometry will need when written as a shape file record. + + The Geometry object to use. + The length in bytes the Geometry will use when represented as a shape file record. + + + + Converts a Shapefile point to a OGIS Polygon. + + + + + Reads a stream and converts the shapefile record to an equilivant geometry object. + + The stream to read. + Total length of the record we are about to read + The geometry factory to use when making the object. + The Geometry object that represents the shape file record. + + + + Writes a Geometry to the given binary wirter. + + The geometry to write. + The writer to use. + The geometry factory to use. + + + + Gets the length of the shapefile record using the geometry passed in. + + The geometry to get the length for. + The length in bytes this geometry is going to use when written out as a shapefile record. + + + + Converts a Shapefile point to a OGIS Point. + + + + + Reads a stream and converts the shapefile record to an equilivent geometry object. + + The stream to read. + Total length of the record we are about to read + The geometry factory to use when making the object. + The Geometry object that represents the shape file record. + + + + Writes to the given stream the equilivent shape file record given a Geometry object. + + The geometry object to write. + The stream to write to. + The geometry factory to use. + + + + Gets the length in words (1 word = 2 bytes) the Geometry will need when written as a shape file record. + + The Geometry object to use. + The length in words (1 word = 2 bytes) the Geometry will use when represented as a shape file record. + + + + Converts a Shapefile point to a OGIS Polygon. + + + + + Reads a stream and converts the shapefile record to an equilivent geometry object. + + The stream to read. + Total length of the record we are about to read + The geometry factory to use when making the object. + The Geometry object that represents the shape file record. + + + + Writes a Geometry to the given binary wirter. + + The geometry to write. + The file stream to write to. + The geometry factory to use. + + + + Gets the length of the shapefile record using the geometry passed in. + + The geometry to get the length for. + The length in bytes this geometry is going to use when written out as a shapefile record. + + + + Method to compute the number of parts to write + + The geometry to write + The number of geometry parts + + + + Function to return a coordinate sequence that is ensured to be closed. + + The base sequence + The factory to use in case we need to create a new sequence + A closed coordinate sequence + + + + Serves to probe linear rings + + Bruno.Labrecque@mddep.gouv.qc.ca + + + + Abstract class that defines the interfaces that other 'Shape' handlers must implement. + + + + + Returns the ShapeType the handler handles. + + + + + Reads a stream and converts the shapefile record to an equilivent geometry object. + + The stream to read. + Total number of total bytes in the record to read. + The geometry factory to use when making the object. + The Geometry object that represents the shape file record. + + + + Read an int from the stream.
Tracks how many words (1 word = 2 bytes) we have read and that we do not over read. +
+ The reader to use + The total number of words (1 word = 2 bytes) this record has + A word counter + The value read +
+ + + Read a double from the stream.
Tracks how many words (1 word = 2 bytes) we have read and than we do not over read. +
+ The reader to use + The total number of words (1 word = 2 bytes) this record has + A word counter + The value read +
+ + + Writes to the given stream the equilivent shape file record given a Geometry object. + + The geometry object to write. + The writer to use. + The geometry factory to use. + + + + Gets the length in words (1 word = 2 bytes) the Geometry will need when written as a shape file record. + + The Geometry object to use. + The length in 16bit words the Geometry will use when represented as a shape file record. + + + + Gets the length in words (1 word = 2 bytes) of a multipart geometry needed when written as a shape file record. + + The number of geometry components + The number of points + A value indicating that we have M ordinates + A value indicating that we have Z (and therefore M) ordinates + The length in words (1 word = 2 bytes) the Geometry will use when represented as a shape file record. + + + + + + + + + + + Get Envelope in external coordinates. + + The precision model to use + The envelope to get + + + + + Method to write the bounding box of x- and y- ordinates (aka envelope) + + The writer to use + The precision model to precise + The envelope to write + + + + Function to determine whether or not the shape type might supply an z-ordinate value + + true if is one of + + + + + + + + + + + Function to determine whether or not the shape type might supply an z-ordinate value + + The shape type + true if is one of + + + + + + + + + + + Function to determine whether this handler might supply an m-ordinate value + + true if is one of + + , + , + , + , + + + + + + Function to determine whether or not the shape type might supply an m-ordinate value + + The shape type + true if is one of + + , + , + , + , + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Get the z values and populate each one of them in Coordinate.Z + If there are M values, return an array with those. + + The reader + Total number of bytes in this record + How many bytes are read from this record + The coordinate buffer + A list of indices which have not been added to the buffer + + + + + + + + + + Zero based shape index in file. + + + + + Keep reading shapes until we find a non-null one. + + + + + False if reached end of file without finding one, otherwise true. + + + + This class is used to read and write ESRI Shapefiles. + + + + + Here's the logic applied when the flag is enabled: + 1. Considering all rings as a potential shell, + search the valid holes for any possible shell. + 2. Check if the ring is inside any shell: if true, + it can be considered a potential hole for the shell. + 3. Check if the ring is inside any hole of the shell: if true, + this means that is actually a shell of a distinct geometry, + and NOT a valid hole for the shell; a hole inside + another hole is not allowed. + + + Note that the experimental polygon builder is considerably slower + - three to four times slower, in fact - than the standard polygon builder, + especially for complex polygons(i.e.: polygons with a large number of holes). + + Rings order explained. + + + + Given a geomtery object, returns the equivalent shape file type. + + A Geometry object. + The equivalent for the geometry object. + + + + Try to retrieve a not-empty geometry to use asa reference + to use when evaluating the . + + The original geometry. + + The itself if not-empty AND not a collection, + or the first not-empty child if is + a collection,or null. + + + + + Returns the appropriate class to convert a shaperecord to an OGIS geometry given the type of shape. + + The shapefile type. + An instance of the appropriate handler to convert the shape record to a Geometry object. + + + + Returns an ShapefileDataReader representing the data in a shapefile. + + The filename (minus the . and extension) to read. + The geometry factory to use when creating the objects. + An ShapefileDataReader representing the data in the shape file. + + + + Creates a DataTable representing the information in a shape file. + + The filename (minus the . and extension) to read. + The name to give to the table. + The geometry factory to use when creating the objects. + The encoding to use when writing data + DataTable representing the data + + + + Initializes a new instance of the DbaseFileReader class. + + + + + + Gets the header information for the dbase file. + + DbaseFileHeader contain header and field information. + + + + Query shapefile by MBR. + MBR coordinates MUST be in the Shapefile's coordinate system. + + NOTE: If you are using the default ISpatialIndex (which is an instance of the STRtree NTS class), it has some limitations. + Since it works with MBRs rather than the shapes themselves, you can get some shapes that are not actually in the MBR + you provided just because their MBRs are bounded by the given envelope. + If you wish to avoid this behaviour, send true in the second paramter, but be weary of the consequences listed below. + + The envlope to query. + + False by default, true to double-check the returned geometries against given Envelope, to avoid index error margin. + + It is advisable that you implement your own ISpatialIndex with your required precision rather than set this to True. + + ********** + CAUTION: If you choose to set this parameter as True, it will greatly affect performance as it + will cancel any lazy mechanism implemented with reading the geometries from the file. + Do not set this to True unless you either: + A. Do not have any performance restrictions. + Or: + B. Absolutely need that precision in the geographic query. + ********** + + + + + + Check validity of parameters - null values and that all file needed to read shapes exist. + + + + + A class to read from a set of files forming the ESRI-Shapefile + + + + + Creates an instance of this class to read from the Shapefile set of files defined by + + The path to the Shapefile + + + + Finalizer + + + + + Dispose method + + + + + Gets a value indicating the header of the main Shapefile (*.shp) + + + + + Function to read the bounding boxes of all geometries in the Shapefile (*.shp) + + An enumeration of bounding boxes + + + + Read shape at a given offset. + + The offset at which the requested shape metadata begins. + + + + + + Shapefile specific constants + + + + + Every value less that this is considered as not set. + + + + + A value that represents an unset value + + + + + Creates a IDataReader that can be used to enumerate through an ESRI shape file. + + + To create a ShapefileDataReader, use the static methods on the Shapefile class. + + + + + Initializes a new instance of the ShapefileDataReader class. + + The shapefile to read (minus the .shp extension) + The GeometryFactory to use. + + + + Initializes a new instance of the ShapefileDataReader class. + + The shapefile to read (minus the .shp extension) + The GeometryFactory to use. + The encoding to use for reading the attribute data + + + + + + + + + Gets a value indicating whether the data reader is closed. + + true if the data reader is closed; otherwise, false. + IsClosed and RecordsAffected are the only properties that you can call after the IDataReader is closed. + + + + Closes the IDataReader 0bject. + + + + + Return geometry feature of the shapefile. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Advances the data reader to the next result, when reading the shapefile. + + false + + + + Advances the IDataReader to the next record. + + true if there are more rows; otherwise, false. + + + + Returns a DataTable that describes the column metadata of the IDataReader. + + A DataTable that describes the column metadata. + + + + Not applicable for this data reader. + + Always -1 for this data reader. + + RecordsAffected is only applicable to batch statements + that include inserts/updates/deletes.The sample always + returns -1. + + + + + Always return a value of zero since nesting is not supported. + + The level of nesting. + The outermost table has a depth of zero. + + + + Gets the numbers of records in the Shapefile. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gets the header for the Shapefile. + + + + + Gets the header for the Dbase file. + + + + + Implementation specific methods. + + + + + + + + A simple test class for write a complete (shp, shx and dbf) shapefile structure. + + + + + Gets the stub header. + + The feature. + The count. + + + + + Gets the stub header. + + The feature. + The count. + The encoding. + + + + + Gets the header from a dbf file. + + The DBF file. + + + + + Gets or sets the header of the shapefile. + + The header. + + + + Gets or sets the geometry factory. + + The geometry factory. + + + + Initializes a new instance of the class. + + Name of the file with or without any extension. + + + + Initializes a new instance of the class. + + File path without any extension + + + + + Writes the specified feature collection. + + The feature collection. + + + + The exception that is thrown when a non-fatal application error occurs related to Topology functionality. + + + + + Initializes a new instance of the ShapefileException class. + + + + + Initializes a new instance of the ShapefileException class with a specified error message. + + A message that describes the error. + + + + Initializes a new instance of the ApplicationException class with serialized data. + + The object that holds the serialized object data. + The contextual information about the source or destination. + + + + Initializes a new instance of the ApplicationException class with a specified error message and a reference to the inner exception that is the cause of this exception. + + The error message that explains the reason for the exception. + The exception that is the cause of the current exception. If the innerException parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception + + + + Class that represents a shape file header record. + + + + + Initializes a new instance of the ShapefileHeader class with values read in from the stream. + + Reads the header information from the stream. + BigEndianBinaryReader stream to the shapefile. + + + + Initializes a new instance of the ShapefileHeader class. + + + + + Gets and sets the bounds of the shape file. + + + + + Gets and sets the shape file type i.e. polygon, point etc... + + + + + Gets and sets the shapefile version. + + + + + Gets and sets the length of the shape file in words. + + + + + Writes a shapefile header to the given stream; + + The binary writer to use. + + + + This class represnts an ESRI Shapefile. + + + + + Initializes a new instance of the Shapefile class with the given parameter + and a standard GeometryFactory. + + The filename of the shape file to read (with .shp). + + + + Gets the bounds of the shape file. + + + + + Returns an enumerator that iterates through a collection. + + + An object + that can be used to iterate through the collection. + + + + + Reads the shapefile and returns a GeometryCollection representing all the records in the shapefile. + + GeometryCollection representing every record in the shapefile. + + + + Summary description for ShapefileEnumerator. + + + Summary description for ShapefileEnumerator. + + + + + Sets the enumerator to its initial position, which is + before the first element in the collection. + + + The collection was modified after the enumerator was created. + + + + + Advances the enumerator to the next element of the collection. + + + true if the enumerator was successfully advanced to the next element; + false if the enumerator has passed the end of the collection. + + The collection was modified after the enumerator was created. + + + + Gets the current element in the collection. + + + The current element in the collection. + + The enumerator is positioned before the first element + of the collection or after the last element. + + + + + Initializes a new instance of the class. + + + + + + Performs application-defined tasks associated with freeing, + releasing, or resetting unmanaged resources. + + + + + Initializes a new instance of the Shapefile class with the given parameters. + + The filename of the shape file to read (with .shp). + The GeometryFactory to use when creating Geometry objects. + + + + This class writes ESRI Shapefiles. + + + + + Initializes a buffered writer where you can write shapes individually to the file. + + The filename + The geometry type + + + + Initializes a new instance of the class + with the given . + + + + + + Adds a shape to the shapefile. You must have used the constrcutor with a filename to use this method! + + + + + + Method to write a collection of geometries to a shapefile on disk. + + + Assumes the type given for the first geometry is the same for all subsequent geometries. + For example, is, if the first Geometry is a Multi-polygon/ Polygon, the subsequent geometies are + Muli-polygon/ polygon and not lines or points. + The dbase file for the corresponding shapefile contains one column called row. It contains + the row number. + + The filename to write to (minus the .shp extension). + The GeometryCollection to write. + Set to true to create an empty DBF-file along with the shp-file + + + + Method to write a dummy dbf file + + The dbase filename + The number of records + + + + Method to write a dummy dbase file + + The stream provider registry + The number of records + + + + Method to write a dummy dbase file + + The dbase file writer + The number of records + + + + Write the enumeration of features to shapefile (shp, shx and dbf) + + Filename to create + Enumeration of features to write, features will be enumerated once + Fields that should be written, only those attributes specified here will be mapped from the feature attributetable while writing + Type of geometries shapefile + Optional Encoding to be used when writing the DBF-file (default Windows-1252) + + + + Feature type enumeration + + + + + Null Shape + + + + + Point + + + + + LineString + + + + + Polygon + + + + + MultiPoint + + + + + PointMZ + + + + + PolyLineMZ + + + + + PolygonMZ + + + + + MultiPointMZ + + + + + PointM + + + + + LineStringM + + + + + PolygonM + + + + + MultiPointM + + + + + MultiPatch + + + + + PointZ + + + + + LineStringZ + + + + + PolygonZ + + + + + MultiPointZ + + + + + Contains methods for reading a single Geometry in binary ESRI shapefile format. + + + + + creator. + + + + + Initialize reader with a standard GeometryFactory. + + + + + Initialize reader with the given GeometryFactory. + + + + + + Function to read a from a ShapeFile stream using the specified . + + The reader to use + The ordinates to read + The read point geometry + + + + Function to read a or from a ShapeFile stream using the specified . + + The reader to use + The ordinates to read + The read lineal geometry + + + + Function to read a either a or an from a ShapeFile stream using the specified . + + The reader to use + The ordinates to read + The read polygonal geometry + + + + Function to read a from a ShapeFile stream using the specified . + + The reader to use + The ordinates to read + The read polygonal geometry + + + + Creates a MultiLineString. + + + + + + Creates a single Polygon with holes. + + + + + + + Creates a single Polygon without holes. + + + + + + + Read the x-y Envelope + + The reader to use + + + + Read the ordinate range Envelope + + The reader to use + + + + + + + + + + + + + + + + + + Read the index parts of the shape header + + The reader + The number of parts + The total number of points + An array of integer values + + + + Method to read the coordinates block + + The reader + The total number of points to read + The markers + The ordinates to read + The buffer to add the coordinates to. + + + + Contains methods for writing a single Geometry in binary ESRI Shapefile format. + + + + + Standard byte size for each complex point. + Each complex point (LineString, Polygon, ...) contains + 4 bytes for ShapeTypes and + 32 bytes for bounding box. + + + + + Creates a ShapeWriter that creates objects using a basic GeometryFactory. + + + + + Write the of the using the provided + + The sequence + The writer + The ordinates, and are written in any case. + + + + Evaluates the of the -values in + and writes it using the provided + + The sequence + The ordinate + The writer + + + + Writes to a stream using + + The point to write + The writer to use + + + + Writes to a stream using + + The LineString to write + The writer to use + + + + Writes to a stream using + + The polygon to write + The writer to use + + + + Writes to a stream using + + The multi point to write + The writer to use + + + + Function to determine which ordinates are set in the . + To do that, this function looks for the first geometry that has a property. + Assuming all other geometries have the same ordinates at hand. + + The geometry + The ordinates flag + + + + Writes to a stream using + + The MultiLineString to write + The writer to use + + + + Writes to a stream using + + The multi polygon to write + The writer to use + + + + Writes the 2D using + + The bounding box to write + The writer + + + + Sets correct length for Byte Stream. + + + + + + + Return correct length for Byte Stream. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Copies a section of a to another . + The sequences may have different dimensions; + in this case only the common dimensions are copied. + + The sequence to copy coordinates from + The starting index of the coordinates to copy + The sequence to which the coordinates should be copied to + The starting index of the coordinates in + The number of coordinates to copy + + + + Copies a coordinate of a to another . + The sequences may contain different ; in this case only the common ordinates are copied. + + The sequence to copy coordinate from + The index of the coordinate to copy + The sequence to which the coordinate should be copied to + The index of the coordinate in + + + + A stream provider that provides s. + + + + + Creates an instance of this class + + The kind of stream + + + + Creates an instance of this class + + The kind of stream + A text to store + An encoding to get the bytes. + If null, is used + + + + Creates an instance of this class + + The kind of stream + The stream + A value indicating whether the contents are read-only + + + + Creates an instance of this class + + The kind of stream + The array of bytes + The maximum length of the + A value indicating whether the contents are read-only + + + + Gets a value indicating the maximum size of the + + + + + Gets a value indicating the used range of the + + + + + Copy the stream to a byte array + + The stream to copy to a byte array + byte array + + + + Array of bytes + + + + + Gets a value indicating that the underlying stream is read-only + + + + + Function to return a Stream of the bytes + + An opened stream + + + + Function to open the underlying stream for writing purposes + + If is not true + this method shall fail + An opened stream + Thrown if is true + + + + Gets a value indicating the kind of stream + + + + + A stream provider that provides s who are managed by the application. + + + + + Creates an instance of this class + + The kind of stream + A managed by the application + + + + Gets a value indicating that the underlying stream is read-only + + + + + Function to return a Stream of the bytes + + An opened stream + + + + Function to open the underlying stream for writing purposes + + If is not true + this method shall fail + An opened stream + Thrown if is true or the underlying stream doesn't support seeking + + + + Gets a value indicating the kind of stream + + + + + An implementation of that gives acces to file streams + + + + + Creates an instance of this class + + The kind of stream + The path to the stream + A value indicating if the provided path is to be validated + + + + Gets a value indicating the path to the file + + + + + Gets a value indicating that the underlying stream is read-only + + + + + Function to open the underlying stream for reading purposes + + An opened stream + + + + Function to open the underlying stream for writing purposes + + If is true this method shall fail + An opened stream + + + + Gets a value indicating the kind of stream + + + + + Interface for stream provider + + + + + Gets a value indicating that the underlying stream is read-only + + + + + Function to open the underlying stream for reading purposes + + An opened stream + + + + Function to open the underlying stream for writing purposes + + If is true + this method shall fail + An opened stream + + + + Gets a value indicating the kind of stream + + + + + Interface for a registry of stream providers that -altogether- form a spatial dataset. + + + + + Indexer for a stream provider + + The stream type + A stream provider + + If no stream provider for the requested can be provided, null is to be returned.
+ Do not throw an exception! +
+
+ + + An enumeration of stream types + + + + + A shape stream (*.shp) + + + + + An index stream (*.shx) + + + + + A projection string (*.prj) + + + + + A data stream (*.dbf) + + + + + A data encoding stream (*.cpg) + + + + + A spatial index stream (*.sbn) + + + + + A spatial index index stream (*.sbx) + + + + + A stream provider registry for an ESRI Shapefile dataset + + + + + Creates an instance of this class + + The path to the shapefile + A value indicating that the must be validated + A value indicating that the data file modified must be validated + A value indicating that the shape index modified must be validated + + + + Creates an instance of this class + + A stream provider for the shape stream + A stream provider for the data stream + A value indicating that the must be validated + A value indicating that the must be validated + + + + Creates an instance of this class + + A stream provider for the shape stream + A stream provider for the data stream + A stream provider for the shape index stream + A value indicating that the must be validated + A value indicating that the must be validated + A value indicating that the must be validated + + + + + + + + Indexer for a stream provider + + The stream type + A stream provider + + + + Utility class for storing coordinates + + + This class may be useful for other IO classes as well + + + + + Utility to check values for a defined null/no-data-value + + + + + Initializes this structure with a + + The value that is to be treated as null + This optional parameter controls whether a value has to be less than to be considered null + + + + Checks if doesn't satisfy null-check + + The value to check + true if is not equal to + + + + Checks if does satisfy null-check + + The value to check + true if is equal to + + + + Gets the defined null value + + + + + Creates an instance of this class + + + + + Creates an instance of this class with defining the values that should be treated as null. + + The value that should be treated as null. + This optional parameter controls whether a value has to be less than to be considered null + + + + Creates an instance of this class with an initial + + The initial capacity of the buffer. + + + + Creates an instance of this class with an initial + + The initial capacity of the buffer. + The value that should be treated as null. + This optional parameter controls whether a value has to be less than to be considered null + + + + Updates the flags + + The z-Ordinate + The m-Ordinate + + + + Gets or sets the used to create a coordinate sequence from the coordinate data in the buffer. + + + + + Gets the number of coordinates added to the buffer + + + + + Gets the defined ordinates in this buffer + + + + + Gets the number of dimension a coordinate sequence must provide + + + + + Gets a value indicating if this buffer contains any z-ordinate values + + + + + Gets a value indicating if this buffer contains any m-ordinate values + + + + + Gets the (current) capacity of the buffer + + + + + Adds a coordinate made up of the ordinates (x, y, z, m) to the buffer. + + The x-Ordinate + The y-Ordinate + The (optional) z-Ordinate + The (optional) m-Ordinate + Allows repeated coordinates to be added + true if the coordinate was successfully added. + + + + Method to add a marker + + + + + Inserts a coordinate made up of the ordinates (, , , ) at index to the buffer. + + The index at which to insert the ordinate. + The x-Ordinate + The y-Ordinate + The (optional) z-Ordinate + The (optional) m-Ordinate + Allows repeated coordinates to be added + true if the coordinate was successfully inserted. + + + + Clears the contents of this buffer + + + + + Converts the contents of the buffer to an array of s + + An array of s + + + + Converts the contents of this to a coordinate sequence using the provided . + + The converter to use + A coordinate sequence + + + + Converts the contents of this to a coordinate sequence. + + A coordinate sequence + + + + Converts the contents of this to a coordinate sequence. + + A coordinate sequence + + + + Sets a z-value at the provided + + The index + The value + + + + Sets a m-value at the provided + + The index + The value + + + + Converts the contents of this to an array of and values. + + An array of s + + + + Converts the contents of this to an array of and values. + Additionally an array of values is supplied if this instance property is true + + An array of s + + + + Converts the contents of this to an array of and values. + Additionally an array of values is supplied if this instance property is true + + An array of s + + + + Converts the contents of this to an array of and values. + Additionally an array of and one of values is supplied if this instance and or property is true + + An array of s + + + + Converts the contents of this to an array of values. + + The number of dimensions and an array of s + + + + Converts the contents of this to an array of values. + + The number of dimensions and an array of s + + + + Checks of is equal to this. + + The coordinate buffer to test. + true if the coordinates in this buffer match those of other. + + + + Checks a coordinate sequence for equality with this + + The coordinate sequence to test + true if the coordinates in the coordinate sequence are equal to those in this buffer. + + + + + + + + + + + + + Creates a coordinate sequence, that has all possibly repeated points removed + + Controls if z- and m-values are to be considered in the equality check. + A coordinate buffer without repeated points + +
+
From 37f7d82eb4834c5d4573f0566a150c38f08c6665 Mon Sep 17 00:00:00 2001 From: Felix Obermaier Date: Wed, 16 Feb 2022 10:55:22 +0100 Subject: [PATCH 18/19] Improve polygon building Added 2 more variants to build the polygons. * Sequential Assumes that polygons are always serialized `shell[, holes][, shell[, holes][, ...]]` and thus starts a new polygon when the current ring is not contained by the current polygon. This is slightly faster than the current default implementation. * UsePolygonizer Throws all rings at the `NetTopologySuite.Operations.Polygonize.Polygonizer` and lets it build the polygon. This is really slow. --- .../Handlers/PolygonBuilder.cs | 55 +++++++ .../Handlers/PolygonHandler.cs | 141 +++++++++++++++++- .../Shapefile.cs | 18 +-- .../Issue70Fixture.cs | 82 ++++++++-- 4 files changed, 261 insertions(+), 35 deletions(-) create mode 100644 src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonBuilder.cs diff --git a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonBuilder.cs b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonBuilder.cs new file mode 100644 index 0000000..8d5b97a --- /dev/null +++ b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonBuilder.cs @@ -0,0 +1,55 @@ +namespace NetTopologySuite.IO.Handlers +{ + /// + /// Specifies the polygon building algorithm to use. + /// + /// Rings order explained. + public enum PolygonBuilder + { + /// + /// The default polygon builder to use. Defaults to + /// + Default, + + /// + /// Depends on Shapefile's ring orientation semantics + /// + /// Ring typeOrientation + /// ShellClockwise, Shapefile's left-hand-rule + /// HoleCounter-Clockwise, Shapefile's right-hand-rule + /// + /// + Legacy = Default, + + /// + /// Here's the logic applied when the flag is enabled + /// + /// Considering all rings as a potential shell, search the valid holes for any possible shell. + /// Check if the ring is inside any shell: if true, it can be considered a potential hole for the shell. + /// Check if the ring is inside any hole of the shell: if true, this means that is actually a shell of a distinct geometry, + /// and NOT a valid hole for the shell; a hole inside another hole is not allowed. + /// + /// + /// + /// Note that this experimental polygon builder is considerably slower + /// - three to four times slower, in fact - than the polygon builder, + /// especially for complex polygons(i.e.: polygons with a large number of holes). + /// + Extended, + + /// + /// No sorting of rings but assume that polygons are serialized in the following order: + /// Shell[, Holes][, Shell[, Holes][, ...]] + /// This leads to the conclusion that the first ring that is not + /// contained by the current polygon, is the start of a new polygon. + /// + Sequential, + + /// + /// Uses + /// + UsePolygonizer + + + } +} diff --git a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs index 4c2439b..b2fb788 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonHandler.cs @@ -7,11 +7,13 @@ namespace NetTopologySuite.IO.Handlers { + /// /// Converts a Shapefile point to a OGIS Polygon. /// public class PolygonHandler : ShapeHandler { + //Thanks to Bruno.Labrecque private static readonly ProbeLinearRing ProbeLinearRing = new ProbeLinearRing(); @@ -86,9 +88,22 @@ public override Geometry Read(BigEndianBinaryReader file, int totalRecordLength, // Geometries via CoordinateSequence further down. GetZMValues(file, totalRecordLength, ref totalRead, buffer, skippedList); - var polys = !Shapefile.ExperimentalPolygonBuilderEnabled - ? InternalBuildPolygons(factory, buffer) - : InternalBuildPolygonsExperimental(factory, buffer); + Polygon[] polys; + switch (Shapefile.PolygonBuilder) + { + case PolygonBuilder.Extended: + polys = InternalBuildPolygonsExperimental(factory, buffer); + break; + case PolygonBuilder.Sequential: + polys = InternalBuildPolygonsEx2(factory, buffer); + break; + case PolygonBuilder.UsePolygonizer: + polys = InternalBuildPolygonsEx3(factory, buffer); + break; + default: + polys = InternalBuildPolygons(factory, buffer); + break; + } if (polys.Length == 0) geom = factory.CreatePolygon(); @@ -241,6 +256,126 @@ bool IsHoleContainedInShell(LinearRing shell, LinearRing hole) => .ToArray(); } + private static Polygon[] InternalBuildPolygonsEx2(GeometryFactory factory, CoordinateBuffer buffer) + { + // Get the resulting sequences + var sequences = buffer.ToSequences(factory.CoordinateSequenceFactory); + + // We do not sort the rings but assume that polygons are serialized in the following + // order: Shell[, Holes]. This leads to the conclusion that the first ring that is not + // contained by the current polygon, is the start of a new polygon. + LinearRing shell = null; + var holes = new List(sequences.Length - 1); + + // Utility function to test if a ring is a potential hole for a shell + bool IsRingContainedByShell(LinearRing testShell, LinearRing testRing) => + shell.EnvelopeInternal.Contains(testRing.EnvelopeInternal) + && PointLocation.IsInRing(testRing.GetCoordinateN(0), shell.CoordinateSequence); + + + var res = new List(sequences.Length); + for (int i = 0; i < sequences.Length; i++) + { + // Skip garbage input data with 0 points + if (sequences[i].Count < 1) continue; + + var tmp = EnsureClosedSequence(sequences[i], factory.CoordinateSequenceFactory); + var testRing = factory.CreateLinearRing(tmp); + if (shell == null) + { + shell = testRing; + } + else + { + // Flag indicating if we this ring starts a new polygon + bool newPolygon = false; + + // If the ring is not contained by the shell, we have a new polygon + if (!IsRingContainedByShell(shell, testRing)) + { + newPolygon = true; + } + else + { + // If any hole contains this ring, we have a new polygon + foreach (var hole in holes) + { + if (IsRingContainedByShell((LinearRing)hole, testRing)) + { + newPolygon = true; + break; + } + } + + // Otherwise add this ring to the holes list + holes.Add(testRing); + } + + // If we have to start a new polygon we do it now + if (newPolygon) + { + res.Add(factory.CreatePolygon(shell, holes.ToArray())); + shell = testRing; + holes.Clear(); + } + } + } + + if (shell != null) + res.Add(factory.CreatePolygon(shell, holes.ToArray())); + + return res.ToArray(); + + //// We do not sort the rings but assume that polygons are serialized in the following + //// order: Shell[, Holes]. This leads to the conclusion that the first ring that is not + //// contained by the current polygon, is the start of a new polygon. + //var res = new List(); + //var currentPolygon = factory.CreatePolygon(rings[0]); + //res.Add(currentPolygon); + + //var holes = new List(); + //for (int i = 1; i < rings.Count; i++) + //{ + // if (currentPolygon.Contains(rings[i])) + // { + // holes.Add(rings[i]); + // currentPolygon = factory.CreatePolygon((LinearRing)currentPolygon.ExteriorRing, holes.ToArray()); + // } + // else + // { + // holes.Clear(); + // currentPolygon = factory.CreatePolygon(rings[i]); + // } + //} + + //return res.ToArray(); + } + + private static Polygon[] InternalBuildPolygonsEx3(GeometryFactory factory, CoordinateBuffer buffer) + { + // Get the resulting sequences + var sequences = buffer.ToSequences(factory.CoordinateSequenceFactory); + + // Add rings to polygonizer + var polygonizer = new Operation.Polygonize.Polygonizer(true); + polygonizer.IsCheckingRingsValid = false; + for (int i = 0; i < sequences.Length; i++) + { + // Skip garbage input data with 0 points + if (sequences[i].Count < 1) continue; + + var tmp = EnsureClosedSequence(sequences[i], factory.CoordinateSequenceFactory); + if (tmp == null) continue; + polygonizer.Add(factory.CreateLinearRing(tmp)); + } + + var polygonal = polygonizer.GetGeometry(); + if (polygonal is MultiPolygon mp) + return mp.Geometries.Cast().ToArray(); + + return new [] {(Polygon)polygonal}; + } + /// /// Writes a Geometry to the given binary wirter. /// diff --git a/src/NetTopologySuite.IO.ShapeFile/Shapefile.cs b/src/NetTopologySuite.IO.ShapeFile/Shapefile.cs index 7422eca..d1eddc2 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Shapefile.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Shapefile.cs @@ -14,23 +14,9 @@ public static partial class Shapefile internal const int Version = 1000; /// - /// Here's the logic applied when the flag is enabled: - /// 1. Considering all rings as a potential shell, - /// search the valid holes for any possible shell. - /// 2. Check if the ring is inside any shell: if true, - /// it can be considered a potential hole for the shell. - /// 3. Check if the ring is inside any hole of the shell: if true, - /// this means that is actually a shell of a distinct geometry, - /// and NOT a valid hole for the shell; a hole inside - /// another hole is not allowed. + /// Gets or sets a value indicating the polygon building algorithm to use. /// - /// - /// Note that the experimental polygon builder is considerably slower - /// - three to four times slower, in fact - than the standard polygon builder, - /// especially for complex polygons(i.e.: polygons with a large number of holes). - /// - /// Rings order explained. - public static bool ExperimentalPolygonBuilderEnabled { get; set; } + public static PolygonBuilder PolygonBuilder { get; set; } /// /// Given a geomtery object, returns the equivalent shape file type. diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs index e6a21a1..f934ad3 100644 --- a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs +++ b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs @@ -7,6 +7,7 @@ using NetTopologySuite.Features; using System; using System.Diagnostics; +using NetTopologySuite.IO.Handlers; namespace NetTopologySuite.IO.ShapeFile.Test { @@ -23,7 +24,7 @@ public class Issue70Fixture [TearDown] public void AfterEachTestExecution() { - Shapefile.ExperimentalPolygonBuilderEnabled = false; + Shapefile.PolygonBuilder = 0; } private static string GetShapefilePath() @@ -59,13 +60,29 @@ private static Polygon ReadPolyBadlyOrientedUsingShapeDataReader() return (Polygon)features.Single().Geometry; } + /// + /// + /// + [TestCase(PolygonBuilder.Legacy, 0)] + [TestCase(PolygonBuilder.Extended, 1)] + [TestCase(PolygonBuilder.Sequential, 1)] + [TestCase(PolygonBuilder.UsePolygonizer, 1)] + public void TestReadPolygonWithWrongShellOrientation(PolygonBuilder polygonBuilder, int numHoles) + { + Shapefile.PolygonBuilder = polygonBuilder; + var poly = ReadPolyBadlyOriented(); + Assert.That(poly.Shell, Is.Not.Null); + Assert.That(poly.Holes, Is.Not.Null); + Assert.That(poly.Holes.Length, Is.EqualTo(numHoles)); + } + /// /// /// [Test] public void TestReadPolygonWithWrongShellOrientationReadsHoleWithFlagEnabled() { - Shapefile.ExperimentalPolygonBuilderEnabled = true; + Shapefile.PolygonBuilder = PolygonBuilder.Extended; var poly = ReadPolyBadlyOriented(); Assert.That(poly.Shell, Is.Not.Null); Assert.That(poly.Holes, Is.Not.Null); @@ -84,7 +101,7 @@ public void TestReadPolygonWithWrongShellOrientationDoesntReadHoleWithFlagDisabl [Test] public void TestReadPolygonWithWrongShellOrientationReadsHoleWithFlagEnabledUsingShapeDataReader() { - Shapefile.ExperimentalPolygonBuilderEnabled = true; + Shapefile.PolygonBuilder = PolygonBuilder.Extended; var poly = ReadPolyBadlyOrientedUsingShapeDataReader(); Assert.That(poly.Shell, Is.Not.Null); Assert.That(poly.Holes, Is.Not.Null); @@ -228,24 +245,44 @@ private static void TestReaderPerformances(string fname, Path.GetFileNameWithoutExtension(fname)); Console.WriteLine(shapeReader ? "ShapeReader" : "ShapeFileDataReader"); - Shapefile.ExperimentalPolygonBuilderEnabled = false; - Assert.That(Shapefile.ExperimentalPolygonBuilderEnabled, Is.False); + Shapefile.PolygonBuilder = PolygonBuilder.Legacy; + Assert.That(Shapefile.PolygonBuilder, Is.EqualTo(PolygonBuilder.Legacy)); var w = Stopwatch.StartNew(); int readDisabled = shapeReader ? ReadDataUsingShapeDataReader(fnameWoExt) : ReadDataUsingShapeFileDataReader(fnameWoExt); w.Stop(); - Console.WriteLine($"flag DISABLED => elapsed: '{w.Elapsed}'"); + Console.WriteLine($"{Shapefile.PolygonBuilder} => elapsed: '{w.Elapsed}'"); Assert.That(readDisabled, Is.EqualTo(featuresCount)); - Shapefile.ExperimentalPolygonBuilderEnabled = true; - Assert.That(Shapefile.ExperimentalPolygonBuilderEnabled, Is.True); + Shapefile.PolygonBuilder = PolygonBuilder.Extended; + Assert.That(Shapefile.PolygonBuilder, Is.EqualTo(PolygonBuilder.Extended)); w.Restart(); int readEnabled = shapeReader ? ReadDataUsingShapeDataReader(fnameWoExt) : ReadDataUsingShapeFileDataReader(fnameWoExt); w.Stop(); - Console.WriteLine($"flag ENABLED => elapsed: '{w.Elapsed}'"); + Console.WriteLine($"{Shapefile.PolygonBuilder} => elapsed: '{w.Elapsed}'"); + Assert.That(readEnabled, Is.EqualTo(featuresCount)); + + Shapefile.PolygonBuilder = PolygonBuilder.Sequential; + Assert.That(Shapefile.PolygonBuilder, Is.EqualTo(PolygonBuilder.Sequential)); + w.Restart(); + readEnabled = shapeReader + ? ReadDataUsingShapeDataReader(fnameWoExt) + : ReadDataUsingShapeFileDataReader(fnameWoExt); + w.Stop(); + Console.WriteLine($"{Shapefile.PolygonBuilder} => elapsed: '{w.Elapsed}'"); + Assert.That(readEnabled, Is.EqualTo(featuresCount)); + + Shapefile.PolygonBuilder = PolygonBuilder.UsePolygonizer; + Assert.That(Shapefile.PolygonBuilder, Is.EqualTo(PolygonBuilder.UsePolygonizer)); + w.Restart(); + readEnabled = shapeReader + ? ReadDataUsingShapeDataReader(fnameWoExt) + : ReadDataUsingShapeFileDataReader(fnameWoExt); + w.Stop(); + Console.WriteLine($"{Shapefile.PolygonBuilder} => elapsed: '{w.Elapsed}'"); Assert.That(readEnabled, Is.EqualTo(featuresCount)); } @@ -267,7 +304,7 @@ private static int ReadDataUsingShapeDataReader(string fname) } [Test] - [Ignore("PerformancesTest")] + [Explicit] public void TestPerformances() { string fname = WriteFeatures(out int featuresCount); @@ -289,12 +326,12 @@ private static TimeSpan TestReaderPerformancesSimple(string fname) private const int PerfTestNum = 20; [Test] - [Ignore("PerformancesTest")] + [Explicit] public void TestPerformancesAvgWithFlagDisabled() { string fname = WriteFeatures(out int _); - Shapefile.ExperimentalPolygonBuilderEnabled = false; - Assert.That(Shapefile.ExperimentalPolygonBuilderEnabled, Is.False); + Shapefile.PolygonBuilder = PolygonBuilder.Default; + Assert.That(Shapefile.PolygonBuilder, Is.EqualTo(PolygonBuilder.Default)); double avg = Enumerable.Range(0, PerfTestNum) .Select(_ => TestReaderPerformancesSimple(fname)) .Average(ts => ts.TotalMilliseconds); @@ -302,12 +339,25 @@ public void TestPerformancesAvgWithFlagDisabled() } [Test] - [Ignore("PerformancesTest")] + [Explicit] public void TestPerformancesAvgWithFlagEnabled() { string fname = WriteFeatures(out int _); - Shapefile.ExperimentalPolygonBuilderEnabled = true; - Assert.That(Shapefile.ExperimentalPolygonBuilderEnabled, Is.True); + Shapefile.PolygonBuilder = PolygonBuilder.Extended; + Assert.That(Shapefile.PolygonBuilder, Is.EqualTo(PolygonBuilder.Extended)); + double avg = Enumerable.Range(0, PerfTestNum) + .Select(_ => TestReaderPerformancesSimple(fname)) + .Average(ts => ts.TotalMilliseconds); + Console.WriteLine($"flag ENABLED: n='{PerfTestNum}' => ms='{avg}'"); + } + + [Test] + [Explicit] + public void TestPerformancesAvgWithEx2Enabled() + { + string fname = WriteFeatures(out int _); + Shapefile.PolygonBuilder = PolygonBuilder.Sequential; + Assert.That(Shapefile.PolygonBuilder, Is.EqualTo(PolygonBuilder.Sequential)); double avg = Enumerable.Range(0, PerfTestNum) .Select(_ => TestReaderPerformancesSimple(fname)) .Average(ts => ts.TotalMilliseconds); From 14879f47c1e9ce629b70ae28b03e1e9c403e86cc Mon Sep 17 00:00:00 2001 From: Diego Guidi Date: Thu, 17 Feb 2022 09:07:36 +0100 Subject: [PATCH 19/19] minor changes to tests --- .../Handlers/PolygonBuilder.cs | 12 ++--- .../Issue70Fixture.cs | 46 +++++++++---------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonBuilder.cs b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonBuilder.cs index 8d5b97a..876fb11 100644 --- a/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonBuilder.cs +++ b/src/NetTopologySuite.IO.ShapeFile/Handlers/PolygonBuilder.cs @@ -7,12 +7,12 @@ public enum PolygonBuilder { /// - /// The default polygon builder to use. Defaults to + /// The default polygon builder to use. Defaults to . /// Default, /// - /// Depends on Shapefile's ring orientation semantics + /// Depends on Shapefile's ring orientation semantics. /// /// Ring typeOrientation /// ShellClockwise, Shapefile's left-hand-rule @@ -22,7 +22,7 @@ public enum PolygonBuilder Legacy = Default, /// - /// Here's the logic applied when the flag is enabled + /// Here's the logic applied when the flag is enabled: /// /// Considering all rings as a potential shell, search the valid holes for any possible shell. /// Check if the ring is inside any shell: if true, it can be considered a potential hole for the shell. @@ -33,13 +33,13 @@ public enum PolygonBuilder /// /// Note that this experimental polygon builder is considerably slower /// - three to four times slower, in fact - than the polygon builder, - /// especially for complex polygons(i.e.: polygons with a large number of holes). + /// especially for complex polygons (i.e.: polygons with a large number of holes). /// Extended, /// - /// No sorting of rings but assume that polygons are serialized in the following order: - /// Shell[, Holes][, Shell[, Holes][, ...]] + /// No sorting of rings but assume that polygons are serialized + /// in the following order: Shell[, Holes][, Shell[, Holes][, ...]]. /// This leads to the conclusion that the first ring that is not /// contained by the current polygon, is the start of a new polygon. /// diff --git a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs index f934ad3..6df7760 100644 --- a/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs +++ b/test/NetTopologySuite.IO.ShapeFile.Test/Issue70Fixture.cs @@ -24,7 +24,7 @@ public class Issue70Fixture [TearDown] public void AfterEachTestExecution() { - Shapefile.PolygonBuilder = 0; + Shapefile.PolygonBuilder = PolygonBuilder.Default; } private static string GetShapefilePath() @@ -325,43 +325,43 @@ private static TimeSpan TestReaderPerformancesSimple(string fname) private const int PerfTestNum = 20; - [Test] - [Explicit] - public void TestPerformancesAvgWithFlagDisabled() + private static void TestReaderPerformancesSimple(PolygonBuilder pb) { string fname = WriteFeatures(out int _); - Shapefile.PolygonBuilder = PolygonBuilder.Default; - Assert.That(Shapefile.PolygonBuilder, Is.EqualTo(PolygonBuilder.Default)); + Shapefile.PolygonBuilder = pb; + Assert.That(Shapefile.PolygonBuilder, Is.EqualTo(pb)); double avg = Enumerable.Range(0, PerfTestNum) .Select(_ => TestReaderPerformancesSimple(fname)) .Average(ts => ts.TotalMilliseconds); - Console.WriteLine($"flag DISABLED: n='{PerfTestNum}' => ms='{avg}'"); + Console.WriteLine($"{pb}: n='{PerfTestNum}' => average ms='{avg}'"); } [Test] [Explicit] - public void TestPerformancesAvgWithFlagEnabled() + public void TestPerformancesWithDefaultPolygonBuilder() { - string fname = WriteFeatures(out int _); - Shapefile.PolygonBuilder = PolygonBuilder.Extended; - Assert.That(Shapefile.PolygonBuilder, Is.EqualTo(PolygonBuilder.Extended)); - double avg = Enumerable.Range(0, PerfTestNum) - .Select(_ => TestReaderPerformancesSimple(fname)) - .Average(ts => ts.TotalMilliseconds); - Console.WriteLine($"flag ENABLED: n='{PerfTestNum}' => ms='{avg}'"); + TestReaderPerformancesSimple(PolygonBuilder.Default); } [Test] [Explicit] - public void TestPerformancesAvgWithEx2Enabled() + public void TestPerformancesWithExtendedPolygonBuilder() { - string fname = WriteFeatures(out int _); - Shapefile.PolygonBuilder = PolygonBuilder.Sequential; - Assert.That(Shapefile.PolygonBuilder, Is.EqualTo(PolygonBuilder.Sequential)); - double avg = Enumerable.Range(0, PerfTestNum) - .Select(_ => TestReaderPerformancesSimple(fname)) - .Average(ts => ts.TotalMilliseconds); - Console.WriteLine($"flag ENABLED: n='{PerfTestNum}' => ms='{avg}'"); + TestReaderPerformancesSimple(PolygonBuilder.Extended); + } + + [Test] + [Explicit] + public void TestPerformancesWithSequentialPolygonBuilder() + { + TestReaderPerformancesSimple(PolygonBuilder.Sequential); + } + + [Test] + [Explicit] + public void TestPerformancesWithUsePolygonizerPolygonBuilder() + { + TestReaderPerformancesSimple(PolygonBuilder.UsePolygonizer); } } }

l`Uo5A2-D4CQu3 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ɏo?4f8t+YMz2CX$l2>T+y(8L^d-Csq<0TeWPnbV% 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