Skip to content

Apply custom segments when building MswSegments#758

Closed
magnesj wants to merge 6 commits intodevfrom
msw-split-intersections-at-custom-boundaries
Closed

Apply custom segments when building MswSegments#758
magnesj wants to merge 6 commits intodevfrom
msw-split-intersections-at-custom-boundaries

Conversation

@magnesj
Copy link
Copy Markdown
Owner

@magnesj magnesj commented Mar 16, 2026

No description provided.

magnesj added 6 commits March 16, 2026 09:02
Iterate per-model bounding boxes and skip models outside the camera frustum to prevent distant off-screen objects from inflating the far plane. This improves depth buffer precision and reduces z-fighting.

Enforce a maximum far/near ratio of 3000.0 by pushing the near plane forward if necessary. Additionally, refine the near plane adjustment when zooming into a point of interest to prevent geometry clipping.
…mand feature

Use CAF_PDM_LOG_ERROR and qFatal to notify the developer with an actionable
message when a command feature ID is not registered in the factory. This
replaces the silent CAF_ASSERT and makes it clear that the feature may have
been deleted without removing all references in appendMenuItems().
…lding RicMswSegment objects

Previously, custom segment intervals were applied only during WELSEGS output generation
in collectWelsegsSegment(), so RicMswSegment objects were built purely from grid cell
boundaries. Completions and intersection lengths were therefore attached to full
cell-crossing segments rather than to the correct custom-interval sub-segments.

Add splitIntersectionsAtCustomBoundaries() to RicWellPathExportMswTableData, called
after filterIntersections() in generateWellSegmentsForMswExportInfo(). For each custom
interval boundary MD that falls strictly inside a WellPathCellIntersectionInfo, the
intersection is split at that MD: the split point is interpolated from the well path
geometry and intersectionLengthsInCellCS is recomputed using
RigWellPathIntersectionTools::calculateLengthInCell, matching the pattern already used
in filterIntersections(). Each resulting RicMswSegment now spans at most one custom
interval, ensuring completions and intersection data are assigned correctly.
…ration

Custom interval boundaries are now applied before RicMswSegment objects are created
(via splitIntersectionsAtCustomBoundaries), so each segment already spans at most one
custom interval by the time output is generated. The downstream WELSEGS output chain
no longer needs to re-apply these boundaries.

Remove the customSegmentIntervals parameter from createSubSegmentMDPairs,
collectWelsegsSegment, collectValveWelsegsSegment, collectCompletionsForSegment,
collectCompletionWelsegsSegments, collectWelsegsDataRecursively, and collectWelsegsData.
Simplify createSubSegmentMDPairs to only subdivide by maxSegmentLength.
…gment

When a custom segment interval spans multiple grid cells, the previous implementation
still created one RicMswSegment per cell crossing inside that interval. Custom intervals
are now honoured: consecutive cell intersections that fall within the same custom interval
are grouped and create a single RicMswSegment spanning the full interval.

In createWellPathSegments(), after the boundary split, cell intersections are grouped:
cells in the same custom interval are merged into one SegmentGroup; cells outside all
custom intervals remain as individual groups. One RicMswSegment is created per group.
Perforation completions are still assigned per-cell within the group so that COMPSEGS
output retains correct per-cell intersection data.

The processedIntersections (boundary-split) vector replaces filteredIntersections in the
assignValveContributionsToSuperXICDs call to keep consistent cell-level detail there too.
…terval segments

Add isCustomInterval flag to RicMswSegment. For segments marked as custom
intervals, skip maxSegmentLength subdivision in WELSEGS output and use the
segment end MD as the WELSEGS length reference point instead of the cell midpoint.
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

MSW: Apply custom segments at intersection level before building segments

✨ Enhancement 🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Split cell intersections at custom segment boundaries before building RicMswSegment objects
  - Ensures completions and intersection lengths are assigned to correct custom-interval sub-segments
  - Adds splitIntersectionsAtCustomBoundaries() function to process intersections early
• Remove custom segment interval handling from WELSEGS output generation
  - Simplifies collectWelsegsSegment() by eliminating complex interval-aware subdivision logic
  - Custom intervals now honored as single output rows without maxSegmentLength subdivision
• Improve near/far clipping plane calculation in viewer
  - Iterate per-model bounding boxes and skip models outside camera frustum
  - Enforce maximum far/near ratio of 3000.0 to preserve depth buffer precision
• Enhance error handling for unknown command features
  - Replace silent CAF_ASSERT with clear error message and qFatal notification
Diagram
flowchart LR
  A["Cell Intersections"] -->|splitIntersectionsAtCustomBoundaries| B["Split at Custom Boundaries"]
  B -->|createWellPathSegments| C["RicMswSegment Objects"]
  C -->|collectWelsegsData| D["WELSEGS Output"]
  E["Custom Intervals"] -.->|define boundaries| B
  F["maxSegmentLength"] -.->|no longer used in createSubSegmentMDPairs| D
Loading

Grey Divider

File Changes

1. ApplicationLibCode/Commands/CompletionExportCommands/RicMswSegment.h ✨ Enhancement +5/-0

Add custom interval tracking to RicMswSegment

• Add setIsCustomInterval() and isCustomInterval() accessor methods
• Add m_isCustomInterval boolean member variable to track if segment spans a custom interval

ApplicationLibCode/Commands/CompletionExportCommands/RicMswSegment.h


2. ApplicationLibCode/Commands/CompletionExportCommands/RicMswSegment.cpp ✨ Enhancement +16/-0

Implement custom interval accessor methods

• Implement setIsCustomInterval() setter method
• Implement isCustomInterval() const getter method

ApplicationLibCode/Commands/CompletionExportCommands/RicMswSegment.cpp


3. ApplicationLibCode/Commands/CompletionExportCommands/RicMswTableDataTools.h ✨ Enhancement +46/-55

Remove custom interval parameters from function signatures

• Remove customSegmentIntervals parameter from all function signatures
• Simplify function declarations for collectWelsegsData, collectWelsegsDataRecursively,
 collectWelsegsSegment, collectValveWelsegsSegment, collectCompletionsForSegment,
 collectCompletionWelsegsSegments
• Simplify createSubSegmentMDPairs() to only take startMD, endMD, maxSegmentLength

ApplicationLibCode/Commands/CompletionExportCommands/RicMswTableDataTools.h


View more (5)
4. ApplicationLibCode/Commands/CompletionExportCommands/RicMswTableDataTools.cpp ✨ Enhancement +82/-197

Simplify WELSEGS output generation by removing interval handling

• Remove customSegmentIntervals parameter from all function implementations
• Simplify collectWelsegsSegment() to use effectiveMaxLength = 0.0 for custom intervals instead
 of complex subdivision
• Change reference point calculation from midpoint to end MD for custom interval segments
• Completely rewrite createSubSegmentMDPairs() to remove custom interval boundary handling logic
• Update all function calls to remove custom interval arguments

ApplicationLibCode/Commands/CompletionExportCommands/RicMswTableDataTools.cpp


5. ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportMswTableData.h ✨ Enhancement +7/-0

Add intersection splitting and custom interval support

• Add splitIntersectionsAtCustomBoundaries() static method declaration
• Add customSegmentIntervals parameter to createWellPathSegments() signature

ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportMswTableData.h


6. ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportMswTableData.cpp ✨ Enhancement +185/-21

Implement intersection splitting at custom boundaries

• Add splitIntersectionsAtCustomBoundaries() function to split intersections at custom interval
 boundaries
• Refactor generateWellSegmentsForMswExportInfo() to call new splitting function before segment
 creation
• Rewrite createWellPathSegments() to group consecutive intersections within same custom interval
 into single segment
• Mark segments with setIsCustomInterval() flag based on whether they span a custom interval
• Remove customSegmentIntervals parameter from collectWelsegsData() call

ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportMswTableData.cpp


7. Fwk/AppFwk/cafCommand/cafCmdFeatureManager.cpp Error handling +10/-1

Improve error handling for unknown command features

• Add #include "cafPdmLogging.h" header
• Replace silent CAF_ASSERT with explicit error logging and qFatal call
• Provide actionable error message indicating command feature may have been deleted without removing
 references

Fwk/AppFwk/cafCommand/cafCmdFeatureManager.cpp


8. Fwk/AppFwk/cafViewer/cafViewer.cpp ✨ Enhancement +56/-20

Improve near/far clipping plane calculation with frustum culling

• Refactor calculateNearFarPlanes() to iterate per-model bounding boxes instead of scene-wide bbox
• Skip models entirely outside camera frustum to prevent distant off-screen objects from inflating
 far plane
• Add fallback to scene-wide bounding box if no model contributes
• Enforce maximum far/near ratio of 3000.0 by pushing near plane forward
• Refine near plane adjustment when camera is inside bounding box to prevent geometry clipping
• Change near plane calculation from CVF_MIN to CVF_MAX for point of interest distance

Fwk/AppFwk/cafViewer/cafViewer.cpp


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Mar 16, 2026

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (1) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Viewer near/far plane changes 📘 Rule violation ⛯ Reliability
Description
This PR modifies camera near/far plane calculation behavior in
caf::Viewer::calculateNearFarPlanes(), which is unrelated to MSW segment export logic. These
changes expand PR scope and increase the chance of unintended rendering regressions.
Code

Fwk/AppFwk/cafViewer/cafViewer.cpp[R604-614]

+    // Enforce a maximum far/near ratio to preserve depth buffer precision.
+    // A 24-bit depth buffer has ~16 M discrete depth values; a far/near ratio of N
+    // means the nearest 1/N of the view depth gets half of those values.
+    // At 3000 the near zone still receives ~5500 depth steps per unit, which is
+    // sufficient for typical reservoir models. Pushing the near plane forward is
+    // preferable to allowing z-fighting from a degraded far plane.
+    const double maxFarNearRatio = 3000.0;
+    if ( ( *nearPlaneDist ) > 0 && ( ( *farPlaneDist ) / ( *nearPlaneDist ) ) > maxFarNearRatio )
+    {
+        ( *nearPlaneDist ) = ( *farPlaneDist ) / maxFarNearRatio;
+    }
Evidence
Compliance ID 1 requires minimal, task-relevant diffs. The added depth-buffer precision enforcement
and other frustum/model iteration logic in cafViewer.cpp is a separate rendering concern from MSW
segment building.

CLAUDE.md
Fwk/AppFwk/cafViewer/cafViewer.cpp[604-614]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
This PR includes rendering/camera near/far plane logic changes in `Fwk/AppFwk/cafViewer/cafViewer.cpp` that are not directly related to applying custom segments when building `MswSegments`.

## Issue Context
To comply with minimal-diff requirements, unrelated improvements should be split into separate PRs unless explicitly required by the MSW segmentation task.

## Fix Focus Areas
- Fwk/AppFwk/cafViewer/cafViewer.cpp[604-614]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Custom MD uses segment end 🐞 Bug ✓ Correctness
Description
RicMswTableDataTools::collectWelsegsSegment uses subEndMD as the WELSEGS reference/output MD for
segments marked isCustomInterval, changing LENGTH/DEPTH (and diameter/roughness sampling) away from
the existing midpoint convention used elsewhere in the MSW export code.
Code

ApplicationLibCode/Commands/CompletionExportCommands/RicMswTableDataTools.cpp[R173-178]

+    // Custom interval segments are honoured as a single output row — do not subdivide by maxSegmentLength.
+    const double effectiveMaxLength = segment->isCustomInterval() ? 0.0 : maxSegmentLength;
+    std::vector<std::pair<double, double>> segments = RicMswTableDataTools::createSubSegmentMDPairs( startMD, endMD, effectiveMaxLength );

    CVF_ASSERT( branch->wellPath() );
Evidence
The PR changes the WELSEGS reference point from midpoint to end MD for custom-interval segments, but
other code explicitly documents/assumes WELSEGS is reported at the midpoint of a segment and even
sets outputMD to midpoint for valve-related WELSEGS export. This creates inconsistent segment
positioning semantics between custom and non-custom segments.

ApplicationLibCode/Commands/CompletionExportCommands/RicMswTableDataTools.cpp[173-201]
ApplicationLibCode/Commands/CompletionExportCommands/RicMswTableDataTools.cpp[210-266]
ApplicationLibCode/Commands/CompletionExportCommands/RicMswBranch.cpp[178-185]
ApplicationLibCode/Commands/CompletionExportCommands/RicWellPathExportMswTableData.cpp[1440-1444]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Custom-interval MSW segments are currently exported with `refMD = subEndMD` and `outputMD = refMD`, while the codebase documents/assumes WELSEGS segment positions are reported at segment midpoints. This changes LENGTH/DEPTH and property sampling semantics only for custom segments.

### Issue Context
The PR already correctly prevents further subdivision of custom-interval segments via `effectiveMaxLength = 0.0`. The remaining change needed is to keep the midpoint reference point for WELSEGS calculations.

### Fix Focus Areas
- ApplicationLibCode/Commands/CompletionExportCommands/RicMswTableDataTools.cpp[173-266]
- ApplicationLibCode/Commands/CompletionExportCommands/RicMswBranch.cpp[178-185]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Near plane formula reversed 🐞 Bug ✓ Correctness
Description
caf::Viewer::calculateNearFarPlanes states it will move the near plane closer when the camera is
inside the bounding box, but the new code sets nearPlaneDist using CVF_MAX(default,
pointOfInterestDist*0.1), which cannot move the near plane closer than the previously computed value
and can instead push it farther away.
Code

Fwk/AppFwk/cafViewer/cafViewer.cpp[R578-585]

+        // If the camera is inside (or past) the bounding box, allow the near plane to move
+        // closer to the camera based on the point of interest distance, so zooming into details
+        // does not clip geometry.
+        if ( minDistEyeToCornerAlongViewDir <= 0 && m_navigationPolicy.notNull() && m_navigationPolicyEnabled )
        {
            double pointOfInterestDist = ( eye - navPointOfinterest ).length();
-            ( *nearPlaneDist )         = CVF_MIN( ( *nearPlaneDist ), pointOfInterestDist * 0.2 );
+            ( *nearPlaneDist )         = CVF_MAX( m_defaultPerspectiveNearPlaneDistance, pointOfInterestDist * 0.1 );
        }
Evidence
The comment explicitly describes moving the near plane closer to avoid clipping, but the implemented
expression uses a max() with a positive distance-derived term, which makes the near plane stay the
same or increase.

Fwk/AppFwk/cafViewer/cafViewer.cpp[575-585]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The near-plane adjustment path meant to reduce clipping when zooming uses `CVF_MAX(...)`, which can only keep or increase the near plane distance, contradicting the stated intent of moving it closer.

### Issue Context
This logic triggers when `minDistEyeToCornerAlongViewDir &lt;= 0` and navigation policy is enabled.

### Fix Focus Areas
- Fwk/AppFwk/cafViewer/cafViewer.cpp[575-589]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
4. Far plane can’t expand 🐞 Bug ⛯ Reliability
Description
caf::Viewer::calculateNearFarPlanes now excludes models whose bounding boxes are outside the
camera’s current frustum when computing farPlaneDist, so models beyond the current far clip are
never considered and farPlaneDist cannot grow to include them unless no model contributes and the
fallback path runs.
Code

Fwk/AppFwk/cafViewer/cafViewer.cpp[R525-563]

+    cvf::Frustum      viewFrustum         = rendering->camera()->frustum();
+    const cvf::Scene* scene               = rendering->scene();
+    bool              anyModelContributed = false;
+
+    if ( scene )
+    {
+        for ( cvf::uint mIdx = 0; mIdx < scene->modelCount(); ++mIdx )
        {
-            maxDistEyeToCornerAlongViewDir = distEyeBoxCornerAlongViewDir;
+            const cvf::Model* model   = scene->model( mIdx );
+            cvf::BoundingBox  modelBB = model->boundingBox();
+
+            if ( !modelBB.isValid() ) continue;
+            if ( viewFrustum.isOutside( modelBB ) ) continue;
+
+            cvf::Vec3d corners[8];
+            modelBB.cornerVertices( corners );
+            for ( int cIdx = 0; cIdx < 8; ++cIdx )
+            {
+                double dist                    = ( corners[cIdx] - eye ) * viewdir;
+                maxDistEyeToCornerAlongViewDir = CVF_MAX( maxDistEyeToCornerAlongViewDir, dist );
+                minDistEyeToCornerAlongViewDir = CVF_MIN( minDistEyeToCornerAlongViewDir, dist );
+            }
+            anyModelContributed = true;
        }
+    }

-        if ( distEyeBoxCornerAlongViewDir < minDistEyeToCornerAlongViewDir )
+    if ( !anyModelContributed )
+    {
+        // Fallback: use the scene-wide bounding box (original behaviour)
+        cvf::BoundingBox bb = rendering->boundingBox();
+        cvf::Vec3d       bboxCorners[8];
+        bb.cornerVertices( bboxCorners );
+        for ( int bcIdx = 0; bcIdx < 8; ++bcIdx )
        {
-            minDistEyeToCornerAlongViewDir = distEyeBoxCornerAlongViewDir; // Sometimes negative-> behind camera
+            double dist                    = ( bboxCorners[bcIdx] - eye ) * viewdir;
+            maxDistEyeToCornerAlongViewDir = CVF_MAX( maxDistEyeToCornerAlongViewDir, dist );
+            minDistEyeToCornerAlongViewDir = CVF_MIN( minDistEyeToCornerAlongViewDir, dist );
        }
    }
Evidence
The function uses camera->frustum() (derived from the camera projection matrix/clip planes) to cull
models before computing the new far plane. Because the far plane is one of the frustum planes,
anything beyond the current far clip is filtered out and cannot influence the next far plane
computation as long as at least one nearer model contributes (preventing the fallback).

Fwk/AppFwk/cafViewer/cafViewer.cpp[525-548]
Fwk/AppFwk/cafViewer/cafViewer.cpp[551-563]
Fwk/VizFwk/LibRender/cvfCamera.cpp[824-832]
Fwk/VizFwk/LibGeometry/cvfFrustum.cpp[201-227]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Far plane calculation currently filters models via `camera()-&gt;frustum()` before computing the new far plane, which can prevent farPlaneDist from expanding to include distant models beyond the current far clip.

### Issue Context
The fallback to scene-wide bounding box runs only when *no* model contributes, so the failure mode occurs when some nearer model contributes but a farther in-view model is clipped.

### Fix Focus Areas
- Fwk/AppFwk/cafViewer/cafViewer.cpp[525-563]
- Fwk/VizFwk/LibRender/cvfCamera.cpp[824-832]
- Fwk/VizFwk/LibGeometry/cvfFrustum.cpp[201-227]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +604 to +614
// Enforce a maximum far/near ratio to preserve depth buffer precision.
// A 24-bit depth buffer has ~16 M discrete depth values; a far/near ratio of N
// means the nearest 1/N of the view depth gets half of those values.
// At 3000 the near zone still receives ~5500 depth steps per unit, which is
// sufficient for typical reservoir models. Pushing the near plane forward is
// preferable to allowing z-fighting from a degraded far plane.
const double maxFarNearRatio = 3000.0;
if ( ( *nearPlaneDist ) > 0 && ( ( *farPlaneDist ) / ( *nearPlaneDist ) ) > maxFarNearRatio )
{
( *nearPlaneDist ) = ( *farPlaneDist ) / maxFarNearRatio;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. viewer near/far plane changes 📘 Rule violation ⛯ Reliability

This PR modifies camera near/far plane calculation behavior in
caf::Viewer::calculateNearFarPlanes(), which is unrelated to MSW segment export logic. These
changes expand PR scope and increase the chance of unintended rendering regressions.
Agent Prompt
## Issue description
This PR includes rendering/camera near/far plane logic changes in `Fwk/AppFwk/cafViewer/cafViewer.cpp` that are not directly related to applying custom segments when building `MswSegments`.

## Issue Context
To comply with minimal-diff requirements, unrelated improvements should be split into separate PRs unless explicitly required by the MSW segmentation task.

## Fix Focus Areas
- Fwk/AppFwk/cafViewer/cafViewer.cpp[604-614]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +173 to 178
// Custom interval segments are honoured as a single output row — do not subdivide by maxSegmentLength.
const double effectiveMaxLength = segment->isCustomInterval() ? 0.0 : maxSegmentLength;
std::vector<std::pair<double, double>> segments = RicMswTableDataTools::createSubSegmentMDPairs( startMD, endMD, effectiveMaxLength );

CVF_ASSERT( branch->wellPath() );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Custom md uses segment end 🐞 Bug ✓ Correctness

RicMswTableDataTools::collectWelsegsSegment uses subEndMD as the WELSEGS reference/output MD for
segments marked isCustomInterval, changing LENGTH/DEPTH (and diameter/roughness sampling) away from
the existing midpoint convention used elsewhere in the MSW export code.
Agent Prompt
### Issue description
Custom-interval MSW segments are currently exported with `refMD = subEndMD` and `outputMD = refMD`, while the codebase documents/assumes WELSEGS segment positions are reported at segment midpoints. This changes LENGTH/DEPTH and property sampling semantics only for custom segments.

### Issue Context
The PR already correctly prevents further subdivision of custom-interval segments via `effectiveMaxLength = 0.0`. The remaining change needed is to keep the midpoint reference point for WELSEGS calculations.

### Fix Focus Areas
- ApplicationLibCode/Commands/CompletionExportCommands/RicMswTableDataTools.cpp[173-266]
- ApplicationLibCode/Commands/CompletionExportCommands/RicMswBranch.cpp[178-185]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +578 to 585
// If the camera is inside (or past) the bounding box, allow the near plane to move
// closer to the camera based on the point of interest distance, so zooming into details
// does not clip geometry.
if ( minDistEyeToCornerAlongViewDir <= 0 && m_navigationPolicy.notNull() && m_navigationPolicyEnabled )
{
double pointOfInterestDist = ( eye - navPointOfinterest ).length();
( *nearPlaneDist ) = CVF_MIN( ( *nearPlaneDist ), pointOfInterestDist * 0.2 );
( *nearPlaneDist ) = CVF_MAX( m_defaultPerspectiveNearPlaneDistance, pointOfInterestDist * 0.1 );
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Near plane formula reversed 🐞 Bug ✓ Correctness

caf::Viewer::calculateNearFarPlanes states it will move the near plane closer when the camera is
inside the bounding box, but the new code sets nearPlaneDist using CVF_MAX(default,
pointOfInterestDist*0.1), which cannot move the near plane closer than the previously computed value
and can instead push it farther away.
Agent Prompt
### Issue description
The near-plane adjustment path meant to reduce clipping when zooming uses `CVF_MAX(...)`, which can only keep or increase the near plane distance, contradicting the stated intent of moving it closer.

### Issue Context
This logic triggers when `minDistEyeToCornerAlongViewDir <= 0` and navigation policy is enabled.

### Fix Focus Areas
- Fwk/AppFwk/cafViewer/cafViewer.cpp[575-589]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +525 to 563
cvf::Frustum viewFrustum = rendering->camera()->frustum();
const cvf::Scene* scene = rendering->scene();
bool anyModelContributed = false;

if ( scene )
{
for ( cvf::uint mIdx = 0; mIdx < scene->modelCount(); ++mIdx )
{
maxDistEyeToCornerAlongViewDir = distEyeBoxCornerAlongViewDir;
const cvf::Model* model = scene->model( mIdx );
cvf::BoundingBox modelBB = model->boundingBox();

if ( !modelBB.isValid() ) continue;
if ( viewFrustum.isOutside( modelBB ) ) continue;

cvf::Vec3d corners[8];
modelBB.cornerVertices( corners );
for ( int cIdx = 0; cIdx < 8; ++cIdx )
{
double dist = ( corners[cIdx] - eye ) * viewdir;
maxDistEyeToCornerAlongViewDir = CVF_MAX( maxDistEyeToCornerAlongViewDir, dist );
minDistEyeToCornerAlongViewDir = CVF_MIN( minDistEyeToCornerAlongViewDir, dist );
}
anyModelContributed = true;
}
}

if ( distEyeBoxCornerAlongViewDir < minDistEyeToCornerAlongViewDir )
if ( !anyModelContributed )
{
// Fallback: use the scene-wide bounding box (original behaviour)
cvf::BoundingBox bb = rendering->boundingBox();
cvf::Vec3d bboxCorners[8];
bb.cornerVertices( bboxCorners );
for ( int bcIdx = 0; bcIdx < 8; ++bcIdx )
{
minDistEyeToCornerAlongViewDir = distEyeBoxCornerAlongViewDir; // Sometimes negative-> behind camera
double dist = ( bboxCorners[bcIdx] - eye ) * viewdir;
maxDistEyeToCornerAlongViewDir = CVF_MAX( maxDistEyeToCornerAlongViewDir, dist );
minDistEyeToCornerAlongViewDir = CVF_MIN( minDistEyeToCornerAlongViewDir, dist );
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Far plane can’t expand 🐞 Bug ⛯ Reliability

caf::Viewer::calculateNearFarPlanes now excludes models whose bounding boxes are outside the
camera’s current frustum when computing farPlaneDist, so models beyond the current far clip are
never considered and farPlaneDist cannot grow to include them unless no model contributes and the
fallback path runs.
Agent Prompt
### Issue description
Far plane calculation currently filters models via `camera()->frustum()` before computing the new far plane, which can prevent farPlaneDist from expanding to include distant models beyond the current far clip.

### Issue Context
The fallback to scene-wide bounding box runs only when *no* model contributes, so the failure mode occurs when some nearer model contributes but a farther in-view model is clipped.

### Fix Focus Areas
- Fwk/AppFwk/cafViewer/cafViewer.cpp[525-563]
- Fwk/VizFwk/LibRender/cvfCamera.cpp[824-832]
- Fwk/VizFwk/LibGeometry/cvfFrustum.cpp[201-227]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@magnesj magnesj closed this Mar 26, 2026
@magnesj magnesj deleted the msw-split-intersections-at-custom-boundaries branch March 26, 2026 11:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant