#3876 Implement rotated labels on contour maps

This commit is contained in:
Gaute Lindkvist
2019-01-03 17:07:55 +01:00
parent 71cacc550f
commit 7a275be335
14 changed files with 593 additions and 208 deletions

View File

@@ -3,14 +3,17 @@
#include "RiaColorTools.h" #include "RiaColorTools.h"
#include "RiaFontCache.h" #include "RiaFontCache.h"
#include "RiaWeightedMeanCalculator.h" #include "RiaWeightedMeanCalculator.h"
#include "RigCellGeometryTools.h"
#include "RivMeshLinesSourceInfo.h" #include "RivMeshLinesSourceInfo.h"
#include "RivScalarMapperUtils.h" #include "RivScalarMapperUtils.h"
#include "RivPartPriority.h"
#include "RimContourMapView.h" #include "RimContourMapView.h"
#include "RimContourMapProjection.h" #include "RimContourMapProjection.h"
#include "cafEffectGenerator.h" #include "cafEffectGenerator.h"
#include "cvfCamera.h"
#include "cvfDrawableText.h" #include "cvfDrawableText.h"
#include "cvfGeometryBuilderFaceList.h" #include "cvfGeometryBuilderFaceList.h"
#include "cvfGeometryUtils.h" #include "cvfGeometryUtils.h"
@@ -18,6 +21,7 @@
#include "cvfPart.h" #include "cvfPart.h"
#include "cvfPrimitiveSetIndexedUInt.h" #include "cvfPrimitiveSetIndexedUInt.h"
#include "cvfScalarMapper.h" #include "cvfScalarMapper.h"
#include "cvfRay.h"
#include <cmath> #include <cmath>
@@ -30,52 +34,26 @@ RivContourMapProjectionPartMgr::RivContourMapProjectionPartMgr(RimContourMapProj
m_parentContourMap = contourMap; m_parentContourMap = contourMap;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivContourMapProjectionPartMgr::createProjectionGeometry()
{
m_contourMapProjection->generateContourPolygons();
m_contourLinePolygons = m_contourMapProjection->contourPolygons();
m_contourMapTriangles = m_contourMapProjection->generateTriangles();
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RivContourMapProjectionPartMgr::appendProjectionToModel(cvf::ModelBasicList* model, const caf::DisplayCoordTransform* displayCoordTransform) const void RivContourMapProjectionPartMgr::appendProjectionToModel(cvf::ModelBasicList* model, const caf::DisplayCoordTransform* displayCoordTransform) const
{ {
cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper();
std::vector<std::vector<cvf::ref<cvf::Drawable>>> contourDrawablesForAllLevels = createContourPolygons(displayCoordTransform);
cvf::ref<cvf::Part> mapPart = createProjectionMapPart(displayCoordTransform); cvf::ref<cvf::Part> mapPart = createProjectionMapPart(displayCoordTransform);
if (mapPart.notNull()) if (mapPart.notNull())
{ {
model->addPart(mapPart.p()); model->addPart(mapPart.p());
} }
if (m_contourMapProjection->showContourLines())
{
std::vector<double> tickValues;
mapper->majorTickValues(&tickValues);
for (size_t i = 0; i < contourDrawablesForAllLevels.size(); ++i)
{
std::vector<cvf::ref<cvf::Drawable>> contourDrawables = contourDrawablesForAllLevels[i];
cvf::Color3f backgroundColor(mapper->mapToColor(tickValues[i]));
cvf::Color3f lineColor = RiaColorTools::contrastColor(backgroundColor, true);
for (cvf::ref<cvf::Drawable> contourDrawable : contourDrawables)
{
if (contourDrawable.notNull() && contourDrawable->boundingBox().isValid())
{
caf::MeshEffectGenerator meshEffectGen(lineColor);
meshEffectGen.setLineWidth(1.0f);
meshEffectGen.createAndConfigurePolygonOffsetRenderState(caf::PO_1);
cvf::ref<cvf::Effect> effect = meshEffectGen.generateCachedEffect();
cvf::ref<cvf::Part> part = new cvf::Part;
part->setDrawable(contourDrawable.p());
part->setEffect(effect.p());
part->setSourceInfo(new RivMeshLinesSourceInfo(m_contourMapProjection.p()));
model->addPart(part.p());
}
}
}
}
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -127,6 +105,70 @@ cvf::ref<cvf::Vec2fArray> RivContourMapProjectionPartMgr::createTextureCoords(co
return textureCoords; return textureCoords;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivContourMapProjectionPartMgr::appendContourLinesToModel(const cvf::Camera* camera,
cvf::ModelBasicList* model,
const caf::DisplayCoordTransform* displayCoordTransform) const
{
if (m_contourMapProjection->showContourLines())
{
cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper();
std::vector<std::vector<cvf::BoundingBox>> labelBBoxes;
std::vector<cvf::ref<cvf::Drawable>> labelDrawables = createContourLabels(camera, displayCoordTransform, &labelBBoxes);
std::vector<std::vector<cvf::ref<cvf::Drawable>>> contourDrawablesForAllLevels =
createContourPolygons(displayCoordTransform, labelBBoxes);
std::vector<double> tickValues;
mapper->majorTickValues(&tickValues);
for (size_t i = 0; i < contourDrawablesForAllLevels.size(); ++i)
{
std::vector<cvf::ref<cvf::Drawable>> contourDrawables = contourDrawablesForAllLevels[i];
cvf::Color3f backgroundColor(mapper->mapToColor(tickValues[i]));
cvf::Color3f lineColor = RiaColorTools::contrastColor(backgroundColor);
for (cvf::ref<cvf::Drawable> contourDrawable : contourDrawables)
{
if (contourDrawable.notNull() && contourDrawable->boundingBox().isValid())
{
caf::MeshEffectGenerator meshEffectGen(lineColor);
meshEffectGen.setLineWidth(1.0f);
meshEffectGen.createAndConfigurePolygonOffsetRenderState(caf::PO_1);
cvf::ref<cvf::Effect> effect = meshEffectGen.generateCachedEffect();
cvf::ref<cvf::Part> part = new cvf::Part;
part->setDrawable(contourDrawable.p());
part->setEffect(effect.p());
part->setSourceInfo(new RivMeshLinesSourceInfo(m_contourMapProjection.p()));
model->addPart(part.p());
}
}
}
for (auto labelDrawableRef : labelDrawables)
{
caf::MeshEffectGenerator meshEffectGen(cvf::Color3::BLACK);
meshEffectGen.setLineWidth(1.0f);
meshEffectGen.createAndConfigurePolygonOffsetRenderState(caf::PO_2);
cvf::ref<cvf::Effect> effect = meshEffectGen.generateCachedEffect();
cvf::ref<cvf::Part> part = new cvf::Part;
part->setDrawable(labelDrawableRef.p());
part->setEffect(effect.p());
part->setPriority(RivPartPriority::Text);
part->setSourceInfo(new RivMeshLinesSourceInfo(m_contourMapProjection.p()));
model->addPart(part.p());
}
}
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -136,13 +178,14 @@ cvf::ref<cvf::DrawableText> RivContourMapProjectionPartMgr::createTextLabel(cons
cvf::ref<cvf::DrawableText> labelDrawable = new cvf::DrawableText(); cvf::ref<cvf::DrawableText> labelDrawable = new cvf::DrawableText();
labelDrawable->setFont(font.p()); labelDrawable->setFont(font.p());
labelDrawable->setCheckPosVisible(true); labelDrawable->setCheckPosVisible(false);
labelDrawable->setUseDepthBuffer(true); labelDrawable->setUseDepthBuffer(true);
labelDrawable->setDrawBorder(false); labelDrawable->setDrawBorder(false);
labelDrawable->setDrawBackground(false); labelDrawable->setDrawBackground(false);
labelDrawable->setBackgroundColor(backgroundColor); labelDrawable->setBackgroundColor(backgroundColor);
labelDrawable->setVerticalAlignment(cvf::TextDrawer::BASELINE); labelDrawable->setVerticalAlignment(cvf::TextDrawer::CENTER);
labelDrawable->setTextColor(textColor); labelDrawable->setTextColor(textColor);
labelDrawable->setBorderColor(textColor);
return labelDrawable; return labelDrawable;
} }
@@ -152,7 +195,7 @@ cvf::ref<cvf::DrawableText> RivContourMapProjectionPartMgr::createTextLabel(cons
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
cvf::ref<cvf::Part> RivContourMapProjectionPartMgr::createProjectionMapPart(const caf::DisplayCoordTransform* displayCoordTransform) const cvf::ref<cvf::Part> RivContourMapProjectionPartMgr::createProjectionMapPart(const caf::DisplayCoordTransform* displayCoordTransform) const
{ {
std::vector<cvf::Vec4d> vertices = m_contourMapProjection->generateTriangles(); const std::vector<cvf::Vec4d>& vertices = m_contourMapTriangles;
if (vertices.size() < 3u) if (vertices.size() < 3u)
{ {
return cvf::ref<cvf::Part>(); return cvf::ref<cvf::Part>();
@@ -192,60 +235,100 @@ cvf::ref<cvf::Part> RivContourMapProjectionPartMgr::createProjectionMapPart(cons
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
std::vector<std::vector<cvf::ref<cvf::Drawable>>> RivContourMapProjectionPartMgr::createContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform) const std::vector<std::vector<cvf::ref<cvf::Drawable>>> RivContourMapProjectionPartMgr::createContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform, const std::vector<std::vector<cvf::BoundingBox>>& labelBBoxes) const
{ {
m_contourMapProjection->generateContourPolygons();
const std::vector<RimContourMapProjection::ContourPolygons>& contourPolygons = m_contourMapProjection->contourPolygons();
const cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper(); const cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper();
std::vector<double> tickValues; std::vector<double> tickValues;
mapper->majorTickValues(&tickValues); mapper->majorTickValues(&tickValues);
std::vector<std::vector<cvf::ref<cvf::Drawable>>> contourDrawablesForAllLevels; std::vector<std::vector<cvf::ref<cvf::Drawable>>> contourDrawablesForAllLevels;
std::vector<cvf::ref<cvf::Drawable>> labelDrawables; contourDrawablesForAllLevels.resize(tickValues.size());
for (int64_t i = (int64_t) contourPolygons.size() - 1; i > 0; --i)
for (size_t i = 1; i < m_contourLinePolygons.size(); ++i)
{ {
std::vector<cvf::ref<cvf::Drawable>> contourDrawables; std::vector<cvf::ref<cvf::Drawable>> contourDrawables;
cvf::Color3f backgroundColor(mapper->mapToColor(tickValues[i])); for (size_t j = 0; j < m_contourLinePolygons[i].size(); ++j)
cvf::Color3f textColor = RiaColorTools::contrastColor(backgroundColor);
for (size_t j = 0; j < contourPolygons[i].size(); ++j)
{ {
if (contourPolygons[i][j].vertices.empty()) continue; if (m_contourLinePolygons[i][j].vertices.empty()) continue;
size_t nVertices = contourPolygons[i][j].vertices.size(); cvf::String labelText(m_contourLinePolygons[i][j].value);
size_t nLabels = m_contourMapProjection->showContourLabels() ? std::max((size_t)1, nVertices / 100u) : 0u;
for (size_t l = 0; l < nLabels; ++l) size_t nVertices = m_contourLinePolygons[i][j].vertices.size();
{
cvf::ref<cvf::DrawableText> label = createTextLabel(textColor, backgroundColor); std::vector<cvf::Vec3f> displayLines; displayLines.reserve(nVertices * 2);
cvf::Vec3d globalVertex = contourPolygons[i][j].vertices[(nVertices * l) / nLabels] + m_contourMapProjection->origin3d();
cvf::Vec3f displayVertex(displayCoordTransform->transformToDisplayCoord(globalVertex));
displayVertex.z() += 3.0f;
label->addText(cvf::String(contourPolygons[i][j].value), displayVertex);
bool overlaps = false;
cvf::BoundingBox bbox = label->boundingBox();
for (cvf::ref<cvf::Drawable> existingLabel : labelDrawables)
{
if (existingLabel->boundingBox().intersects(bbox))
{
overlaps = true;
break;
}
}
if (!overlaps)
{
labelDrawables.push_back(label);
}
}
cvf::ref<cvf::Vec3fArray> vertexArray = new cvf::Vec3fArray(nVertices);
for (size_t v = 0; v < nVertices; ++v) for (size_t v = 0; v < nVertices; ++v)
{ {
cvf::Vec3d globalVertex = contourPolygons[i][j].vertices[v] + m_contourMapProjection->origin3d(); cvf::Vec3d globalVertex1 = m_contourLinePolygons[i][j].vertices[v] + m_contourMapProjection->origin3d();
cvf::Vec3d displayVertex1 = displayCoordTransform->transformToDisplayCoord(globalVertex); cvf::Vec3d displayVertex1 = displayCoordTransform->transformToDisplayCoord(globalVertex1);
(*vertexArray)[v] = cvf::Vec3f(displayVertex1);
cvf::Vec3d globalVertex2;
if (v < nVertices - 1)
globalVertex2 = m_contourLinePolygons[i][j].vertices[v + 1] + m_contourMapProjection->origin3d();
else
globalVertex2 = m_contourLinePolygons[i][j].vertices[0] + m_contourMapProjection->origin3d();
cvf::Vec3d displayVertex2 = displayCoordTransform->transformToDisplayCoord(globalVertex2);
cvf::BoundingBox lineBBox;
lineBBox.add(displayVertex1);
lineBBox.add(displayVertex2);
bool addOriginalSegment = true;
for (const cvf::BoundingBox& existingBBox : labelBBoxes[i])
{
if (lineBBox.intersects(existingBBox))
{
if (existingBBox.contains(displayVertex1) && existingBBox.contains(displayVertex2))
{
addOriginalSegment = false;
}
else
{
cvf::Vec3d dir = displayVertex2 - displayVertex1;
cvf::Ray ray;
ray.setOrigin(displayVertex1);
ray.setDirection(dir.getNormalized());
ray.setMaximumDistance(dir.length());
if (!existingBBox.contains(displayVertex1))
{
cvf::Vec3d intersection;
bool hit = ray.boxIntersect(existingBBox, &intersection);
if (hit)
{
displayLines.push_back(cvf::Vec3f(displayVertex1));
displayLines.push_back(cvf::Vec3f(intersection));
addOriginalSegment = false;
}
}
if (!existingBBox.contains(displayVertex2))
{
ray.setOrigin(displayVertex2);
ray.setDirection(-ray.direction());
cvf::Vec3d intersection;
bool hit = ray.boxIntersect(existingBBox, &intersection);
if (hit)
{
displayLines.push_back(cvf::Vec3f(intersection));
displayLines.push_back(cvf::Vec3f(displayVertex2));
addOriginalSegment = false;
}
}
}
}
}
if (addOriginalSegment)
{
displayLines.push_back(cvf::Vec3f(displayVertex1));
displayLines.push_back(cvf::Vec3f(displayVertex2));
}
} }
cvf::ref<cvf::Vec3fArray> vertexArray = new cvf::Vec3fArray(displayLines);
std::vector<cvf::uint> indices; std::vector<cvf::uint> indices;
indices.reserve(vertexArray->size()); indices.reserve(vertexArray->size());
for (cvf::uint k = 0; k < vertexArray->size(); ++k) for (cvf::uint k = 0; k < vertexArray->size(); ++k)
@@ -253,7 +336,7 @@ std::vector<std::vector<cvf::ref<cvf::Drawable>>> RivContourMapProjectionPartMgr
indices.push_back(k); indices.push_back(k);
} }
cvf::ref<cvf::PrimitiveSetIndexedUInt> indexedUInt = new cvf::PrimitiveSetIndexedUInt(cvf::PrimitiveType::PT_LINE_LOOP); cvf::ref<cvf::PrimitiveSetIndexedUInt> indexedUInt = new cvf::PrimitiveSetIndexedUInt(cvf::PrimitiveType::PT_LINES);
cvf::ref<cvf::UIntArray> indexArray = new cvf::UIntArray(indices); cvf::ref<cvf::UIntArray> indexArray = new cvf::UIntArray(indices);
indexedUInt->setIndices(indexArray.p()); indexedUInt->setIndices(indexArray.p());
@@ -263,17 +346,89 @@ std::vector<std::vector<cvf::ref<cvf::Drawable>>> RivContourMapProjectionPartMgr
geo->setVertexArray(vertexArray.p()); geo->setVertexArray(vertexArray.p());
contourDrawables.push_back(geo); contourDrawables.push_back(geo);
} }
for (cvf::ref<cvf::Drawable> labelDrawable : labelDrawables) contourDrawablesForAllLevels[i] = contourDrawables;
{
contourDrawables.push_back(labelDrawable);
}
contourDrawablesForAllLevels.push_back(contourDrawables);
} }
return contourDrawablesForAllLevels; return contourDrawablesForAllLevels;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<cvf::ref<cvf::Drawable>>
RivContourMapProjectionPartMgr::createContourLabels(const cvf::Camera* camera,
const caf::DisplayCoordTransform* displayCoordTransform,
std::vector<std::vector<cvf::BoundingBox>>* labelBBoxes) const
{
CVF_ASSERT(camera && displayCoordTransform && labelBBoxes);
const cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper();
std::vector<double> tickValues;
mapper->majorTickValues(&tickValues);
std::vector<cvf::ref<cvf::Drawable>> labelDrawables;
labelBBoxes->clear();
labelBBoxes->resize(m_contourLinePolygons.size());
for (int64_t i = (int64_t)m_contourLinePolygons.size() - 1; i > 0; --i)
{
cvf::Color3f backgroundColor(mapper->mapToColor(tickValues[i]));
cvf::Color3f textColor = RiaColorTools::contrastColor(backgroundColor);
cvf::ref<cvf::DrawableText> label = createTextLabel(textColor, backgroundColor);
for (size_t j = 0; j < m_contourLinePolygons[i].size(); ++j)
{
if (m_contourLinePolygons[i][j].vertices.empty()) continue;
cvf::String labelText(m_contourLinePolygons[i][j].value);
size_t nVertices = m_contourLinePolygons[i][j].vertices.size();
size_t nLabels = m_contourMapProjection->showContourLabels() ? std::max((size_t)1, nVertices / 50u) : 0u;
for (size_t l = 0; l < nLabels; ++l)
{
size_t nVertex = (nVertices * l) / nLabels;
cvf::Vec3d globalVertex1 = m_contourLinePolygons[i][j].vertices[nVertex] + m_contourMapProjection->origin3d();
cvf::Vec3d globalVertex2 =
m_contourLinePolygons[i][j].vertices[nVertex + 1 % nVertices] + m_contourMapProjection->origin3d();
cvf::Vec3d globalVertex = 0.5 * (globalVertex1 + globalVertex2);
cvf::Vec3f segment = cvf::Vec3f(globalVertex2 - globalVertex1).getNormalized();
cvf::Vec3d displayVertex = displayCoordTransform->transformToDisplayCoord(globalVertex);
cvf::Vec3d windowVertex;
camera->project(displayVertex, &windowVertex);
displayVertex.z() += 10.0f;
cvf::BoundingBox windowBBox = label->textBoundingBox(labelText, cvf::Vec3f::ZERO, segment);
cvf::Vec3d displayBBoxMin, displayBoxMax;
camera->unproject(windowBBox.min() + windowVertex, &displayBBoxMin);
camera->unproject(windowBBox.max() + windowVertex, &displayBoxMax);
cvf::BoundingBox displayBBox(displayBBoxMin - cvf::Vec3d::Z_AXIS * 20.0, displayBoxMax + cvf::Vec3d::Z_AXIS * 20.0);
bool overlaps = false;
for (auto boxVector : *labelBBoxes)
{
for (const cvf::BoundingBox& existingBBox : boxVector)
{
if (existingBBox.intersects(displayBBox))
{
overlaps = true;
break;
}
}
}
if (!overlaps)
{
label->addText(labelText, cvf::Vec3f(displayVertex), segment);
labelBBoxes->at(i).push_back(displayBBox);
}
}
}
if (label->numberOfTexts() != 0u)
{
labelDrawables.push_back(label);
}
}
return labelDrawables;
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------

View File

@@ -18,6 +18,8 @@
#pragma once #pragma once
#include "RimContourMapProjection.h"
#include "cafPdmPointer.h" #include "cafPdmPointer.h"
#include "cafDisplayCoordTransform.h" #include "cafDisplayCoordTransform.h"
@@ -26,29 +28,37 @@
#include "cvfDrawableText.h" #include "cvfDrawableText.h"
#include "cvfModelBasicList.h" #include "cvfModelBasicList.h"
#include "cvfObject.h" #include "cvfObject.h"
#include "cvfVector4.h"
class RimContourMapView; class RimContourMapView;
class RimContourMapProjection;
class RivContourMapProjectionPartMgr : public cvf::Object class RivContourMapProjectionPartMgr : public cvf::Object
{ {
public: public:
RivContourMapProjectionPartMgr(RimContourMapProjection* contourMapProjection, RimContourMapView* contourMap); RivContourMapProjectionPartMgr(RimContourMapProjection* contourMapProjection, RimContourMapView* contourMap);
void createProjectionGeometry();
void appendProjectionToModel(cvf::ModelBasicList* model, void appendProjectionToModel(cvf::ModelBasicList* model,
const caf::DisplayCoordTransform* displayCoordTransform) const; const caf::DisplayCoordTransform* displayCoordTransform) const;
void appendContourLinesToModel(const cvf::Camera* camera, cvf::ModelBasicList* model, const caf::DisplayCoordTransform* displayCoordTransform) const;
void appendPickPointVisToModel(cvf::ModelBasicList* model, void appendPickPointVisToModel(cvf::ModelBasicList* model,
const caf::DisplayCoordTransform* displayCoordTransform) const; const caf::DisplayCoordTransform* displayCoordTransform) const;
cvf::ref<cvf::Vec2fArray> createTextureCoords(const std::vector<double>& values) const; cvf::ref<cvf::Vec2fArray> createTextureCoords(const std::vector<double>& values) const;
private: private:
static cvf::ref<cvf::DrawableText> createTextLabel(const cvf::Color3f& textColor, const cvf::Color3f& backgroundColor); static cvf::ref<cvf::DrawableText> createTextLabel(const cvf::Color3f& textColor, const cvf::Color3f& backgroundColor);
cvf::ref<cvf::Part> createProjectionMapPart(const caf::DisplayCoordTransform* displayCoordTransform) const; cvf::ref<cvf::Part> createProjectionMapPart(const caf::DisplayCoordTransform* displayCoordTransform) const;
std::vector<std::vector<cvf::ref<cvf::Drawable>>> createContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform) const; std::vector<std::vector<cvf::ref<cvf::Drawable>>> createContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform, const std::vector<std::vector<cvf::BoundingBox>>& labelBBoxes) const;
std::vector<cvf::ref<cvf::Drawable>> createContourLabels(const cvf::Camera* camera, const caf::DisplayCoordTransform* displayCoordTransform, std::vector<std::vector<cvf::BoundingBox>>* labelBBoxes) const;
cvf::ref<cvf::DrawableGeo> createPickPointVisDrawable(const caf::DisplayCoordTransform* displayCoordTransform) const; cvf::ref<cvf::DrawableGeo> createPickPointVisDrawable(const caf::DisplayCoordTransform* displayCoordTransform) const;
private: private:
caf::PdmPointer<RimContourMapProjection> m_contourMapProjection; caf::PdmPointer<RimContourMapProjection> m_contourMapProjection;
caf::PdmPointer<RimContourMapView> m_parentContourMap; caf::PdmPointer<RimContourMapView> m_parentContourMap;
std::vector<RimContourMapProjection::ContourPolygons> m_contourLinePolygons;
std::vector<cvf::Vec4d> m_contourMapTriangles;
std::vector<std::vector<cvf::BoundingBox>> m_labelBoundingBoxes;
}; };

View File

@@ -49,6 +49,7 @@ const cvf::Mat4d defaultViewMatrix(1, 0, 0, 0,
0, 0, 0, 1); 0, 0, 0, 1);
RimContourMapView::RimContourMapView() RimContourMapView::RimContourMapView()
: m_cameraPositionLastUpdate(cvf::Vec3d::UNDEFINED)
{ {
CAF_PDM_InitObject("Contour Map View", ":/2DMap16x16.png", "", ""); CAF_PDM_InitObject("Contour Map View", ":/2DMap16x16.png", "", "");
@@ -224,7 +225,9 @@ void RimContourMapView::updateGeometry()
appendWellsAndFracturesToModel(); appendWellsAndFracturesToModel();
createContourMapGeometry();
appendContourMapProjectionToModel(); appendContourMapProjectionToModel();
appendContourLinesToModel();
appendPickPointVisToModel(); appendPickPointVisToModel();
@@ -243,6 +246,17 @@ void RimContourMapView::setFaultVisParameters()
faultResultSettings()->customFaultResult()->setResultVariable("None"); faultResultSettings()->customFaultResult()->setResultVariable("None");
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimContourMapView::createContourMapGeometry()
{
if (m_viewer && m_contourMapProjection->isChecked())
{
m_contourMapProjectionPartMgr->createProjectionGeometry();
}
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -268,6 +282,31 @@ void RimContourMapView::appendContourMapProjectionToModel()
} }
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimContourMapView::appendContourLinesToModel()
{
if (m_viewer && m_contourMapProjection->isChecked())
{
cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep);
if (frameScene)
{
cvf::String name = "ContourMapLines";
this->removeModelByName(frameScene, name);
cvf::ref<cvf::ModelBasicList> contourMapLabelModelBasicList = new cvf::ModelBasicList;
contourMapLabelModelBasicList->setName(name);
cvf::ref<caf::DisplayCoordTransform> transForm = this->displayCoordTransform();
m_contourMapProjectionPartMgr->appendContourLinesToModel(viewer()->mainCamera(), contourMapLabelModelBasicList.p(), transForm.p());
contourMapLabelModelBasicList->updateBoundingBoxesRecursive();
frameScene->addModel(contourMapLabelModelBasicList.p());
}
}
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -414,3 +453,26 @@ QWidget* RimContourMapView::createViewWidget(QWidget* mainWindowParent)
} }
return widget; return widget;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimContourMapView::onViewNavigationChanged()
{
cvf::Vec3d currentCameraPosition = viewer()->mainCamera()->position();
if (m_cameraPositionLastUpdate.isUndefined() || zoomChangeAboveTreshold(currentCameraPosition))
{
appendContourLinesToModel();
m_cameraPositionLastUpdate = currentCameraPosition;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimContourMapView::zoomChangeAboveTreshold(const cvf::Vec3d& currentCameraPosition) const
{
double distance = std::max(std::fabs(m_cameraPositionLastUpdate.z()), std::fabs(currentCameraPosition.z()));
const double threshold = 0.01 * distance;
return (m_cameraPositionLastUpdate - currentCameraPosition).length() > threshold;
}

View File

@@ -43,7 +43,9 @@ protected:
void updateCurrentTimeStep() override; void updateCurrentTimeStep() override;
void updateGeometry(); void updateGeometry();
void setFaultVisParameters(); void setFaultVisParameters();
void createContourMapGeometry();
void appendContourMapProjectionToModel(); void appendContourMapProjectionToModel();
void appendContourLinesToModel();
void appendPickPointVisToModel(); void appendPickPointVisToModel();
void updateLegends() override; void updateLegends() override;
void updateViewWidgetAfterCreation() override; void updateViewWidgetAfterCreation() override;
@@ -57,10 +59,14 @@ protected:
QWidget* createViewWidget(QWidget* mainWindowParent) override; QWidget* createViewWidget(QWidget* mainWindowParent) override;
void onViewNavigationChanged() override;
bool zoomChangeAboveTreshold(const cvf::Vec3d& currentCameraPosition) const;
private: private:
cvf::ref<RivContourMapProjectionPartMgr> m_contourMapProjectionPartMgr; cvf::ref<RivContourMapProjectionPartMgr> m_contourMapProjectionPartMgr;
caf::PdmChildField<RimContourMapProjection*> m_contourMapProjection; caf::PdmChildField<RimContourMapProjection*> m_contourMapProjection;
caf::PdmField<bool> m_showAxisLines; caf::PdmField<bool> m_showAxisLines;
caf::PdmField<bool> m_showScaleLegend; caf::PdmField<bool> m_showScaleLegend;
cvf::Vec3d m_cameraPositionLastUpdate;
}; };

View File

@@ -155,6 +155,21 @@ RimMdiWindowGeometry RimViewWindow::mdiWindowGeometry()
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimViewWindow::viewNavigationChanged()
{
onViewNavigationChanged();
}
//--------------------------------------------------------------------------------------------------
/// Default implementation of virtual method to trigger updates on view navigation (zoom, camera move, etc)
//--------------------------------------------------------------------------------------------------
void RimViewWindow::onViewNavigationChanged()
{
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -207,7 +222,6 @@ void RimViewWindow::setAsMdiWindow(int mainWindowID)
} }
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------

View File

@@ -63,6 +63,8 @@ public:
virtual QImage snapshotWindowContent() = 0; virtual QImage snapshotWindowContent() = 0;
virtual void zoomAll() = 0; virtual void zoomAll() = 0;
void viewNavigationChanged();
protected: protected:
void removeMdiWindowFromMdiArea(); void removeMdiWindowFromMdiArea();
@@ -75,6 +77,7 @@ protected:
virtual void updateMdiWindowTitle(); // Has real default implementation virtual void updateMdiWindowTitle(); // Has real default implementation
virtual void deleteViewWidget() = 0; virtual void deleteViewWidget() = 0;
virtual void onLoadDataAndUpdate() = 0; virtual void onLoadDataAndUpdate() = 0;
virtual void onViewNavigationChanged();
virtual bool isWindowVisible() { return m_showWindow();} // Virtual To allow special visibility control virtual bool isWindowVisible() { return m_showWindow();} // Virtual To allow special visibility control
////////// //////////

View File

@@ -749,7 +749,7 @@ void RiuViewer::updateNavigationPolicy()
void RiuViewer::navigationPolicyUpdate() void RiuViewer::navigationPolicyUpdate()
{ {
caf::Viewer::navigationPolicyUpdate(); caf::Viewer::navigationPolicyUpdate();
ownerViewWindow()->viewNavigationChanged();
if (m_rimView) if (m_rimView)
{ {
RimViewLinker* viewLinker = m_rimView->assosiatedViewLinker(); RimViewLinker* viewLinker = m_rimView->assosiatedViewLinker();

View File

@@ -174,6 +174,7 @@ protected:
// Support the navigation policy concept // Support the navigation policy concept
virtual bool event( QEvent* e ); virtual bool event( QEvent* e );
cvf::ref<caf::NavigationPolicy> m_navigationPolicy; cvf::ref<caf::NavigationPolicy> m_navigationPolicy;
bool m_navigationPolicyEnabled; bool m_navigationPolicyEnabled;
@@ -196,7 +197,6 @@ private:
void removeModelFromAllFrames(cvf::Model* model); void removeModelFromAllFrames(cvf::Model* model);
void updateCamera(int width, int height); void updateCamera(int width, int height);
void releaseOGlResourcesForCurrentFrame(); void releaseOGlResourcesForCurrentFrame();
void debugShowRenderingSequencePartNames(); void debugShowRenderingSequencePartNames();

View File

@@ -189,14 +189,23 @@ void DrawableText::setUseDepthBuffer(bool useDepthBuffer)
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void DrawableText::addText(const String& text, const Vec3f& position) void DrawableText::addText(const String& text, const Vec3f& position, const Vec3f& direction)
{ {
m_positions.push_back(position); m_positions.push_back(position);
m_texts.push_back(text); m_texts.push_back(text);
m_boundingBox.add(position); m_directions.push_back(direction);
m_boundingBox.add(position);
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t DrawableText::numberOfTexts() const
{
return m_texts.size();
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Main shader based rendering path for the geometry /// Main shader based rendering path for the geometry
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -269,6 +278,28 @@ BoundingBox DrawableText::boundingBox() const
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::BoundingBox
DrawableText::textBoundingBox(const String& text, const Vec3f& position, const Vec3f& direction /*= Vec3f::X_AXIS*/)
{
ref<Glyph> glyph = m_font->getGlyph(L'A');
Vec2f textExtent(m_font->textExtent(text));
short verticalAlignment = TextDrawer::calculateVerticalAlignmentOffset(*m_font, m_verticalAlignment);
float glyphMarginX = 0.25f * static_cast<float>(glyph->width());
float glyphMarginY = 0.25f * static_cast<float>(glyph->height());
BoundingBox textBox;
std::array<Vec3f, 4> corners =
TextDrawer::textCorners(*glyph, cvf::Vec2f::ZERO, textExtent, verticalAlignment, direction, glyphMarginX, glyphMarginY);
for (const Vec3f& corner : corners)
{
textBox.add(position + corner);
}
return textBox;
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -293,7 +324,7 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr
CVF_ASSERT(!shaderProgram || ShaderProgram::supportedOpenGL(oglContext)); CVF_ASSERT(!shaderProgram || ShaderProgram::supportedOpenGL(oglContext));
if (m_texts.size() == 0) return; if (m_texts.size() == 0) return;
CVF_ASSERT(m_positions.size() == m_texts.size()); CVF_ASSERT(m_positions.size() == m_texts.size() && m_positions.size() == m_directions.size());
if (m_checkPosVisible) if (m_checkPosVisible)
{ {
@@ -342,6 +373,7 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr
Mat4d modelViewProjectionMatrix = Mat4d(matrixState.modelViewProjectionMatrix()); Mat4d modelViewProjectionMatrix = Mat4d(matrixState.modelViewProjectionMatrix());
std::vector<Vec3f> projCoords; std::vector<Vec3f> projCoords;
std::vector<String> textsToDraw; // Text strings to be drawn std::vector<String> textsToDraw; // Text strings to be drawn
std::vector<Vec3f> directions;
size_t pos; size_t pos;
for (pos = 0; pos < m_positions.size(); pos++) for (pos = 0; pos < m_positions.size(); pos++)
{ {
@@ -353,6 +385,7 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr
// Note: Need to adjust for the current viewport, as the coords returned from project are in global windows coordinates // Note: Need to adjust for the current viewport, as the coords returned from project are in global windows coordinates
projCoords.push_back(Vec3f(static_cast<float>(proj.x() - matrixState.viewportPosition().x()), static_cast<float>(proj.y() - matrixState.viewportPosition().y()), static_cast<float>(1.0 - 2.0*proj.z()))); // Map z into 1 .. -1 projCoords.push_back(Vec3f(static_cast<float>(proj.x() - matrixState.viewportPosition().x()), static_cast<float>(proj.y() - matrixState.viewportPosition().y()), static_cast<float>(1.0 - 2.0*proj.z()))); // Map z into 1 .. -1
textsToDraw.push_back(m_texts[pos]); textsToDraw.push_back(m_texts[pos]);
directions.push_back(m_directions[pos]);
} }
} }
@@ -389,7 +422,7 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr
for (i = 0; i < textsToDraw.size(); i++) for (i = 0; i < textsToDraw.size(); i++)
{ {
Vec3f pos = projCoords[i]; Vec3f pos = projCoords[i];
drawer.addText(textsToDraw[i], pos); drawer.addText(textsToDraw[i], pos, directions[i]);
} }
if (shaderProgram) if (shaderProgram)

View File

@@ -65,8 +65,8 @@ public:
void setFont(Font* font); void setFont(Font* font);
ref<Font> font() const; ref<Font> font() const;
void addText(const String& text, const Vec3f& position); void addText(const String& text, const Vec3f& position, const Vec3f& direction = Vec3f::X_AXIS);
size_t numberOfTexts() const;
void setVerticalAlignment(TextDrawer::Alignment alignment); void setVerticalAlignment(TextDrawer::Alignment alignment);
void setTextColor(const Color3f& color); void setTextColor(const Color3f& color);
void setBackgroundColor(const Color3f& color); void setBackgroundColor(const Color3f& color);
@@ -87,6 +87,7 @@ public:
virtual size_t faceCount() const; virtual size_t faceCount() const;
virtual BoundingBox boundingBox() const; virtual BoundingBox boundingBox() const;
BoundingBox textBoundingBox(const String& text, const Vec3f& position, const Vec3f& direction = Vec3f::X_AXIS);
virtual bool rayIntersectCreateDetail(const Ray& ray, Vec3d* intersectionPoint, ref<HitDetail>* hitDetail) const; virtual bool rayIntersectCreateDetail(const Ray& ray, Vec3d* intersectionPoint, ref<HitDetail>* hitDetail) const;
bool rayIntersect(const Ray& ray, const Camera& camera, Vec3d* intersectionPoint); bool rayIntersect(const Ray& ray, const Camera& camera, Vec3d* intersectionPoint);
@@ -103,6 +104,8 @@ private:
private: private:
std::vector<Vec3f> m_positions; // Coordinate of the lower left corner of where to place the text in pixel coordinates std::vector<Vec3f> m_positions; // Coordinate of the lower left corner of where to place the text in pixel coordinates
std::vector<String> m_texts; // Text strings to be drawn std::vector<String> m_texts; // Text strings to be drawn
std::vector<Vec3f> m_directions; // Text direction
ref<Font> m_font; // Font used to draw text ref<Font> m_font; // Font used to draw text
TextDrawer::Alignment m_verticalAlignment; TextDrawer::Alignment m_verticalAlignment;

View File

@@ -72,7 +72,9 @@ Glyph::Glyph(wchar_t character)
m_horizontalBearingY(0), m_horizontalBearingY(0),
m_horizontalAdvance(0), m_horizontalAdvance(0),
m_textureImage(new TextureImage), m_textureImage(new TextureImage),
m_textureCoordinates(new FloatArray(8)) m_textureCoordinates(new FloatArray(8)),
m_minFilter(NEAREST),
m_magFilter(NEAREST)
{ {
// Lower left // Lower left
m_textureCoordinates->set(0, 0.0f); m_textureCoordinates->set(0, 0.0f);
@@ -345,8 +347,23 @@ void Glyph::setupAndBindTexture(OpenGLContext* oglContext, bool software)
// Use fixed function texture setup // Use fixed function texture setup
ref<Texture2D_FF> texture = new Texture2D_FF(m_textureImage.p()); ref<Texture2D_FF> texture = new Texture2D_FF(m_textureImage.p());
texture->setWrapMode(Texture2D_FF::CLAMP); texture->setWrapMode(Texture2D_FF::CLAMP);
texture->setMinFilter(Texture2D_FF::NEAREST); if (m_minFilter == NEAREST)
texture->setMagFilter(Texture2D_FF::NEAREST); {
texture->setMinFilter(Texture2D_FF::NEAREST);
}
else
{
texture->setMinFilter(Texture2D_FF::LINEAR);
}
if (m_magFilter == NEAREST)
{
texture->setMagFilter(Texture2D_FF::NEAREST);
}
else
{
texture->setMagFilter(Texture2D_FF::LINEAR);
}
ref<RenderStateTextureMapping_FF> textureMapping = new RenderStateTextureMapping_FF(texture.p()); ref<RenderStateTextureMapping_FF> textureMapping = new RenderStateTextureMapping_FF(texture.p());
textureMapping->setTextureFunction(RenderStateTextureMapping_FF::MODULATE); textureMapping->setTextureFunction(RenderStateTextureMapping_FF::MODULATE);
@@ -359,8 +376,23 @@ void Glyph::setupAndBindTexture(OpenGLContext* oglContext, bool software)
{ {
ref<Sampler> sampler = new Sampler; ref<Sampler> sampler = new Sampler;
sampler->setWrapMode(Sampler::CLAMP_TO_EDGE); sampler->setWrapMode(Sampler::CLAMP_TO_EDGE);
sampler->setMinFilter(Sampler::NEAREST); if (m_minFilter == NEAREST)
sampler->setMagFilter(Sampler::NEAREST); {
sampler->setMinFilter(Sampler::NEAREST);
}
else
{
sampler->setMinFilter(Sampler::LINEAR);
}
if (m_magFilter == NEAREST)
{
sampler->setMagFilter(Sampler::NEAREST);
}
else
{
sampler->setMagFilter(Sampler::LINEAR);
}
ref<Texture> texture = new Texture(m_textureImage.p()); ref<Texture> texture = new Texture(m_textureImage.p());
@@ -377,4 +409,20 @@ void Glyph::setupAndBindTexture(OpenGLContext* oglContext, bool software)
} }
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void Glyph::setMinFilter(TextureFilter filter)
{
m_minFilter = filter;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void Glyph::setMagFilter(TextureFilter filter)
{
m_magFilter = filter;
}
} // namespace cvf } // namespace cvf

View File

@@ -55,6 +55,12 @@ class OpenGLContext;
class Glyph : public Object class Glyph : public Object
{ {
public: public:
enum TextureFilter
{
NEAREST,
LINEAR
};
Glyph(wchar_t character); Glyph(wchar_t character);
virtual ~Glyph(); virtual ~Glyph();
@@ -78,6 +84,9 @@ public:
void setupAndBindTexture(OpenGLContext* oglContext, bool software); void setupAndBindTexture(OpenGLContext* oglContext, bool software);
void setMinFilter(TextureFilter filter);
void setMagFilter(TextureFilter filter);
private: private:
wchar_t m_character; // Character this glyph is generated from wchar_t m_character; // Character this glyph is generated from
@@ -95,6 +104,10 @@ private:
ref<TextureImage> m_textureImage; // Pre-rendered image of m_character ref<TextureImage> m_textureImage; // Pre-rendered image of m_character
ref<FloatArray> m_textureCoordinates; // Texture coordinates of where in the m_texgtureImage to find the given pre-rendered character ref<FloatArray> m_textureCoordinates; // Texture coordinates of where in the m_texgtureImage to find the given pre-rendered character
ref<RenderState> m_textureBindings; // For shader based rendering this is a TextureBindings object, while software rendering uses RenderStateTextureMapping_FF instead ref<RenderState> m_textureBindings; // For shader based rendering this is a TextureBindings object, while software rendering uses RenderStateTextureMapping_FF instead
// Texture filter options
TextureFilter m_minFilter;
TextureFilter m_magFilter;
}; };
} // namespace cvf } // namespace cvf

View File

@@ -99,13 +99,14 @@ TextDrawer::~TextDrawer()
// -------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------
/// Add text to be drawn /// Add text to be drawn
// -------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------
void TextDrawer::addText(const String& text, const Vec2f& pos) void TextDrawer::addText(const String& text, const Vec2f& pos, const Vec2f& dir)
{ {
CVF_ASSERT(!text.isEmpty()); CVF_ASSERT(!text.isEmpty());
CVF_ASSERT(!pos.isUndefined()); CVF_ASSERT(!pos.isUndefined());
m_texts.push_back(text); m_texts.push_back(text);
m_positions.push_back(Vec3f(pos)); m_positions.push_back(Vec3f(pos));
m_directions.push_back(Vec3f(dir));
} }
@@ -115,13 +116,14 @@ void TextDrawer::addText(const String& text, const Vec2f& pos)
/// Note: The Z coordinate needs to correspond with the orthographic projection that is setup /// Note: The Z coordinate needs to correspond with the orthographic projection that is setup
/// to render the text. So the range should be <1..-1> with 1 being closest to the near plane. /// to render the text. So the range should be <1..-1> with 1 being closest to the near plane.
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void TextDrawer::addText(const String& text, const Vec3f& pos) void TextDrawer::addText(const String& text, const Vec3f& pos, const Vec3f& dir)
{ {
CVF_ASSERT(!text.isEmpty()); CVF_ASSERT(!text.isEmpty());
CVF_ASSERT(!pos.isUndefined()); CVF_ASSERT(!pos.isUndefined());
m_texts.push_back(text); m_texts.push_back(text);
m_positions.push_back(pos); m_positions.push_back(pos);
m_directions.push_back(dir);
} }
@@ -132,6 +134,7 @@ void TextDrawer::removeAllTexts()
{ {
m_texts.clear(); m_texts.clear();
m_positions.clear(); m_positions.clear();
m_directions.clear();
} }
@@ -170,44 +173,7 @@ void TextDrawer::setVerticalAlignment(TextDrawer::Alignment alignment)
CVF_ASSERT(m_font.notNull()); CVF_ASSERT(m_font.notNull());
CVF_ASSERT(!m_font->isEmpty()); CVF_ASSERT(!m_font->isEmpty());
switch (alignment) m_verticalAlignment = calculateVerticalAlignmentOffset(*m_font, alignment);
{
case TextDrawer::TOP:
{
// Character assumed to reach all the way up
ref<Glyph> glyph_top = m_font->getGlyph(L'`');
m_verticalAlignment = static_cast<short>(-glyph_top->horizontalBearingY());
break;
}
case TextDrawer::CENTER:
{
// Center around A
ref<Glyph> glyph_top = m_font->getGlyph(L'A');
m_verticalAlignment = static_cast<short>(-((glyph_top->horizontalBearingY() + 1) >> 1));
break;
}
case TextDrawer::BASELINE:
{
m_verticalAlignment = 0;
break;
}
case TextDrawer::BOTTOM:
{
// Character assumed to reach all the way down
ref<Glyph> glyph_bottom = m_font->getGlyph(L'g');
m_verticalAlignment = static_cast<short>(static_cast<short>(glyph_bottom->height()) + glyph_bottom->horizontalBearingY());
break;
}
default:
{
CVF_FAIL_MSG("Unsupported alignment type");
break;
}
}
} }
@@ -307,7 +273,7 @@ void TextDrawer::renderSoftware(OpenGLContext* oglContext, const MatrixState& ma
void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrixState, bool softwareRendering) void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrixState, bool softwareRendering)
{ {
CVF_CALLSITE_OPENGL(oglContext); CVF_CALLSITE_OPENGL(oglContext);
CVF_ASSERT(m_positions.size() == m_texts.size()); CVF_ASSERT(m_positions.size() == m_texts.size() && m_positions.size() == m_directions.size());
static const ushort connects[] = { 0, 1, 2, 0, 2, 3 }; static const ushort connects[] = { 0, 1, 2, 0, 2, 3 };
static const ushort lineConnects[] = { 0, 1, 1, 2, 2, 3, 3, 0 }; static const ushort lineConnects[] = { 0, 1, 1, 2, 2, 3, 3, 0 };
@@ -315,11 +281,11 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
float vertexArray[12]; float vertexArray[12];
float textureCoords[8]; // Will be updated for each glyph float textureCoords[8]; // Will be updated for each glyph
float* v1 = &vertexArray[0]; std::array<float*, 4> vertices = { &vertexArray[0], &vertexArray[3], &vertexArray[6], &vertexArray[9] };
float* v2 = &vertexArray[3]; for (size_t i = 0; i < vertices.size(); ++i)
float* v3 = &vertexArray[6]; {
float* v4 = &vertexArray[9]; vertices[i][2] = 0.0f;
v1[2] = v2[2] = v3[2] = v4[2] = 0.0f; }
// Prepare 2D pixel exact projection to draw texts // Prepare 2D pixel exact projection to draw texts
Camera projCam; Camera projCam;
@@ -374,7 +340,7 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
// Use a fixed line spacing // Use a fixed line spacing
float lineSpacing = m_font->lineSpacing(); float lineSpacing = m_font->lineSpacing();
Vec2f offset(0,0); Vec2f offset(0, 0);
// Render background and border // Render background and border
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@@ -401,27 +367,24 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
// Figure out margin // Figure out margin
ref<Glyph> glyph = m_font->getGlyph(L'A'); ref<Glyph> glyph = m_font->getGlyph(L'A');
float charHeight = static_cast<float>(glyph->height()); float glyphMarginX = cvf::Math::floor(0.5f * static_cast<float>(glyph->width()));
float charWidth = static_cast<float>(glyph->width()); float glyphMarginY = cvf::Math::floor(0.5f * static_cast<float>(glyph->height()));
offset.x() = cvf::Math::floor(charWidth/2.0f);
offset.y() = cvf::Math::floor(charHeight/2.0f);
size_t numTexts = m_texts.size(); size_t numTexts = m_texts.size();
for (size_t i = 0; i < numTexts; i++) for (size_t i = 0; i < numTexts; i++)
{ {
Vec3f pos = m_positions[i]; Vec3f pos = m_positions[i];
String text = m_texts[i]; String text = m_texts[i];
Vec2ui textExtent = m_font->textExtent(text); Vec2f textExtent(m_font->textExtent(text));
std::array<Vec3f, 4> corners = textCorners(*glyph, cvf::Vec2f::ZERO, textExtent, m_verticalAlignment, m_directions[i], glyphMarginX, glyphMarginY);
Vec3f min = pos;//Vec3f(textBB.min()); for (size_t v = 0; v < vertices.size(); ++v)
Vec3f max = Vec3f(min.x() + static_cast<float>(textExtent.x()) + offset.x()*2.0f, min.y() + static_cast<float>(textExtent.y()) + offset.y()*2.0f, 0.0f); {
for (int c = 0; c < 3; ++c)
// Draw the background triangle {
v1[0] = min.x(); v1[1] = min.y(); v1[2] = pos.z(); vertices[v][c] = pos[c] + corners[v][c];
v2[0] = max.x(); v2[1] = min.y(); v2[2] = pos.z(); }
v3[0] = max.x(); v3[1] = max.y(); v3[2] = pos.z(); }
v4[0] = min.x(); v4[1] = max.y(); v4[2] = pos.z();
if (m_drawBackground) if (m_drawBackground)
{ {
@@ -432,10 +395,10 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
glColor3fv(m_backgroundColor.ptr()); glColor3fv(m_backgroundColor.ptr());
glBegin(GL_TRIANGLE_FAN); glBegin(GL_TRIANGLE_FAN);
glVertex3fv(v1); for (size_t v = 0; v < vertices.size(); ++v)
glVertex3fv(v2); {
glVertex3fv(v3); glVertex3fv(vertices[v]);
glVertex3fv(v4); }
glEnd(); glEnd();
#endif #endif
} }
@@ -456,10 +419,10 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
#ifndef CVF_OPENGL_ES #ifndef CVF_OPENGL_ES
glColor3fv(m_borderColor.ptr()); glColor3fv(m_borderColor.ptr());
glBegin(GL_LINE_LOOP); glBegin(GL_LINE_LOOP);
glVertex3fv(v1); for (size_t v = 0; v < vertices.size(); ++v)
glVertex3fv(v2); {
glVertex3fv(v3); glVertex3fv(vertices[v]);
glVertex3fv(v4); }
glEnd(); glEnd();
#endif #endif
} }
@@ -523,16 +486,16 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
size_t i, j; size_t i, j;
for (i = 0; i < numTexts; i++) for (i = 0; i < numTexts; i++)
{ {
Vec3f pos = m_positions[i]; Vec3f pos = m_positions[i];
Vec3f textDir = m_directions[i];
String text = m_texts[i]; String text = m_texts[i];
// Need to round off to integer positions to avoid buggy text drawing on iPad2 // Need to round off to integer positions to avoid buggy text drawing on iPad2
pos.x() = cvf::Math::floor(pos.x()); pos.x() = cvf::Math::floor(pos.x());
pos.y() = cvf::Math::floor(pos.y()); pos.y() = cvf::Math::floor(pos.y());
// Cursor incrementor // Cursor incrementor
Vec2f cursor(pos); Vec2f cursor(Vec2f::ZERO);
cursor += offset; cursor += offset;
std::vector<cvf::String> lines = text.split("\n"); std::vector<cvf::String> lines = text.split("\n");
@@ -547,30 +510,27 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
{ {
character = line[j]; character = line[j];
ref<Glyph> glyph = m_font->getGlyph(character); ref<Glyph> glyph = m_font->getGlyph(character);
cvf::Vec2f glyphExtent(static_cast<float>(glyph->width()), static_cast<float>(glyph->height()));
std::array<Vec3f, 4> corners = textCorners(*glyph, cursor, glyphExtent, m_verticalAlignment, textDir);
float textureWidth = static_cast<float>(glyph->width()); for (size_t v = 0; v < vertices.size(); ++v)
float textureHeight = static_cast<float>(glyph->height()); {
for (int c = 0; c < 3; ++c)
// Lower left corner {
v1[0] = cursor.x() + static_cast<float>(glyph->horizontalBearingX()); vertices[v][c] = pos[c] + corners[v][c];
v1[1] = cursor.y() + static_cast<float>(glyph->horizontalBearingY()) - textureHeight + static_cast<float>(m_verticalAlignment); }
v1[2] = pos.z(); }
if (textDir.dot(cvf::Vec3f::X_AXIS) < 0.9 && textDir.dot(cvf::Vec3f::Y_AXIS) < 0.9)
// Lower right corner {
v2[0] = v1[0] + textureWidth; glyph->setMinFilter(Glyph::LINEAR);
v2[1] = v1[1]; glyph->setMagFilter(Glyph::LINEAR);
v2[2] = pos.z(); }
else
// Upper right corner {
v3[0] = v2[0]; glyph->setMinFilter(Glyph::NEAREST);
v3[1] = v1[1] + textureHeight; glyph->setMagFilter(Glyph::NEAREST);
v3[2] = pos.z(); }
// Upper left corner
v4[0] = v1[0];
v4[1] = v3[1];
v4[2] = pos.z();
glyph->setupAndBindTexture(oglContext, softwareRendering); glyph->setupAndBindTexture(oglContext, softwareRendering);
// Get texture coordinates // Get texture coordinates
@@ -592,19 +552,19 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
// First triangle in quad // First triangle in quad
glTexCoord2fv(&textureCoordinatesPtr[0]); glTexCoord2fv(&textureCoordinatesPtr[0]);
glVertex3fv(v1); glVertex3fv(vertices[0]);
glTexCoord2fv(&textureCoordinatesPtr[2]); glTexCoord2fv(&textureCoordinatesPtr[2]);
glVertex3fv(v2); glVertex3fv(vertices[1]);
glTexCoord2fv(&textureCoordinatesPtr[4]); glTexCoord2fv(&textureCoordinatesPtr[4]);
glVertex3fv(v3); glVertex3fv(vertices[2]);
// Second triangle in quad // Second triangle in quad
glTexCoord2fv(&textureCoordinatesPtr[0]); glTexCoord2fv(&textureCoordinatesPtr[0]);
glVertex3fv(v1); glVertex3fv(vertices[0]);
glTexCoord2fv(&textureCoordinatesPtr[4]); glTexCoord2fv(&textureCoordinatesPtr[4]);
glVertex3fv(v3); glVertex3fv(vertices[2]);
glTexCoord2fv(&textureCoordinatesPtr[6]); glTexCoord2fv(&textureCoordinatesPtr[6]);
glVertex3fv(v4); glVertex3fv(vertices[3]);
glEnd(); glEnd();
#endif #endif
@@ -623,7 +583,7 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
} }
// CR // CR
cursor.x() = pos.x() + offset.x(); cursor.x() = offset.x();
cursor.y() += lineSpacing; cursor.y() += lineSpacing;
} }
} }
@@ -693,4 +653,75 @@ bool TextDrawer::pickText(const Vec3f& pickCoord2d, const String& text, const Ve
return false; return false;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
short TextDrawer::calculateVerticalAlignmentOffset(Font& font, Alignment alignment)
{
switch (alignment)
{
case TextDrawer::TOP:
{
// Character assumed to reach all the way up
ref<Glyph> glyph_top = font.getGlyph(L'`');
return static_cast<short>(-glyph_top->horizontalBearingY());
}
case TextDrawer::CENTER:
{
// Center around A
ref<Glyph> glyph_top = font.getGlyph(L'A');
return static_cast<short>(-((glyph_top->horizontalBearingY() + 1) >> 1));
}
case TextDrawer::BASELINE:
{
return 0;
}
case TextDrawer::BOTTOM:
{
// Character assumed to reach all the way down
ref<Glyph> glyph_bottom = font.getGlyph(L'g');
return static_cast<short>(static_cast<short>(glyph_bottom->height()) + glyph_bottom->horizontalBearingY());
}
default:
{
CVF_FAIL_MSG("Unsupported alignment type");
break;
}
}
return 0;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::array<cvf::Vec3f, 4>
TextDrawer::textCorners(const Glyph& glyph, const Vec2f& textStart, const Vec2f& textExtent, short verticalAlignment, const Vec3f& textDirection, float marginX, float marginY)
{
Vec3f tangent = textDirection;
if (tangent.x() < 0.0f) tangent *= -1.0f;
Vec2f tan2d(tangent.x(), tangent.y());
Vec3f normal(-tan2d.perpendicularVector(), tangent.z());
float x1 = textStart.x() + static_cast<float>(glyph.horizontalBearingX()) - marginY;
float y1 = textStart.y() + static_cast<float>(glyph.horizontalBearingY()) - static_cast<float>(glyph.height()) + static_cast<float>(verticalAlignment) - marginY;
float x2 = x1 + textExtent.x() + 2.0f * marginX;
float y2 = y1 + textExtent.y() + 2.0f * marginY;
// Lower left corner
Vec3f c1 = tangent * x1 + normal * y1;
// Lower right corner
Vec3f c2 = tangent * x2 + normal * y1;
// Upper right corner
Vec3f c3 = tangent * x2 + normal * y2;
// Upper left corner
Vec3f c4 = tangent * x1 + normal * y2;
return { c1, c2, c3, c4 };
}
} // namespace cvf } // namespace cvf

View File

@@ -39,12 +39,15 @@
#include "cvfObject.h" #include "cvfObject.h"
#include "cvfString.h" #include "cvfString.h"
#include "cvfVector2.h"
#include "cvfVector3.h" #include "cvfVector3.h"
#include "cvfColor3.h" #include "cvfColor3.h"
#include <array>
namespace cvf { namespace cvf {
class Glyph;
class Font; class Font;
class ShaderProgram; class ShaderProgram;
class MatrixState; class MatrixState;
@@ -72,8 +75,8 @@ public:
TextDrawer(Font* font); TextDrawer(Font* font);
virtual ~TextDrawer(); virtual ~TextDrawer();
void addText(const String& text, const Vec2f& pos); void addText(const String& text, const Vec2f& pos, const Vec2f& dir = Vec2f::X_AXIS);
void addText(const String& text, const Vec3f& pos); void addText(const String& text, const Vec3f& pos, const Vec3f& dir = Vec3f::X_AXIS);
void removeAllTexts(); void removeAllTexts();
void setVerticalAlignment(Alignment alignment); void setVerticalAlignment(Alignment alignment);
@@ -96,7 +99,10 @@ public:
void renderSoftware(OpenGLContext* oglContext, const MatrixState& matrixState); void renderSoftware(OpenGLContext* oglContext, const MatrixState& matrixState);
static bool pickText(const Vec3f& pickCoord2d, const String& text, const Vec3f& pos, Font* font); static bool pickText(const Vec3f& pickCoord2d, const String& text, const Vec3f& pos, Font* font);
static short calculateVerticalAlignmentOffset(Font& font, Alignment alignment);
static std::array<Vec3f, 4> textCorners(const Glyph& glyph, const Vec2f& textStart, const Vec2f& textExtent, short verticalAlignment, const Vec3f& textDirection, float marginX = 0.0, float marginY = 0.0);
private: private:
void doRender2d(OpenGLContext* oglContext, const MatrixState& matrixState, bool softwareRendering); void doRender2d(OpenGLContext* oglContext, const MatrixState& matrixState, bool softwareRendering);
@@ -104,6 +110,7 @@ private:
ref<Font> m_font; // Font used to draw text ref<Font> m_font; // Font used to draw text
std::vector<Vec3f> m_positions; // Coordinate of the lower left corner of where to place each individual text strings std::vector<Vec3f> m_positions; // Coordinate of the lower left corner of where to place each individual text strings
std::vector<String> m_texts; // Text strings to be drawn std::vector<String> m_texts; // Text strings to be drawn
std::vector<Vec3f> m_directions; // Clockwise rotations around the position in radians
bool m_drawBackground; bool m_drawBackground;
bool m_drawBorder; bool m_drawBorder;