mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-20 12:12:15 +00:00
77cf535b45
Replace Qt math wrappers with Eigen across ViewportWindow, OverlayRenderer, Federation, and the bonsai-side viewport modules. Eigen was already the canonical type for the actually-important matrix work (InstanceCompose, ModelGpuData, federation matrices); QVector3D/QVector4D/QMatrix4x4 were leftover from when Qt was the path of least resistance. They offered nothing over Eigen for our use case beyond a few graphics helpers (lookAt / perspective / ortho) which were 30 lines to write. Substitutions: QMatrix4x4 → Eigen::Matrix4f QVector2D → Eigen::Vector2f QVector3D → Eigen::Vector3f QVector4D → Eigen::Vector4f API rewrites: .lengthSquared() → .squaredNorm() .length() → .norm() .isNull() → .isZero() .setToIdentity() → .setIdentity() .constData() → .data() .toVector3D() → .head<3>() .inverted(&ok) → tryInvert4f(M, out) Q::dotProduct(a,b) → a.dot(b) Q::crossProduct(a,b) → a.cross(b) QMat4x4(... row-major) → Eigen::Map<const Matrix4f>(col-major buf) QMat4x4().lookAt(...) → lookAtRH(eye, target, up) QMat4x4().perspective(.) → perspectiveYFovGL(fovy, aspect, n, f) QMat4x4().ortho(...) → orthoGL(l, r, b, t, n, f) Default-init divergence handled explicitly (QMatrix4x4() = identity, QVector3D() = zero; Eigen leaves both uninitialized). Public API (CameraState, HomeView, ViewportWindow::computeObjectAabb, the addSectionPlaneAtSurface / pickSurfaceAt / raycast signatures) follows through to Eigen too; bonsai-side View.cpp and Commands.cpp updated to match. Camera helpers (lookAtRH, perspectiveYFovGL, orthoGL, tryInvert4f) extracted to a new CameraMath.h so OverlayRenderer's gizmo MVP and ViewportWindow's buildViewProj share the same definitions. Federation drops its <QVector3D> include in favour of <Eigen/Dense> (already had the latter for the georef matrices). Builds: desktop IfcViewerMinimal ✓, BonsaiViewer ✓, web IfcViewerWeb ✓. Tests: 100/100 pass. Closes #78 + #79; opens the door for #80-#83.
86 lines
4.2 KiB
C++
86 lines
4.2 KiB
C++
/********************************************************************************
|
|
* *
|
|
* This file is part of IfcOpenShell. *
|
|
* *
|
|
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
|
* it under the terms of the Lesser GNU General Public License as published by *
|
|
* the Free Software Foundation, either version 3.0 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* IfcOpenShell is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* Lesser GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the Lesser GNU General Public License *
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
|
* *
|
|
********************************************************************************/
|
|
|
|
#ifndef CAMERAMATH_H
|
|
#define CAMERAMATH_H
|
|
|
|
// Camera-matrix helpers. Eigen ships no lookAt/perspective/ortho out of
|
|
// the box (it's a math library, not a graphics one); QMatrix4x4 used to
|
|
// supply them. These functions reproduce QMatrix4x4's behaviour for the
|
|
// cases the viewport actually uses (right-handed lookAt, GL-clip
|
|
// perspective + ortho), expressed in column-major Eigen::Matrix4f so the
|
|
// result lands directly in u.view_proj for the GPU. Note both projection
|
|
// matrices target GL clip space [-1, 1] — callers pre-multiply by a
|
|
// z-remap matrix to land WebGPU's [0, 1].
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
#include <cmath>
|
|
|
|
inline Eigen::Matrix4f lookAtRH(const Eigen::Vector3f& eye,
|
|
const Eigen::Vector3f& target,
|
|
const Eigen::Vector3f& up) {
|
|
const Eigen::Vector3f f = (target - eye).normalized();
|
|
const Eigen::Vector3f s = f.cross(up).normalized();
|
|
const Eigen::Vector3f u = s.cross(f);
|
|
Eigen::Matrix4f m = Eigen::Matrix4f::Identity();
|
|
m(0, 0) = s.x(); m(0, 1) = s.y(); m(0, 2) = s.z(); m(0, 3) = -s.dot(eye);
|
|
m(1, 0) = u.x(); m(1, 1) = u.y(); m(1, 2) = u.z(); m(1, 3) = -u.dot(eye);
|
|
m(2, 0) = -f.x(); m(2, 1) = -f.y(); m(2, 2) = -f.z(); m(2, 3) = f.dot(eye);
|
|
return m;
|
|
}
|
|
|
|
inline Eigen::Matrix4f perspectiveYFovGL(float fovy_deg, float aspect,
|
|
float near_plane, float far_plane) {
|
|
const float fovy_rad = fovy_deg * float(M_PI) / 180.0f;
|
|
const float t = std::tan(fovy_rad * 0.5f);
|
|
Eigen::Matrix4f m = Eigen::Matrix4f::Zero();
|
|
m(0, 0) = 1.0f / (aspect * t);
|
|
m(1, 1) = 1.0f / t;
|
|
m(2, 2) = -(far_plane + near_plane) / (far_plane - near_plane);
|
|
m(2, 3) = -(2.0f * far_plane * near_plane) / (far_plane - near_plane);
|
|
m(3, 2) = -1.0f;
|
|
return m;
|
|
}
|
|
|
|
inline Eigen::Matrix4f orthoGL(float left, float right,
|
|
float bottom, float top,
|
|
float near_plane, float far_plane) {
|
|
Eigen::Matrix4f m = Eigen::Matrix4f::Identity();
|
|
m(0, 0) = 2.0f / (right - left);
|
|
m(1, 1) = 2.0f / (top - bottom);
|
|
m(2, 2) = -2.0f / (far_plane - near_plane);
|
|
m(0, 3) = -(right + left) / (right - left);
|
|
m(1, 3) = -(top + bottom) / (top - bottom);
|
|
m(2, 3) = -(far_plane + near_plane) / (far_plane - near_plane);
|
|
return m;
|
|
}
|
|
|
|
// Inverse-with-invertibility-check. QMatrix4x4::inverted(bool*)
|
|
// returned identity (silently) on a singular matrix and flipped the
|
|
// `ok` out-parameter; Eigen's .inverse() always runs even on singular
|
|
// input. computeInverseWithCheck is the safe equivalent.
|
|
inline bool tryInvert4f(const Eigen::Matrix4f& M, Eigen::Matrix4f& out) {
|
|
bool invertible = false;
|
|
M.computeInverseWithCheck(out, invertible, /*absDetThreshold=*/0);
|
|
return invertible;
|
|
}
|
|
|
|
#endif // CAMERAMATH_H
|