379 lines
13 KiB
C++
Executable File
379 lines
13 KiB
C++
Executable File
/**
|
|
* Building Model
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Gerlinde Rudolphus, ESZS, 2016-04-14
|
|
*/
|
|
|
|
#include "ces_building_model.h"
|
|
|
|
#include <Buildings/BuildingControlUnit/VWM/vwm_xml_reader.h>
|
|
#include <Buildings/BuildingControlUnit/VWM/vwm_math.h>
|
|
#include <LtsUtilsCore/dds_vector.h>
|
|
|
|
#include <float.h>
|
|
|
|
#include <QLineF>
|
|
#include <QDebug>
|
|
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
|
bool intersects(const QLineF &line1, const QLineF &line2)
|
|
{
|
|
const QPointF a = line1.p2() - line1.p1();
|
|
const QPointF b = line2.p1() - line2.p2();
|
|
const QPointF c = line1.p1() - line2.p1();
|
|
const qreal denominator = a.y() * b.x() - a.x() * b.y();
|
|
if (denominator == 0 || !std::isfinite(denominator))
|
|
return false;
|
|
const qreal reciprocal = 1 / denominator;
|
|
const qreal na = (b.y() * c.x() - b.x() * c.y()) * reciprocal;
|
|
if (na < 0 || na > 1)
|
|
return false;
|
|
const qreal nb = (a.x() * c.y() - a.y() * c.x()) * reciprocal;
|
|
if (nb < 0 || nb > 1)
|
|
return false;
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
|
|
namespace CesBuildings
|
|
{
|
|
|
|
/*************************************************************************************************
|
|
* Static methods *
|
|
*************************************************************************************************/
|
|
|
|
bool BuildingModel::isValid(const LtsUtils::QPoint3D &point)
|
|
{
|
|
return point != invalidPosition();
|
|
}
|
|
|
|
bool BuildingModel::isValid(const Core::GeoPosition &point)
|
|
{
|
|
return !qFuzzyIsNull(point.lon()) && !qFuzzyIsNull(point.lat()) && point.z() > invalidGeoPosition().z();
|
|
}
|
|
|
|
LtsUtils::QPoint3D BuildingModel::invalidPosition()
|
|
{
|
|
return BuildingControlUnit::VWM::Math::invalidPosition();
|
|
}
|
|
|
|
Core::GeoPosition BuildingModel::invalidGeoPosition()
|
|
{
|
|
return Core::GeoPosition(0., 0., -10000.);
|
|
}
|
|
|
|
|
|
/*************************************************************************************************
|
|
* Ctor, dtor and init *
|
|
*************************************************************************************************/
|
|
|
|
BuildingModel::BuildingModel(QObject *parent)
|
|
: QObject(parent)
|
|
, BuildingControlUnit::VWM::Building()
|
|
, m_logger(CentralEffectSimulation::getLogger(QStringLiteral("BuildingModel")))
|
|
{
|
|
}
|
|
|
|
BuildingModel::~BuildingModel()
|
|
{
|
|
}
|
|
|
|
|
|
bool BuildingModel::init(
|
|
const InfrastructureManagement::MainFootprint &mfp, const InfrastructureManagement::MainStructureElement &mse,
|
|
const QByteArray &vmd,
|
|
const int buildingId
|
|
)
|
|
{
|
|
m_buildingId = buildingId;
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START, m_buildingId=" << m_buildingId;
|
|
|
|
m_angle = mse.angle() * M_PI / 180.;
|
|
m_refPosGeo = mse.geoPosition();
|
|
m_refPosUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(mse.geoPosition().lon(), mse.geoPosition().lat());
|
|
m_refPos = {m_refPosUtm.x, m_refPosUtm.y, m_refPosGeo.z()};
|
|
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, m_buildingId=" << m_buildingId
|
|
<< ", m_angle=" << m_angle
|
|
<< ", m_refPosGeo=" << m_refPosGeo
|
|
<< ", m_refPos=" << m_refPos;
|
|
|
|
|
|
for (const InfrastructureManagement::FootprintElement &footprintElement : qAsConst(mfp.elements()))
|
|
m_footprint << QPointF(footprintElement.relPosition().offsetX(), footprintElement.relPosition().offsetY());
|
|
if (m_footprint.isEmpty())
|
|
{
|
|
ERROR_LOG(m_logger) << "Error reading MainFootprint for building " << m_buildingId;
|
|
return false;
|
|
} // if
|
|
m_boundingRect = m_footprint.boundingRect();
|
|
|
|
// const std::vector<uint8_t> &data = vmd.vulnerabilityData();
|
|
// QByteArray array = qUncompress(QByteArray::fromRawData(reinterpret_cast<const char*>(&data[0]), data.size()));
|
|
if (!BuildingControlUnit::VWM::XmlReader::readBuilding(vmd, *this))
|
|
{
|
|
ERROR_LOG(m_logger) << "Error reading VulnerabilityModelData for building " << m_buildingId;
|
|
return false;
|
|
} // if
|
|
|
|
m_height = DBL_MIN;
|
|
const QMap<int, BuildingControlUnit::VWM::Room> &roomMap = rooms();
|
|
for (const BuildingControlUnit::VWM::Room &room : qAsConst(roomMap))
|
|
for (const BuildingControlUnit::VWM::OuterWall &outerWall : qAsConst(room.outerWalls()))
|
|
for (const BuildingControlUnit::VWM::WallElement &wallElement : qAsConst(outerWall.elements()))
|
|
for (const LtsUtils::QPoint3D &point : qAsConst(wallElement))
|
|
if (point.z() > m_height)
|
|
m_height = point.z();
|
|
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END, m_buildingId=" << m_buildingId;
|
|
return true;
|
|
}
|
|
|
|
|
|
/*************************************************************************************************
|
|
* Intersection calculations *
|
|
*************************************************************************************************/
|
|
|
|
bool BuildingModel::hasIntersectionSimplified(const LtsUtils::QPoint3D &start, const LtsUtils::QPoint3D &end) const
|
|
{
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_buildingId=" << m_buildingId
|
|
<< ", start=" << start << ", end=" << end;
|
|
|
|
// keep origin of QRect (topLeft) in mind:
|
|
static const QLineF topLine = QLineF(m_boundingRect.topRight(), m_boundingRect.topLeft());
|
|
static const QLineF leftLine = QLineF(m_boundingRect.topLeft(), m_boundingRect.bottomLeft());
|
|
static const QLineF bottomLine = QLineF(m_boundingRect.bottomLeft(), m_boundingRect.bottomRight());
|
|
static const QLineF rightLine = QLineF(m_boundingRect.bottomRight(), m_boundingRect.topRight());
|
|
|
|
// qCritical() << " topLine" << topLine;
|
|
// qCritical() << " leftLine" << leftLine;
|
|
// qCritical() << " bottomLine" << bottomLine;
|
|
// qCritical() << " rightLine" << rightLine;
|
|
|
|
// qCritical() << " start.z()" << start.z();
|
|
// qCritical() << " end.z()" << end.z();
|
|
// qCritical() << " m_height" << m_height;
|
|
|
|
// over the building?
|
|
if (start.z() > m_height && end.z() > m_height)
|
|
return false;
|
|
|
|
const QPointF start2D(start.x(), start.y());
|
|
const QPointF end2D(end.x(), end.y());
|
|
const QLineF startToEnd = QLineF(start2D, end2D);
|
|
|
|
// qCritical() << " startToEnd" << startToEnd;
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
|
QPointF dummy;
|
|
if (startToEnd.intersects(topLine, &dummy) != QLineF::BoundedIntersection &&
|
|
startToEnd.intersects(leftLine, &dummy) != QLineF::BoundedIntersection &&
|
|
startToEnd.intersects(bottomLine, &dummy) != QLineF::BoundedIntersection &&
|
|
startToEnd.intersects(rightLine, &dummy) != QLineF::BoundedIntersection &&
|
|
!m_boundingRect.contains(start2D) && !m_boundingRect.contains(end2D))
|
|
#else
|
|
if (!intersects(startToEnd, topLine) && !intersects(startToEnd, leftLine) &&
|
|
!intersects(startToEnd, bottomLine) && !intersects(startToEnd, rightLine) &&
|
|
!m_boundingRect.contains(start2D) && !m_boundingRect.contains(end2D))
|
|
#endif
|
|
return false;
|
|
|
|
// qCritical() << " intersects done";
|
|
|
|
|
|
QPolygonF poly;
|
|
poly << start2D;
|
|
poly << end2D;
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
|
if (!m_footprint.intersects(poly))
|
|
#else
|
|
if (m_footprint.intersected(poly).isEmpty())
|
|
#endif
|
|
return false;
|
|
|
|
// qCritical() << " hasIntersectionSimplified -> return true";
|
|
return true;
|
|
}
|
|
|
|
bool BuildingModel::hasIntersectionSimplified(const Core::GeoPosition &start, const Core::GeoPosition &end) const
|
|
{
|
|
return hasIntersectionSimplified(fromGeographic(start), fromGeographic(end));
|
|
}
|
|
|
|
bool BuildingModel::hasIntersectionSimplified(const QVector<LtsUtils::QPoint3D> &trajectory) const
|
|
{
|
|
for (int i = 1; i < trajectory.size(); ++i)
|
|
if (hasIntersectionSimplified(trajectory[i - 1], trajectory[i]))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool BuildingModel::hasIntersectionSimplified(const std::vector<Core::GeoPosition> &trajectory) const
|
|
{
|
|
for (unsigned int i = 1; i < trajectory.size(); ++i)
|
|
if (hasIntersectionSimplified(trajectory[i - 1], trajectory[i]))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
|
|
bool BuildingModel::hasIntersection(const LtsUtils::QPoint3D &start, const LtsUtils::QPoint3D &end) const
|
|
{
|
|
if (!hasIntersectionSimplified(start, end))
|
|
return false;
|
|
|
|
bool bHasIntersection = BuildingControlUnit::VWM::Math::hasIntersection(start, end, rooms());
|
|
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_buildingId=" << m_buildingId
|
|
<< ", start=" << start << ", end=" << end
|
|
<< ", rooms().size()" << rooms().size()
|
|
<< ", bHasIntersection=" << bHasIntersection;
|
|
return bHasIntersection;
|
|
}
|
|
|
|
bool BuildingModel::hasIntersection(const Core::GeoPosition &start, const Core::GeoPosition &end) const
|
|
{
|
|
return hasIntersection(fromGeographic(start), fromGeographic(end));
|
|
}
|
|
|
|
bool BuildingModel::hasIntersection(const QVector<LtsUtils::QPoint3D> &trajectory) const
|
|
{
|
|
for (int i = 1; i < trajectory.size(); ++i)
|
|
if (hasIntersection(trajectory[i - 1], trajectory[i]))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool BuildingModel::hasIntersection(const std::vector<Core::GeoPosition> &trajectory) const
|
|
{
|
|
for (unsigned int i = 1; i < trajectory.size(); ++i)
|
|
if (hasIntersection(trajectory[i - 1], trajectory[i]))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
|
|
Core::GeoPosition BuildingModel::intersection(const LtsUtils::QPoint3D &start, const LtsUtils::QPoint3D &end) const
|
|
{
|
|
const LtsUtils::QPoint3D point = BuildingControlUnit::VWM::Math::intersection(start, end, rooms());
|
|
return !isValid(point) ? invalidGeoPosition() : toGeographic(point);
|
|
}
|
|
|
|
Core::GeoPosition BuildingModel::intersection(const Core::GeoPosition &start, const Core::GeoPosition &end) const
|
|
{
|
|
return intersection(fromGeographic(start), fromGeographic(end));
|
|
}
|
|
|
|
Core::GeoPosition BuildingModel::intersection(const QVector<LtsUtils::QPoint3D> &trajectory) const
|
|
{
|
|
for (int i = 1; i < trajectory.size(); ++i)
|
|
{
|
|
Core::GeoPosition pos = intersection(trajectory[i - 1], trajectory[i]);
|
|
if (!isValid(pos))
|
|
continue;
|
|
return pos;
|
|
} // for
|
|
return {};
|
|
}
|
|
|
|
Core::GeoPosition BuildingModel::intersection(const std::vector<Core::GeoPosition> &trajectory) const
|
|
{
|
|
for (unsigned int i = 1; i < trajectory.size(); ++i)
|
|
{
|
|
Core::GeoPosition pos = intersection(fromGeographic(trajectory[i - 1]), fromGeographic(trajectory[i]));
|
|
if (!isValid(pos))
|
|
continue;
|
|
return pos;
|
|
} // for
|
|
return {};
|
|
}
|
|
|
|
|
|
/*************************************************************************************************
|
|
* Coordinate transformations *
|
|
*************************************************************************************************/
|
|
|
|
LtsUtils::QPoint3D BuildingModel::fromGeographic(const Core::GeoPosition &point) const
|
|
{
|
|
// qCritical() << " point.z = " << point.z();
|
|
// qCritical() << " m_refPos = " << m_refPos.x() << " - " << m_refPos.y() << " - " << m_refPos.z();
|
|
const LtsCoordTrans::UtmCoordinate utm = LtsCoordTrans::UtmCoordinate::fromGeographic(point.lon(), point.lat());
|
|
// qCritical() << " utm = " << utm.mgrs(7);
|
|
return toReference({utm.x, utm.y, point.z()});
|
|
}
|
|
|
|
QVector<LtsUtils::QPoint3D> BuildingModel::fromGeographic(const std::vector<Core::GeoPosition> &points) const
|
|
{
|
|
QVector<LtsUtils::QPoint3D> ret;
|
|
ret.reserve(points.size());
|
|
for (const Core::GeoPosition &point : qAsConst(points))
|
|
ret.append(fromGeographic(point));
|
|
return ret;
|
|
}
|
|
|
|
Core::GeoPosition BuildingModel::toGeographic(const LtsUtils::QPoint3D &point) const
|
|
{
|
|
const QPointF geoPos2D = m_refPosUtm.geographic(point.rotated(m_angle, LtsUtils::QPoint3D::Axis::Z).toPointF());
|
|
return Core::GeoPosition(geoPos2D.x(), geoPos2D.y(), point.z() + m_refPos.z());
|
|
}
|
|
|
|
std::vector<Core::GeoPosition> BuildingModel::toGeographic(const QVector<LtsUtils::QPoint3D> &points) const
|
|
{
|
|
std::vector<Core::GeoPosition> ret;
|
|
ret.reserve(points.size());
|
|
for (const LtsUtils::QPoint3D &point : qAsConst(points))
|
|
ret.push_back(toGeographic(point));
|
|
return ret;
|
|
}
|
|
|
|
|
|
LtsUtils::QPoint3D BuildingModel::fromReference(const LtsUtils::QPoint3D &point) const
|
|
{
|
|
return point.rotated(m_angle, LtsUtils::QPoint3D::Axis::Z) + m_refPos;
|
|
}
|
|
|
|
QVector<LtsUtils::QPoint3D> BuildingModel::fromReference(const QVector<LtsUtils::QPoint3D> &points) const
|
|
{
|
|
QVector<LtsUtils::QPoint3D> ret;
|
|
ret.reserve(points.size());
|
|
for (const LtsUtils::QPoint3D &point : qAsConst(points))
|
|
ret.append(fromReference(point));
|
|
return ret;
|
|
}
|
|
|
|
LtsUtils::QPoint3D BuildingModel::toReference(const LtsUtils::QPoint3D &point) const
|
|
{
|
|
return (point - m_refPos).rotated(-m_angle, LtsUtils::QPoint3D::Axis::Z);
|
|
}
|
|
|
|
QVector<LtsUtils::QPoint3D> BuildingModel::toReference(const QVector<LtsUtils::QPoint3D> &points) const
|
|
{
|
|
QVector<LtsUtils::QPoint3D> ret;
|
|
ret.reserve(points.size());
|
|
for (const LtsUtils::QPoint3D &point : qAsConst(points))
|
|
ret.append(toReference(point));
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*************************************************************************************************
|
|
* Overloaded operators *
|
|
*************************************************************************************************/
|
|
|
|
bool BuildingModel::operator ==(const BuildingModel &other) const
|
|
{
|
|
return m_buildingId == other.m_buildingId;
|
|
}
|
|
|
|
bool BuildingModel::operator !=(const BuildingModel &other) const
|
|
{
|
|
return m_buildingId != other.m_buildingId;
|
|
}
|
|
|
|
} // namespace CesBuildings
|