ArcGIS Runtime SDK for Qt

Edit geometries

You edit geometries when you want to change existing geometries or create new ones. However, Geometry objects are immutable. To edit geometries, use geometry builders.

Geometry builders

Geometry builders (or builders for short) create or change geometry. A geometry builder contains the same things a geometry contains—vertices, segments, and parts—allowing its state to be changed as needed. You can create new geometries at any point from the builder’s current state. A builder is available for each type of geometry. Each builder exposes the appropriate methods for modifying a specific type of geometry. In the case of PolylineBuilder and PolygonBuilder that share many members, both inherit from MultipartBuilder, which in turn inherits from GeometryBuilder. Other builders inherit directly from GeometryBuilder.

Because builders represent geometries under construction, they do not use the same immutable collection types as those returned from members of the geometry classes containing a part, part collection, or point collection. Instead, builder members use mutable collection types.

Modify existing geometry

To modify an existing geometry, complete the following steps:

  1. Create the appropriate type of builder and initialize its state by passing in the geometry to be edited. For example, modify a polyline by creating an PolylineBuilder and pass in the existing polyline to the builder.
  2. Use the methods on the builder to change the builder’s state. For example, add a new part to a polyline or remove a point from a multipoint.
  3. Get the changed geometry from the builder's geometry property.
  4. Repeat steps 2 and 3 as many times as necessary. By keeping a reference to the builder, you can repeatedly modify the builder state as many times as required, for example, to update a temporary graphic to display the current state to the user.

The following code demonstrates how to use a polyline builder to update a polyline geometry in a graphic as more points are appended to the polyline. Vertices are appended to the polyline when the user clicks on the map. The process can be restarted by clicking a button.

The polyline builder and the graphic are declared in QML code. The polyline builder gets the spatial reference from the map view. The geometry of the graphic will be set later.

PolylineBuilder {
    id: polylineBuilder
    spatialReference: currentSR
}


Graphic {
    id: editPolylineGraphic


    symbol: SimpleLineSymbol {
        style: Enums.SimpleLineSymbolStyleSolid
        color: "red"
        width: 4 * scaleFactor
    }
}

A JavaScript function (in this case the onClicked function for the restart button) clears the content of a graphics overlay and populates the polyline builder with an initial two points. The polyline geometry is retrieved from the builder and applied to the graphic, and the graphic is appended to the graphics overlay for display.

onClicked: {
    editPolylineGraphicsOverlay.graphics.clear();
    polylineBuilder.parts.removeAll();
    polylineBuilder.addPointXY(-100000.0, 0.0);
    polylineBuilder.addPointXY( 100000.0, 0.0);
    editPolylineGraphic.geometry = polylineBuilder.geometry;
    editPolylineGraphicsOverlay.graphics.append(editPolylineGraphic);

Later, in another JavaScript function that is called from the onClicked handler on the map, a point is added to the polyline builder. When a point is added, the graphic's geometry is updated in place. You do not need to recreate the graphic.

function addPoint(pt) {
    polylineBuilder.addPointXY(pt.x, pt.y);
    editPolylineGraphic.geometry = polylineBuilder.geometry;
}

You don't have to initialize a builder with an existing geometry—you can also use builders to create entirely new geometries.

When creating geometries, use sketchValid to determine when a builder contains enough information to convert the builder’s state successfully to a geometry.

Tip:

When editing geometries using locations from the screen, and the map is a wraparound map, you may need to normalize the geometry before you save it to a geodatabase or use it in tasks or other operations.

Spatial reference management

When working with geometries and builders, the following principles apply with regard to their SpatialReference:

  • The spatial reference of a builder is always set during builder instantiation and cannot be changed. It can be set to null.
  • You don't need to set the spatial reference of points or segments passed into methods on geometries, collections, or builders. If the spatial reference is not set, the input coordinates will be assumed to be in the same spatial reference as the geometry, collection, or builder.
  • It is an error to add a point or segment having a different spatial reference than that of the geometry, collection, or builder you're adding it to. This includes the case where the spatial reference of the geometry, collection, or builder is null and that of the added point or segment is not null.
  • A Point or Segment returned from a geometry’s member will have the same spatial reference as the geometry it came from.
  • When creating a new Polygon, the API first sets the spatial reference parameter for the new Polygon, then the points are added. If there is a mismatch between the spatial reference of the new Polygon and the points being added, this is an error.

Tip:

If required for your workflow, use the method on GeometryEngine to project points to a different spatial reference.

Multipoint geometries

You can declare a Multipoint with a QML declaration:

MultipointBuilder {
    id: mpBuilderWGS84
    spatialReference: SpatialReference { wkid: 4326 }
}

Then, add points using a JavaScript function:

mpBuilderWGS84.points.addPointXY(-117.195654, 34.056077);
mpBuilderWGS84.points.addPointXY(-117.190113, 34.057237);
mpBuilderWGS84.points.addPointXY(-117.195102, 34.057237);
var mpEsri = mpBuilderWGS84.geometry;

You can also use a MultipointBuilder to create a new or modify an existing Multipoint. Access the mutable PointCollection through the builder's points property, and work directly with this collection to add, remove, or insert points. When you are finished modifying the point collection, access the immutable Multipoint through the geometry property.

Multipart geometries

Polygons and polylines can have multiple parts. You can use a multipart polygon to define a group of islands, or a multipart polyline to represent a non-continuous linear feature. Due to the geometric complexity of polygons and polylines, PolylineBuilder and PolygonBuilder are used more frequently than other builders such as PointBuilder. Using the methods on these collections, you can build polygons and polylines by adding points. As with multipoint geometries, use the PointCollection to modify multipart geometries. Or, you can edit the segments in multipart geometries.

You can also edit using a mix of point-based and segment-based methods.

Editing parts

To edit the parts of a MultipartBuilder, use its parts property to access and change the PartCollection. You can also add a new point to the end of a MultipartBuilder using the addPointXY or addPointXYZ method.

Editing parts using points

The Part is a collection of segments. Working with the point-based method results in defining an ordered series of vertices and, as a consequence, creating straight LineSegments within the builder between those vertices.

The following principles apply when editing parts using points:

  • Use addPoint(int, Point) to insert a vertex at a specific index into a part. This will increase the number of segments in the part by one. Connections between segments are preserved—adjacent segments touch at their starting and ending vertices.
  • Use removePoint(int) to remove the vertex at a specific index from a part. The number of segments decreases by one, and connections between segments are preserved.
  • Use setPoint to replace a vertex in the collection without the need for a remove followed by an add. The total number of vertices or segments in the collection remains unchanged.
  • You can add a new vertex to the end of a MultipartBuilder using the addPoint method. This adds a vertex to the end of the last part in the builder. If there are no parts in the builder, this method will create a new part first, then add the new vertex.
  • You do not need to close a part belonging to a polygon.

Caution:

When working with point-based methods that take an index parameter, keep in mind that this is the index of the specific vertex, which is a different index than that used when working with segments. This is because where a segment’s ending vertex is at the same location as the starting vertex of the next segment, it is represented by a single Point in point-based methods.

Editing parts using segments

When you work with the segments in a part, you specify each segment’s starting and ending vertex. This differs from editing with points, where sequential vertices define a series of adjacent segments. Specifying starting and ending vertices for adjacent segments can result in gaps, where the end vertex of one segment does not have exactly the same location as the start vertex of the next adjacent segment. Gaps are not automatically corrected in the builder until you access the builder’s member to instantiate a new polyline or polygon. At that time, if any adjacent segments in the part do not touch, a short connecting segment will be added automatically to the new geometry to ensure the part forms a continuous edge in the new geometry. To avoid automatically adding segments, re-use the location of the end vertex of the previous segment as the start vertex of the subsequent segment, and use insert, remove, and add methods with care.

Similar to geometries, all segments are immutable. Unlike geometries, there are no builders for segments. Segments are fully defined when created, setting all properties at once.

The following principles apply when editing parts using segments:

  • Use setSegment to insert a segment into a part at a specific index. This increases the number of segments in the part by one. Be careful: this will result in a gap at either end of the new segment if the start and end vertices do not share a location with the preceding and following adjacent segments, respectively.
  • Use removeSegment to remove a segment from a part. If you remove anything other than the first or last segment in the part, this will result in a gap between the remaining segments. The number of segments decreases by one, and connections between segments are preserved.
  • Because segments are immutable, existing segments in a part cannot be changed. However, you can replace the existing segment at a specified index with a new segment by calling setSegment.
  • You do not need to close a part belonging to a polygon.

Caution:

When working with segment-based methods that take an index parameter, keep in mind that this is the index of the segment within the part and is a different index than that used when working with point-based helper methods. If a segment's ending vertex is at the same location as the starting vertex of the next segment, this location is represented by a single Point in point-based methods. However, if there is a gap, separate Points are returned for the two locations that define the gap.

Topological simplicity in features and graphics

To be saved as a feature in a geodatabase, a geometry must be simplified—that is, be topologically consistent. The rules vary for different types of geometry but include requirements such as polygons not having overlapping parts. Pass a geometry to the GeometryEngine object's simplify method to return a simplified copy that can be saved in a geodatabase.

Note that in some cases, simplification can change the contents of the geometry, including resulting in an empty geometry. Topological simplicity is different than geometry generalization. For more information, see ITopologicalOperator.Simplify in the ArcObjects help.

The requirements for a geometry that will be used in a graphic are less rigorous than those used in a feature—there is no need to simplify geometries to display them in graphics.

Builders and sketchValid

In some workflows, both graphics and features are used. In interactive editing scenarios, for example, a user sketches a geometry on the map. A graphic is used initially to display the state of the sketch during sketching. When the user decides that the sketch is complete, the geometry can be saved to a geodatabase feature. You can use sketchValid on a geometry builder to determine when the builder contains enough state to be converted successfully to a geometry. This is a useful tool to enable or disable saving the sketch by the user. To be considered a valid sketch, a polygon builder must contain at least one part with three or more vertices in it, and a polyline builder must contain at least one part with at least two vertices. A multipoint builder must contain at least one point, and for a point or envelope builder, the x and y coordinates must not be NaN. If these conditions are satisfied, these cases should result in a geometry that could be visible if drawn.

Although sketchValid may be a good first check when building a geometry, it should not be relied upon to indicate if the eventual geometry will be valid or empty after simplification. Before allowing a user to save a geometry, consider taking a further verification step of calling simplify. This approach can also be used for other situations that require geometries to be simple, for example, measurement or topological operations.

When importing or exporting geometries, for example, to JSON, if a multipart geometry has insufficient points, additional points can be added to ensure each segment has two endpoints to preserve the stability of other clients that may expect this.

Z-values and m-values

All types of geometry can have z-values. When building geometries, a simple rule determines whether or not the geometry stores z-values. If you call a method that has a z-value parameter, or add a point or segment that has z-values to a builder, the resulting geometry will store z-values—hasZ will return true.

Geometries can also have m-values, used in linear referencing workflows.

Pay special attention to z- and m-values in editing workflows. When syncing edits, sync errors may occur if the z- or m-awareness of the geometry does not match that of the service. Find out more in the ArcGIS REST API help topic Error handling with sync.

Tip:

When saving geometries in geodatabase features, check that hasZ and hasM match the attribute awareness of the feature table being edited.