Use the Geometry Editor to create new point, multipoint, polyline, or polygon geometries or to edit existing geometries by interacting with a map view.

Use case
A field worker can mark features of interest on a map using an appropriate geometry. Features such as sample or observation locations, fences or pipelines, and building footprints can be digitized using point, multipoint, polyline, and polygon geometry types. Polyline and polygon geometries can be created and edited using a vertex-based creation and editing tool (i.e. vertex locations specified explicitly via tapping), or using a freehand tool.
How to use the sample
To create a new geometry, press the button appropriate for the geometry type you want to create (i.e. points, multipoints, polyline, or polygon) and interactively tap and drag on the map view to create the geometry.
To edit an existing geometry, tap the geometry to be edited in the map and then perform edits by tapping and dragging its elements.
When the whole geometry is selected, you can use the control handles to scale and rotate the geometry.
If creating or editing polyline or polygon geometries, choose the desired creation/editing tool (i.e. VertexTool, ReticleVertexTool, FreehandTool, or one of the available ShapeTools).
When using the ReticleVertexTool, you can move the map position of the reticle by dragging and zooming the map. Insert a vertex under the reticle by tapping on the map. Move a vertex by tapping when the reticle is located over a vertex, drag the map to move the position of the reticle, then tap a second time to place the vertex.
Use the control panel to undo or redo changes made to the geometry, delete a selected element, save the geometry, stop the editing session and discard any edits, and remove all geometries from the map.
How it works
-
Create a
GeometryEditorand set it to the MapView usingMapView::setGeometryEditor(GeometryEditor). -
Start the
GeometryEditorusingGeometryEditor::start(GeometryType)to create a new geometry orGeometryEditor::start(Geometry)to edit an existing geometry.- If using the Geometry Editor to edit an existing geometry, the geometry must be retrieved from the graphics overlay being used to visualize the geometry prior to calling the start method. To do this:
- Use
MapView::identifyGraphicsOverlayAsync(...)to identify graphics at the location of a tap. - Get the
IdentifyGraphicsOverlayResultvia theMapQuickView::IdentifyGraphicsOverLayCompletedslot - Find the desired graphic in the
IdentifyGraphicsOverlayResult::graphics()list. - Access the geometry associated with the
GraphicusingGraphic::geometry()- this will be used in theGeometryEditor::start(Geometry)method.
- Use
- If using the Geometry Editor to edit an existing geometry, the geometry must be retrieved from the graphics overlay being used to visualize the geometry prior to calling the start method. To do this:
-
Create
VertexTool,ReticleVertexTool,FreehandTool, orShapeToolobjects which define how the user interacts with the view to create or edit geometries, and set the geometry editor tool usingGeometryEditor::setTool(GeometryEditorTool). -
Edit a tool’s
InteractionConfigurationto set theGeometryEditorScaleModeto allow either uniform or stretch scale mode. -
Check to see if undo and redo are possible during an editing session using
GeometryEditor::canUndo()andGeometryEditor::canRedo(). If it’s possible, useGeometryEditor::undo()andGeometryEditor::redo(). -
Check whether the currently selected
GeometryEditorElementcan be deleted (GeometryEditor::selectedElement::canDelete()). If the element can be deleted, delete usingGeometryEditor::deleteSelectedElement(). -
Call
GeometryEditor::stop()to finish the editing session. TheGeometryEditordoes not automatically handle the visualization of a geometry output from an editing session. This must be done manually by propagating the geometry returned byGeometryEditor::stop()into aGraphicand aGraphicsOverlay.- To create a new
Graphicin theGraphicsOverlay:- Create a new
Graphicwith the geometry returned by theGeometryEditor::stop()method and a symbol. - Append the
Graphicto theGraphicsOverlay’sGraphicListModel(i.e.GraphicsOverlay::graphics::append(Graphic)).
- Create a new
- To update the geometry underlying an existing
Graphicin theGraphicsOverlay:- Replace the existing
Graphic’sGeometryproperty with the geometry returned by theGeometryEditor::stop()method usingGraphic::setGeometry(Geometry).
- Replace the existing
- To create a new
Relevant API
- Geometry
- GeometryEditor
- Graphic
- GraphicsOverlay
- MapView
Additional information
The sample opens with the ArcGIS Imagery basemap centered on the island of Inis Meáin (Aran Islands) in Ireland. Inis Meáin comprises a landscape of interlinked stone walls, roads, buildings, archaeological sites, and geological features, producing complex geometrical relationships.
Tags
draw, edit, freehand, geometry editor, sketch, vertex
Sample Code
// [WriteFile Name=CreateAndEditGeometries, Category=Geometry]// [Legal]// Copyright 2023 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
#ifdef PCH_BUILD#include "pch.hpp"#endif // PCH_BUILD
// sample headers#include "CreateAndEditGeometries.h"
// ArcGIS Maps SDK headers#include "FreehandTool.h"#include "GeometryEditor.h"#include "GeometryEditorElement.h"#include "GeometryEditorTypes.h"#include "GeometryTypes.h"#include "Graphic.h"#include "GraphicListModel.h"#include "GraphicsOverlay.h"#include "GraphicsOverlayListModel.h"#include "IdentifyGraphicsOverlayResult.h"#include "InteractionConfiguration.h"#include "Map.h"#include "MapQuickView.h"#include "MapTypes.h"#include "Multipoint.h"#include "MultipointBuilder.h"#include "Point.h"#include "PointCollection.h"#include "Polygon.h"#include "PolygonBuilder.h"#include "Polyline.h"#include "PolylineBuilder.h"#include "ReticleVertexTool.h"#include "ShapeTool.h"#include "SimpleFillSymbol.h"#include "SimpleLineSymbol.h"#include "SimpleMarkerSymbol.h"#include "SpatialReference.h"#include "SymbolTypes.h"#include "VertexTool.h"
// Qt headers#include <QFuture>#include <QUuid>
using namespace Esri::ArcGISRuntime;
CreateAndEditGeometries::CreateAndEditGeometries(QObject* parent /* = nullptr */): QObject(parent), m_map(new Map(BasemapStyle::ArcGISImagery, this)){ m_geometryEditor = new GeometryEditor(this); m_graphicsOverlay = new GraphicsOverlay(this); m_tempGraphicsParent = new QObject(this);
// Create the tools to toggle between m_vertexTool = new VertexTool(this); m_freehandTool = new FreehandTool(this); m_arrowTool = ShapeTool::create(ShapeToolType::Arrow, this); m_ellipseTool = ShapeTool::create(ShapeToolType::Ellipse, this); m_rectangleTool = ShapeTool::create(ShapeToolType::Rectangle, this); m_triangleTool = ShapeTool::create(ShapeToolType::Triangle, this); m_reticleTool = new ReticleVertexTool(this);}
CreateAndEditGeometries::~CreateAndEditGeometries() = default;
void CreateAndEditGeometries::init(){ // Register the map view for QML qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView"); qmlRegisterType<CreateAndEditGeometries>("Esri.Samples", 1, 0, "CreateAndEditGeometriesSample");}
// Set the view (created in QML)void CreateAndEditGeometries::setMapView(MapQuickView* mapView){ if (!mapView || mapView == m_mapView) return;
m_mapView = mapView; m_mapView->setMap(m_map);
m_mapView->setViewpointCenterAsync(Point(-9.5920, 53.08230, SpatialReference::wgs84()), 5000);
m_mapView->graphicsOverlays()->append(m_graphicsOverlay);
// Set the geometry editor on the map view m_mapView->setGeometryEditor(m_geometryEditor);
emit mapViewChanged();
createInitialSymbols(); createInitialGraphics(); createConnections();}
// Button methods
void CreateAndEditGeometries::startGeometryEditorWithGeometryType(GeometryEditorMode geometryEditorMode){ switch (geometryEditorMode) { case GeometryEditorMode::PointMode: m_geometryEditor->start(GeometryType::Point); break;
case GeometryEditorMode::MultipointMode: m_geometryEditor->start(GeometryType::Multipoint); break;
case GeometryEditorMode::PolylineMode: m_geometryEditor->start(GeometryType::Polyline); break;
case GeometryEditorMode::PolygonMode: m_geometryEditor->start(GeometryType::Polygon); break;
default: break; }
emit geometryEditorStartedChanged();}
void CreateAndEditGeometries::stopEditing(bool saveGeometry){ // Calling stop on the geometry editor returns the currently drawn geometry const Geometry geometry = m_geometryEditor->stop(); emit geometryEditorStartedChanged();
// If the user wants to discard edits if (!saveGeometry) { // If the user was editing an existing geometry, show the original graphic and clear the selection if (m_editingGraphic) { m_editingGraphic->setVisible(true); m_editingGraphic = nullptr; } return; }
// If the user wants to stop editing and save the geometry // If the user was editing an existing graphic, update its geometry if (m_editingGraphic) { m_editingGraphic->setGeometry(geometry);
// Show the graphic and clear the selection m_editingGraphic->setVisible(true); m_editingGraphic = nullptr;
return; }
// If the user was not editing an existing graphic, create a new graphic with the geometry and a symbol // Determine what symbology to use for the graphic Symbol* geometrySymbol = nullptr; switch (geometry.geometryType()) { case GeometryType::Point: geometrySymbol = m_pointSymbol; break;
case GeometryType::Multipoint: geometrySymbol = m_multiPointSymbol; break;
case GeometryType::Polyline: geometrySymbol = m_lineSymbol; break;
case GeometryType::Polygon: geometrySymbol = m_polygonSymbol; break;
default: return; }
// Append the new graphic to the graphics overlay m_graphicsOverlay->graphics()->append(new Graphic(geometry, geometrySymbol, m_tempGraphicsParent));}
void CreateAndEditGeometries::setTool(GeometryEditorToolType toolType){ switch (toolType) { case GeometryEditorToolType::Vertex: m_geometryEditor->setTool(m_vertexTool); break;
case GeometryEditorToolType::Freehand: m_geometryEditor->setTool(m_freehandTool); break;
case GeometryEditorToolType::Arrow: m_geometryEditor->setTool(m_arrowTool); break;
case GeometryEditorToolType::Ellipse: m_geometryEditor->setTool(m_ellipseTool); break;
case GeometryEditorToolType::Rectangle: m_geometryEditor->setTool(m_rectangleTool); break;
case GeometryEditorToolType::Triangle: m_geometryEditor->setTool(m_triangleTool); break;
case GeometryEditorToolType::Reticle: m_geometryEditor->setTool(m_reticleTool);
default: break; }}
void CreateAndEditGeometries::clearGraphics(){ m_graphicsOverlay->graphics()->clear();
// Clearing the graphics overlay does not delete the graphics it contains // We can delete the graphics' shared parent to easily delete all of them and prevent memory leaks delete m_tempGraphicsParent; m_tempGraphicsParent = new QObject(this);}
void CreateAndEditGeometries::undo(){ if (m_geometryEditor->canUndo()) m_geometryEditor->undo(); emit canUndoOrRedoChanged();}
void CreateAndEditGeometries::redo(){ if (m_geometryEditor->canRedo()) m_geometryEditor->redo(); emit canUndoOrRedoChanged();}
void CreateAndEditGeometries::deleteSelectedElement(){ m_geometryEditor->deleteSelectedElement(); emit canUndoOrRedoChanged();}
void CreateAndEditGeometries::setScaleMode(ScaleMode scaleMode){ const GeometryEditorScaleMode toolScaleMode = (scaleMode == ScaleMode::UniformScaleMode) ? GeometryEditorScaleMode::Uniform : GeometryEditorScaleMode::Stretch;
// Set the scale mode on all available tools m_vertexTool->configuration()->setScaleMode(toolScaleMode); m_freehandTool->configuration()->setScaleMode(toolScaleMode); m_arrowTool->configuration()->setScaleMode(toolScaleMode); m_ellipseTool->configuration()->setScaleMode(toolScaleMode); m_rectangleTool->configuration()->setScaleMode(toolScaleMode); m_triangleTool->configuration()->setScaleMode(toolScaleMode);}
MapQuickView* CreateAndEditGeometries::mapView() const{ return m_mapView;}
// Create slots for asynchronous signalsvoid CreateAndEditGeometries::createConnections(){ // Allow user to edit existing graphics by clicking on them connect(m_mapView, &MapQuickView::mouseClicked, this, [this](const QMouseEvent& mouseEvent) { if (!m_geometryEditor->isStarted()) { m_mapView->identifyGraphicsOverlayAsync(m_graphicsOverlay, mouseEvent.position(), 5 ,false).then(this, [this](IdentifyGraphicsOverlayResult* rawResult){ // Handle editing selected graphics, if any
auto identifyResult = std::unique_ptr<IdentifyGraphicsOverlayResult>(rawResult);
// Return if no graphics were identified if (identifyResult->graphics().isEmpty()) return;
m_editingGraphic = identifyResult->graphics().first();
// Hide the graphic currently being edited m_editingGraphic->setVisible(false);
// Start the geometry editor with the graphic's geometry. This does not directly affect the graphic. m_geometryEditor->start(m_editingGraphic->geometry());
emit geometryEditorStartedChanged(); }); } emit canUndoOrRedoChanged(); emit elementIsSelectedChanged(); });
// Enable or disable buttons when mouse is released (ie after a drag operation) connect(m_mapView, &MapQuickView::mouseReleased, this, [this](const QMouseEvent&) { emit canUndoOrRedoChanged(); emit elementIsSelectedChanged(); });}
// State checks to control when buttons are enabledbool CreateAndEditGeometries::geometryEditorStarted() const{ return (m_geometryEditor && m_geometryEditor->isStarted());}
bool CreateAndEditGeometries::canUndo(){ return (m_geometryEditor && m_geometryEditor->canUndo());}
bool CreateAndEditGeometries::canRedo(){ return (m_geometryEditor && m_geometryEditor->canRedo());}
bool CreateAndEditGeometries::elementIsSelected(){ return (m_geometryEditor && m_geometryEditor->selectedElement() && m_geometryEditor->selectedElement()->canDelete());}
// Create symbols used by all graphicsvoid CreateAndEditGeometries::createInitialSymbols(){ m_pointSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle::Square, QColor(255, 45, 0), 10, this); m_multiPointSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle::Circle, QColor(255, 255, 0), 5, this); m_lineSymbol = new SimpleLineSymbol(SimpleLineSymbolStyle::Solid, QColor(0, 0, 255), 2, this); m_polygonSymbol = new SimpleFillSymbol(SimpleFillSymbolStyle::Solid, QColor(255, 0, 0, 75), new SimpleLineSymbol(SimpleLineSymbolStyle::Dash, QColor(0, 0, 0), 1.0, this), this);}
// Create graphics that are present upon sample instantiationvoid CreateAndEditGeometries::createInitialGraphics(){ // Create a temporary parent to give all the builders so we can easily delete them later QObject* tempParent = new QObject(this);
// Create point geometry const Point house(-9.59309629, 53.0830063, SpatialReference::wgs84());
// Create multipoint geometry MultipointBuilder* multipointBuilder = new MultipointBuilder(SpatialReference::wgs84(), tempParent); PointCollection* pointCollection = new PointCollection(SpatialReference::wgs84(), tempParent); pointCollection->addPoints( { Point(-9.59386587, 53.08289651), Point(-9.59330546, 53.08256400), Point(-9.59326997, 53.08304595), Point(-9.59250034, 53.08286101), Point(-9.59286835, 53.08311506), Point(-9.59370896, 53.08234917), Point(-9.59341755, 53.08286662), Point(-9.59246485, 53.08294507), Point(-9.59241815, 53.08284607), Point(-9.59307943, 53.08234731) }); multipointBuilder->setPoints(pointCollection); const Multipoint outbuildings(multipointBuilder->toMultipoint());
// Create polyline geometries PolylineBuilder* polylineBuilder = new PolylineBuilder(SpatialReference::wgs84(), tempParent); polylineBuilder->addPoints( { Point(-9.59486423, 53.08169453), Point(-9.5947812, 53.081754310), Point(-9.59475464, 53.08189379), Point(-9.59494393, 53.08213622), Point(-9.59464173, 53.08240521), Point(-9.59413694, 53.08260115), Point(-9.59357903, 53.08292660), Point(-9.59335984, 53.08311589), Point(-9.59318051, 53.08316903), Point(-9.59301779, 53.08322216), Point(-9.59264252, 53.08370038), Point(-9.59250636, 53.08383986) });
const Polyline road1(polylineBuilder->toPolyline()); delete polylineBuilder;
polylineBuilder = new PolylineBuilder(SpatialReference::wgs84(), tempParent); polylineBuilder->addPoints( { Point(-9.59400079, 53.08136244), Point(-9.59395761, 53.08149528), Point(-9.59368862, 53.08170450), Point(-9.59358235, 53.08219267), Point(-9.59331667, 53.08290335), Point(-9.59314398, 53.08314246), Point(-9.59306760, 53.08330519), Point(-9.59303439, 53.08351109), Point(-9.59301447, 53.08363728), Point(-9.59293809, 53.08387307) });
const Polyline road2(polylineBuilder->toPolyline());
// Create polygon geometry PolygonBuilder* polygonBuilder = new PolygonBuilder(SpatialReference::wgs84(), tempParent); polygonBuilder->addPoints( { Point(-9.59350122, 53.08320723), Point(-9.59345177, 53.08333534), Point(-9.59309789, 53.08327198), Point(-9.59300344, 53.08317992), Point(-9.59221827, 53.08304034), Point(-9.59220706, 53.08287782), Point(-9.59229486, 53.08280871), Point(-9.59236398, 53.08268915), Point(-9.59255263, 53.08256769), Point(-9.59265165, 53.08237906), Point(-9.59287552, 53.08241478), Point(-9.59292812, 53.08230120), Point(-9.59322940, 53.08235022), Point(-9.59342188, 53.08260009), Point(-9.59354382, 53.08238728), Point(-9.59365852, 53.08203535), Point(-9.59408443, 53.08210446), Point(-9.59448232, 53.08224456), Point(-9.59436090, 53.08243697), Point(-9.59458319, 53.08245939), Point(-9.59439639, 53.08264619), Point(-9.59433288, 53.08279750), Point(-9.59404707, 53.08323649), Point(-9.59350122, 53.08320723) });
const Polygon boundary(polygonBuilder->toPolygon());
// Delete the builders' parent to clean up all objects used in creating the graphics delete tempParent;
// Create graphics with the geometries m_graphicsOverlay->graphics()->append( { new Graphic(boundary, m_polygonSymbol, m_tempGraphicsParent), new Graphic(road2, m_lineSymbol, m_tempGraphicsParent), new Graphic(road1, m_lineSymbol, m_tempGraphicsParent), new Graphic(outbuildings, m_multiPointSymbol, m_tempGraphicsParent), new Graphic(house, m_pointSymbol, m_tempGraphicsParent) });}// [WriteFile Name=CreateAndEditGeometries, Category=Geometry]// [Legal]// Copyright 2023 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
#ifndef CREATEANDEDITGEOMETRIES_H#define CREATEANDEDITGEOMETRIES_H
// Qt headers#include <QObject>
namespace Esri::ArcGISRuntime{ class GeometryEditor; class Graphic; class GraphicsOverlay; class FreehandTool; class Map; class MapQuickView; class ShapeTool; class SimpleMarkerSymbol; class SimpleLineSymbol; class SimpleFillSymbol; class VertexTool; class ReticleVertexTool;}
Q_MOC_INCLUDE("MapQuickView.h");
class CreateAndEditGeometries : public QObject{ Q_OBJECT
Q_PROPERTY(Esri::ArcGISRuntime::MapQuickView* mapView READ mapView WRITE setMapView NOTIFY mapViewChanged) Q_PROPERTY(bool geometryEditorStarted READ geometryEditorStarted NOTIFY geometryEditorStartedChanged) Q_PROPERTY(bool canUndo READ canUndo NOTIFY canUndoOrRedoChanged) Q_PROPERTY(bool canRedo READ canRedo NOTIFY canUndoOrRedoChanged) Q_PROPERTY(bool elementIsSelected READ elementIsSelected NOTIFY elementIsSelectedChanged)
public: explicit CreateAndEditGeometries(QObject* parent = nullptr); ~CreateAndEditGeometries() override;
enum class GeometryEditorMode { PointMode, MultipointMode, PolylineMode, PolygonMode };
Q_ENUM(GeometryEditorMode)
enum class ScaleMode { StretchScaleMode, UniformScaleMode };
Q_ENUM(ScaleMode)
enum class GeometryEditorToolType { Freehand, Vertex, Arrow, Ellipse, Rectangle, Triangle, Reticle };
Q_ENUM(GeometryEditorToolType)
static void init();
Q_INVOKABLE void startGeometryEditorWithGeometryType(GeometryEditorMode geometryEditorMode); Q_INVOKABLE void stopEditing(bool saveGeometry); Q_INVOKABLE void setTool(GeometryEditorToolType toolType); Q_INVOKABLE void clearGraphics(); Q_INVOKABLE void undo(); Q_INVOKABLE void redo(); Q_INVOKABLE void deleteSelectedElement(); Q_INVOKABLE void setScaleMode(ScaleMode scaleMode);
signals: void mapViewChanged(); void geometryEditorStartedChanged(); void canUndoOrRedoChanged(); void elementIsSelectedChanged();
private: Esri::ArcGISRuntime::MapQuickView* mapView() const; void setMapView(Esri::ArcGISRuntime::MapQuickView* mapView); bool geometryEditorStarted() const; bool canUndo(); bool canRedo(); bool elementIsSelected();
void createInitialSymbols(); void createInitialGraphics(); void createConnections();
Esri::ArcGISRuntime::Map* m_map = nullptr; Esri::ArcGISRuntime::MapQuickView* m_mapView = nullptr;
Esri::ArcGISRuntime::GraphicsOverlay* m_graphicsOverlay = nullptr; Esri::ArcGISRuntime::Graphic* m_editingGraphic = nullptr;
Esri::ArcGISRuntime::SimpleMarkerSymbol* m_pointSymbol = nullptr; Esri::ArcGISRuntime::SimpleMarkerSymbol* m_multiPointSymbol = nullptr; Esri::ArcGISRuntime::SimpleLineSymbol* m_lineSymbol = nullptr; Esri::ArcGISRuntime::SimpleFillSymbol* m_polygonSymbol = nullptr;
Esri::ArcGISRuntime::GeometryEditor* m_geometryEditor = nullptr;
// Tools Esri::ArcGISRuntime::VertexTool* m_vertexTool = nullptr; Esri::ArcGISRuntime::FreehandTool* m_freehandTool = nullptr; Esri::ArcGISRuntime::ShapeTool* m_arrowTool = nullptr; Esri::ArcGISRuntime::ShapeTool* m_ellipseTool = nullptr; Esri::ArcGISRuntime::ShapeTool* m_rectangleTool = nullptr; Esri::ArcGISRuntime::ShapeTool* m_triangleTool = nullptr; Esri::ArcGISRuntime::ReticleVertexTool* m_reticleTool = nullptr;
QObject* m_tempGraphicsParent = nullptr;};
#endif // CREATEANDEDITGEOMETRIES_H// [WriteFile Name=CreateAndEditGeometries, Category=Geometry]// [Legal]// Copyright 2023 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
import QtQuickimport QtQuick.Controlsimport QtQuick.Layoutsimport Esri.Samples
Item {
// add a mapView component MapView { id: view anchors.fill: parent
Component.onCompleted: { // Set and keep the focus on MapView to enable keyboard navigation forceActiveFocus(); } }
// Declare the C++ instance which creates the map etc. and supply the view CreateAndEditGeometriesSample { id: model mapView: view
onGeometryEditorStartedChanged: { // Uncheck UI buttons when the geometry editor stops if (!geometryEditorStarted) { pointButton.checked = false; multiPointButton.checked = false; lineButton.checked = false; polygonButton.checked = false; } } }
// Prevent mouse interaction from propagating to the MapView MouseArea { anchors.fill: control onPressed: mouse => mouse.accepted = true; onWheel: wheel => wheel.accepted = true; }
Control { id: control anchors.right: parent.right padding: 5 width: 140
background: Rectangle { color: "black" opacity: .5 }
contentItem: ColumnLayout { id: columns anchors { verticalCenter: parent.verticalCenter horizontalCenter: parent.horizontalCenter }
GridLayout { id: geometryColumn Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter columns: 2
Text { id: geometryHeader Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Layout.columnSpan: 2 text: "Create" color: "white" font.pixelSize: 16 font.bold: true }
GeometryEditorButton { id: pointButton buttonName: qsTr("Point") iconPath: "qrc:/Samples/Geometry/CreateAndEditGeometries/iconAssets/point-32.png" checkable: true enabled: !model.geometryEditorStarted onClicked: { toolCombo.currentIndex = 0; toolCombo.enabled = false; model.startGeometryEditorWithGeometryType(CreateAndEditGeometriesSample.PointMode); } }
GeometryEditorButton { id: multiPointButton buttonName: qsTr("Multipoint") iconPath: "qrc:/Samples/Geometry/CreateAndEditGeometries/iconAssets/multipoint-32.png" checkable: true enabled: !model.geometryEditorStarted onClicked: { toolCombo.currentIndex = 0; toolCombo.enabled = false; model.startGeometryEditorWithGeometryType(CreateAndEditGeometriesSample.MultipointMode); } }
GeometryEditorButton { id: lineButton buttonName: qsTr("Line") iconPath: "qrc:/Samples/Geometry/CreateAndEditGeometries/iconAssets/line-32.png" checkable: true enabled: !model.geometryEditorStarted onClicked: { model.startGeometryEditorWithGeometryType(CreateAndEditGeometriesSample.PolylineMode); } }
GeometryEditorButton { id: polygonButton buttonName: qsTr("Polygon") iconPath: "qrc:/Samples/Geometry/CreateAndEditGeometries/iconAssets/polygon-32.png" checkable: true enabled: !model.geometryEditorStarted onClicked: { model.startGeometryEditorWithGeometryType(CreateAndEditGeometriesSample.PolygonMode); } }
ComboBox { id: toolCombo model: [qsTr("Vertex Tool"), qsTr("Freehand Tool"), qsTr("Arrow Shape Tool"), qsTr("Ellipse Shape Tool"), ("Rectangle Shape Tool"), qsTr("Triangle Shape Tool"), qsTr("Reticle Tool")] Layout.columnSpan: 2 Layout.fillWidth: true
Rectangle { anchors.fill: parent radius: 10 // Make the rectangle visible if a dropdown indicator exists // An indicator only exists if a theme is set visible: parent.indicator border.width: 1 }
onCurrentIndexChanged: { switch (currentIndex) { case 0: // Vertex Tool model.setTool(CreateAndEditGeometriesSample.Vertex); break; case 1: // Freehand Tool model.setTool(CreateAndEditGeometriesSample.Freehand); break; case 2: // ShapeTool with arrow shape type model.setTool(CreateAndEditGeometriesSample.Arrow); break; case 3: // ShapeTool with ellipse shape type model.setTool(CreateAndEditGeometriesSample.Ellipse); break; case 4: // ShapeTool with rectangle shape type model.setTool(CreateAndEditGeometriesSample.Rectangle); break; case 5: // ShapeTool with triangle shape type model.setTool(CreateAndEditGeometriesSample.Triangle); break; case 6: // Reticle Vertex Tool model.setTool(CreateAndEditGeometriesSample.Reticle); break; default: model.setTool(CreateAndEditGeometriesSample.Vertex); } } } }
ComboBox { id: scaleModeDropdown Layout.columnSpan: 2 Layout.fillWidth: true
Rectangle { anchors.fill: parent radius: 10 // Make the rectangle visible if a dropdown indicator exists // An indicator only exists if a theme is set visible: parent.indicator border.width: 1 }
model: ["Stretch Scale", "Uniform Scale"] enabled: true onCurrentIndexChanged: { switch (currentIndex) { case 0: model.setScaleMode(CreateAndEditGeometriesSample.StretchScaleMode); break; case 1: model.setScaleMode(CreateAndEditGeometriesSample.UniformScaleMode); break; default: break; } }
}
GridLayout { id: editingColumn Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter columns: 2
Text { id: editingHeader Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Layout.columnSpan: 2 text: qsTr("Edit") color: "white" font.pixelSize: 16 font.bold: true }
GeometryEditorButton { id: undoButton buttonName: qsTr("Undo") iconPath: "qrc:/Samples/Geometry/CreateAndEditGeometries/iconAssets/undo-32.png" enabled: model.geometryEditorStarted && model.canUndo onClicked: model.undo(); }
GeometryEditorButton { id: redoButton buttonName: qsTr("Redo") iconPath: "qrc:/Samples/Geometry/CreateAndEditGeometries/iconAssets/redo-32.png" enabled: model.geometryEditorStarted && model.canRedo onClicked: model.redo(); }
GeometryEditorButton { id: deleteVertexButton buttonName: qsTr("Delete selected element") iconPath: "qrc:/Samples/Geometry/CreateAndEditGeometries/iconAssets/erase-32.png" Layout.columnSpan: 2 enabled: model.geometryEditorStarted && model.elementIsSelected onClicked: model.deleteSelectedElement(); }
GeometryEditorButton { id: saveEditsButton buttonName: qsTr("Stop and save edits") iconPath: "qrc:/Samples/Geometry/CreateAndEditGeometries/iconAssets/check-circle-32.png" Layout.columnSpan: 2 enabled: model.geometryEditorStarted onClicked: { toolCombo.enabled = true; model.stopEditing(true); } }
GeometryEditorButton { id: discardEditsButton buttonName: qsTr("Stop and discard edits") iconPath: "qrc:/Samples/Geometry/CreateAndEditGeometries/iconAssets/circle-disallowed-32.png" Layout.columnSpan: 2 enabled: model.geometryEditorStarted onClicked: { toolCombo.enabled = true; model.stopEditing(false); } }
GeometryEditorButton { id: clearGraphicsButton buttonName: qsTr("Delete all geometries") iconPath: "qrc:/Samples/Geometry/CreateAndEditGeometries/iconAssets/trash-32.png" Layout.columnSpan: 2 enabled: !model.geometryEditorStarted onClicked: model.clearGraphics(); } } } }}// [WriteFile Name=CreateAndEditGeometries, Category=Geometry]// [Legal]// Copyright 2023 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
import QtQuickimport QtQuick.Controlsimport QtQuick.Layouts
// This component defines each of the buttons in the Geometry Editor control UI
RoundButton { id: geometryEditorButton
property string buttonName: "" property string iconPath: ""
Layout.fillWidth: true
// Set the focus policy so that the buttons do not take focus from the MapView focusPolicy: Qt.NoFocus
radius: 5
Rectangle { anchors.fill: parent radius: parent.radius opacity: parent.enabled || parent.checked ? 1 : 0.3 color: geometryEditorButton.down ? "#d0d0d0" : "#e0e0e0" }
Image { id: imgComponent anchors { horizontalCenter: parent.horizontalCenter verticalCenter: parent.verticalCenter verticalCenterOffset: -textComponent.height/2 } source: iconPath width: 20 fillMode: Image.PreserveAspectFit }
Text { id: textComponent anchors { top: imgComponent.bottom horizontalCenter: parent.horizontalCenter } text: buttonName font.pixelSize: 8 }}// [Legal]// Copyright 2023 Esri.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// [Legal]
// sample headers#include "CreateAndEditGeometries.h"
// ArcGIS Maps SDK headers#include "ArcGISRuntimeEnvironment.h"
// Qt headers#include <QCommandLineParser>#include <QDir>#include <QGuiApplication>#include <QQmlApplicationEngine>
// Platform specific headers#ifdef Q_OS_WIN#include <Windows.h>#endif
int main(int argc, char *argv[]){ Esri::ArcGISRuntime::ArcGISRuntimeEnvironment::setUseLegacyAuthentication(false); QGuiApplication app(argc, argv); app.setApplicationName(QString("CreateAndEditGeometries"));
// Use of ArcGIS location services, such as basemap styles, geocoding, and routing services, // requires an access token. For more information see // https://links.esri.com/arcgis-runtime-security-auth.
// The following methods grant an access token:
// 1. User authentication: Grants a temporary access token associated with a user's ArcGIS account. // To generate a token, a user logs in to the app with an ArcGIS account that is part of an // organization in ArcGIS Online or ArcGIS Enterprise.
// 2. API key authentication: Get a long-lived access token that gives your application access to // ArcGIS location services. Go to the tutorial at https://links.esri.com/create-an-api-key. // Copy the API Key access token.
const QString accessToken = QString("");
if (accessToken.isEmpty()) { qWarning() << "Use of ArcGIS location services, such as the basemap styles service, requires" << "you to authenticate with an ArcGIS account or set the API Key property."; } else { Esri::ArcGISRuntime::ArcGISRuntimeEnvironment::setApiKey(accessToken); }
// Initialize the sample CreateAndEditGeometries::init();
// Initialize application view QQmlApplicationEngine engine; // Add the import Path engine.addImportPath(QDir(QCoreApplication::applicationDirPath()).filePath("qml"));
#ifdef ARCGIS_RUNTIME_IMPORT_PATH_2 engine.addImportPath(ARCGIS_RUNTIME_IMPORT_PATH_2);#endif
// Set the source engine.load(QUrl("qrc:/Samples/Geometry/CreateAndEditGeometries/main.qml"));
return app.exec();}// Copyright 2023 Esri.
// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.
import QtQuick.Controlsimport Esri.Samples
ApplicationWindow { visible: true width: 800 height: 600
CreateAndEditGeometries { anchors.fill: parent }}