// Use acceleration to speed up relational operations. Accelerate your source geometry only if you are going to test many other geometries against it.
// Acceleration is applicable for polylines and polygons only. Note that accelerated geometries take more memory so if you aren't going to get any
// benefit from accelerating it, don't do it.
// The performance of the following GeometryEngine functions are the only ones which can be improved with an accelerated geometry.
// GeometryEngine.Instance.Contains
// GeometryEngine.Instance.Crosses
// GeometryEngine.Instance.Disjoint
// GeometryEngine.Instance.Disjoint3D
// GeometryEngine.Instance.Equals
// GeometryEngine.Instance.Intersects
// GeometryEngine.Instance.Relate
// GeometryEngine.Instance.Touches
// GeometryEngine.Instance.Within
// Note: Needs QueuedTask to run
{
// accelerate the geometry to test
var acceleratedPoly = GeometryEngine.Instance.AccelerateForRelationalOperations(polygon);
// loop through all the geometries to test against
foreach (var testPolygon in testPolygons)
{
bool contains = GeometryEngine.Instance.Contains(acceleratedPoly, testPolygon);
bool within = GeometryEngine.Instance.Within(acceleratedPoly, testPolygon);
bool crosses = GeometryEngine.Instance.Crosses(acceleratedPoly, testPolygon);
// do something with the results...
}
}
Determine area of a polygon
var g1 = PolygonBuilderEx.FromJson("{\"rings\": [ [ [0, 0], [10, 0], [10, 10], [0, 10] ] ] }");
double d = GeometryEngine.Instance.Area(g1);
// d = -100.0 //negative due to wrong ring orientation
d = GeometryEngine.Instance.Area(GeometryEngine.Instance.SimplifyAsFeature(g1));
// d = 100.0 // feature has been simplifed; ring orientation is correct
Determine the boundary of a multi-part Polygon
// create a donut polygon. Must use the PolygonBuilderEx object
List<Coordinate2D> outerPts =
[
new Coordinate2D(10.0, 10.0),
new Coordinate2D(10.0, 20.0),
new Coordinate2D(20.0, 20.0),
new Coordinate2D(20.0, 10.0),
];
List<Coordinate2D> innerPts =
[
new Coordinate2D(13.0, 13.0),
new Coordinate2D(17.0, 13.0),
new Coordinate2D(17.0, 17.0),
new Coordinate2D(13.0, 17.0),
];
Polygon donut = null;
// add the outer points
PolygonBuilderEx pb = new(outerPts);
// add the inner points (note they are defined anticlockwise)
pb.AddPart(innerPts);
// get the polygon
donut = pb.ToGeometry();
// get the boundary
Geometry g = GeometryEngine.Instance.Boundary(donut);
Polyline boundary = g as Polyline;
// use the boundary...
Buffer a MapPoint
// buffer a point
MapPoint pt = MapPointBuilderEx.CreateMapPoint(1.0, 1.0, SpatialReferences.WGS84);
Geometry ptBuffer = GeometryEngine.Instance.Buffer(pt, 5.0);
Polygon buffer = ptBuffer as Polygon;
// clip a polyline by an envelope
Envelope env = EnvelopeBuilderEx.CreateEnvelope(2.0, 2.0, 4.0, 4.0);
LineSegment line = LineBuilderEx.CreateLineSegment(new Coordinate2D(0, 3), new Coordinate2D(5.0, 3.0));
polyline = PolylineBuilderEx.CreatePolyline(line);
Geometry clipGeom = GeometryEngine.Instance.Clip(polyline, env);
Clip a Polyline by a Polygon
// clip a polyline by a polygon
List<Coordinate2D> list =
[
new Coordinate2D(1.0, 1.0),
new Coordinate2D(1.0, 4.0),
new Coordinate2D(4.0, 4.0),
new Coordinate2D(4.0, 1.0),
];
polygon = PolygonBuilderEx.CreatePolygon(list, SpatialReferences.WGS84);
LineSegment crossingLine = LineBuilderEx.CreateLineSegment(MapPointBuilderEx.CreateMapPoint(0, 3), MapPointBuilderEx.CreateMapPoint(5.0, 3.0));
Polyline p = PolylineBuilderEx.CreatePolyline(crossingLine);
Geometry geometry = GeometryEngine.Instance.Clip(p, polygon.Extent);
Construct a geodetic line with specified distance and azimuth
var sr = SpatialReferenceBuilder.CreateSpatialReference(4326);
var mapPoint = MapPointBuilderEx.CreateMapPoint(15, 60, sr);
// calculate
var polylineGeodetic = GeometryEngine.Instance.ConstructGeodeticLineFromDistance(GeodeticCurveType.Loxodrome, mapPoint, 5000000, 45, null, CurveDensifyMethod.ByLength, 300000);
Construct a geodetic line connecting points
var sr = SpatialReferenceBuilder.CreateSpatialReference(4326);
var pt1 = MapPointBuilderEx.CreateMapPoint(60, 180, sr);
var pt2 = MapPointBuilderEx.CreateMapPoint(60, 0, sr);
// densify by length
var gl = GeometryEngine.Instance.ConstructGeodeticLineFromPoints(GeodeticCurveType.Geodesic, pt1, pt2, null, CurveDensifyMethod.ByLength, -3.356);
// densify by deviation
gl = GeometryEngine.Instance.ConstructGeodeticLineFromPoints(GeodeticCurveType.Geodesic, pt1, pt2, null, CurveDensifyMethod.ByDeviation, -0.0026);
Construct a Point at a distance and angle from an existing Point
// build a polyline
polyline = PolylineBuilderEx.CreatePolyline(
[
MapPointBuilderEx.CreateMapPoint(1, 1, 10, 20),
MapPointBuilderEx.CreateMapPoint(0, 0, 10, 20),
MapPointBuilderEx.CreateMapPoint(1, -1, 10, 20)
]);
// build the extender line
var extender = PolylineBuilderEx.CreatePolyline(
[
MapPointBuilderEx.CreateMapPoint(2, 2),
MapPointBuilderEx.CreateMapPoint(2, -2),
]);
// extend
var result = GeometryEngine.Instance.Extend(polyline, extender, ExtendFlags.KeepEndAttributes);
Polyline extendedLine = result as Polyline;
// result.Parts[0].Points[0] = 2, 2, 10, 20
// result.parts[0].Points[1] = 1, 1, 10, 20
// result.Parts[0].Points[2] = 0, 0, 10, 20
// result.Parts[0].Points[3] = 1, -1, 10, 20
// result.Parts[0].Points[4] = 2, -2, 10, 20
// change the flags
result = GeometryEngine.Instance.Extend(polyline, extender, ExtendFlags.NoEndAttributes);
extendedLine = result as Polyline;
// result.Parts[0].Points[0] = 2, 2, 0
// result.parts[0].Points[1] = 1, 1, 10, 20
// result.Parts[0].Points[2] = 0, 0, 10, 20
// result.Parts[0].Points[3] = 1, -1, 10, 20
// result.Parts[0].Points[4] = 2, -2, 0
// extend
result = GeometryEngine.Instance.Extend(polyline, extender, ExtendFlags.KeepEndAttributes | ExtendFlags.NoExtendAtTo);
extendedLine = result as Polyline;
// result.Parts[0].Points[0] = 2, 2, 10, 20
// result.parts[0].Points[1] = 1, 1, 10, 20
// result.Parts[0].Points[2] = 0, 0, 10, 20
// result.Parts[0].Points[3] = 1, -1, 10, 20
// extend with no intersection
polyline = PolylineBuilderEx.CreatePolyline(
[
MapPointBuilderEx.CreateMapPoint(1, 1),
MapPointBuilderEx.CreateMapPoint(3, 1)
]);
extender = PolylineBuilderEx.CreatePolyline(
[
MapPointBuilderEx.CreateMapPoint(1, 4),
MapPointBuilderEx.CreateMapPoint(3, 4)
]);
result = GeometryEngine.Instance.Extend(polyline, extender, ExtendFlags.Default);
// result = null
result = GeometryEngine.Instance.Extend(polyline, extender, ExtendFlags.KeepEndAttributes | ExtendFlags.NoExtendAtTo);
// Use the result ...
Generalize
Polyline generalizedPolyline = GeometryEngine.Instance.Generalize(polylineWithZ, 200) as Polyline;
// generalizedPolyline.HasZ = true
Polygon generalized3DPolyline = GeometryEngine.Instance.Generalize3D(polylineWithZ, 200) as Polygon;
// generalized3DPolyline.HasZ = true
// note that generalized3DPolyline and generalizedPolyline will have different definitions
// i.e generalizedPolyline.IsEqual(generalized3DPolyline) = false
Calculate the Geodesic Area of a polygon
polygon = PolygonBuilderEx.CreatePolygon(
[
MapPointBuilderEx.CreateMapPoint(-10018754.1713946, 10018754.1713946),
MapPointBuilderEx.CreateMapPoint(10018754.1713946, 10018754.1713946),
MapPointBuilderEx.CreateMapPoint(10018754.1713946, -10018754.1713946),
MapPointBuilderEx.CreateMapPoint(-10018754.1713946, -10018754.1713946)
], SpatialReferences.WebMercator);
var area = GeometryEngine.Instance.GeodesicArea(polygon);
// area is close to 255032810857732.31
area = GeometryEngine.Instance.GeodesicArea(polygon, AreaUnit.SquareKilometers);
// area is close to 255032810.85953,
Create a buffer polygon at the specified geodesic distance
// buffer a point
MapPoint pt = MapPointBuilderEx.CreateMapPoint(1.0, 1.0, SpatialReferences.WGS84);
Polygon outPolygon = GeometryEngine.Instance.GeodesicBuffer(pt, 5) as Polygon;
double delta = SpatialReferences.WGS84.XYTolerance * 2 * Math.Sqrt(2);
ReadOnlyPointCollection points = outPolygon.Points;
foreach (MapPoint p in points)
{
double d = GeometryEngine.Instance.GeodesicDistance(pt, p);
// d = 5 (+- delta)
}
// specify a unit for the distance
outPolygon = GeometryEngine.Instance.GeodesicBuffer(pt, 5000, LinearUnit.Millimeters) as Polygon;
// buffer of 0 distance produces an empty geometry
Geometry g = GeometryEngine.Instance.GeodesicBuffer(pt, 0);
// g.IsEmpty = true
// buffer many points
List<MapPoint> list =
[
MapPointBuilderEx.CreateMapPoint(1.0, 1.0, SpatialReferences.WGS84),
MapPointBuilderEx.CreateMapPoint(10.0, 20.0),
MapPointBuilderEx.CreateMapPoint(40.0, 40.0),
MapPointBuilderEx.CreateMapPoint(60.0, 60.0),
];
outPolygon = GeometryEngine.Instance.GeodesicBuffer(list, 10000) as Polygon;
// outPolygon.PartCount = 4
// buffer different geometry types
List<Coordinate2D> coords =
[
new Coordinate2D(1, 2), new Coordinate2D(10, 20), new Coordinate2D(20, 30),
new Coordinate2D(50, 60), new Coordinate2D(70, 80), new Coordinate2D(80, 40),
new Coordinate2D(90, 10), new Coordinate2D(110, 15), new Coordinate2D(120, 30),
new Coordinate2D(10, 40), new Coordinate2D(-10, 40), new Coordinate2D(-10, 50)
];
List<Geometry> manyGeometries =
[
MapPointBuilderEx.CreateMapPoint(1.0, 1.0, SpatialReferences.WGS84),
PolylineBuilderEx.CreatePolyline([coords[0], coords[1], coords[2]], SpatialReferences.WGS84),
PolylineBuilderEx.CreatePolyline([coords[3], coords[4], coords[5]]),
PolygonBuilderEx.CreatePolygon([coords[9], coords[10], coords[11]])
];
outPolygon = GeometryEngine.Instance.GeodesicBuffer(manyGeometries, 20000) as Polygon;
// specify unit types
outPolygon = GeometryEngine.Instance.GeodesicBuffer(manyGeometries, 20, LinearUnit.Miles) as Polygon;
Determine geodesic distance between two Geometries
var point1 = MapPointBuilderEx.CreateMapPoint(-170, 45, SpatialReferences.WGS84);
var point2 = MapPointBuilderEx.CreateMapPoint(170, 45, SpatialReferences.WGS84);
var distances_meters = GeometryEngine.Instance.GeodesicDistance(point1, point2);
// distance is approximately 1572912.2066940258 in meters
var distance_feet = GeometryEngine.Instance.GeodesicDistance(point1, point2, LinearUnit.Feet);
// distance is approximately 5160473.11904786 in feet
polyline = PolylineBuilderEx.CreatePolyline(
[
MapPointBuilderEx.CreateMapPoint(-10018754.1713946, 10018754.1713946),
MapPointBuilderEx.CreateMapPoint(10018754.1713946, 10018754.1713946)
], SpatialReferences.WebMercator);
var length = GeometryEngine.Instance.GeodesicLength(polyline);
// length is approx 5243784.5551844323 in meters
length = GeometryEngine.Instance.GeodesicLength(polyline, LinearUnit.Miles);
// length is approx 3258.33666089067 in miles
var polyline2 = GeometryEngine.Instance.Project(polyline, SpatialReferences.WGS84);
length = GeometryEngine.Instance.GeodesicLength(polyline2);
// length is approx 5243784.55518443 in meters after projecting
List<Coordinate2D> coords =
[
new Coordinate2D(-80, 0),
new Coordinate2D(-20, 60),
new Coordinate2D(40, 20),
new Coordinate2D(0, -20),
new Coordinate2D(-80, 0)
];
SpatialReference sr = SpatialReferences.WGS84;
// create a polyline
polyline = PolylineBuilderEx.CreatePolyline(coords, sr);
// densify in km
Polyline geodesicPolyline = GeometryEngine.Instance.GeodeticDensifyByDeviation(polyline, 200, LinearUnit.Kilometers, GeodeticCurveType.Geodesic) as Polyline;
// densify in m
geodesicPolyline = GeometryEngine.Instance.GeodeticDensifyByDeviation(polyline, 200, LinearUnit.Meters, GeodeticCurveType.Geodesic) as Polyline;
// Change curve type to Loxodrome
Polyline loxodromePolyline = GeometryEngine.Instance.GeodeticDensifyByDeviation(polyline, 200, LinearUnit.Meters, GeodeticCurveType.Loxodrome) as Polyline;
GeodeticDensifyByLength - polygon
List<Coordinate2D> coords =
[
new Coordinate2D(-80, 0),
new Coordinate2D(-20, 60),
new Coordinate2D(40, 20),
new Coordinate2D(0, -20),
new Coordinate2D(-80, 0)
];
SpatialReference sr = SpatialReferences.WGS84;
// create a polygon
polygon = PolygonBuilderEx.CreatePolygon(coords, sr);
// get the geodesic lengths of the polygon segments
ReadOnlySegmentCollection segments = polygon.Parts[0];
List<double> geoLengths = new(segments.Count);
foreach (Segment s in segments)
{
Polyline line = PolylineBuilderEx.CreatePolyline(s, sr);
double geoLen = GeometryEngine.Instance.GeodesicLength(line);
geoLengths.Add(geoLen);
}
// find the max length
geoLengths.Sort();
double maxLen = geoLengths[^1];
// densify the polygon (in meters)
Polygon densifiedPoly = GeometryEngine.Instance.GeodeticDensifyByLength(polygon, maxLen, LinearUnit.Meters, GeodeticCurveType.Geodesic) as Polygon;
// densify the polygon (in km)
double maxSegmentLength = maxLen / 10000;
densifiedPoly = GeometryEngine.Instance.GeodeticDensifyByLength(polygon, maxSegmentLength, LinearUnit.Kilometers, GeodeticCurveType.Geodesic) as Polygon;
Calculate geodetic distance, azimuth between two points
// get all the geographic coordinate systems
IReadOnlyList<CoordinateSystemListEntry> gcs_list = GeometryEngine.Instance.GetPredefinedCoordinateSystemList(CoordinateSystemFilter.GeographicCoordinateSystem);
// get the projected coordinate systems
IReadOnlyList<CoordinateSystemListEntry> proj_list = GeometryEngine.Instance.GetPredefinedCoordinateSystemList(CoordinateSystemFilter.ProjectedCoordinateSystem);
// get the vertical coordinate systems
IReadOnlyList<CoordinateSystemListEntry> vert_list = GeometryEngine.Instance.GetPredefinedCoordinateSystemList(CoordinateSystemFilter.VerticalCoordinateSystem);
// get geographic and projected coordinate systems
IReadOnlyList<CoordinateSystemListEntry> combined_list = GeometryEngine.Instance.GetPredefinedCoordinateSystemList(CoordinateSystemFilter.GeographicCoordinateSystem | CoordinateSystemFilter.ProjectedCoordinateSystem);
// investigate one of the entries
CoordinateSystemListEntry entry = gcs_list[0];
int wkid = entry.Wkid;
string category = entry.Category;
string name = entry.Name;
Retrieve system geographic transformations
// a geographic transformation is the definition of how to project from one spatial reference to another
IReadOnlyList<GeographicTransformationListEntry> list = GeometryEngine.Instance.GetPredefinedGeographicTransformationList();
// a GeographicTransformationListEntry consists of Name, Wkid, the From SpatialReference Wkid, the To SpatialReference Wkid
GeographicTransformationListEntry entry = list[0];
int fromWkid = entry.FromSRWkid;
int toWkid = entry.ToSRWkid;
int wkid = entry.Wkid;
string name = entry.Name;
Get the M values at the specified distance along the multipart
string json = "{\"hasM\":true,\"paths\":[[[-3000,-2000,-3],[-2000,-2000,-2]],[[-2000,-2000,1],[-2000,1000,2]]],\"spatialReference\":{\"wkid\":3857}}";
polyline = PolylineBuilderEx.FromJson(json);
// polyline has 2 parts
GeometryEngine.Instance.GetMsAtDistance(polyline, 0, AsRatioOrLength.AsLength, out double m1, out double m2);
// m1 = -3
// m2 = NaN
GeometryEngine.Instance.GetMsAtDistance(polyline, 500, AsRatioOrLength.AsLength, out m1, out m2);
// m1 = -2.5
// m2 = NaN
GeometryEngine.Instance.GetMsAtDistance(polyline, 1000, AsRatioOrLength.AsLength, out m1, out m2);
// m1 = -2
// m2 = 1 // m2 has a value because distance 1000 is at the end of the first part, beginning of the second part
Insert M value at the given distance - InsertMAtDistance
string json = "{\"hasM\":true,\"paths\":[[[-3000,-2000,-3],[-2000,-2000,-2],[-1000,-2000,null]]]}";
polyline = PolylineBuilderEx.FromJson(json);
// A point already exists at the given distance
double m = -1;
double distance = 2000;
bool createNewPart = false;
Polyline outputPolyline = GeometryEngine.Instance.InsertMAtDistance(polyline, m, distance, AsRatioOrLength.AsLength, createNewPart, out bool splitHappened, out int partIndex, out int segmentIndex) as Polyline;
// splitHappened = false, partIndex = 0, segmentIndex = 2
// outputPolyline.Points[2].M = -1
json = "{\"hasM\":true,\"paths\":[[[-3000,-2000,-3],[-2000,-2000,-2],[-1000,-2000,-1]],[[0,0,0],[0,1000,0],[0,2000,2]]],\"spatialReference\":{\"wkid\":3857}}";
polyline = PolylineBuilderEx.FromJson(json);
// A point already exists at the given distance, but createNewPart = true
m = 1;
distance = 3000;
createNewPart = true;
outputPolyline = GeometryEngine.Instance.InsertMAtDistance(polyline, m, distance, AsRatioOrLength.AsLength, createNewPart, out splitHappened, out partIndex, out segmentIndex) as Polyline;
string outputJson = outputPolyline.ToJson();
// splitHappened = true, partIndex = 2, segmentIndex = 0
// outputJson = {"hasM":true,"paths":[[[-3000,-2000,-3],[-2000,-2000,-2],[-1000,-2000,-1]],[[0,0,0],[0,1000,1]],[[0,1000,1],[0,2000,2]]]}}
// A new part has been created and the M values for outputPolyline.Points[4] and outputPolyline.Points[5] have been modified
// A point does not exist at the given distance
m = 1;
distance = 3500;
createNewPart = false;
outputPolyline = GeometryEngine.Instance.InsertMAtDistance(polyline, m, distance, AsRatioOrLength.AsLength, createNewPart, out splitHappened, out partIndex, out segmentIndex) as Polyline;
outputJson = outputPolyline.ToJson();
// splitHappened = true even though createNewPart = false because a new point was created
// partIndex = 1, segmentIndex = 2
// outputJson = {"hasM":true,"paths":[[[-3000,-2000,-3],[-2000,-2000,-2],[-1000,-2000,-1]],[[0,0,0],[0,1000,0],[0,1500,1],[0,2000,2]]]}
// A new point has been inserted (0, 1500, 1) by interpolating the X and Y coordinates and M value set to the input M value.
Calibrate M values using M values from input points - CalibrateByMs
string json = "{\"hasM\":true,\"paths\":[[[0,0,-1],[1,0,0],[1,1,1],[1,2,2],[3,1,3],[5,3,4],[9,5,5],[7,6,6]]],\"spatialReference\":{\"wkid\":4326}}";
polyline = PolylineBuilderEx.FromJson(json);
// Interpolate using points (0, 0, 17), (1, 0, 42), (7, 6, 18)
List<MapPoint> updatePoints = new(3);
MapPointBuilderEx builder = new(0, 0)
{
M = 17
};
updatePoints.Add(builder.ToGeometry() as MapPoint);
builder.X = 1;
builder.M = 42;
updatePoints.Add(builder.ToGeometry() as MapPoint);
builder.X = 7;
builder.Y = 6;
builder.M = 18;
updatePoints.Add(builder.ToGeometry() as MapPoint);
// Calibrate all the points in the polyline
double cutOffDistance = polyline.Length;
Polyline updatedPolyline = GeometryEngine.Instance.CalibrateByMs(polyline, updatePoints, UpdateMMethod.Interpolate, cutOffDistance) as Polyline;
// The points in the updated polyline are
// (0, 0, 17 ), ( 1, 0, 42 ), ( 1, 1, 38 ), ( 1, 2, 34 ), ( 3, 1, 30 ), ( 5, 3, 26 ), ( 9, 5, 22 ), ( 7, 6, 18 )
// ExtrapolateBefore using points (1, 2, 42), (9, 5, 18)
builder.X = 1;
builder.Y = 2;
builder.M = 42;
updatePoints[0] = builder.ToGeometry() as MapPoint;
builder.X = 9;
builder.Y = 5;
builder.M = 18;
updatePoints[1] = builder.ToGeometry() as MapPoint;
updatePoints.RemoveAt(2);
updatedPolyline = GeometryEngine.Instance.CalibrateByMs(polyline, updatePoints, UpdateMMethod.ExtrapolateBefore, cutOffDistance) as Polyline;
// The points in the updated polyline are
// ( 0, 0, 66 ), ( 1, 0, 58 ), ( 1, 1, 50 ), ( 1, 2, 42 ), ( 3, 1, 3 ), ( 5, 3, 4 ), ( 9, 5, 18 ), ( 7, 6, 6 )
// ExtrapolateAfter using points (0, 0, 17), (1, 2, 42)
builder.X = 0;
builder.Y = 0;
builder.M = 17;
updatePoints.Insert(0, builder.ToGeometry() as MapPoint);
updatePoints.RemoveAt(2);
updatedPolyline = GeometryEngine.Instance.CalibrateByMs(polyline, updatePoints, UpdateMMethod.ExtrapolateAfter, cutOffDistance) as Polyline;
// The points in the updated polyline are
// ( 0, 0, 17 ), ( 1, 0, 0 ), ( 1, 1, 1 ), ( 1, 2, 42 ), ( 3, 1, 50.333333333333333 ), ( 5, 3, 58.666666666666671 ), ( 9, 5, 67 ), ( 7, 6, 75.333333333333343 )
// ExtrapolateAfter and Interpolate using points (0, 0, 17), (1, 2, 42)
updatedPolyline = GeometryEngine.Instance.CalibrateByMs(polyline, updatePoints, UpdateMMethod.ExtrapolateAfter | UpdateMMethod.Interpolate, cutOffDistance) as Polyline;
// The points in the updated polyline are
// (0,0,17),(1,0,25.333333333333336),(1,1,33.666666666666671),(1,2,42),(3,1,50.333333333333336),(5,3,58.666666666666671),(9,5,67),(7,6,75.333333333333343)
Calibrate M-values using segment lengths and M values from input points - CalibrateMsByDistance
string json = "{\"hasM\":true,\"paths\":[[[-4,2,1],[-4,5,2],[-2,5,3],[-2,7,4],[2,7,5]],[[4,1,-1],[2,1,-2],[2,-2,-3],[-3,-2,-4],[-3,0,-5]]]}}";
polyline = PolylineBuilderEx.FromJson(json);
Polyline outputPolyline = GeometryEngine.Instance.DropMs(polyline) as Polyline;
// outputPolyline.HasM = true. Every M-value is NaN.
// outputPolyline.ToJson() = {"hasM":true,"paths":[[[-4,2,null],[-4,5,null],[-2,5,null],[-2,7,null],[2,7,null]],[[4,1,-null],[2,1,null],[2,-2,null],[-3,-2,null],[-3,0,null]]]}
Extrapolate M-values based on a range defined by part and vertex indices - ExtrapolateMs
string json = "{\"hasM\":true,\"paths\":[[[2,0,50],[2,1,40],[3,1,30],[3,5,60],[7,5,12],[7,1,20],[9,1,28],[9,3,10]]],\"spatialReference\":{\"wkid\":4326}}";
polyline = PolylineBuilderEx.FromJson(json);
// Extrapolate M-values from part 0, point 3 to part 0, point 5
Polyline outPolyline = GeometryEngine.Instance.ExtrapolateMs(polyline, ExtrapolateMMethod.ExtrapolateBefore, 0, 3, 0, 5) as Polyline;
// The points in outPolyline are (x, y, m):
// ( 2, 0, 90 ), ( 2, 1, 85 ), ( 3, 1, 80 ), ( 3, 5, 60 ), ( 7, 5, 12 ), ( 7, 1, 20 ), ( 9, 1, 28 ), ( 9, 3, 10 )
json = "{\"hasM\":true,\"paths\":[[[2,0,50],[2,1,40],[3,1,30],[3,5,60],[7,5,12],[7,1,20],[9,1,28],[9,3,10]],[[5,-4,-10],[5,-2,-40],[10,-2,-60],[10,-6,-50],[8,-6,-40],[8,-4,-80],[6,-4,-90]]],\"spatialReference\":{\"wkid\":4326}}";
polyline = PolylineBuilderEx.FromJson(json);
// Extrapolate M-values from part 0, point 5 to part1, point 1
outPolyline = GeometryEngine.Instance.ExtrapolateMs(polyline, ExtrapolateMMethod.ExtrapolateAfter, 0, 5, 1, 1) as Polyline;
// The points in part 0 of outPolyline don't change. They are (x, y, m):
// ( 2, 0, 50 ), ( 2, 1, 40 ), ( 3, 1, 30 ), ( 3, 5, 60 ), ( 7, 5, 12 ), ( 7, 1, 20 ), ( 9, 1, 28 ), ( 9, 3, 10 )
// The points in part 1 of outPolyline are (x, y, m):
// ( 5, -4, -10 ), ( 5, -2, -40 ), ( 10, -2, -90 ), ( 10, -6, -130 ), ( 8, -6, -150 ), ( 8, -4, -170 ), ( 6, -4, -190 )
Get a list of distances along the multipart at points with the specified M-value - GetDistancesAtM
string json = "{\"hasM\":true,\"paths\":[[[-4,1,1],[-4,3,2],[-2,3,3],[-2,5,1]],[[3,5,1],[3,2,2],[6,2,3],[6,-2,2]]]}";
polyline = PolylineBuilderEx.FromJson(json);
// Get the distances as length measured from the start of the multipart
IReadOnlyList<double> distances = GeometryEngine.Instance.GetDistancesAtM(polyline, AsRatioOrLength.AsLength, 2);
// distances.Count = 4
// distances[0] = 2 measured to the point (-4, 3, 2)
// distances[1] = 5 measured to the point (-2, 4, 2). Its M-value is interpolated from the segment (-2, 3, 3) -> (-2, 5, 1)
// distances[2] = 9 measured to the point (3, 2, 2)
// distances[3] = 16 measured to the point (6, -2, 2)
// Get the distances as a ratio of the distance measured from the start of the multipart and the total length of the multipart
distances = GeometryEngine.Instance.GetDistancesAtM(polyline, AsRatioOrLength.AsRatio, 2);
// distances.Count = 4;
// distances are { 0.125, 0.3125, 0.5625, 1 }
Get a polyline and other details corresponding to the subcurves between the specified M-values GetSubCurveBetweenMsEx
string json = "{\"hasM\":true,\"paths\":[[[-2000,0,1],[-1000,1000,-1],[-1000,0,3],[1000,1000,4],[2000,1000,5],[2000,2000,6],[3000,2000,7],[4000,0,8]]],\"spatialReference\":{\"wkid\":3857}}";
polyline = PolylineBuilderEx.FromJson(json);
// Get the subcurve between M-values 2 and 6
Polyline subCurve = GeometryEngine.Instance.GetSubCurveBetweenMsEx(polyline, 2, 6, out MSubCurveRelation fromDetail, out MSubCurveRelation toDetail);
// The subcurve has one part and five points. The subcurve points are (x, y, m):
// (-1000, 250, 2), (-1000, 0, 3), (1000, 1000, 4), (2000, 1000, 5), (2000, 2000, 6)
// fromDetail = toDetail = MSubCurveRelation.MBetweenMinMax
// Get the subcurve between M-values -2 and 3.5
subCurve = GeometryEngine.Instance.GetSubCurveBetweenMsEx(polyline, -2, 3.5, out fromDetail, out toDetail);
// The subcurve has two parts and five points.
// The subcurve points in part 0 are (x, y, m): (-1000, 1000, -1), (-2000, 0, 1)
// The subcurve points in part 1 are (x, y, m): (-1000, 1000, -1), (-1000, 0, 3), (0, 500, 3.5)
// fromDetail = MSubCurveRelation.MBelowMin, toDetail = MSubCurveRelation.MBetweenMinMax
Get a combination of monotonicity values that describes all trends in the M-values over the length of the multipart - GetMMonotonicity
// Create a multipoint and multiply M-values by 6
Coordinate2D[] coords = [ new Coordinate2D(-4, 4), new Coordinate2D(-1, 1), new Coordinate2D(2, 6),
new Coordinate2D(-8, 2), new Coordinate2D(5, -3), new Coordinate2D(7, 2), new Coordinate2D(5, 3), new Coordinate2D(3, -1) ];
double[] ms = [1, 2, 3, 4, 5, 6, 7, 8];
MultipointBuilderEx builder = new(coords)
{
Ms = ms,
HasM = true
};
Multipoint multipoint = builder.ToGeometry();
Multipoint outMultipoint = GeometryEngine.Instance.MultiplyMs(multipoint, 6) as Multipoint;
// The xy-values of the points in outMultipoint are the same as the points in the input multipoint.
// The M-values in outMultipoint are { 6, 12, 18, 24, 30, 36, 42, 48 }
Add an offset value to each of the M-values - OffsetMs
// Create a polyline and add an offset of 2 to each of the M-values
MapPointBuilderEx pointBuilder = new(0, 0)
{
M = 1
};
MapPoint point1 = pointBuilder.ToGeometry();
pointBuilder.SetValues(2, 2);
pointBuilder.M = 3;
MapPoint point2 = pointBuilder.ToGeometry();
polyline = PolylineBuilderEx.CreatePolyline([point1, point2], AttributeFlags.HasM); ;
Polyline outPolyline = GeometryEngine.Instance.OffsetMs(polyline, 2) as Polyline;
// The xy-values of the points in outPolyline are the same as the points in the input polyline.
// The M-values in outPolyline are { 3, 5 }
// Create an envelope and add an offset of 25 to each of the M-values
EnvelopeBuilderEx envelopeBuilder = new(-5, 1, 2, 4)
{
MMin = 10,
MMax = 20
};
Envelope envelope = envelopeBuilder.ToGeometry();
Envelope outEnvelope = GeometryEngine.Instance.OffsetMs(envelope, 25) as Envelope;
// The xy-values of the points in outEnvelope are the same as the points in the input envelope.
// outEnvelope.MMin = 35, outEnvelope.MMax = 45
// Add a negative offset to the M-values of the envelope
outEnvelope = GeometryEngine.Instance.OffsetMs(envelope, -10) as Envelope;
// The xy-values of the points in outEnvelope are the same as the points in the input envelope.
// outEnvelope.MMin = 0, outEnvelope.MMax = 10
Reorient a polyline such that all M-values are non-decreasing, if possible - OrientByMs
string json = "{\"hasM\":true,\"paths\":[[[0,0,1],[0,1,0],[1,1,-1],[1,0,-2]]]}";
polyline = PolylineBuilderEx.FromJson(json);
Polyline outputPolyline = GeometryEngine.Instance.OrientByMs(polyline);
// The points of outputPolyline are (x, y, m): (1, 0, -2), (1, 1, -1), (0, 1, 0), (0, 0, 1)
// M-values of second part is not monotonic, so it won't change. The first part will change.
json = "{\"hasM\":true,\"paths\":[[[0,0,1],[0,1,0],[1,1,-1],[1,0,-2]],[[5,4,6],[6,4,5],[8,6,7]]]}";
polyline = PolylineBuilderEx.FromJson(json);
outputPolyline = GeometryEngine.Instance.OrientByMs(polyline);
// The points of part 0 of outputPolyline are (x, y, m): (1, 0, -2), (1, 1, -1), (0, 1, 0), (0, 0, 1)
// The points of part 1 of outputPolyline are (x, y, m): (5, 4, 6), (6, 4, 5), (8, 6, 7)
Get the first and last defined M-values in a polyline - QueryFirstLastM
string json = "{\"hasM\":true,\"paths\":[[[5,4,6],[6,4,5],[8,6,7]],[[0,0,1],[0,1,0],[1,1,-1],[1,0,-2]]]}";
polyline = PolylineBuilderEx.FromJson(json);
GeometryEngine.Instance.QueryFirstLastM(polyline, out double firstM, out double lastM);
// firstM = 6, lastM = -2
json = "{\"hasM\":true,\"paths\":[[[5,4,null],[6,4,5],[8,6,7]],[[0,0,1],[0,1,0],[1,1,-1],[1,0,null]]]}";
polyline = PolylineBuilderEx.FromJson(json);
GeometryEngine.Instance.QueryFirstLastM(polyline, out firstM, out lastM);
// firstM = 5, lastM = -1
json = "{\"hasM\":true,\"paths\":[[[5,4,null],[6,4,null],[8,6,null]],[[0,0,null],[0,1,null],[1,1,null],[1,0,null]]]}";
polyline = PolylineBuilderEx.FromJson(json);
GeometryEngine.Instance.QueryFirstLastM(polyline, out firstM, out lastM);
// firstM and lastM are NaN
json = "{\"hasM\":true,\"paths\":[]}";
polyline = PolylineBuilderEx.FromJson(json);
GeometryEngine.Instance.QueryFirstLastM(polyline, out firstM, out lastM);
// firstM and lastM are NaN
Reverse the order of the M-values along a multipart - ReverseMs
string json = "{\"hasM\":true,\"paths\":[[[5,4,6],[6,4,5],[8,6,7]]],\"spatialReference\":{\"wkid\":4326}}";
polyline = PolylineBuilderEx.FromJson(json);
Polyline outputPolyline = GeometryEngine.Instance.ReverseMs(polyline) as Polyline;
// The xy-coordinates in outputPolyline are not changed.
// The M-values in outputPolyline are: { 7, 5, 6 }
Set Ms at the beginning and end of the geometry and interpolate M-values between the two values - SetAndInterpolateMsBetween
Set the M-values to the cumulative length of the start of the multipart - SetMsAtDistance
string json = "{\"hasM\":true,\"paths\":[[[-3000,-2000,1],[-2000,-2000,2],[-1000,-2000,3],[0,-2000,null],[1000,-2000,4],[2000,-2000,5],[3000,-2000,10],[4000,-2000,11],[5000,-2000,12],[6000,-2000,13],[7000,-2000,14]]],\"spatialReference\":{\"wkid\":3857}}";
polyline = PolylineBuilderEx.FromJson(json);
Polyline outPolyline = GeometryEngine.Instance.SetMsAsDistance(polyline, AsRatioOrLength.AsLength) as Polyline;
// The xy-coordinates don't change.
// The M-values of the vertices in outPolyline are (x, y, m):
// { 0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000 }
json = "{\"hasM\":true,\"rings\":[[[0,0],[0,3000],[4000,3000],[4000,0],[0,0]]],\"spatialReference\":{\"wkid\":3857}}";
polygon = PolygonBuilderEx.FromJson(json);
Polygon outPolygon = GeometryEngine.Instance.SetMsAsDistance(polygon, AsRatioOrLength.AsLength) as Polygon;
// The M-values of the vertices in outPolygon are (x, y, m): { 0, 3000, 7000, 10000, 14000 };
Set the M-values of the vertices as scaled and offset distances measured along a polyline - SetMsAsDistance
string json = "{\"hasM\":true,\"paths\":[[[0,0,1],[3,0,2],[3,6,3],[7,6,4]]],\"spatialReference\":{\"wkid\":4326}}";
polyline = PolylineBuilderEx.FromJson(json);
Coordinate2D origin = new(0, 0);
Polyline outputPolyline = GeometryEngine.Instance.SetMsAsDistance(polyline, origin, 0.5, 1, true) as Polyline;
// The xy-coordinates of the polyline don't change.
// The points of outputPolyline are (x, y, m):
// (0, 0, 1), (3, 0, 2.5), (3, 6, 5.5), (7, 6, 7.5)
// Measurements will start at the end of the polyline, point (7, 6)
origin = new Coordinate2D(4, 6);
outputPolyline = GeometryEngine.Instance.SetMsAsDistance(polyline, origin, 0.5, 1, true) as Polyline;
// The points of outputPolyline are (x, y, m):
// (0, 0, 7.5), (3, 0, 6), (3, 6, 3), (7, 6, 1)
Snap the M-values to the M-precision of the spatial reference - SnapMsToSpatialReference
SpatialReference sr = SpatialReferences.WebMercator; // precision = 1 / MScale = 0.0001
// MapPoint
MapPointBuilderEx pointBuilder = new(3, 4, sr)
{
M = 5.00006
};
MapPoint point = pointBuilder.ToGeometry();
MapPoint outputPoint = GeometryEngine.Instance.SnapMsToSpatialReference(point) as MapPoint;
// outputPoint.M = 5.0001
// Multipoint
MapPointBuilderEx mapPointBuilderEx = new(-3, -4, sr)
{
M = -5.000007
};
pointBuilder = mapPointBuilderEx;
MapPoint point2 = pointBuilder.ToGeometry();
Multipoint multipoint = MultipointBuilderEx.CreateMultipoint([point, point2], AttributeFlags.HasM, sr);
Multipoint outputMultipoint = GeometryEngine.Instance.SnapMsToSpatialReference(multipoint) as Multipoint;
// outputMultipoint.Points[0].M = 5.0001, outputMultipoint.Points[1].M = -5
// Polyline
string json = "{\"hasM\":true,\"paths\":[[[3,2,10.00065],[3,4,15.000325],[5,4,20],[5,2,15.000325],[3,2,10.00065]]],\"spatialReference\":{\"wkid\":3857}}";
polyline = PolylineBuilderEx.FromJson(json);
Polyline outputPolyline = GeometryEngine.Instance.SnapMsToSpatialReference(polyline) as Polyline;
// The M-values for the vertices in outputPolyline are { 10.0007, 15.0003, 20, 15.0003, 10.0007 }
Set the M-values of the vertices as scaled and offset M distances measured along a polyline - UpdateAllMsByMs
string json = "{\"hasM\":true,\"paths\":[[[-8,2,1],[-8,5,8],[-5,5,0],[-5,7,12]],[[3,2,20],[7,2,30],[7,4,10],[13,4,5]]]}";
polyline = PolylineBuilderEx.FromJson(json);
Coordinate2D origin = new(-5, 6);
Polyline outputPolyline = GeometryEngine.Instance.UpdateAllMsByMs(polyline, origin, 1, 0, true);
// The xy-coordinates don't change.
// The M-values of the vertices in part 0 of outputPolyline are { 27, 20, 12, 0 }
// The M-values of the vertices in part 1 of outputPolyline are { 27, 37, 57, 62 }
outputPolyline = GeometryEngine.Instance.UpdateAllMsByMs(polyline, origin, 2, 4, true);
// The M-values of the vertices in part 0 of outputPolyline are { 58, 44, 28, 4 }
// The M-values of the vertices in part 1 of outputPolyline are { 58, 78, 118, 128 }
Update M-values along the shortest path between the specified vertices - UpdateMsByDistance
string json = "{\"hasM\":true,\"paths\":[[[-8,2,1],[-8,5,8],[-5,5,0],[-5,7,12]]],\"spatialReference\":{\"wkid\":4326}}";
polyline = PolylineBuilderEx.FromJson(json);
Polyline outputPolyline = GeometryEngine.Instance.UpdateMsByDistance(polyline, 0, 0, 0, 2, 10, 20, UpdateMMethod.Interpolate, true);
// The xy-coordinates don't change.
// The M-values of the vertices in outputPolyline are { 10, 15, 20, 12 }
json = "{\"hasM\":true,\"paths\":[[[-8,2,1],[-8,5,8],[-5,5,0],[-5,7,12]],[[3,2,20],[7,2,30],[7,4,10],[13,4,5]]]}";
polyline = PolylineBuilderEx.FromJson(json);
outputPolyline = GeometryEngine.Instance.UpdateMsByDistance(polyline, 0, 2, 1, 1, 10, 20, UpdateMMethod.ExtrapolateBefore, true);
// The M-values of the vertices in part 0 of outputPolyline are { -5, 2.5, 10, 5 }
// The M-values of the vertices in part 1 of outputPolyline are { 20, 20, 10, 5 }
Update M-values with the interpolation ratio determined by existing M-values and the input M-values - UpdateMsByMs
string json = "{\"hasM\":true,\"paths\":[[[-8,2,1],[-8,5,8],[-5,5,0],[-5,7,12]]],\"spatialReference\":{\"wkid\":4326}}";
polyline = PolylineBuilderEx.FromJson(json);
Polyline outputPolyline = GeometryEngine.Instance.UpdateMsByMs(polyline, 0, 1, 0, 3, -2, 14, UpdateMMethod.Interpolate);
// The xy-coordinates don't change.
// The M-values of the vertices in outputPolyline are (x, y, m): { 1, -2, 30, 14 }
Move a MapPoint
MapPoint pt = MapPointBuilderEx.CreateMapPoint(1.0, 3.0);
MapPoint ptResult = GeometryEngine.Instance.Move(pt, -3.5, 2.5) as MapPoint;
// ptResult is (-2.5, 5.5)
LineSegment line = LineBuilderEx.CreateLineSegment(MapPointBuilderEx.CreateMapPoint(0, 3), MapPointBuilderEx.CreateMapPoint(5.0, 3.0));
polyline = PolylineBuilderEx.CreatePolyline(line);
bool simple = GeometryEngine.Instance.IsSimpleAsFeature(polyline);
// ratio = false
MapPoint pt = GeometryEngine.Instance.MovePointAlongLine(polyline, 1.0, false, 0.0, SegmentExtensionType.NoExtension);
// pt = 1.0, 3.0
pt = GeometryEngine.Instance.MovePointAlongLine(polyline, 1.0, false, -1.0, SegmentExtensionType.NoExtension);
// pt = 1.0, 4.0
pt = GeometryEngine.Instance.MovePointAlongLine(polyline, 1.0, false, 2.0, SegmentExtensionType.NoExtension);
// pt = 1.0, 1.0
// ratio = true
pt = GeometryEngine.Instance.MovePointAlongLine(polyline, 0.5, true, 0, SegmentExtensionType.NoExtension);
// pt = 2.5, 3.0
// move past the line
pt = GeometryEngine.Instance.MovePointAlongLine(polyline, 7, false, 0, SegmentExtensionType.NoExtension);
// pt = 5.0, 3.0
// move past the line with extension at "to" point
pt = GeometryEngine.Instance.MovePointAlongLine(polyline, 7, false, 0, SegmentExtensionType.ExtendEmbeddedAtTo);
// pt = 7.0, 3.0
// negative distance with extension at "from" point
pt = GeometryEngine.Instance.MovePointAlongLine(polyline, -2, false, 0, SegmentExtensionType.ExtendEmbeddedAtFrom);
// pt = -2.0, 3.0
// ratio = true
pt = GeometryEngine.Instance.MovePointAlongLine(polyline, 0.5, true, 0, SegmentExtensionType.NoExtension);
// pt = 2.5, 3.0
// line with Z
List<Coordinate3D> coords3D = [new Coordinate3D(0, 0, 0), new Coordinate3D(1113195, 1118890, 5000)];
Polyline polylineZ = PolylineBuilderEx.CreatePolyline(coords3D, SpatialReferences.WebMercator);
// polylineZ.HasZ = true
// ratio = true, no offset
pt = GeometryEngine.Instance.MovePointAlongLine(polylineZ, 0.5, true, 0, SegmentExtensionType.NoExtension);
// pt.X = 556597.5
// pt.Y = 559445
// pt.Z = 2500
// ratio = true, past the line with "to" extension, no offset
pt = GeometryEngine.Instance.MovePointAlongLine(polylineZ, 1.5, true, 0, SegmentExtensionType.ExtendEmbeddedAtTo);
// pt.X = 1669792.5
// pt.Y = 1678335
// pt.Z = 7500
// ratio = true, negative distance past the line with no extension, no offset
pt = GeometryEngine.Instance.MovePointAlongLine(polylineZ, -1.5, true, 0, SegmentExtensionType.NoExtension);
// pt.X = 0
// pt.Y = 0
// pt.Z = -7500
// polyline with Z but 2d distance = 0
MapPoint pt3 = MapPointBuilderEx.CreateMapPoint(5, 5, 0);
MapPoint pt4 = MapPointBuilderEx.CreateMapPoint(5, 5, 10);
List<MapPoint> pts = [pt3, pt4];
polyline = PolylineBuilderEx.CreatePolyline(pts);
// polyline.HasZ = true
// polyline.Length3D = 10
// polyline.Length = 0
MapPoint result = GeometryEngine.Instance.MovePointAlongLine(polyline, 2, false, 0, SegmentExtensionType.NoExtension);
// result = 5, 5, 2
// polyline with length2d = 0 and length3d = 0
MapPoint pt5 = MapPointBuilderEx.CreateMapPoint(5, 5, 10);
MapPoint pt6 = MapPointBuilderEx.CreateMapPoint(5, 5, 10);
pts.Clear();
pts.Add(pt5);
pts.Add(pt6);
polyline = PolylineBuilderEx.CreatePolyline(pts);
// polyline.HasZ = true
// polyline.Length3D = 0
// polyline.Length = 0
result = GeometryEngine.Instance.MovePointAlongLine(polyline, 3, true, 0, SegmentExtensionType.NoExtension);
// result = 5, 5, 10
result = GeometryEngine.Instance.MovePointAlongLine(polyline, 3, true, 0, SegmentExtensionType.ExtendEmbeddedAtFrom);
// result = 5, 5, 10
// polyline with Z and M
List<MapPoint> inputPoints =
[
MapPointBuilderEx.CreateMapPoint(1, 2, 3, 4),
MapPointBuilderEx.CreateMapPoint(1, 2, 33, 44),
];
Polyline polylineZM = PolylineBuilderEx.CreatePolyline(inputPoints, SpatialReferences.WGS84);
// polylineZM.HasZ = true
// polylineZM.HasM = true
// ratio = true, no offset
MapPoint pointAlong = GeometryEngine.Instance.MovePointAlongLine(polylineZM, 0.5, true, 0, SegmentExtensionType.NoExtension);
// pointAlong = 1, 2, 18, 24
// ratio = true with offset
pointAlong = GeometryEngine.Instance.MovePointAlongLine(polylineZM, 0.2, true, 2.23606797749979, SegmentExtensionType.NoExtension);
// pointAlong = 1, 2, 9, 12
Separate components of a geometry into single component geometries
List<Coordinate2D> coords2D =
[
new Coordinate2D(0, 0),
new Coordinate2D(1, 4),
new Coordinate2D(2, 7),
new Coordinate2D(-10, 3)
];
Multipoint multipoint = MultipointBuilderEx.CreateMultipoint(coords2D, SpatialReferences.WGS84);
IReadOnlyList<Geometry> result = GeometryEngine.Instance.MultipartToSinglePart(multipoint);
// result.Count = 4,
// 'explode' a multipart polygon
result = GeometryEngine.Instance.MultipartToSinglePart(multipartPolygon);
// create a bag of geometries
polygon = PolygonBuilderEx.CreatePolygon(coords2D, SpatialReferences.WGS84);
var bag = GeometryBagBuilderEx.CreateGeometryBag([multipoint, polygon]);
// bag.PartCount = =2
result = GeometryEngine.Instance.MultipartToSinglePart(bag);
// result.Count == 2
// result[0] is MultiPoint
// result[1] is Polygon
Nearest Point versus Nearest Vertex
SpatialReference sr = SpatialReferences.WGS84;
MapPoint pt = MapPointBuilderEx.CreateMapPoint(5, 5, sr);
List<Coordinate2D> coords =
[
new Coordinate2D(10, 1),
new Coordinate2D(10, -4),
new Coordinate2D(0, -4),
new Coordinate2D(0, 1),
new Coordinate2D(10, 1)
];
polygon = PolygonBuilderEx.CreatePolygon(coords);
// find the nearest point in the polygon geometry to the pt
ProximityResult result = GeometryEngine.Instance.NearestPoint(polygon, pt);
// result.Point = 5, 1
// result.SegmentIndex = 3
// result.PartIndex = 0
// result.PointIndex = null
//result.Distance = 4
//result.RightSide = false
// find the nearest vertex in the polgyon geometry to the pt
result = GeometryEngine.Instance.NearestVertex(polygon, pt);
// result.Point = 10, 1
// result.PointIndex = 0
// result.SegmentIndex = null
// result.PartIndex = 0
// result.Distance = Math.Sqrt(41)
// result.RightSide = false
var g1 = PolygonBuilderEx.FromJson("{\"rings\": [ [ [0, 0], [10, 0], [10, 10], [0, 10] ] ] }");
var result = GeometryEngine.Instance.Area(g1); // result = -100.0 - negative due to wrong ring orientation
// simplify it
var result2 = GeometryEngine.Instance.Area(GeometryEngine.Instance.SimplifyAsFeature(g1, true));
// result2 = 100.0 - positive due to correct ring orientation (clockwise)
Get Non Simple Reason
SpatialReference sr = SpatialReferences.WGS84;
Coordinate2D[] coords = [new Coordinate2D(5, 10), new Coordinate2D(15, 20), new Coordinate2D(25, 10), new Coordinate2D(5, 20)];
polyline = PolylineBuilderEx.CreatePolyline(coords, sr);
bool isSimple = GeometryEngine.Instance.GetNonSimpleReason(polyline, out NonSimpleReason nonSimpleReason);
// isSimple = true;
// nonSimpleReason = NonSimpleReason.IsSimple
double resolution = sr.XYResolution;
coords = [new Coordinate2D(0, 0), new Coordinate2D(0, 1.8 * resolution), new Coordinate2D(10, 10), new Coordinate2D(0, 5)];
polyline = PolylineBuilderEx.CreatePolyline(coords, sr);
isSimple = GeometryEngine.Instance.GetNonSimpleReason(polyline, out nonSimpleReason);
// isSimple = false
// nonSimpleReason = NonSimpleReason.ShortSegments
coords = [ new Coordinate2D(10, 10), new Coordinate2D(10, 20), new Coordinate2D(40, 20),
new Coordinate2D(40, 10), new Coordinate2D(60, 10), new Coordinate2D(70, 10)];
polygon = PolygonBuilderEx.CreatePolygon(coords, sr);
isSimple = GeometryEngine.Instance.GetNonSimpleReason(polygon, out nonSimpleReason);
//isSimple = false
//nonSimpleReason = NonSimpleReason.SelfIntersections
Simplify a polyline with intersections, overlaps
List<Coordinate2D> coords =
[
new Coordinate2D(8, 0),
new Coordinate2D(8, 4),
new Coordinate2D(6, 4),
new Coordinate2D(8, 4),
new Coordinate2D(10, 4),
new Coordinate2D(8, 4)
];
SpatialReference sr = SpatialReferences.WGS84;
// build a line that has segments that cross over each other
polyline = PolylineBuilderEx.CreatePolyline(coords, sr);
// polyline.PartCount = 1
ReadOnlyPartCollection parts = polyline.Parts;
ReadOnlySegmentCollection segments = parts[0];
// segments.Count = 5
// note there is a difference between SimpleAsFeature (doesn't detect intersections and overlaps, determines if it's simple enough for gdb storage)
// and SimplifyPolyline (does detect intersections etc)
bool isSimple = GeometryEngine.Instance.IsSimpleAsFeature(polyline, false);
// isSimple = true
// simplify it (with force = false)
// because it has already been deemed 'simple' (previous IsSimpleAsFeature call) no detection of intersections, overlaps occur
Polyline simplePolyline = GeometryEngine.Instance.SimplifyPolyline(polyline, SimplifyType.Planar, false);
// simplePolyline.PartCount = 1
ReadOnlyPartCollection simpleParts = simplePolyline.Parts;
ReadOnlySegmentCollection simpleSegments = simpleParts[0];
// simpleSegments.Count = 5
// simplify it (with force = true)
// detection of intersections, overlaps occur
simplePolyline = GeometryEngine.Instance.SimplifyPolyline(polyline, SimplifyType.Planar, true);
// simplePolyline.PartCount = 3
simpleParts = simplePolyline.Parts;
simpleSegments = simpleParts[0];
// simpleSegments.Count = 1
// smooth with a maxDeviation of 0
Polyline smoothPolyline = GeometryEngine.Instance.Smooth(polyline, 0) as Polyline;
// smooth with a maxDeviation of 0.5
smoothPolyline = GeometryEngine.Instance.Smooth(polyline, 0.5) as Polyline;
// smooth a polygon with a maxDeviation of 0
Polygon smoothPolygon = GeometryEngine.Instance.Smooth(polygon, 0) as Polygon;
// maxDeviation < 0 behaves as if maxDeviation = 0
smoothPolygon = GeometryEngine.Instance.Smooth(polygon, -1) as Polygon;
// NaN maxDeviation behaves as if maxDeviation = 0
smoothPolygon = GeometryEngine.Instance.Smooth(polygon, double.NaN) as Polygon;
Split multipart at point
// define a polyline
MapPoint startPointZ = MapPointBuilderEx.CreateMapPoint(1, 1, 5);
MapPoint endPointZ = MapPointBuilderEx.CreateMapPoint(20, 1, 5);
Polyline polylineZ = PolylineBuilderEx.CreatePolyline([startPointZ, endPointZ]);
// define a split point
MapPoint splitPointAboveLine = MapPointBuilderEx.CreateMapPoint(10, 10, 10);
// split the polyline at the point. Don't project the split point onto the line, don't create a new part
var splitPolyline = GeometryEngine.Instance.SplitAtPoint(polylineZ, splitPointAboveLine, false, false, out bool splitOccurred, out int partIndex, out int segmentIndex);
// splitOccurred = true
// partIndex = 0
// segmentIndex = 1
// splitPolyline.PointCount = 3
// splitPolyline.PartCount = 1
// splitPolyline coordinates are (1, 1, 5), (10, 10, 10), (20, 1, 5)
// split the polyline at the point. dont project the split point onto the line, do create a new part
splitPolyline = GeometryEngine.Instance.SplitAtPoint(polylineZ, splitPointAboveLine, false, false, out splitOccurred, out partIndex, out segmentIndex);
// splitOccurred = true
// partIndex = 1
// segmentIndex = 0
// splitPolyline.PointCount = 4
// splitPolyline.PartCount = 2
// splitPolyline first part coordinates are (1, 1, 5), (10, 10, 10)
// splitPolyline second part coordinates are (10, 10, 10), (20, 1, 5)
// split the polyline at the point. do project the split point onto the line, don't create a new part
splitPolyline = GeometryEngine.Instance.SplitAtPoint(polylineZ, splitPointAboveLine, false, false, out splitOccurred, out partIndex, out segmentIndex);
// splitOccurred = true
// partIndex = 0
// segmentIndex = 1
// splitPolyline.PointCount = 3
// splitPolyline.PartCount = 1
// splitPolyline coordinates are (1, 1, 5), (10, 10, 5), (20, 1, 5)
// split the polyline at the point. do project the split point onto the line, do create a new part
splitPolyline = GeometryEngine.Instance.SplitAtPoint(polylineZ, splitPointAboveLine, false, false, out splitOccurred, out partIndex, out segmentIndex);
// splitOccurred = true
// partIndex = 1
// segmentIndex = 0
// splitPolyline.PointCount = 4
// splitPolyline.PartCount = 2
// splitPolyline first part coordinates are (1, 1, 5), (10, 10, 5)
// splitPolyline second part coordinates are (10, 10, 5), (20, 1, 5)
//
// try to split with a point that won't split the line - pt extends beyond the line
//
var pointAfterLine = MapPointBuilderEx.CreateMapPoint(50, 1, 10);
splitPolyline = GeometryEngine.Instance.SplitAtPoint(polylineZ, pointAfterLine, false, false, out splitOccurred, out partIndex, out segmentIndex);
// splitOccurred = false
// ignore partIndex, sgementIndex
// splitPolyline is the same as polylineZ
///
/// multipart polygon
///
List<Coordinate3D> coordsZ =
[
new Coordinate3D(10,10,5),
new Coordinate3D(10,20,5),
new Coordinate3D(20,20,5),
new Coordinate3D(20,10,5)
];
List<Coordinate3D> coordsZ_2ndPart =
[
new Coordinate3D(30,20,10),
new Coordinate3D(30,30,10),
new Coordinate3D(35,28,10),
new Coordinate3D(40,30,10),
new Coordinate3D(40,20,10)
];
var builder = new PolygonBuilderEx
{
HasZ = true
};
builder.AddPart(coordsZ);
builder.AddPart(coordsZ_2ndPart);
Polygon multipart = builder.ToGeometry();
// pointA is closer to the first part of the multipart - the split occurs in the first part
var pointA = MapPointBuilderEx.CreateMapPoint(22, 18, 7);
var splitPolygon = GeometryEngine.Instance.SplitAtPoint(multipart, pointA, false, false, out splitOccurred, out partIndex, out segmentIndex);
// splitPolygon.PointCount = 12
// splitPolygon.PartCount = 2
// splitPolygon first part coordinates (10, 10, 5), (10, 20, 5), (20, 20, 5), (22, 18, 7), (20, 10, 5), (10, 10, 5)
// pointB is midPoint between the 2 parts - no split will occur
var pointB = MapPointBuilderEx.CreateMapPoint(25, 20, 7);
splitPolygon = GeometryEngine.Instance.SplitAtPoint(multipart, pointB, true, false, out splitOccurred, out partIndex, out segmentIndex);
// splitOccurred = false
// ignore partIndex, sgementIndex
// splitPolyline is the same as polylineZ
// Not all of the input points are transformed as some of them are outside of the GCS horizon.
Coordinate2D[] inCoords2D =
[
new Coordinate2D(-1, -1),
new Coordinate2D(-2, -5),
new Coordinate2D(-5, -11),
new Coordinate2D(-10, -19),
new Coordinate2D(-17, -29),
new Coordinate2D(-26, -41),
new Coordinate2D(-37, -5),
new Coordinate2D(-50, -21),
new Coordinate2D(-65, -39),
new Coordinate2D(-82, -9)
];
int arraySize = inCoords2D.Length;
ProjectionTransformation projTrans = ProjectionTransformation.Create(SpatialReferences.WGS84, SpatialReferenceBuilder.CreateSpatialReference(24891));
Coordinate2D[] outCoords2D = new Coordinate2D[arraySize];
// transform and choose to remove the clipped coordinates
int numPointsTransformed = GeometryEngine.Instance.Transform2D(inCoords2D, projTrans, ref outCoords2D, true);
// numPointsTransformed = 4
// outCoords2D.Length = 4
// outCoords2D[0] = {5580417.6876455201, 1328841.2376554986}
// outCoords2D[1] = {3508774.290814558, -568027.23444226268}
// outCoords2D[2] = {1568096.0886155984, -2343435.4394415971}
// outCoords2D[3] = {57325.827391741652, 1095146.8917508761}
// transform and don't remove the clipped coordinates
numPointsTransformed = GeometryEngine.Instance.Transform2D(inCoords2D, projTrans, ref outCoords2D, false);
// numPointsTransformed = 4
// outCoords2D.Length = 10
// outCoords2D[0] = {double.Nan, double.Nan}
// outCoords2D[1] = {double.Nan, double.Nan}
// outCoords2D[2] = {double.Nan, double.Nan}
// outCoords2D[3] = {double.Nan, double.Nan}
// outCoords2D[4] = {double.Nan, double.Nan}
// outCoords2D[5] = {double.Nan, double.Nan}
// outCoords2D[6] = {5580417.6876455201, 1328841.2376554986}
// outCoords2D[7] = {3508774.290814558, -568027.23444226268}
// outCoords2D[8] = {1568096.0886155984, -2343435.4394415971}
// outCoords2D[9] = {57325.827391741652, 1095146.8917508761}
Transform3D
// Not all of the input points are transformed as some of them are outside of the GCS horizon.
Coordinate3D[] inCoords3D =
[
new Coordinate3D(-1, -1, 0),
new Coordinate3D(-2, -5, 1),
new Coordinate3D(-5, -11, 2),
new Coordinate3D(-10, -19, 3),
new Coordinate3D(-17, -29, 4),
new Coordinate3D(-26, -41, 5),
new Coordinate3D(-37, -5, 6),
new Coordinate3D(-50, -21, 7),
new Coordinate3D(-65, -39, 8),
new Coordinate3D(-82, -9, 9)
];
int arraySize = inCoords3D.Length;
ProjectionTransformation projTrans = ProjectionTransformation.Create(SpatialReferences.WGS84, SpatialReferenceBuilder.CreateSpatialReference(24891));
Coordinate3D[] outCoords3D = new Coordinate3D[arraySize];
// transform and choose to remove the clipped coordinates
int numPointsTransformed = GeometryEngine.Instance.Transform3D(inCoords3D, projTrans, ref outCoords3D);
// numPointsTransformed = 4
// outCoords2D.Length = 4
// outCoords2D[0] = {5580417.6876455201, 1328841.2376554986, 7}
// outCoords2D[1] = {3508774.290814558, -568027.23444226268, 8}
// outCoords2D[2] = {1568096.0886155984, -2343435.4394415971, 9}
// outCoords2D[3] = {57325.827391741652, 1095146.8917508761, 10}
Union two MapPoints - creates a Multipoint
MapPoint pt1 = MapPointBuilderEx.CreateMapPoint(1.0, 1.0);
MapPoint pt2 = MapPointBuilderEx.CreateMapPoint(2.0, 2.5);
Geometry geometry = GeometryEngine.Instance.Union(pt1, pt2);
Multipoint multipoint = geometry as Multipoint; // multipoint has point count of 2
Union two Polygons
// union two polygons
List<MapPoint> polyPts =
[
MapPointBuilderEx.CreateMapPoint(3.0, 2.0),
MapPointBuilderEx.CreateMapPoint(3.0, 6.0),
MapPointBuilderEx.CreateMapPoint(6.0, 6.0),
MapPointBuilderEx.CreateMapPoint(6.0, 2.0),
];
Polygon poly1 = PolygonBuilderEx.CreatePolygon(polyPts);
bool isSimple = GeometryEngine.Instance.IsSimpleAsFeature(poly1);
Envelope env = EnvelopeBuilderEx.CreateEnvelope(MapPointBuilderEx.CreateMapPoint(4.0, 4.0), MapPointBuilderEx.CreateMapPoint(8, 8));
Polygon poly2 = PolygonBuilderEx.CreatePolygon(env);
isSimple = GeometryEngine.Instance.IsSimpleAsFeature(poly2);
Geometry g = GeometryEngine.Instance.Union(poly1, poly2);
Polygon polyResult = g as Polygon;
Union many Polylines
// union many polylines
List<Coordinate2D> coords =
[
new Coordinate2D(1, 2), new Coordinate2D(3, 4), new Coordinate2D(4, 2),
new Coordinate2D(5, 6), new Coordinate2D(7, 8), new Coordinate2D(8, 4),
new Coordinate2D(9, 10), new Coordinate2D(11, 12), new Coordinate2D(12, 8),
new Coordinate2D(10, 8), new Coordinate2D(12, 12), new Coordinate2D(14, 10)
];
// create Disjoint lines
List<Polyline> manyLines =
[
PolylineBuilderEx.CreatePolyline([coords[0], coords[1], coords[2]], SpatialReferences.WGS84),
PolylineBuilderEx.CreatePolyline([coords[3], coords[4], coords[5]]),
PolylineBuilderEx.CreatePolyline([coords[6], coords[7], coords[8]])
];
polyline = GeometryEngine.Instance.Union(manyLines) as Polyline;
Union many Polygons
// union many polygons
List<Coordinate3D> coordsZ =
[
new Coordinate3D(1, 2, 0), new Coordinate3D(3, 4, 1), new Coordinate3D(4, 2, 2),
new Coordinate3D(5, 6, 3), new Coordinate3D(7, 8, 4), new Coordinate3D(8, 4, 5),
new Coordinate3D(9, 10, 6), new Coordinate3D(11, 12, 7), new Coordinate3D(12, 8, 8),
new Coordinate3D(10, 8, 9), new Coordinate3D(12, 12, 10), new Coordinate3D(14, 10, 11)
];
// create polygons
List<Polygon> manyPolygonsZ =
[
PolygonBuilderEx.CreatePolygon([coordsZ[0], coordsZ[1], coordsZ[2]], SpatialReferences.WGS84),
PolygonBuilderEx.CreatePolygon([coordsZ[3], coordsZ[4], coordsZ[5]]),
PolygonBuilderEx.CreatePolygon([coordsZ[6], coordsZ[7], coordsZ[8]])
];
polygon = GeometryEngine.Instance.Union(manyPolygonsZ) as Polygon;
Generalize a multipart - Weed
// generalize with a maxDeviation of 0
Polyline weedPolyline = GeometryEngine.Instance.Weed(polyline, 0) as Polyline;
// generalize with a maxDeviation < 0
weedPolyline = GeometryEngine.Instance.Weed(polyline, -1000000) as Polyline;
// generalize with a maxDeviation > 0
weedPolyline = GeometryEngine.Instance.Weed(polyline, 1000000) as Polyline;
MapPoints, Polylines, Polygons within Polygon
// build a polygon
List<MapPoint> pts =
[
MapPointBuilderEx.CreateMapPoint(1.0, 1.0),
MapPointBuilderEx.CreateMapPoint(1.0, 2.0),
MapPointBuilderEx.CreateMapPoint(2.0, 2.0),
MapPointBuilderEx.CreateMapPoint(2.0, 1.0),
];
Polygon poly = PolygonBuilderEx.CreatePolygon(pts);
// an inner point
MapPoint innerPt = MapPointBuilderEx.CreateMapPoint(1.5, 1.5);
bool within = GeometryEngine.Instance.Within(innerPt, poly); // within = true
// point on a boundary
within = GeometryEngine.Instance.Within(pts[0], poly); // within = false
// an interior line
MapPoint innerPt2 = MapPointBuilderEx.CreateMapPoint(1.25, 1.75);
List<MapPoint> innerLinePts = [innerPt, innerPt2];
polyline = PolylineBuilderEx.CreatePolyline(innerLinePts);
within = GeometryEngine.Instance.Within(polyline, poly); // within = true
// a line that crosses the boundary
MapPoint outerPt = MapPointBuilderEx.CreateMapPoint(3, 1.5);
List<MapPoint> crossingLinePts = [innerPt, outerPt];
polyline = PolylineBuilderEx.CreatePolyline(crossingLinePts);
within = GeometryEngine.Instance.Within(polyline, poly); // within = false
// polygon in polygon
Envelope env = EnvelopeBuilderEx.CreateEnvelope(innerPt, innerPt2);
within = GeometryEngine.Instance.Within(env, poly); // within = true