Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
@@ -0,0 +1,556 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AbstractGraphicalObject
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/GeoView.h>
|
||||
#include <arcgis/Graphic.h>
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/Multipart.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QDebug>
|
||||
#include <QSharedPointer>
|
||||
#include <QApplication>
|
||||
#include <QThread>
|
||||
#include <QObject>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
AbstractGraphicalObject::AbstractGraphicalObject(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: m_geoView(geoView)
|
||||
, m_graphicsLayer(graphicsLayer)
|
||||
, m_uniqueMapId(uniqueMapId)
|
||||
, m_debugInfo(debugInfo)
|
||||
, m_logger(getLogger("AbstractGraphicalObject"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
m_pickable = (m_uniqueMapId != INVALID_MAP_ID);
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
AbstractGraphicalObject::~AbstractGraphicalObject()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< ", m_graphicsLayer-overlayId=" << (m_graphicsLayer ? m_graphicsLayer->overlayId() : QString(QStringLiteral("unknown")));
|
||||
|
||||
#if ACRGIS_VERSION >= 0x640F00 // 100.15.0
|
||||
// removeOne ist helpful to let ModuleTest succeed: 'situationMapModuleTest checkOverlayHandler3 none'
|
||||
if (m_graphic && m_graphicsLayer && m_graphicsLayer->graphics())
|
||||
m_graphicsLayer->graphics()->removeOne(m_graphic);
|
||||
delete m_graphic;
|
||||
m_graphic = nullptr;
|
||||
#else
|
||||
|
||||
/*
|
||||
// cleanup
|
||||
// to make sure, the the graphic is removed from internal container BEFORE
|
||||
// graphic is deleted, follow the documentation: use Layer::removeGraphic
|
||||
// (instead 'delete m_graphic')
|
||||
if (m_graphic && m_graphicsLayer && m_graphicsLayer->graphics())
|
||||
m_graphicsLayer->graphics()->removeOne(m_graphic);
|
||||
|
||||
if (m_graphic)
|
||||
{
|
||||
delete m_graphic;
|
||||
m_graphic = nullptr;
|
||||
}
|
||||
*/
|
||||
|
||||
// Race condition between removeOne() and delete m_graphic :
|
||||
// BUG-000116867 is for the deadlock
|
||||
// BUG-000117464 is for the crash
|
||||
// Use following workaround until ESRI will release the fix (with 100.5!?)
|
||||
if (m_graphic && m_graphicsLayer && m_graphicsLayer->graphics())
|
||||
{
|
||||
const int idx = m_graphicsLayer->graphics()->indexOf(m_graphic);
|
||||
|
||||
if (idx < 0)
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " indexOf failed, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
auto graphicCopy = m_graphic;
|
||||
|
||||
QObject::connect (m_graphicsLayer->graphics(), &Esri::ArcGISRuntime::GraphicListModel::graphicRemoved,
|
||||
m_graphic, [idx, graphicCopy](int index)
|
||||
{
|
||||
if (idx == index)
|
||||
delete graphicCopy;
|
||||
});
|
||||
m_graphicsLayer->graphics()->removeOne(m_graphic);
|
||||
}
|
||||
// : Race condition between removeOne() and delete m_graphic
|
||||
|
||||
// m_esriSimpleLineSymbol AND m_esriSimpleFillSymbol will be destroyed m_graphic
|
||||
|
||||
#endif // ACRGIS_VERSION >= 0x640F00
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
Esri::ArcGISRuntime::Graphic *AbstractGraphicalObject::graphic()
|
||||
{
|
||||
return m_graphic;
|
||||
}
|
||||
|
||||
Esri::ArcGISRuntime::GraphicsOverlay *AbstractGraphicalObject::graphicsLayer()
|
||||
{
|
||||
return m_graphicsLayer;
|
||||
}
|
||||
|
||||
Esri::ArcGISRuntime::Geometry AbstractGraphicalObject::getGraphicGeometry() const
|
||||
{
|
||||
if (! m_graphic)
|
||||
return Esri::ArcGISRuntime::Geometry();
|
||||
return m_graphic->geometry();
|
||||
}
|
||||
|
||||
bool AbstractGraphicalObject::updateView()
|
||||
{
|
||||
if (!changed())
|
||||
return true;
|
||||
|
||||
bool success = updateViewImpl();
|
||||
resetChanged();
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
QString AbstractGraphicalObject::debugInfo() const
|
||||
{
|
||||
return m_debugInfo;
|
||||
}
|
||||
void AbstractGraphicalObject::setDebugInfo(const QString &debugInfo)
|
||||
{
|
||||
m_debugInfo = debugInfo;
|
||||
}
|
||||
|
||||
int AbstractGraphicalObject::drawOrder() const
|
||||
{
|
||||
return m_drawOrder.value();
|
||||
}
|
||||
void AbstractGraphicalObject::setDrawOrder(int drawOrder)
|
||||
{
|
||||
m_drawOrder = drawOrder;
|
||||
// if (m_graphic)
|
||||
// m_graphic->setDrawOrder(m_drawOrder.value());
|
||||
}
|
||||
|
||||
|
||||
QString AbstractGraphicalObject::toString() const
|
||||
{
|
||||
QString str;
|
||||
|
||||
if (!m_debugInfo.isEmpty())
|
||||
str.append(QStringLiteral("debugInfo=%1").arg(m_debugInfo));
|
||||
if (m_graphicsLayer)
|
||||
str.append(QStringLiteral(" layer='%1'").arg(m_graphicsLayer->objectName()));
|
||||
|
||||
str.append(QStringLiteral(" m_drawOrder='%1'").arg(m_drawOrder.value()));
|
||||
|
||||
if (m_graphic)
|
||||
str.append(QStringLiteral(" zIndex='%1'").arg(m_graphic->zIndex()));
|
||||
|
||||
str.append(QStringLiteral(" visibility='%1'").arg(m_visibility.value()));
|
||||
str.append(QStringLiteral(" selected='%1'").arg(m_selected.value()));
|
||||
|
||||
str.append(QStringLiteral(" scale='%1'").arg(m_scale.value()));
|
||||
str.append(QStringLiteral(" positions.count='%1'").arg(m_positions.value().count()));
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
UniqueMapId AbstractGraphicalObject::uniqueMapId() const
|
||||
{
|
||||
return m_uniqueMapId;
|
||||
}
|
||||
|
||||
void AbstractGraphicalObject::setUniqueMapId(UniqueMapId uniqueId)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId=" << uniqueId;
|
||||
|
||||
m_uniqueMapId = uniqueId;
|
||||
|
||||
// use attribute to store application obj id (SimWorld) at graphic
|
||||
if (m_graphic)
|
||||
{
|
||||
// use attributeModel to store application obj id (SimWorld) at graphic
|
||||
Esri::ArcGISRuntime::AttributeListModel *attListModel = m_graphic->attributes();
|
||||
if (attListModel)
|
||||
attListModel->insertAttribute(QLatin1String(SituationMap::UniqueMapIdAttribute), m_uniqueMapId);
|
||||
else
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no AttributeListModel, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId=" << m_uniqueMapId;
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId=" << uniqueId;
|
||||
}
|
||||
|
||||
Point3D AbstractGraphicalObject::origin() const
|
||||
{
|
||||
return m_positions.value().value(0); // value => if index is out of range -> default object
|
||||
}
|
||||
void AbstractGraphicalObject::setOrigin(const Point3D &origin)
|
||||
{
|
||||
// TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
// << " origin=" << origin;
|
||||
|
||||
if (m_positions.value().isEmpty())
|
||||
m_positions.refValue().append(origin);
|
||||
else
|
||||
{
|
||||
// https://stackoverflow.com/a/1573715/2352507
|
||||
// Any comparison(except with "!=") with NaN returns false.
|
||||
// NaN != NaN -> true!!!
|
||||
if (m_positions.value().value(0) != origin) // NaN != NaN -> true!!!
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " value(0) = " << m_positions.value().value(0) << " origin = " << origin;
|
||||
m_positions.refValue().clear();
|
||||
m_positions.refValue().append(origin);
|
||||
}
|
||||
}
|
||||
|
||||
// TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
// << " origin=" << origin
|
||||
// << " changed=" << m_positions.changed()
|
||||
// << " SIZE=" << m_positions.value().size();
|
||||
}
|
||||
|
||||
void AbstractGraphicalObject::setOrigin(const QPointF &origin)
|
||||
{
|
||||
setOrigin(Point3D(origin.x(), origin.y(), .0));
|
||||
}
|
||||
|
||||
PositionCont AbstractGraphicalObject::positions() const
|
||||
{
|
||||
return m_positions.value();
|
||||
}
|
||||
void AbstractGraphicalObject::setPositions(const PositionCont &posCont)
|
||||
{
|
||||
m_positions = posCont;
|
||||
|
||||
// TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
// << " changed=" << m_positions.changed();
|
||||
}
|
||||
|
||||
|
||||
bool AbstractGraphicalObject::isSinglePoint() const
|
||||
{
|
||||
return m_positions.value().count() == 1;
|
||||
}
|
||||
bool AbstractGraphicalObject::isMultiPoint() const
|
||||
{
|
||||
return m_positions.value().count() > 1;
|
||||
}
|
||||
bool AbstractGraphicalObject::isArea() const
|
||||
{
|
||||
return m_positions.value().count() > 2;
|
||||
}
|
||||
|
||||
LineStyle AbstractGraphicalObject::lineStyle() const
|
||||
{
|
||||
return m_lineStyle.value();
|
||||
}
|
||||
LineStyle &AbstractGraphicalObject::rLineStyle()
|
||||
{
|
||||
return m_lineStyle.refValue();
|
||||
}
|
||||
void AbstractGraphicalObject::setLineStyle(const LineStyle &lineStyle)
|
||||
{
|
||||
m_lineStyle = lineStyle;
|
||||
}
|
||||
|
||||
FillStyle AbstractGraphicalObject::fillStyle() const
|
||||
{
|
||||
return m_fillStyle.value();
|
||||
}
|
||||
FillStyle &AbstractGraphicalObject::rFillStyle()
|
||||
{
|
||||
return m_fillStyle.refValue();
|
||||
}
|
||||
void AbstractGraphicalObject::setFillStyle(const FillStyle &fillStyle)
|
||||
{
|
||||
m_fillStyle = fillStyle;
|
||||
}
|
||||
|
||||
|
||||
bool AbstractGraphicalObject::visibility() const
|
||||
{
|
||||
return m_visibility.value();
|
||||
}
|
||||
void AbstractGraphicalObject::setVisibility(bool visibility)
|
||||
{
|
||||
m_visibility = visibility;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " visibility=" << m_visibility;
|
||||
}
|
||||
|
||||
bool AbstractGraphicalObject::selected() const
|
||||
{
|
||||
return m_selected.value();
|
||||
}
|
||||
void AbstractGraphicalObject::setSelected(bool selected)
|
||||
{
|
||||
m_selected = selected;
|
||||
}
|
||||
|
||||
|
||||
bool AbstractGraphicalObject::pickable() const
|
||||
{
|
||||
return m_pickable.value();
|
||||
}
|
||||
void AbstractGraphicalObject::setPickable(bool pickable)
|
||||
{
|
||||
// allow pickable only if m_uniqueMapId is valid:
|
||||
m_pickable = pickable && (m_uniqueMapId != INVALID_MAP_ID);
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " pickable=" << m_pickable;
|
||||
}
|
||||
|
||||
|
||||
float AbstractGraphicalObject::scale() const
|
||||
{
|
||||
return m_scale.value();
|
||||
}
|
||||
void AbstractGraphicalObject::setScale(float scale)
|
||||
{
|
||||
m_scale = scale;
|
||||
}
|
||||
|
||||
|
||||
bool AbstractGraphicalObject::addUpdateGraphic()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " updateGraphic";
|
||||
|
||||
bool successGraphic = true;
|
||||
|
||||
if (! m_graphic)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " no m_graphic -> return true";
|
||||
return true;
|
||||
}
|
||||
|
||||
// append just once :-)
|
||||
if (! m_graphicsLayer->graphics()->contains(m_graphic))
|
||||
{
|
||||
m_graphicsLayer->graphics()->append(m_graphic);
|
||||
successGraphic = m_graphicsLayer->graphics()->contains(m_graphic);
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " successGraphic=" << successGraphic;
|
||||
return successGraphic;
|
||||
}
|
||||
|
||||
|
||||
bool AbstractGraphicalObject::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId =" << m_uniqueMapId
|
||||
<< " origin =" << this->origin()
|
||||
<< " visibility=" << m_visibility;
|
||||
bool success = true;
|
||||
|
||||
// some checks:
|
||||
if (!m_graphicsLayer)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " no graphicsLayer";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_graphic)
|
||||
{
|
||||
m_graphic = new Esri::ArcGISRuntime::Graphic();
|
||||
m_graphic->setObjectName(m_debugInfo);
|
||||
m_graphic->setZIndex(m_drawOrder.value());
|
||||
|
||||
// use attributeModel to store application obj id (SimWorld) at graphic
|
||||
Esri::ArcGISRuntime::AttributeListModel *attLisModel = m_graphic->attributes();
|
||||
if (attLisModel)
|
||||
attLisModel->insertAttribute(QLatin1String(SituationMap::UniqueMapIdAttribute), m_uniqueMapId);
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no AttributeListModel, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId=" << m_uniqueMapId;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success=" << success;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool AbstractGraphicalObject::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId=" << m_uniqueMapId
|
||||
<< " origin=" << this->origin()
|
||||
<< " visibility=" << m_visibility
|
||||
<< " selected=" << m_selected
|
||||
<< " drawOrder=" << m_drawOrder
|
||||
<< " pickable=" << m_pickable
|
||||
<< " pickableCHG=" << m_pickable.changed();
|
||||
|
||||
if (QApplication::instance()->thread()->currentThreadId() != QThread::currentThreadId())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " wrong Thread, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId=" << m_uniqueMapId;
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
if (m_graphic)
|
||||
{
|
||||
m_graphic->setZIndex(m_drawOrder.value());
|
||||
m_graphic->setVisible(m_visibility.value());
|
||||
m_graphic->setSelected(m_selected.value());
|
||||
|
||||
// Picking:
|
||||
if (m_pickable.changed())
|
||||
{
|
||||
// use attributeModel to store m_pickable at graphic
|
||||
Esri::ArcGISRuntime::AttributeListModel *attLisModel = m_graphic->attributes();
|
||||
if (attLisModel)
|
||||
attLisModel->insertAttribute(QLatin1String(SituationMap::IsPickableAttribute), m_pickable.value());
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no AttributeListModel, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId=" << m_uniqueMapId;
|
||||
}
|
||||
}
|
||||
m_pickable.reset();
|
||||
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " uniqueMapId =" << m_uniqueMapId;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AbstractGraphicalObject::assignLineStyleToGraphic()
|
||||
{
|
||||
if (!m_graphic)
|
||||
return false;
|
||||
|
||||
const LineStyle &ls = m_lineStyle.value();
|
||||
|
||||
if (!m_esriSimpleLineSymbol)
|
||||
{
|
||||
m_esriSimpleLineSymbol =
|
||||
new Esri::ArcGISRuntime::SimpleLineSymbol(convert(ls.linePattern()), ls.lineColor(), ls.lineWidth() * m_scale.value(), m_graphic);
|
||||
} else {
|
||||
m_esriSimpleLineSymbol->setStyle(convert(ls.linePattern()));
|
||||
m_esriSimpleLineSymbol->setColor(ls.lineColor());
|
||||
m_esriSimpleLineSymbol->setWidth(ls.lineWidth() * m_scale.value());
|
||||
}
|
||||
m_graphic->setSymbol(m_esriSimpleLineSymbol.data());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AbstractGraphicalObject::assignFillStyleToGraphic()
|
||||
{
|
||||
if (!m_graphic)
|
||||
return false;
|
||||
|
||||
const LineStyle &ls = m_lineStyle.value();
|
||||
const FillStyle &fs = m_fillStyle.value();
|
||||
|
||||
// 1. the Line
|
||||
if (!m_esriSimpleLineSymbol)
|
||||
{
|
||||
m_esriSimpleLineSymbol =
|
||||
new Esri::ArcGISRuntime::SimpleLineSymbol(convert(ls.linePattern()), ls.lineColor(), ls.lineWidth() * m_scale.value(), m_graphic);
|
||||
} else {
|
||||
m_esriSimpleLineSymbol->setStyle(convert(ls.linePattern()));
|
||||
m_esriSimpleLineSymbol->setColor(ls.lineColor());
|
||||
m_esriSimpleLineSymbol->setWidth(ls.lineWidth() * m_scale.value());
|
||||
}
|
||||
|
||||
// 1. the Fill
|
||||
if (!m_esriSimpleFillSymbol)
|
||||
{
|
||||
m_esriSimpleFillSymbol =
|
||||
new Esri::ArcGISRuntime::SimpleFillSymbol(convert(fs.fillPattern()), fs.fillColor(), m_esriSimpleLineSymbol, m_graphic);
|
||||
} else {
|
||||
m_esriSimpleFillSymbol->setStyle(convert(fs.fillPattern()));
|
||||
m_esriSimpleFillSymbol->setColor(fs.fillColor());
|
||||
m_esriSimpleFillSymbol->setOutline(m_esriSimpleLineSymbol);
|
||||
}
|
||||
m_graphic->setSymbol(m_esriSimpleFillSymbol.data());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Esri::ArcGISRuntime::SimpleLineSymbolStyle AbstractGraphicalObject::convert(const LinePattern linePattern)
|
||||
{
|
||||
switch (linePattern)
|
||||
{
|
||||
case LinePattern::Dash: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::Dash;
|
||||
case LinePattern::DashDot: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::DashDot;
|
||||
case LinePattern::DashDotDot: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::DashDotDot;
|
||||
case LinePattern::Dot: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::Dot;
|
||||
case LinePattern::Null: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::Null;
|
||||
case LinePattern::Solid: return Esri::ArcGISRuntime::SimpleLineSymbolStyle::Solid;
|
||||
} // switch
|
||||
|
||||
return Esri::ArcGISRuntime::SimpleLineSymbolStyle::Solid;
|
||||
}
|
||||
|
||||
|
||||
Esri::ArcGISRuntime::SimpleFillSymbolStyle AbstractGraphicalObject::convert(const FillPattern fillPattern)
|
||||
{
|
||||
switch (fillPattern)
|
||||
{
|
||||
case FillPattern::BackwardDiagonal: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::BackwardDiagonal;
|
||||
case FillPattern::Cross: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::Cross;
|
||||
case FillPattern::DiagonalCross: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::DiagonalCross;
|
||||
case FillPattern::ForwardDiagonal: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::ForwardDiagonal;
|
||||
case FillPattern::Horizontal: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::Horizontal;
|
||||
case FillPattern::Null: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::Null;
|
||||
case FillPattern::Solid: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::Solid;
|
||||
case FillPattern::Vertical: return Esri::ArcGISRuntime::SimpleFillSymbolStyle::Vertical;
|
||||
} // switch
|
||||
|
||||
return Esri::ArcGISRuntime::SimpleFillSymbolStyle::BackwardDiagonal;
|
||||
}
|
||||
|
||||
int AbstractGraphicalObject::countOfPolygonFirstPart(const Esri::ArcGISRuntime::Multipart &polylinePolygon)
|
||||
{
|
||||
if (polylinePolygon.isEmpty() || polylinePolygon.parts().isEmpty())
|
||||
return -1;
|
||||
|
||||
return polylinePolygon.parts().part(0).pointCount();
|
||||
}
|
||||
|
||||
|
||||
const Esri::ArcGISRuntime::SpatialReference AbstractGraphicalObject::spatialReference() const
|
||||
{
|
||||
return m_geoView->spatialReference();
|
||||
}
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,213 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AbstractGraphicalObject
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include <Map/situation_map_types.h>
|
||||
#include <Map/line_style.h>
|
||||
#include <Map/fill_style.h>
|
||||
#include <Common/simple_value.h>
|
||||
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/SimpleLineSymbol.h>
|
||||
#include <arcgis/SimpleFillSymbol.h>
|
||||
|
||||
// Qt
|
||||
#include <QPointer>
|
||||
|
||||
|
||||
// forward:
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class GeoView;
|
||||
class Graphic;
|
||||
class GraphicsOverlay;
|
||||
class Geometry;
|
||||
class Multipart;
|
||||
class SpatialReference;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
//forward
|
||||
class GraphicalObjectText;
|
||||
|
||||
|
||||
class SITUATIONMAP_EXPORT AbstractGraphicalObject
|
||||
{
|
||||
|
||||
public:
|
||||
AbstractGraphicalObject(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
virtual ~AbstractGraphicalObject();
|
||||
|
||||
AbstractGraphicalObject(const AbstractGraphicalObject &other) = delete;
|
||||
AbstractGraphicalObject &operator=(AbstractGraphicalObject &other) = delete;
|
||||
|
||||
virtual Esri::ArcGISRuntime::Graphic *graphic();
|
||||
virtual Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer();
|
||||
|
||||
virtual QString toString() const;
|
||||
|
||||
virtual UniqueMapId uniqueMapId() const;
|
||||
virtual void setUniqueMapId(UniqueMapId uniqueId);
|
||||
|
||||
virtual QString debugInfo() const;
|
||||
virtual void setDebugInfo(const QString &debugInfo);
|
||||
|
||||
virtual int drawOrder() const;
|
||||
virtual void setDrawOrder(int drawOrder);
|
||||
|
||||
// Data access:
|
||||
|
||||
// for SinglePoint:
|
||||
virtual Point3D origin() const;
|
||||
virtual void setOrigin(const Point3D &origin);
|
||||
virtual void setOrigin(const QPointF &origin); // ToDO accept this??
|
||||
|
||||
// for MultiPoint:
|
||||
virtual PositionCont positions() const;
|
||||
virtual void setPositions(const PositionCont &posCont);
|
||||
|
||||
virtual bool isSinglePoint() const;
|
||||
virtual bool isMultiPoint() const;
|
||||
virtual bool isArea() const;
|
||||
|
||||
virtual LineStyle lineStyle() const;
|
||||
virtual LineStyle &rLineStyle();
|
||||
/**
|
||||
* @brief setLineStyle (Font-)size is limited to 500.
|
||||
* (High values can lead to coredump with 'SymbolDrawHelper::create_line_image FAILED, SkBitmap is NULL or empty')
|
||||
* @param lineStyle to set.
|
||||
*/
|
||||
virtual void setLineStyle(const LineStyle &lineStyle);
|
||||
|
||||
virtual FillStyle fillStyle() const;
|
||||
virtual FillStyle &rFillStyle();
|
||||
virtual void setFillStyle(const FillStyle &fillStyle);
|
||||
|
||||
// Scale :
|
||||
virtual float scale() const;
|
||||
virtual void setScale(float scale);
|
||||
// : Scale
|
||||
|
||||
|
||||
// Visibility :
|
||||
virtual bool visibility() const;
|
||||
virtual void setVisibility(bool visibility);
|
||||
// : Visibility
|
||||
|
||||
// Selection, Picking :
|
||||
bool selected() const;
|
||||
void setSelected(bool selected);
|
||||
|
||||
bool pickable() const;
|
||||
/**
|
||||
* @brief setPickable The method allows pickable=true only if uniqueMapIdis valid.
|
||||
* @param pickable new value.
|
||||
*/
|
||||
void setPickable(bool pickable);
|
||||
// : Selection, Picking
|
||||
|
||||
|
||||
virtual Esri::ArcGISRuntime::Geometry getGraphicGeometry() const;
|
||||
|
||||
bool updateView();
|
||||
|
||||
bool addUpdateGraphic();
|
||||
|
||||
static Esri::ArcGISRuntime::SimpleLineSymbolStyle convert(const LinePattern linePattern);
|
||||
static Esri::ArcGISRuntime::SimpleFillSymbolStyle convert(const FillPattern fillPattern);
|
||||
|
||||
bool assignLineStyleToGraphic();
|
||||
bool assignFillStyleToGraphic();
|
||||
|
||||
|
||||
static int countOfPolygonFirstPart(const Esri::ArcGISRuntime::Multipart &polylinePolygon);
|
||||
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
const Esri::ArcGISRuntime::SpatialReference spatialReference() const;
|
||||
|
||||
virtual bool changed()
|
||||
{
|
||||
return m_drawOrder.changed()
|
||||
|| m_positions.changed()
|
||||
|| m_visibility.changed()
|
||||
|| m_selected.changed()
|
||||
|| m_pickable.changed()
|
||||
|| m_scale.changed()
|
||||
|| m_lineStyle.changed()
|
||||
|| m_fillStyle.changed();
|
||||
}
|
||||
|
||||
virtual bool updateViewImpl() = 0;
|
||||
|
||||
virtual void resetChanged()
|
||||
{
|
||||
m_drawOrder.reset();
|
||||
m_positions.reset();
|
||||
m_visibility.reset();
|
||||
m_selected.reset();
|
||||
m_pickable.reset();
|
||||
m_scale.reset();
|
||||
m_lineStyle.reset();
|
||||
m_fillStyle.reset();
|
||||
}
|
||||
|
||||
|
||||
virtual bool create() = 0;
|
||||
|
||||
|
||||
const Esri::ArcGISRuntime::GeoView *m_geoView = nullptr;
|
||||
Esri::ArcGISRuntime::GraphicsOverlay *m_graphicsLayer = nullptr;
|
||||
Esri::ArcGISRuntime::Graphic *m_graphic = nullptr;
|
||||
SimpleValue<int> m_drawOrder = 0;
|
||||
|
||||
// Data
|
||||
UniqueMapId m_uniqueMapId;
|
||||
|
||||
|
||||
QString m_debugInfo; ///< for debugging
|
||||
|
||||
SimpleValue<PositionCont> m_positions;
|
||||
|
||||
SimpleValue<bool> m_visibility = true;
|
||||
|
||||
SimpleValue<bool> m_selected = false;
|
||||
SimpleValue<bool> m_pickable = true;
|
||||
|
||||
SimpleValue<float> m_scale = 1.0;
|
||||
|
||||
SimpleValue<LineStyle> m_lineStyle;
|
||||
SimpleValue<FillStyle> m_fillStyle;
|
||||
QPointer<Esri::ArcGISRuntime::SimpleLineSymbol> m_esriSimpleLineSymbol = nullptr;
|
||||
QPointer<Esri::ArcGISRuntime::SimpleFillSymbol> m_esriSimpleFillSymbol = nullptr;
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* EllipseParameters
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "ellipse_parameters.h"
|
||||
|
||||
|
||||
// ESRI
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QString>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
float EllipseParameters::lengthX() const
|
||||
{
|
||||
return m_lengthX;
|
||||
}
|
||||
|
||||
void EllipseParameters::setLengthX(float lengthX)
|
||||
{
|
||||
m_lengthX = lengthX;
|
||||
}
|
||||
float EllipseParameters::lengthY() const
|
||||
{
|
||||
return m_lengthY;
|
||||
}
|
||||
|
||||
void EllipseParameters::setLengthY(float lengthY)
|
||||
{
|
||||
m_lengthY = lengthY;
|
||||
}
|
||||
float EllipseParameters::directionDegree() const
|
||||
{
|
||||
return m_directionDegree;
|
||||
}
|
||||
|
||||
void EllipseParameters::setDirectionDegree(float directionDegree)
|
||||
{
|
||||
m_directionDegree = directionDegree;
|
||||
}
|
||||
int EllipseParameters::maxSegmentLength() const
|
||||
{
|
||||
return m_maxSegmentLength;
|
||||
}
|
||||
|
||||
void EllipseParameters::setMaxSegmentLength(int value)
|
||||
{
|
||||
m_maxSegmentLength = value;
|
||||
}
|
||||
|
||||
int EllipseParameters::maxPointCount() const
|
||||
{
|
||||
return m_maxPointCount;
|
||||
}
|
||||
|
||||
void EllipseParameters::setMaxPointCount(int maxPointCount)
|
||||
{
|
||||
m_maxPointCount = maxPointCount;
|
||||
}
|
||||
|
||||
|
||||
bool EllipseParameters::isValid() const
|
||||
{
|
||||
return ((m_lengthX > 0) && (m_lengthY > 0)) ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::ostream &operator<< (std::ostream &stream,
|
||||
const EllipseParameters &value)
|
||||
{
|
||||
QString str;
|
||||
str.append(QStringLiteral(" lengthX=%1").arg(value.lengthX()));
|
||||
str.append(QStringLiteral(" lengthY=%1").arg(value.lengthY()));
|
||||
str.append(QStringLiteral(" directionDegree=%1").arg(value.directionDegree()));
|
||||
str.append(QStringLiteral(" maxSegmentLength=%1").arg(value.maxSegmentLength()));
|
||||
|
||||
stream << str.toStdString();
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* EllipseParameters
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include <situation_map_export.h>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class SITUATIONMAP_EXPORT EllipseParameters
|
||||
{
|
||||
public:
|
||||
|
||||
static constexpr unsigned int MAX_POINT_COUNT_DEFAULT = 30;
|
||||
|
||||
EllipseParameters() = default;
|
||||
|
||||
float lengthX() const;
|
||||
void setLengthX(float lengthX);
|
||||
|
||||
float lengthY() const;
|
||||
void setLengthY(float lengthY);
|
||||
|
||||
float directionDegree() const;
|
||||
void setDirectionDegree(float directionDegree);
|
||||
|
||||
int maxSegmentLength() const;
|
||||
void setMaxSegmentLength(int value);
|
||||
|
||||
int maxPointCount() const;
|
||||
void setMaxPointCount(int maxPointCount);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* @brief operator== Compare two objects
|
||||
* @param other to be compared with
|
||||
* @return true if identical, otherwise false.
|
||||
*/
|
||||
bool operator==(const EllipseParameters &other) const
|
||||
{
|
||||
return ((this->m_lengthX == other.m_lengthX) &&
|
||||
(this->m_lengthY == other.m_lengthY) &&
|
||||
(this->m_directionDegree == other.m_directionDegree) &&
|
||||
(this->m_maxSegmentLength == other.m_maxSegmentLength) &&
|
||||
(this->m_maxPointCount == other.m_maxPointCount)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief operator!= Compare two objects
|
||||
* @param other to be compared with
|
||||
* @return true if NOT identical, otherwise false.
|
||||
*/
|
||||
bool operator!=(const EllipseParameters &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
float m_lengthX = 0;
|
||||
float m_lengthY = 0;
|
||||
float m_directionDegree = 0;
|
||||
int m_maxSegmentLength = 10; // meter
|
||||
int m_maxPointCount = MAX_POINT_COUNT_DEFAULT;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
SITUATIONMAP_EXPORT std::ostream &operator<< (std::ostream &stream,
|
||||
const EllipseParameters &value);
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectAttributes
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_attributes.h"
|
||||
#include <MapImpl/map_impl.h>
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
#include <Common/simple_value.h>
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/Map.h>
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
class GraphicalObjectAttributes::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
~Private() = default;
|
||||
|
||||
// ESRI data:
|
||||
MapImpl *m_mapImpl = nullptr;
|
||||
QString m_logicalLayerName;
|
||||
|
||||
// OWN data:
|
||||
SimpleValue<QVariantMap> m_attributes;
|
||||
|
||||
}; // class GraphicalObjectAttributes::Private
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
GraphicalObjectAttributes::GraphicalObjectAttributes(MapImpl *mapImpl,
|
||||
Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer,
|
||||
const QString &debugInfo,
|
||||
const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(mapImpl->getEsriGeoView(), graphicsLayer, debugInfo, uniqueMapId),
|
||||
m_logger(getLogger("GraphicalObjectAttributes")),
|
||||
d(new Private)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectAttributes::~GraphicalObjectAttributes()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
delete d;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
bool GraphicalObjectAttributes::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_visibility = " << m_visibility;
|
||||
|
||||
bool success = BaseClass::create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
bool successGraphic = addUpdateGraphic(); // CHECK
|
||||
if (!successGraphic)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " addUpdateGraphic failed, debugInfo='" << m_debugInfo << "'" << " uniqueMapId=" << m_uniqueMapId;
|
||||
return false;
|
||||
}
|
||||
|
||||
// real work:
|
||||
// empty
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
return success;
|
||||
}
|
||||
|
||||
QVariantMap GraphicalObjectAttributes::attributes() const
|
||||
{
|
||||
return d->m_attributes.value();
|
||||
}
|
||||
|
||||
void GraphicalObjectAttributes::setAttributes(const QVariantMap &attributes)
|
||||
{
|
||||
d->m_attributes = attributes;
|
||||
}
|
||||
|
||||
bool GraphicalObjectAttributes::changed()
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| d->m_attributes.changed();
|
||||
}
|
||||
void GraphicalObjectAttributes::resetChanged()
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
d->m_attributes.reset();
|
||||
}
|
||||
|
||||
Esri::ArcGISRuntime::Geometry GraphicalObjectAttributes::getGraphicGeometry() const
|
||||
{
|
||||
if (m_graphic) return m_graphic->geometry();
|
||||
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Geometry is undefined";
|
||||
|
||||
return Esri::ArcGISRuntime::Geometry();
|
||||
} // Esri::ArcGISRuntime::Geometry GraphicalObjectAttributes::getGraphicGeometry() const
|
||||
|
||||
|
||||
bool GraphicalObjectAttributes::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " visibility=" << m_visibility
|
||||
<< " selected=" << m_selected
|
||||
<< " origin=" << this->origin()
|
||||
<< " scale=" << m_scale.value();
|
||||
|
||||
bool success = create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!BaseClass::updateViewImpl())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// real work:
|
||||
if (m_positions.changed())
|
||||
{
|
||||
const PositionCont &posCont = m_positions.value();
|
||||
if (posCont.size() == 1)
|
||||
{
|
||||
const Point3D &origin = this->origin();
|
||||
Esri::ArcGISRuntime::Point originGeometry(origin.x(),
|
||||
origin.y(),
|
||||
origin.z(),
|
||||
spatialReference());
|
||||
m_graphic->setGeometry(originGeometry);
|
||||
}
|
||||
}
|
||||
|
||||
if (d->m_attributes.changed())
|
||||
{
|
||||
QVariantMap rawAttributes = d->m_attributes.value();
|
||||
|
||||
// add basics:
|
||||
rawAttributes[QLatin1String(SituationMap::UniqueMapIdAttribute)] = m_uniqueMapId;
|
||||
rawAttributes[QLatin1String(SituationMap::IsPickableAttribute)] = m_pickable.value();
|
||||
m_graphic->attributes()->setAttributesMap(rawAttributes);
|
||||
|
||||
if (m_logger.isDebugEnabled())
|
||||
qCritical() << " XXXXX set rawAttributes " << rawAttributes;
|
||||
}
|
||||
|
||||
if (m_graphic)
|
||||
{
|
||||
m_graphic->setZIndex(m_drawOrder.value());
|
||||
m_graphic->setVisible(m_visibility.value());
|
||||
m_graphic->setSelected(m_selected.value());
|
||||
}
|
||||
|
||||
if (!success)
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " failure, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success = " << success
|
||||
<< " visibility=" << m_visibility;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectAttributes
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
// forward:
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
// forward:
|
||||
class MapImpl;
|
||||
|
||||
|
||||
/**
|
||||
* @brief The GraphicalObjectAttributes class
|
||||
*/
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectAttributes : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief GraphicalObjectAttributes
|
||||
* @param mapImpl map to be used.
|
||||
* @param logicalLayerName logical layer name to be used.
|
||||
* @param debugInfo debugInfo to be used
|
||||
* @param uniqueMapId uniqueMapId to be used. (Optional to fulfill rubberband requirements)
|
||||
*/
|
||||
GraphicalObjectAttributes(MapImpl *mapImpl,
|
||||
Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer,
|
||||
const QString &debugInfo,
|
||||
const UniqueMapId &uniqueMapId = INVALID_MAP_ID);
|
||||
|
||||
GraphicalObjectAttributes(const GraphicalObjectAttributes &other) = delete;
|
||||
GraphicalObjectAttributes &operator=(GraphicalObjectAttributes &other) = delete;
|
||||
|
||||
virtual ~GraphicalObjectAttributes();
|
||||
|
||||
|
||||
QVariantMap attributes() const;
|
||||
void setAttributes(const QVariantMap &attributes);
|
||||
|
||||
Esri::ArcGISRuntime::Geometry getGraphicGeometry() const override;
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
virtual bool create() override;
|
||||
|
||||
bool changed() override;
|
||||
void resetChanged() override;
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
// logical
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
class Private;
|
||||
/**
|
||||
* The private d-pointer to not break BC when changing internals of this class
|
||||
*/
|
||||
Private *d = nullptr;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectCube
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_cube.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/PolygonBuilder.h>
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
GraphicalObjectCube::GraphicalObjectCube(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_logger(getLogger("GraphicalObjectCube"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectCube::~GraphicalObjectCube()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
bool GraphicalObjectCube::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool success = BaseClass::create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
}
|
||||
|
||||
// real work:
|
||||
// empty
|
||||
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
// << " drawOrder = " << m_graphic->drawOrder()
|
||||
<< " success = " << success;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectCube::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
// some checks:
|
||||
if (!this->isArea())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!create())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!BaseClass::updateViewImpl())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
// real work:
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
|
||||
// Attribute 'height':
|
||||
QVariantMap attMap = m_graphic->attributes()->attributesMap();
|
||||
|
||||
attMap[QStringLiteral("height")] = QVariant(m_height.value());
|
||||
//
|
||||
// Attribute 'PartyName' is replaced by Attribute 'Extrusion_Color' to be more flexible
|
||||
//
|
||||
|
||||
|
||||
// Attribute 'Extrusion_Color':
|
||||
if (m_extrusionColorName.value().isEmpty())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||||
<< " debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_extrusionColorName is empty";
|
||||
// -> time for the defaultSymbol of the Renderer
|
||||
attMap[QStringLiteral("Extrusion_Color")] = QStringLiteral("DOES_NOT_EXIST");
|
||||
}
|
||||
else
|
||||
attMap[QStringLiteral("Extrusion_Color")] = QVariant(m_extrusionColorName.value());
|
||||
|
||||
m_graphic->attributes()->setAttributesMap(attMap);
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " attributesMap[height] ='" << attMap[QStringLiteral("height")].toDouble() << "'";
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " attributesMap[Extrusion_Color] ='" << attMap[QStringLiteral("Extrusion_Color")].toString() << "'";
|
||||
|
||||
// geometry:
|
||||
Esri::ArcGISRuntime::PolygonBuilder builder(spatialReference());
|
||||
|
||||
const PositionCont &posCont = m_positions.value();
|
||||
for (const Point3D &pos : posCont)
|
||||
{
|
||||
builder.addPoint(pos.x(), pos.y());
|
||||
}
|
||||
|
||||
if (! builder.isSketchValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " builder -> sketch invalid";
|
||||
return false;
|
||||
}
|
||||
m_graphic->setGeometry(builder.toGeometry());
|
||||
|
||||
|
||||
// add
|
||||
bool successGraphic = addUpdateGraphic();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " drawOrder = " << m_graphic->zIndex();
|
||||
return successGraphic;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::ostream &operator<<(std::ostream &stream,
|
||||
const GraphicalObjectCube &value)
|
||||
{
|
||||
stream << value.toString();
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectCube
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
// forward:
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The GraphicalObjectCube class for 3D
|
||||
*
|
||||
*/
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectCube : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
explicit GraphicalObjectCube(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectCube();
|
||||
|
||||
double height() const
|
||||
{
|
||||
return m_height.value();
|
||||
}
|
||||
void setHeight(double height)
|
||||
{
|
||||
m_height = height;
|
||||
}
|
||||
|
||||
const QString &extrusionColorName() const
|
||||
{
|
||||
return m_extrusionColorName.value();
|
||||
}
|
||||
void setExtrusionColorName(const QString &extrusionColorName)
|
||||
{
|
||||
m_extrusionColorName = extrusionColorName;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_height.changed()
|
||||
|| m_extrusionColorName.changed();
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_height.reset();
|
||||
m_extrusionColorName.reset();
|
||||
}
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
|
||||
// Data
|
||||
SimpleValue<double> m_height;
|
||||
SimpleValue<QString> m_extrusionColorName;
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
SITUATIONMAP_EXPORT std::ostream &operator<< (std::ostream &stream,
|
||||
const GraphicalObjectCube &value);
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectEllipse
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_ellipse.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/Polygon.h>
|
||||
#include <arcgis/GeometryEngine.h>
|
||||
#include <arcgis/SimpleLineSymbol.h>
|
||||
#include <arcgis/SimpleFillSymbol.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QElapsedTimer>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
GraphicalObjectEllipse::GraphicalObjectEllipse(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_logger(getLogger("GraphicalObjectEllipse"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectEllipse::~GraphicalObjectEllipse()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
delete m_internalParameters;
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
bool GraphicalObjectEllipse::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool success = BaseClass::create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
// real work:
|
||||
// empty
|
||||
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
// << " drawOrder = " << m_graphic->drawOrder()
|
||||
<< " success = " << success;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectEllipse::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
// some checks:
|
||||
if (!this->isSinglePoint())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!create())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!BaseClass::updateViewImpl())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_ellipseParameters.value().isValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " ellipseParameters not valid";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// real work:
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " update geometry";
|
||||
|
||||
bool successEllipse = true;
|
||||
if (m_ellipseParameters.changed() || m_positions.changed())
|
||||
{
|
||||
// apply attributes:
|
||||
parameterToInternal();
|
||||
|
||||
Esri::ArcGISRuntime::Polygon ellipse;
|
||||
successEllipse = createEllipse(ellipse);
|
||||
if (successEllipse)
|
||||
m_graphic->setGeometry(ellipse);
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " createEllipse failed";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
assignFillStyleToGraphic();
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool successGraphic = addUpdateGraphic();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " drawOrder = " << m_graphic->zIndex()
|
||||
<< " successEllipse = " << successEllipse
|
||||
<< " successGraphic = " << successGraphic;
|
||||
return successEllipse && successGraphic;
|
||||
}
|
||||
|
||||
void GraphicalObjectEllipse::parameterToInternal()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
if (!m_internalParameters)
|
||||
{
|
||||
m_internalParameters = new Esri::ArcGISRuntime::GeodesicEllipseParameters();
|
||||
m_internalParameters->setGeometryType(Esri::ArcGISRuntime::GeometryType::Polygon);
|
||||
}
|
||||
|
||||
// TODO !!??: set xy correct, calc maxSegLength...
|
||||
|
||||
|
||||
const EllipseParameters &ellipseParameterRef = m_ellipseParameters.value();
|
||||
|
||||
// 1a, 1b
|
||||
m_internalParameters->setMaxSegmentLength(ellipseParameterRef.maxSegmentLength());
|
||||
m_internalParameters->setMaxPointCount(ellipseParameterRef.maxPointCount());
|
||||
|
||||
// 2
|
||||
const Point3D &origin = this->origin();
|
||||
Esri::ArcGISRuntime::Point mapPoint(origin.x(), origin.y(), origin.z(), spatialReference()); // center of ellipse
|
||||
|
||||
Esri::ArcGISRuntime::Point normalizedPt =
|
||||
Esri::ArcGISRuntime::GeometryEngine::normalizeCentralMeridian(mapPoint);
|
||||
m_internalParameters->setCenter(normalizedPt);
|
||||
// m_internalParameters->setCenter(mapPoint);
|
||||
|
||||
// 3, 4
|
||||
m_internalParameters->setSemiAxis1Length(ellipseParameterRef.lengthX());
|
||||
m_internalParameters->setSemiAxis2Length(ellipseParameterRef.lengthY());
|
||||
|
||||
// 5
|
||||
m_internalParameters->setAxisDirection(ellipseParameterRef.directionDegree());
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
bool GraphicalObjectEllipse::createEllipse(Esri::ArcGISRuntime::Polygon &ellipse)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool success = createEllipsePolygon(*m_internalParameters, ellipse);
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success = " << success
|
||||
// << " pointCount = " << ellipse.pointCount()
|
||||
<< " dimension = " << ellipse.dimension();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GraphicalObjectEllipse::createEllipsePolygon(const Esri::ArcGISRuntime::GeodesicEllipseParameters &ellipseParameters,
|
||||
Esri::ArcGISRuntime::Polygon &polygon)
|
||||
{
|
||||
LOGGER_T m_logger = getLogger("GraphicalObjectEllipse");
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
QElapsedTimer timer;
|
||||
|
||||
if (m_logger.isInfoEnabled())
|
||||
timer.start();
|
||||
|
||||
|
||||
bool success = false;
|
||||
|
||||
Esri::ArcGISRuntime::Geometry ellipseGeometry =
|
||||
Esri::ArcGISRuntime::GeometryEngine::ellipseGeodesic(ellipseParameters);
|
||||
if (ellipseGeometry.isEmpty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " There was an error computing the geodesic ellipse. Try a different segment length.";
|
||||
}
|
||||
else
|
||||
{
|
||||
polygon = Esri::ArcGISRuntime::Polygon(ellipseGeometry);
|
||||
success = true;
|
||||
}
|
||||
int count = AbstractGraphicalObject::countOfPolygonFirstPart(polygon);
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||||
<< " count=" << count
|
||||
<< " (semiAxis1Length=" << ellipseParameters.semiAxis1Length()
|
||||
<< " , semiAxis2Length=" << ellipseParameters.semiAxis2Length()
|
||||
<< " , maxPointCount=" << ellipseParameters.maxPointCount()
|
||||
<< " , maxSegmentLength=" << ellipseParameters.maxSegmentLength()
|
||||
<< " , dimension = " << polygon.dimension()
|
||||
<< ")";
|
||||
|
||||
|
||||
|
||||
if (m_logger.isDebugEnabled())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||||
<< " took " << timer.elapsed() << "ms"
|
||||
<< " (semiAxis1Length=" << ellipseParameters.semiAxis1Length()
|
||||
<< " , semiAxis2Length=" << ellipseParameters.semiAxis2Length()
|
||||
<< " , maxPointCount=" << ellipseParameters.maxPointCount()
|
||||
<< " , maxSegmentLength=" << ellipseParameters.maxSegmentLength()
|
||||
<< " , dimension = " << polygon.dimension()
|
||||
<< ")";
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END"
|
||||
<< " success = " << success;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GraphicalObjectEllipse::createCirclePolygon(const Esri::ArcGISRuntime::Point &originMap,
|
||||
float radius,
|
||||
unsigned int maxPointCount,
|
||||
Esri::ArcGISRuntime::Polygon &polygon)
|
||||
{
|
||||
LOGGER_T m_logger = getLogger("GraphicalObjectEllipse");
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||||
<< " origin=" << originMap.x() << " ; " << originMap.y() << " ; " << originMap.z()
|
||||
<< " radius=" << radius;
|
||||
|
||||
Esri::ArcGISRuntime::GeodesicEllipseParameters ePara;
|
||||
ePara.setGeometryType(Esri::ArcGISRuntime::GeometryType::Polygon);
|
||||
|
||||
// 1
|
||||
ePara.setMaxSegmentLength(10);
|
||||
if (maxPointCount == 0)
|
||||
ePara.setMaxPointCount(EllipseParameters::MAX_POINT_COUNT_DEFAULT);
|
||||
else
|
||||
ePara.setMaxPointCount(maxPointCount);
|
||||
|
||||
// 2
|
||||
const Esri::ArcGISRuntime::Point &mapPoint = originMap; // center of ellipse
|
||||
|
||||
Esri::ArcGISRuntime::Point normalizedPt =
|
||||
Esri::ArcGISRuntime::GeometryEngine::normalizeCentralMeridian(mapPoint);
|
||||
ePara.setCenter(normalizedPt);
|
||||
|
||||
// 3, 4
|
||||
ePara.setSemiAxis1Length(radius);
|
||||
ePara.setSemiAxis2Length(radius);
|
||||
|
||||
// 5
|
||||
ePara.setAxisDirection(0);
|
||||
|
||||
return createEllipsePolygon(ePara, polygon);
|
||||
}
|
||||
|
||||
bool GraphicalObjectEllipse::createCirclePolygon(const Esri::ArcGISRuntime::Point &originMap,
|
||||
float radius,
|
||||
unsigned int maxPointCount,
|
||||
PositionCont &posCont)
|
||||
{
|
||||
Esri::ArcGISRuntime::Polygon circle;
|
||||
bool success = GraphicalObjectEllipse::createCirclePolygon(originMap,
|
||||
radius,
|
||||
maxPointCount,
|
||||
circle);
|
||||
|
||||
if (success && !circle.isEmpty())
|
||||
{
|
||||
posCont.clear();
|
||||
|
||||
const Esri::ArcGISRuntime::ImmutablePart &immutablePart = circle.parts().part(0);
|
||||
const int size = immutablePart.pointCount();
|
||||
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
const Esri::ArcGISRuntime::Point &p = immutablePart.point(i);
|
||||
posCont.append(Point3D(p.x(), p.y(), p.z()));
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
EllipseParameters GraphicalObjectEllipse::ellipseParameters() const
|
||||
{
|
||||
return m_ellipseParameters.value();
|
||||
}
|
||||
|
||||
EllipseParameters &GraphicalObjectEllipse::rEllipseParameters()
|
||||
{
|
||||
return m_ellipseParameters.refValue();
|
||||
}
|
||||
|
||||
void GraphicalObjectEllipse::setEllipseParameters(const EllipseParameters &ellipseParameters)
|
||||
{
|
||||
m_ellipseParameters = ellipseParameters;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::ostream &operator<<(std::ostream &stream,
|
||||
const GraphicalObjectEllipse &value)
|
||||
{
|
||||
stream << value.toString();
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectEllipse
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
#include "ellipse_parameters.h"
|
||||
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
// forward:
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class Polygon;
|
||||
class Point;
|
||||
class GeodesicEllipseParameters;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectEllipse : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
GraphicalObjectEllipse(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectEllipse();
|
||||
|
||||
EllipseParameters ellipseParameters() const;
|
||||
EllipseParameters &rEllipseParameters();
|
||||
void setEllipseParameters(const EllipseParameters &ellipseParameters);
|
||||
|
||||
|
||||
static bool createEllipsePolygon(const Esri::ArcGISRuntime::GeodesicEllipseParameters &ellipseParameters,
|
||||
Esri::ArcGISRuntime::Polygon &polygon);
|
||||
|
||||
static bool createCirclePolygon(const Esri::ArcGISRuntime::Point &originMap,
|
||||
float radius,
|
||||
unsigned int maxPointCount,
|
||||
Esri::ArcGISRuntime::Polygon &polygon);
|
||||
|
||||
static bool createCirclePolygon(const Esri::ArcGISRuntime::Point &originMap,
|
||||
float radius,
|
||||
unsigned int maxPointCount,
|
||||
PositionCont &posCont);
|
||||
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_ellipseParameters.changed();
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_ellipseParameters.reset();
|
||||
}
|
||||
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
|
||||
// Data
|
||||
Esri::ArcGISRuntime::GeodesicEllipseParameters *m_internalParameters = nullptr;
|
||||
SimpleValue<EllipseParameters> m_ellipseParameters;
|
||||
|
||||
void parameterToInternal();
|
||||
virtual bool createEllipse(Esri::ArcGISRuntime::Polygon &ellipse);
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
// Forbid some overloaded methods without effects of this object;
|
||||
virtual PositionCont positions() const override
|
||||
{
|
||||
return PositionCont();
|
||||
}
|
||||
virtual void setPositions(const PositionCont &posCont) override
|
||||
{
|
||||
Q_UNUSED(posCont);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::ostream &operator<< (std::ostream &stream,
|
||||
const GraphicalObjectEllipse &value);
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectModelSceneMarker
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_model_scene_marker.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
#include <MathUtils/simple_helper.h>
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/ModelSceneSymbol.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QPainter>
|
||||
#include <QFile>
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
GraphicalObjectModelSceneMarker::GraphicalObjectModelSceneMarker(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_logger(getLogger("GraphicalObjectModelSceneMarker"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectModelSceneMarker::~GraphicalObjectModelSceneMarker()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
delete m_modelSceneSymbol;
|
||||
m_modelSceneSymbol = nullptr;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectModelSceneMarker::setUrl(const QUrl &url)
|
||||
{
|
||||
m_url = url;
|
||||
}
|
||||
|
||||
QUrl GraphicalObjectModelSceneMarker::url() const
|
||||
{
|
||||
return m_url.value();
|
||||
}
|
||||
|
||||
void GraphicalObjectModelSceneMarker::setHeading(float heading)
|
||||
{
|
||||
m_heading = heading;
|
||||
}
|
||||
|
||||
float GraphicalObjectModelSceneMarker::heading() const
|
||||
{
|
||||
return m_heading.value();
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectModelSceneMarker::create()
|
||||
{
|
||||
return BaseClass::create();
|
||||
}
|
||||
|
||||
bool GraphicalObjectModelSceneMarker::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " origin =" << this->origin() // .x() << " , " << this->origin().y()
|
||||
<< " visibility=" << m_visibility
|
||||
<< " pickable=" << m_pickable
|
||||
<< " pickable.changed=" << m_pickable.changed()
|
||||
<< " selected=" << m_selected
|
||||
<< " m_url = " << m_url.value().toString()
|
||||
<< " m_drawOrder = " << m_drawOrder
|
||||
<< " m_scale = " << m_scale.value()
|
||||
<< " m_heading = " << m_heading.value();
|
||||
|
||||
// some checks:
|
||||
if (!isSinglePoint())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " debugInfo='" << m_debugInfo << "'"
|
||||
<< " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile fi(m_url.value().path());
|
||||
if (!fi.exists())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_url does not exists: '" << fi.fileName() << "'";
|
||||
m_url.reset();
|
||||
}
|
||||
|
||||
if (m_url.value().isEmpty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " debugInfo='" << m_debugInfo << "'"
|
||||
<< " no url provided (or does not exist)";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
const Point3D &origin = this->origin();
|
||||
Esri::ArcGISRuntime::Point originGeometry(origin.x(),
|
||||
origin.y(),
|
||||
origin.z(),
|
||||
spatialReference());
|
||||
m_graphic->setGeometry(originGeometry);
|
||||
|
||||
// url changed?
|
||||
if ( (m_modelSceneSymbol && (m_modelSceneSymbol->url() != m_url.value())) ||
|
||||
m_scale.changed())
|
||||
{
|
||||
// force re-create ModelSceneSymbol:
|
||||
delete m_modelSceneSymbol;
|
||||
m_modelSceneSymbol = nullptr;
|
||||
}
|
||||
|
||||
if (!m_modelSceneSymbol)
|
||||
{
|
||||
m_modelSceneSymbol = new Esri::ArcGISRuntime::ModelSceneSymbol(m_url.value(), m_scale.value()); // url, scale
|
||||
}
|
||||
|
||||
m_modelSceneSymbol->setHeading(m_heading.value()); // degree, clockwise, 0 is north/12
|
||||
// m_modelSceneSymbol->setAnchorPosition(Esri::ArcGISRuntime::SceneSymbolAnchorPosition::Bottom);
|
||||
m_graphic->setSymbol(m_modelSceneSymbol);
|
||||
|
||||
|
||||
|
||||
success = BaseClass::updateViewImpl();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
success = addUpdateGraphic();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success=" << success
|
||||
<< " m_drawOrder = " << m_drawOrder
|
||||
<< " m_graphic->drawOrder = " << m_graphic->zIndex();
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace SituationMap
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectModelSceneMarker
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
#include <Map/text_style.h>
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
|
||||
// Esri
|
||||
#include <arcgis/SymbolTypes.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QImage>
|
||||
#include <QUrl>
|
||||
|
||||
|
||||
// forward:
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class Graphic;
|
||||
class GraphicsOverlay;
|
||||
class ModelSceneSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectModelSceneMarker : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
GraphicalObjectModelSceneMarker(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectModelSceneMarker();
|
||||
|
||||
// Data access:
|
||||
// to be cont.
|
||||
void setUrl(const QUrl &url);
|
||||
QUrl url() const;
|
||||
|
||||
// degree ; 0 is north/12
|
||||
void setHeading(float heading);
|
||||
float heading() const;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_url.changed()
|
||||
|| m_heading.changed()
|
||||
;
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_url.reset();
|
||||
m_heading.reset();
|
||||
}
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
// used ModelSceneSymbol:
|
||||
Esri::ArcGISRuntime::ModelSceneSymbol *m_modelSceneSymbol{nullptr};
|
||||
|
||||
SimpleValue<QUrl> m_url; // e.g. /shd/CTC/TOOLS/ArcGIS/Runtime/Data/3D/Bristol/Collada/Bristol.dae
|
||||
SimpleValue<float> m_heading{0.0}; // degree, clockwise, 0 is north/12
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
// Forbid some overloaded methods without effects of this object;
|
||||
PositionCont positions() const override
|
||||
{
|
||||
return PositionCont();
|
||||
}
|
||||
void setPositions(const PositionCont &posCont) override
|
||||
{
|
||||
Q_UNUSED(posCont);
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,323 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectPath
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_multi_path.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/PolygonBuilder.h>
|
||||
#include <arcgis/PolylineBuilder.h>
|
||||
#include <arcgis/SimpleLineSymbol.h>
|
||||
#include <arcgis/SimpleFillSymbol.h>
|
||||
#include <arcgis/GeoView.h>
|
||||
#include <arcgis/GeometryEngine.h>
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
GraphicalObjectMultiPath::GraphicalObjectMultiPath(const GraphicalObjectPathType type
|
||||
, const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, UniqueMapId uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_pathType(type)
|
||||
, m_logger(getLogger("GraphicalObjectMultiPath"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
}
|
||||
|
||||
GraphicalObjectMultiPath::~GraphicalObjectMultiPath()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
}
|
||||
|
||||
PositionCont GraphicalObjectMultiPath::path(int pathIndex) const
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " pathIndex=" << pathIndex;
|
||||
if (hasPosCont(pathIndex))
|
||||
return getPosCont(pathIndex).value();
|
||||
return {};
|
||||
}
|
||||
void GraphicalObjectMultiPath::setPath(int pathIndex, const PositionCont &positions)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " pathIndex=" << pathIndex
|
||||
<< " positions=" << positions;
|
||||
m_positionsCont[pathIndex] = positions;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectMultiPath::clearPath(int pathIndex)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " pathIndex=" << pathIndex;
|
||||
if (pathIndex == -1)
|
||||
{
|
||||
m_positions.refValue().clear();
|
||||
m_positionsCont.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasPosCont(pathIndex))
|
||||
{
|
||||
// Do not remove the whole entry to let changed() work
|
||||
m_positionsCont[pathIndex].refValue().clear();
|
||||
}
|
||||
}
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectMultiPath::clearAllPaths()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
m_positions.refValue().clear();
|
||||
m_positionsCont.clear();
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectMultiPath::reduceTo(const QList<int> &remainingPathIndexes)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " remainingPathIndexes=" << remainingPathIndexes;
|
||||
QList<int> keys = m_positionsCont.keys();
|
||||
for (int key : qAsConst(keys))
|
||||
{
|
||||
if (!remainingPathIndexes.contains(key))
|
||||
{
|
||||
// Do not remove the whole entry to let chanded() work
|
||||
m_positionsCont[key].refValue().clear();
|
||||
}
|
||||
}
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
QList<int> GraphicalObjectMultiPath::pathIndexInUse()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
QList<int> ret;
|
||||
///// ret << 0; // pathIndex=0 -> m_positions
|
||||
|
||||
QMapIterator<int, SimpleValue<PositionCont> > mapIt(m_positionsCont);
|
||||
while (mapIt.hasNext())
|
||||
{
|
||||
mapIt.next();
|
||||
const SimpleValue<PositionCont> &posData = mapIt.value();
|
||||
const PositionCont &posCont = posData.value();
|
||||
if (! posCont.isEmpty())
|
||||
ret += mapIt.key();
|
||||
} // while
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectMultiPath::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool success = BaseClass::create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectMultiPath::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool success = create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
success = BaseClass::updateViewImpl();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
success = updatePositions();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success = " << success
|
||||
<< " drawOrder = " << m_graphic->zIndex();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GraphicalObjectMultiPath::updatePositions()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool success = true;
|
||||
|
||||
int pathIdxToInsert = 0;
|
||||
const int minPoints = this->pathType() == GraphicalObjectPathType::Polyline ? 2 : 3;
|
||||
|
||||
QSharedPointer<Esri::ArcGISRuntime::MultipartBuilder> builder;
|
||||
|
||||
// some preparations: ( do no check isMultiPoint / isArea: m_positions should typically be empty!!!
|
||||
switch (m_pathType)
|
||||
{
|
||||
case GraphicalObjectPathType::Polyline:
|
||||
builder = QSharedPointer<Esri::ArcGISRuntime::PolylineBuilder>(new Esri::ArcGISRuntime::PolylineBuilder(spatialReference()));
|
||||
|
||||
break;
|
||||
case GraphicalObjectPathType::Polygon:
|
||||
builder = QSharedPointer<Esri::ArcGISRuntime::PolygonBuilder>(new Esri::ArcGISRuntime::PolygonBuilder(spatialReference()));
|
||||
break;
|
||||
} // switch
|
||||
|
||||
QSharedPointer<Esri::ArcGISRuntime::PartCollection> partCollection =
|
||||
QSharedPointer<Esri::ArcGISRuntime::PartCollection>(new Esri::ArcGISRuntime::PartCollection(builder->spatialReference()));
|
||||
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< ", m_positionsCont.size() /#rings=" << m_positionsCont.size();
|
||||
|
||||
QMutableMapIterator<int, SimpleValue<PositionCont> > mapIt(m_positionsCont);
|
||||
//
|
||||
// LOOP PER SINGLE POLY
|
||||
//
|
||||
while (mapIt.hasNext())
|
||||
{
|
||||
mapIt.next();
|
||||
const int key = mapIt.key();
|
||||
|
||||
const SimpleValue<PositionCont> &posData = mapIt.value();
|
||||
const PositionCont &posCont = posData.value();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< ", key / #ring=" << key
|
||||
<< ", rings.size()=" << posCont.size();
|
||||
|
||||
// maybe some pathIdx are cleared by clearPath() or similar:
|
||||
if (posCont.isEmpty())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||||
<< " posCont empty, cleared? -> remove/cleanup"
|
||||
<< " pathIdxToInsert = " << pathIdxToInsert
|
||||
<< " mapIt.key() = " << key;
|
||||
mapIt.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (posCont.count() < minPoints)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " incorrect number of positions"
|
||||
<< " (" << posCont.count() << ")"
|
||||
<< ", minPoints=" << minPoints
|
||||
<< ", pathIdxToInsert = " << pathIdxToInsert
|
||||
<< ", mapIt.key() = " << key
|
||||
<< ", m_debugInfo = " << m_debugInfo;
|
||||
|
||||
success = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Esri::ArcGISRuntime::Part part(builder->spatialReference());
|
||||
|
||||
//
|
||||
// LOOP PER POINT
|
||||
//
|
||||
for (auto pos : qAsConst(posCont))
|
||||
{
|
||||
part.addPoint(pos.x(), pos.y(), pos.z());
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< ", key / #ring=" << key
|
||||
<< ", addPoint=" << pos;
|
||||
|
||||
}
|
||||
|
||||
partCollection->addPart(&part);
|
||||
} // if (posCont.count() < minPoints)
|
||||
|
||||
} // while
|
||||
|
||||
builder->setParts(partCollection.get());
|
||||
|
||||
//
|
||||
// builder to geometry;
|
||||
//
|
||||
switch (m_pathType)
|
||||
{
|
||||
case GraphicalObjectPathType::Polyline:
|
||||
{
|
||||
const Esri::ArcGISRuntime::Polyline &multipartPolyline =
|
||||
static_cast<Esri::ArcGISRuntime::PolylineBuilder *>(builder.data())->toPolyline();
|
||||
m_graphic->setGeometry(multipartPolyline);
|
||||
assignLineStyleToGraphic();
|
||||
}
|
||||
break;
|
||||
case GraphicalObjectPathType::Polygon:
|
||||
{
|
||||
const Esri::ArcGISRuntime::Polygon &multipartPolygon =
|
||||
static_cast<Esri::ArcGISRuntime::PolygonBuilder *>(builder.data())->toPolygon();
|
||||
m_graphic->setGeometry(multipartPolygon);
|
||||
//assignLineStyleToGraphic();
|
||||
assignFillStyleToGraphic();
|
||||
}
|
||||
break;
|
||||
} // switch
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'";
|
||||
success = addUpdateGraphic();
|
||||
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success = " << success
|
||||
<< " drawOrder = " << m_graphic->zIndex();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GraphicalObjectMultiPath::hasPosCont(int idx) const
|
||||
{
|
||||
return m_positionsCont.contains(idx);
|
||||
}
|
||||
|
||||
SimpleValue<PositionCont> &GraphicalObjectMultiPath::getPosCont(int idx)
|
||||
{
|
||||
return m_positionsCont[idx];
|
||||
}
|
||||
|
||||
const SimpleValue<PositionCont> GraphicalObjectMultiPath::getPosCont(int idx) const
|
||||
{
|
||||
return m_positionsCont[idx];
|
||||
}
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectPath
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "graphical_object_path.h"
|
||||
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QMap>
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectMultiPath : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
|
||||
GraphicalObjectMultiPath(const GraphicalObjectPathType type
|
||||
, const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, UniqueMapId uniqueMapId);
|
||||
|
||||
~GraphicalObjectMultiPath();
|
||||
|
||||
GraphicalObjectPathType pathType() const
|
||||
{
|
||||
return m_pathType;
|
||||
}
|
||||
|
||||
virtual PositionCont path(int pathIndex) const;
|
||||
virtual void setPath(int pathIndex, const PositionCont &positions);
|
||||
|
||||
/*! \name Subsidiary polyline/polygons */
|
||||
//@{
|
||||
virtual void clearPath(int pathIndex);
|
||||
virtual void clearAllPaths();
|
||||
virtual QList<int> pathIndexInUse();
|
||||
virtual void reduceTo(const QList<int> &remainingPathIndexes);
|
||||
//@}
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
bool updatePositions();
|
||||
bool changed() override
|
||||
{
|
||||
bool baseClassChanged = BaseClass::changed();
|
||||
if (baseClassChanged)
|
||||
return true;
|
||||
|
||||
for (const SimpleValue<PositionCont> &posData : qAsConst(m_positionsCont))
|
||||
{
|
||||
if (posData.changed())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
|
||||
for (SimpleValue<PositionCont> &posData : m_positionsCont)
|
||||
posData.reset();
|
||||
}
|
||||
|
||||
bool create() override;
|
||||
bool updateViewImpl() override;
|
||||
|
||||
// logical
|
||||
const GraphicalObjectPathType m_pathType;
|
||||
//bool updatePositions();
|
||||
|
||||
private:
|
||||
// Attention: will contain 'positions' of idx == 1 and higher :
|
||||
bool hasPosCont(int idx) const;
|
||||
SimpleValue<PositionCont> &getPosCont(int idx);
|
||||
const SimpleValue<PositionCont> getPosCont(int idx) const;
|
||||
|
||||
QMap<int, SimpleValue<PositionCont> > m_positionsCont;
|
||||
// : Attention: will contain 'positions' of idx == 1 and higher
|
||||
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectPath
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_path.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/PolygonBuilder.h>
|
||||
#include <arcgis/PolylineBuilder.h>
|
||||
#include <arcgis/SimpleLineSymbol.h>
|
||||
#include <arcgis/SimpleFillSymbol.h>
|
||||
#include <arcgis/GeoView.h>
|
||||
#include <arcgis/GeometryEngine.h>
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
QLatin1String toString(const GraphicalObjectPathType subType)
|
||||
{
|
||||
switch (subType)
|
||||
{
|
||||
case GraphicalObjectPathType::Polyline:
|
||||
return QLatin1String("Polyline");
|
||||
break;
|
||||
case GraphicalObjectPathType::Polygon:
|
||||
return QLatin1String("Polygon");
|
||||
break;
|
||||
} // switch
|
||||
return QLatin1String("GraphicalObjectPathTypeERROR");
|
||||
}
|
||||
|
||||
|
||||
GraphicalObjectPath::GraphicalObjectPath(const GraphicalObjectPathType type
|
||||
, const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_pathType(type)
|
||||
, m_logger(getLogger("GraphicalObjectPath"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
}
|
||||
|
||||
GraphicalObjectPath::~GraphicalObjectPath()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_pathType=" << m_pathType;
|
||||
}
|
||||
|
||||
bool GraphicalObjectPath::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
bool success = BaseClass::create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success = " << success
|
||||
// << " drawOrder = " << m_graphic->drawOrder()
|
||||
;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectPath::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_positions= " << m_positions.value()
|
||||
<< ", m_maxSegmentLength=" << m_maxSegmentLength;
|
||||
|
||||
QSharedPointer<Esri::ArcGISRuntime::MultipartBuilder> builder;
|
||||
|
||||
// some checks:
|
||||
switch (m_pathType)
|
||||
{
|
||||
case GraphicalObjectPathType::Polyline:
|
||||
if (!this->isMultiPoint())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
builder = QSharedPointer<Esri::ArcGISRuntime::PolylineBuilder>(new Esri::ArcGISRuntime::PolylineBuilder(spatialReference()));
|
||||
|
||||
break;
|
||||
case GraphicalObjectPathType::Polygon:
|
||||
if (!this->isArea())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
builder = QSharedPointer<Esri::ArcGISRuntime::PolygonBuilder>(new Esri::ArcGISRuntime::PolygonBuilder(spatialReference()));
|
||||
break;
|
||||
} // switch
|
||||
|
||||
|
||||
if (! builder)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " no builder";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
success = BaseClass::updateViewImpl();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// real work:
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " update geometry";
|
||||
|
||||
|
||||
const PositionCont &posCont = m_positions.value();
|
||||
for (const Point3D &pos : posCont)
|
||||
builder->addPoint(pos.x(), pos.y(), pos.z());
|
||||
|
||||
if (! builder->isSketchValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " builder -> sketch invalid";
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// apply attributes:
|
||||
//
|
||||
|
||||
// N. Thoden, 13.02.2018
|
||||
// Case #02062713 [BOS] BasicSceneView_lineNotComplete
|
||||
// If a line has a line of ~10km (Borderline)
|
||||
// the line may 'move' on the ground (3D, RenderMode::Dynamic, SurfarcePlacement::Draped)
|
||||
// To avoid these kind of effect, the advice is to densify the geometry
|
||||
// [similar: Case #02054233 [BOS] LineArtefacts in 3D ->
|
||||
// BUG-000111565 : Lines created on the GraphicsOverlay with "Dynamic" Rendering mode on 3D doesn't render completely when zooming in]
|
||||
|
||||
//
|
||||
// N. Thoden, 29.03.2018
|
||||
// Consulting with Luke Smallwood / using the V100.2.1. debug libs:
|
||||
// densify leads to an assert, so avoid densify
|
||||
// (until now densify does not lead to an improvement..)
|
||||
|
||||
//
|
||||
// N. Thoden, 19.04.2021
|
||||
// [GUEZE-495]: 3D Lagedarstellung Trefferlinien
|
||||
// Linie fehlt teilweise
|
||||
// jetzt (typeweise) per m_maxSegmentLength aktivierbar
|
||||
|
||||
switch (m_pathType)
|
||||
{
|
||||
case GraphicalObjectPathType::Polyline:
|
||||
{
|
||||
const Esri::ArcGISRuntime::Polyline &polyline =
|
||||
static_cast<Esri::ArcGISRuntime::PolylineBuilder *>(builder.data())->toPolyline();
|
||||
if (m_maxSegmentLength > 0)
|
||||
{
|
||||
m_graphic->setGeometry(Esri::ArcGISRuntime::GeometryEngine::densifyGeodetic(polyline,
|
||||
m_maxSegmentLength,
|
||||
Esri::ArcGISRuntime::LinearUnit::meters(),
|
||||
Esri::ArcGISRuntime::GeodeticCurveType::Geodesic));
|
||||
} else {
|
||||
m_graphic->setGeometry(polyline);
|
||||
} // if (densify)
|
||||
assignLineStyleToGraphic();
|
||||
}
|
||||
break;
|
||||
case GraphicalObjectPathType::Polygon:
|
||||
{
|
||||
const Esri::ArcGISRuntime::Polygon &polygon =
|
||||
static_cast<Esri::ArcGISRuntime::PolygonBuilder *>(builder.data())->toPolygon();
|
||||
|
||||
if (m_maxSegmentLength > 0)
|
||||
{
|
||||
m_graphic->setGeometry(Esri::ArcGISRuntime::GeometryEngine::densifyGeodetic(polygon,
|
||||
m_maxSegmentLength,
|
||||
Esri::ArcGISRuntime::LinearUnit::meters(),
|
||||
Esri::ArcGISRuntime::GeodeticCurveType::Geodesic));
|
||||
} else {
|
||||
m_graphic->setGeometry(polygon);
|
||||
}
|
||||
assignFillStyleToGraphic();
|
||||
}
|
||||
break;
|
||||
} // switch
|
||||
|
||||
const int count = AbstractGraphicalObject::countOfPolygonFirstPart(m_graphic->geometry());
|
||||
if (count > 1000)
|
||||
WARNING_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< ", huge amount of vertices, countOfPolygonFirstPart = " << count;
|
||||
else
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< ", amount of vertices, countOfPolygonFirstPart = " << count;
|
||||
|
||||
success = addUpdateGraphic();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success = " << success
|
||||
<< " drawOrder = " << m_graphic->zIndex();
|
||||
return success;
|
||||
}
|
||||
|
||||
double GraphicalObjectPath::maxSegmentLength() const
|
||||
{
|
||||
return m_maxSegmentLength;
|
||||
}
|
||||
|
||||
void GraphicalObjectPath::setMaxSegmentLength(double maxSegmentLength)
|
||||
{
|
||||
m_maxSegmentLength = maxSegmentLength;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::ostream &operator<<(std::ostream &stream,
|
||||
const GraphicalObjectPathType &value)
|
||||
{
|
||||
stream << toString(value).latin1();
|
||||
return stream;
|
||||
}
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectPath
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
// forward:
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
enum class GraphicalObjectPathType {Polyline, Polygon};
|
||||
QLatin1String toString(const GraphicalObjectPathType subType);
|
||||
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectPath : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
|
||||
explicit GraphicalObjectPath(const GraphicalObjectPathType type
|
||||
, const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectPath();
|
||||
|
||||
GraphicalObjectPathType pathType() const
|
||||
{
|
||||
return m_pathType;
|
||||
}
|
||||
|
||||
|
||||
double maxSegmentLength() const;
|
||||
void setMaxSegmentLength(double maxSegmentLength);
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
bool updateViewImpl() override;
|
||||
|
||||
// logical
|
||||
const GraphicalObjectPathType m_pathType;
|
||||
double m_maxSegmentLength{-1};
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
SITUATIONMAP_EXPORT std::ostream &operator<< (std::ostream &stream,
|
||||
const GraphicalObjectPathType &value);
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
+573
@@ -0,0 +1,573 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectPictureMarker
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_picture_marker.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
#include <SymbologyImpl/symbol_extension_renderer.h>
|
||||
#include <MathUtils/simple_helper.h>
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/PictureMarkerSymbol.h>
|
||||
#include <arcgis/SimpleMarkerSymbol.h>
|
||||
#include <arcgis/MultipointBuilder.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QPainter>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
/**
|
||||
* @brief getSimpleMarkerSymbolStyle
|
||||
* @param markerSymbolType type to get
|
||||
* @param filePath filePath of requested marker; if empty -> use return value, if !empty -> use filePath and get file out of qrc
|
||||
* @param hotSpotPercent -0.5 to 0.5; e.g. x=center, y=bottom -> -0.5
|
||||
* @return corrosponding Esri::ArcGISRuntime::SimpleMarkerSymbolStyle, see filePath
|
||||
*/
|
||||
Esri::ArcGISRuntime::SimpleMarkerSymbolStyle getSimpleMarkerSymbolStyle(MarkerSymbolType markerSymbolType,
|
||||
QString &filePath,
|
||||
QPointF *hotSpotPercent = nullptr)
|
||||
{
|
||||
if (hotSpotPercent)
|
||||
*hotSpotPercent = QPointF();
|
||||
|
||||
filePath.clear();
|
||||
|
||||
Esri::ArcGISRuntime::SimpleMarkerSymbolStyle esriSMSS =
|
||||
Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Circle;
|
||||
|
||||
switch (markerSymbolType)
|
||||
{
|
||||
case SituationMap::MarkerSymbolType::Undefined:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Circle;
|
||||
break;
|
||||
|
||||
case SituationMap::MarkerSymbolType::Circle:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Circle;
|
||||
break;
|
||||
case SituationMap::MarkerSymbolType::Cross:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Cross;
|
||||
break;
|
||||
case SituationMap::MarkerSymbolType::Diamond:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Diamond;
|
||||
break;
|
||||
case SituationMap::MarkerSymbolType::Square:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Square;
|
||||
break;
|
||||
case SituationMap::MarkerSymbolType::X:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::X;
|
||||
break;
|
||||
case SituationMap::MarkerSymbolType::Triangle:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Triangle;
|
||||
break;
|
||||
|
||||
case SituationMap::MarkerSymbolType::PushPin2D:
|
||||
esriSMSS = Esri::ArcGISRuntime::SimpleMarkerSymbolStyle::Circle;
|
||||
filePath = QLatin1String(":/situationMap/pushPinRedClipArt.png");
|
||||
if (hotSpotPercent)
|
||||
*hotSpotPercent = QPointF(0, -0.5);
|
||||
|
||||
break;
|
||||
} //switch
|
||||
|
||||
return esriSMSS;
|
||||
}
|
||||
|
||||
GraphicalObjectPictureMarker::GraphicalObjectPictureMarker(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_logger(getLogger("GraphicalObjectPictureMarker"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectPictureMarker::~GraphicalObjectPictureMarker()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
resetPictureMarkerSymbol();
|
||||
resetImage();
|
||||
resetSimpleMarkerSymbol();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectPictureMarker::setImage(const QImage &image, const QSize &defaultSize)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " visibility=" << m_visibility
|
||||
<< " image.size()=" << image.size()
|
||||
<< " defaultSize=" << defaultSize
|
||||
<< " m_imageDefaultSize=" << m_imageDefaultSize
|
||||
<< " m_imageChanged=" << m_imageChanged
|
||||
<< " m_imageDefaultSize.changed()=" << m_imageDefaultSize.changed();
|
||||
resetSimpleMarkerSymbol();
|
||||
|
||||
if (m_image != image)
|
||||
{
|
||||
m_image = image;
|
||||
m_imageChanged = true;
|
||||
}
|
||||
|
||||
// store defautlSize (member shouldn´t be modified)
|
||||
m_imageDefaultSize = defaultSize;
|
||||
if (m_imageDefaultSize.changed())
|
||||
m_imageChanged = true;
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " visibility=" << m_visibility
|
||||
<< " image.size()=" << image.size()
|
||||
<< " defaultSize=" << defaultSize
|
||||
<< " m_imageDefaultSize=" << m_imageDefaultSize
|
||||
<< " m_imageChanged=" << m_imageChanged
|
||||
<< " m_imageDefaultSize.changed()=" << m_imageDefaultSize.changed();
|
||||
}
|
||||
|
||||
void GraphicalObjectPictureMarker::setPictureMarkerSymbol(Esri::ArcGISRuntime::PictureMarkerSymbol *pms, QSize defaultSize)
|
||||
{
|
||||
resetSimpleMarkerSymbol();
|
||||
resetImage();
|
||||
|
||||
if (m_isOwnPms)
|
||||
{
|
||||
delete m_pictureMarkerSymbol;
|
||||
m_pictureMarkerSymbol = nullptr;
|
||||
}
|
||||
|
||||
if (m_pictureMarkerSymbol == pms &&
|
||||
m_imageDefaultSize.value() == defaultSize)
|
||||
return;
|
||||
m_isOwnPms = false;
|
||||
m_pictureMarkerSymbol = pms;
|
||||
m_imageDefaultSize = defaultSize;
|
||||
m_imageChanged = true;
|
||||
}
|
||||
|
||||
void GraphicalObjectPictureMarker::resetImage()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
m_image = QImage();
|
||||
m_imageChanged = true;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectPictureMarker::resetPictureMarkerSymbol()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
if (m_isOwnPms)
|
||||
delete m_pictureMarkerSymbol;
|
||||
m_pictureMarkerSymbol = nullptr;
|
||||
if (m_workaorundTimer)
|
||||
m_workaorundTimer->stop();
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectPictureMarker::resetSimpleMarkerSymbol()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
delete m_simpleMarkerSymbol;
|
||||
m_simpleMarkerSymbol = nullptr;
|
||||
m_markerSymbolType = MarkerSymbolType::Undefined;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
|
||||
MarkerSymbolType GraphicalObjectPictureMarker::markerSymbolType()
|
||||
{
|
||||
return m_markerSymbolType.value();
|
||||
}
|
||||
|
||||
int GraphicalObjectPictureMarker::markerSymbolSize()
|
||||
{
|
||||
return m_markerSize.value();
|
||||
}
|
||||
|
||||
void GraphicalObjectPictureMarker::setMarkerSymbol(MarkerSymbolType markerSymbolType,
|
||||
int size, const QColor &color)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " color=" << color;
|
||||
|
||||
resetImage();
|
||||
|
||||
m_markerSymbolType = markerSymbolType;
|
||||
m_markerSize = size;
|
||||
m_markerColor = color;
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
QSize GraphicalObjectPictureMarker::currentSize() const
|
||||
{
|
||||
return m_currentSize;
|
||||
}
|
||||
|
||||
bool GraphicalObjectPictureMarker::create()
|
||||
{
|
||||
return BaseClass::create();
|
||||
}
|
||||
|
||||
int GraphicalObjectPictureMarker::xOffset() const
|
||||
{
|
||||
return m_externalOffset.value().x();
|
||||
}
|
||||
void GraphicalObjectPictureMarker::setXOffset(int xOffset)
|
||||
{
|
||||
m_externalOffset.refValue().rx() = xOffset;
|
||||
}
|
||||
int GraphicalObjectPictureMarker::yOffset() const
|
||||
{
|
||||
return m_externalOffset.value().y();
|
||||
}
|
||||
void GraphicalObjectPictureMarker::setYOffset(int yOffset)
|
||||
{
|
||||
m_externalOffset.refValue().ry() = yOffset;
|
||||
}
|
||||
|
||||
float GraphicalObjectPictureMarker::rotationAngle()
|
||||
{
|
||||
return m_angle.value();
|
||||
}
|
||||
void GraphicalObjectPictureMarker::setRotationAngle(float angle)
|
||||
{
|
||||
m_angle = angle;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectPictureMarker::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " origin =" << this->origin() // .x() << " , " << this->origin().y()
|
||||
<< " visibility=" << m_visibility
|
||||
<< " pickable=" << m_pickable
|
||||
<< " pickable.changed=" << m_pickable.changed()
|
||||
<< " selected=" << m_selected
|
||||
<< " m_angle = " << m_angle.value()
|
||||
<< " m_drawOrder = " << m_drawOrder
|
||||
<< " m_image.size() = " << m_image.size()
|
||||
<< " m_imageChanged = " << m_imageChanged
|
||||
<< " m_imageDefaultSize=" << m_imageDefaultSize
|
||||
<< " m_imageDefaultSize.changed()=" << m_imageDefaultSize.changed()
|
||||
<< " m_scale = " << m_scale.value();
|
||||
|
||||
// some checks:
|
||||
if (m_positions.value().size() < 1)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " debugInfo='" << m_debugInfo << "'"
|
||||
<< " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Image or Marker ???
|
||||
//
|
||||
QString filePath;
|
||||
QPointF hotSpotPercent;
|
||||
Esri::ArcGISRuntime::SimpleMarkerSymbolStyle esriSMSS =
|
||||
getSimpleMarkerSymbolStyle(m_markerSymbolType.value(),
|
||||
filePath,
|
||||
&hotSpotPercent);
|
||||
m_markerHotSpotPercent = hotSpotPercent;
|
||||
|
||||
if (m_markerSymbolType.value() != MarkerSymbolType::Undefined)
|
||||
{
|
||||
if (m_markerSize.changed() ||
|
||||
m_markerSymbolType.changed() ||
|
||||
m_markerColor.changed() ||
|
||||
m_markerSymbolType.changed() ||
|
||||
m_angle.changed() ||
|
||||
m_markerHotSpotPercent.changed())
|
||||
{
|
||||
if (!reCreateSymbol(filePath, esriSMSS))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_image.isNull() && (!m_isOwnPms && m_pictureMarkerSymbol == nullptr))
|
||||
{
|
||||
// in context of class 'TacticalAppearance' the PictureMarker exist always...
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " no image and m_markerSymbolType==Undefined -> nothing to do";
|
||||
// -> nothing to do:
|
||||
return true; // -> nothing to do:
|
||||
}
|
||||
|
||||
if (m_scale.changed() ||
|
||||
m_imageChanged ||
|
||||
m_markerSymbolType.changed() ||
|
||||
m_markerSize.changed() ||
|
||||
m_angle.changed() ||
|
||||
!m_pictureMarkerSymbol)
|
||||
{
|
||||
if (!reCreateSymbol(filePath, esriSMSS))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const PositionCont &posCont = m_positions.value();
|
||||
if (posCont.size() == 1)
|
||||
{
|
||||
const Point3D &origin = this->origin();
|
||||
Esri::ArcGISRuntime::Point originGeometry(origin.x(),
|
||||
origin.y(),
|
||||
origin.z(),
|
||||
spatialReference());
|
||||
m_graphic->setGeometry(originGeometry);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Eception: Layer with name "AES2" should NOT have no renderer 8 to enable multipoint graphics
|
||||
// [GUEZE-496] RPL Nr 770: 3D Lagedarstellung Einfrieren der SW Appl.
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " posCont.size() = " << posCont.size();
|
||||
Esri::ArcGISRuntime::MultipointBuilder builder(spatialReference());
|
||||
for (const Point3D &pos : posCont)
|
||||
builder.points()->addPoint(pos.x(), pos.y(), pos.z());
|
||||
|
||||
if (! builder.isSketchValid())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " builder -> sketch invalid";
|
||||
return false;
|
||||
}
|
||||
m_graphic->setGeometry(builder.toGeometry());
|
||||
}
|
||||
|
||||
bool success = BaseClass::updateViewImpl();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
success = addUpdateGraphic();
|
||||
|
||||
|
||||
QSize imgSize = m_image.size();
|
||||
QSizeF pmSize;
|
||||
if (m_pictureMarkerSymbol)
|
||||
pmSize = QSizeF(m_pictureMarkerSymbol->width(), m_pictureMarkerSymbol->height());
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
// << " success=" << success
|
||||
<< " m_drawOrder = " << m_drawOrder
|
||||
<< " m_graphic->drawOrder = " << m_graphic->zIndex()
|
||||
<< " m_image->size() = " << imgSize
|
||||
<< " pictureMarkerSymbol->size() = " << pmSize;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GraphicalObjectPictureMarker::reCreateSymbol(const QString &filePath,
|
||||
const Esri::ArcGISRuntime::SimpleMarkerSymbolStyle esriSMSS)
|
||||
{
|
||||
const bool imageRequired = !m_image.isNull() || !filePath.isEmpty();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " filePath = '" << filePath << "'"
|
||||
<< " m_image->size() = " << m_image.size()
|
||||
<< " m_imageChanged = " << m_imageChanged
|
||||
<< " m_angle = " << m_angle.value()
|
||||
<< " m_currentSize = " << m_currentSize
|
||||
<< " m_imageDefaultSize = " << m_imageDefaultSize.value()
|
||||
<< " m_imageDefaultSize.changed() = " << m_imageDefaultSize.changed();
|
||||
|
||||
//
|
||||
// Now we know what to use: Image or Marker
|
||||
//
|
||||
|
||||
if (!create())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
// what is used currently?
|
||||
// image or m_simpleMarkerSymbol(esri)?
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " imageRequired=" << imageRequired
|
||||
<< " m_pictureMarkerSymbol=" << m_pictureMarkerSymbol
|
||||
<< " m_simpleMarkerSymbol=" << m_simpleMarkerSymbol;
|
||||
|
||||
if (!filePath.isEmpty())
|
||||
{
|
||||
// e.g. case PushPin2D
|
||||
QImage img;
|
||||
if (img.load(filePath))
|
||||
{
|
||||
int iSize = qRound(m_markerSize.value() * m_scale.value());
|
||||
m_currentSize = QSize(iSize, iSize);
|
||||
img = img.scaledToHeight(iSize, Qt::SmoothTransformation);
|
||||
|
||||
QColor localColor = m_markerColor.value();
|
||||
|
||||
if (m_markerSymbolType.value() == MarkerSymbolType::PushPin2D && localColor.isValid())
|
||||
{
|
||||
QColor colorToBeReplaced(255, 0, 0);
|
||||
AdvancedSymbology::ExtensionRenderer::replaceColor(img, colorToBeReplaced.rgba(), localColor.rgba());
|
||||
}
|
||||
setImage(img);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " loading image failed, debugInfo='" << m_debugInfo << "'"
|
||||
<< " path='" << filePath << "'";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Transfer data to esriSymbols:
|
||||
//
|
||||
|
||||
// Image:
|
||||
if (!m_image.isNull() || (!m_isOwnPms && m_pictureMarkerSymbol))
|
||||
{
|
||||
resetSimpleMarkerSymbol();
|
||||
|
||||
QSize realImageSize;
|
||||
if (!m_isOwnPms && m_pictureMarkerSymbol)
|
||||
{
|
||||
if (m_imageDefaultSize.value().isEmpty())
|
||||
m_currentSize = m_image.size() * m_scale.value();
|
||||
else
|
||||
m_currentSize = m_imageDefaultSize.value() * m_scale.value();
|
||||
realImageSize = m_currentSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
// scale localImage by m_scale
|
||||
QImage localImage;
|
||||
if (!filePath.isEmpty())
|
||||
{
|
||||
// case PushPin2D -> already scaled by m_scale. So don´t scale again:
|
||||
localImage = m_image;
|
||||
m_currentSize = localImage.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_imageDefaultSize.value().isEmpty())
|
||||
m_currentSize = m_image.size() * m_scale.value();
|
||||
else
|
||||
m_currentSize = m_imageDefaultSize.value() * m_scale.value();
|
||||
|
||||
// scaled required?
|
||||
if (m_image.size() != m_currentSize)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " SCALE FROM " << m_image.size() << " TO " << m_currentSize;
|
||||
localImage = m_image.scaled(m_currentSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
++m_scaleCounter4Moduletest;
|
||||
} else {
|
||||
localImage = m_image;
|
||||
m_currentSize = localImage.size();
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_scaleCounter4Moduletest = " << m_scaleCounter4Moduletest
|
||||
<< ", localImage.size() = " << localImage.size();
|
||||
|
||||
delete m_pictureMarkerSymbol;
|
||||
m_pictureMarkerSymbol = new Esri::ArcGISRuntime::PictureMarkerSymbol(localImage);
|
||||
realImageSize = localImage.size();
|
||||
|
||||
|
||||
// Workaround :
|
||||
// Norbert Thoden, 11.06.2020:
|
||||
// do some calls again to fix ESRI-Bug:
|
||||
// Bug: new Image('localImage#) / pictureMarkerSymbol, but sometimes it will not be shown :-(
|
||||
// Using try and error, we recognize that an additional call seems to fix that issue:
|
||||
if (!m_workaorundTimer)
|
||||
{
|
||||
m_workaorundTimer = new QTimer(m_graphic);
|
||||
m_workaorundTimer->setInterval(150);
|
||||
m_workaorundTimer->setSingleShot(true);
|
||||
QObject::connect(m_workaorundTimer, &QTimer::timeout, m_graphic, [this]() {
|
||||
if (!m_graphic)
|
||||
return;
|
||||
m_graphic->setZIndex(m_drawOrder.value());
|
||||
m_graphic->setVisible(m_visibility.value());
|
||||
m_graphic->setSelected(m_selected.value());
|
||||
});
|
||||
}
|
||||
m_workaorundTimer->start();
|
||||
// : Workaround
|
||||
|
||||
}
|
||||
m_imageChanged = false;
|
||||
|
||||
// set image to pms AND ALSO the Heigth and Width!!!
|
||||
|
||||
// // !!! Important !!!
|
||||
// // Case #01713501 - PictureMarker-offset
|
||||
// // Esri::PictureMarkerSymbol:: setHeight/setWidth -> typographic points.
|
||||
// // 36pt -> 48pixel -> factor 0.75
|
||||
// double pixelToPointFactor = 0.71;
|
||||
// m_pictureMarkerSymbol->setHeight(m_image->size().height() * pixelToPointFactor);
|
||||
// m_pictureMarkerSymbol->setWidth (m_image->size().width() * pixelToPointFactor);
|
||||
// // !!! Important !!!
|
||||
|
||||
QPointF markerHotSpot = QPointF(realImageSize.width() / 2.0 * m_markerHotSpotPercent.value().x(),
|
||||
realImageSize.height() / 2.0 * m_markerHotSpotPercent.value().y());
|
||||
|
||||
QPointF finalOffset = (markerHotSpot.toPoint() * -1) * 1.33 // 1.33; // try and error (48pixel / 36pt)
|
||||
+
|
||||
(m_externalOffset.value() * 0.75); // 0.75; // try and error (36pt / 48pixel)
|
||||
|
||||
m_pictureMarkerSymbol->setOffsetX(finalOffset.x());
|
||||
m_pictureMarkerSymbol->setOffsetY(finalOffset.y());
|
||||
|
||||
m_pictureMarkerSymbol->setAngle(m_angle.value());
|
||||
|
||||
m_graphic->setSymbol(m_pictureMarkerSymbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
resetPictureMarkerSymbol();
|
||||
resetImage();
|
||||
if (!m_simpleMarkerSymbol)
|
||||
m_simpleMarkerSymbol = new Esri::ArcGISRuntime::SimpleMarkerSymbol();
|
||||
|
||||
m_simpleMarkerSymbol->setSize(m_markerSize.value() * m_scale.value());
|
||||
m_simpleMarkerSymbol->setStyle(esriSMSS);
|
||||
m_simpleMarkerSymbol->setAngle(m_angle.value());
|
||||
|
||||
m_simpleMarkerSymbol->setOffsetX(m_externalOffset.value().x());
|
||||
m_simpleMarkerSymbol->setOffsetY(m_externalOffset.value().y());
|
||||
|
||||
m_simpleMarkerSymbol->setColor(m_markerColor.value());
|
||||
|
||||
m_graphic->setSymbol(m_simpleMarkerSymbol);
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " filePath = '" << filePath << "'"
|
||||
<< " m_image->size() = " << m_image.size()
|
||||
<< " m_imageChanged = " << m_imageChanged
|
||||
<< " m_currentSize = " << m_currentSize
|
||||
<< " m_imageDefaultSize = " << m_imageDefaultSize.value()
|
||||
<< " m_imageDefaultSize.changed() = " << m_imageDefaultSize.changed();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace SituationMap
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectPictureMarker
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
#include <Map/text_style.h>
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
|
||||
// Esri
|
||||
#include <arcgis/SymbolTypes.h>
|
||||
#include <arcgis/DistanceCompositeSceneSymbol.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QImage>
|
||||
|
||||
|
||||
// forward:
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class Graphic;
|
||||
class GraphicsOverlay;
|
||||
class PictureMarkerSymbol;
|
||||
class SimpleMarkerSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
class QTimer;
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectPictureMarker : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
GraphicalObjectPictureMarker(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectPictureMarker();
|
||||
|
||||
// Data access:
|
||||
const QImage &image() const { return m_image; }
|
||||
QSize imageDefaultSize() const { return m_imageDefaultSize.value(); }
|
||||
void setImage(const QImage &image, const QSize &defaultSize = QSize());
|
||||
|
||||
void setPictureMarkerSymbol(Esri::ArcGISRuntime::PictureMarkerSymbol *pms, QSize defaultSize);
|
||||
|
||||
virtual MarkerSymbolType markerSymbolType();
|
||||
virtual int markerSymbolSize();
|
||||
virtual void setMarkerSymbol(MarkerSymbolType markerSymbolType,
|
||||
int size,
|
||||
const QColor &color = QColor());
|
||||
|
||||
virtual QSize currentSize() const;
|
||||
|
||||
// Offset (x: to right ; y: to north)
|
||||
virtual int xOffset() const;
|
||||
virtual void setXOffset(int xOffset);
|
||||
virtual int yOffset() const;
|
||||
virtual void setYOffset(int yOffset);
|
||||
|
||||
// rotation / angle
|
||||
virtual float rotationAngle();
|
||||
virtual void setRotationAngle(float angle);
|
||||
|
||||
protected:
|
||||
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_markerSymbolType.changed()
|
||||
|| m_markerSize.changed()
|
||||
|| m_markerColor.changed()
|
||||
|| m_angle.changed()
|
||||
|| m_markerHotSpotPercent.changed()
|
||||
|| m_externalOffset.changed()
|
||||
|| m_imageChanged
|
||||
;
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_markerSymbolType.reset();
|
||||
m_markerSize.reset();
|
||||
m_markerColor.reset();
|
||||
m_angle.reset();
|
||||
m_markerHotSpotPercent.reset();
|
||||
m_externalOffset.reset();
|
||||
m_imageChanged = false;
|
||||
|
||||
m_imageDefaultSize.reset();
|
||||
}
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
void resetImage();
|
||||
void resetPictureMarkerSymbol();
|
||||
void resetSimpleMarkerSymbol();
|
||||
bool reCreateSymbol(const QString &filePath,
|
||||
const Esri::ArcGISRuntime::SimpleMarkerSymbolStyle esriSMSS);
|
||||
|
||||
// used for image:
|
||||
QImage m_image;
|
||||
SimpleValue<QSize> m_imageDefaultSize;
|
||||
Esri::ArcGISRuntime::PictureMarkerSymbol *m_pictureMarkerSymbol = nullptr;
|
||||
bool m_imageChanged = true;
|
||||
bool m_isOwnPms = true;
|
||||
|
||||
// used marker:
|
||||
Esri::ArcGISRuntime::SimpleMarkerSymbol *m_simpleMarkerSymbol = nullptr;
|
||||
QTimer *m_workaorundTimer = nullptr; // for re-new of Esri::ArcGISRuntime::PictureMarkerSymbol
|
||||
|
||||
QSize m_currentSize;
|
||||
int m_scaleCounter4Moduletest = 0;
|
||||
|
||||
|
||||
SimpleValue<MarkerSymbolType> m_markerSymbolType = MarkerSymbolType::Undefined;
|
||||
SimpleValue<int> m_markerSize = 10;
|
||||
SimpleValue<QColor> m_markerColor = QColor(Qt::red);
|
||||
|
||||
SimpleValue<float> m_angle = 0; ///
|
||||
SimpleValue<QPointF> m_markerHotSpotPercent; ///< Store marker-specific offset.
|
||||
SimpleValue<QPoint> m_externalOffset; ///< Stores external offset.
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectRange
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_range.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/PolygonBuilder.h>
|
||||
#include <arcgis/MultipartBuilder.h>
|
||||
#include <arcgis/ImmutablePartCollection.h>
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
GraphicalObjectRange::GraphicalObjectRange(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_logger(getLogger("GraphicalObjectRange"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectRange::~GraphicalObjectRange()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
|
||||
int GraphicalObjectRange::range() const
|
||||
{
|
||||
return m_range.value();
|
||||
}
|
||||
|
||||
float GraphicalObjectRange::angle() const
|
||||
{
|
||||
return m_angleDegree.value();
|
||||
}
|
||||
|
||||
void GraphicalObjectRange::setRange(int range, float angleDegree)
|
||||
{
|
||||
m_angleDegree = angleDegree;
|
||||
m_range = range;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool GraphicalObjectRange::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
EllipseParameters ellipsePara;
|
||||
ellipsePara.setLengthX(m_range.value());
|
||||
ellipsePara.setLengthY(m_range.value());
|
||||
ellipsePara.setDirectionDegree(m_angleDegree.value()) ;
|
||||
ellipsePara.setDirectionDegree((m_angleDegree.value() * -1) + 90);
|
||||
ellipsePara.setMaxSegmentLength(10);
|
||||
ellipsePara.setMaxPointCount(30); // limit to 30 to reduce the number of vertices. If to high, keep performance impact to 3D in mind!!!
|
||||
|
||||
this->setEllipseParameters(ellipsePara);
|
||||
|
||||
bool success = BaseClass::updateViewImpl();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " drawOrder = " << m_graphic->zIndex()
|
||||
<< " success = " << success;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectRange::createEllipse(Esri::ArcGISRuntime::Polygon &ellipse)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " range=" << m_range
|
||||
<< " angle=" << m_angleDegree;
|
||||
|
||||
bool success = BaseClass::createEllipse(ellipse);
|
||||
|
||||
if (success &&
|
||||
!ellipse.isEmpty() &&
|
||||
!ellipse.parts().isEmpty() &&
|
||||
!ellipse.parts().part(0).isEmpty())
|
||||
{
|
||||
const Point3D ¢er = this->origin();
|
||||
|
||||
// 'modify' ellipe (by copying, adding and re-assigning):
|
||||
|
||||
// part 0 - ellipse
|
||||
// we have to copy the point since the ellipse does not contain the z value anymore :-(
|
||||
Esri::ArcGISRuntime::Part partCircle(ellipse.spatialReference());
|
||||
const Esri::ArcGISRuntime::ImmutablePart &im = ellipse.parts().part(0);
|
||||
|
||||
for (int i = 0; i < im.pointCount(); ++i)
|
||||
{
|
||||
const Esri::ArcGISRuntime::Point &p = im.point(i);
|
||||
partCircle.addPoint(Esri::ArcGISRuntime::Point(p.x(),
|
||||
p.y(),
|
||||
center.z() // p.z()
|
||||
));
|
||||
}
|
||||
|
||||
// part 1 - line to center
|
||||
Esri::ArcGISRuntime::Part partLine(ellipse.spatialReference());
|
||||
partLine.addPoint(im.startPoint().x(),
|
||||
im.startPoint().y(),
|
||||
center.z());
|
||||
partLine.addPoint(center.x(),
|
||||
center.y(),
|
||||
center.z());
|
||||
// a polyGON requiree to have at least 3 points:
|
||||
partLine.addPoint(center.x(),
|
||||
center.y(),
|
||||
center.z()+0.01);
|
||||
|
||||
// combine them to a PartCollection:
|
||||
Esri::ArcGISRuntime::PartCollection pc(ellipse.spatialReference());
|
||||
pc.addPart(&partCircle);
|
||||
pc.addPart(&partLine);
|
||||
|
||||
Esri::ArcGISRuntime::PolygonBuilder builder(ellipse.spatialReference());
|
||||
builder.setParts(&pc);
|
||||
|
||||
ellipse = builder.toPolygon();
|
||||
|
||||
success = true;
|
||||
|
||||
}
|
||||
else
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'";
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::ostream &operator<<(std::ostream &stream,
|
||||
const GraphicalObjectRange &value)
|
||||
{
|
||||
stream << value.toString();
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectRange
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "graphical_object_ellipse.h"
|
||||
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectRange : public GraphicalObjectEllipse
|
||||
{
|
||||
|
||||
using BaseClass = GraphicalObjectEllipse;
|
||||
|
||||
public:
|
||||
GraphicalObjectRange(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectRange();
|
||||
|
||||
int range() const;
|
||||
float angle() const;
|
||||
|
||||
void setRange(int range, float angleDegree);
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
// bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_angleDegree.changed()
|
||||
|| m_range.changed();
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_angleDegree.reset();
|
||||
m_range.reset();
|
||||
}
|
||||
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
|
||||
bool createEllipse(Esri::ArcGISRuntime::Polygon &ellipse) override;
|
||||
|
||||
|
||||
private:
|
||||
SimpleValue<float> m_angleDegree = 0;
|
||||
SimpleValue<int> m_range = 0;
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// output operator:
|
||||
//-----------------------------------------------------------------------------
|
||||
std::ostream &operator<< (std::ostream &stream,
|
||||
const GraphicalObjectRange &value);
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectRendererAttributes
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_renderer_attributes.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
#include <MathUtils/simple_helper.h>
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/ModelSceneSymbol.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QPainter>
|
||||
#include <QFile>
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
GraphicalObjectRendererAttributes::GraphicalObjectRendererAttributes(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_logger(getLogger("GraphicalObjectRendererAttributes"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectRendererAttributes::~GraphicalObjectRendererAttributes()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectRendererAttributes::setAttributeMap(const QVariantMap &attribMap)
|
||||
{
|
||||
m_attributeMap = attribMap;
|
||||
}
|
||||
|
||||
QVariantMap GraphicalObjectRendererAttributes::attributeMap() const
|
||||
{
|
||||
return m_attributeMap.value();
|
||||
}
|
||||
|
||||
bool GraphicalObjectRendererAttributes::create()
|
||||
{
|
||||
return BaseClass::create();
|
||||
}
|
||||
|
||||
bool GraphicalObjectRendererAttributes::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " origin =" << this->origin() // .x() << " , " << this->origin().y()
|
||||
<< " visibility=" << m_visibility
|
||||
<< " pickable=" << m_pickable
|
||||
<< " pickable.changed=" << m_pickable.changed()
|
||||
<< " selected=" << m_selected
|
||||
<< " m_attributeMap = " << m_attributeMap.value().size()
|
||||
<< " m_drawOrder = " << m_drawOrder;
|
||||
|
||||
// some checks:
|
||||
if (!isSinglePoint())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " debugInfo='" << m_debugInfo << "'"
|
||||
<< " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
const Point3D &origin = this->origin();
|
||||
m_graphic->setGeometry(Esri::ArcGISRuntime::Point(origin.x(),
|
||||
origin.y(),
|
||||
origin.z(),
|
||||
spatialReference()));
|
||||
|
||||
if (m_attributeMap.changed())
|
||||
{
|
||||
QVariantMap cur = m_graphic->attributes()->attributesMap();
|
||||
|
||||
if (m_logger.isDebugEnabled())
|
||||
qCritical() << " debugInfo='" << m_debugInfo << "'" << ", QVariantMap before unite " << cur;
|
||||
|
||||
cur.unite(m_attributeMap.value());
|
||||
|
||||
if (m_logger.isDebugEnabled())
|
||||
qCritical() << " debugInfo='" << m_debugInfo << "'" << ", QVariantMap after unite " << cur;
|
||||
|
||||
m_graphic->attributes()->setAttributesMap(cur);
|
||||
}
|
||||
|
||||
// keep anchor like Esri::ArcGISRuntime::SceneSymbolAnchorPosition::Bottom in mind.
|
||||
// assigned during setup the Renderer (LayerFactory, AdapterDds...)
|
||||
|
||||
success = BaseClass::updateViewImpl();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
success = addUpdateGraphic();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success=" << success
|
||||
<< " m_drawOrder = " << m_drawOrder
|
||||
<< " m_graphic->drawOrder = " << m_graphic->zIndex();
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace SituationMap
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectRendererAttributes
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
#include <Map/text_style.h>
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
|
||||
// Esri
|
||||
#include <arcgis/SymbolTypes.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QImage>
|
||||
#include <QVariantMap>
|
||||
|
||||
|
||||
// forward:
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class Graphic;
|
||||
class GraphicsOverlay;
|
||||
class ModelSceneSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectRendererAttributes : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
GraphicalObjectRendererAttributes(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectRendererAttributes();
|
||||
|
||||
// Data access:
|
||||
// to be cont.
|
||||
void setAttributeMap(const QVariantMap &attribMap);
|
||||
QVariantMap attributeMap() const;
|
||||
|
||||
protected:
|
||||
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_attributeMap.changed()
|
||||
;
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_attributeMap.reset();
|
||||
}
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
// no ModelSceneSymbol since Renderer-based
|
||||
|
||||
SimpleValue<QVariantMap> m_attributeMap;
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
// Forbid some overloaded methods without effects of this object;
|
||||
PositionCont positions() const override
|
||||
{
|
||||
return PositionCont();
|
||||
}
|
||||
void setPositions(const PositionCont &posCont) override
|
||||
{
|
||||
Q_UNUSED(posCont);
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectSceneMarker
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_scene_marker.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
#include <MathUtils/simple_helper.h>
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/arcgisversion.h> // This file is created by RME, not ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/SimpleMarkerSceneSymbol.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QPainter>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
GraphicalObjectSceneMarker::GraphicalObjectSceneMarker(SceneMarkerType type
|
||||
, const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_type(type)
|
||||
, m_logger(getLogger("GraphicalObjectSceneMarker"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectSceneMarker::~GraphicalObjectSceneMarker()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
delete m_simpleMarkerSceneSymbol;
|
||||
m_simpleMarkerSceneSymbol = nullptr;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void GraphicalObjectSceneMarker::setDiameter(double diameter)
|
||||
{
|
||||
m_diameter = diameter;
|
||||
}
|
||||
|
||||
double GraphicalObjectSceneMarker::diameter() const
|
||||
{
|
||||
return m_diameter.value();
|
||||
}
|
||||
|
||||
bool GraphicalObjectSceneMarker::create()
|
||||
{
|
||||
return BaseClass::create();
|
||||
}
|
||||
|
||||
bool GraphicalObjectSceneMarker::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " origin =" << this->origin() // .x() << " , " << this->origin().y()
|
||||
<< " visibility=" << m_visibility
|
||||
<< " pickable=" << m_pickable
|
||||
<< " pickable.changed=" << m_pickable.changed()
|
||||
<< " selected=" << m_selected
|
||||
<< " m_diameter = " << m_diameter.value()
|
||||
<< " m_heading = " << m_heading.value()
|
||||
<< " m_pitch = " << m_pitch.value()
|
||||
<< " m_roll = " << m_roll.value()
|
||||
<< " m_drawOrder = " << m_drawOrder
|
||||
<< " m_lineStyle = " << m_lineStyle.value()
|
||||
<< " m_fillStyle = " << m_fillStyle.value()
|
||||
<< " fillColor = " << m_fillStyle.value().fillColor()
|
||||
<< " m_scale = " << m_scale.value();
|
||||
|
||||
if (m_graphicsLayer->renderingMode() != Esri::ArcGISRuntime::GraphicsRenderingMode::Dynamic)
|
||||
for (int i=0; i<10; ++i)
|
||||
ERROR_LOG(m_logger) << " RenderingMode::Dynamic required!!! , debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
// some checks:
|
||||
if (!isSinglePoint())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " debugInfo='" << m_debugInfo << "'"
|
||||
<< " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = create();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
const double radiusHeight = m_diameter.value()/2.0;
|
||||
|
||||
Point3D origin = this->origin();
|
||||
|
||||
// Try to set AnchorPosition::Top, to let the cone rotate around top/tip.
|
||||
// Using a cone, the anchor point does not work as expected, we have to move
|
||||
if (m_type == SceneMarkerType::CONE)
|
||||
{
|
||||
//
|
||||
// It´s a SCENE Marker. So we are per definition in 3D and origin is in degree.
|
||||
//
|
||||
// heading is in degree:m_heading.value()
|
||||
// offset as vector:
|
||||
QPointF offsetMeter(0, radiusHeight/2.0);
|
||||
const int rotAngleDegree = (static_cast<int>(m_heading.value())-90)%360;
|
||||
DEBUG_LOG(m_logger) << " offsetMeter = " << offsetMeter << ", m_heading = " << m_heading.value() << ", rotAngleDegree = " << rotAngleDegree;
|
||||
MathUtils::rotatePoint(offsetMeter, QPointF(), rotAngleDegree);
|
||||
// new temporary origin...
|
||||
// -> rad
|
||||
origin *= LtsCoordTrans::deg2rad();
|
||||
LtsCoordTrans::UtmCoordinate newOrigin = LtsCoordTrans::UtmCoordinate::fromGeographic(origin.x(), origin.y());
|
||||
DEBUG_LOG(m_logger) << " newOrigin = " << newOrigin.mgrs();
|
||||
|
||||
// add rotated offset to temporary origin:
|
||||
const QPointF origin2D = newOrigin.geographic(offsetMeter) * LtsCoordTrans::rad2deg();
|
||||
// -> deg
|
||||
// write back; z-value stays untouched:
|
||||
origin.rx() = origin2D.x();
|
||||
origin.ry() = origin2D.y();
|
||||
}
|
||||
|
||||
const Esri::ArcGISRuntime::Point originGeometry(origin.x(),
|
||||
origin.y(),
|
||||
origin.z(),
|
||||
spatialReference());
|
||||
m_graphic->setGeometry(originGeometry);
|
||||
|
||||
if (!m_simpleMarkerSceneSymbol)
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case SceneMarkerType::CONE: // Kegel
|
||||
m_simpleMarkerSceneSymbol =
|
||||
Esri::ArcGISRuntime::SimpleMarkerSceneSymbol::cone(
|
||||
m_fillStyle.value().fillColor(),
|
||||
radiusHeight, radiusHeight, // V100.8: cone: 'diameter' is interpreted as radius
|
||||
Esri::ArcGISRuntime::SceneSymbolAnchorPosition::Center); // V100.8: cone: Top does not work as aspected - grrr
|
||||
break;
|
||||
case SceneMarkerType::SPHERE: // Kugel
|
||||
m_simpleMarkerSceneSymbol =
|
||||
Esri::ArcGISRuntime::SimpleMarkerSceneSymbol::sphere(
|
||||
m_fillStyle.value().fillColor(),
|
||||
radiusHeight*2.0,
|
||||
Esri::ArcGISRuntime::SceneSymbolAnchorPosition::Center);
|
||||
break;
|
||||
} // switch
|
||||
}
|
||||
m_simpleMarkerSceneSymbol->setColor(m_fillStyle.value().fillColor());
|
||||
|
||||
if (m_type == SceneMarkerType::CONE)
|
||||
{
|
||||
m_simpleMarkerSceneSymbol->setWidth(radiusHeight);
|
||||
m_simpleMarkerSceneSymbol->setHeight(radiusHeight);
|
||||
m_simpleMarkerSceneSymbol->setDepth(radiusHeight);
|
||||
} else {
|
||||
m_simpleMarkerSceneSymbol->setWidth(m_diameter.value());
|
||||
m_simpleMarkerSceneSymbol->setHeight(m_diameter.value());
|
||||
m_simpleMarkerSceneSymbol->setDepth(m_diameter.value());
|
||||
}
|
||||
|
||||
m_simpleMarkerSceneSymbol->setHeading(m_heading.value());
|
||||
m_simpleMarkerSceneSymbol->setPitch(m_pitch.value());
|
||||
m_simpleMarkerSceneSymbol->setRoll(m_roll.value());
|
||||
|
||||
m_graphic->setSymbol(m_simpleMarkerSceneSymbol);
|
||||
|
||||
success = BaseClass::updateViewImpl();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
success = addUpdateGraphic();
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateView failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success=" << success
|
||||
<< " m_drawOrder = " << m_drawOrder
|
||||
<< " m_graphic->drawOrder = " << m_graphic->zIndex();
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectSceneMarker
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
#include <Map/text_style.h>
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
|
||||
// Esri
|
||||
#include <arcgis/SymbolTypes.h>
|
||||
|
||||
|
||||
// Qt
|
||||
#include <QImage>
|
||||
|
||||
|
||||
// forward:
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class Graphic;
|
||||
class GraphicsOverlay;
|
||||
class SimpleMarkerSceneSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
class QTimer;
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
// !!! Layer with RenderingMode::Dynamic required !!!
|
||||
// !!! Layer with RenderingMode::Dynamic required !!!
|
||||
// !!! Layer with RenderingMode::Dynamic required !!!
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
enum class SceneMarkerType {CONE, SPHERE};
|
||||
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectSceneMarker : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
|
||||
public:
|
||||
GraphicalObjectSceneMarker(SceneMarkerType type
|
||||
, const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId);
|
||||
|
||||
~GraphicalObjectSceneMarker();
|
||||
|
||||
// Data access:
|
||||
// to be cont. (type is sphere, to support cube, cylinder etc)
|
||||
void setDiameter(double diameter);
|
||||
double diameter() const;
|
||||
|
||||
double heading() const { return m_heading.value(); }
|
||||
void setHeading(double headingDegree) { m_heading = headingDegree; }
|
||||
double pitch() const { return m_pitch.value(); }
|
||||
void setPitch(double pitchDegree) { m_pitch = pitchDegree; }
|
||||
double roll() const { return m_roll.value(); }
|
||||
void setRoll(double rollDegree) { m_roll = rollDegree; }
|
||||
|
||||
protected:
|
||||
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_diameter.changed()
|
||||
|| m_heading.changed()
|
||||
|| m_pitch.changed()
|
||||
|| m_roll.changed()
|
||||
;
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_diameter.reset();
|
||||
m_heading.reset();
|
||||
m_pitch.reset();
|
||||
m_roll.reset();
|
||||
}
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
// used marker:
|
||||
Esri::ArcGISRuntime::SimpleMarkerSceneSymbol *m_simpleMarkerSceneSymbol{nullptr};
|
||||
|
||||
SceneMarkerType m_type{SceneMarkerType::SPHERE};
|
||||
SimpleValue<double> m_diameter{25};
|
||||
|
||||
SimpleValue<double> m_heading{0}; // degree
|
||||
SimpleValue<double> m_pitch{0}; // degree
|
||||
SimpleValue<double> m_roll{0}; // degree
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
// Forbid some overloaded methods without effects of this object;
|
||||
PositionCont positions() const override
|
||||
{
|
||||
return PositionCont();
|
||||
}
|
||||
void setPositions(const PositionCont &posCont) override
|
||||
{
|
||||
Q_UNUSED(posCont);
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,340 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectText
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "graphical_object_text.h"
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/TextSymbol.h>
|
||||
#include <arcgis/PictureMarkerSymbol.h>
|
||||
|
||||
// Qt
|
||||
#include <QString>
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
GraphicalObjectText::GraphicalObjectText(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
||||
, m_textSymbol(nullptr)
|
||||
, m_logger(getLogger("GraphicalObjectText"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
GraphicalObjectText::~GraphicalObjectText()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " text='" << m_text << "'";
|
||||
|
||||
delete m_textSymbol;
|
||||
m_textSymbol = nullptr;
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " text='" << m_text << "'";
|
||||
}
|
||||
|
||||
QString GraphicalObjectText::toString() const
|
||||
{
|
||||
QString str;
|
||||
// str.append( BaseClass::toString() );
|
||||
|
||||
if (!m_debugInfo.isEmpty())
|
||||
str.append(QStringLiteral("debugInfo=%1").arg(m_debugInfo));
|
||||
|
||||
if (m_graphicsLayer)
|
||||
str.append(QStringLiteral(" layer='%1'").arg(m_graphicsLayer->objectName()));
|
||||
|
||||
if (m_graphic)
|
||||
str.append(QStringLiteral(" zIndex='%1'").arg(m_graphic->zIndex()));
|
||||
|
||||
std::ostringstream stream;
|
||||
stream << this->origin();
|
||||
str.append(QLatin1String(stream.str().c_str()));
|
||||
|
||||
if (!m_text.value().isEmpty())
|
||||
str.append(QStringLiteral("text=%1").arg(m_text.value()));
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
QString GraphicalObjectText::text() const
|
||||
{
|
||||
return m_text.value();
|
||||
}
|
||||
|
||||
void GraphicalObjectText::setText(const QString &text)
|
||||
{
|
||||
m_text = text;
|
||||
}
|
||||
|
||||
TextStyle GraphicalObjectText::textStyle() const
|
||||
{
|
||||
return m_textStyle.value();
|
||||
}
|
||||
TextStyle &GraphicalObjectText::rTextStyle()
|
||||
{
|
||||
return m_textStyle.refValue();
|
||||
}
|
||||
void GraphicalObjectText::setTextStyle(const TextStyle &textStyle)
|
||||
{
|
||||
m_textStyle = textStyle;
|
||||
}
|
||||
|
||||
float GraphicalObjectText::xOffset() const
|
||||
{
|
||||
return m_offset.value().x();
|
||||
}
|
||||
void GraphicalObjectText::setXOffset(float xOffset)
|
||||
{
|
||||
QPointF temp = m_offset.value();
|
||||
temp.rx() = xOffset;
|
||||
m_offset = temp;
|
||||
}
|
||||
float GraphicalObjectText::yOffset() const
|
||||
{
|
||||
return m_offset.value().y();
|
||||
}
|
||||
void GraphicalObjectText::setYOffset(float yOffset)
|
||||
{
|
||||
QPointF temp = m_offset.value();
|
||||
temp.ry() = yOffset;
|
||||
m_offset = temp;
|
||||
}
|
||||
|
||||
|
||||
bool GraphicalObjectText::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " text='" << m_text << "'"
|
||||
<< " origin =" << this->origin() // .x() << " , " << this->origin().y()
|
||||
<< " visibility=" << m_visibility;
|
||||
bool success = true;
|
||||
|
||||
// some checks:
|
||||
if (!m_graphicsLayer)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " no graphicsLayer";
|
||||
return false;
|
||||
}
|
||||
|
||||
BaseClass::create();
|
||||
|
||||
if (!m_textSymbol)
|
||||
m_textSymbol = new Esri::ArcGISRuntime::TextSymbol();
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " text='" << m_text << "'"
|
||||
<< " success=" << success
|
||||
<< " drawOrder = " << m_graphic->zIndex();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GraphicalObjectText::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " text='" << m_text << "'"
|
||||
<< " origin =" << this->origin() // .x() << " , " << this->origin().y()
|
||||
<< " visibility=" << m_visibility
|
||||
<< " m_textStyle=" << m_textStyle
|
||||
<< " offset=" << m_offset;
|
||||
|
||||
// some checks:
|
||||
if (!this->isSinglePoint())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " incorrect number of positions"
|
||||
<< " (" << this->positions().count() << ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
if (m_visibility.value())
|
||||
{
|
||||
success = create(); // create only if visible
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! BaseClass::updateViewImpl())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " updateViewImpl failed";
|
||||
}
|
||||
|
||||
// FATAL_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
// << " text='" << m_text << "'"
|
||||
// << " changed1=" << m_text.changed()
|
||||
// << " changed2="<< m_textStyle.changed();
|
||||
|
||||
bool assignTextSymbol = false;
|
||||
|
||||
// || m_visibility.changed()) -> szenario: create invisible object and make it visible
|
||||
if (m_text.changed() || m_visibility.changed())
|
||||
{
|
||||
m_textSymbol->setText(m_text.value());
|
||||
assignTextSymbol = true;
|
||||
}
|
||||
|
||||
// TextStyle to TextSymbol@ESRI :
|
||||
if (m_textStyle.changed()
|
||||
|| m_scale.changed()
|
||||
|| m_visibility.changed() // -> szenario: create invisible object and make it visible
|
||||
)
|
||||
{
|
||||
const TextStyle &textStyle = m_textStyle.value();
|
||||
m_textSymbol->setColor(textStyle.textColor());
|
||||
|
||||
// High values can lead to coredump with 'SymbolDrawHelper::create_line_image FAILED, SkBitmap is NULL or empty' -> limit
|
||||
m_textSymbol->setSize(std::min(500.0f, textStyle.size() * m_scale.value()));
|
||||
m_textSymbol->setAngle(textStyle.angle());
|
||||
|
||||
m_textSymbol->setFontFamily(textStyle.fontFamily());
|
||||
|
||||
m_textSymbol->setFontWeight(textStyle.bold() ? Esri::ArcGISRuntime::FontWeight::Bold : Esri::ArcGISRuntime::FontWeight::Normal);
|
||||
m_textSymbol->setFontStyle(textStyle.italic() ? Esri::ArcGISRuntime::FontStyle::Italic : Esri::ArcGISRuntime::FontStyle::Normal);
|
||||
|
||||
Esri::ArcGISRuntime::FontDecoration fd = Esri::ArcGISRuntime::FontDecoration::None;
|
||||
if (textStyle.underline())
|
||||
fd = Esri::ArcGISRuntime::FontDecoration::Underline;
|
||||
if (textStyle.strikeThrough())
|
||||
fd = Esri::ArcGISRuntime::FontDecoration::LineThrough;
|
||||
m_textSymbol->setFontDecoration(fd);
|
||||
|
||||
float outlineWidth = 0;
|
||||
if (textStyle.textOutlineWidth() > 0)
|
||||
outlineWidth = textStyle.textOutlineWidth() * m_scale.value();
|
||||
if (m_textSymbol->size() <= 15) // small size -> outline reduces readability :-(
|
||||
outlineWidth = 0.0;
|
||||
m_textSymbol->setHaloWidth(outlineWidth);
|
||||
|
||||
if (textStyle.textOutlineColor().isValid())
|
||||
m_textSymbol->setHaloColor(textStyle.textOutlineColor());
|
||||
|
||||
// qWarning() << " haloWidth = " << m_textSymbol->haloWidth();
|
||||
|
||||
// m_textSymbol->setHaloColor(Qt::white);
|
||||
// m_textSymbol->setHaloWidth(outlineWidth);
|
||||
|
||||
// qWarning() << " fontSize " << textStyle.size() * m_scale.value()
|
||||
// <<" (textStyle.size() " << textStyle.size()
|
||||
// << " m_scale.value() " << m_scale.value() << ")";
|
||||
|
||||
// qWarning() << " outlineWidth " << outlineWidth
|
||||
// <<" (textStyle.textOutlineWidth() " << textStyle.textOutlineWidth()
|
||||
// << " m_scale.value() " << m_scale.value() << ")";
|
||||
|
||||
// if (textStyle.backgroundColor().isValid())
|
||||
m_textSymbol->setBackgroundColor(textStyle.backgroundColor());
|
||||
|
||||
// m_textSymbol->setAntiAliased(textStyle.antiAliased());
|
||||
|
||||
m_textSymbol->setHorizontalAlignment(convert(textStyle.horizontalAlignment()));
|
||||
m_textSymbol->setVerticalAlignment(convert(textStyle.verticalAlignment()));
|
||||
|
||||
assignTextSymbol = true;
|
||||
// : TextStyle to TextSymbol@ESRI
|
||||
}
|
||||
|
||||
// || m_visibility.changed()) -> szenario: create invisible object and make it visible
|
||||
if (m_offset.changed() || m_visibility.changed())
|
||||
{
|
||||
m_textSymbol->setOffsetX(m_offset.value().x());
|
||||
m_textSymbol->setOffsetY(m_offset.value().y());
|
||||
assignTextSymbol = true;
|
||||
}
|
||||
|
||||
if (assignTextSymbol)
|
||||
m_graphic->setSymbol(m_textSymbol);
|
||||
|
||||
|
||||
// check ChangedFlags:
|
||||
// Object is created and text is invisble due to scale (meterPerPixel)
|
||||
// map is zoomed in -> text should arise, but on m_visibility is changed:
|
||||
if (m_visibility.changed() || m_positions.changed())
|
||||
{
|
||||
const Point3D &origin = this->origin();
|
||||
m_graphic->setGeometry(Esri::ArcGISRuntime::Point(origin.x(),
|
||||
origin.y(),
|
||||
origin.z(),
|
||||
spatialReference()));
|
||||
success = addUpdateGraphic();
|
||||
} // m_visibility.changed() || m_positions.changed()
|
||||
|
||||
}
|
||||
else // if visible
|
||||
{
|
||||
BaseClass::updateViewImpl();
|
||||
success = addUpdateGraphic();
|
||||
}
|
||||
|
||||
if (m_logger.isTraceEnabled())
|
||||
{
|
||||
int drawOrder = -1;
|
||||
if (m_graphic)
|
||||
drawOrder = m_graphic->zIndex();
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " text='" << m_text << "'"
|
||||
<< " success=" << success
|
||||
<< " drawOrder = " << drawOrder;
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
// << " fontFamily='" << m_textSymbol->fontFamily() << "'"
|
||||
;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Esri::ArcGISRuntime::HorizontalAlignment GraphicalObjectText::convert(const HorizontalAlignment horizontalAlignment)
|
||||
{
|
||||
Esri::ArcGISRuntime::HorizontalAlignment esriAlignmenmt =
|
||||
Esri::ArcGISRuntime::HorizontalAlignment::Left;
|
||||
switch (horizontalAlignment)
|
||||
{
|
||||
case HorizontalAlignment::Left: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Left; break;
|
||||
case HorizontalAlignment::Center: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Center; break;
|
||||
case HorizontalAlignment::Right: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Right; break;
|
||||
case HorizontalAlignment::Justify: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Justify; break;
|
||||
} // switch
|
||||
|
||||
return esriAlignmenmt;
|
||||
}
|
||||
|
||||
Esri::ArcGISRuntime::VerticalAlignment GraphicalObjectText::convert(const VerticalAlignment verticalAlignment)
|
||||
{
|
||||
Esri::ArcGISRuntime::VerticalAlignment esriAlignmenmt =
|
||||
Esri::ArcGISRuntime::VerticalAlignment::Bottom;
|
||||
switch (verticalAlignment)
|
||||
{
|
||||
case VerticalAlignment::Bottom: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Bottom; break;
|
||||
case VerticalAlignment::Middle: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Middle; break;
|
||||
case VerticalAlignment::Top: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Top; break;
|
||||
case VerticalAlignment::BaseLine: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Baseline; break;
|
||||
} // switch
|
||||
return esriAlignmenmt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GraphicalObjectText
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
#include <Map/text_style.h>
|
||||
#include <Map/situation_map_utils.h>
|
||||
#include <Common/simple_value.h>
|
||||
#include <Common/situation_map_logging.h>
|
||||
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
// forward:
|
||||
namespace Esri
|
||||
{
|
||||
namespace ArcGISRuntime
|
||||
{
|
||||
class Graphic;
|
||||
class GraphicsOverlay;
|
||||
class PictureMarkerSymbol;
|
||||
class TextSymbol;
|
||||
|
||||
enum class HorizontalAlignment;
|
||||
enum class VerticalAlignment;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
class SITUATIONMAP_EXPORT GraphicalObjectText : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
GraphicalObjectText(const Esri::ArcGISRuntime::GeoView *geoView
|
||||
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
||||
, const QString &debugInfo
|
||||
, const UniqueMapId &uniqueMapId
|
||||
);
|
||||
|
||||
~GraphicalObjectText();
|
||||
|
||||
QString toString() const override; // specialized
|
||||
|
||||
// Data access:
|
||||
QString text() const;
|
||||
void setText(const QString &text);
|
||||
|
||||
TextStyle textStyle() const;
|
||||
TextStyle &rTextStyle();
|
||||
void setTextStyle(const TextStyle &textStyle);
|
||||
|
||||
// Offset
|
||||
virtual float xOffset() const;
|
||||
virtual void setXOffset(float xOffset);
|
||||
virtual float yOffset() const;
|
||||
virtual void setYOffset(float yOffset);
|
||||
|
||||
static Esri::ArcGISRuntime::HorizontalAlignment convert(const HorizontalAlignment horizontalAlignment);
|
||||
static Esri::ArcGISRuntime::VerticalAlignment convert(const VerticalAlignment verticalAlignment);
|
||||
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
bool create() override;
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| m_text.changed()
|
||||
|| m_textStyle.changed()
|
||||
|| m_offset.changed();
|
||||
}
|
||||
|
||||
void resetChanged() override
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
m_text.reset();
|
||||
m_textStyle.reset();
|
||||
m_offset.reset();
|
||||
}
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
Esri::ArcGISRuntime::TextSymbol *m_textSymbol = nullptr;
|
||||
|
||||
SimpleValue<QString> m_text; ///< to be displayed on map
|
||||
SimpleValue<TextStyle> m_textStyle;
|
||||
SimpleValue<QPointF> m_offset; ///< Offset (pixel).
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
// Forbid some overloaded methods without effects of this object;
|
||||
virtual PositionCont positions() const override
|
||||
{
|
||||
return PositionCont();
|
||||
}
|
||||
virtual void setPositions(const PositionCont &posCont) override
|
||||
{
|
||||
Q_UNUSED(posCont);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* StubGraphicalObject
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
|
||||
#include <Map/situation_map_types.h>
|
||||
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@class StubGraphicalObject stub_graphical_object.h
|
||||
The class \c StubGraphicalObject is used as substitution for a graphical object. It does
|
||||
nothing and the purpose is only to satisfy the interface of AbstractGraphicalObject.
|
||||
@see AbstractGraphicalObject
|
||||
*/
|
||||
class StubGraphicalObject : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
explicit StubGraphicalObject()
|
||||
: AbstractGraphicalObject(nullptr, nullptr, QString(), UniqueMapId())
|
||||
{
|
||||
}
|
||||
|
||||
~StubGraphicalObject() = default;
|
||||
|
||||
StubGraphicalObject(const StubGraphicalObject &other) = delete;
|
||||
StubGraphicalObject &operator=(StubGraphicalObject &other) = delete;
|
||||
|
||||
protected:
|
||||
|
||||
bool changed() override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool updateViewImpl() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool create() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
@@ -0,0 +1,622 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* TacticalAppearance
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "tactical_appearance.h"
|
||||
#include <MapImpl/map_impl.h>
|
||||
#include <Symbology/symbol_dictionary.h>
|
||||
#include <Symbology/sidc_builder_base.h>
|
||||
#include <Symbology/sidc_codec.h>
|
||||
#include <GraphicalObjects/graphical_object_picture_marker.h>
|
||||
#include <Map/situation_map_utils.h> // operator<<
|
||||
#include <Common/simple_value.h>
|
||||
|
||||
|
||||
// ESRI
|
||||
#include <arcgis/Map.h>
|
||||
#include <arcgis/GraphicsOverlay.h>
|
||||
#include <arcgis/PolygonBuilder.h>
|
||||
#include <arcgis/PolylineBuilder.h>
|
||||
#include <arcgis/MultipointBuilder.h>
|
||||
|
||||
// Qt
|
||||
#include <QElapsedTimer>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
|
||||
class TacticalAppearance::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
~Private() = default;
|
||||
|
||||
// ESRI data:
|
||||
MapImpl *m_mapImpl = nullptr;
|
||||
QString m_logicalLayerName;
|
||||
|
||||
Esri::ArcGISRuntime::GraphicsOverlay *m_graphicOverlayTactical = nullptr;
|
||||
AdvancedSymbology::SymbolDictionary *m_dictionary = nullptr;
|
||||
AdvancedSymbology::SymbolResultWatcher m_symbolResultWatcher;
|
||||
|
||||
// OWN data:
|
||||
SimpleValue<QString> m_uniqueDesignation;
|
||||
SimpleValue<SymbolData> m_symbol;
|
||||
|
||||
|
||||
AdvancedSymbology::SymbolDataToRender m_symDataToRender;
|
||||
GraphicalObjectPictureMarker *m_pictureMarker = nullptr;
|
||||
|
||||
}; // class TacticalAppearance::Private
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
TacticalAppearance::TacticalAppearance(MapImpl *mapImpl,
|
||||
const QString &logicalLayerName,
|
||||
const QString &debugInfo,
|
||||
const UniqueMapId &uniqueMapId)
|
||||
: BaseClass(mapImpl->getEsriGeoView(), nullptr, debugInfo, uniqueMapId),
|
||||
m_logger(getLogger("TacticalAppearance")),
|
||||
d(new Private)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< ", logicalLayerName='" << logicalLayerName << "'";
|
||||
|
||||
d->m_symDataToRender.sizeL = 100;
|
||||
d->m_mapImpl = mapImpl;
|
||||
d->m_logicalLayerName = logicalLayerName;
|
||||
|
||||
if (!m_graphicsLayer && d->m_mapImpl)
|
||||
m_graphicsLayer = d->m_mapImpl->getGraphicsLayer(d->m_logicalLayerName);
|
||||
|
||||
if (!m_graphicsLayer)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " getGraphicsLayer failed";
|
||||
}
|
||||
|
||||
if (d->m_mapImpl)
|
||||
d->m_dictionary = &(d->m_mapImpl->symbolDictionary());
|
||||
|
||||
|
||||
// lambda:
|
||||
// m_symbolResultWatcher is canceled on destruction.
|
||||
// So it`s safe that no signal will be fired afterwards.
|
||||
// To avoid CLang warnings use m_symbolResultWatcher as context (3rd para), although it´s not intended.
|
||||
// Better idea?
|
||||
QObject::connect(&d->m_symbolResultWatcher, &AdvancedSymbology::SymbolResultWatcher::resultReady, &d->m_symbolResultWatcher, [this]()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " resultReady...";
|
||||
|
||||
QSharedPointer<AdvancedSymbology::SymbolResult> symResult = d->m_symbolResultWatcher.symbolResult();
|
||||
if (! symResult)
|
||||
return; // should NEVER happen! (Which object should have triggered the signal???)
|
||||
|
||||
if (d->m_pictureMarker)
|
||||
{
|
||||
d->m_pictureMarker->setImage(symResult->symbolImage().image());
|
||||
d->m_pictureMarker->updateView();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
TacticalAppearance::~TacticalAppearance()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
// abort pending call to SymbolDictionary::findSymbol:
|
||||
d->m_symbolResultWatcher.cancel();
|
||||
|
||||
delete d->m_pictureMarker;
|
||||
d->m_pictureMarker = nullptr;
|
||||
|
||||
removeGraphicFromGraphicOverlayTactical();
|
||||
|
||||
delete d;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void TacticalAppearance::removeGraphicFromGraphicOverlayTactical()
|
||||
{
|
||||
if (m_logger.isTraceEnabled())
|
||||
{
|
||||
if (m_graphic)
|
||||
{
|
||||
Esri::ArcGISRuntime::GraphicsOverlay *gOverlay = m_graphic->graphicsOverlay();
|
||||
if (gOverlay)
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START debugInfo='" << m_debugInfo << "'" << " name = '" << gOverlay->overlayId() << "'";
|
||||
}
|
||||
}
|
||||
|
||||
if (m_graphic && d->m_graphicOverlayTactical && d->m_graphicOverlayTactical->graphics())
|
||||
d->m_graphicOverlayTactical->graphics()->removeOne(m_graphic);
|
||||
|
||||
delete m_graphic;
|
||||
m_graphic = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool TacticalAppearance::useDictionaryRenderMode(const AdvancedSymbology::GeometryType &geomType) const
|
||||
{
|
||||
bool usePictureMarker = isSinglePoint() && (AdvancedSymbology::GeometryType::Point == geomType || AdvancedSymbology::GeometryType::Undefined == geomType);
|
||||
return !usePictureMarker || symbol().useAlwaysDictionaryRenderer;
|
||||
} // bool TacticalAppearance::useDictionaryRenderMode() const
|
||||
|
||||
|
||||
bool TacticalAppearance::create()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_visibility = " << m_visibility;
|
||||
|
||||
bool success = true;
|
||||
|
||||
//
|
||||
// Prepare / create :
|
||||
//
|
||||
// a) singlePoint / exactly one coordinate -> use pictureMarker
|
||||
// or
|
||||
// b) multiPoint / more than one coordinate -> m_graphic / DictionaryRenderer
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* This assumption doesn't work any more because some polyline and polygon symbols will have only one
|
||||
* anchor point and the real geometry is defined by additional attributes like radius, with, length ...
|
||||
*
|
||||
* JT 2016/12/20
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
if (m_graphicsLayer && m_visibility.value())
|
||||
{
|
||||
const SymbolData &symbolData_ref = d->m_symbol.value();
|
||||
const QString &baseSymbolCode = AdvancedSymbology::SidcBuilderBase::concreteSidcToBaseSymbolCode(symbolData_ref.sidc);
|
||||
const AdvancedSymbology::SymbolProperties &symbolProperties = d->m_dictionary->symbolProperties(baseSymbolCode);
|
||||
AdvancedSymbology::GeometryType geomType = symbolProperties.geometryType();
|
||||
|
||||
if (useDictionaryRenderMode(geomType))
|
||||
{
|
||||
if (!d->m_graphicOverlayTactical)
|
||||
d->m_graphicOverlayTactical = d->m_mapImpl->getGraphicsLayerDict(d->m_logicalLayerName);
|
||||
|
||||
if (!d->m_graphicOverlayTactical)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " getGraphicsLayerDict failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_graphic)
|
||||
{
|
||||
m_graphic = new Esri::ArcGISRuntime::Graphic();
|
||||
m_graphic->setObjectName(m_debugInfo);
|
||||
m_graphic->setZIndex(m_drawOrder.value());
|
||||
|
||||
// use attributeModel to store application obj id (SimWorld) at graphic
|
||||
Esri::ArcGISRuntime::AttributeListModel *attLisModel = m_graphic->attributes();
|
||||
if (attLisModel)
|
||||
attLisModel->insertAttribute(QLatin1String(SituationMap::UniqueMapIdAttribute), m_uniqueMapId);
|
||||
else
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no AttributeListModel, debugInfo='" << m_debugInfo << "'" << " uniqueMapId=" << m_uniqueMapId;
|
||||
|
||||
// Adding an empty graphic leads to Segmentation fault.
|
||||
// (in Esri_runtimecore::Map_renderer::Dictionary_renderer::derive_geometry)
|
||||
|
||||
bool successGraphic = addUpdateGraphic(); // CHECK
|
||||
if (!successGraphic)
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " addUpdateGraphic failed, debugInfo='" << m_debugInfo << "'" << " uniqueMapId=" << m_uniqueMapId;
|
||||
|
||||
} // if (!m_graphic)
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_graphic is needless now:
|
||||
removeGraphicFromGraphicOverlayTactical();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// : Prepare / create
|
||||
|
||||
bool positionsEmpty = m_positions.value().isEmpty();
|
||||
if (positionsEmpty)
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " positions empty";
|
||||
|
||||
success = success && !positionsEmpty;
|
||||
|
||||
if (!success)
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " create failed";
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
return success;
|
||||
}
|
||||
|
||||
void TacticalAppearance::createPictureMarker()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
if (!d->m_pictureMarker && d->m_mapImpl)
|
||||
{
|
||||
d->m_pictureMarker = new GraphicalObjectPictureMarker(d->m_mapImpl->getEsriGeoView()
|
||||
, m_graphicsLayer
|
||||
, m_debugInfo + QLatin1String("#PicMarkTacticalAppearance")
|
||||
, m_uniqueMapId);
|
||||
}
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
void TacticalAppearance::removePictureMarker()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
||||
delete d->m_pictureMarker;
|
||||
d->m_pictureMarker = nullptr;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
||||
}
|
||||
|
||||
QString TacticalAppearance::uniqueDesignation() const
|
||||
{
|
||||
return d->m_uniqueDesignation.value();
|
||||
}
|
||||
void TacticalAppearance::setUniqueDesignation(const QString &uniqueDesignation)
|
||||
{
|
||||
d->m_uniqueDesignation = uniqueDesignation;
|
||||
}
|
||||
|
||||
SymbolImage TacticalAppearance::symbolImage() const
|
||||
{
|
||||
SymbolImage symImage;
|
||||
if (d->m_pictureMarker)
|
||||
{
|
||||
symImage.setImage(d->m_pictureMarker->image());
|
||||
symImage.setValid(!symImage.image().isNull());
|
||||
}
|
||||
return symImage;
|
||||
}
|
||||
|
||||
|
||||
SymbolData TacticalAppearance::symbol() const
|
||||
{
|
||||
return d->m_symbol.value();
|
||||
}
|
||||
|
||||
void TacticalAppearance::setSymbol(const SymbolData &symbol)
|
||||
{
|
||||
d->m_symbol = symbol;
|
||||
}
|
||||
|
||||
bool TacticalAppearance::changed()
|
||||
{
|
||||
return BaseClass::changed()
|
||||
|| d->m_uniqueDesignation.changed()
|
||||
|| d->m_symbol.changed();
|
||||
}
|
||||
void TacticalAppearance::resetChanged()
|
||||
{
|
||||
BaseClass::resetChanged();
|
||||
d->m_uniqueDesignation.reset();
|
||||
d->m_symbol.reset();
|
||||
}
|
||||
|
||||
Esri::ArcGISRuntime::Geometry TacticalAppearance::getGraphicGeometry() const
|
||||
{
|
||||
if (d->m_pictureMarker) return d->m_pictureMarker->getGraphicGeometry();
|
||||
if (m_graphic) return m_graphic->geometry();
|
||||
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Geometry is undefined";
|
||||
|
||||
return Esri::ArcGISRuntime::Geometry();
|
||||
} // Esri::ArcGISRuntime::Geometry TacticalAppearance::getGraphicGeometry() const
|
||||
|
||||
|
||||
bool TacticalAppearance::updateViewImpl()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< " symbol='" << d->m_symbol.value().sidc << "'"
|
||||
<< " visibility=" << m_visibility
|
||||
<< " selected=" << m_selected
|
||||
<< " origin=" << this->origin()
|
||||
<< " scale=" << m_scale.value();
|
||||
|
||||
const SymbolData &symbolData_ref = d->m_symbol.value();
|
||||
const QString &baseSymbolCode = AdvancedSymbology::SidcBuilderBase::concreteSidcToBaseSymbolCode(symbolData_ref.sidc);
|
||||
const AdvancedSymbology::SymbolProperties &symbolProperties = d->m_dictionary->symbolProperties(baseSymbolCode);
|
||||
AdvancedSymbology::GeometryType geomType = symbolProperties.geometryType();
|
||||
|
||||
if (geomType == AdvancedSymbology::GeometryType::Undefined)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " GeometryType::Undefined, symbolProperties failed!?!";
|
||||
return false;
|
||||
}
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
||||
<< ", geomType=" << geomType
|
||||
<< ", useDictionaryRenderMode(geomType)=" << useDictionaryRenderMode(geomType);
|
||||
|
||||
bool success = create();
|
||||
|
||||
if (!success)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " create failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (useDictionaryRenderMode(geomType))
|
||||
{
|
||||
// real work:
|
||||
if (m_positions.changed() || d->m_symbol.changed() || m_visibility.changed())
|
||||
{
|
||||
auto buildPointClusterGeometry = [this]() -> Esri::ArcGISRuntime::Geometry
|
||||
{
|
||||
QSharedPointer<Esri::ArcGISRuntime::MultipointBuilder> builder(new Esri::ArcGISRuntime::MultipointBuilder(spatialReference()));
|
||||
Esri::ArcGISRuntime::PointCollection points(spatialReference());
|
||||
const auto posCont = positions();
|
||||
for (const auto &pos : posCont)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " addPoint:" << pos.x() << " - " << pos.y();
|
||||
points.addPoint(pos.x(), pos.y());
|
||||
}
|
||||
builder->setPoints(&points);
|
||||
return builder->toGeometry();
|
||||
}; // buildPointClusterGeometry
|
||||
|
||||
Esri::ArcGISRuntime::Geometry geom;
|
||||
|
||||
switch (geomType)
|
||||
{
|
||||
case AdvancedSymbology::GeometryType::Undefined : break;
|
||||
|
||||
case AdvancedSymbology::GeometryType::Point :
|
||||
case AdvancedSymbology::GeometryType::Polyline :
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " m_positions.count()=" << m_positions.value().count();
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* If a PolylineBuilder is used here to create symbol geometry the construction appropriate symbol standard (MIL2525C / MIL2525D / App6)
|
||||
* will not be done and the symbol is always a simple polyline. Using MultipointBuilder to build symbol geometry the result is based on
|
||||
* underlying symbol standard.
|
||||
* 2016/12/9 JT
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
geom = buildPointClusterGeometry();
|
||||
|
||||
} break;
|
||||
|
||||
case AdvancedSymbology::GeometryType::Polygon :
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " m_positions.count()=" << m_positions.value().count();
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* Some symbols have polygon geometry and could have only one or two positions. In case of less than 3 positions do the same as for
|
||||
* polylines and use MultipointBuilder to create the symbol geometry. In other case use PolygonBuilder.
|
||||
* 2016/12/13 JT
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
if (positions().size() > 2)
|
||||
{
|
||||
QSharedPointer<Esri::ArcGISRuntime::PolygonBuilder> builder(new Esri::ArcGISRuntime::PolygonBuilder(spatialReference()));
|
||||
const auto posCont = positions();
|
||||
for (const auto &pos : posCont)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " addPoint:" << pos.x() << " - " << pos.y();
|
||||
builder->addPoint(pos.x(), pos.y());
|
||||
}
|
||||
geom = builder->toGeometry();
|
||||
}
|
||||
else
|
||||
geom = buildPointClusterGeometry();
|
||||
|
||||
} break;
|
||||
|
||||
} // switch
|
||||
|
||||
if (geom.isEmpty())
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " Geometry NOT OK -> fallback symbol" << " (geometryType was " << geomType << ")";
|
||||
createPictureMarker();
|
||||
d->m_pictureMarker->setDebugInfo(m_debugInfo + QLatin1String("#fallback"));
|
||||
|
||||
int size = symbolData_ref.size;
|
||||
if (size < 10) size = 10;
|
||||
if (size > 100) size = 100;
|
||||
|
||||
d->m_pictureMarker->setMarkerSymbol(MarkerSymbolType::Diamond, size, symbolData_ref.color);
|
||||
d->m_pictureMarker->setOrigin(this->origin());
|
||||
d->m_pictureMarker->setDrawOrder(m_drawOrder.value());
|
||||
d->m_pictureMarker->updateView();
|
||||
success = false;
|
||||
}
|
||||
else // geom is not empty
|
||||
{
|
||||
removePictureMarker();
|
||||
|
||||
if (m_graphic)
|
||||
{
|
||||
success = true;
|
||||
|
||||
// move to graphic:
|
||||
m_graphic->setGeometry(geom);
|
||||
|
||||
// prepare rawAttributes for DictionaryRenderer:
|
||||
|
||||
QVariantMap rawAttributes = d->m_symbol.value().attributeMap;
|
||||
|
||||
// build from scratch to honor removed attributes:
|
||||
// (Otherwise the will remain wrongly)
|
||||
|
||||
rawAttributes[QLatin1String(SituationMap::UniqueMapIdAttribute)] = m_uniqueMapId;
|
||||
rawAttributes[QLatin1String(SituationMap::IsPickableAttribute)] = m_pickable.value(); // set pickable attribute JT 2016/12/21
|
||||
|
||||
rawAttributes[QLatin1String("_type")] = QLatin1String("position_report");
|
||||
rawAttributes[QLatin1String("_action")] = QLatin1String("update");
|
||||
rawAttributes[QLatin1String("sidc")] = AdvancedSymbology::SidcCodec::decodeRawSidc(d->m_symbol.value().sidc); // in case of MIL2525
|
||||
rawAttributes[QLatin1String("sic")] = AdvancedSymbology::SidcCodec::decodeRawSidc(d->m_symbol.value().sidc); // in case of APP6
|
||||
|
||||
Esri::ArcGISRuntime::AttributeListModel * attributeModel = m_graphic->attributes();
|
||||
if (attributeModel)
|
||||
attributeModel->setAttributesMap(rawAttributes);
|
||||
else
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'" << " no AttributeListModel";
|
||||
|
||||
|
||||
|
||||
// // prepare rawAttributes for DictionaryRenderer:
|
||||
// QVariantMap rawAttributes = d->m_symbol.value().attributeMap;
|
||||
|
||||
// rawAttributes[QLatin1String(SituationMap::IsPickableAttribute)] = m_pickable.value(); // set pickable attribute JT 2016/12/21
|
||||
|
||||
// rawAttributes[QLatin1String("_type")] = QLatin1String("position_report");
|
||||
// rawAttributes[QLatin1String("_action")] = QLatin1String("update");
|
||||
// rawAttributes[QLatin1String("sidc")] = AdvancedSymbology::SidcCodec::decodeRawSidc(d->m_symbol.value().sidc); // in case of MIL2525
|
||||
// rawAttributes[QLatin1String("sic")] = AdvancedSymbology::SidcCodec::decodeRawSidc(d->m_symbol.value().sidc); // in case of APP6
|
||||
// // move to graphic:
|
||||
// m_graphic->setGeometry(geom);
|
||||
|
||||
// /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// * Replace:
|
||||
// * m_graphic->attributes()->setAttributesMap(rawAttributes);
|
||||
// *
|
||||
// * because it doesn't work anymore in ArcGISRuntime V100.2
|
||||
// * JT, 2018/01/24
|
||||
// * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
// Esri::ArcGISRuntime::AttributeListModel * attributeModel = m_graphic->attributes();
|
||||
// if (attributeModel)
|
||||
// {
|
||||
// if (!attributeModel->isEmpty())
|
||||
// {
|
||||
// for (auto it = rawAttributes.cbegin(); it != rawAttributes.cend(); ++it)
|
||||
// {
|
||||
// const QString &attrKey = it.key();
|
||||
// if (attributeModel->containsAttribute(attrKey))
|
||||
// {
|
||||
// attributeModel->replaceAttribute(attrKey, rawAttributes[attrKey]);
|
||||
// continue;
|
||||
// }
|
||||
// attributeModel->insertAttribute(attrKey, rawAttributes[attrKey]);
|
||||
// }
|
||||
// }
|
||||
// else attributeModel->setAttributesMap(rawAttributes);
|
||||
// }
|
||||
|
||||
// 2021-08, N. Thoden
|
||||
// While switching back to the behaviour that one logical layer has
|
||||
// 1st getGraphicsLayer and 2nd getGraphicsLayerDict [GUEZE-496],
|
||||
// the tactical appereance of DangerArea and similar disappears.
|
||||
// Reason: m_graphicsLayer and m_graphicOverlayTactical are different now!
|
||||
// It seems like that in former versions (< V100.8) the graphic could
|
||||
// be added to more than one Esri layer.
|
||||
// Now (V100.8) adding to a second layer fails.
|
||||
// But we can remove the m_graphic from the default m_graphicsLayer
|
||||
// before adding the the desired one: m_graphicOverlayTactical
|
||||
if (m_graphicsLayer->graphics()->contains(m_graphic))
|
||||
m_graphicsLayer->graphics()->removeOne(m_graphic);
|
||||
|
||||
// add to graphicOverlayTactical:
|
||||
if (! d->m_graphicOverlayTactical->graphics()->contains(m_graphic))
|
||||
d->m_graphicOverlayTactical->graphics()->append(m_graphic);
|
||||
|
||||
bool successGraphic = d->m_graphicOverlayTactical->graphics()->contains(m_graphic);
|
||||
if (!successGraphic)
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " m_graphic not added to m_graphicOverlayTactical";
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " no m_graphic";
|
||||
// success = false;
|
||||
success = true; // if the DictionaryRenderer is used, m_graphic is null and that is ok.
|
||||
}
|
||||
|
||||
} // if (geom.isEmpty())
|
||||
}
|
||||
|
||||
}
|
||||
else // !useDictionaryRenderMode(geomType)
|
||||
{
|
||||
createPictureMarker();
|
||||
d->m_pictureMarker->setOrigin(this->origin());
|
||||
|
||||
// real work:
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " update geometry";
|
||||
|
||||
|
||||
if (d->m_symbol.changed() || m_scale.changed())
|
||||
{
|
||||
if (d->m_dictionary)
|
||||
{
|
||||
int widthPixel = SituationMap::SymbolSizeLdefault;
|
||||
widthPixel *= symbolData_ref.size * m_scale.value();
|
||||
|
||||
d->m_symDataToRender.sidc = symbolData_ref.sidc;
|
||||
d->m_symDataToRender.fillColor = symbolData_ref.color;
|
||||
d->m_symDataToRender.fillColorReplace = true;
|
||||
d->m_symDataToRender.sizeL = widthPixel;
|
||||
|
||||
if (d->m_pictureMarker->image().isNull())
|
||||
d->m_pictureMarker->setImage(d->m_dictionary->temporaryImage(d->m_symDataToRender.sizeL));
|
||||
d->m_symbolResultWatcher.setSymbolResult(d->m_dictionary->fetchSymbol(d->m_symDataToRender));
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
||||
<< " visibility=" << m_visibility
|
||||
<< " no dictionary";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (d->m_pictureMarker)
|
||||
{
|
||||
d->m_pictureMarker->setDrawOrder(m_drawOrder.value());
|
||||
d->m_pictureMarker->setVisibility(m_visibility.value());
|
||||
d->m_pictureMarker->setSelected(m_selected.value());
|
||||
d->m_pictureMarker->setPickable(m_pickable.value());
|
||||
|
||||
success = success && d->m_pictureMarker->updateView();
|
||||
}
|
||||
} // else !useDictionaryRenderMode(geomType)
|
||||
|
||||
|
||||
if (d->m_pictureMarker)
|
||||
{
|
||||
d->m_pictureMarker->setOrigin(this->origin()); // to avoid incorrect number of positions..
|
||||
d->m_pictureMarker->setVisibility(m_visibility.value());
|
||||
d->m_pictureMarker->setSelected(m_selected.value());
|
||||
success = d->m_pictureMarker->updateView() && success;
|
||||
}
|
||||
|
||||
// in case of no pictureMarker:
|
||||
if (m_graphic)
|
||||
{
|
||||
m_graphic->setZIndex(m_drawOrder.value());
|
||||
m_graphic->setVisible(m_visibility.value());
|
||||
m_graphic->setSelected(m_selected.value());
|
||||
}
|
||||
|
||||
// reset flags
|
||||
d->m_symbol.reset();
|
||||
|
||||
if (!success)
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " failure, debugInfo='" << m_debugInfo << "'";
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
||||
<< " success = " << success
|
||||
<< " visibility=" << m_visibility;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
} // namespace SituationMap
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* TacticalAppearance
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Own
|
||||
#include "abstract_graphical_object.h"
|
||||
|
||||
// Esri
|
||||
|
||||
|
||||
// Qt
|
||||
|
||||
|
||||
// forward:
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
// forward:
|
||||
class MapImpl;
|
||||
class GraphicalObjectPictureMarker;
|
||||
|
||||
|
||||
/**
|
||||
* @brief The TacticalAppearance class displays sidcs.
|
||||
* To do so, the number of coordinate lead to use
|
||||
* - the GraphicalObjectPictureMarker (exactly one coordinate)
|
||||
* or
|
||||
* - the Message (more than one coordinate)
|
||||
*
|
||||
* Use cases:
|
||||
* - Participant: sidc with #coords == 1, TacticalAppearance should get exactly one coordinate.
|
||||
* (GraphicalObjectPictureMarker on ESRI::GraphicsLayer is used)
|
||||
* - Tactical display of a Building: sidc #coords >= 2, TacticalAppearance should get list of positions.
|
||||
* (Message on ESRI::MessageGroupLayer is used)
|
||||
* - (Tactical) PreviewIcon of a Building: sidc #coords == 1, TacticalAppearance should get exactly one coordinate.
|
||||
* (GraphicalObjectPictureMarker on ESRI::GraphicsLayer is used)
|
||||
* - Tactical symbols of plan editor
|
||||
*
|
||||
* In case of GraphicalObjectPictureMarker the image creation is done by AdvancedSymbology::SymbolDictionary::symbolImageBySidcExtended().
|
||||
*/
|
||||
class SITUATIONMAP_EXPORT TacticalAppearance : public AbstractGraphicalObject
|
||||
{
|
||||
|
||||
using BaseClass = AbstractGraphicalObject;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief TacticalAppearance
|
||||
* @param mapImpl map to be used.
|
||||
* @param logicalLayerName logical layer name to be used.
|
||||
* @param debugInfo debugInfo to be used
|
||||
* @param uniqueMapId uniqueMapId to be used. (Optional to fulfill rubberband requirements)
|
||||
*/
|
||||
TacticalAppearance(MapImpl *mapImpl,
|
||||
const QString &logicalLayerName,
|
||||
const QString &debugInfo,
|
||||
const UniqueMapId &uniqueMapId = INVALID_MAP_ID);
|
||||
|
||||
TacticalAppearance(const TacticalAppearance &other) = delete;
|
||||
TacticalAppearance &operator=(TacticalAppearance &other) = delete;
|
||||
|
||||
virtual ~TacticalAppearance();
|
||||
|
||||
|
||||
SymbolData symbol() const;
|
||||
void setSymbol(const SymbolData &symbol);
|
||||
|
||||
QString uniqueDesignation() const;
|
||||
void setUniqueDesignation(const QString &uniqueDesignation);
|
||||
|
||||
|
||||
SymbolImage symbolImage() const;
|
||||
|
||||
Esri::ArcGISRuntime::Geometry getGraphicGeometry() const override;
|
||||
|
||||
protected:
|
||||
// Internal/Admin
|
||||
virtual bool create() override;
|
||||
virtual void createPictureMarker();
|
||||
virtual void removePictureMarker();
|
||||
|
||||
void removeGraphicFromGraphicOverlayTactical();
|
||||
|
||||
bool changed() override;
|
||||
void resetChanged() override;
|
||||
|
||||
|
||||
bool updateViewImpl() override;
|
||||
|
||||
bool useDictionaryRenderMode(const AdvancedSymbology::GeometryType &geomType) const;
|
||||
|
||||
// logical
|
||||
|
||||
private:
|
||||
LOGGER_T m_logger; ///< Interface of the Logging-Facility
|
||||
|
||||
class Private;
|
||||
/**
|
||||
* The private d-pointer to not break BC when changing internals of this class
|
||||
*/
|
||||
Private *d = nullptr;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
Reference in new issue
Block a user