mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
#3876 Implement rotated labels on contour maps
This commit is contained in:
@@ -3,14 +3,17 @@
|
||||
#include "RiaColorTools.h"
|
||||
#include "RiaFontCache.h"
|
||||
#include "RiaWeightedMeanCalculator.h"
|
||||
#include "RigCellGeometryTools.h"
|
||||
#include "RivMeshLinesSourceInfo.h"
|
||||
#include "RivScalarMapperUtils.h"
|
||||
#include "RivPartPriority.h"
|
||||
|
||||
#include "RimContourMapView.h"
|
||||
#include "RimContourMapProjection.h"
|
||||
|
||||
#include "cafEffectGenerator.h"
|
||||
|
||||
#include "cvfCamera.h"
|
||||
#include "cvfDrawableText.h"
|
||||
#include "cvfGeometryBuilderFaceList.h"
|
||||
#include "cvfGeometryUtils.h"
|
||||
@@ -18,6 +21,7 @@
|
||||
#include "cvfPart.h"
|
||||
#include "cvfPrimitiveSetIndexedUInt.h"
|
||||
#include "cvfScalarMapper.h"
|
||||
#include "cvfRay.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
@@ -30,52 +34,26 @@ RivContourMapProjectionPartMgr::RivContourMapProjectionPartMgr(RimContourMapProj
|
||||
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
|
||||
{
|
||||
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);
|
||||
if (mapPart.notNull())
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
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();
|
||||
labelDrawable->setFont(font.p());
|
||||
labelDrawable->setCheckPosVisible(true);
|
||||
labelDrawable->setCheckPosVisible(false);
|
||||
labelDrawable->setUseDepthBuffer(true);
|
||||
labelDrawable->setDrawBorder(false);
|
||||
labelDrawable->setDrawBackground(false);
|
||||
labelDrawable->setBackgroundColor(backgroundColor);
|
||||
labelDrawable->setVerticalAlignment(cvf::TextDrawer::BASELINE);
|
||||
labelDrawable->setVerticalAlignment(cvf::TextDrawer::CENTER);
|
||||
labelDrawable->setTextColor(textColor);
|
||||
labelDrawable->setBorderColor(textColor);
|
||||
|
||||
return labelDrawable;
|
||||
}
|
||||
@@ -152,7 +195,7 @@ cvf::ref<cvf::DrawableText> RivContourMapProjectionPartMgr::createTextLabel(cons
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
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)
|
||||
{
|
||||
return cvf::ref<cvf::Part>();
|
||||
@@ -192,59 +235,99 @@ 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();
|
||||
std::vector<double> tickValues;
|
||||
mapper->majorTickValues(&tickValues);
|
||||
|
||||
std::vector<std::vector<cvf::ref<cvf::Drawable>>> contourDrawablesForAllLevels;
|
||||
std::vector<cvf::ref<cvf::Drawable>> labelDrawables;
|
||||
for (int64_t i = (int64_t) contourPolygons.size() - 1; i > 0; --i)
|
||||
contourDrawablesForAllLevels.resize(tickValues.size());
|
||||
|
||||
for (size_t i = 1; i < m_contourLinePolygons.size(); ++i)
|
||||
{
|
||||
std::vector<cvf::ref<cvf::Drawable>> contourDrawables;
|
||||
|
||||
cvf::Color3f backgroundColor(mapper->mapToColor(tickValues[i]));
|
||||
cvf::Color3f textColor = RiaColorTools::contrastColor(backgroundColor);
|
||||
for (size_t j = 0; j < m_contourLinePolygons[i].size(); ++j)
|
||||
{
|
||||
if (m_contourLinePolygons[i][j].vertices.empty()) continue;
|
||||
|
||||
for (size_t j = 0; j < contourPolygons[i].size(); ++j)
|
||||
{
|
||||
if (contourPolygons[i][j].vertices.empty()) continue;
|
||||
cvf::String labelText(m_contourLinePolygons[i][j].value);
|
||||
|
||||
size_t nVertices = contourPolygons[i][j].vertices.size();
|
||||
size_t nLabels = m_contourMapProjection->showContourLabels() ? std::max((size_t)1, nVertices / 100u) : 0u;
|
||||
for (size_t l = 0; l < nLabels; ++l)
|
||||
{
|
||||
cvf::ref<cvf::DrawableText> label = createTextLabel(textColor, backgroundColor);
|
||||
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);
|
||||
size_t nVertices = m_contourLinePolygons[i][j].vertices.size();
|
||||
|
||||
std::vector<cvf::Vec3f> displayLines; displayLines.reserve(nVertices * 2);
|
||||
for (size_t v = 0; v < nVertices; ++v)
|
||||
{
|
||||
cvf::Vec3d globalVertex = contourPolygons[i][j].vertices[v] + m_contourMapProjection->origin3d();
|
||||
cvf::Vec3d displayVertex1 = displayCoordTransform->transformToDisplayCoord(globalVertex);
|
||||
(*vertexArray)[v] = cvf::Vec3f(displayVertex1);
|
||||
cvf::Vec3d globalVertex1 = m_contourLinePolygons[i][j].vertices[v] + m_contourMapProjection->origin3d();
|
||||
cvf::Vec3d displayVertex1 = displayCoordTransform->transformToDisplayCoord(globalVertex1);
|
||||
|
||||
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;
|
||||
indices.reserve(vertexArray->size());
|
||||
@@ -253,7 +336,7 @@ std::vector<std::vector<cvf::ref<cvf::Drawable>>> RivContourMapProjectionPartMgr
|
||||
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);
|
||||
indexedUInt->setIndices(indexArray.p());
|
||||
|
||||
@@ -263,17 +346,89 @@ std::vector<std::vector<cvf::ref<cvf::Drawable>>> RivContourMapProjectionPartMgr
|
||||
geo->setVertexArray(vertexArray.p());
|
||||
contourDrawables.push_back(geo);
|
||||
}
|
||||
for (cvf::ref<cvf::Drawable> labelDrawable : labelDrawables)
|
||||
{
|
||||
contourDrawables.push_back(labelDrawable);
|
||||
contourDrawablesForAllLevels[i] = contourDrawables;
|
||||
}
|
||||
|
||||
contourDrawablesForAllLevels.push_back(contourDrawables);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RimContourMapProjection.h"
|
||||
|
||||
#include "cafPdmPointer.h"
|
||||
#include "cafDisplayCoordTransform.h"
|
||||
|
||||
@@ -26,29 +28,37 @@
|
||||
#include "cvfDrawableText.h"
|
||||
#include "cvfModelBasicList.h"
|
||||
#include "cvfObject.h"
|
||||
#include "cvfVector4.h"
|
||||
|
||||
class RimContourMapView;
|
||||
class RimContourMapProjection;
|
||||
|
||||
class RivContourMapProjectionPartMgr : public cvf::Object
|
||||
{
|
||||
public:
|
||||
RivContourMapProjectionPartMgr(RimContourMapProjection* contourMapProjection, RimContourMapView* contourMap);
|
||||
|
||||
void createProjectionGeometry();
|
||||
void appendProjectionToModel(cvf::ModelBasicList* model,
|
||||
const caf::DisplayCoordTransform* displayCoordTransform) const;
|
||||
void appendContourLinesToModel(const cvf::Camera* camera, cvf::ModelBasicList* model, const caf::DisplayCoordTransform* displayCoordTransform) const;
|
||||
void appendPickPointVisToModel(cvf::ModelBasicList* model,
|
||||
const caf::DisplayCoordTransform* displayCoordTransform) const;
|
||||
|
||||
cvf::ref<cvf::Vec2fArray> createTextureCoords(const std::vector<double>& values) const;
|
||||
|
||||
|
||||
private:
|
||||
static cvf::ref<cvf::DrawableText> createTextLabel(const cvf::Color3f& textColor, const cvf::Color3f& backgroundColor);
|
||||
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;
|
||||
private:
|
||||
caf::PdmPointer<RimContourMapProjection> m_contourMapProjection;
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ const cvf::Mat4d defaultViewMatrix(1, 0, 0, 0,
|
||||
0, 0, 0, 1);
|
||||
|
||||
RimContourMapView::RimContourMapView()
|
||||
: m_cameraPositionLastUpdate(cvf::Vec3d::UNDEFINED)
|
||||
{
|
||||
CAF_PDM_InitObject("Contour Map View", ":/2DMap16x16.png", "", "");
|
||||
|
||||
@@ -224,7 +225,9 @@ void RimContourMapView::updateGeometry()
|
||||
|
||||
appendWellsAndFracturesToModel();
|
||||
|
||||
createContourMapGeometry();
|
||||
appendContourMapProjectionToModel();
|
||||
appendContourLinesToModel();
|
||||
|
||||
appendPickPointVisToModel();
|
||||
|
||||
@@ -243,6 +246,17 @@ void RimContourMapView::setFaultVisParameters()
|
||||
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;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,9 @@ protected:
|
||||
void updateCurrentTimeStep() override;
|
||||
void updateGeometry();
|
||||
void setFaultVisParameters();
|
||||
void createContourMapGeometry();
|
||||
void appendContourMapProjectionToModel();
|
||||
void appendContourLinesToModel();
|
||||
void appendPickPointVisToModel();
|
||||
void updateLegends() override;
|
||||
void updateViewWidgetAfterCreation() override;
|
||||
@@ -57,10 +59,14 @@ protected:
|
||||
|
||||
QWidget* createViewWidget(QWidget* mainWindowParent) override;
|
||||
|
||||
void onViewNavigationChanged() override;
|
||||
|
||||
bool zoomChangeAboveTreshold(const cvf::Vec3d& currentCameraPosition) const;
|
||||
private:
|
||||
cvf::ref<RivContourMapProjectionPartMgr> m_contourMapProjectionPartMgr;
|
||||
caf::PdmChildField<RimContourMapProjection*> m_contourMapProjection;
|
||||
caf::PdmField<bool> m_showAxisLines;
|
||||
caf::PdmField<bool> m_showScaleLegend;
|
||||
cvf::Vec3d m_cameraPositionLastUpdate;
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -63,6 +63,8 @@ public:
|
||||
virtual QImage snapshotWindowContent() = 0;
|
||||
virtual void zoomAll() = 0;
|
||||
|
||||
void viewNavigationChanged();
|
||||
|
||||
protected:
|
||||
void removeMdiWindowFromMdiArea();
|
||||
|
||||
@@ -75,6 +77,7 @@ protected:
|
||||
virtual void updateMdiWindowTitle(); // Has real default implementation
|
||||
virtual void deleteViewWidget() = 0;
|
||||
virtual void onLoadDataAndUpdate() = 0;
|
||||
virtual void onViewNavigationChanged();
|
||||
virtual bool isWindowVisible() { return m_showWindow();} // Virtual To allow special visibility control
|
||||
//////////
|
||||
|
||||
|
||||
@@ -749,7 +749,7 @@ void RiuViewer::updateNavigationPolicy()
|
||||
void RiuViewer::navigationPolicyUpdate()
|
||||
{
|
||||
caf::Viewer::navigationPolicyUpdate();
|
||||
|
||||
ownerViewWindow()->viewNavigationChanged();
|
||||
if (m_rimView)
|
||||
{
|
||||
RimViewLinker* viewLinker = m_rimView->assosiatedViewLinker();
|
||||
|
||||
@@ -174,6 +174,7 @@ protected:
|
||||
|
||||
// Support the navigation policy concept
|
||||
virtual bool event( QEvent* e );
|
||||
|
||||
cvf::ref<caf::NavigationPolicy> m_navigationPolicy;
|
||||
bool m_navigationPolicyEnabled;
|
||||
|
||||
@@ -196,7 +197,6 @@ private:
|
||||
void removeModelFromAllFrames(cvf::Model* model);
|
||||
|
||||
void updateCamera(int width, int height);
|
||||
|
||||
void releaseOGlResourcesForCurrentFrame();
|
||||
void debugShowRenderingSequencePartNames();
|
||||
|
||||
|
||||
@@ -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_texts.push_back(text);
|
||||
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
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -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));
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -342,6 +373,7 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr
|
||||
Mat4d modelViewProjectionMatrix = Mat4d(matrixState.modelViewProjectionMatrix());
|
||||
std::vector<Vec3f> projCoords;
|
||||
std::vector<String> textsToDraw; // Text strings to be drawn
|
||||
std::vector<Vec3f> directions;
|
||||
size_t 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
|
||||
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]);
|
||||
directions.push_back(m_directions[pos]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,7 +422,7 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr
|
||||
for (i = 0; i < textsToDraw.size(); i++)
|
||||
{
|
||||
Vec3f pos = projCoords[i];
|
||||
drawer.addText(textsToDraw[i], pos);
|
||||
drawer.addText(textsToDraw[i], pos, directions[i]);
|
||||
}
|
||||
|
||||
if (shaderProgram)
|
||||
|
||||
@@ -65,8 +65,8 @@ public:
|
||||
void setFont(Font* font);
|
||||
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 setTextColor(const Color3f& color);
|
||||
void setBackgroundColor(const Color3f& color);
|
||||
@@ -87,6 +87,7 @@ public:
|
||||
virtual size_t faceCount() 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;
|
||||
bool rayIntersect(const Ray& ray, const Camera& camera, Vec3d* intersectionPoint);
|
||||
@@ -103,6 +104,8 @@ private:
|
||||
private:
|
||||
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<Vec3f> m_directions; // Text direction
|
||||
|
||||
ref<Font> m_font; // Font used to draw text
|
||||
|
||||
TextDrawer::Alignment m_verticalAlignment;
|
||||
|
||||
@@ -72,7 +72,9 @@ Glyph::Glyph(wchar_t character)
|
||||
m_horizontalBearingY(0),
|
||||
m_horizontalAdvance(0),
|
||||
m_textureImage(new TextureImage),
|
||||
m_textureCoordinates(new FloatArray(8))
|
||||
m_textureCoordinates(new FloatArray(8)),
|
||||
m_minFilter(NEAREST),
|
||||
m_magFilter(NEAREST)
|
||||
{
|
||||
// Lower left
|
||||
m_textureCoordinates->set(0, 0.0f);
|
||||
@@ -345,8 +347,23 @@ void Glyph::setupAndBindTexture(OpenGLContext* oglContext, bool software)
|
||||
// Use fixed function texture setup
|
||||
ref<Texture2D_FF> texture = new Texture2D_FF(m_textureImage.p());
|
||||
texture->setWrapMode(Texture2D_FF::CLAMP);
|
||||
if (m_minFilter == 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());
|
||||
textureMapping->setTextureFunction(RenderStateTextureMapping_FF::MODULATE);
|
||||
@@ -359,8 +376,23 @@ void Glyph::setupAndBindTexture(OpenGLContext* oglContext, bool software)
|
||||
{
|
||||
ref<Sampler> sampler = new Sampler;
|
||||
sampler->setWrapMode(Sampler::CLAMP_TO_EDGE);
|
||||
if (m_minFilter == 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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -55,6 +55,12 @@ class OpenGLContext;
|
||||
class Glyph : public Object
|
||||
{
|
||||
public:
|
||||
enum TextureFilter
|
||||
{
|
||||
NEAREST,
|
||||
LINEAR
|
||||
};
|
||||
|
||||
Glyph(wchar_t character);
|
||||
virtual ~Glyph();
|
||||
|
||||
@@ -78,6 +84,9 @@ public:
|
||||
|
||||
void setupAndBindTexture(OpenGLContext* oglContext, bool software);
|
||||
|
||||
void setMinFilter(TextureFilter filter);
|
||||
void setMagFilter(TextureFilter filter);
|
||||
|
||||
private:
|
||||
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<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
|
||||
|
||||
// Texture filter options
|
||||
TextureFilter m_minFilter;
|
||||
TextureFilter m_magFilter;
|
||||
};
|
||||
|
||||
} // namespace cvf
|
||||
|
||||
@@ -99,13 +99,14 @@ TextDrawer::~TextDrawer()
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
/// 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(!pos.isUndefined());
|
||||
|
||||
m_texts.push_back(text);
|
||||
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
|
||||
/// 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(!pos.isUndefined());
|
||||
|
||||
m_texts.push_back(text);
|
||||
m_positions.push_back(pos);
|
||||
m_directions.push_back(dir);
|
||||
}
|
||||
|
||||
|
||||
@@ -132,6 +134,7 @@ void TextDrawer::removeAllTexts()
|
||||
{
|
||||
m_texts.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->isEmpty());
|
||||
|
||||
switch (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;
|
||||
}
|
||||
}
|
||||
m_verticalAlignment = calculateVerticalAlignmentOffset(*m_font, alignment);
|
||||
}
|
||||
|
||||
|
||||
@@ -307,7 +273,7 @@ void TextDrawer::renderSoftware(OpenGLContext* oglContext, const MatrixState& ma
|
||||
void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrixState, bool softwareRendering)
|
||||
{
|
||||
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 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 textureCoords[8]; // Will be updated for each glyph
|
||||
|
||||
float* v1 = &vertexArray[0];
|
||||
float* v2 = &vertexArray[3];
|
||||
float* v3 = &vertexArray[6];
|
||||
float* v4 = &vertexArray[9];
|
||||
v1[2] = v2[2] = v3[2] = v4[2] = 0.0f;
|
||||
std::array<float*, 4> vertices = { &vertexArray[0], &vertexArray[3], &vertexArray[6], &vertexArray[9] };
|
||||
for (size_t i = 0; i < vertices.size(); ++i)
|
||||
{
|
||||
vertices[i][2] = 0.0f;
|
||||
}
|
||||
|
||||
// Prepare 2D pixel exact projection to draw texts
|
||||
Camera projCam;
|
||||
@@ -401,27 +367,24 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
||||
|
||||
// Figure out margin
|
||||
ref<Glyph> glyph = m_font->getGlyph(L'A');
|
||||
float charHeight = static_cast<float>(glyph->height());
|
||||
float charWidth = static_cast<float>(glyph->width());
|
||||
|
||||
offset.x() = cvf::Math::floor(charWidth/2.0f);
|
||||
offset.y() = cvf::Math::floor(charHeight/2.0f);
|
||||
|
||||
float glyphMarginX = cvf::Math::floor(0.5f * static_cast<float>(glyph->width()));
|
||||
float glyphMarginY = cvf::Math::floor(0.5f * static_cast<float>(glyph->height()));
|
||||
size_t numTexts = m_texts.size();
|
||||
for (size_t i = 0; i < numTexts; i++)
|
||||
{
|
||||
Vec3f pos = m_positions[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());
|
||||
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);
|
||||
|
||||
// Draw the background triangle
|
||||
v1[0] = min.x(); v1[1] = min.y(); v1[2] = pos.z();
|
||||
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();
|
||||
for (size_t v = 0; v < vertices.size(); ++v)
|
||||
{
|
||||
for (int c = 0; c < 3; ++c)
|
||||
{
|
||||
vertices[v][c] = pos[c] + corners[v][c];
|
||||
}
|
||||
}
|
||||
|
||||
if (m_drawBackground)
|
||||
{
|
||||
@@ -432,10 +395,10 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glColor3fv(m_backgroundColor.ptr());
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
glVertex3fv(v1);
|
||||
glVertex3fv(v2);
|
||||
glVertex3fv(v3);
|
||||
glVertex3fv(v4);
|
||||
for (size_t v = 0; v < vertices.size(); ++v)
|
||||
{
|
||||
glVertex3fv(vertices[v]);
|
||||
}
|
||||
glEnd();
|
||||
#endif
|
||||
}
|
||||
@@ -456,10 +419,10 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
||||
#ifndef CVF_OPENGL_ES
|
||||
glColor3fv(m_borderColor.ptr());
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex3fv(v1);
|
||||
glVertex3fv(v2);
|
||||
glVertex3fv(v3);
|
||||
glVertex3fv(v4);
|
||||
for (size_t v = 0; v < vertices.size(); ++v)
|
||||
{
|
||||
glVertex3fv(vertices[v]);
|
||||
}
|
||||
glEnd();
|
||||
#endif
|
||||
}
|
||||
@@ -524,7 +487,7 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
||||
for (i = 0; i < numTexts; i++)
|
||||
{
|
||||
Vec3f pos = m_positions[i];
|
||||
|
||||
Vec3f textDir = m_directions[i];
|
||||
String text = m_texts[i];
|
||||
|
||||
// Need to round off to integer positions to avoid buggy text drawing on iPad2
|
||||
@@ -532,7 +495,7 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
||||
pos.y() = cvf::Math::floor(pos.y());
|
||||
|
||||
// Cursor incrementor
|
||||
Vec2f cursor(pos);
|
||||
Vec2f cursor(Vec2f::ZERO);
|
||||
cursor += offset;
|
||||
|
||||
std::vector<cvf::String> lines = text.split("\n");
|
||||
@@ -547,29 +510,26 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
||||
{
|
||||
character = line[j];
|
||||
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());
|
||||
float textureHeight = static_cast<float>(glyph->height());
|
||||
|
||||
// Lower left corner
|
||||
v1[0] = cursor.x() + static_cast<float>(glyph->horizontalBearingX());
|
||||
v1[1] = cursor.y() + static_cast<float>(glyph->horizontalBearingY()) - textureHeight + static_cast<float>(m_verticalAlignment);
|
||||
v1[2] = pos.z();
|
||||
|
||||
// Lower right corner
|
||||
v2[0] = v1[0] + textureWidth;
|
||||
v2[1] = v1[1];
|
||||
v2[2] = pos.z();
|
||||
|
||||
// Upper right corner
|
||||
v3[0] = v2[0];
|
||||
v3[1] = v1[1] + textureHeight;
|
||||
v3[2] = pos.z();
|
||||
|
||||
// Upper left corner
|
||||
v4[0] = v1[0];
|
||||
v4[1] = v3[1];
|
||||
v4[2] = pos.z();
|
||||
for (size_t v = 0; v < vertices.size(); ++v)
|
||||
{
|
||||
for (int c = 0; c < 3; ++c)
|
||||
{
|
||||
vertices[v][c] = pos[c] + corners[v][c];
|
||||
}
|
||||
}
|
||||
if (textDir.dot(cvf::Vec3f::X_AXIS) < 0.9 && textDir.dot(cvf::Vec3f::Y_AXIS) < 0.9)
|
||||
{
|
||||
glyph->setMinFilter(Glyph::LINEAR);
|
||||
glyph->setMagFilter(Glyph::LINEAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
glyph->setMinFilter(Glyph::NEAREST);
|
||||
glyph->setMagFilter(Glyph::NEAREST);
|
||||
}
|
||||
|
||||
glyph->setupAndBindTexture(oglContext, softwareRendering);
|
||||
|
||||
@@ -592,19 +552,19 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
||||
|
||||
// First triangle in quad
|
||||
glTexCoord2fv(&textureCoordinatesPtr[0]);
|
||||
glVertex3fv(v1);
|
||||
glVertex3fv(vertices[0]);
|
||||
glTexCoord2fv(&textureCoordinatesPtr[2]);
|
||||
glVertex3fv(v2);
|
||||
glVertex3fv(vertices[1]);
|
||||
glTexCoord2fv(&textureCoordinatesPtr[4]);
|
||||
glVertex3fv(v3);
|
||||
glVertex3fv(vertices[2]);
|
||||
|
||||
// Second triangle in quad
|
||||
glTexCoord2fv(&textureCoordinatesPtr[0]);
|
||||
glVertex3fv(v1);
|
||||
glVertex3fv(vertices[0]);
|
||||
glTexCoord2fv(&textureCoordinatesPtr[4]);
|
||||
glVertex3fv(v3);
|
||||
glVertex3fv(vertices[2]);
|
||||
glTexCoord2fv(&textureCoordinatesPtr[6]);
|
||||
glVertex3fv(v4);
|
||||
glVertex3fv(vertices[3]);
|
||||
|
||||
glEnd();
|
||||
#endif
|
||||
@@ -623,7 +583,7 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix
|
||||
}
|
||||
|
||||
// CR
|
||||
cursor.x() = pos.x() + offset.x();
|
||||
cursor.x() = offset.x();
|
||||
cursor.y() += lineSpacing;
|
||||
}
|
||||
}
|
||||
@@ -693,4 +653,75 @@ bool TextDrawer::pickText(const Vec3f& pickCoord2d, const String& text, const Ve
|
||||
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
|
||||
|
||||
@@ -39,12 +39,15 @@
|
||||
|
||||
#include "cvfObject.h"
|
||||
#include "cvfString.h"
|
||||
#include "cvfVector2.h"
|
||||
#include "cvfVector3.h"
|
||||
#include "cvfColor3.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace cvf {
|
||||
|
||||
class Glyph;
|
||||
class Font;
|
||||
class ShaderProgram;
|
||||
class MatrixState;
|
||||
@@ -72,8 +75,8 @@ public:
|
||||
TextDrawer(Font* font);
|
||||
virtual ~TextDrawer();
|
||||
|
||||
void addText(const String& text, const Vec2f& pos);
|
||||
void addText(const String& text, const Vec3f& pos);
|
||||
void addText(const String& text, const Vec2f& pos, const Vec2f& dir = Vec2f::X_AXIS);
|
||||
void addText(const String& text, const Vec3f& pos, const Vec3f& dir = Vec3f::X_AXIS);
|
||||
void removeAllTexts();
|
||||
|
||||
void setVerticalAlignment(Alignment alignment);
|
||||
@@ -97,6 +100,9 @@ public:
|
||||
|
||||
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:
|
||||
void doRender2d(OpenGLContext* oglContext, const MatrixState& matrixState, bool softwareRendering);
|
||||
|
||||
@@ -104,6 +110,7 @@ private:
|
||||
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<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_drawBorder;
|
||||
|
||||
Reference in New Issue
Block a user