Skip to content

Commit

Permalink
Refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
magnesj committed Sep 11, 2023
1 parent 36e7589 commit e06cb1c
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ RivAnnotationSourceInfo::RivAnnotationSourceInfo( const std::string m_text, cons
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivAnnotationTools::LabelPositionStrategy RivAnnotationSourceInfo::positionStrategyHint() const
RivAnnotationTools::LabelPositionStrategy RivAnnotationSourceInfo::labelPositionStrategyHint() const
{
return m_labelPositionHint;
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivAnnotationSourceInfo::setPositionStrategyHint( RivAnnotationTools::LabelPositionStrategy strategy )
void RivAnnotationSourceInfo::setLabelPositionStrategyHint( RivAnnotationTools::LabelPositionStrategy strategy )
{
m_labelPositionHint = strategy;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ class RivAnnotationSourceInfo : public cvf::Object
public:
RivAnnotationSourceInfo( const std::string m_text, const std::vector<cvf::Vec3d>& displayCoords );

RivAnnotationTools::LabelPositionStrategy positionStrategyHint() const;
void setPositionStrategyHint( RivAnnotationTools::LabelPositionStrategy strategy );
RivAnnotationTools::LabelPositionStrategy labelPositionStrategyHint() const;
void setLabelPositionStrategyHint( RivAnnotationTools::LabelPositionStrategy strategy );

std::string text() const;
std::vector<cvf::Vec3d> anchorPointsDisplayCoords() const;
Expand Down
252 changes: 133 additions & 119 deletions ApplicationLibCode/ModelVisualization/RivAnnotationTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
#include "RivPartPriority.h"
#include "RivPolylineGenerator.h"

#include "cafAppEnum.h"
#include "cafEffectGenerator.h"

#include "cvfCamera.h"
#include "cvfDrawableGeo.h"
#include "cvfDrawableText.h"
Expand All @@ -35,16 +37,45 @@
#include "cvfViewport.h"

#include <algorithm>
#include <optional>

namespace caf
{

template <>
void caf::AppEnum<RivAnnotationTools::LabelPositionStrategy>::setUp()
{
addItem( RivAnnotationTools::LabelPositionStrategy::LEFT, "LEFT", "Left" );
addItem( RivAnnotationTools::LabelPositionStrategy::RIGHT, "RIGHT", "Right" );
addItem( RivAnnotationTools::LabelPositionStrategy::LEFT_AND_RIGHT, "LEFT_AND_RIGHT", "Left and Right" );
addItem( RivAnnotationTools::LabelPositionStrategy::COUNT_HINT, "COUNT_HINT", "Count Hint" );
addItem( RivAnnotationTools::LabelPositionStrategy::ALL, "All", "All" );
addItem( RivAnnotationTools::LabelPositionStrategy::NONE, "None", "Disabled" );
// RivAnnotationTools::LabelPositionStrategy::UNKNOWN is not included, as this is enum is not supposed to be displayed in GUI
setDefault( RivAnnotationTools::LabelPositionStrategy::RIGHT );
}

} // End namespace caf

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivAnnotationTools::RivAnnotationTools( LabelPositionStrategy positionStrategy )
: m_strategy( positionStrategy )
RivAnnotationTools::RivAnnotationTools()
: m_strategy( RivAnnotationTools::LabelPositionStrategy::UNDEFINED )
, m_labelCountHint( 0 )
{
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivAnnotationTools::setLabelPositionStrategy( LabelPositionStrategy positionStrategy )
{
// By default, each annotation object has a label position strategy. Use this method to override the default.

m_strategy = positionStrategy;
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -86,166 +117,149 @@ struct LabelInfo
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivAnnotationTools::addAnnotationLabels( const cvf::Collection<cvf::Part>& partCollection,
const cvf::Camera* camera,
cvf::ModelBasicList* model )
auto computeScalingFactorFromZoom = []( const cvf::Camera* camera ) -> double
{
if ( !camera || !model ) return;
double scalingFactor = 1.0;

auto computeScalingFactorFromZoom = []( const cvf::Camera* camera ) -> double
if ( camera )
{
double scalingFactor = 1.0;

if ( camera )
auto viewPort = camera->viewport();
cvf::Vec3d vpCorner1( 0, viewPort->height(), 0 );
cvf::Vec3d vpCorner2( viewPort->width(), 0, 0 );
bool unprojOk = true;
cvf::Vec3d corner1Display, corner2Display, e1;
unprojOk &= camera->unproject( vpCorner1, &corner1Display );
unprojOk &= camera->unproject( vpCorner2, &corner2Display );

if ( unprojOk )
{
auto viewPort = camera->viewport();
cvf::Vec3d vpCorner1( 0, viewPort->height(), 0 );
cvf::Vec3d vpCorner2( viewPort->width(), 0, 0 );
bool unprojOk = true;
cvf::Vec3d corner1Display, corner2Display, e1;
unprojOk &= camera->unproject( vpCorner1, &corner1Display );
unprojOk &= camera->unproject( vpCorner2, &corner2Display );

if ( unprojOk )
{
scalingFactor = 10 * ( corner1Display - corner2Display ).length();
}
scalingFactor = 10 * ( corner1Display - corner2Display ).length();
}
}

return scalingFactor;
};

const double anchorLineScalingFactor = computeScalingFactorFromZoom( camera );
return scalingFactor;
};

std::vector<LabelInfo> labelInfo;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
auto createLabel = []( const cvf::Camera* camera,
const RivAnnotationSourceInfo* annotationObject,
const double viewportWidth,
const double normalizedXPosition,
const double anchorLineScalingFactor ) -> std::optional<LabelInfo>
{
if ( !camera || !annotationObject ) return std::nullopt;

for ( auto p : partCollection )
cvf::Vec3d anchorPosition;
double smallestDistance = std::numeric_limits<double>::max();
for ( const auto& displayCoord : annotationObject->anchorPointsDisplayCoords() )
{
auto annotationObject = dynamic_cast<RivAnnotationSourceInfo*>( p->sourceInfo() );
if ( annotationObject )
{
if ( m_strategy == LabelPositionStrategy::RIGHT || m_strategy == LabelPositionStrategy::LEFT_AND_RIGHT )
{
cvf::Vec3d lineAnchorPosition;
const auto width = camera->viewport()->width();
double smallestDistance = 100000;
cvf::Vec3d screenCoord;
camera->project( displayCoord, &screenCoord );

for ( const auto& v : annotationObject->anchorPointsDisplayCoords() )
{
cvf::Vec3d screenCoord;
camera->project( v, &screenCoord );
double horizontalDistance = std::fabs( normalizedXPosition * viewportWidth - screenCoord.x() );

double candidate = 0.9 * width - screenCoord.x();
candidate *= candidate;
if ( horizontalDistance < smallestDistance )
{
smallestDistance = horizontalDistance;
anchorPosition = displayCoord;
}
}

if ( candidate < smallestDistance )
{
smallestDistance = candidate;
lineAnchorPosition = v;
}
}
if ( smallestDistance == std::numeric_limits<double>::max() ) return std::nullopt;

cvf::Vec3d directionPointToCam = ( camera->position() - lineAnchorPosition ).getNormalized();
const cvf::Vec3d directionPointToCam = ( camera->position() - anchorPosition ).getNormalized();

cvf::Vec3d labelPosition = lineAnchorPosition + directionPointToCam * anchorLineScalingFactor;
cvf::Vec3d labelScreenCoord;
camera->project( labelPosition, &labelScreenCoord );
labelScreenCoord.x() = 0.9 * camera->viewport()->width();
camera->unproject( labelScreenCoord, &labelPosition );
cvf::Vec3d labelPosition = anchorPosition + directionPointToCam * anchorLineScalingFactor;

auto labelText = annotationObject->text();
const double maxScreenSpaceAdjustment = viewportWidth * 0.05;
if ( smallestDistance < maxScreenSpaceAdjustment )
{
// Establish a fixed horizontal anchor point for the label in screen coordinates. Achieved through conversion to screen coordinates,
// adjusting the x-coordinate, and then reverting to display coordinates.
cvf::Vec3d screenCoord;
camera->project( labelPosition, &screenCoord );

labelInfo.push_back( { labelText, lineAnchorPosition, labelPosition } );
}
screenCoord.x() = normalizedXPosition * viewportWidth;
camera->unproject( screenCoord, &labelPosition );
}

if ( m_strategy == LabelPositionStrategy::LEFT || m_strategy == LabelPositionStrategy::LEFT_AND_RIGHT )
{
cvf::Vec3d lineAnchorPosition;
const auto width = camera->viewport()->width();
double smallestDistance = 100000;
return LabelInfo( annotationObject->text(), anchorPosition, labelPosition );
};

for ( const auto& v : annotationObject->anchorPointsDisplayCoords() )
{
cvf::Vec3d screenCoord;
camera->project( v, &screenCoord );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivAnnotationTools::addAnnotationLabels( const cvf::Collection<cvf::Part>& partCollection,
const cvf::Camera* camera,
cvf::ModelBasicList* model )
{
if ( !camera || !model ) return;

double candidate = 0.1 * width - screenCoord.x();
candidate *= candidate;
const double anchorLineScalingFactor = computeScalingFactorFromZoom( camera );

if ( candidate < smallestDistance )
{
smallestDistance = candidate;
lineAnchorPosition = v;
}
}
std::vector<LabelInfo> labelInfo;

cvf::Vec3d directionPointToCam = ( camera->position() - lineAnchorPosition ).getNormalized();
for ( auto p : partCollection )
{
auto annotationObject = dynamic_cast<RivAnnotationSourceInfo*>( p->sourceInfo() );
if ( annotationObject )
{
auto strategy = annotationObject->labelPositionStrategyHint();
if ( m_strategy != LabelPositionStrategy::UNDEFINED )
{
strategy = m_strategy;
}

cvf::Vec3d labelPosition = lineAnchorPosition + directionPointToCam * anchorLineScalingFactor;
cvf::Vec3d labelScreenCoord;
camera->project( labelPosition, &labelScreenCoord );
labelScreenCoord.x() = 0.1 * camera->viewport()->width();
camera->unproject( labelScreenCoord, &labelPosition );
const auto viewportWidth = camera->viewport()->width();
const auto viewportHeight = camera->viewport()->height();

auto labelText = annotationObject->text();
if ( strategy == LabelPositionStrategy::RIGHT || strategy == LabelPositionStrategy::LEFT_AND_RIGHT )
{
// Close to the right edge of the visible screen area
const auto normalizedXPosition = 0.9;

labelInfo.push_back( { labelText, lineAnchorPosition, labelPosition } );
auto labelCandidate = createLabel( camera, annotationObject, viewportWidth, normalizedXPosition, anchorLineScalingFactor );
if ( labelCandidate.has_value() ) labelInfo.push_back( labelCandidate.value() );
}

if ( m_strategy == LabelPositionStrategy::COUNT_HINT )
if ( strategy == LabelPositionStrategy::LEFT || strategy == LabelPositionStrategy::LEFT_AND_RIGHT )
{
const auto vpWidth = camera->viewport()->width();
const auto wpHeight = camera->viewport()->height();
// Close to the left edge of the visible screen area
const auto normalizedXPosition = 0.1;

auto labelCandidate = createLabel( camera, annotationObject, viewportWidth, normalizedXPosition, anchorLineScalingFactor );
if ( labelCandidate.has_value() ) labelInfo.push_back( labelCandidate.value() );
}

if ( strategy == LabelPositionStrategy::COUNT_HINT || strategy == LabelPositionStrategy::ALL )
{
std::vector<cvf::Vec3d> visibleCoords;
for ( const auto& v : annotationObject->anchorPointsDisplayCoords() )
{
cvf::Vec3d screenCoord;
camera->project( v, &screenCoord );

if ( screenCoord.x() > 0 && screenCoord.x() < vpWidth && screenCoord.y() > 0 && screenCoord.y() < wpHeight )
if ( screenCoord.x() > 0 && screenCoord.x() < viewportWidth && screenCoord.y() > 0 && screenCoord.y() < viewportHeight )
visibleCoords.push_back( v );
}

size_t stride = std::max( size_t( 1 ), visibleCoords.size() / m_labelCountHint - 1 );

for ( size_t i = 0; i < visibleCoords.size(); i += stride )
size_t stride = 1;
if ( strategy == LabelPositionStrategy::COUNT_HINT )
{
size_t adjustedIndex = std::min( i, visibleCoords.size() - 1 );

cvf::Vec3d lineAnchorPosition = visibleCoords[adjustedIndex];
cvf::Vec3d directionPointToCam = ( camera->position() - lineAnchorPosition ).getNormalized();
cvf::Vec3d labelPosition = lineAnchorPosition + directionPointToCam * anchorLineScalingFactor;

auto labelText = annotationObject->text();

labelInfo.push_back( { labelText, lineAnchorPosition, labelPosition } );
stride = std::max( size_t( 1 ), visibleCoords.size() / std::max( 1, m_labelCountHint - 1 ) );
}
}
else if ( m_strategy == LabelPositionStrategy::ALL )
{
const auto vpWidth = camera->viewport()->width();
const auto wpHeight = camera->viewport()->height();

std::vector<cvf::Vec3d> visibleCoords;
for ( const auto& v : annotationObject->anchorPointsDisplayCoords() )
{
cvf::Vec3d screenCoord;
camera->project( v, &screenCoord );

if ( screenCoord.x() > 0 && screenCoord.x() < vpWidth && screenCoord.y() > 0 && screenCoord.y() < wpHeight )
visibleCoords.push_back( v );
}

for ( size_t i = 0; i < visibleCoords.size(); i++ )
for ( size_t i = 0; i < visibleCoords.size(); i += stride )
{
cvf::Vec3d lineAnchorPosition = visibleCoords[i];
cvf::Vec3d directionPointToCam = ( camera->position() - lineAnchorPosition ).getNormalized();
cvf::Vec3d labelPosition = lineAnchorPosition + directionPointToCam * anchorLineScalingFactor;
size_t adjustedIndex = std::min( i, visibleCoords.size() - 1 );

auto labelText = annotationObject->text();
const cvf::Vec3d lineAnchorPosition = visibleCoords[adjustedIndex];
const cvf::Vec3d directionPointToCam = ( camera->position() - lineAnchorPosition ).getNormalized();
const cvf::Vec3d labelPosition = lineAnchorPosition + directionPointToCam * anchorLineScalingFactor;

labelInfo.push_back( { labelText, lineAnchorPosition, labelPosition } );
labelInfo.push_back( { annotationObject->text(), lineAnchorPosition, labelPosition } );
}
}
}
Expand Down
9 changes: 7 additions & 2 deletions ApplicationLibCode/ModelVisualization/RivAnnotationTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,16 @@ class RivAnnotationTools
LEFT_AND_RIGHT,
COUNT_HINT,
ALL,
NONE
NONE,
UNDEFINED
};

RivAnnotationTools( LabelPositionStrategy positionStrategy );
RivAnnotationTools();

// By default, each annotation object has a label position strategy. Use this method to override the default.
void setLabelPositionStrategy( LabelPositionStrategy positionStrategy );
void setCountHint( int countHint );

void addAnnotationLabels( const cvf::Collection<cvf::Part>& partCollection, const cvf::Camera* camera, cvf::ModelBasicList* model );

static cvf::ref<cvf::Part>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ void RivSeismicSectionPartMgr::appendSurfaceIntersectionLines( cvf::ModelBasicLi
// Add annotation info to be used to display label in Rim3dView::onViewNavigationChanged()
// Set the source info once, as this data is only used for display of labels
auto annoObj = new RivAnnotationSourceInfo( surface->fullName().toStdString(), completePolyLine );
annoObj->setPositionStrategyHint( RivAnnotationTools::LabelPositionStrategy::RIGHT );
annoObj->setLabelPositionStrategyHint( RivAnnotationTools::LabelPositionStrategy::RIGHT );

firstPart->setSourceInfo( annoObj );
}
Expand Down
Loading

0 comments on commit e06cb1c

Please sign in to comment.