/** * @RDE_HEADER@ * Math claculations for VWM * $Id$ * $HeadURL$ * $Author$ * Created by Christian Ehrlicher, SLSE, 2017-01-24 */ #include "vwm_math.h" #include #include // [GUEZE-483] RPL Nr 756: Steilfeuer Mörser auf Gebäude // values take from xml file have 3 digits. Therefore 0.00001 is to small // use 0.002 #define epsilon 0.002 namespace BuildingControlUnit { namespace VWM { namespace Math { static NGL::INGLLogger &logger() { return BuildingControlUnit::getLogger("VWM.Math"); } LtsUtils::QPoint3D rotateAroundYAxis(const LtsUtils::QPoint3D &in, double phi) { LtsUtils::QPoint3D a1( cos(phi), 0, -sin(phi)); LtsUtils::QPoint3D a2( 0, 1, 0); LtsUtils::QPoint3D a3( sin(phi), 0, cos(phi)); return LtsUtils::QPoint3D(LtsUtils::QPoint3D::dotProduct(a1, in), LtsUtils::QPoint3D::dotProduct(a2, in), LtsUtils::QPoint3D::dotProduct(a3, in)); } LtsUtils::QPoint3D rotateAroundZAxis(const LtsUtils::QPoint3D &in, double phi) { LtsUtils::QPoint3D a1( cos(phi), sin(phi), 0); LtsUtils::QPoint3D a2(-sin(phi), cos(phi), 0); LtsUtils::QPoint3D a3( 0, 0, 1); return LtsUtils::QPoint3D(LtsUtils::QPoint3D::dotProduct(a1, in), LtsUtils::QPoint3D::dotProduct(a2, in), LtsUtils::QPoint3D::dotProduct(a3, in)); } static inline double getDet2(double a11, double a12, double a21, double a22) { return a11 * a22 - a12 * a21; } static inline double getDet3(const LtsUtils::QPoint3D &a1, const LtsUtils::QPoint3D &a2, const LtsUtils::QPoint3D &a3) { double sum = 0; sum += (a1.x() * a2.y() * a3.z() + a1.y() * a2.z() * a3.x() + a1.z() * a2.x() * a3.y()); sum -= (a1.z() * a2.y() * a3.x() - a1.y() * a2.x() * a3.z() - a1.x() * a2.z() * a3.y()); return sum; } VwmPlane::VwmPlane(const LtsUtils::QPoint3D &pos, const LtsUtils::QPoint3D &vec1, const LtsUtils::QPoint3D &vec2) : m_pos(pos) , m_vec1(vec1 - pos) , m_vec2(vec2 - pos) { m_det.setX(getDet2(m_vec1.y(), m_vec1.z(), m_vec2.y(), m_vec2.z())); m_det.setY(getDet2(m_vec1.z(), m_vec1.x(), m_vec2.z(), m_vec2.x())); m_det.setZ(getDet2(m_vec1.x(), m_vec1.y(), m_vec2.x(), m_vec2.y())); m_planeC = LtsUtils::QPoint3D::dotProduct(m_pos, m_det); } bool VwmPlane::getPlaneEquation() const { if (qFuzzyIsNull(m_det.z()) && qFuzzyIsNull(m_det.x()) && qFuzzyIsNull(m_det.y())) return false; return true; } bool VwmPlane::isPlaneLineIntersection(const LtsUtils::QPoint3D &vec) const { const double det = getDet3(vec, m_vec1, m_vec2); if (qFuzzyIsNull(det)) return false; return true; } bool VwmPlane::isPlaneLineOrthogonal(const LtsUtils::QPoint3D &dir) const { const double nv = LtsUtils::QPoint3D::dotProduct(m_det, dir); return (qFuzzyIsNull(nv)); } double VwmPlane::getPlaneLineSkalar(const LtsUtils::QPoint3D &pos, const LtsUtils::QPoint3D &dir) const { const double nv = LtsUtils::QPoint3D::dotProduct(m_det, dir); if (qFuzzyIsNull(nv)) return 0; const double np = LtsUtils::QPoint3D::dotProduct(m_det, pos); return (m_planeC - np) / nv; } LtsUtils::QPoint3D VwmPlane::getPlaneLineIntersection(const LtsUtils::QPoint3D &pos, const LtsUtils::QPoint3D &dir) const { const double lambda = getPlaneLineSkalar(pos, dir); LtsUtils::QPoint3D ret (pos + (dir * lambda)); return ret; } double VwmPlane::distPlaneToPoint(const LtsUtils::QPoint3D &pos, const LtsUtils::QPoint3D &dir) const { const double f = m_det.length(); const double dp = LtsUtils::QPoint3D::dotProduct(m_det, pos); double dist = (m_planeC - dp) / f; dist *= (LtsUtils::QPoint3D::dotProduct(m_det, dir) < 0) ? -1.0 : 1.0; return dist; } bool vecIsLinearlyDependent(const LtsUtils::QPoint3D &v1, const LtsUtils::QPoint3D &v2) { double lambda; if (fabs(v1.x()) > epsilon) lambda = v2.x() / v1.x(); else if (fabs(v1.y()) > epsilon) lambda = v2.y() / v1.y(); else if (fabs(v1.z()) > epsilon) lambda = v2.z() / v1.z(); else return true; // dependent if ( (fabs(lambda*v1.x()-v2.x()) < epsilon) && (fabs(lambda*v1.y()-v2.y()) < epsilon) && (fabs(lambda*v1.z()-v2.z()) < epsilon)) { return true; // dependent } return false; // independent } // // polyIsLinearlyDependent is replaced by getCoordsForPlane(); // return value '0' can happen if isLinearlyDependent and as return at the end.... //int polyIsLinearlyDependent(const QVector &poly) //{ // NGL::INGLLogger &l = logger(); // // Check, if vector != 0 ///* for (int i = 0; i < poly.size()-1; ++i) // { // LtsUtils::QPoint3D v1 = poly.at(i+1) - poly.at(i); // DEBUG_LOG(l) << "isLinearlyDependent=" << std::boolalpha << isLinearlyDependent // << " i=" << i // << " v1=" << v1.x() << "/" << v1.y() << "/" << v1.z(); // if ( v1.x() * v1.x() + v1.y() * v1.y() + v1.z() * v1.z() > epsilon) // return i; // }*/ // // Check, if point is Linearly Dependent // for (int i = 0; i < poly.size()-2; ++i) // { // LtsUtils::QPoint3D v1 = poly.at(i+1) - poly.at(i); // LtsUtils::QPoint3D v2 = poly.at(i+2) - poly.at(i); // bool isLinearlyDependent = vecIsLinearlyDependent(v1, v2); // DEBUG_LOG(l) << "isLinearlyDependent=" << std::boolalpha << isLinearlyDependent // << " i=" << i // << " v1=" << v1.x() << "/" << v1.y() << "/" << v1.z() // << " v2=" << v2.x() << "/" << v2.y() << "/" << v2.z(); // if (isLinearlyDependent) // return i; // } // return 0; //} /* [GUEZE-483] RPL Nr 756: Steilfeuer Mörser auf Gebäude Bei weiterer Betrachtung ist aufgefallen, das bei bldg_1104 AWES auf die Ecken des Bldgs NICHT zu einem Zerstörung führen - Fehler. Bei der Analyse ergeben sich folgende Erkenntnisse: - Der epsilon-Wert war auf 0.0001. Da aber die Werte aus den den XML-Dateien eine Auflösung von 3Stellen (mm) aufweisen, sind Rechenfehler auch in dieser Größenordnung zu erwarten. Der epsilon-Wert wird in dem Zuge auf 0.002 gesetzt. - vecIsLinearlyDependent Hier war der return-Value vertauscht -> korrigiert. - polyIsLinearlyDependent War missverständlich/fehleranfällig, da im Falle von isLinearlyDependent grundsätzlich auch '0' zurückgegeben werden kann. dies aber auch der return-Value am Ende der Funktion ist... Was bedeutet nun also '0'??? - getCoordsForPlane wurde als Nachfolger von polyIsLinearlyDependent() eingeführt. Aus dem WallElement werden die ggf. vorhandenen linearen Abhänigkeiten entfernt. Der Aufrufer kann dann daraus eine Plane erstellen (Nutzung der 3 ersten Werte) - Der UnitTest 'VwmMathUnitTest' wurde erweitert: - Es werden einfache Gut- und Schlechtfälle wurden konstruiert. - Es werden realen Polygonzüge geprüft. (bldg 1104, Raum 401; bldg_salchau577...) */ QVector getCoordsForPlane(const QVector &poly) { NGL::INGLLogger &l = logger(); if (poly.size() < 3) return {}; QVector idxToRemove; for (int i = 0; i < poly.size()-2; ++i) { const LtsUtils::QPoint3D &v1 = poly.at(i+1) - poly.at(i); const LtsUtils::QPoint3D &v2 = poly.at(i+2) - poly.at(i); bool isLinearlyDependent = vecIsLinearlyDependent(v1, v2); DEBUG_LOG(l) << "isLinearlyDependent=" << isLinearlyDependent << " i=" << i << " v1=" << v1.x() << "/" << v1.y() << "/" << v1.z() << " v2=" << v2.x() << "/" << v2.y() << "/" << v2.z(); if (isLinearlyDependent) idxToRemove.push_front(i+1); } // for QVector ret = poly; for (auto idx : idxToRemove) ret.remove(idx); return ret; // Maybe there is a LinearlyDependency regarding beginning and and of vector. // Until now, this seems to be not relevant, since the first coordinates are taken. } bool isPointInPolygon(const QVector &poly, const LtsUtils::QPoint3D &pos) { NGL::INGLLogger &l = logger(); double anglesum = 0.0; double vz = 1.0; LtsUtils::QPoint3D vn; if (poly.size() < 3) return false; for (int i = 0; i < poly.size(); ++i) { DEBUG_LOG(l) << "calculate point i=" << i; const int nextIdx1 = (i + 1) % poly.size(); const int nextIdx2 = (i + 2) % poly.size(); const LtsUtils::QPoint3D &p1 = poly.at(i) - pos; const LtsUtils::QPoint3D &p2 = poly.at(nextIdx1) - pos; if (i == 0) vn = LtsUtils::QPoint3D::crossProduct(p1,p2); const double dist1 = p1.length(); const double dist2 = p2.length(); if (qFuzzyIsNull(dist1 * dist2)) { DEBUG_LOG(l) << "isPointInPolygon = false"; return false; } const double cosTheta = LtsUtils::QPoint3D::dotProduct(p1, p2) / (dist1 * dist2); anglesum += vz * acos(cosTheta); const LtsUtils::QPoint3D &n = LtsUtils::QPoint3D::crossProduct(vn, p2); const LtsUtils::QPoint3D &p3 = poly.at(nextIdx2) - pos; const double dp = LtsUtils::QPoint3D::dotProduct(n, p3); vz = (dp < 0) ? -1.0 : 1.0; } const double delta = 0.01; const double sum = (M_PI * 2) - fabs(anglesum); bool result = -delta < sum && sum < delta; DEBUG_LOG(l) << "isPointInPolygon=" << std::boolalpha << result << " (sum=" << sum << ", anglesum=" << anglesum << ")" << ", pos=" << pos; return result; } static inline bool getHitPositionInternal(const QVector &planePoints, const LtsUtils::QPoint3D &position, const LtsUtils::QPoint3D &direction, HitPosition &hitPos) { NGL::INGLLogger &l = logger(); if (planePoints.size() < 3) { WARNING_LOG(l) << "Wall with fewer than 3 points - modelling error!"; return false; } QVector localPoly = getCoordsForPlane(planePoints); if (localPoly.size() < 3) { ERROR_LOG(l) << "planePoints are not sufficiant"; for (auto coord : planePoints) ERROR_LOG(l) << "planePoints are not sufficiant: << " << coord; for (auto coord : qAsConst(localPoly)) ERROR_LOG(l) << "localPoly are not sufficiant: << " << coord; return false; } const VwmPlane vwmPlane(localPoly.at(0), localPoly.at(1), localPoly.at(2)); for ( int i = 0; i < localPoly.size(); ++i) { DEBUG_LOG(l) << "vwmPlane at(" << i << ")=" << localPoly.at(i).x() << "/" << localPoly.at(i).y() << "/" << localPoly.at(i).z() ; } DEBUG_LOG(l) << " plane params: p1 = " << vwmPlane.pos() << ", p2 = " << vwmPlane.vec1() << ", p3 = " << vwmPlane.vec2() << ", det = " << vwmPlane.det() << ", C = " << vwmPlane.planeC() << ", isVertical=" << vwmPlane.isVertical(); if (!vwmPlane.getPlaneEquation()) return false; DEBUG_LOG(l) << " getPlaneEquation = true"; if (!vwmPlane.isPlaneLineIntersection(direction)) return false; DEBUG_LOG(l) << " isPlaneLineIntersection = true"; const double lambda = vwmPlane.getPlaneLineSkalar(position, direction); if (lambda <= 0) return false; DEBUG_LOG(l) << " lambda = " << lambda; const LtsUtils::QPoint3D pos = vwmPlane.getPlaneLineIntersection(position, direction); DEBUG_LOG(l) << "pos=" << pos.x() << "/" << pos.y() << "/" << pos.z() << " position=" << position.x() << "/" << position.y() << "/" << position.z() << " direction=" << direction.x() << "/" << direction.y() << "/" << direction.z(); if (!isPointInPolygon(planePoints, pos)) return false; DEBUG_LOG(l) << " isPointInPolygon = true (pos=" << pos << ")"; // never negative since this will bailed out with getPlaneLineSkalar() above const double curDist = (pos - position).length(); // const double curDist = vwmPlane.distPlaneToPoint(position, direction); // ERROR_LOG(l) << "l: " << curDist << " = " << (pos - position).length(); DEBUG_LOG(l) << " distance = " << curDist; if (curDist > hitPos.distance) return false; hitPos.distance = curDist; return true; } HitPosition getHitPosition(const LtsUtils::QPoint3D &position, const LtsUtils::QPoint3D &direction, const QMap &rooms) { NGL::INGLLogger &l = logger(); INFO_LOG(l) << "XXXXX Searching hit position for position " << position << ", direction " << direction << ", #rooms = " << rooms.size(); HitPosition hitPos; for (const Room &room : rooms) { DEBUG_LOG(l) << "****** roomId: " << room.id() << ", #walls = " << room.outerWalls().size(); for (int idxOuterWall = 0; idxOuterWall < room.outerWalls().size(); ++idxOuterWall) { const OuterWall &wall = room.outerWalls().at(idxOuterWall); DEBUG_LOG(l) << " roomId: " << room.id() << ", wallIdx = " << idxOuterWall << ", #elements = " << wall.elements().size(); for (int idxWallElement = 0; idxWallElement < wall.elements().size(); ++idxWallElement) { const WallElement &wallElement = wall.elements().at(idxWallElement); DEBUG_LOG(l) << " roomId: " << room.id() << ", wallIdx = " << idxOuterWall << ", wElementIdx = " << idxWallElement; if (!getHitPositionInternal(wallElement, position, direction, hitPos)) continue; DEBUG_LOG(l) << " nearest distance = " << hitPos.distance << " on outer wall: roomId: " << room.id() << ", wallIdx = " << idxOuterWall << ", wElementIdx = " << idxWallElement; hitPos.state = HitPosition::State::OuterWall; hitPos.roomId = room.id(); hitPos.outerWallIdx = idxOuterWall; hitPos.exclusionZoneIdx = -1; for (int idxExclusionZone = 0; idxExclusionZone < wall.exclusionZones().size(); ++idxExclusionZone) { const ExclusionZone &ez = wall.exclusionZones().at(idxExclusionZone); DEBUG_LOG(l) << " roomId: " << room.id() << ", wallIdxx = " << idxOuterWall << ", wElementIdx = " << idxWallElement << " - exclusion zone element idx = " << idxExclusionZone << ", #elements = " << ez.elements().size(); for (int idxExclusionZoneElement = 0; idxExclusionZoneElement < ez.elements().size(); ++idxExclusionZoneElement) { const ExclusionZoneElement &ezElement = ez.elements().at(idxExclusionZoneElement); DEBUG_LOG(l) << " roomId: " << room.id() << ", wallIdx = " << idxOuterWall << ", wElementIdx = " << idxWallElement << " - exclusion zone element idx = " << idxExclusionZoneElement; if (!getHitPositionInternal(ezElement, position, direction, hitPos)) continue; hitPos.state = HitPosition::State::ExclusionZone; hitPos.exclusionZoneIdx = idxExclusionZone; DEBUG_LOG(l) << " nearest distance = " << hitPos.distance << " on exclusion zone"; } } } } } INFO_LOG(l) << "XXXXX HitPosition: " << hitPos.state << ", roomId = " << hitPos.roomId << ", outerWallIndex = " << hitPos.outerWallIdx << ", exclusionZoneIndex = " << hitPos.exclusionZoneIdx; return hitPos; } // ThorstenMeyer: Beim Treffer eines BSMs wird die HitRoomID wie folgt bestimmt //1. Berechnung des Strahls S durch das BSM in Schußrichtung: // Die Richtung „vwmDir3D“ wird mit der Funktion übergeben: // getHitPosition(VwmPosition3D* vwmCoord,VwmPosition3D* vwmDir3D) //2. Berechnung von 2 linear unabhängigen Vektoren durch die Differenzbildung von // Polygoneckpunkten einer OuterWall: // if (vwmPlaneOW.getIsLinearlyIndependent(…) // Achtung isLinearly_In_dependent vs isLinearlyDependent //3. Berechnung der durch die 2 linear unabhängigen Vektoren aufgespannten Ebene E: // vwmPlaneOW.getPlaneEquation(…) //4. Berechnung der Schnittpunktmenge des Strahls S und der Ebene E: // if (vwmPlaneOW.isPlaneLineIntersection(vwmDir3D)) //5. Überprüfung, ob die Schnittpunktmenge von S und E ein Punkt P ist: // if (vwmPlaneOW.getPlaneLineSkalar(vwmCoord,vwmDir3D) > 0) //6. Im Fall #Schnittpunktmenge=1: Überprüfung, ob der Punkt P im Polygon liegt. // if (vwmPolygonOW->calcPointInPolygon(posOW)) //7. Im Fall „Punkt in Polygon“: Berechnung Abstand von BSM zum „Punkt im Polygon“. // dist = vwmPlaneOW.distPlaneToPoint(vwmCoord); //8. Berechnung Abstände BSM zum „Punkt im Polygon“ für alle OuterWalls. //9. Bestimmung OuterWall OW (getroffene Außenwand) mit dem kürzesten Abstand BSM zum Punkt // im OuterWall-Polygon. //10. HitRoomID = Raumnummer des Raums, zu dem die OuterWall OW gehört. HitPosition checkBsmPosition(const LtsUtils::QPoint3D &position, const LtsUtils::QPoint3D &bsmViewDirection, const QMap &rooms) { NGL::INGLLogger &l = logger(); const LtsUtils::QPoint3D direction(bsmViewDirection * -1); INFO_LOG(l) << "XXXXX Searching nearest room for bsm position " << position << ", bsmViewDirection " << bsmViewDirection << ", hit direction " << direction << ", #rooms = " << rooms.size(); HitPosition hitPos; for (const Room &room : rooms) { DEBUG_LOG(l) << "room[" << room.id() << "] #walls = " << room.outerWalls().size(); for (int idxOuterWall = 0; idxOuterWall < room.outerWalls().size(); ++idxOuterWall) { const OuterWall &wall = room.outerWalls().at(idxOuterWall); DEBUG_LOG(l) << "room[" << room.id() << "]" << " wall[" << idxOuterWall << "] #elements = " << wall.elements().size(); for (int idxWallElement = 0; idxWallElement < wall.elements().size(); ++idxWallElement) { const WallElement &wallElement = wall.elements().at(idxWallElement); DEBUG_LOG(l) << "room[" << room.id() << "]" << " wallElement[" << idxWallElement << "] #points = " << wallElement.size(); if (wallElement.size() < 3) continue; // fix wallElement regarding polyIsLinearlyDependent // [GUEZE-483] RPL Nr 756: Steilfeuer Mörser auf Gebäude const QVector &localWallElement = getCoordsForPlane(wallElement); DEBUG_LOG(l) << "room[" << room.id() << "]" << " wallElement[" << idxWallElement << "] #points = " << localWallElement.size() << " after removing Linearly Dependent)"; if (localWallElement.size() < 3) { ERROR_LOG(l) << "localWallElement are not sufficiant"; for (auto coord : wallElement) ERROR_LOG(l) << "wallElement are not sufficiant: << " << coord; for (auto coord : qAsConst(localWallElement)) ERROR_LOG(l) << "localWallElement are not sufficiant: << " << coord; continue; } for (auto pointOfWallElementLinear : qAsConst(localWallElement)) DEBUG_LOG(l) << "room[" << room.id() << "]" << " wall[" << idxOuterWall << "] " << " wallElement[" << idxWallElement << "] #points = " << localWallElement.size() << ", pointOfWallElementLinear=" << pointOfWallElementLinear; const VwmPlane vwmPlaneOW(localWallElement.at(0), localWallElement.at(1), localWallElement.at(2)); DEBUG_LOG(l) << "room[" << room.id() << "]" << " wall[" << idxOuterWall << "]" << " wallElement[" << idxWallElement << "]" << ", planeOW params: p1 = " << vwmPlaneOW.pos() << ", p2 = " << vwmPlaneOW.vec1() << ", p3 = " << vwmPlaneOW.vec2() << ", det = " << vwmPlaneOW.det() << ", C = " << vwmPlaneOW.planeC() << ", vwmPlaneOW.isVertical=" << vwmPlaneOW.isVertical(); if (!vwmPlaneOW.getPlaneEquation()) continue; DEBUG_LOG(l) << " getPlaneEquation() = true"; if (!vwmPlaneOW.isPlaneLineIntersection(direction)) continue; DEBUG_LOG(l) << " isPlaneLineIntersection() = true -> direction=" << direction; // only check for orthogonal, do not check for correct direction (in contrast to getHitPosition() above) if (vwmPlaneOW.isPlaneLineOrthogonal(direction)) continue; const LtsUtils::QPoint3D posOW = vwmPlaneOW.getPlaneLineIntersection(position, direction); DEBUG_LOG(l) << " point to check: " << posOW; if (!isPointInPolygon(localWallElement, posOW)) continue; DEBUG_LOG(l) << " isPointInPolygon() = true"; const double curDistOW = vwmPlaneOW.distPlaneToPoint(position, direction); const double absDistOW = fabs(curDistOW); DEBUG_LOG(l) << " distance = " << curDistOW << " - room " << room.id(); if (absDistOW > fabs(hitPos.distance)) continue; hitPos.distance = curDistOW; hitPos.state = HitPosition::State::OuterWall; hitPos.roomId = room.id(); hitPos.outerWallIdx = idxOuterWall; DEBUG_LOG(l) << " XXXXX nearest distance = " << curDistOW << " on outer wall in room " << room.id() << "room[" << room.id() << "]" << " wall[" << idxOuterWall << "]" << " wallElement[" << idxWallElement << "]"; // we don't care about exclusion zones since they should be on the same plane as the wall } // for } // for } // for INFO_LOG(l) << "XXXXX HitPosition: " << hitPos.state << ", roomId = " << hitPos.roomId << ", outerWallIndex = " << hitPos.outerWallIdx << ", exclusionZoneIndex = " << hitPos.exclusionZoneIdx; return hitPos; } /////////////////////////////////////////////////////////////////////////////////////////////////// // Intersection methods // LtsUtils::QPoint3D getIntersectionInternal( const QVector &planePoints, const LtsUtils::QPoint3D &position, const LtsUtils::QPoint3D &direction ) { NGL::INGLLogger &l = logger(); if (planePoints.size() < 3) { WARNING_LOG(l) << "Wall with fewer than 3 points - modelling error!"; return invalidPosition(); } const QVector &localPoly = getCoordsForPlane(planePoints); if (localPoly.size() < 3) { ERROR_LOG(l) << "planePoints are not sufficiant"; for (auto coord : qAsConst(planePoints)) ERROR_LOG(l) << "planePoints are not sufficiant: << " << coord; for (auto coord : qAsConst(localPoly)) ERROR_LOG(l) << "localPoly are not sufficiant: << " << coord; return invalidPosition(); } const VwmPlane vwmPlane(localPoly.at(0), localPoly.at(1), localPoly.at(2)); if (l.isDebugEnabled()) { for ( int i = 0; i < localPoly.size(); ++i) DEBUG_LOG(l) << "vwmPlane at(" << i << ")=" << localPoly.at(i).x() << "/" << localPoly.at(i).y() << "/" << localPoly.at(i).z(); DEBUG_LOG(l) << "plane params: p1 = " << vwmPlane.pos() << ", p2 = " << vwmPlane.vec1() << ", p3 = " << vwmPlane.vec2() << ", det = " << vwmPlane.det() << ", C = " << vwmPlane.planeC(); } // if if (!vwmPlane.getPlaneEquation()) return invalidPosition(); DEBUG_LOG(l) << "getPlaneEquation() = true"; if (!vwmPlane.isPlaneLineIntersection(direction)) return invalidPosition(); DEBUG_LOG(l) << "isPlaneLineIntersection() = true"; const double planeLineScalar = vwmPlane.getPlaneLineSkalar(position, direction); if (planeLineScalar <= 0) return invalidPosition(); DEBUG_LOG(l) << "getPlaneLineSkalar() = " << planeLineScalar; const LtsUtils::QPoint3D pos = vwmPlane.getPlaneLineIntersection(position, direction); bool bIsPointInPolygon = isPointInPolygon(localPoly, pos); DEBUG_LOG(l) << "bIsPoinliotInPolygon = " << bIsPointInPolygon; return bIsPointInPolygon ? pos : invalidPosition(); } LtsUtils::QPoint3D intersection(const LtsUtils::QPoint3D &start, const LtsUtils::QPoint3D &end, const QMap &rooms) { NGL::INGLLogger &l = logger(); DEBUG_LOG(l) << "Searching for intersection: start = " << start << ", end = " << end; LtsUtils::QPoint3D intersectionPoint = invalidPosition(); double distance = (end - start).length(); const LtsUtils::QPoint3D direction = (end - start).normalized(); DEBUG_LOG(l) << "Searching for intersection: START" << ", intersectionPoint = " << intersectionPoint << ", distance = " << distance << ", direction = " << direction; int cnt = 0; int roomId4Debugging = 1; for (const Room &room : qAsConst(rooms)) for (const OuterWall &outerWall : qAsConst(room.outerWalls())) for (const WallElement &wallElement : qAsConst(outerWall.elements())) { const LtsUtils::QPoint3D point = getIntersectionInternal(wallElement, start, direction); DEBUG_LOG(l) << "getIntersectionInternal:" << " cnt = " << cnt++ << " room.id = " << room.id() << " - point=" << point; if (point == invalidPosition()) continue; const double dist = (point - start).length(); if (dist < distance) { DEBUG_LOG(l) << "Intersection found for room " << room.id() << ": " << point; intersectionPoint = point; distance = dist; roomId4Debugging =room.id(); } // if } // for if (roomId4Debugging > 0) DEBUG_LOG(l) << "Searching for intersection: FOUND" << ", intersectionPoint = " << intersectionPoint << ", distance = " << distance << ", direction = " << direction << ", at roomId=" << roomId4Debugging; return intersectionPoint; } bool hasIntersection(const LtsUtils::QPoint3D &start, const LtsUtils::QPoint3D &end, const QMap &rooms) { const double distance = (end - start).length(); const LtsUtils::QPoint3D direction = (end - start).normalized(); for (const Room &room : qAsConst(rooms)) for (const OuterWall &outerWall : qAsConst(room.outerWalls())) for (const WallElement &wallElement : qAsConst(outerWall.elements())) { const LtsUtils::QPoint3D point = getIntersectionInternal(wallElement, start, direction); if (point == invalidPosition()) continue; if ((start - point).length() > distance) continue; return true; } // for return false; } LtsUtils::QPoint3D invalidPosition() { return {100000., 100000., -10000.}; } } // namespace Math } // namespace VWM } // namespace BuildingControlUnit