API's for Drawing shapes and HitTest

1732
11
09-01-2018 09:45 AM
VishnuB
New Contributor III

Hi,

I am using ArcGIS Runtime 100.2.1 for Qt. Few days back i have gone through some sample runtime application for WPF. In that i saw many useful and easy API's for creating geometries and identifying graphics layers 

// Wait for user to draw
var geom = await MyMapView.Editor.RequestShapeAsync(DrawShape.Polygon);

//Hit test whlie mouse hovering

var graphic = await _graphicsLayer.HitTestAsync(MyMapView, screenPoint);

Is there any similar kind of API's available in Runtime sdk for Qt?

Thank You

Vishnu B

0 Kudos
11 Replies
LucasDanzinger
Esri Frequent Contributor

Hi Vishnu,

This looks like you are comparing the 10.2.x version to the 100.x version. GraphicsLayer has been replaced by GraphicsOverlay and hitTest has been replaced with MapView.identifyLayer/MapView.identifyGraphics.

With that said, Qt does not yet have these helpers to draw shapes easily, whereas .NET and other SDKs already do have the implemented. You can use the GeometryBuilder classes to draw geometries on your own, but the simplified helpers are not there yet. This is a feature that we call the "SketchEditor". We hope to have them soon in the Qt SDK.

Thanks,

Lucas

0 Kudos
BradDuBois
New Contributor II

What is the status of this for the Qt SDK?

0 Kudos
LucasDanzinger
Esri Frequent Contributor

SketchEditor still is not yet available, but you can still use the GeometryBuilder classes to build whatever geometries you want. Can you share some details about what workflows you are trying to achieve so we can prioritize the necessary work?

0 Kudos
BradDuBois
New Contributor II

Hello Lucas,

I’m working on providing a routing interface for flight plans. I am using the C++ and QML combination for the application so I have a MissionMap class that holds a SceneQuickView and is instantiated from QML. I want to be able to draw and edit a collection of lines with a symbol at the vertices and line ends that are not connected. I’d like to be able to click on the symbol to move the line end(s) around and redraw the line(s) as it’s being dragged. I am currently using a GraphicsOverlay and I’m just starting working through the live drawing of a route using the mouse. I am able to draw lines using the mouse click but I wanted to also be able to move the lines as discussed above but not sure how best to detect that a line has been clicked (I’m not drawing the vertex symbol yet, maybe I should work on that first so I can be more deterministic about which end of the line I want to move).

I also need to be able to draw the lines in 3D space, when I add a complete line programmatically and set the surfacePlacement to Absolute (I’ve tried various, and extreme z values, and the other surface placement types), it does not draw above the surface of map. I’m sure I’m doing something wrong, but I was able to use the corollary from QML and display lines in 3D space.

I still need to create some data structures to wrap around these overlay objects so I can get back to them and edit as needed.

Any help is greatly appreciated to be able to use this SDK to its fullest potential!

Thanks,

Brad DuBois

0 Kudos
LucasDanzinger
Esri Frequent Contributor

I think these types of workflows should still be possible. It sounds like you want a vertex editing example where each vertex of the line can be selected and moved to a new location. You should be able to do this by using the GeometryBuilder classes and various GeometryEngine methods, but I unfortunately don't have a sample for you. Hopefully I can put something together at some point to get you on the right track.

As for the surface placement, the issue could be a few different things:

- does it just draw as draped regardless of what you set, or is it not drawing at all?

- Is your graphics rendering mode set to dynamic or static? GraphicsOverlay Class | ArcGIS for Developers 

- What symbol are you using to display this?

0 Kudos
BradDuBois
New Contributor II

Currently I am not displaying the vertex symbol, I started looking into that last week but didn't find a solution before the weekend.  There will be a set of symbols that our graphics guy will make that represent different types of waypoint markers.  I am planning on .png files.  Something like this:

I was able to show that I can move a line with the PolylineBuilder object, updating one end of the line in the MouseMoved event handler:

void MissionMap::onMouseMoved(QMouseEvent &mouse)
{
    Point point = sceneView_->screenToBaseSurface(mouse.x(), mouse.y());
    if (isEditMode_ && mousePressedAndHeld_)
    {
        qDebug() << "Mouse Moving: (" << point.x() << ", " << point.y() << ")";
        lineBuilderFromMouse_.parts()->part(0)->setPoint(0, Point(point.x(), point.y(), point.z(), SpatialReference(WGS84)));
        routeOverlay_->graphics()->at(0)->setGeometry(lineBuilderFromMouse_.toGeometry());
        mouse.accept();
    }
}

I hardcoded the first indices for the part and point that is to be adjusted just so I could see if it moved as I hoped it would.  I do not know if this is recommended way of doing this but it does seem to work.  The problem I need to solve is being able to know what is being selected on Map so I can modify the correct object and point in the line builder.

For the 3D display of the lines, I'm trying to set it to Absolute and the call to setSurfacePlacement doesn't change the value for some reason:

This is being done in my MissionMap class constructor right after I new up the routeOverlay_ object.  Maybe there is something else that needs to be done before the surface placement can set?  I have tried both static and dynamic rendering modes but I get the same result.

Any samples of moving a line vertices by dragging around the vertex image would be very helpful.

0 Kudos
LucasDanzinger
Esri Frequent Contributor

Attached is an example of editing a 3D polyline. To use the app, select the "Select" radio button and then click on the line near a vertex to get the nearest vertex on the line. Select the "Edit" radio button to update the geometry of the selected vertex. It uses a TubeSymbol to display in 3D. Here is a preview of the code, but the attached project should run.

m_graphicsOverlay = new GraphicsOverlay(this);
m_sceneView->graphicsOverlays()->append(m_graphicsOverlay);
auto props = m_graphicsOverlay->sceneProperties();
props.setSurfacePlacement(SurfacePlacement::Absolute);
m_graphicsOverlay->setSceneProperties(props);

SolidStrokeSymbolLayer* sssl = new SolidStrokeSymbolLayer(5, QColor("red"), {}, StrokeSymbolLayerLineStyle3D::Tube, this);
MultilayerPolylineSymbol* mps = new MultilayerPolylineSymbol({sssl}, this);
SimpleRenderer* sr = new SimpleRenderer(mps, this);
m_graphicsOverlay->setRenderer(sr);

m_polylineBuilder = new PolylineBuilder(SpatialReference(3857), this);
m_polylineBuilder->addPoint(0, 0, 5);
m_polylineBuilder->addPoint(10, 10, 25);
m_polylineBuilder->addPoint(20, 20, 15);
m_polylineBuilder->addPoint(30, 60, 35);

m_graphic = new Graphic(m_polylineBuilder->toGeometry(), this);
m_graphicsOverlay->graphics()->append(m_graphic);

Camera camera(Point(-10, 10, SpatialReference(3857)), 200, 0, 90, 0);
m_sceneView->setViewpointCamera(camera);

connect(m_sceneView, &SceneQuickView::mouseClicked, this, [this](QMouseEvent e)
{
  m_sceneView->screenToLocation(e.x(), e.y());
});

connect(m_sceneView, &SceneQuickView::screenToLocationCompleted, this, [this](QUuid, Point pt)
{
  pt = GeometryEngine::project(pt, SpatialReference(3857));

  if (m_isSelecting)
  {
    auto result = GeometryEngine::nearestVertex(m_graphic->geometry(), pt);
    m_currentPartIndex = result.partIndex();
    m_currentPointIndex = result.pointIndex();
  }
  else
  {
    m_polylineBuilder->parts()->part(m_currentPartIndex)->setPoint(m_currentPointIndex, pt);
    m_graphic->setGeometry(m_polylineBuilder->toGeometry());
  }
});
BradDuBois
New Contributor II

Thanks Lucas,

I hadn't seen the GeometryEngine yet.  There looks to be some useful stuff in that class.  Your example does illustrate a some good stuff but I still have some questions.  The nearestVertex function needs to know what graphics object to check against.  How do we handle when there multiple polylines on the map?  Do we have to iterate the polylines and determine which was closest to the mouse click, then pass in that geometry?  Or is there a more direct way to tell what graphic was clicked on?

0 Kudos
LucasDanzinger
Esri Frequent Contributor

You'd use SceneView::identifyGraphicsOverlay for that. This takes in a graphics overlay and screen coordinates and tells you which graphic is at that location - GeoView Class | ArcGIS for Developers 

More conceptual doc on that is here - Identify features—ArcGIS Runtime SDK for Qt | ArcGIS for Developers