Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+662
@@ -0,0 +1,662 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Interface
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "building_ownership.h"
|
||||
#include <Map/map.h>
|
||||
#include <Map/object_factory.h>
|
||||
#include <MapObjects/cube.h>
|
||||
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <MathUtils/simple_helper.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
|
||||
#define USE_BUFFER_APPROACH
|
||||
#ifdef USE_BUFFER_APPROACH
|
||||
# include <arcgis/PolygonBuilder.h>
|
||||
# include <arcgis/GeometryEngine.h>
|
||||
#endif // USE_BUFFER_APPROACH
|
||||
|
||||
namespace SituationMap
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// PositionCont BuildingOwnership::retrieveBuildingGeometry(int buildingId, int floorId) const
|
||||
// QMap<int, double> BuildingOwnership::retrieveBuildingAbsHeight(int buildingId) const
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// class BuildingGeometryCache
|
||||
//------------------------------------------------------------------------------
|
||||
class BuildingGeometryCache
|
||||
{
|
||||
//------------------------------------------------------------------------------
|
||||
// struct KEY_T
|
||||
//------------------------------------------------------------------------------
|
||||
struct KEY_T
|
||||
{
|
||||
KEY_T(int buildingId = -1, int floorId = -1)
|
||||
: m_buildingId(buildingId), m_floorId(floorId)
|
||||
{}
|
||||
|
||||
int m_buildingId{-1};
|
||||
int m_floorId{-1};
|
||||
|
||||
bool operator<(const KEY_T &other) const
|
||||
{
|
||||
return m_buildingId < other.m_buildingId
|
||||
|| ((m_buildingId == other.m_buildingId) && (m_floorId < other.m_floorId));
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
BuildingGeometryCache() = default;
|
||||
~BuildingGeometryCache() = default;
|
||||
|
||||
void init(BuildingOwnership *buildingOwnership)
|
||||
{
|
||||
m_buildingOwnership = buildingOwnership;
|
||||
}
|
||||
|
||||
PositionCont retrieveBuildingGeometry(int buildingId, int floorId) const
|
||||
{
|
||||
const KEY_T key(buildingId, floorId);
|
||||
loadGeometry(key);
|
||||
return m_cacheGeometry[key];
|
||||
};
|
||||
|
||||
QMap<int, double> retrieveBuildingAbsHeight(int buildingId) const
|
||||
{
|
||||
loadAbsHeight(buildingId);
|
||||
return m_cacheAbsHeight[buildingId];
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
void loadGeometry(const KEY_T &key) const
|
||||
{
|
||||
if (m_cacheGeometry.contains(key))
|
||||
return;
|
||||
m_cacheGeometry[key] = m_buildingOwnership->retrieveBuildingGeometryInternal(key.m_buildingId, key.m_floorId);
|
||||
}
|
||||
|
||||
void loadAbsHeight(int buildingId) const
|
||||
{
|
||||
if (m_cacheAbsHeight.contains(buildingId))
|
||||
return;
|
||||
m_cacheAbsHeight[buildingId] = m_buildingOwnership->retrieveBuildingAbsHeightInternal(buildingId);
|
||||
}
|
||||
|
||||
private:
|
||||
BuildingOwnership *m_buildingOwnership{nullptr};
|
||||
mutable QMap<KEY_T, PositionCont> m_cacheGeometry;
|
||||
mutable QMap<int, QMap<int, double>> m_cacheAbsHeight; // key == buildingId
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
class BuildingOwnership::Private
|
||||
{
|
||||
public:
|
||||
explicit Private() = default;
|
||||
|
||||
~Private() = default;
|
||||
|
||||
// buildingId, BuildingOwnership
|
||||
QMap<int32_t, CentralEffectSimulation::BuildingOwnership> m_ownershipData;
|
||||
|
||||
BuildingGeometryCache m_buildingGeometryCache;
|
||||
|
||||
Map *m_map = nullptr;
|
||||
|
||||
// MapObjects
|
||||
QMap<QPair<int, int>, UniqueMapId> m_bldgFlr2UniqueMapId;
|
||||
|
||||
bool m_visible = false;
|
||||
int m_drawOrder = 0;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static QPair<int, int> createKey(int buildingId, int floorId)
|
||||
{
|
||||
return {buildingId, floorId};
|
||||
}
|
||||
|
||||
static int buildingIdOfKey(const QPair<int, int> &keyData)
|
||||
{
|
||||
return keyData.first;
|
||||
}
|
||||
|
||||
|
||||
RefPointer<Cube> getCreateCube(int buildingId, int floorId)
|
||||
{
|
||||
const QPair<int, int> &key = createKey(buildingId, floorId);
|
||||
const UniqueMapId uniqueMapId = m_bldgFlr2UniqueMapId.value(key, INVALID_MAP_ID);
|
||||
|
||||
if (!SituationMap::isUniqueMapIdValid(uniqueMapId))
|
||||
{
|
||||
const QString &layernameForCubes = m_map->layerFactory().layernameForCubes();
|
||||
const QString &key_debugInfo = QStringLiteral("bldg_%1-flr%2").arg(buildingId).arg(floorId);
|
||||
|
||||
RefPointer<Cube> cube =
|
||||
m_map->objectFactory().create<Cube>(layernameForCubes, key_debugInfo);
|
||||
|
||||
if (cube.valid())
|
||||
m_bldgFlr2UniqueMapId[key] = cube->uniqueMapId();
|
||||
return cube;
|
||||
}
|
||||
return m_map->objectFactory().get<Cube>(uniqueMapId);
|
||||
}
|
||||
|
||||
void removeCube(int buildingId = -1)
|
||||
{
|
||||
QMutableMapIterator<QPair<int, int>, UniqueMapId> mapIt(m_bldgFlr2UniqueMapId);
|
||||
|
||||
while (mapIt.hasNext())
|
||||
{
|
||||
mapIt.next();
|
||||
|
||||
const QPair<int, int> &key = mapIt.key();
|
||||
int curBuildingId = buildingIdOfKey(key);
|
||||
|
||||
if ((buildingId < 0) ||
|
||||
(buildingId == curBuildingId)
|
||||
)
|
||||
{
|
||||
UniqueMapId uMapId = mapIt.value();
|
||||
SituationMap::AbstractMapObject *mapObj = m_map->objectFactory().idToMapObject(uMapId);
|
||||
if (mapObj)
|
||||
mapObj->removeMySelf();
|
||||
|
||||
// Will remove that pair from map:
|
||||
mapIt.remove();
|
||||
}
|
||||
} // while
|
||||
}
|
||||
|
||||
bool updateVisibility(int buildingId = -1)
|
||||
{
|
||||
bool success = true;
|
||||
QMutableMapIterator<QPair<int, int>, UniqueMapId> mapIt(m_bldgFlr2UniqueMapId);
|
||||
while (mapIt.hasNext())
|
||||
{
|
||||
mapIt.next();
|
||||
|
||||
const QPair<int, int> &key = mapIt.key();
|
||||
int curBuildingId = buildingIdOfKey(key);
|
||||
|
||||
if ((buildingId < 0) ||
|
||||
(buildingId == curBuildingId)
|
||||
)
|
||||
{
|
||||
UniqueMapId uMapId = mapIt.value();
|
||||
SituationMap::AbstractMapObject *mapObj = m_map->objectFactory().idToMapObject(uMapId);
|
||||
if (mapObj)
|
||||
{
|
||||
mapObj->setVisibility(m_visible);
|
||||
if (!mapObj->updateView())
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
} // while
|
||||
return success;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// class BuildingOwnership
|
||||
//------------------------------------------------------------------------------
|
||||
BuildingOwnership::BuildingOwnership(int drawOrder, QObject *parent)
|
||||
: BaseClass(parent)
|
||||
, m_logger(getLogger("BuildingOwnership"))
|
||||
, d(new Private())
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
d->m_drawOrder = drawOrder;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
BuildingOwnership::~BuildingOwnership()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
this->stop();
|
||||
// this->removeAllObjects(); // will be done by dtor on Map
|
||||
delete d;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
bool BuildingOwnership::init(Map *map, PluginProvider *pluginProvider)
|
||||
{
|
||||
d->m_map = map;
|
||||
|
||||
if (!d->m_map)
|
||||
return false;
|
||||
|
||||
if (!pluginProvider ||
|
||||
!pluginProvider->cesDtc() ||
|
||||
!pluginProvider->ismDtc())
|
||||
return false;
|
||||
|
||||
m_cesDtc = pluginProvider->cesDtc();
|
||||
m_ismDtc = pluginProvider->ismDtc();
|
||||
|
||||
d->m_buildingGeometryCache.init(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BuildingOwnership::removeAllObjects()
|
||||
{
|
||||
d->removeCube(); // will remove all stored MapObjects/Cubes
|
||||
}
|
||||
|
||||
bool BuildingOwnership::run()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
if (!d->m_map)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no m_map";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_cesDtc)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no m_cesDtc";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_cesDtc->disconnect(this);
|
||||
|
||||
qRegisterMetaType<CentralEffectSimulation::BuildingOwnership>("CentralEffectSimulation::BuildingOwnership");
|
||||
|
||||
connect(m_cesDtc.get(), &CentralEffectSimulation::Interface::Dtc::buildingOwnershipChanged,
|
||||
this, &BuildingOwnership::onBuildingOwnershipChanged, Qt::QueuedConnection);
|
||||
|
||||
// get:
|
||||
m_cesDtc->buildingOwnerships([this](const CentralEffectSimulation::BuildingOwnership & data)
|
||||
{
|
||||
onBuildingOwnershipChanged(data, DataModification::eAdded);
|
||||
});
|
||||
|
||||
|
||||
// Trigger manually :
|
||||
if (false)
|
||||
{
|
||||
std::function<void(int, int, int)> fTriggerBuilding = [this](int partyId, int buildingId, int floorId)
|
||||
{
|
||||
// V100.1: Renderingmode::Dynamic -> cube shows height
|
||||
// V100.1: Renderingmode::Static -> cube is flat
|
||||
|
||||
// retrieve geometry:
|
||||
const PositionCont &absPositionsGeo = retrieveBuildingGeometry(buildingId, floorId);
|
||||
|
||||
// retrieve height:
|
||||
QMap<int, double> floorHeights = retrieveBuildingAbsHeight(buildingId);
|
||||
|
||||
// cubes:
|
||||
RefPointer<Cube> cube = d->getCreateCube(buildingId, floorId);
|
||||
if (!cube)
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no cube created";
|
||||
|
||||
cube->setVisibility(d->m_visible);
|
||||
cube->setDrawOrder(d->m_drawOrder);
|
||||
|
||||
cube->setPartyId(partyId); // means: set partyId of owner
|
||||
cube->setPositions(absPositionsGeo);
|
||||
const double height = floorHeights.value(floorId, 2.5 * floorId);
|
||||
cube->setHeight(height);
|
||||
|
||||
bool success = cube->updateView();
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " cube->updateView " << success;
|
||||
};
|
||||
|
||||
// partyId, bldId, floorid
|
||||
fTriggerBuilding(24, 5, 1);
|
||||
fTriggerBuilding(-1, 5, 2);
|
||||
fTriggerBuilding(89, 5, 3);
|
||||
|
||||
}
|
||||
// : Trigger manually
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
return true;
|
||||
}
|
||||
|
||||
void BuildingOwnership::stop()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
m_cesDtc->disconnect(this);
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
bool BuildingOwnership::isVisible() const
|
||||
{
|
||||
return d->m_visible;
|
||||
}
|
||||
bool BuildingOwnership::setVisible(bool visible)
|
||||
{
|
||||
d->m_visible = visible;
|
||||
bool succ = d->updateVisibility();
|
||||
return succ;
|
||||
}
|
||||
|
||||
void BuildingOwnership::onBuildingOwnershipChanged(const CentralEffectSimulation::BuildingOwnership &data, DataModification modType)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
const int buildingId = data.buildingId();
|
||||
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
case DataModification::eModified:
|
||||
// retrieve geometry from ISM and ownership and finally create cubes
|
||||
updateBuilding(buildingId);
|
||||
break;
|
||||
case DataModification::eRemoved:
|
||||
// reset ownership -> remove cubes:
|
||||
d->removeCube(buildingId);
|
||||
break;
|
||||
|
||||
} // switch
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
void BuildingOwnership::onResetBuildingOwnership()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
d->removeCube();
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
void BuildingOwnership::updateBuilding(int buildingId)
|
||||
{
|
||||
// retrieve data for complete building:
|
||||
const CentralEffectSimulation::BuildingOwnership &bos = m_cesDtc->buildingOwnership(buildingId);
|
||||
|
||||
// update own data:
|
||||
d->m_ownershipData[buildingId] = bos;
|
||||
|
||||
const auto &ownerships = bos.ownerships();
|
||||
|
||||
// accessable by floorId:
|
||||
QMap<int, int> floor2Party;
|
||||
for (const CentralEffectSimulation::Ownership &ownership : ownerships)
|
||||
// BuildingOwnership uses a '0' to indicate an invalid partyId.... :-(
|
||||
if (ownership.partyId() > 0)
|
||||
floor2Party[ownership.floorId()] = ownership.partyId();
|
||||
|
||||
|
||||
// qCritical() << "floor2Party" << floor2Party;
|
||||
|
||||
|
||||
// retrieve height of all floors:
|
||||
const QMap<int, double> &floorHeights = retrieveBuildingAbsHeight(buildingId);
|
||||
|
||||
|
||||
// create/update one Cube (MapObject) per floor:
|
||||
QMapIterator<int, double> mapIt(floorHeights);
|
||||
int floorCounter = 0;
|
||||
while (mapIt.hasNext())
|
||||
{
|
||||
mapIt.next();
|
||||
|
||||
// a) floorId
|
||||
const int floorId = mapIt.key();
|
||||
|
||||
// b) height
|
||||
const double height = mapIt.value();
|
||||
|
||||
// c) partyId:
|
||||
// set them to "unknown", if not existing:
|
||||
const int partyId = floor2Party.value(floorId, -1); // invalid partyId -> unknown -> white color
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION
|
||||
<< " floorId=" << floorId
|
||||
<< " height=" << height
|
||||
<< " partyId=" << partyId;
|
||||
|
||||
|
||||
// retrieve geometry:
|
||||
const PositionCont &absPositionsGeo = retrieveBuildingGeometry(buildingId, ++floorCounter);
|
||||
|
||||
// cubes
|
||||
RefPointer<Cube> cube = d->getCreateCube(buildingId, floorId);
|
||||
|
||||
cube->setVisibility(d->m_visible);
|
||||
cube->setDrawOrder(d->m_drawOrder);
|
||||
|
||||
cube->setPartyId(partyId); // means: set partyId of owner
|
||||
cube->setPositions(absPositionsGeo);
|
||||
cube->setHeight(height);
|
||||
|
||||
if (!cube->updateView())
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " cube->updateView() failed";
|
||||
} // while
|
||||
}
|
||||
|
||||
PositionCont BuildingOwnership::retrieveBuildingGeometry(int buildingId, int floorId) const
|
||||
{
|
||||
return d->m_buildingGeometryCache.retrieveBuildingGeometry(buildingId, floorId);
|
||||
}
|
||||
|
||||
PositionCont BuildingOwnership::retrieveBuildingGeometryInternal(int buildingId, int floorId) const
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||||
<< " buildingId=" << buildingId
|
||||
<< " floorId=" << floorId;
|
||||
if (!m_ismDtc)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION << " no m_ismDtc";
|
||||
return PositionCont();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// retrieve relative points of footprint:
|
||||
//
|
||||
QVector<QPointF> relPositions;
|
||||
{
|
||||
const InfrastructureManagement::MainFootprint &mainFootprint = m_ismDtc->mainFootprint(buildingId);
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START"
|
||||
<< " mainFootprint.elements().size()=" << mainFootprint.elements().size();
|
||||
|
||||
relPositions.reserve(mainFootprint.elements().size());
|
||||
// sorted per definition
|
||||
const auto &fpElements = mainFootprint.elements();
|
||||
for (const InfrastructureManagement::FootprintElement &element : fpElements)
|
||||
{
|
||||
const auto &relPos = element.relPosition();
|
||||
relPositions += QPointF(relPos.offsetX(), relPos.offsetY());
|
||||
}
|
||||
}
|
||||
// DEBUG_LOG(m_logger) << "footprintOrg = " << relPositions;
|
||||
|
||||
//
|
||||
// expand the polyline depending on the floor:
|
||||
//
|
||||
|
||||
#ifndef USE_BUFFER_APPROACH
|
||||
// calculate the mass/center point of the outline/polygon:
|
||||
{
|
||||
// assume that there will be not more than 100 floors:
|
||||
const double distance = 0.5 + (100 - floorId) * 0.01;
|
||||
|
||||
const QPolygonF &massPoly = relPositions.toVector();
|
||||
const QPointF &massCenterPoint = massPoly.boundingRect().center();
|
||||
|
||||
// increase distance to massCenterPoint (depending on the quadrant)
|
||||
const double massCenterPointX = massCenterPoint.x();
|
||||
const double massCenterPointY = massCenterPoint.y();
|
||||
QMutableListIterator<QPointF> listIt(relPositions);
|
||||
while (listIt.hasNext())
|
||||
{
|
||||
QPointF &relPosition = listIt.next();
|
||||
// X
|
||||
if (relPosition.x() < massCenterPointX)
|
||||
relPosition.rx() -= distance;
|
||||
else
|
||||
relPosition.rx() += distance;
|
||||
|
||||
// Y
|
||||
if (relPosition.y() < massCenterPointY)
|
||||
relPosition.ry() -= distance;
|
||||
else
|
||||
relPosition.ry() += distance;
|
||||
} // for
|
||||
// DEBUG_LOG(m_logger) << "footprintBlown = " << relPositions;
|
||||
}
|
||||
#endif // USE_BUFFER_APPROACH
|
||||
|
||||
|
||||
//
|
||||
// translate to absolute
|
||||
//
|
||||
PositionCont absPositionsGeo;
|
||||
|
||||
const InfrastructureManagement::MainStructureElement &mse = m_ismDtc->mainStructureElement(buildingId);
|
||||
|
||||
const Core::GeoPosition &geoPosition = mse.geoPosition();
|
||||
const QPointF &referencePointGeo = QPointF(geoPosition.lon(), geoPosition.lat());
|
||||
const LtsCoordTrans::UtmCoordinate referencePointUTM = LtsCoordTrans::UtmCoordinate::fromGeographic(referencePointGeo);
|
||||
const double angleRad = mse.angle() * LtsCoordTrans::deg2rad();
|
||||
|
||||
// add relPos to referencePoint:
|
||||
const QPointF center;
|
||||
absPositionsGeo.reserve(relPositions.size());
|
||||
for (const auto &relPosition : qAsConst(relPositions))
|
||||
{
|
||||
const QPointF &relPositionRotate = MathUtils::rotate(relPosition, center, angleRad); // rotate relPosition by angleRad around 0,0
|
||||
const QPointF &pGeo = referencePointUTM.geographic(relPositionRotate); // add relPosition to referencePointUTM
|
||||
absPositionsGeo.append(Point3D::fromQPointF(pGeo));
|
||||
} // for
|
||||
|
||||
// DEBUG_LOG(m_logger) << "absPositionsGeo = " << absPositionsGeo;
|
||||
|
||||
#ifdef USE_BUFFER_APPROACH
|
||||
{
|
||||
//
|
||||
// This works better for building for building with a shape like a 'H'...
|
||||
//
|
||||
|
||||
// assume that there will be not more than 100 floors:
|
||||
const double distance = (100 - floorId) * 0.01;
|
||||
|
||||
// create EsriGeometry:
|
||||
|
||||
Esri::ArcGISRuntime::PolygonBuilder polygonBuilder(Esri::ArcGISRuntime::SpatialReference::wgs84());
|
||||
constexpr double rad2deg = LtsCoordTrans::rad2deg();
|
||||
for (const Point3D &point : qAsConst(absPositionsGeo))
|
||||
polygonBuilder.addPoint(Esri::ArcGISRuntime::Point(point.x() * rad2deg,
|
||||
point.y() * rad2deg,
|
||||
point.z()));
|
||||
const Esri::ArcGISRuntime::Geometry &esriGeometry = polygonBuilder.toGeometry();
|
||||
|
||||
const Esri::ArcGISRuntime::Polygon polyline =
|
||||
Esri::ArcGISRuntime::GeometryEngine::bufferGeodetic(esriGeometry,
|
||||
distance,
|
||||
Esri::ArcGISRuntime::LinearUnitId::Meters,
|
||||
0.1,
|
||||
Esri::ArcGISRuntime::GeodeticCurveType::Geodesic);
|
||||
|
||||
if (polyline.parts().isEmpty())
|
||||
return absPositionsGeo;
|
||||
|
||||
const Esri::ArcGISRuntime::ImmutablePart &immutablePart = polyline.parts().part(0);
|
||||
const Esri::ArcGISRuntime::ImmutablePointCollection &pointCollection = immutablePart.points();
|
||||
const int size = pointCollection.size();
|
||||
|
||||
// NOTICE_LOG(m_logger) << " pointCollection.size = " << pointCollection.size()
|
||||
// << " - buildingId = " << buildingId
|
||||
// << ", mse.name = " << mse.name();
|
||||
|
||||
absPositionsGeo.clear();
|
||||
absPositionsGeo.reserve(size);
|
||||
|
||||
for (const Esri::ArcGISRuntime::Point &esriP : pointCollection)
|
||||
{
|
||||
absPositionsGeo.append(Point3D(esriP.x() * LtsCoordTrans::deg2rad(),
|
||||
esriP.y() * LtsCoordTrans::deg2rad(),
|
||||
esriP.z()));
|
||||
} // for;
|
||||
}
|
||||
#endif // USE_BUFFER_APPROACH
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
return absPositionsGeo;
|
||||
}
|
||||
|
||||
QMap<int, double> BuildingOwnership::retrieveBuildingAbsHeight(int buildingId) const
|
||||
{
|
||||
return d->m_buildingGeometryCache.retrieveBuildingAbsHeight(buildingId);
|
||||
}
|
||||
|
||||
QMap<int, double> BuildingOwnership::retrieveBuildingAbsHeightInternal(int buildingId) const
|
||||
{
|
||||
QMap<int, double> floorHeights;
|
||||
|
||||
const InfrastructureManagement::MainStructureElement &mse = m_ismDtc->mainStructureElement(buildingId);
|
||||
|
||||
// move from dds to QVector:
|
||||
for (const InfrastructureManagement::StructureElement &element : mse.elements())
|
||||
{
|
||||
if (element.structureElementTypeId() != InfrastructureManagement::StructureElementType::Floor)
|
||||
continue;
|
||||
|
||||
const int floorId = element.id();
|
||||
|
||||
//
|
||||
// Cubes are using the UniqueValueRenderer of layer 'BuildingOwnership'.
|
||||
// To reduce the dependency to the elevation source, choose
|
||||
// ExtrusionMode::AbsoluteHeight @ UniqueValueRenderer
|
||||
// Additionally, the top is flat (and not according base surface.)
|
||||
//
|
||||
// If UniqueValueRenderer uses: Esri::ArcGISRuntime::ExtrusionMode::AbsoluteHeight
|
||||
// ExtrusionMode::AbsoluteHeight has a flat top.
|
||||
double height = element.geoPosition().z();
|
||||
|
||||
// If UniqueValueRenderer uses: Esri::ArcGISRuntime::ExtrusionMode::BaseHeight
|
||||
// This is the only extrusion mode that doesn't have a flat top.
|
||||
// The extruded height, we need the relative,
|
||||
// double height = element.relPosition().offsetZ();
|
||||
floorHeights[floorId] = height;
|
||||
}
|
||||
|
||||
// this is the height of the bottom, not the ceiling
|
||||
// therefore we have take value of topwards neighboring floor:
|
||||
{
|
||||
QMutableMapIterator<int, double> mapIt(floorHeights);
|
||||
while (mapIt.hasNext())
|
||||
{
|
||||
QMap<int, double>::iterator curFloor = mapIt.next();
|
||||
if (mapIt.hasNext())
|
||||
{
|
||||
QMap<int, double>::iterator upperFloor = mapIt.peekNext(); // neighboring floor
|
||||
curFloor.value() = upperFloor.value();
|
||||
}
|
||||
else
|
||||
curFloor.value() += 2.0; // add default height of 2 [meter]
|
||||
}
|
||||
}
|
||||
|
||||
return floorHeights;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user