Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
Executable
+499
@@ -0,0 +1,499 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Class to translate, scale and rotate geoemtry.
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** 01.07.2016, JT : First edition for use with Qt5
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "plan_editor.h"
|
||||
#include "logging.h"
|
||||
|
||||
|
||||
|
||||
#include <Map/situation_map_types.h>
|
||||
#include <Map/coord_translation_functor.h>
|
||||
#include <Map/map.h>
|
||||
#include <Map/geometry_model_renderer.h>
|
||||
|
||||
#include <Rubberbands/rubberband_factory.h>
|
||||
|
||||
#include <GeometryModel/geometry_model_factory.h>
|
||||
#include <GeometryModel/geometry_node_visitor.h>
|
||||
|
||||
#include <MathUtils/math_const.h>
|
||||
#include <MathUtils/simple_helper.h>
|
||||
#include <MathUtils/matrix2d.h>
|
||||
|
||||
#include <QtCore/QList>
|
||||
|
||||
#include <QtWidgets/QGraphicsView>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
class Map;
|
||||
class GeometryModel;
|
||||
|
||||
namespace RB { class RubberbandTransform; }
|
||||
|
||||
} // namespace SituationMap
|
||||
|
||||
namespace PlanEditor
|
||||
{
|
||||
|
||||
const unsigned int RubberbandMinPixelSize = 20;
|
||||
|
||||
template<class RubberbandClass> class GeometryPlacer : public QObject
|
||||
{
|
||||
public:
|
||||
|
||||
static RubberbandClass *create(PlanEditor *planEditor
|
||||
, SituationMap::Map *map
|
||||
, SituationMap::GeometryModel *geoModel
|
||||
, const QList<SituationMap::UniqueMapId> &uidList
|
||||
, QObject *parent);
|
||||
|
||||
bool isValid() const { return (m_previewGeoModel != nullptr); }
|
||||
|
||||
void changeStyleAttributes();
|
||||
|
||||
private:
|
||||
|
||||
GeometryPlacer(PlanEditor *planEditor, SituationMap::Map *map, SituationMap::GeometryModel *, const QList<SituationMap::UniqueMapId> &, QObject *parent);
|
||||
virtual ~GeometryPlacer();
|
||||
|
||||
void applyTransform(SituationMap::GeometryModel *geoModel);
|
||||
void abortTransform();
|
||||
|
||||
void previewTransform(SituationMap::Map *map, const SituationMap::MathUtils::Matrix2D &mat);
|
||||
void previewTransform(SituationMap::Map *map, const SituationMap::MathUtils::Matrix2D &mat, const SituationMap::GeometryModel::Node &node);
|
||||
|
||||
void adjustEllipse(SituationMap::GeometryModel *geoModel, const SituationMap::GeometryModel::Node &p, const QList<QPointF> &v);
|
||||
|
||||
PlanEditor *m_planEditor;
|
||||
QPointer<SituationMap::Map> m_map;
|
||||
SituationMap::GeometryModel *m_previewGeoModel;
|
||||
SituationMap::GeometryModelRenderer *m_previewGeoModelRenderer;
|
||||
QList<SituationMap::UniqueMapId> m_uidList;
|
||||
RubberbandClass *m_rubberband;
|
||||
|
||||
Logger &m_logger;
|
||||
|
||||
}; // template<class RubberbandClass> class GeometryPlacer
|
||||
|
||||
|
||||
template<class RubberbandClass> RubberbandClass *GeometryPlacer<RubberbandClass>::create(PlanEditor *planEditor
|
||||
, SituationMap::Map *map
|
||||
, SituationMap::GeometryModel *geoModel
|
||||
, const QList<SituationMap::UniqueMapId> &uidList
|
||||
, QObject *parent)
|
||||
{
|
||||
if (!std::is_base_of<SituationMap::RB::RubberbandTransform, RubberbandClass>::value) return nullptr;
|
||||
|
||||
GeometryPlacer<RubberbandClass> *gP = new GeometryPlacer<RubberbandClass>(planEditor, map, geoModel, uidList, parent);
|
||||
|
||||
if (gP == nullptr) return nullptr;
|
||||
if (!gP->isValid())
|
||||
{
|
||||
delete gP;
|
||||
gP = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
return gP->m_rubberband;
|
||||
} // RubberbandClass * GeometryPlacer<RubberbandClass>::create()
|
||||
|
||||
|
||||
static const char *const PreviewLayer = "PlanEditorPreview";
|
||||
|
||||
template<class RubberbandClass> GeometryPlacer<RubberbandClass>::GeometryPlacer(PlanEditor *planEditor
|
||||
, SituationMap::Map *map
|
||||
, SituationMap::GeometryModel *geoModel
|
||||
, const QList<SituationMap::UniqueMapId> &uidList
|
||||
, QObject *parent)
|
||||
: m_planEditor(planEditor)
|
||||
, m_map(map)
|
||||
, m_previewGeoModel(nullptr)
|
||||
, m_previewGeoModelRenderer(nullptr)
|
||||
, m_uidList()
|
||||
, m_rubberband(nullptr)
|
||||
, m_logger(getLogger("PlanEditor-GeometryPlacer"))
|
||||
|
||||
{
|
||||
|
||||
if (uidList.isEmpty()) return;
|
||||
|
||||
// first get bounding box of all selected features
|
||||
|
||||
m_previewGeoModel = SituationMap::GeometryModelFactory::singleton()->create();
|
||||
|
||||
qreal xmin = std::numeric_limits<qreal>::infinity();
|
||||
qreal xmax = -std::numeric_limits<qreal>::infinity();
|
||||
qreal ymin = std::numeric_limits<qreal>::infinity();
|
||||
qreal ymax = -std::numeric_limits<qreal>::infinity();
|
||||
|
||||
m_uidList.reserve(uidList.size());
|
||||
for (SituationMap::UniqueMapId uid : uidList)
|
||||
{
|
||||
const SituationMap::GeometryModel::Node &modelPrimitive = geoModel->findPrimitive(uid);
|
||||
if (modelPrimitive.isValid())
|
||||
{
|
||||
const QList<QPointF> &vertexList = geoModel->getPrimitivePoints(modelPrimitive);
|
||||
|
||||
for (const QPointF &p : vertexList )
|
||||
{
|
||||
if (p.x() < xmin) xmin = p.x();
|
||||
if (p.x() > xmax) xmax = p.x();
|
||||
if (p.y() < ymin) ymin = p.y();
|
||||
if (p.y() > ymax) ymax = p.y();
|
||||
}
|
||||
|
||||
if (!vertexList.empty())
|
||||
{
|
||||
m_uidList << uid;
|
||||
|
||||
m_previewGeoModel->copy(modelPrimitive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_uidList.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << LOGFUNCTION << "Object list of GeometryPlacer is empty.";
|
||||
return;
|
||||
}
|
||||
|
||||
if ((!std::isfinite(xmin)) && (!std::isfinite(ymin)) && (!std::isfinite(xmax)) && (!std::isfinite(ymax)))
|
||||
{
|
||||
// Huch, oh, oh, oh
|
||||
// This should not happen, can't get a valid bounding box
|
||||
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << "Can't determine bounding box of selected features";
|
||||
|
||||
#ifdef LTS_DEBUG
|
||||
|
||||
// We want to find the reason why something is going wrong here. Let's go on with
|
||||
// debugging here. Do it only in case of LTS_DEBUG is defined. Keep in mind that
|
||||
// NDEBUG is all ways defined because we compile release with debug information for
|
||||
// debugging too. As result the assert macro doesn't work here.
|
||||
|
||||
throw std::range_error("Infinte bounding box, abort GeometryPlacer"); // Juhu, let's crash here.
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
previewTransform(map, SituationMap::MathUtils::Matrix2D());
|
||||
|
||||
|
||||
QPointF minCorner(xmin, ymin);
|
||||
QPointF maxCorner(xmax, ymax);
|
||||
|
||||
minCorner = map->geoCoordinateToViewPortWindowPoint(minCorner);
|
||||
maxCorner = map->geoCoordinateToViewPortWindowPoint(maxCorner);
|
||||
|
||||
qreal pixelWidth = maxCorner.x() - minCorner.x();
|
||||
qreal pixelHeight = maxCorner.y() - minCorner.y();
|
||||
|
||||
bool isMinSize = false;
|
||||
|
||||
if (fabs(pixelWidth) < RubberbandMinPixelSize)
|
||||
{
|
||||
qreal centerX = (minCorner.x() + maxCorner.x()) * 0.5;
|
||||
qreal dx = RubberbandMinPixelSize * 0.5;
|
||||
|
||||
dx = (pixelWidth < 0) ? -dx : dx;
|
||||
|
||||
minCorner.setX(centerX - dx);
|
||||
maxCorner.setX(centerX + dx);
|
||||
|
||||
isMinSize = true;
|
||||
}
|
||||
|
||||
if (fabs(pixelHeight) < RubberbandMinPixelSize)
|
||||
{
|
||||
qreal centerY = (minCorner.y() + maxCorner.y()) * 0.5;
|
||||
qreal dy = RubberbandMinPixelSize * 0.5;
|
||||
|
||||
dy = (pixelHeight < 0) ? -dy : dy;
|
||||
|
||||
minCorner.setY(centerY - dy);
|
||||
maxCorner.setY(centerY + dy);
|
||||
|
||||
isMinSize = true;
|
||||
}
|
||||
|
||||
if (isMinSize)
|
||||
{
|
||||
minCorner = map->viewPortWindowPointToGeoCoordinate(minCorner);
|
||||
maxCorner = map->viewPortWindowPointToGeoCoordinate(maxCorner);
|
||||
|
||||
xmin = minCorner.x();
|
||||
ymin = minCorner.y();
|
||||
xmax = maxCorner.x();
|
||||
ymax = maxCorner.y();
|
||||
}
|
||||
|
||||
m_rubberband = dynamic_cast<RubberbandClass *>(map->rubberbandFactory().create<RubberbandClass>(parent));
|
||||
|
||||
if (m_rubberband)
|
||||
{
|
||||
map->layerFactory().addOverlayLayer(QLatin1String(PreviewLayer), QLatin1String(PreviewLayer));
|
||||
|
||||
m_previewGeoModelRenderer = map->createGeometryModelRenderer(QLatin1String(PreviewLayer), m_previewGeoModel);
|
||||
|
||||
m_rubberband->setAutoDelete(true);
|
||||
|
||||
QVector<QPointF> vertexVector(4);
|
||||
|
||||
vertexVector[0] = QPointF(xmin, ymin);
|
||||
vertexVector[1] = QPointF(xmax, ymin);
|
||||
vertexVector[2] = QPointF(xmax, ymax);
|
||||
vertexVector[3] = QPointF(xmin, ymax);
|
||||
|
||||
m_rubberband->rectangleVerticies(vertexVector);
|
||||
|
||||
QObject::connect(m_rubberband, &SituationMap::RB::Rubberband::apply, this, [this, geoModel]() { applyTransform(geoModel); });
|
||||
QObject::connect(m_rubberband, &SituationMap::RB::Rubberband::abort, this, [this]() { abortTransform(); });
|
||||
QObject::connect(m_rubberband, &SituationMap::RB::Rubberband::finished, this, [this]() { delete this; });
|
||||
|
||||
QObject::connect(m_rubberband, &SituationMap::RB::RubberbandTransform::updatePreview
|
||||
, this, [this, map](SituationMap::RB::Rubberband *, const SituationMap::MathUtils::Matrix2D & mat) { previewTransform(map, mat); });
|
||||
|
||||
m_rubberband->setUserData(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete m_previewGeoModel;
|
||||
m_previewGeoModel = nullptr;
|
||||
}
|
||||
|
||||
} // template<class RubberbandClass> GeometryPlacer::GeometryPlayer( SituationMap::GeometryModel & )
|
||||
|
||||
|
||||
class ChangeStyleVisitor : public SituationMap::GeometryNodeVisitor
|
||||
{
|
||||
PlanEditor *m_planEditor;
|
||||
|
||||
bool apply(SituationMap::GeometryModel *, const SituationMap::GeometryModel::Node &node, SituationMap::GeometryModel::PrimitiveType nodeType) override
|
||||
{
|
||||
switch (nodeType)
|
||||
{
|
||||
case SituationMap::GeometryModel::PrimitiveType::MapDefaults : break;
|
||||
case SituationMap::GeometryModel::PrimitiveType::Node : break;
|
||||
case SituationMap::GeometryModel::PrimitiveType::RootNode : break;
|
||||
case SituationMap::GeometryModel::PrimitiveType::Unknown : break;
|
||||
|
||||
default: m_planEditor->addStyleAttributes(node, false);
|
||||
}
|
||||
return true;
|
||||
} // bool apply( SituationMap::GeometryModel * geoModel, const SituationMap::GeometryModel::Node & node, SituationMap::GeometryModel::PrimitiveType nodeType)
|
||||
|
||||
|
||||
public:
|
||||
|
||||
ChangeStyleVisitor(PlanEditor *planEditor, SituationMap::GeometryModel *model)
|
||||
: SituationMap::GeometryNodeVisitor(model), m_planEditor(planEditor)
|
||||
{;}
|
||||
|
||||
~ChangeStyleVisitor() = default;
|
||||
|
||||
}; // ChangeStyleVisitor
|
||||
|
||||
|
||||
template<class RubberbandClass> void GeometryPlacer<RubberbandClass>::adjustEllipse(SituationMap::GeometryModel *geoModel, const SituationMap::GeometryModel::Node &p, const QList<QPointF> &v)
|
||||
{
|
||||
auto distance = [](const QPointF & v0, const QPointF & v1) -> double
|
||||
{
|
||||
QPointF dv = v1 - v0;
|
||||
return sqrt(dv.x() * dv.x() + dv.y() * dv.y());
|
||||
};
|
||||
|
||||
SituationMap::CoordTranslationFunctor *proj = m_map->coordTranslationFunctor();
|
||||
|
||||
QPointF centerPoint(v.first());
|
||||
for (int i = 1; i < 4; ++i) centerPoint += v.at(i);
|
||||
centerPoint /= 4;
|
||||
|
||||
const QPointF &v0 = (proj) ? proj->geographicToMap(v[0]) : v[0]; // ToDo: optimize calculation here
|
||||
const QPointF &v1 = (proj) ? proj->geographicToMap(v[1]) : v[1];
|
||||
const QPointF &v2 = (proj) ? proj->geographicToMap(v[2]) : v[2];
|
||||
|
||||
double diameterX = distance(v0, v1);
|
||||
double diameterY = distance(v1, v2);
|
||||
double phiSin = (v1.y() - v0.y()) / diameterX;
|
||||
double phiCos = (v1.x() - v0.x()) / diameterX;
|
||||
double phi = SituationMap::MathUtils::getMathAngle(QPointF(phiCos, phiSin)) * 180.0 / MathConst::pi;
|
||||
|
||||
geoModel->setPrimitiveAttribute(p, SituationMap::GeometryModel::Attribute::Center, QVariant(centerPoint));
|
||||
geoModel->setPrimitiveAttribute(p, SituationMap::GeometryModel::Attribute::Width, QVariant(diameterX));
|
||||
geoModel->setPrimitiveAttribute(p, SituationMap::GeometryModel::Attribute::Height, QVariant(diameterY));
|
||||
geoModel->setPrimitiveAttribute(p, SituationMap::GeometryModel::Attribute::Rotate, QVariant(phi));
|
||||
|
||||
}; // adjustEllipse
|
||||
|
||||
|
||||
template<class RubberbandClass> void GeometryPlacer<RubberbandClass>::changeStyleAttributes()
|
||||
{
|
||||
ChangeStyleVisitor doChangeStyle(m_planEditor, m_previewGeoModel);
|
||||
doChangeStyle.traverse();
|
||||
|
||||
m_previewGeoModelRenderer->render();
|
||||
m_map->getQGraphicsView()->viewport()->update(); // onUpdateView();
|
||||
|
||||
} // template<class RubberbandClass> void GeometryPlacer<RubberbandClass>::changeStyleAttributes(const QString & undoToken)
|
||||
|
||||
|
||||
template<class RubberbandClass> void GeometryPlacer<RubberbandClass>::applyTransform(SituationMap::GeometryModel *geoModel)
|
||||
{
|
||||
SituationMap::CoordTranslationFunctor *proj = m_map->coordTranslationFunctor();
|
||||
|
||||
geoModel->startUndoBlock();
|
||||
{
|
||||
const SituationMap::MathUtils::Matrix2D &mat = m_rubberband->transformMatrix();
|
||||
for (SituationMap::UniqueMapId uid : qAsConst(m_uidList))
|
||||
{
|
||||
const SituationMap::GeometryModel::Node &modelPrimitive = geoModel->findPrimitive(uid);
|
||||
if (modelPrimitive.isValid())
|
||||
{
|
||||
QList<QPointF> vertexList = m_previewGeoModel->getPrimitivePoints(modelPrimitive);
|
||||
QList<QPointF>::iterator vit = vertexList.begin();
|
||||
|
||||
if (proj)
|
||||
{
|
||||
for (; vit != vertexList.end(); ++vit)
|
||||
{
|
||||
const QPointF &pt = proj->geographicToMap(*vit);
|
||||
*vit = proj->mapToGeographic(mat.apply(pt));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; vit != vertexList.end(); ++vit)
|
||||
*vit = mat.apply(*vit);
|
||||
}
|
||||
geoModel->setPrimitivePoints(modelPrimitive, vertexList);
|
||||
|
||||
if ((geoModel->getType(modelPrimitive) == SituationMap::GeometryModel::PrimitiveType::Ellipse) && (vertexList.size() == 4))
|
||||
adjustEllipse(geoModel, modelPrimitive, vertexList);
|
||||
}
|
||||
}
|
||||
}
|
||||
geoModel->endUndoBlock(QObject::tr("apply transform geometry", TR_UNDO_TOKEN));
|
||||
|
||||
delete this;
|
||||
} // template<class RubberbandClass> void GeometryPlacer<RubberbandClass>::applyTransform( SituationMap::GeometryModel * geoModel )
|
||||
|
||||
|
||||
template<class RubberbandClass> void GeometryPlacer<RubberbandClass>::abortTransform()
|
||||
{
|
||||
delete this;
|
||||
} // template<class RubberbandClass> void GeometryPlacer<RubberbandClass>::abortTransform()
|
||||
|
||||
|
||||
template<class RubberbandClass> void GeometryPlacer<RubberbandClass>::previewTransform(SituationMap::Map *map, const SituationMap::MathUtils::Matrix2D &mat)
|
||||
{
|
||||
if (mat.isIdentity()) return;
|
||||
|
||||
previewTransform(map, mat, m_previewGeoModel->getRootNode());
|
||||
|
||||
m_previewGeoModelRenderer->render();
|
||||
map->getQGraphicsView()->viewport()->update(); // onUpdateView();
|
||||
|
||||
} // template<class RubberbandClass> void GeometryPlacer<RubberbandClass>::previewTransform( const SituationMap::MathUtils::Matrix2D & mat )
|
||||
|
||||
|
||||
|
||||
template<class RubberbandClass> void GeometryPlacer<RubberbandClass>::previewTransform(SituationMap::Map *map
|
||||
, const SituationMap::MathUtils::Matrix2D &mat
|
||||
, const SituationMap::GeometryModel::Node &node)
|
||||
{
|
||||
if (mat.isIdentity()) return;
|
||||
|
||||
SituationMap::GeometryModel::Node n(node);
|
||||
|
||||
SituationMap::CoordTranslationFunctor *proj = m_map->coordTranslationFunctor();
|
||||
|
||||
while (n.isValid())
|
||||
{
|
||||
SituationMap::GeometryModel::PrimitiveType primitiveType = m_previewGeoModel->getType(n);
|
||||
|
||||
if (n.hasChildNodes() && ((primitiveType == SituationMap::GeometryModel::PrimitiveType::RootNode) || (primitiveType == SituationMap::GeometryModel::PrimitiveType::Node)))
|
||||
previewTransform(map, mat, n.firstChildNode());
|
||||
else
|
||||
{
|
||||
QList<QPointF> vertexList = m_previewGeoModel->getPrimitivePoints(n);
|
||||
if (!vertexList.isEmpty())
|
||||
{
|
||||
QList<QPointF>::iterator vit = vertexList.begin();
|
||||
|
||||
if (proj)
|
||||
{
|
||||
for (; vit != vertexList.end(); ++vit)
|
||||
{
|
||||
const QPointF &pt = proj->geographicToMap(*vit);
|
||||
*vit = proj->mapToGeographic(mat.apply(pt));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; vit != vertexList.end(); ++vit)
|
||||
*vit = mat.apply(*vit);
|
||||
}
|
||||
m_previewGeoModel->setPrimitivePoints(n, vertexList);
|
||||
|
||||
if ((m_previewGeoModel->getType(n) == SituationMap::GeometryModel::PrimitiveType::Ellipse) && (vertexList.size() == 4))
|
||||
adjustEllipse(m_previewGeoModel, n, vertexList);
|
||||
}
|
||||
}
|
||||
n = n.next();
|
||||
}
|
||||
} // template<class RubberbandClass> void GeometryPlacer<RubberbandClass>::previewTransform( SitautionMap::Map *, const SituationMap::MathUtils::Matrix2D &, SituationMap::GeometryModel::Node & )
|
||||
|
||||
|
||||
template<class RubberbandClass> GeometryPlacer<RubberbandClass>::~GeometryPlacer()
|
||||
{
|
||||
if (m_map)
|
||||
{
|
||||
delete (m_previewGeoModel);
|
||||
delete (m_previewGeoModelRenderer);
|
||||
|
||||
if (m_rubberband)
|
||||
m_map->layerFactory().removeOverlayLayer(QLatin1String(PreviewLayer));
|
||||
|
||||
m_map->update();
|
||||
}
|
||||
m_previewGeoModel = nullptr;
|
||||
m_previewGeoModelRenderer = nullptr;
|
||||
m_rubberband = nullptr;
|
||||
|
||||
} // template<class RubberbandClass> GeometryPlacer<RubberbandClass>::~GeometryPlacer()
|
||||
|
||||
|
||||
} // namespace PlanEditor
|
||||
|
||||
Reference in new issue
Block a user