mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-10-02 04:59:52 +00:00
ifcviewer: add incremental orbit/pan/zoom to ViewportCore (#85)
The orbit navigation math lived in the Qt ViewportWindow, operating on ViewportCore's camera fields through references. That left the web host with no way to drive the camera — orbit/pan/zoom were Qt-only. Lift the three pixel-delta moves into ViewportCore as orbitBy / panBy / dollyBy so every host (Qt desktop + web) shares one implementation and the math can't drift between platforms. panBy takes the viewport height as a parameter (the one Qt coupling: pan's world-units-per-pixel needs it) so the core stays toolkit-free. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -445,6 +445,53 @@ void ViewportCore::setStandardView(float yaw_deg, float pitch_deg) {
|
|||||||
host_->requestFrame();
|
host_->requestFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViewportCore::orbitBy(float dx_px, float dy_px) {
|
||||||
|
// 0.4 deg/px matches the GL viewport. pitch is clamped just shy of
|
||||||
|
// the pole so orbitEye() stays well-conditioned.
|
||||||
|
camera_yaw_deg_ -= dx_px * 0.4f;
|
||||||
|
camera_pitch_deg_ += dy_px * 0.4f;
|
||||||
|
camera_pitch_deg_ = std::clamp(camera_pitch_deg_, -89.9f, 89.9f);
|
||||||
|
host_->requestFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewportCore::panBy(float dx_px, float dy_px, int viewport_height_px) {
|
||||||
|
constexpr float kDeg2Rad = float(M_PI) / 180.0f;
|
||||||
|
|
||||||
|
// Pan in the camera's screen-space plane. Within 1° of straight
|
||||||
|
// up/down the world-Z up-reference degenerates (cross with forward
|
||||||
|
// is the zero vector → NaN), so switch to world-Y up — matches the
|
||||||
|
// up-vector switch in buildViewProj so top/bottom views still pan.
|
||||||
|
const Eigen::Vector3f target(camera_target_[0], camera_target_[1], camera_target_[2]);
|
||||||
|
const Eigen::Vector3f eye = orbitEye(camera_target_, camera_distance_,
|
||||||
|
camera_yaw_deg_, camera_pitch_deg_);
|
||||||
|
const Eigen::Vector3f fwd = (target - eye).normalized();
|
||||||
|
const Eigen::Vector3f world_up = (std::abs(camera_pitch_deg_) >= 89.0f)
|
||||||
|
? Eigen::Vector3f(0.0f, 1.0f, 0.0f)
|
||||||
|
: Eigen::Vector3f(0.0f, 0.0f, 1.0f);
|
||||||
|
const Eigen::Vector3f right = fwd.cross(world_up).normalized();
|
||||||
|
const Eigen::Vector3f up = right.cross(fwd).normalized();
|
||||||
|
|
||||||
|
const float half_h_world = camera_distance_
|
||||||
|
* std::tan(camera_fov_y_deg_ * 0.5f * kDeg2Rad);
|
||||||
|
const float pan_per_pixel = (viewport_height_px > 0)
|
||||||
|
? (2.0f * half_h_world / float(viewport_height_px))
|
||||||
|
: 0.0f;
|
||||||
|
|
||||||
|
const Eigen::Vector3f shift = -right * (dx_px * pan_per_pixel)
|
||||||
|
+ up * (dy_px * pan_per_pixel);
|
||||||
|
camera_target_[0] += shift.x();
|
||||||
|
camera_target_[1] += shift.y();
|
||||||
|
camera_target_[2] += shift.z();
|
||||||
|
host_->requestFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewportCore::dollyBy(float notches) {
|
||||||
|
// Each notch zooms ~10% in/out; sign matches "wheel up = in".
|
||||||
|
const float factor = std::pow(0.9f, notches);
|
||||||
|
camera_distance_ = std::max(0.01f, camera_distance_ * factor);
|
||||||
|
host_->requestFrame();
|
||||||
|
}
|
||||||
|
|
||||||
void ViewportCore::toggleProjection() {
|
void ViewportCore::toggleProjection() {
|
||||||
projection_ortho_ = !projection_ortho_;
|
projection_ortho_ = !projection_ortho_;
|
||||||
std::fprintf(stderr, "[info] [wgpu] projection: %s\n",
|
std::fprintf(stderr, "[info] [wgpu] projection: %s\n",
|
||||||
|
|||||||
@@ -184,6 +184,26 @@ public:
|
|||||||
void setCamera(float tx, float ty, float tz,
|
void setCamera(float tx, float ty, float tz,
|
||||||
float dist, float yaw_deg, float pitch_deg);
|
float dist, float yaw_deg, float pitch_deg);
|
||||||
void setStandardView(float yaw_deg, float pitch_deg);
|
void setStandardView(float yaw_deg, float pitch_deg);
|
||||||
|
|
||||||
|
// ---- Incremental orbit navigation ---------------------------------------
|
||||||
|
//
|
||||||
|
// Pixel-delta camera moves, shared by every host (Qt desktop + web).
|
||||||
|
// Hosts translate raw pointer/wheel events into these calls and own
|
||||||
|
// their own UI concerns (drag promotion, pivot indicator, cursor
|
||||||
|
// capture); the orbit math lives here so it can't drift between
|
||||||
|
// platforms. Each schedules a frame via the host.
|
||||||
|
//
|
||||||
|
// orbitBy: drag-right yaws the world right (yaw -= dx), drag-down
|
||||||
|
// tilts the camera up (pitch += dy). 0.4 deg/px matches GL.
|
||||||
|
// panBy: shifts the target in the camera's screen plane; world
|
||||||
|
// units/pixel track the frustum height at the pivot so the
|
||||||
|
// feel is zoom-independent. Needs the viewport height.
|
||||||
|
// dollyBy: each wheel notch zooms ~10% (distance *= 0.9^notches);
|
||||||
|
// positive notches zoom in.
|
||||||
|
void orbitBy(float dx_px, float dy_px);
|
||||||
|
void panBy(float dx_px, float dy_px, int viewport_height_px);
|
||||||
|
void dollyBy(float notches);
|
||||||
|
|
||||||
void toggleProjection();
|
void toggleProjection();
|
||||||
bool projectionOrtho() const { return projection_ortho_; }
|
bool projectionOrtho() const { return projection_ortho_; }
|
||||||
std::string cameraString() const;
|
std::string cameraString() const;
|
||||||
|
|||||||
Reference in New Issue
Block a user