#include "RivContourMapProjectionPartMgr.h" #include "RiaColorTools.h" #include "RiaFontCache.h" #include "RiaWeightedMeanCalculator.h" #include "RigCellGeometryTools.h" #include "RivMeshLinesSourceInfo.h" #include "RivScalarMapperUtils.h" #include "RivPartPriority.h" #include "RimGridView.h" #include "RimContourMapProjection.h" #include "cafEffectGenerator.h" #include "cvfCamera.h" #include "cvfDrawableText.h" #include "cvfGeometryBuilderFaceList.h" #include "cvfGeometryUtils.h" #include "cvfMeshEdgeExtractor.h" #include "cvfPart.h" #include "cvfPrimitiveSetIndexedUInt.h" #include "cvfScalarMapper.h" #include "cvfRay.h" #include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivContourMapProjectionPartMgr::RivContourMapProjectionPartMgr(RimContourMapProjection* contourMapProjection, RimGridView* contourMap) { m_contourMapProjection = contourMapProjection; m_parentContourMap = contourMap; m_labelEffect = new cvf::Effect; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivContourMapProjectionPartMgr::createProjectionGeometry() { m_contourMapProjection->generateGeometryIfNecessary(); m_contourLinePolygons = m_contourMapProjection->contourPolygons(); m_contourMapTriangles = m_contourMapProjection->trianglesWithVertexValues(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivContourMapProjectionPartMgr::appendProjectionToModel(cvf::ModelBasicList* model, const caf::DisplayCoordTransform* displayCoordTransform) const { cvf::ref mapPart = createProjectionMapPart(displayCoordTransform); if (mapPart.notNull()) { model->addPart(mapPart.p()); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivContourMapProjectionPartMgr::appendPickPointVisToModel(cvf::ModelBasicList* model, const caf::DisplayCoordTransform* displayCoordTransform) const { cvf::ref drawable = createPickPointVisDrawable(displayCoordTransform); if (drawable.notNull() && drawable->boundingBox().isValid()) { caf::MeshEffectGenerator meshEffectGen(cvf::Color3::MAGENTA); meshEffectGen.setLineWidth(1.0f); meshEffectGen.createAndConfigurePolygonOffsetRenderState(caf::PO_2); cvf::ref effect = meshEffectGen.generateCachedEffect(); cvf::ref part = new cvf::Part; part->setDrawable(drawable.p()); part->setEffect(effect.p()); part->setSourceInfo(new RivMeshLinesSourceInfo(m_contourMapProjection.p())); model->addPart(part.p()); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RivContourMapProjectionPartMgr::createTextureCoords(const std::vector& values) const { cvf::Vec2ui patchSize = m_contourMapProjection->numberOfVerticesIJ(); cvf::ref textureCoords = new cvf::Vec2fArray(values.size()); #pragma omp parallel for for (int i = 0; i < (int) values.size(); ++i) { if (values[i] != std::numeric_limits::infinity()) { cvf::Vec2f textureCoord = m_contourMapProjection->legendConfig()->scalarMapper()->mapToTextureCoord(values[i]); textureCoord.y() = 0.0; (*textureCoords)[i] = textureCoord; } else { (*textureCoords)[i] = cvf::Vec2f(0.0, 1.0); } } return textureCoords; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivContourMapProjectionPartMgr::appendContourLinesToModel(const cvf::Camera* camera, cvf::ModelBasicList* model, const caf::DisplayCoordTransform* displayCoordTransform) { if (m_contourMapProjection->showContourLines()) { cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper(); std::vector> labelBBoxes; std::vector> labelDrawables = createContourLabels(camera, displayCoordTransform, &labelBBoxes); std::vector>> contourDrawablesForAllLevels = createContourPolygons(displayCoordTransform, labelBBoxes); std::vector tickValues; mapper->majorTickValues(&tickValues); for (size_t i = 0; i < contourDrawablesForAllLevels.size(); ++i) { std::vector> contourDrawables = contourDrawablesForAllLevels[i]; cvf::Color3f backgroundColor(mapper->mapToColor(tickValues[i])); cvf::Color3f lineColor = RiaColorTools::contrastColor(backgroundColor); for (cvf::ref contourDrawable : contourDrawables) { if (contourDrawable.notNull() && contourDrawable->boundingBox().isValid()) { caf::MeshEffectGenerator meshEffectGen(lineColor); meshEffectGen.setLineWidth(1.0f); meshEffectGen.createAndConfigurePolygonOffsetRenderState(caf::PO_1); cvf::ref effect = meshEffectGen.generateCachedEffect(); cvf::ref part = new cvf::Part; part->setDrawable(contourDrawable.p()); part->setEffect(effect.p()); part->setPriority(RivPartPriority::MeshLines); part->setSourceInfo(new RivMeshLinesSourceInfo(m_contourMapProjection.p())); model->addPart(part.p()); } } } for (auto labelDrawableRef : labelDrawables) { cvf::ref part = new cvf::Part; part->setDrawable(labelDrawableRef.p()); part->setEffect(m_labelEffect.p()); part->setPriority(RivPartPriority::Text); part->setSourceInfo(new RivMeshLinesSourceInfo(m_contourMapProjection.p())); model->addPart(part.p()); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RivContourMapProjectionPartMgr::createTextLabel(const cvf::Color3f& textColor, const cvf::Color3f& backgroundColor) { auto font = RiaFontCache::getFont(RiaFontCache::FONT_SIZE_10); cvf::ref labelDrawable = new cvf::DrawableText(); labelDrawable->setFont(font.p()); labelDrawable->setCheckPosVisible(false); labelDrawable->setUseDepthBuffer(true); labelDrawable->setDrawBorder(false); labelDrawable->setDrawBackground(false); labelDrawable->setBackgroundColor(backgroundColor); labelDrawable->setVerticalAlignment(cvf::TextDrawer::CENTER); labelDrawable->setTextColor(textColor); labelDrawable->setBorderColor(textColor); return labelDrawable; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RivContourMapProjectionPartMgr::createProjectionMapPart(const caf::DisplayCoordTransform* displayCoordTransform) const { const std::vector& vertices = m_contourMapTriangles; if (vertices.size() < 3u) { return cvf::ref(); } cvf::ref vertexArray = new cvf::Vec3fArray(vertices.size()); cvf::ref faceList = new cvf::UIntArray(vertices.size()); std::vector values(vertices.size()); for (uint i = 0; i < vertices.size(); ++i) { cvf::Vec3d globalVertex = cvf::Vec3d(vertices[i].x(), vertices[i].y(), vertices[i].z()) + m_contourMapProjection->origin3d(); cvf::Vec3f displayVertexPos (displayCoordTransform->transformToDisplayCoord(globalVertex)); (*vertexArray)[i] = displayVertexPos; (*faceList)[i] = i; values[i] = vertices[i].w(); } cvf::ref indexUInt = new cvf::PrimitiveSetIndexedUInt(cvf::PrimitiveType::PT_TRIANGLES, faceList.p()); cvf::ref geo = new cvf::DrawableGeo; geo->addPrimitiveSet(indexUInt.p()); geo->setVertexArray(vertexArray.p()); cvf::ref part = new cvf::Part; part->setDrawable(geo.p()); cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper(); cvf::ref textureCoords = createTextureCoords(values); RivScalarMapperUtils::applyTextureResultsToPart( part.p(), textureCoords.p(), mapper, 1.0f, caf::FC_NONE, true, m_parentContourMap->backgroundColor()); part->setSourceInfo(new RivObjectSourceInfo(m_contourMapProjection.p())); part->setPriority(RivPartPriority::BaseLevel); return part; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector>> RivContourMapProjectionPartMgr::createContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform, const std::vector>& labelBBoxes) const { const cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper(); std::vector tickValues; mapper->majorTickValues(&tickValues); std::vector>> contourDrawablesForAllLevels; contourDrawablesForAllLevels.resize(tickValues.size()); for (size_t i = 1; i < m_contourLinePolygons.size(); ++i) { std::vector> contourDrawables; 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(); std::vector displayLines; displayLines.reserve(nVertices * 2); for (size_t v = 0; v < nVertices; ++v) { 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 vertexArray = new cvf::Vec3fArray(displayLines); std::vector indices; indices.reserve(vertexArray->size()); for (cvf::uint k = 0; k < vertexArray->size(); ++k) { indices.push_back(k); } cvf::ref indexedUInt = new cvf::PrimitiveSetIndexedUInt(cvf::PrimitiveType::PT_LINES); cvf::ref indexArray = new cvf::UIntArray(indices); indexedUInt->setIndices(indexArray.p()); cvf::ref geo = new cvf::DrawableGeo; geo->addPrimitiveSet(indexedUInt.p()); geo->setVertexArray(vertexArray.p()); contourDrawables.push_back(geo); } if (!contourDrawables.empty()) { contourDrawablesForAllLevels[i] = contourDrawables; } } return contourDrawablesForAllLevels; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector> RivContourMapProjectionPartMgr::createContourLabels(const cvf::Camera* camera, const caf::DisplayCoordTransform* displayCoordTransform, std::vector>* labelBBoxes) const { CVF_ASSERT(camera && displayCoordTransform && labelBBoxes); const cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper(); std::vector tickValues; mapper->majorTickValues(&tickValues); std::vector> 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 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 = nVertices; double distanceSinceLastLabel = std::numeric_limits::infinity(); for (size_t l = 0; l < nLabels; ++l) { size_t nVertex = (nVertices * l) / nLabels; size_t nextVertex = (nVertex + 1) % nVertices; cvf::Vec3d globalVertex1 = m_contourLinePolygons[i][j].vertices[nVertex] + m_contourMapProjection->origin3d(); cvf::Vec3d globalVertex2 = m_contourLinePolygons[i][j].vertices[nextVertex] + m_contourMapProjection->origin3d(); cvf::Vec3d globalVertex = 0.5 * (globalVertex1 + globalVertex2); cvf::Vec3d segment = globalVertex2 - globalVertex1; cvf::Vec3d displayVertex = displayCoordTransform->transformToDisplayCoord(globalVertex); cvf::Vec3d windowVertex; camera->project(displayVertex, &windowVertex); CVF_ASSERT(!windowVertex.isUndefined()); displayVertex.z() += 10.0f; cvf::BoundingBox windowBBox = label->textBoundingBox(labelText, cvf::Vec3f::ZERO, cvf::Vec3f(segment.getNormalized())); cvf::Vec3d displayBBoxMin, displayBBoxMax; camera->unproject(windowBBox.min() + windowVertex, &displayBBoxMin); camera->unproject(windowBBox.max() + windowVertex, &displayBBoxMax); CVF_ASSERT(!displayBBoxMin.isUndefined()); CVF_ASSERT(!displayBBoxMax.isUndefined()); cvf::BoundingBox displayBBox(displayBBoxMin - cvf::Vec3d::Z_AXIS * 20.0, displayBBoxMax + cvf::Vec3d::Z_AXIS * 20.0); cvf::Vec3d currentExtent = displayBBoxMax - displayBBoxMin; bool overlaps = false; if (distanceSinceLastLabel < currentExtent.length() * 10.0) { overlaps = true; } if (!overlaps) { for (auto boxVector : *labelBBoxes) { for (const cvf::BoundingBox& existingBBox : boxVector) { double dist = (displayBBox.center() - existingBBox.center()).length(); if (dist < segment.length() || existingBBox.intersects(displayBBox)) { overlaps = true; break; } } } } if (!overlaps) { cvf::Vec3f displayVertexV(displayVertex); CVF_ASSERT(!displayVertex.isUndefined()); label->addText(labelText, displayVertexV, cvf::Vec3f(segment.getNormalized())); labelBBoxes->at(i).push_back(displayBBox); distanceSinceLastLabel = 0.0; } else { distanceSinceLastLabel += segment.length(); } } } if (label->numberOfTexts() != 0u) { labelDrawables.push_back(label); } } return labelDrawables; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RivContourMapProjectionPartMgr::createPickPointVisDrawable(const caf::DisplayCoordTransform* displayCoordTransform) const { std::vector pickPointPolygon = m_contourMapProjection->generatePickPointPolygon(); if (pickPointPolygon.empty()) { return nullptr; } cvf::ref vertexArray = new cvf::Vec3fArray(pickPointPolygon.size()); for (size_t i = 0; i < pickPointPolygon.size(); ++i) { cvf::Vec3d globalPoint = pickPointPolygon[i] + m_contourMapProjection->origin3d(); cvf::Vec3f displayPoint(displayCoordTransform->transformToDisplayCoord(globalPoint)); (*vertexArray)[i] = displayPoint; } cvf::ref geo = nullptr; if (vertexArray->size() > 0u) { std::vector indices; indices.reserve(vertexArray->size()); for (cvf::uint j = 0; j < vertexArray->size(); ++j) { indices.push_back(j); } cvf::ref indexedUInt = new cvf::PrimitiveSetIndexedUInt(cvf::PrimitiveType::PT_LINES); cvf::ref indexArray = new cvf::UIntArray(indices); indexedUInt->setIndices(indexArray.p()); geo = new cvf::DrawableGeo; geo->addPrimitiveSet(indexedUInt.p()); geo->setVertexArray(vertexArray.p()); } return geo; }