Optionally show polygon geometry info as text label

This commit is contained in:
Magne Sjaastad
2025-05-30 08:20:43 +02:00
committed by GitHub
parent 118ecf941a
commit e492685070
13 changed files with 241 additions and 120 deletions
@@ -182,47 +182,14 @@ void RivMeasurementPartMgr::buildPolyLineParts( const cvf::Camera* camera, const
{
negativeXDir = true;
}
QString text = m_measurement->label();
auto labelPosition = pointsInDisplay.back();
RiaGuiApplication* app = RiaGuiApplication::instance();
auto backgroundColor = RiaPreferences::current()->defaultViewerBackgroundColor;
auto fontColor = RiuGuiTheme::getColorByVariableName( "textColor" );
QString text = m_measurement->label();
auto labelPosition = pointsInDisplay.back();
auto font = app->defaultWellLabelFont();
cvf::ref<cvf::DrawableText> drawableText = new cvf::DrawableText;
drawableText->setFont( font );
drawableText->setCheckPosVisible( false );
drawableText->setDrawBorder( true );
drawableText->setDrawBackground( true );
drawableText->setVerticalAlignment( cvf::TextDrawer::BASELINE );
drawableText->setBackgroundColor( backgroundColor );
drawableText->setBorderColor( RiaColorTools::computeOffsetColor( backgroundColor, 0.3f ) );
drawableText->setTextColor( RiaColorTools::fromQColorTo3f( fontColor ) );
cvf::String cvfString = cvfqt::Utils::toString( text );
cvf::Vec3d windowLabelPosition;
camera->project( labelPosition, &windowLabelPosition );
cvf::BoundingBox oneCharBB = drawableText->textBoundingBox( cvf::String( "A" ), cvf::Vec3f( labelPosition ) );
if ( negativeXDir )
{
cvf::BoundingBox textBB = drawableText->textBoundingBox( cvfString, cvf::Vec3f( labelPosition ) );
windowLabelPosition.x() -= textBB.extent().x() + oneCharBB.extent().x();
}
else
{
windowLabelPosition.x() += oneCharBB.extent().x();
}
camera->unproject( windowLabelPosition, &labelPosition );
cvf::Vec3f textCoord( labelPosition );
drawableText->addText( cvfString, textCoord );
auto drawableText = RivPolylineGenerator::createOrientedLabel( negativeXDir, camera, labelPosition, text );
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName( "RivMeasurementPartMgr: " + cvfString );
part->setName( "RivMeasurementPartMgr: " );
part->setDrawable( drawableText.p() );
cvf::ref<cvf::Effect> eff = new cvf::Effect();
@@ -18,9 +18,18 @@
#include "RivPolylineGenerator.h"
#include "RiaColorTools.h"
#include "RiaGuiApplication.h"
#include "RiaPreferences.h"
#include "RiuGuiTheme.h"
#include "cvfCamera.h"
#include "cvfDrawableGeo.h"
#include "cvfDrawableText.h"
#include "cvfPrimitiveSetDirect.h"
#include "cvfPrimitiveSetIndexedUInt.h"
#include "cvfqtUtils.h"
//--------------------------------------------------------------------------------------------------
///
@@ -162,3 +171,54 @@ cvf::ref<cvf::DrawableGeo> RivPolylineGenerator::createSetOfLines( const std::ve
return polylineGeo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::DrawableText> RivPolylineGenerator::createOrientedLabel( bool negativeXDirection,
const cvf::Camera* camera,
const cvf::Vec3d& labelPosition,
const QString& labelText )
{
RiaGuiApplication* app = RiaGuiApplication::instance();
auto backgroundColor = RiaPreferences::current()->defaultViewerBackgroundColor;
auto fontColor = RiuGuiTheme::getColorByVariableName( "textColor" );
auto font = app->defaultWellLabelFont();
cvf::ref<cvf::DrawableText> drawableText = new cvf::DrawableText;
drawableText->setFont( font );
drawableText->setCheckPosVisible( false );
drawableText->setDrawBorder( true );
drawableText->setDrawBackground( true );
drawableText->setVerticalAlignment( cvf::TextDrawer::BASELINE );
drawableText->setBackgroundColor( backgroundColor );
drawableText->setBorderColor( RiaColorTools::computeOffsetColor( backgroundColor, 0.3f ) );
drawableText->setTextColor( RiaColorTools::fromQColorTo3f( fontColor ) );
cvf::String cvfString = cvfqt::Utils::toString( labelText );
cvf::Vec3d finalPosition = labelPosition;
if ( camera )
{
cvf::Vec3d windowLabelPosition;
camera->project( labelPosition, &windowLabelPosition );
auto oneCharBB = drawableText->textBoundingBox( cvf::String( "A" ), cvf::Vec3f( labelPosition ) );
if ( negativeXDirection )
{
auto textBB = drawableText->textBoundingBox( cvfString, cvf::Vec3f( labelPosition ) );
windowLabelPosition.x() -= textBB.extent().x() + oneCharBB.extent().x();
}
else
{
windowLabelPosition.x() += oneCharBB.extent().x();
}
camera->unproject( windowLabelPosition, &finalPosition );
}
drawableText->addText( cvfString, cvf::Vec3f( finalPosition ) );
return drawableText;
}
@@ -21,11 +21,15 @@
#include "cvfObject.h"
#include <cvfVector3.h>
#include <QString>
#include <vector>
namespace cvf
{
class DrawableGeo;
class DrawableText;
class Camera;
} // namespace cvf
//==================================================================================================
@@ -42,4 +46,7 @@ public:
static cvf::ref<cvf::DrawableGeo> createPointsFromPolylineDrawable( const std::vector<std::vector<cvf::Vec3d>>& polyLines );
static cvf::ref<cvf::DrawableGeo> createSetOfLines( const std::vector<std::vector<cvf::Vec3d>>& lines );
static cvf::ref<cvf::DrawableText>
createOrientedLabel( bool negativeXDirection, const cvf::Camera* camera, const cvf::Vec3d& labelPosition, const QString& labelText );
};
@@ -31,6 +31,8 @@
#include "RivPartPriority.h"
#include "RivPolylineGenerator.h"
#include "RiuViewer.h"
#include "cafEffectGenerator.h"
#include "cafDisplayCoordTransform.h"
@@ -79,7 +81,9 @@ bool RivPolylinePartMgr::isPolylinesInBoundingBox( std::vector<std::vector<cvf::
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivPolylinePartMgr::buildPolylineParts( const caf::DisplayCoordTransform* displayXf, const cvf::BoundingBox& boundingBox )
void RivPolylinePartMgr::buildPolylineParts( const cvf::Camera* camera,
const caf::DisplayCoordTransform* displayXf,
const cvf::BoundingBox& boundingBox )
{
auto polylineDef = m_polylineInterface->polyLinesData();
if ( polylineDef.isNull() || polylineDef->rawPolyLines().empty() )
@@ -120,6 +124,38 @@ void RivPolylinePartMgr::buildPolylineParts( const caf::DisplayCoordTransform* d
m_linePart = part;
}
auto labelText = m_polylineInterface->label();
if ( !labelText.isEmpty() && !polylineDef->completePolyLines().empty() && m_linePart.notNull() )
{
cvf::BoundingBox bb;
for ( const auto& lines : linesInDisplay )
{
for ( const auto& point : lines )
{
bb.add( point );
}
}
if ( bb.isValid() )
{
auto labelPosition = bb.center();
labelPosition.z() += 200;
bool negativeXDir = false;
auto drawableText = RivPolylineGenerator::createOrientedLabel( negativeXDir, camera, labelPosition, labelText );
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName( "RivPolylinePartMgr::buildPolylineParts" );
part->setDrawable( drawableText.p() );
cvf::ref<cvf::Effect> eff = new cvf::Effect();
part->setEffect( eff.p() );
part->setPriority( RivPartPriority::PartType::Text );
m_labelPart = part;
}
}
// Sphere part
if ( polylineDef->showSpheres() )
{
@@ -236,6 +272,7 @@ void RivPolylinePartMgr::clearAllGeometry()
{
m_linePart = nullptr;
m_spherePart = nullptr;
m_labelPart = nullptr;
}
//--------------------------------------------------------------------------------------------------
@@ -261,8 +298,14 @@ void RivPolylinePartMgr::appendDynamicGeometryPartsToModel( cvf::ModelBasicList*
{
if ( !collectionVisible() ) return;
cvf::Camera* camera = nullptr;
if ( m_rimView.notNull() && m_rimView->viewer() )
{
camera = m_rimView->viewer()->mainCamera();
}
// build the lines
buildPolylineParts( displayXf, boundingBox );
buildPolylineParts( camera, displayXf, boundingBox );
// add the things we should
if ( m_linePart.notNull() )
@@ -274,4 +317,9 @@ void RivPolylinePartMgr::appendDynamicGeometryPartsToModel( cvf::ModelBasicList*
{
model->addPart( m_spherePart.p() );
}
if ( m_labelPart.notNull() )
{
model->addPart( m_labelPart.p() );
}
}
@@ -34,6 +34,7 @@ class Part;
class ModelBasicList;
class Transform;
class Font;
class Camera;
} // namespace cvf
namespace caf
@@ -57,7 +58,7 @@ public:
private:
bool isPolylinesInBoundingBox( std::vector<std::vector<cvf::Vec3d>> polyline, const cvf::BoundingBox& boundingBox );
void buildPolylineParts( const caf::DisplayCoordTransform* displayXf, const cvf::BoundingBox& boundingBox );
void buildPolylineParts( const cvf::Camera* camera, const caf::DisplayCoordTransform* displayXf, const cvf::BoundingBox& boundingBox );
std::vector<std::vector<cvf::Vec3d>> getPolylinesPointsInDomain( RigPolyLinesData* lineDef );
std::vector<std::vector<cvf::Vec3d>> transformPolylinesPointsToDisplay( const std::vector<std::vector<cvf::Vec3d>>& pointsInDomain,
@@ -72,4 +73,5 @@ private:
caf::PdmPointer<Rim3dView> m_rimView;
cvf::ref<cvf::Part> m_linePart;
cvf::ref<cvf::Part> m_spherePart;
cvf::ref<cvf::Part> m_labelPart;
};
@@ -20,15 +20,17 @@
#include "RiaApplication.h"
#include "RigPolygonTools.h"
#include "Rim3dView.h"
#include "RimGridView.h"
#include "MeasurementCommands/RicMeasurementPickEventHandler.h"
#include "RiuMainWindow.h"
#include "RiuMeasurementEventFilter.h"
#include "RiuViewerCommands.h"
#include "RiuMainWindow.h"
#include "cvfGeometryTools.h"
CAF_PDM_SOURCE_INIT( RimMeasurement, "RimMeasurement" );
@@ -127,63 +129,8 @@ void RimMeasurement::removeAllPoints()
//--------------------------------------------------------------------------------------------------
QString RimMeasurement::label() const
{
auto lengths = calculateLengths();
QString text;
if ( m_pointsInDomainCoords.size() > 2 )
{
text = QString( "Segment Length: %1\nSegment Horizontal Length: %2\n" ).arg( lengths.lastSegmentLength ).arg( lengths.lastSegmentHorisontalLength );
text += QString( "Total Length: %1\nTotal Horizontal Length: %2\n" ).arg( lengths.totalLength ).arg( lengths.totalHorizontalLength );
text += QString( "\nHorizontal Area : %1" ).arg( lengths.area );
}
else
{
text = QString( "Length: %1\nHorizontal Length: %2\n" ).arg( lengths.lastSegmentLength ).arg( lengths.lastSegmentHorisontalLength );
}
return text;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimMeasurement::Lengths RimMeasurement::calculateLengths() const
{
Lengths lengths;
for ( size_t p = 1; p < m_pointsInDomainCoords.size(); p++ )
{
const auto& p0 = m_pointsInDomainCoords[p - 1];
const auto& p1 = m_pointsInDomainCoords[p];
lengths.lastSegmentLength = ( p1 - p0 ).length();
const auto& p1_horiz = cvf::Vec3d( p1.x(), p1.y(), p0.z() );
lengths.lastSegmentHorisontalLength = ( p1_horiz - p0 ).length();
lengths.totalLength += lengths.lastSegmentLength;
lengths.totalHorizontalLength += lengths.lastSegmentHorisontalLength;
}
{
std::vector<Vec3d> pointsProjectedInZPlane;
for ( const auto& p : m_pointsInDomainCoords )
{
auto pointInZ = p;
pointInZ.z() = 0.0;
pointsProjectedInZPlane.push_back( pointInZ );
}
Vec3d area = cvf::GeometryTools::polygonAreaNormal3D( pointsProjectedInZPlane );
lengths.area = cvf::Math::abs( area.z() );
}
return lengths;
bool includeLastSegmentInfo = true;
return RigPolygonTools::geometryDataAsText( m_pointsInDomainCoords, includeLastSegmentInfo );
}
//--------------------------------------------------------------------------------------------------
@@ -45,25 +45,6 @@ public:
MEASURE_POLYLINE
};
class Lengths
{
public:
Lengths()
: totalLength( 0 )
, lastSegmentLength( 0 )
, totalHorizontalLength( 0 )
, lastSegmentHorisontalLength( 0 )
, area( 0 )
{
}
double totalLength;
double lastSegmentLength;
double totalHorizontalLength;
double lastSegmentHorisontalLength;
double area;
};
RimMeasurement();
~RimMeasurement() override;
@@ -78,8 +59,6 @@ public:
QString label() const;
private:
Lengths calculateLengths() const;
void updateView() const;
private:
@@ -21,6 +21,7 @@
#include "RiaColorTools.h"
#include "RigPolyLinesData.h"
#include "RigPolygonTools.h"
#include "Rim3dView.h"
#include "RimPolygon.h"
@@ -65,6 +66,8 @@ RimPolygonInView::RimPolygonInView()
CAF_PDM_InitField( &m_selectPolygon, "SelectPolygon", false, "" );
caf::PdmUiPushButtonEditor::configureEditorLabelHidden( &m_selectPolygon );
CAF_PDM_InitField( &m_showLabel, "ShowLabel", false, "Show Label" );
CAF_PDM_InitField( &m_handleScalingFactor, "HandleScalingFactor", 2.0, "Handle Scaling Factor" );
CAF_PDM_InitFieldNoDefault( &m_targets, "Targets", "Targets" );
@@ -305,6 +308,8 @@ void RimPolygonInView::defineUiOrdering( QString uiConfigName, caf::PdmUiOrderin
uiOrdering.add( &m_handleScalingFactor );
}
uiOrdering.add( &m_showLabel );
if ( m_polygon() )
{
uiOrdering.add( &m_selectPolygon );
@@ -388,6 +393,23 @@ void RimPolygonInView::uiOrderingForLocalPolygon( QString uiConfigName, caf::Pdm
uiOrdering.add( &m_handleScalingFactor );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimPolygonInView::label() const
{
if ( m_showLabel() && m_polygon() )
{
bool includeLastSegmentInfo = false;
QString label = m_polygon->name();
label += "\n" + RigPolygonTools::geometryDataAsText( m_polygon->pointsInDomainCoords(), includeLastSegmentInfo );
return label;
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -74,6 +74,8 @@ public:
void uiOrderingForLocalPolygon( QString uiConfigName, caf::PdmUiOrdering& uiOrdering );
QString label() const override;
protected:
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
@@ -100,6 +102,8 @@ private:
caf::PdmField<double> m_handleScalingFactor;
caf::PdmChildArrayField<RimPolylineTarget*> m_targets;
caf::PdmField<bool> m_showLabel;
cvf::ref<RivPolylinePartMgr> m_polylinePartMgr;
std::shared_ptr<RicPolylineTargetsPickEventHandler> m_pickTargetsEventHandler;
};
@@ -425,6 +425,8 @@ void RimGridView::appendPolygonPartsToModel( caf::DisplayCoordTransform* scaleTr
}
nativeOrOverrideViewer()->addStaticModelOnce( m_polygonVizModel.p(), isUsingOverrideViewer() );
m_polygonVizModel->updateBoundingBoxesRecursive();
}
//--------------------------------------------------------------------------------------------------
@@ -26,4 +26,5 @@ class RimPolylinesDataInterface
{
public:
virtual cvf::ref<RigPolyLinesData> polyLinesData() const = 0;
virtual QString label() const { return {}; };
};
@@ -28,6 +28,15 @@ namespace RigPolygonTools
{
namespace internal
{
struct GeometryData
{
double totalLength{ 0 };
double lastSegmentLength{ 0 };
double totalHorizontalLength{ 0 };
double lastSegmentHorisontalLength{ 0 };
double horizontalArea{ 0 };
};
// Function to check if a point is valid and within bounds
bool isValid( int x, int y, int rows, int cols, const IntegerImage& image, const IntegerImage& visited )
{
@@ -113,6 +122,46 @@ namespace internal
return ( count % 2 ) == 1; // Odd count means inside, even means outside
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
GeometryData computePolygonGeometryData( const std::vector<cvf::Vec3d>& vertices )
{
GeometryData geometryData;
for ( size_t p = 1; p < vertices.size(); p++ )
{
const auto& p0 = vertices[p - 1];
const auto& p1 = vertices[p];
geometryData.lastSegmentLength = ( p1 - p0 ).length();
const auto& p1_horiz = cvf::Vec3d( p1.x(), p1.y(), p0.z() );
geometryData.lastSegmentHorisontalLength = ( p1_horiz - p0 ).length();
geometryData.totalLength += geometryData.lastSegmentLength;
geometryData.totalHorizontalLength += geometryData.lastSegmentHorisontalLength;
}
auto projectToZPlane = []( const std::vector<cvf::Vec3d>& vertices )
{
std::vector<cvf::Vec3d> pointsProjectedInZPlane;
for ( const auto& p : vertices )
{
auto pointInZ = p;
pointInZ.z() = 0.0;
pointsProjectedInZPlane.push_back( pointInZ );
}
return pointsProjectedInZPlane;
};
cvf::Vec3d area = cvf::GeometryTools::polygonAreaNormal3D( projectToZPlane( vertices ) );
geometryData.horizontalArea = cvf::Math::abs( area.z() );
return geometryData;
}
}; // namespace internal
//--------------------------------------------------------------------------------------------------
@@ -406,4 +455,34 @@ void simplifyPolygon( std::vector<cvf::Vec3d>& vertices, double epsilon )
vertices = { vertices.front(), vertices.back() };
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString geometryDataAsText( const std::vector<cvf::Vec3d>& vertices, bool includeLastSegmentInfo )
{
auto geometryData = internal::computePolygonGeometryData( vertices );
QString text;
if ( vertices.size() > 2 )
{
if ( includeLastSegmentInfo )
{
text += QString( "Segment Length: %1\nSegment Horizontal Length: %2\n" )
.arg( geometryData.lastSegmentLength )
.arg( geometryData.lastSegmentHorisontalLength );
}
text +=
QString( "Total Length: %1\nTotal Horizontal Length: %2\n" ).arg( geometryData.totalLength ).arg( geometryData.totalHorizontalLength );
text += QString( "\nHorizontal Area : %1" ).arg( geometryData.horizontalArea );
}
else
{
text = QString( "Length: %1\nHorizontal Length: %2\n" ).arg( geometryData.lastSegmentLength ).arg( geometryData.lastSegmentHorisontalLength );
}
return text;
}
} // namespace RigPolygonTools
@@ -20,6 +20,8 @@
#include "cvfVector3.h"
#include <QString>
#include <vector>
namespace RigPolygonTools
@@ -39,4 +41,5 @@ double area( const std::vector<Point>& polygon );
// Recursive function modifying the incoming vertices
void simplifyPolygon( std::vector<cvf::Vec3d>& vertices, double epsilon );
QString geometryDataAsText( const std::vector<cvf::Vec3d>& vertices, bool includeLastSegmentInfo );
} // namespace RigPolygonTools