/** * Building Model * $Id$ * $HeadURL$ * $Author$ * Created by Gerlinde Rudolphus, ESZS, 2016-04-14 */ #include "ces_building_model.h" #include #include #include #include #include #include #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 &data = vmd.vulnerabilityData(); // QByteArray array = qUncompress(QByteArray::fromRawData(reinterpret_cast(&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 &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 &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 &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 &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 &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 &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 &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 BuildingModel::fromGeographic(const std::vector &points) const { QVector 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 BuildingModel::toGeographic(const QVector &points) const { std::vector 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 BuildingModel::fromReference(const QVector &points) const { QVector 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 BuildingModel::toReference(const QVector &points) const { QVector 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