mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-24 22:27:55 -05:00
Zoom All could pass a zero view direction (eye equal to view reference point). The up vector then also became zero, giving a plane with a zero normal and an assert in Plane::distanceToOrigin. Fall back to the Y axis when the direction is zero or undefined. Follow-up to the parallel dir/up fix in #14849. Call stack: [5] cvf::AssertHandlerConsole::handleAssert(char const*, int, char const*, char const*) at cvfAssert.cpp:125 [6] cvf::Plane::distanceToOrigin() const at cvfPlane.cpp:313 [7] cvf::Camera::computeFitViewEyePosition(cvf::BoundingBox const&, cvf::Vector3<double> const&, cvf::Vector3<double> const&, double, double, double) at cvfCamera.cpp:361 [8] caf::Viewer::zoomAll() at cafViewer.cpp:992 [9] caf::CmdFeature::actionTriggered(bool) at cafCmdFeature.cpp:176
129 lines
5.0 KiB
C++
129 lines
5.0 KiB
C++
#include "gtest/gtest.h"
|
|
|
|
#include "cvfBoundingBox.h"
|
|
#include "cvfCamera.h"
|
|
#include "cvfFrustum.h"
|
|
|
|
using namespace cvf;
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Camera::computeViewFrustum() returns an empty frustum for a degenerate projection matrix. View
|
|
/// frustum culling in ModelBasicList::partVisible() then asserted in Frustum::isOutside().
|
|
//--------------------------------------------------------------------------------------------------
|
|
TEST( CvfCameraCrashTriageTest, IncompleteFrustumDoesNotCull )
|
|
{
|
|
Frustum frustum;
|
|
|
|
BoundingBox bb;
|
|
bb.add( Vec3d( 0, 0, 0 ) );
|
|
bb.add( Vec3d( 1, 1, 1 ) );
|
|
|
|
EXPECT_FALSE( frustum.isOutside( bb ) );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// computeFitViewEyePosition() used to assert/abort (CVF_ASSERT in Plane::distanceToOrigin) when
|
|
/// the view direction and up vector are parallel: dir^up then becomes a zero vector, producing an
|
|
/// invalid (zero-normal) plane used internally. Reproduces the crash reported from
|
|
/// caf::Viewer::zoomAll() with a degenerate camera orientation.
|
|
//--------------------------------------------------------------------------------------------------
|
|
TEST( CvfCameraCrashTriageTest, FitViewWithParallelDirAndUpDoesNotCrash )
|
|
{
|
|
Camera c;
|
|
|
|
BoundingBox bb;
|
|
bb.add( Vec3d( 0, 0, 0 ) );
|
|
bb.add( Vec3d( 1, 1, 1 ) );
|
|
|
|
Vec3d inViewDir( 0, 0, 1 );
|
|
Vec3d inUp( 0, 0, 1 );
|
|
double coverageFactor = 0.9;
|
|
|
|
Vec3d eye = Camera::computeFitViewEyePosition( bb, inViewDir, inUp, coverageFactor, c.fieldOfViewYDeg(), 1.0 );
|
|
|
|
EXPECT_FALSE( eye.isUndefined() );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// fitView() must also produce a valid, non-singular camera orientation when dir and up are
|
|
/// parallel: it uses the (uncorrected) up vector both for setFromLookAt() and internally in
|
|
/// computeFitViewEyePosition()/createLookAtMatrix(), so the whole up vector derivation must be
|
|
/// consistent, not only the right vector used to compute the eye position.
|
|
//--------------------------------------------------------------------------------------------------
|
|
TEST( CvfCameraCrashTriageTest, FitViewWithParallelDirAndUpProducesValidViewMatrix )
|
|
{
|
|
Camera c;
|
|
c.setViewport( 0, 0, 100, 100 );
|
|
|
|
BoundingBox bb;
|
|
bb.add( Vec3d( 0, 0, 0 ) );
|
|
bb.add( Vec3d( 1, 1, 1 ) );
|
|
|
|
Vec3d inViewDir( 0, 0, 1 );
|
|
Vec3d inUp( 0, 0, 1 );
|
|
double coverageFactor = 0.9;
|
|
|
|
c.fitView( bb, inViewDir, inUp, coverageFactor );
|
|
|
|
Vec3d eye;
|
|
Vec3d vrp;
|
|
Vec3d up;
|
|
c.toLookAt( &eye, &vrp, &up );
|
|
|
|
EXPECT_FALSE( eye.isUndefined() );
|
|
EXPECT_FALSE( c.direction().isUndefined() );
|
|
EXPECT_FALSE( c.up().isUndefined() );
|
|
EXPECT_FALSE( c.right().isUndefined() );
|
|
|
|
// direction, up and right should form a valid, mutually orthogonal basis (within floating point
|
|
// tolerance). If the up vector correction is not applied consistently, the derived up/right
|
|
// vectors from the (singular) view matrix will be degenerate (zero length or not orthogonal).
|
|
EXPECT_NEAR( c.direction().length(), 1.0, 1e-6 );
|
|
EXPECT_NEAR( c.up().length(), 1.0, 1e-6 );
|
|
EXPECT_NEAR( c.right().length(), 1.0, 1e-6 );
|
|
EXPECT_NEAR( c.direction() * c.up(), 0.0, 1e-6 );
|
|
EXPECT_NEAR( c.direction() * c.right(), 0.0, 1e-6 );
|
|
EXPECT_NEAR( c.up() * c.right(), 0.0, 1e-6 );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// A zero view direction (eye == view reference point, as in caf::Viewer::zoomAll()) gave a zero up
|
|
/// vector and a zero-normal plane, which asserted in Plane::distanceToOrigin().
|
|
//--------------------------------------------------------------------------------------------------
|
|
TEST( CvfCameraCrashTriageTest, FitViewEyePositionWithZeroDirDoesNotCrash )
|
|
{
|
|
Camera c;
|
|
|
|
BoundingBox bb;
|
|
bb.add( Vec3d( 0, 0, 0 ) );
|
|
bb.add( Vec3d( 1, 1, 1 ) );
|
|
|
|
for ( const auto& dir : { Vec3d::ZERO, Vec3d::UNDEFINED } )
|
|
{
|
|
Vec3d eye = Camera::computeFitViewEyePosition( bb, dir, Vec3d( 0, 0, 1 ), 0.9, c.fieldOfViewYDeg(), 1.0 );
|
|
|
|
EXPECT_FALSE( eye.isUndefined() );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// fitView() must derive the up vector from the same valid direction as the eye position
|
|
//--------------------------------------------------------------------------------------------------
|
|
TEST( CvfCameraCrashTriageTest, FitViewWithZeroOrUndefinedDirProducesValidViewMatrix )
|
|
{
|
|
BoundingBox bb;
|
|
bb.add( Vec3d( 0, 0, 0 ) );
|
|
bb.add( Vec3d( 1, 1, 1 ) );
|
|
|
|
for ( const auto& dir : { Vec3d::ZERO, Vec3d::UNDEFINED } )
|
|
{
|
|
Camera c;
|
|
c.setViewport( 0, 0, 100, 100 );
|
|
c.fitView( bb, dir, Vec3d( 0, 0, 1 ), 0.9 );
|
|
|
|
EXPECT_NEAR( c.direction().length(), 1.0, 1e-6 );
|
|
EXPECT_NEAR( c.up().length(), 1.0, 1e-6 );
|
|
EXPECT_NEAR( c.right().length(), 1.0, 1e-6 );
|
|
}
|
|
}
|