Find the shortest distance between a polyline and a point. Draw a red polyline with left-clicks of mouse. Vertices are added until you double-click to end the polyline. The next left-click marks a point in blue. The distance measured is between the polyline and the point. Your application can find the shortest distance between two geometries in map units with GeometryEngine::distance(). Using another approach, this sample measures the length along a geodesic line using GeometryEngine::getNearestCoordinate(). It returns the nearest coordinate of the polyline to the point, and can return the distance in various units. A line is drawn between the point and the nearest coordinate on the line. Then the sample calls GeometryEngine::geodesicLength() to get the distance in miles.
Shortest distance (online)
// Copyright 2015 ESRI
//
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
//
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
//
// See the Sample code usage restrictions document for further information.
//
#ifndef SHORTEST_DISTANCE_SAMPLE_H
#define SHORTEST_DISTANCE_SAMPLE_H
#include "rtsample.h"
#include "Polyline.h"
#include "GraphicsLayer.h"
#include "Point.h"
#include "Geometry.h"
#include <QGraphicsItem>
namespace Ui {
class shortest_distance_sample;
}
class shortest_distance_mouse_helper;
class shortest_distance_sample : public RTSample
{
Q_OBJECT
friend class shortest_distance_mouse_helper;
public:
explicit shortest_distance_sample(const QString& title, const QString& categoryList, const QString& shortDesc, const QString& longDesc, const QString& thumbnail);
virtual ~shortest_distance_sample();
virtual void run();
public slots:
void onMapReady();
void onMouseRelease(QMouseEvent& event);
void onMousePress(QMouseEvent& event);
private:
void reset();
void drawPoint(const EsriRuntimeQt::Point& point);
void drawLine(const EsriRuntimeQt::Point& point);
void shortestDistance(const EsriRuntimeQt::Point& point);
shortest_distance_mouse_helper *m_mouseHelper;
EsriRuntimeQt::Polyline m_polyline;
EsriRuntimeQt::GraphicsLayer* m_graphicsLayer;
QList<EsriRuntimeQt::Geometry> m_points;
QPointF m_lastMouseCoord;
QLabel *m_distanceLabel;
bool m_shortestDistance;
bool m_doubleClick;
bool m_ignoredDoubleClickRelease;
bool m_pathBegan;
int m_polyLineGraphicId;
};
class shortest_distance_mouse_helper : public QGraphicsItem
{
Q_INTERFACES(QGraphicsItem)
public:
QRectF boundingRect() const
{
return QRect(0, 0, m_sample->m_map->width(), m_sample->m_map->height());
}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{ // No need to paint
Q_UNUSED(painter)
Q_UNUSED(option)
Q_UNUSED(widget)
}
shortest_distance_mouse_helper(shortest_distance_sample *sample)
{
setAcceptHoverEvents(true);
m_sample = sample;
}
private:
shortest_distance_mouse_helper() {}
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
shortest_distance_sample *m_sample;
};
#endif // SHORTEST_DISTANCE_SAMPLE_H
// Copyright 2015 ESRI
//
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
//
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
//
// See the Sample code usage restrictions document for further information.
//
#include "shortest_distance_sample.h"
#include "GeometryEngine.h"
#include "ArcGISTiledMapServiceLayer.h"
#include "SimpleMarkerSymbol.h"
#include "widgetpanel.h"
shortest_distance_sample::shortest_distance_sample(const QString& title, const QString& categoryList, const QString& shortDesc, const QString& longDesc, const QString& thumbnail) :
RTSample(title, categoryList, shortDesc, longDesc, thumbnail),
m_mouseHelper(nullptr),
m_distanceLabel(nullptr),
m_shortestDistance(false),
m_doubleClick(false),
m_ignoredDoubleClickRelease(false),
m_pathBegan(false),
m_polyLineGraphicId(-1)
{
}
shortest_distance_sample::~shortest_distance_sample()
{
}
void shortest_distance_sample::run()
{
setRunning();
m_map = new EsriRuntimeQt::Map(this);
m_mapGraphicsView = EsriRuntimeQt::MapGraphicsView::create(m_map, this);
QString url("http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer");
EsriRuntimeQt::ArcGISTiledMapServiceLayer* mapServiceLayer = new EsriRuntimeQt::ArcGISTiledMapServiceLayer(url, this);
m_map->addLayer(mapServiceLayer);
// Construct the GraphicsLayer object
m_graphicsLayer = new EsriRuntimeQt::GraphicsLayer(this);
// add the graphics layer to the map
m_map->addLayer(m_graphicsLayer);
displaySampleWidget(m_mapGraphicsView);
// connect signals
connect(m_map, SIGNAL(mapReady()), this, SLOT(onMapReady()));
connect(m_map, SIGNAL(mousePress(QMouseEvent&)), this, SLOT(onMousePress(QMouseEvent&)));
connect(m_map, SIGNAL(mouseRelease(QMouseEvent&)), this, SLOT(onMouseRelease(QMouseEvent&)));
QPalette palette;
palette.setColor(QPalette::Window, Qt::white);
palette.setColor(QPalette::WindowText, Qt::black);
m_distanceLabel = new QLabel("Result will be displayed here.");
QFont font;
font.setPixelSize(11);
m_distanceLabel->setFont(font);
m_distanceLabel->setMargin(5);
m_distanceLabel->setAutoFillBackground(true);
m_distanceLabel->setPalette(palette);
WidgetPanel* widget = new WidgetPanel();
QLabel* instructionsLabel = new QLabel(
QString("This application measures the shortest distance between and polyline and a point.\n") +
QString("- Left-click to draw a polyline; double-click to end the polyline.\n") +
QString("- Then left-click to draw a point; this will measure the shortest distance to the polyline.\n") +
QString("- Right click to clear the polylines."));
instructionsLabel->setWordWrap(true);
instructionsLabel->setFont(font);
instructionsLabel->setFrameStyle(QFrame::WinPanel|QFrame::Sunken);
instructionsLabel->setMargin(5);
QVBoxLayout* layout = new QVBoxLayout();
layout->setMargin(0);
layout->addWidget(instructionsLabel);
layout->addWidget(m_distanceLabel);
widget->setFixedSize(315, 135);
widget->setLayout(layout);
widget->setPalette(QPalette(QPalette::Base));
QGraphicsProxyWidget *proxy = m_mapGraphicsView->scene()->addWidget(widget);
proxy->setPos(10, 10);
proxy->setFlag(QGraphicsItem::ItemIsSelectable, false);
proxy->setOpacity(0.675);
m_mouseHelper = new shortest_distance_mouse_helper(this);
m_mapGraphicsView->scene()->addItem(m_mouseHelper);
}
void shortest_distance_sample::onMapReady()
{
m_map->setExtent(EsriRuntimeQt::Envelope(-14321929, 2497898, -7339385, 6587123, m_map->spatialReference()));
}
void shortest_distance_sample::onMouseRelease(QMouseEvent& event)
{
if (m_doubleClick && !m_ignoredDoubleClickRelease)
{
m_ignoredDoubleClickRelease = true;
return;
}
QPoint scenePosition = event.pos();
// make sure the mouse didn't move - if so it was a pan so do nothing
if (m_lastMouseCoord.x() != scenePosition.x() || m_lastMouseCoord.y() != scenePosition.y())
return;
EsriRuntimeQt::Point mapPoint = m_map->toMapPoint(scenePosition.x(), scenePosition.y());
if (m_doubleClick)
{
shortestDistance(mapPoint);
return;
}
drawPoint(mapPoint);
drawLine(mapPoint);
}
void shortest_distance_sample::onMousePress(QMouseEvent& event)
{
// store the location of the left mouse click
if (event.button() == Qt::LeftButton)
{
m_lastMouseCoord = QPointF(event.pos().x(), event.pos().y());
return;
}
// clear the polylines on right-click
if (event.button() == Qt::RightButton)
reset();
}
void shortest_distance_sample::reset()
{
m_doubleClick = false;
m_shortestDistance = false;
m_pathBegan = false;
m_ignoredDoubleClickRelease = false;
m_graphicsLayer->removeAll();
m_polyline = EsriRuntimeQt::Polyline();
m_points.clear();
}
void shortest_distance_sample::drawPoint(const EsriRuntimeQt::Point& point)
{ // draw the current point
m_points.append(point);
m_graphicsLayer->addGraphic(new EsriRuntimeQt::Graphic(point, EsriRuntimeQt::SimpleMarkerSymbol(Qt::red, 7)));
}
void shortest_distance_sample::drawLine(const EsriRuntimeQt::Point& point)
{ // draws the line connected from the previously added point
if (!m_pathBegan)
{
m_pathBegan = true;
m_polyline.startPath(point);
m_polyLineGraphicId = m_graphicsLayer->addGraphic(new EsriRuntimeQt::Graphic(EsriRuntimeQt::Polyline(m_polyline),
EsriRuntimeQt::SimpleLineSymbol(Qt::red, 1)));
}
else
{
m_polyline.lineTo(point);
m_graphicsLayer->updateGraphic(m_polyLineGraphicId, new EsriRuntimeQt::Graphic(EsriRuntimeQt::Polyline(m_polyline),
EsriRuntimeQt::SimpleLineSymbol(Qt::red, 1)));
}
}
void shortest_distance_sample::shortestDistance(const EsriRuntimeQt::Point& point)
{
EsriRuntimeQt::Proximity2DResult nearestPointResult = EsriRuntimeQt::GeometryEngine::nearestCoordinate(m_polyline,point,false);
EsriRuntimeQt::Point nearestPointOnPolyline = nearestPointResult.coordinate();
EsriRuntimeQt::Polyline shortestPath;
shortestPath.startPath(point);
shortestPath.lineTo(nearestPointOnPolyline);
m_graphicsLayer->addGraphic(new EsriRuntimeQt::Graphic(point,
EsriRuntimeQt::SimpleMarkerSymbol(Qt::blue, 7,
EsriRuntimeQt::SimpleMarkerSymbolStyle::Circle)));
m_graphicsLayer->addGraphic(new EsriRuntimeQt::Graphic(nearestPointOnPolyline,
EsriRuntimeQt::SimpleMarkerSymbol(Qt::blue, 7,
EsriRuntimeQt::SimpleMarkerSymbolStyle::Circle)));
m_graphicsLayer->addGraphic(new EsriRuntimeQt::Graphic(shortestPath, EsriRuntimeQt::SimpleLineSymbol(Qt::blue, 1), this));
double distance = EsriRuntimeQt::GeometryEngine::geodesicLength(shortestPath,
new EsriRuntimeQt::LinearUnit(EsriRuntimeQt::LinearUnitCode::MileUS, this));
QString text = "Shortest distance: " + QString::number(distance) + " miles.";
m_distanceLabel->setText(text);
m_shortestDistance = true;
}
void shortest_distance_mouse_helper::mouseDoubleClickEvent (QGraphicsSceneMouseEvent *event)
{ // draw the final point
if (event->button() == Qt::LeftButton)
{
EsriRuntimeQt::Point mapPoint = m_sample->m_map->toMapPoint(event->scenePos().x(), event->scenePos().y());
m_sample->drawLine(mapPoint);
m_sample->m_doubleClick = true;
}
}