In order to add any kind of geometry, such as a line, circle, or 3D fence, we must get down to the basics and discuss geometry in enough detail so that you are able to add more content to your map or scene, either by constructing the geometry in code or allowing the user to interactively create the geometry on the map or scene. (We will discuss interactive editing in Chapter 9, Editing Features.) In this section, we're going to consider the following object diagram and discuss each type of geometry:
All objects in this section will come from Esri.ArcGISRuntime.Geometry
.
All of these geometries are immutable, which means that once you create them, you can't change them. However, all of these geometries can be created and modified with their respective builder classes. We will discuss the builder classes after we've introduced these geometries.
The Geometry
object is an abstract class that defines a geometric shape, which means all subclasses inherit its properties and methods. The Geometry
object has some important methods, such as FromJson
, which allows you to convert from a JSON representation of the geometry. There is also ToJson
, which allows you to convert a Geometry
object to JSON. The IsEqual
method will tell you whether two geometries are equal. By equal, we mean that their spatial references are the same. This also means that for geometries containing points, the order in which the points are created must also match. The HasZ
property is a Boolean that simply lets you determine whether the object has the z values.
Lastly, the Dimension
property tells you the dimensionality of the object. A point has zero dimensions. What this means is that if you were to put a bounding box around the object, the box itself would have an area of zero. A line has a dimensionality of 1
because if it starts at (0,0)
and goes to (0,1)
, and a box will have a width but not a height. Polygons are two dimensional. Volumes are three dimensional.
A MapPoint
class is a fundamental geometry that you need to master. As you've seen in previous chapters, it's easy to create:
MapPoint point = new MapPoint(0,0);
A MapPoint
class has six overloads on its constructor. To create a 3D point, just provide the z value:
MapPoint p1 = new MapPoint(0, 0, 0);
However, these simple examples don't say anything about the coordinate system we're using, so there is another overload that allows you to specify it, like this:
MapPoint point = new MapPoint(0, 0, 0, SpatialReferences.Wgs84);
By specifying WGS84, this point will be at latitude 0 degrees and longitude 0 degrees. This location is a very different location if the spatial reference is Mercator. To convert from one coordinate system to another, you will use the GeometryEngine
method, which we will discuss later.
If you have lots of points that need to be created, a better method is to use a PointCollection
class. For example, if you are loading in a CSV file with thousands of points, you could have code like this:
// create an empty point collection var points = new PointCollection(SpatialReferences.WebMercator); // set the capacity if you know the maximum number of points to add points.Capacity = maxNumberOfPoints; // repeat adding vertex coordinates directly into the // PointCollection (no MapPoint instances) while(lotsOfPoints) { // ... read x/y coordinate values ... points.AddPoint(x,y); } // pass the point collection to the Polygon constructor var polygon = new Polygon(points);
An envelope is just a rectangle that you can use in multiple ways. As we discussed earlier, you can use it to set or get the map extent, the viewing frustum in 3D, or get the extent of a set of geometries. And envelope has three overloaded constructors. You can create an envelope with two MapPoint
classes by setting the corners, using four coordinates, and by setting the four coordinates of the box along with a spatial reference.
Envelopes have several useful methods, such as GetCenter
, Intersect
, Intersects
, and Union
. These methods are useful when navigating the map or scene. For example, if your app has two maps and you want to merge the maps' two envelopes, you can do that with Union
.
Multipart is an abstract class for Polygon
and Polyline
. The most useful property in this class is parts. For example, if you have a polyline, you can get all of the constituent parts that make it up.
A polyline is a collection of one or more segments (lines). As with MapPoint
, this kind of geometry can be created with code or interactively via the mouse, touch, or stylus. To create a Polyline
constructor, you have several options. The polylines can be created with MapPoint
, an enumeration of MapPoint
classes, an enumeration of Segment
instances, or an enumeration of an enumeration of segments. For example, here's some code that creates a line from two MapPoint
classes that are added to a generic List
field:
MapPoint point1 = new MapPoint(0, 0, 0); MapPoint point2 = new MapPoint(0, 1, 0); List<MapPoint> list = new List<MapPoint>(); list.Add(point1); list.Add(point2); Polyline polyline = new Polyline(list, SpatialReferences.Wgs84);
To create Polyline
using LineSegment
, you can use the following code:
LineSegment linSegmentLeft = new LineSegment(point1, point2); LineSegment linSegmentTop = new LineSegment(point2, point3); LineSegment linSegmentRight = new LineSegment(point3, point4); LineSegment linSegmentBottom = new LineSegment(point4, point1); List<LineSegment> listOfLines = new List<ineSegment>(); Polyline pl = new Polyline(listOfLines);
A polygon is a closed shape defined by three or more parts. Each part is a connected sequence of Segment
instances. To create a polygon, the first point of the first Segment
instance must be at the same location at the last point of the last Segment
instance. This forms a closed ring. A polygon can have multiple rings, but they should not overlap. Here is a simple example of a polygon with one ring:
MapPoint point1 = new MapPoint(0, 0, 1); MapPoint point2 = new MapPoint(0, 1, 1); MapPoint point3 = new MapPoint(1, 1, 1); MapPoint point4 = new MapPoint(1, 0, 1); List<MapPoint> list = new List<MapPoint>(); Polygon polygon = new Polygon(list);
Here is another example of a polygon that contains two rings:
// interior ring List<MapPoint> exteriorRing = new List<MapPoint>(); exteriorRing.Add(new MapPoint(5, 5)); exteriorRing.Add(new MapPoint(5, 10)); exteriorRing.Add(new MapPoint(10, 10)); exteriorRing.Add(new MapPoint(10, 5)); //exterior ring List<MapPoint> interiorRing = new List<MapPoint>(); interiorRing.Add(new MapPoint(6, 6)); interiorRing.Add(new MapPoint(9, 6)); interiorRing.Add(new MapPoint(9, 9)); interiorRing.Add(new MapPoint(6, 9)); // List of rings List<List<MapPoint>> myRings = new List<List<MapPoint>>(); myRings.Add(interiorRing); myRings.Add(interiorRing); Polygon myPolygon = new Polygon(myRings);
Once the polygon has been symbolized, it will look like this:
It's very important that the points that make up the polygon or polyline must be ordered. One other method worth noting about a polygon is that you can get a polyline representation using Polygon.ToPolyline
. Also, a useful property is IsEmpty
, which can be used to check whether you can perform an operation on the polygon. If the polygon contains no parts, you won't be able to do anything with it.
A Multipoint
object is a single representation of multiple non-connected points. An example of this kind of geometry might be a collection of bore holes for a mining operation. Instead of tracking every point, they are grouped together to form a single record. Another example is a LiDAR point cloud. A Multipoint
object has two overloaded constructors. The first one allows for an IEnumerable collection, and the other one also allows for an IEnumerable
method with a SpatialReference
instance. A Multipoint
object is created like this:
MapPoint point1 = new MapPoint(0, 0, 1); MapPoint point2 = new MapPoint(0, 1, 1); MapPoint point3 = new MapPoint(1, 1, 1); MapPoint point4 = new MapPoint(1, 0, 1); List<MapPoint> list = new List<MapPoint>(); list.Add(point1); list.Add(point2); list.Add(point3); list.Add(point4); Multipoint mp = new Multipoint(list); // Once it is created you can access the individual MapPoints like // this: Multipoint multiPoint = new Multipoint(list); for (int i = 0; i < multiPoint.Points.Count; i++) { MapPoint point = multiPoint.Points[i]; }