Skip To Content ArcGIS for Developers Sign In Dashboard

ArcGIS Runtime SDK for Qt

Densify and generalize

Sample Viewer View Sample on GitHub

A multipart geometry can be densified by adding interpolated points at regular intervals. Generalizing a multipart geometry simplifies it while preserving its general shape. Densifying a multipart geometry adds more vertices at regular intervals.

Use case

The sample shows a polyline representing a ship's location at irregular intervals. The density of vertices along the ship's route is appropriate to represent the path of the ship at the sample map view's initial scale. However, that level of detail may be too great if you wanted to show a polyline of the ship's movement down the whole of the Willamette river. Then, you might consider generalizing the polyline to still faithfully represent the ship's passage on the river without having an overly complicated geometry.

Densifying a multipart geometry can be used to more accurately represent curved lines or to add more regularity to the vertices making up a multipart geometry.

How to use the sample

Use the sliders to control the parameters of the densify and generalize methods. You can deselect the checkboxes for either method to remove its effect from the result polyline.

How it works

To densify and generalize a polyline:

  1. Use the static method GeometryEngine.densify(polyline, maxSegmentLength) to densify the polyline. The resulting polyline will add points along the line so that there are no points greater than maxSegmentLength from the next point.
  2. Use the static method GeometryEngine.generalize(polyline, maxDeviation, true) to generalize the polyline. The resulting polyline will reduce vertices from the line to simplify the shape. None of these points can deviate farther from the original line than maxDeviation. The last parameter, removeDegenerateParts, will clean up extraneous parts if the geometry is multi-part (it will have no effect in this sample).
  3. Note that maxSegmentLength and maxDeviation are in the units of geometry's coordinate system. This could be in degrees in some coordinate systems. In this example, a cartesian coordinate system is used at a small enough scale that geodesic distances are not required.

Relevant API

  • GeometryEngine
  • Multipoint
  • Point
  • PointCollection
  • Polyline
  • SimpleLineSymbol
  • SpatialReference

Tags

densify, Edit and Manage Data, generalize, simplify

Sample Code

import QtQuick 2.6
import QtQuick.Controls 2.2
import Esri.ArcGISRuntime 100.9

Rectangle {
    id: rootRectangle
    clip: true
    width: 800
    height: 600    

    MapView {
        id: mapView
        anchors.fill: parent

        // Declare a map with the streets night vector basemap
        Map {
            BasemapStreetsNightVector {}
        }

        // Add a graphics overlay
        GraphicsOverlay {
            id: graphicsOverlay

            // original multipart red graphic
            Graphic {
                id: originalMultipointGraphic
                zIndex: 0

                SimpleMarkerSymbol {
                    color: "red"
                    size: 7
                    style: Enums.SimpleMarkerSymbolStyleCircle
                }

                Component.onCompleted: {
                    const pointCollection = createPointCollection();
                    const multipointBuilder = ArcGISRuntimeEnvironment.createObject("MultipointBuilder", { spatialReference: pointCollection.spatialReference });
                    multipointBuilder.points = pointCollection;
                    originalMultipointGraphic.geometry = multipointBuilder.geometry;
                    mapView.setViewpointGeometryAndPadding(originalMultipointGraphic.geometry, 100);
                }
            }

            // original red dotted line graphic
            Graphic {
                id: originalLineGraphic
                zIndex: 1

                SimpleLineSymbol {
                    color: "red"
                    style: Enums.SimpleLineSymbolStyleDot
                    width: 3
                }

                Component.onCompleted: {
                    const pointCollection = createPointCollection();
                    const polylineBuilder = ArcGISRuntimeEnvironment.createObject("PolylineBuilder", { spatialReference: pointCollection.spatialReference });
                    for (let i = 0; i < pointCollection.size; i++) {
                        polylineBuilder.addPoint(pointCollection.point(i));
                    }
                    originalLineGraphic.geometry = polylineBuilder.geometry;
                }
            }

            // resulting (densified and generalized) multipart magenta graphic
            Graphic {
                id: resultMultipointGraphic
                visible: showResultCheckbox.checked
                zIndex: 2

                SimpleMarkerSymbol {
                    color: "magenta"
                    size: 7
                    style: Enums.SimpleMarkerSymbolStyleCircle
                }
            }

            // resulting (densified and generalized) multipart magenta graphic
            Graphic {
                id: resultPolylineGraphic
                visible: showResultCheckbox.checked
                zIndex: 3

                SimpleLineSymbol {
                    color: "magenta"
                    width: 3
                    style: Enums.SimpleLineSymbolStyleSolid
                }
            }
        }
    }

    function updateGeometry() {
        // Get the initial Geometry
        let polyline = originalLineGraphic.geometry;
        if (!polyline)
            return;

        // Generalize the polyline
        if (generalizeCheckbox.checked)
            polyline = GeometryEngine.generalize(polyline, maxDeviationSlider.value, true);

        // Densify the polyline
        if (densifyCheckbox.checked)
            polyline = GeometryEngine.densify(polyline, maxSegmentLengthSlider.value);

        // Update the line graphic
        resultPolylineGraphic.geometry = polyline;

        // Update the multipoint graphic
        const multipointBuilder = ArcGISRuntimeEnvironment.createObject("MultipointBuilder", { spatialReference: polyline.spatialReference });
        const pointCollection = ArcGISRuntimeEnvironment.createObject("PointCollection", { spatialReference: polyline.spatialReference });
        if (polyline.parts.size < 1)
            return;

        const polylinePoints = polyline.parts.part(0).points();
        for (let i = 0; i < polylinePoints.size; i++) {
            pointCollection.addPoint(polylinePoints.point(i));
        }
        multipointBuilder.points = pointCollection;
        resultMultipointGraphic.geometry = multipointBuilder.geometry;
    }

    function createPointCollection() {
        const sr = ArcGISRuntimeEnvironment.createObject("SpatialReference", {wkid: 32126});
        const pointCollection = ArcGISRuntimeEnvironment.createObject("PointCollection", { spatialReference: sr });
        pointCollection.addPointXYZ(2330611.130549, 202360.002957, 0.000000);
        pointCollection.addPointXYZ(2330583.834672, 202525.984012, 0.000000);
        pointCollection.addPointXYZ(2330574.164902, 202691.488009, 0.000000);
        pointCollection.addPointXYZ(2330689.292623, 203170.045888, 0.000000);
        pointCollection.addPointXYZ(2330696.773344, 203317.495798, 0.000000);
        pointCollection.addPointXYZ(2330691.419723, 203380.917080, 0.000000);
        pointCollection.addPointXYZ(2330435.065296, 203816.662457, 0.000000);
        pointCollection.addPointXYZ(2330369.500800, 204329.861789, 0.000000);
        pointCollection.addPointXYZ(2330400.929891, 204712.129673, 0.000000);
        pointCollection.addPointXYZ(2330484.300447, 204927.797132, 0.000000);
        pointCollection.addPointXYZ(2330514.469919, 205000.792463, 0.000000);
        pointCollection.addPointXYZ(2330638.099138, 205271.601116, 0.000000);
        pointCollection.addPointXYZ(2330725.315888, 205631.231308, 0.000000);
        pointCollection.addPointXYZ(2330755.640702, 206433.354860, 0.000000);
        pointCollection.addPointXYZ(2330680.644719, 206660.240923, 0.000000);
        pointCollection.addPointXYZ(2330386.957926, 207340.947204, 0.000000);
        pointCollection.addPointXYZ(2330485.861737, 207742.298501, 0.000000);
        return pointCollection;
    }


    Rectangle {
        anchors {
            fill: controlColumn
            margins: -5
        }
        color: "#f9f9f9"
        radius: 5
    }

    Column {
        id: controlColumn
        anchors {
            left: parent.left
            top: parent.top
            margins: 10
        }
        spacing: 5


        CheckBox {
            id: densifyCheckbox
            text: "Densify"
            checked: true
        }

        Text {
            text: "Max segment length"
            enabled: densifyCheckbox.checked
        }

        Slider {
            id: maxSegmentLengthSlider
            from: 100
            to: 500
            width: 175
            value: 100
            onValueChanged: updateGeometry();
        }

        CheckBox {
            id: generalizeCheckbox
            text: "Generalize"
            checked: true
        }

        Text {
            text: "Max deviation"
            enabled: generalizeCheckbox.checked
        }

        Slider {
            id: maxDeviationSlider
            from: 1
            to: 250
            width: 175
            onValueChanged: updateGeometry();
        }

        CheckBox {
            id: showResultCheckbox
            text: "Show Result"
            checked: true
        }
    }
}