ResInsight/ApplicationLibCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp
2021-01-11 15:27:45 +01:00

820 lines
29 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015- Statoil ASA
// Copyright (C) 2015- Ceetron Solutions AS
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight 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 GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RivGridBoxGenerator.h"
#include "RiaColorTools.h"
#include "RiaFontCache.h"
#include "RiaGuiApplication.h"
#include "RiaPreferences.h"
#include "RivPartPriority.h"
#include "RivPatchGenerator.h"
#include "cafEffectGenerator.h"
#include "cvfCamera.h"
#include "cvfDrawableText.h"
#include "cvfFixedAtlasFont.h"
#include "cvfGeometryBuilderDrawableGeo.h"
#include "cvfGeometryBuilderFaceList.h"
#include "cvfMeshEdgeExtractor.h"
#include "cvfPrimitiveSetIndexedUInt.h"
#include "cvfRenderStateDepth.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivGridBoxGenerator::RivGridBoxGenerator()
: m_gridColor( cvf::Color3f::LIGHT_GRAY )
, m_gridLegendColor( cvf::Color3f::BLACK )
, m_needsRegeneration( true )
{
m_gridBoxModel = new cvf::ModelBasicList();
m_gridBoxModel->setName( "GridBoxModel" );
m_scaleZ = 1.0;
m_displayModelOffset = cvf::Vec3d::ZERO;
m_fontPointSize = caf::FontTools::absolutePointSize( RiaPreferences::current()->defaultSceneFontSize() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivGridBoxGenerator::setScaleZ( double scaleZ )
{
if ( m_scaleZ != scaleZ ) m_needsRegeneration = true;
m_scaleZ = scaleZ;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivGridBoxGenerator::setDisplayModelOffset( cvf::Vec3d offset )
{
if ( m_displayModelOffset != offset ) m_needsRegeneration = true;
m_displayModelOffset = offset;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivGridBoxGenerator::setGridBoxDomainCoordBoundingBox( const cvf::BoundingBox& incomingBB )
{
double expandFactor = 0.05;
// Use ScalarMapperDiscreteLinear to find human readable tick mark positions for grid box sub division coordinate
// values Expand the range for ScalarMapperDiscreteLinear until the geometry bounding box has a generated tick mark
// coords both below minimum and above maximum bounding box coords
cvf::BoundingBox bb;
if ( incomingBB.isValid() )
{
bb = incomingBB;
}
else
{
bb.add( cvf::Vec3d::ZERO );
}
cvf::Vec3d min = bb.min();
cvf::Vec3d max = bb.max();
size_t levelCount = 6;
{
bool majorTickValuesCoversDomainValues = false;
while ( !majorTickValuesCoversDomainValues )
{
m_domainCoordsXValues.clear();
cvf::ScalarMapperDiscreteLinear linDiscreteScalarMapper;
linDiscreteScalarMapper.setRange( min.x(), max.x() );
linDiscreteScalarMapper.setLevelCount( levelCount, true );
linDiscreteScalarMapper.majorTickValues( &m_domainCoordsXValues );
majorTickValuesCoversDomainValues = true;
if ( m_domainCoordsXValues[1] > bb.min().x() )
{
min.x() = min.x() - bb.extent().x() * expandFactor;
max.x() = max.x() + bb.extent().x() * expandFactor;
majorTickValuesCoversDomainValues = false;
}
if ( m_domainCoordsXValues[m_domainCoordsXValues.size() - 1] < bb.max().x() )
{
min.x() = min.x() - bb.extent().x() * expandFactor;
max.x() = max.x() + bb.extent().x() * expandFactor;
majorTickValuesCoversDomainValues = false;
}
}
}
{
bool majorTickValuesCoversDomainValues = false;
while ( !majorTickValuesCoversDomainValues )
{
m_domainCoordsYValues.clear();
cvf::ScalarMapperDiscreteLinear linDiscreteScalarMapper;
linDiscreteScalarMapper.setRange( min.y(), max.y() );
linDiscreteScalarMapper.setLevelCount( levelCount, true );
linDiscreteScalarMapper.majorTickValues( &m_domainCoordsYValues );
majorTickValuesCoversDomainValues = true;
if ( m_domainCoordsYValues[1] > bb.min().y() )
{
min.y() = min.y() - bb.extent().y() * expandFactor;
max.y() = max.y() + bb.extent().y() * expandFactor;
majorTickValuesCoversDomainValues = false;
}
if ( m_domainCoordsYValues[m_domainCoordsYValues.size() - 1] < bb.max().y() )
{
min.y() = min.y() - bb.extent().y() * expandFactor;
max.y() = max.y() + bb.extent().y() * expandFactor;
majorTickValuesCoversDomainValues = false;
}
}
}
{
bool majorTickValuesCoversDomainValues = false;
while ( !majorTickValuesCoversDomainValues )
{
m_domainCoordsZValues.clear();
cvf::ScalarMapperDiscreteLinear linDiscreteScalarMapper;
linDiscreteScalarMapper.setRange( min.z(), max.z() );
linDiscreteScalarMapper.setLevelCount( levelCount, true );
linDiscreteScalarMapper.majorTickValues( &m_domainCoordsZValues );
majorTickValuesCoversDomainValues = true;
if ( m_domainCoordsZValues[1] > bb.min().z() )
{
min.z() = min.z() - bb.extent().z() * expandFactor;
max.z() = max.z() + bb.extent().z() * expandFactor;
majorTickValuesCoversDomainValues = false;
}
if ( m_domainCoordsZValues[m_domainCoordsZValues.size() - 1] < bb.max().z() )
{
min.z() = min.z() - bb.extent().z() * expandFactor;
max.z() = max.z() + bb.extent().z() * expandFactor;
majorTickValuesCoversDomainValues = false;
}
}
}
cvf::BoundingBox expandedBB;
expandedBB.add( min );
expandedBB.add( max );
if ( !m_domainCoordsBoundingBox.isValid() || m_domainCoordsBoundingBox.min() != expandedBB.min() ||
m_domainCoordsBoundingBox.max() != expandedBB.max() )
{
m_needsRegeneration = true;
}
m_domainCoordsBoundingBox = expandedBB;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivGridBoxGenerator::createGridBoxParts()
{
if ( m_needsRegeneration )
{
computeDisplayCoords();
createGridBoxFaceParts();
createGridBoxLegendParts();
m_needsRegeneration = false;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivGridBoxGenerator::setGridLabelFontSize( int fontSize )
{
if ( m_fontPointSize != fontSize )
{
m_fontPointSize = fontSize;
m_needsRegeneration = true;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivGridBoxGenerator::updateFromCamera( const cvf::Camera* camera )
{
m_gridBoxModel->removeAllParts();
if ( m_gridBoxFaceParts.empty() ) return;
std::vector<bool> faceVisibility( 6, false );
for ( size_t i = POS_X; i <= NEG_Z; i++ )
{
bool isFaceVisible = false;
cvf::Vec3f sideNorm = sideNormalOutwards( (FaceType)i );
if ( camera->projection() == cvf::Camera::PERSPECTIVE )
{
cvf::Vec3d camToSide = camera->position() - pointOnSide( (FaceType)i );
camToSide.normalize();
isFaceVisible = sideNorm.dot( cvf::Vec3f( camToSide ) ) < 0.0;
}
else
{
cvf::Vec3d camToSide = camera->direction();
isFaceVisible = sideNorm.dot( cvf::Vec3f( camToSide ) ) > 0.0;
}
if ( isFaceVisible )
{
m_gridBoxModel->addPart( m_gridBoxFaceParts[i].p() );
faceVisibility[i] = true;
}
}
if ( !m_gridBoxLegendParts.empty() )
{
std::vector<bool> edgeVisibility( 12, false );
computeEdgeVisibility( faceVisibility, edgeVisibility );
CVF_ASSERT( m_gridBoxLegendParts.size() == ( NEG_X_NEG_Y + 1 ) * 2 );
for ( size_t i = POS_Z_POS_X; i <= NEG_X_NEG_Y; i++ )
{
if ( edgeVisibility[i] )
{
// We have two parts for each edge - line and text
m_gridBoxModel->addPart( m_gridBoxLegendParts[2 * i].p() );
m_gridBoxModel->addPart( m_gridBoxLegendParts[2 * i + 1].p() );
}
}
}
m_gridBoxModel->updateBoundingBoxesRecursive();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivGridBoxGenerator::computeEdgeVisibility( const std::vector<bool>& faceVisibility, std::vector<bool>& edgeVisibility )
{
CVF_ASSERT( faceVisibility.size() == NEG_Z + 1 );
CVF_ASSERT( edgeVisibility.size() == NEG_X_NEG_Y + 1 );
// POS Z
if ( faceVisibility[POS_Z] ^ faceVisibility[POS_X] )
{
edgeVisibility[POS_Z_POS_X] = true;
}
if ( faceVisibility[POS_Z] ^ faceVisibility[NEG_X] )
{
edgeVisibility[POS_Z_NEG_X] = true;
}
if ( faceVisibility[POS_Z] ^ faceVisibility[POS_Y] )
{
edgeVisibility[POS_Z_POS_Y] = true;
}
if ( faceVisibility[POS_Z] ^ faceVisibility[NEG_Y] )
{
edgeVisibility[POS_Z_NEG_Y] = true;
}
// NEG Z
if ( faceVisibility[NEG_Z] ^ faceVisibility[POS_X] )
{
edgeVisibility[NEG_Z_POS_X] = true;
}
if ( faceVisibility[NEG_Z] ^ faceVisibility[NEG_X] )
{
edgeVisibility[NEG_Z_NEG_X] = true;
}
if ( faceVisibility[NEG_Z] ^ faceVisibility[POS_Y] )
{
edgeVisibility[NEG_Z_POS_Y] = true;
}
if ( faceVisibility[NEG_Z] ^ faceVisibility[NEG_Y] )
{
edgeVisibility[NEG_Z_NEG_Y] = true;
}
// POS X
if ( faceVisibility[POS_X] ^ faceVisibility[POS_Y] )
{
edgeVisibility[POS_X_POS_Y] = true;
}
if ( faceVisibility[POS_X] ^ faceVisibility[NEG_Y] )
{
edgeVisibility[POS_X_NEG_Y] = true;
}
// NEG X
if ( faceVisibility[NEG_X] ^ faceVisibility[POS_Y] )
{
edgeVisibility[NEG_X_POS_Y] = true;
}
if ( faceVisibility[NEG_X] ^ faceVisibility[NEG_Y] )
{
edgeVisibility[NEG_X_NEG_Y] = true;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Model* RivGridBoxGenerator::model()
{
return m_gridBoxModel.p();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivGridBoxGenerator::createGridBoxFaceParts()
{
m_gridBoxFaceParts.clear();
CVF_ASSERT( m_displayCoordsBoundingBox.isValid() );
CVF_ASSERT( m_displayCoordsXValues.size() > 0 );
CVF_ASSERT( m_displayCoordsYValues.size() > 0 );
CVF_ASSERT( m_displayCoordsZValues.size() > 0 );
cvf::Vec3d min = m_displayCoordsBoundingBox.min();
cvf::Vec3d max = m_displayCoordsBoundingBox.max();
for ( int face = POS_X; face <= NEG_Z; face++ )
{
// TODO: move out of loop
RivPatchGenerator patchGen;
if ( face == POS_X )
{
patchGen.setOrigin( cvf::Vec3d( max.x(), 0.0, 0.0 ) );
patchGen.setAxes( cvf::Vec3d::Y_AXIS, cvf::Vec3d::Z_AXIS );
patchGen.setSubdivisions( m_displayCoordsYValues, m_displayCoordsZValues );
}
else if ( face == NEG_X )
{
patchGen.setOrigin( cvf::Vec3d( min.x(), 0.0, 0.0 ) );
patchGen.setAxes( cvf::Vec3d::Y_AXIS, cvf::Vec3d::Z_AXIS );
patchGen.setSubdivisions( m_displayCoordsYValues, m_displayCoordsZValues );
}
else if ( face == POS_Y )
{
patchGen.setOrigin( cvf::Vec3d( 0.0, max.y(), 0.0 ) );
patchGen.setAxes( cvf::Vec3d::X_AXIS, cvf::Vec3d::Z_AXIS );
patchGen.setSubdivisions( m_displayCoordsXValues, m_displayCoordsZValues );
}
else if ( face == NEG_Y )
{
patchGen.setOrigin( cvf::Vec3d( 0.0, min.y(), 0.0 ) );
patchGen.setAxes( cvf::Vec3d::X_AXIS, cvf::Vec3d::Z_AXIS );
patchGen.setSubdivisions( m_displayCoordsXValues, m_displayCoordsZValues );
}
else if ( face == POS_Z )
{
patchGen.setOrigin( cvf::Vec3d( 0.0, 0.0, max.z() ) );
patchGen.setAxes( cvf::Vec3d::X_AXIS, cvf::Vec3d::Y_AXIS );
patchGen.setSubdivisions( m_displayCoordsXValues, m_displayCoordsYValues );
}
else if ( face == NEG_Z )
{
patchGen.setOrigin( cvf::Vec3d( 0.0, 0.0, min.z() ) );
patchGen.setAxes( cvf::Vec3d::X_AXIS, cvf::Vec3d::Y_AXIS );
patchGen.setSubdivisions( m_displayCoordsXValues, m_displayCoordsYValues );
}
else
{
CVF_ASSERT( false );
}
cvf::GeometryBuilderFaceList builder;
patchGen.generate( &builder );
cvf::ref<cvf::Vec3fArray> vertexArray = builder.vertices();
cvf::ref<cvf::UIntArray> faceList = builder.faceList();
{
// Box mesh
cvf::MeshEdgeExtractor ee;
ee.addFaceList( *faceList );
cvf::ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo;
geo->setVertexArray( vertexArray.p() );
geo->addPrimitiveSet( new cvf::PrimitiveSetIndexedUInt( cvf::PT_LINES, ee.lineIndices().p() ) );
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName( "Grid box " );
part->setDrawable( geo.p() );
part->updateBoundingBox();
cvf::ref<cvf::Effect> eff;
caf::MeshEffectGenerator effGen( m_gridColor );
eff = effGen.generateCachedEffect();
part->setEffect( eff.p() );
m_gridBoxFaceParts.push_back( part.p() );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivGridBoxGenerator::createGridBoxLegendParts()
{
m_gridBoxLegendParts.clear();
CVF_ASSERT( m_displayCoordsBoundingBox.isValid() );
CVF_ASSERT( m_displayCoordsXValues.size() > 0 );
CVF_ASSERT( m_displayCoordsYValues.size() > 0 );
CVF_ASSERT( m_displayCoordsZValues.size() > 0 );
for ( int edge = POS_Z_POS_X; edge <= NEG_X_NEG_Y; edge++ )
{
cvf::Collection<cvf::Part> parts;
createLegend( (EdgeType)edge, &parts );
for ( size_t i = 0; i < parts.size(); i++ )
{
m_gridBoxLegendParts.push_back( parts.at( i ) );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Vec3d RivGridBoxGenerator::displayModelCoordFromDomainCoord( const cvf::Vec3d& domainCoord ) const
{
cvf::Vec3d coord = domainCoord - m_displayModelOffset;
coord.z() *= m_scaleZ;
return coord;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivGridBoxGenerator::createLegend( EdgeType edge, cvf::Collection<cvf::Part>* parts )
{
cvf::Vec3d posMin = cvf::Vec3d::ZERO;
cvf::Vec3d posMax = cvf::Vec3d::ZERO;
cvf::Vec3d min = m_displayCoordsBoundingBox.min();
cvf::Vec3d max = m_displayCoordsBoundingBox.max();
if ( min == max )
{
return;
}
AxisType axis = X_AXIS;
cvf::Vec3f tickMarkDir = cvf::Vec3f::X_AXIS;
switch ( edge )
{
case RivGridBoxGenerator::POS_Z_POS_X:
axis = Y_AXIS;
posMin.set( max.x(), min.y(), max.z() );
posMax.set( max.x(), max.y(), max.z() );
tickMarkDir = cornerDirection( POS_Z, POS_X );
break;
case RivGridBoxGenerator::POS_Z_NEG_X:
axis = Y_AXIS;
posMin.set( min.x(), min.y(), max.z() );
posMax.set( min.x(), max.y(), max.z() );
tickMarkDir = cornerDirection( POS_Z, NEG_X );
break;
case RivGridBoxGenerator::POS_Z_POS_Y:
axis = X_AXIS;
posMin.set( min.x(), max.y(), max.z() );
posMax.set( max.x(), max.y(), max.z() );
tickMarkDir = cornerDirection( POS_Z, POS_Y );
break;
case RivGridBoxGenerator::POS_Z_NEG_Y:
axis = X_AXIS;
posMin.set( min.x(), min.y(), max.z() );
posMax.set( max.x(), min.y(), max.z() );
tickMarkDir = cornerDirection( POS_Z, NEG_Y );
break;
case RivGridBoxGenerator::NEG_Z_POS_X:
axis = Y_AXIS;
posMin.set( max.x(), min.y(), min.z() );
posMax.set( max.x(), max.y(), min.z() );
tickMarkDir = cornerDirection( NEG_Z, POS_X );
break;
case RivGridBoxGenerator::NEG_Z_NEG_X:
axis = Y_AXIS;
posMin.set( min.x(), min.y(), min.z() );
posMax.set( min.x(), max.y(), min.z() );
tickMarkDir = cornerDirection( NEG_Z, NEG_X );
break;
case RivGridBoxGenerator::NEG_Z_POS_Y:
axis = X_AXIS;
posMin.set( min.x(), max.y(), min.z() );
posMax.set( max.x(), max.y(), min.z() );
tickMarkDir = cornerDirection( NEG_Z, POS_Y );
break;
case RivGridBoxGenerator::NEG_Z_NEG_Y:
axis = X_AXIS;
posMin.set( min.x(), min.y(), min.z() );
posMax.set( max.x(), min.y(), min.z() );
tickMarkDir = cornerDirection( NEG_Z, NEG_Y );
break;
case RivGridBoxGenerator::POS_X_POS_Y:
axis = Z_AXIS;
posMin.set( max.x(), max.y(), min.z() );
posMax.set( max.x(), max.y(), max.z() );
tickMarkDir = cornerDirection( POS_X, POS_Y );
break;
case RivGridBoxGenerator::POS_X_NEG_Y:
axis = Z_AXIS;
posMin.set( max.x(), min.y(), min.z() );
posMax.set( max.x(), min.y(), max.z() );
tickMarkDir = cornerDirection( POS_X, NEG_Y );
break;
case RivGridBoxGenerator::NEG_X_POS_Y:
axis = Z_AXIS;
posMin.set( min.x(), max.y(), min.z() );
posMax.set( min.x(), max.y(), max.z() );
tickMarkDir = cornerDirection( NEG_X, POS_Y );
break;
case RivGridBoxGenerator::NEG_X_NEG_Y:
axis = Z_AXIS;
posMin.set( min.x(), min.y(), min.z() );
posMax.set( min.x(), min.y(), max.z() );
tickMarkDir = cornerDirection( NEG_X, NEG_Y );
break;
default:
CVF_TIGHT_ASSERT( false );
break;
}
std::vector<double>* displayCoordsTickValues = nullptr;
std::vector<double>* domainCoordsTickValues = nullptr;
if ( axis == X_AXIS )
{
displayCoordsTickValues = &m_displayCoordsXValues;
domainCoordsTickValues = &m_domainCoordsXValues;
}
else if ( axis == Y_AXIS )
{
displayCoordsTickValues = &m_displayCoordsYValues;
domainCoordsTickValues = &m_domainCoordsYValues;
}
else if ( axis == Z_AXIS )
{
displayCoordsTickValues = &m_displayCoordsZValues;
domainCoordsTickValues = &m_domainCoordsZValues;
}
CVF_ASSERT( displayCoordsTickValues );
CVF_ASSERT( domainCoordsTickValues );
size_t numVerts = ( displayCoordsTickValues->size() ) * 2;
size_t numLines = ( displayCoordsTickValues->size() ) + 1;
cvf::ref<cvf::Vec3fArray> vertices = new cvf::Vec3fArray;
vertices->reserve( numVerts );
cvf::ref<cvf::UIntArray> indices = new cvf::UIntArray;
indices->reserve( 2 * numLines );
float tickLength = static_cast<float>( m_displayCoordsBoundingBox.extent().length() / 100.0 );
cvf::Vec3f point = cvf::Vec3f( posMin );
cvf::Vec3f tickPoint;
// Tick marks
for ( size_t i = 0; i < displayCoordsTickValues->size(); ++i )
{
point[axis] = static_cast<float>( displayCoordsTickValues->at( i ) );
vertices->add( point );
tickPoint = point + tickLength * tickMarkDir;
;
vertices->add( tickPoint );
if ( i == 0 || i == displayCoordsTickValues->size() - 1 )
{
// Do not show tick mark at ends of legend
// Add to list of indices to keep surrounding code unchanged
indices->add( 2 * static_cast<cvf::uint>( i ) );
indices->add( 2 * static_cast<cvf::uint>( i ) );
}
else
{
indices->add( 2 * static_cast<cvf::uint>( i ) );
indices->add( 2 * static_cast<cvf::uint>( i ) + 1 );
}
}
// Backbone of legend
indices->add( 0 );
indices->add( static_cast<cvf::uint>( numVerts ) - 2 );
{
// Legend lines
cvf::ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo;
geo->setVertexArray( vertices.p() );
cvf::ref<cvf::PrimitiveSetIndexedUInt> primSet = new cvf::PrimitiveSetIndexedUInt( cvf::PT_LINES );
primSet->setIndices( indices.p() );
geo->addPrimitiveSet( primSet.p() );
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName( "Legend lines" );
part->setDrawable( geo.p() );
part->updateBoundingBox();
cvf::ref<cvf::Effect> eff;
caf::MeshEffectGenerator effGen( m_gridLegendColor );
eff = effGen.generateUnCachedEffect();
part->setPriority( RivPartPriority::PartType::Text );
part->setEffect( eff.p() );
parts->push_back( part.p() );
}
{
// Text labels
cvf::ref<cvf::DrawableText> geo = new cvf::DrawableText;
cvf::ref<cvf::Font> font = RiaGuiApplication::instance()->defaultSceneFont();
if ( caf::FontTools::absolutePointSize( RiaPreferences::current()->defaultSceneFontSize() ) != m_fontPointSize )
{
font = RiaFontCache::getFont( m_fontPointSize );
}
geo->setFont( font.p() );
geo->setTextColor( m_gridLegendColor );
geo->setCheckPosVisible( false );
geo->setDrawBackground( false );
geo->setDrawBorder( false );
// Do not draw legend labels at first/last tick mark
for ( size_t idx = 1; idx < domainCoordsTickValues->size() - 1; idx++ )
{
double legendValue = domainCoordsTickValues->at( idx );
if ( axis == Z_AXIS )
{
legendValue = -domainCoordsTickValues->at( idx );
}
cvf::int64 integerValue = static_cast<cvf::int64>( legendValue );
cvf::String numberText = cvf::String( "%1" ).arg( integerValue );
geo->addText( numberText, vertices->get( idx * 2 + 1 ) + ( 0.5f * tickLength ) * tickMarkDir );
}
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName( "Legend text" );
part->setDrawable( geo.p() );
part->updateBoundingBox();
caf::TextEffectGenerator textGen;
cvf::ref<cvf::Effect> eff = textGen.generateCachedEffect();
part->setEffect( eff.p() );
parts->push_back( part.p() );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Vec3f RivGridBoxGenerator::sideNormalOutwards( FaceType face )
{
switch ( face )
{
case RivGridBoxGenerator::POS_X:
return cvf::Vec3f::X_AXIS;
case RivGridBoxGenerator::NEG_X:
return -cvf::Vec3f::X_AXIS;
case RivGridBoxGenerator::POS_Y:
return cvf::Vec3f::Y_AXIS;
case RivGridBoxGenerator::NEG_Y:
return -cvf::Vec3f::Y_AXIS;
case RivGridBoxGenerator::POS_Z:
return cvf::Vec3f::Z_AXIS;
case RivGridBoxGenerator::NEG_Z:
return -cvf::Vec3f::Z_AXIS;
default:
break;
}
return cvf::Vec3f::ZERO;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Vec3d RivGridBoxGenerator::pointOnSide( FaceType face )
{
switch ( face )
{
case RivGridBoxGenerator::POS_X:
case RivGridBoxGenerator::POS_Y:
case RivGridBoxGenerator::POS_Z:
return cvf::Vec3d( m_displayCoordsBoundingBox.max() );
case RivGridBoxGenerator::NEG_X:
case RivGridBoxGenerator::NEG_Y:
case RivGridBoxGenerator::NEG_Z:
return cvf::Vec3d( m_displayCoordsBoundingBox.min() );
default:
break;
}
return cvf::Vec3d::ZERO;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Vec3f RivGridBoxGenerator::cornerDirection( FaceType face1, FaceType face2 )
{
cvf::Vec3f dir = sideNormalOutwards( face1 ) + sideNormalOutwards( face2 );
dir.normalize();
return dir;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivGridBoxGenerator::updateFromBackgroundColor( const cvf::Color3f& backgroundColor )
{
m_gridColor = RiaColorTools::computeOffsetColor( backgroundColor, 0.3f );
cvf::Color3f contrastColor = RiaColorTools::contrastColor( backgroundColor );
if ( contrastColor != m_gridLegendColor ) m_needsRegeneration = true;
m_gridLegendColor = contrastColor;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivGridBoxGenerator::computeDisplayCoords()
{
m_displayCoordsBoundingBox.reset();
m_displayCoordsXValues.clear();
m_displayCoordsYValues.clear();
m_displayCoordsZValues.clear();
m_displayCoordsBoundingBox.add( displayModelCoordFromDomainCoord( m_domainCoordsBoundingBox.min() ) );
m_displayCoordsBoundingBox.add( displayModelCoordFromDomainCoord( m_domainCoordsBoundingBox.max() ) );
for ( size_t i = 0; i < m_domainCoordsXValues.size(); i++ )
{
m_displayCoordsXValues.push_back( m_domainCoordsXValues[i] - m_displayModelOffset.x() );
}
for ( size_t i = 0; i < m_domainCoordsYValues.size(); i++ )
{
m_displayCoordsYValues.push_back( m_domainCoordsYValues[i] - m_displayModelOffset.y() );
}
for ( size_t i = 0; i < m_domainCoordsZValues.size(); i++ )
{
m_displayCoordsZValues.push_back( m_scaleZ * ( m_domainCoordsZValues[i] - m_displayModelOffset.z() ) );
}
}