diff --git a/common/camera.cpp b/common/camera.cpp index 08e3f6b3..f59bc779 100644 --- a/common/camera.cpp +++ b/common/camera.cpp @@ -1079,7 +1079,25 @@ void lcCamera::RemoveTime(lcStep Start, lcStep Time) mUpVector.RemoveTime(Start, Time); } -void lcCamera::ZoomExtents(float AspectRatio, const lcVector3& Center, const std::vector& Points, lcStep Step, bool AddKey) +void lcCamera::ExpandFarPlane(const std::vector& Points) +{ + if (!IsSimple()) + return; + + float FarDistance = 0.0f; + + for (const lcVector3& Point : Points) + FarDistance = lcMax(FarDistance, -lcMul31(Point, mWorldView).z); + + // Orthographic views use four times the camera's far plane. + if (GetProjection() == lcCameraProjection::Orthographic) + FarDistance /= 4.0f; + + if (FarDistance > DefaultFarPlane && FarDistance > m_zFar) + m_zFar = ceilf(FarDistance * 1.1f / 10000.0f) * 10000.0f; +} + +void lcCamera::ZoomExtents(float AspectRatio, const lcVector3& Center, const std::vector& Points, lcStep Step, bool AddKey, bool AdjustFarPlane) { lcVector3 Position, TargetPosition; @@ -1137,6 +1155,9 @@ void lcCamera::ZoomExtents(float AspectRatio, const lcVector3& Center, const std mTargetPosition.ChangeKey(TargetPosition, Step, AddKey); UpdatePosition(Step); + + if (AdjustFarPlane) + ExpandFarPlane(Points); } void lcCamera::ZoomRegion(float AspectRatio, const lcVector3& Position, const lcVector3& TargetPosition, const lcVector3* Corners, lcStep Step, bool AddKey) diff --git a/common/camera.h b/common/camera.h index f1fdc52a..82a39528 100644 --- a/common/camera.h +++ b/common/camera.h @@ -204,7 +204,8 @@ public: void CopyPosition(const lcCamera* Camera); void CopySettings(const lcCamera* Camera); - void ZoomExtents(float AspectRatio, const lcVector3& Center, const std::vector& Points, lcStep Step, bool AddKey); + void ZoomExtents(float AspectRatio, const lcVector3& Center, const std::vector& Points, lcStep Step, bool AddKey, bool AdjustFarPlane); + void ExpandFarPlane(const std::vector& Points); void ZoomRegion(float AspectRatio, const lcVector3& Position, const lcVector3& TargetPosition, const lcVector3* Corners, lcStep Step, bool AddKey); void Zoom(float Distance, lcStep Step, bool AddKey); void Pan(const lcVector3& Distance, lcStep Step, bool AddKey); @@ -222,7 +223,8 @@ public: float m_fovy = 30.0f; float m_zNear = 25.0f; - float m_zFar = 50000; + static constexpr float DefaultFarPlane = 50000.0f; + float m_zFar = DefaultFarPlane; lcMatrix44 mWorldView; lcObjectProperty mPosition = lcObjectProperty(lcVector3(0.0f, 0.0f, 0.0f)); diff --git a/common/lc_application.cpp b/common/lc_application.cpp index 3e9e1577..b4810ed0 100644 --- a/common/lc_application.cpp +++ b/common/lc_application.cpp @@ -1148,7 +1148,7 @@ lcStartupMode lcApplication::Initialize(const QList>& Libra { const lcStep FitStep = Options.ImageStart == Options.ImageEnd ? Options.ImageStart : ActiveModel->GetLastStep(); - ActiveModel->ZoomExtentsAtStep(ActiveView->GetCamera(), (float)ActiveView->GetWidth() / (float)ActiveView->GetHeight(), FitStep, lcGeometryBoundsMode::AvailableGeometryOnly); + ActiveView->ZoomExtentsAtStep(FitStep, lcGeometryBoundsMode::AvailableOnly, !Options.SetZPlanes); } auto ProgressCallback = [&StdOut](const QString& FileName) diff --git a/common/lc_global.h b/common/lc_global.h index 58d5a3ae..a2cedb83 100644 --- a/common/lc_global.h +++ b/common/lc_global.h @@ -63,12 +63,6 @@ class QPrinter; typedef quint32 lcStep; #define LC_STEP_MAX 0xffffffff -enum class lcGeometryBoundsMode -{ - IncludeFallbackGeometry, - AvailableGeometryOnly -}; - // Version number. #define LC_VERSION_MAJOR 26 #define LC_VERSION_MINOR 9 @@ -78,6 +72,7 @@ enum class lcGeometryBoundsMode // Forward declarations. class Project; class lcModel; +enum class lcGeometryBoundsMode; class lcObject; class lcPiece; class lcCamera; diff --git a/common/lc_mainwindow.cpp b/common/lc_mainwindow.cpp index dcd03b70..db94411f 100644 --- a/common/lc_mainwindow.cpp +++ b/common/lc_mainwindow.cpp @@ -1737,7 +1737,7 @@ void lcMainWindow::RestoreTabLayout(const QByteArray& TabLayout) if (Model) { - SetCurrentModelTab(Model); + SetCurrentModelTab(Model, false); TabWidget = (lcModelTabWidget*)mModelTabWidget->widget(mModelTabWidget->count() - 1); } @@ -1792,6 +1792,7 @@ void lcMainWindow::RestoreTabLayout(const QByteArray& TabLayout) Camera->SetUpVector(UpVector, 1, false); } Camera->UpdatePosition(1); + Camera->ExpandFarPlane(CurrentView->GetModel()->GetPiecesBoundingBoxPoints(lcGeometryBoundsMode::IncludeFallback)); } } else @@ -1857,7 +1858,7 @@ void lcMainWindow::CloseCurrentModelTab() NewProject(); } -void lcMainWindow::SetCurrentModelTab(lcModel* Model) +void lcMainWindow::SetCurrentModelTab(lcModel* Model, bool AdjustFarPlane) { for (int TabIdx = 0; TabIdx < mModelTabWidget->count(); TabIdx++) { @@ -1884,7 +1885,7 @@ void lcMainWindow::SetCurrentModelTab(lcModel* Model) ViewWidget->show(); ViewWidget->setFocus(); - NewView->ZoomExtents(); + NewView->ZoomExtents(lcGeometryBoundsMode::IncludeFallback, AdjustFarPlane); } void lcMainWindow::AddView(lcView* View) @@ -2152,7 +2153,7 @@ void lcMainWindow::ResetViews() ViewWidget->show(); ViewWidget->setFocus(); - NewView->ZoomExtents(); + NewView->ZoomExtents(lcGeometryBoundsMode::IncludeFallback, true); } void lcMainWindow::ToggleDockWidget(QWidget* DockWidget) @@ -3401,7 +3402,7 @@ void lcMainWindow::HandleCommand(lcCommandId CommandId) case LC_VIEW_ZOOM_EXTENTS: if (ActiveView) - ActiveView->ZoomExtents(); + ActiveView->ZoomExtents(lcGeometryBoundsMode::IncludeFallback, false); break; case LC_VIEW_LOOK_AT: diff --git a/common/lc_mainwindow.h b/common/lc_mainwindow.h index 2d2dffa4..b8c7713c 100644 --- a/common/lc_mainwindow.h +++ b/common/lc_mainwindow.h @@ -199,7 +199,7 @@ public: void RestoreTabLayout(const QByteArray& TabLayout); void RemoveAllModelTabs(); void CloseCurrentModelTab(); - void SetCurrentModelTab(lcModel* Model); + void SetCurrentModelTab(lcModel* Model, bool AdjustFarPlane); void AddView(lcView* View); void RemoveView(lcView* View); diff --git a/common/lc_minifigdialog.cpp b/common/lc_minifigdialog.cpp index 8b7bd5e4..b852f0fd 100644 --- a/common/lc_minifigdialog.cpp +++ b/common/lc_minifigdialog.cpp @@ -7,6 +7,7 @@ #include "pieceinf.h" #include "lc_library.h" #include "lc_view.h" +#include "lc_model.h" #include "camera.h" #include "lc_doublespinbox.h" #include "lc_qutils.h" @@ -133,7 +134,7 @@ lcMinifigDialog::lcMinifigDialog(QWidget* Parent) mMinifigWizard->Calculate(); mView->GetCamera()->SetViewpoint(lcVector3(0.0f, -270.0f, 90.0f)); - mView->ZoomExtents(); + mView->ZoomExtents(lcGeometryBoundsMode::IncludeFallback, false); ui->buttonBox->button(QDialogButtonBox::StandardButton::Ok)->setFocus(); diff --git a/common/lc_model.cpp b/common/lc_model.cpp index d8ff5e25..32473863 100644 --- a/common/lc_model.cpp +++ b/common/lc_model.cpp @@ -1731,14 +1731,20 @@ lcResult lcModel::RenderStepImageWithReadyAssets(bool Zoom, int Width, i View.SetOffscreenContext(); View.MakeCurrent(); + View.SetSize(Width, Height); if (!OutputCamera && !ActiveView) - ZoomExtentsAtStep(View.GetCamera(), (float)Width / (float)Height, GetLastStep(), lcGeometryBoundsMode::AvailableGeometryOnly); + { + SetTemporaryStep(GetLastStep()); + View.ZoomExtents(lcGeometryBoundsMode::AvailableOnly, true); + } SetTemporaryStep(Step); if (Zoom && ActiveView && !OutputCamera) - ZoomExtents(View.GetCamera(), (float)Width / (float)Height, lcMatrix44Identity(), lcGeometryBoundsMode::AvailableGeometryOnly); + { + View.ZoomExtents(lcGeometryBoundsMode::AvailableOnly, true); + } if (!View.BeginRenderToImage(Width, Height)) { @@ -2057,14 +2063,23 @@ lcResult lcModel::SaveStepImages(const QString& BaseName, bool AddStepSuff { WaitForAssets(); - lcCamera OutputCamera(true); + std::unique_ptr OutputView; lcCamera* Camera = nullptr; if (!gMainWindow || !gMainWindow->GetActiveView()) { - OutputCamera.SetViewpoint(lcViewpoint::Home); - ZoomExtentsAtStep(&OutputCamera, (float)Width / (float)Height, GetLastStep(), lcGeometryBoundsMode::AvailableGeometryOnly); - Camera = &OutputCamera; + const lcStep CurrentStep = mCurrentStep; + + OutputView = std::make_unique(lcViewType::View, this); + OutputView->SetSize(Width, Height); + SetTemporaryStep(GetLastStep()); + OutputView->ZoomExtents(lcGeometryBoundsMode::AvailableOnly, true); + SetTemporaryStep(CurrentStep); + + if (!mActive) + CalculateStep(LC_STEP_MAX); + + Camera = OutputView->GetCamera(); } for (lcStep Step = Start; Step <= End; Step++) @@ -2184,7 +2199,7 @@ void lcModel::SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::v { const lcMesh* Mesh = mPieceInfo ? mPieceInfo->GetDisplayMesh() : nullptr; - if (Mode == lcGeometryBoundsMode::AvailableGeometryOnly && mPieceInfo && mPieceInfo->mState != lcPieceInfoState::Loaded) + if (Mode == lcGeometryBoundsMode::AvailableOnly && mPieceInfo && mPieceInfo->mState != lcPieceInfoState::Loaded) Mesh = nullptr; if (Mesh) @@ -4864,7 +4879,7 @@ std::vector lcModel::GetPiecesBoundingBoxPoints(lcGeometryBoundsMode std::vector Points; const lcMesh* Mesh = mPieceInfo ? mPieceInfo->GetDisplayMesh() : nullptr; - if (Mode == lcGeometryBoundsMode::AvailableGeometryOnly && mPieceInfo && mPieceInfo->mState != lcPieceInfoState::Loaded) + if (Mode == lcGeometryBoundsMode::AvailableOnly && mPieceInfo && mPieceInfo->mState != lcPieceInfoState::Loaded) Mesh = nullptr; if (Mesh) @@ -6038,7 +6053,7 @@ void lcModel::MoveCamera(lcCamera* Camera, const lcVector3& Direction) } } -void lcModel::ZoomExtents(lcCamera* Camera, float Aspect, const lcMatrix44& WorldMatrix, lcGeometryBoundsMode Mode) +void lcModel::ZoomExtents(lcCamera* Camera, float Aspect, const lcMatrix44& WorldMatrix, lcGeometryBoundsMode Mode, bool AdjustFarPlane) { std::vector Points = GetPiecesBoundingBoxPoints(Mode); @@ -6063,7 +6078,7 @@ void lcModel::ZoomExtents(lcCamera* Camera, float Aspect, const lcMatrix44& Worl BeginEditHistory(); } - Camera->ZoomExtents(Aspect, Center, Points, mCurrentStep, gMainWindow ? gMainWindow->GetAddKeys() : false); + Camera->ZoomExtents(Aspect, Center, Points, mCurrentStep, gMainWindow ? gMainWindow->GetAddKeys() : false, AdjustFarPlane); if (!mIsPreview && gMainWindow) gMainWindow->UpdateSelectedObjects(false); @@ -6077,18 +6092,6 @@ void lcModel::ZoomExtents(lcCamera* Camera, float Aspect, const lcMatrix44& Worl } } -void lcModel::ZoomExtentsAtStep(lcCamera* Camera, float Aspect, lcStep Step, lcGeometryBoundsMode Mode) -{ - const lcStep CurrentStep = mCurrentStep; - - SetTemporaryStep(Step); - ZoomExtents(Camera, Aspect, lcMatrix44Identity(), Mode); - SetTemporaryStep(CurrentStep); - - if (!mActive) - CalculateStep(LC_STEP_MAX); -} - void lcModel::Zoom(lcCamera* Camera, float Amount) { if (!Camera->IsSimple()) diff --git a/common/lc_model.h b/common/lc_model.h index c9a043fe..6586ba3b 100644 --- a/common/lc_model.h +++ b/common/lc_model.h @@ -5,6 +5,12 @@ #include "lc_objectproperty.h" #include "lc_result.h" +enum class lcGeometryBoundsMode +{ + IncludeFallback, + AvailableOnly +}; + enum class lcCameraProjection; struct lcSetInventoryItem; struct lcModelHistoryEditState; @@ -424,8 +430,7 @@ public: void ZoomRegionToolClicked(lcView* View, float AspectRatio, const lcVector3& Position, const lcVector3& TargetPosition, const lcVector3* Corners); void LookAt(lcCamera* Camera); void MoveCamera(lcCamera* Camera, const lcVector3& Direction); - void ZoomExtents(lcCamera* Camera, float Aspect, const lcMatrix44& WorldMatrix, lcGeometryBoundsMode Mode); - void ZoomExtentsAtStep(lcCamera* Camera, float Aspect, lcStep Step, lcGeometryBoundsMode Mode); + void ZoomExtents(lcCamera* Camera, float Aspect, const lcMatrix44& WorldMatrix, lcGeometryBoundsMode Mode, bool AdjustFarPlane); void Zoom(lcCamera* Camera, float Amount); void MoveSelectedObjects(const lcVector3& Distance, lcModelTransformFlags Flags, lcModelHistoryEditMerge ModelHistoryEditMerge) diff --git a/common/lc_previewwidget.cpp b/common/lc_previewwidget.cpp index 0e5cf903..b837691f 100644 --- a/common/lc_previewwidget.cpp +++ b/common/lc_previewwidget.cpp @@ -195,7 +195,7 @@ void lcPreviewDockWidget::RefreshPendingAssets() } if (mAssetRefreshPending && mRefitAfterAssetLoad) - mPreview->ZoomExtents(); + mPreview->ZoomExtents(lcGeometryBoundsMode::IncludeFallback, false); mAssetRefreshPending = false; mRefitAfterAssetLoad = true; @@ -321,7 +321,7 @@ bool lcPreview::SetCurrentPiece(PieceInfo* Info, int ColorCode) mModel->UpdatePieceInfo(UpdatedModels); Library->ReleasePieceInfo(Info); - ZoomExtents(); + ZoomExtents(lcGeometryBoundsMode::IncludeFallback, true); return true; } diff --git a/common/lc_thumbnailmanager.cpp b/common/lc_thumbnailmanager.cpp index f42008dd..250ebc70 100644 --- a/common/lc_thumbnailmanager.cpp +++ b/common/lc_thumbnailmanager.cpp @@ -377,7 +377,7 @@ void lcThumbnailManager::DrawThumbnail(lcPartThumbnailId ThumbnailId, lcPartThum mView->GetCamera()->SetViewpoint(Position, Center, lcVector3(0, 0, 1)); mView->GetCamera()->m_fovy = 20.0f; - mView->ZoomExtents(); + mView->ZoomExtents(lcGeometryBoundsMode::IncludeFallback, false); mView->OnDraw(); diff --git a/common/lc_view.cpp b/common/lc_view.cpp index c1ae797a..e19e7c81 100644 --- a/common/lc_view.cpp +++ b/common/lc_view.cpp @@ -1832,7 +1832,7 @@ void lcView::SetViewpoint(lcViewpoint Viewpoint) } mCamera->SetViewpoint(Viewpoint); - ZoomExtents(); + ZoomExtents(lcGeometryBoundsMode::IncludeFallback, false); Redraw(); } @@ -1849,7 +1849,7 @@ void lcView::SetViewpoint(const lcVector3& Position) } mCamera->SetViewpoint(Position); - ZoomExtents(); + ZoomExtents(lcGeometryBoundsMode::IncludeFallback, false); Redraw(); } @@ -1882,7 +1882,7 @@ void lcView::SetCameraAngles(float Latitude, float Longitude) } mCamera->SetAngles(Latitude, Longitude, 1.0f); - ZoomExtents(); + ZoomExtents(lcGeometryBoundsMode::IncludeFallback, false); Redraw(); } @@ -1892,7 +1892,7 @@ void lcView::SetDefaultCamera() mCamera = new lcCamera(true); mCamera->SetViewpoint(lcViewpoint::Home); - ZoomExtents(); + ZoomExtents(lcGeometryBoundsMode::IncludeFallback, false); Redraw(); } @@ -1978,7 +1978,7 @@ void lcView::Zoom(float Amount) ActiveModel->Zoom(mCamera, Amount); } -void lcView::ZoomExtents() +void lcView::ZoomExtents(lcGeometryBoundsMode Mode, bool AdjustFarPlane) { lcModel* ActiveModel = GetActiveModel(); @@ -1986,10 +1986,27 @@ void lcView::ZoomExtents() { const lcMatrix44 WorldMatrix = mActiveSubmodelInstance ? mActiveSubmodelTransform : lcMatrix44Identity(); - ActiveModel->ZoomExtents(mCamera, (float)mWidth / (float)mHeight, WorldMatrix, lcGeometryBoundsMode::IncludeFallbackGeometry); + ActiveModel->ZoomExtents(mCamera, (float)mWidth / (float)mHeight, WorldMatrix, Mode, AdjustFarPlane); } } +void lcView::ZoomExtentsAtStep(lcStep Step, lcGeometryBoundsMode Mode, bool AdjustFarPlane) +{ + lcModel* ActiveModel = GetActiveModel(); + + if (!ActiveModel) + return; + + const lcStep CurrentStep = ActiveModel->GetCurrentStep(); + + ActiveModel->SetTemporaryStep(Step); + ZoomExtents(Mode, AdjustFarPlane); + ActiveModel->SetTemporaryStep(CurrentStep); + + if (!ActiveModel->IsActive()) + ActiveModel->CalculateStep(LC_STEP_MAX); +} + lcCursor lcView::GetCursor() const { const lcTool CurrentTool = GetCurrentTool(); @@ -2840,7 +2857,7 @@ void lcView::OnLeftButtonDoubleClick() { if (mViewType != lcViewType::View) { - ZoomExtents(); + ZoomExtents(lcGeometryBoundsMode::IncludeFallback, false); return; } diff --git a/common/lc_view.h b/common/lc_view.h index 35d782d0..882d3328 100644 --- a/common/lc_view.h +++ b/common/lc_view.h @@ -275,7 +275,8 @@ public: void LookAt(); void MoveCamera(const lcVector3& Direction); void Zoom(float Amount); - void ZoomExtents(); + void ZoomExtents(lcGeometryBoundsMode Mode, bool AdjustFarPlane); + void ZoomExtentsAtStep(lcStep Step, lcGeometryBoundsMode Mode, bool AdjustFarPlane); void RemoveCamera(); void ShowContextMenu() const; diff --git a/common/lc_viewwidget.cpp b/common/lc_viewwidget.cpp index aaeac2b2..2cb7f1b6 100644 --- a/common/lc_viewwidget.cpp +++ b/common/lc_viewwidget.cpp @@ -100,7 +100,7 @@ bool lcViewWidget::event(QEvent* Event) break; case Qt::SmartZoomNativeGesture: - mView->ZoomExtents(); + mView->ZoomExtents(lcGeometryBoundsMode::IncludeFallback, false); break; default: diff --git a/common/piece.cpp b/common/piece.cpp index 3076f734..c98ee513 100644 --- a/common/piece.cpp +++ b/common/piece.cpp @@ -1145,7 +1145,7 @@ void lcPiece::SubModelCompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector void lcPiece::SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector& Points, lcGeometryBoundsMode Mode) const { - if (Mode == lcGeometryBoundsMode::AvailableGeometryOnly && mPieceInfo->GetSynthInfo() && !HasGeneratedMesh()) + if (Mode == lcGeometryBoundsMode::AvailableOnly && mPieceInfo->GetSynthInfo() && !HasGeneratedMesh()) return; lcMesh* Mesh = GetDisplayMesh(); diff --git a/common/pieceinf.cpp b/common/pieceinf.cpp index a02d8a1e..ba832b1c 100644 --- a/common/pieceinf.cpp +++ b/common/pieceinf.cpp @@ -422,7 +422,7 @@ void PieceInfo::CompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min void PieceInfo::AddSubModelBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector& Points, lcGeometryBoundsMode Mode) const { - if (Mode == lcGeometryBoundsMode::AvailableGeometryOnly) + if (Mode == lcGeometryBoundsMode::AvailableOnly) { if (IsModel()) { diff --git a/common/project.cpp b/common/project.cpp index f78bf796..a1d8c084 100644 --- a/common/project.cpp +++ b/common/project.cpp @@ -233,7 +233,7 @@ void Project::SetActiveModel(lcModel* ActiveModel, bool UpdateInterface) if (!mIsPreview && gMainWindow && UpdateInterface) { - gMainWindow->SetCurrentModelTab(mActiveModel); + gMainWindow->SetCurrentModelTab(mActiveModel, true); mActiveModel->UpdateInterface(); } } diff --git a/docs/asset-loading.md b/docs/asset-loading.md index 2410cf1d..decd8347 100644 --- a/docs/asset-loading.md +++ b/docs/asset-loading.md @@ -27,6 +27,25 @@ the visible step. The spinner hides immediately when work settles; there is no until the project's failures disappear or the project changes. Views redraw and update bounds as results arrive, but keep the user's camera. +Interactive and output camera fits go through `lcView::ZoomExtents()`, with +fallback geometry included for interactive views and only available geometry +included for outputs. The view delegates fitting and saved camera undo history +to `lcModel::ZoomExtents()`. `lcView::ZoomExtentsAtStep()` restores the model's +current step after fitting. +The adjustment flag passes through view, model, and camera. The camera adjusts +clipping after updating its fitted position, using the fit's transformed bounding +points without collecting bounds again. +The view fit entry points take an explicit `AdjustFarPlane` flag. Initial view +and preview fits and automatic image output fits enable it, using the bounds +available at that time; ordinary fits disable it. The distance expands only when +those bounds extend beyond both the default 50,000 and the current distance. Later asset +updates, redraws, navigation, and fits do not adjust clipping again. +Increases include a 10% margin and round up to multiples of 10,000; they never +shrink the distance or change saved model cameras. Explicit command-line clipping +planes remain authoritative for image output. +Restored tab layouts defer clipping adjustment until the ordinary camera's saved +position and settings have been applied, so a saved distance cannot undo the +load-time expansion. Named model cameras retain their saved clipping settings. During synth edits, the previous generated mesh stays visible until a replacement settles. Images and geometry exports wait for their requirements and omit failed geometry instead of saving loading cubes. See [Caller policies](#caller-policies) @@ -355,8 +374,8 @@ including current synth generations, and repeats picking before placement. If loading fails, both dragging and insertion use the available or fallback geometry rather than rejecting placement. -Automatic output fitting uses `lcGeometryBoundsMode::AvailableGeometryOnly`; -interactive fitting uses `IncludeFallbackGeometry`. A whole-model wait can +Automatic output fitting uses `lcGeometryBoundsMode::AvailableOnly`; +interactive fitting uses `IncludeFallback`. A whole-model wait can conservatively include later steps even when output requests an earlier step. Scene flags preventing fallback cubes do not themselves initiate a wait or guarantee success. See [lc_view.cpp](../common/lc_view.cpp) and