#3441 Valve visualisation in 3D view.

This commit is contained in:
Gaute Lindkvist
2018-10-10 16:57:43 +02:00
parent cfbe6a1a24
commit e7a39fb2f8
17 changed files with 590 additions and 149 deletions

View File

@@ -397,6 +397,176 @@ cvf::ref<cvf::DrawableGeo> RivPipeGeometryGenerator::generateExtrudedCylinder(do
return geo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::DrawableGeo> RivPipeGeometryGenerator::generateVariableRadiusTube(size_t crossSectionNodeCount,
const cvf::Vec3dArray* cylinderCenterCoords,
const std::vector<double>& radii)
{
const double epsilon = 1.0e-8;
CVF_ASSERT(cylinderCenterCoords != nullptr);
// Calculate first valid pipe direction, to be able to handle centerNodes in the same place
cvf::Vec3d lastValidPipeDirection = cvf::Vec3d::UNDEFINED;
for (size_t i = 0; i < cylinderCenterCoords->size() - 1; i++)
{
cvf::Vec3d candidateDir = (*cylinderCenterCoords)[i + 1] - (*cylinderCenterCoords)[i];
if (candidateDir.normalize())
{
lastValidPipeDirection = candidateDir;
break;
}
}
if (lastValidPipeDirection.isUndefined()) return nullptr; // The pipe coordinates are all the same point
cvf::Vec3d dir = (*cylinderCenterCoords)[1] - (*cylinderCenterCoords)[0];
if (!dir.normalize())
{
dir = lastValidPipeDirection;
}
cvf::Vec3d orient1 = dir.perpendicularVector();
orient1.normalize();
cvf::Vec3d orient2 = dir ^ orient1;
orient2.normalize();
std::vector<cvf::Vec3d> lastExtrudedNodes;
computeCircle(radii[0], crossSectionNodeCount, (*cylinderCenterCoords)[0], orient1, orient2, &lastExtrudedNodes);
std::vector<cvf::Vec3f> crossSectionVertices;
std::vector<cvf::Vec3f> cylinderSegmentNormals;
// Insert the first set of vertices
for (size_t i = 0; i < lastExtrudedNodes.size(); i++)
{
crossSectionVertices.push_back(cvf::Vec3f(lastExtrudedNodes[i]));
}
// Loop along the cylinder center coords and calculate the cross section vertexes in each center vertex
for (size_t ccIdx = 0; ccIdx < cylinderCenterCoords->size()-1; ccIdx++)
{
size_t nextCcIdx = ccIdx + 1;
// Calculate this and next pipe direction, and intersection plane
cvf::Vec3d firstCoord = (*cylinderCenterCoords)[ccIdx];
cvf::Vec3d secondCoord = (*cylinderCenterCoords)[nextCcIdx];
cvf::Vec3d nextDir = secondCoord - firstCoord;
if (!nextDir.normalize())
{
nextDir = lastValidPipeDirection;
}
else
{
lastValidPipeDirection = nextDir;
}
orient1 = nextDir.perpendicularVector().getNormalized();
orient2 = (nextDir ^ orient1).getNormalized();
std::vector<cvf::Vec3d> extrudedNodes;
computeCircle(radii[nextCcIdx], crossSectionNodeCount, (*cylinderCenterCoords)[nextCcIdx], orient1, orient2, &extrudedNodes);
// Insert the next set of vertices and calculate normals for segment
for (size_t i = 0; i < extrudedNodes.size(); i++)
{
cvf::Vec3f nextNodeAlongWellPath = cvf::Vec3f(extrudedNodes[i]);
cvf::Vec3f currentNode = cvf::Vec3f(lastExtrudedNodes[i]);
cvf::Vec3f wellDirectionDir = nextNodeAlongWellPath - currentNode;
if (!wellDirectionDir.normalize())
{
wellDirectionDir = cvf::Vec3f(lastValidPipeDirection);
}
cvf::Vec3f lastNodeAlongCircle;
cvf::Vec3f nextNodeAlongCircle;
if (i > 0)
{
lastNodeAlongCircle = cvf::Vec3f(lastExtrudedNodes[i - 1]);
}
else
{
lastNodeAlongCircle = cvf::Vec3f(lastExtrudedNodes.back());
}
if (i < extrudedNodes.size() - 1)
{
nextNodeAlongCircle = cvf::Vec3f(lastExtrudedNodes[i + 1]);
}
else
{
nextNodeAlongCircle = cvf::Vec3f(lastExtrudedNodes.front());
}
cvf::Vec3f circleDir = (nextNodeAlongCircle - lastNodeAlongCircle).getNormalized();
cvf::Vec3f segmentNormal = (wellDirectionDir ^ circleDir).getNormalized();
crossSectionVertices.push_back(cvf::Vec3f(nextNodeAlongWellPath));
cylinderSegmentNormals.push_back(segmentNormal);
}
lastExtrudedNodes = extrudedNodes;
}
size_t crossSectionCount = crossSectionVertices.size() / crossSectionNodeCount;
if (crossSectionCount < 2) return nullptr;
CVF_ASSERT(crossSectionVertices.size() - crossSectionNodeCount == cylinderSegmentNormals.size());
size_t segmentCount = crossSectionCount - 1;
size_t vertexCount = segmentCount * crossSectionNodeCount * 4;
cvf::ref<cvf::Vec3fArray> quadVertexArray = new cvf::Vec3fArray();
quadVertexArray->reserve(vertexCount);
cvf::ref<cvf::Vec3fArray> quadNormalArray = new cvf::Vec3fArray();
quadNormalArray->reserve(vertexCount);
size_t segmentIdx = 0;
for (segmentIdx = 0; segmentIdx < segmentCount; segmentIdx++)
{
for (size_t nodeIdx = 0; nodeIdx < crossSectionNodeCount - 1; nodeIdx++)
{
quadVertexArray->add(crossSectionVertices[((segmentIdx + 0) * crossSectionNodeCount) + nodeIdx + 0]);
quadVertexArray->add(crossSectionVertices[((segmentIdx + 0) * crossSectionNodeCount) + nodeIdx + 1]);
quadVertexArray->add(crossSectionVertices[((segmentIdx + 1) * crossSectionNodeCount) + nodeIdx + 1]);
quadVertexArray->add(crossSectionVertices[((segmentIdx + 1) * crossSectionNodeCount) + nodeIdx + 0]);
quadNormalArray->add(cylinderSegmentNormals[((segmentIdx + 0) * crossSectionNodeCount) + nodeIdx + 0]);
quadNormalArray->add(cylinderSegmentNormals[((segmentIdx + 0) * crossSectionNodeCount) + nodeIdx + 1]);
quadNormalArray->add(cylinderSegmentNormals[((segmentIdx + 0) * crossSectionNodeCount) + nodeIdx + 1]);
quadNormalArray->add(cylinderSegmentNormals[((segmentIdx + 0) * crossSectionNodeCount) + nodeIdx + 0]);
}
// Last quad closing the cylinder
quadVertexArray->add(crossSectionVertices[((segmentIdx + 0) * crossSectionNodeCount) + crossSectionNodeCount - 1]);
quadVertexArray->add(crossSectionVertices[((segmentIdx + 0) * crossSectionNodeCount) + 0]);
quadVertexArray->add(crossSectionVertices[((segmentIdx + 1) * crossSectionNodeCount) + 0]);
quadVertexArray->add(crossSectionVertices[((segmentIdx + 1) * crossSectionNodeCount) + crossSectionNodeCount - 1]);
quadNormalArray->add(cylinderSegmentNormals[((segmentIdx + 0) * crossSectionNodeCount) + crossSectionNodeCount - 1]);
quadNormalArray->add(cylinderSegmentNormals[((segmentIdx + 0) * crossSectionNodeCount) + 0]);
quadNormalArray->add(cylinderSegmentNormals[((segmentIdx + 0) * crossSectionNodeCount) + 0]);
quadNormalArray->add(cylinderSegmentNormals[((segmentIdx + 0) * crossSectionNodeCount) + crossSectionNodeCount - 1]);
}
CVF_ASSERT(vertexCount == quadVertexArray->size());
CVF_ASSERT(vertexCount == quadNormalArray->size());
cvf::ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo;
geo->setFromQuadVertexArray(quadVertexArray.p());
geo->setNormalArray(quadNormalArray.p());
return geo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -647,3 +817,46 @@ void RivPipeGeometryGenerator::cylinderWithCenterLineParts(cvf::Collection<cvf::
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivPipeGeometryGenerator::tubeWithCenterLinePartsAndVariableWidth(cvf::Collection<cvf::Part>* destinationParts,
const std::vector<cvf::Vec3d>& centerCoords,
const std::vector<double>& radii,
const cvf::Color3f& color)
{
setCrossSectionVertexCount(12);
cvf::ref<cvf::Vec3dArray> activeCoords = new cvf::Vec3dArray(centerCoords);
setPipeCenterCoords(activeCoords.p());
cvf::ref<cvf::DrawableGeo> surfaceGeo = generateVariableRadiusTube(m_crossSectionNodeCount, activeCoords.p(), radii);
if (surfaceGeo.notNull())
{
cvf::Part* part = new cvf::Part;
part->setDrawable(surfaceGeo.p());
caf::SurfaceEffectGenerator surfaceGen(cvf::Color4f(color), caf::PO_1);
cvf::ref<cvf::Effect> eff = surfaceGen.generateCachedEffect();
part->setEffect(eff.p());
destinationParts->push_back(part);
}
cvf::ref<cvf::DrawableGeo> centerLineGeo = createCenterLine();
if (centerLineGeo.notNull())
{
cvf::Part* part = new cvf::Part;
part->setDrawable(centerLineGeo.p());
caf::SurfaceEffectGenerator surfaceGen(cvf::Color4f(color), caf::PO_1);
cvf::ref<cvf::Effect> eff = surfaceGen.generateCachedEffect();
part->setEffect(eff.p());
destinationParts->push_back(part);
}
}

View File

@@ -64,7 +64,16 @@ public:
void setFirstVisibleSegmentIndex(size_t segmentIndex);
size_t segmentIndexFromTriangleIndex(size_t triangleIndex) const;
void cylinderWithCenterLineParts(cvf::Collection<cvf::Part>* destinationParts, const std::vector<cvf::Vec3d>& centerCoords, const cvf::Color3f& color, double radius);
void cylinderWithCenterLineParts(cvf::Collection<cvf::Part>* destinationParts,
const std::vector<cvf::Vec3d>& centerCoords,
const cvf::Color3f& color,
double radius);
void tubeWithCenterLinePartsAndVariableWidth(cvf::Collection<cvf::Part>* destinationParts,
const std::vector<cvf::Vec3d>& centerCoords,
const std::vector<double>& radii,
const cvf::Color3f& color);
private:
void clearComputedData();
void updateFilteredPipeCenterCoords();
@@ -75,6 +84,7 @@ private:
static cvf::ref<cvf::DrawableGeo> generateLine(const cvf::Vec3dArray* coords);
static cvf::ref<cvf::DrawableGeo> generateExtrudedCylinder(double radius, size_t crossSectionNodeCount,const cvf::Vec3dArray* cylinderCenterCoords);
static cvf::ref<cvf::DrawableGeo> generateVariableRadiusTube(size_t crossSectionNodeCount, const cvf::Vec3dArray* cylinderCenterCoords, const std::vector<double>& radii);
static void computeExtrudedCoordsAndNormals(cvf::Vec3d intersectionCoord,
cvf::Vec3d intersectionPlaneNormal,

View File

@@ -38,7 +38,10 @@
#include "RimPerforationCollection.h"
#include "RimPerforationInterval.h"
#include "RimWellPath.h"
#include "RimWellPathAttribute.h"
#include "RimWellPathAttributeCollection.h"
#include "RimWellPathCollection.h"
#include "RimWellPathValve.h"
#include "RimWellPathFractureCollection.h"
#include "RimWellPathFracture.h"
@@ -159,6 +162,52 @@ void RivWellPathPartMgr::appendFishboneSubsPartsToModel(cvf::ModelBasicList* mod
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivWellPathPartMgr::appendCasingShoesToModel(cvf::ModelBasicList* model,
const caf::DisplayCoordTransform* displayCoordTransform,
double characteristicCellSize)
{
if (!m_rimWellPath) return;
RivPipeGeometryGenerator geoGenerator;
std::vector<RimWellPathAttribute*> attributes = m_rimWellPath->attributeCollection()->attributes();
for (RimWellPathAttribute* attribute : attributes)
{
if (attribute->componentType() == RiaDefines::CASING)
{
double wellPathRadius = this->wellPathRadius(characteristicCellSize, this->wellPathCollection());
double endMD = attribute->endMD();
double shoeStartMD = endMD - 2.5;
std::vector<cvf::Vec3d> displayCoords;
displayCoords.push_back(displayCoordTransform->transformToDisplayCoord(m_rimWellPath->wellPathGeometry()->interpolatedPointAlongWellPath(shoeStartMD)));
displayCoords.push_back(displayCoordTransform->transformToDisplayCoord(m_rimWellPath->wellPathGeometry()->interpolatedPointAlongWellPath(endMD)));
displayCoords.push_back(displayCoordTransform->transformToDisplayCoord(m_rimWellPath->wellPathGeometry()->interpolatedPointAlongWellPath(endMD)));
std::vector<double> radii;
radii.push_back(wellPathRadius);
radii.push_back(wellPathRadius * 2.0);
radii.push_back(wellPathRadius * 1.1);
cvf::ref<RivObjectSourceInfo> objectSourceInfo = new RivObjectSourceInfo(attribute);
cvf::Collection<cvf::Part> parts;
geoGenerator.tubeWithCenterLinePartsAndVariableWidth(&parts, displayCoords, radii, attribute->defaultComponentColor());
for (auto part : parts)
{
part->setSourceInfo(objectSourceInfo.p());
model->addPart(part.p());
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -282,15 +331,95 @@ void RivWellPathPartMgr::appendPerforationsToModel(cvf::ModelBasicList* model,
perfIntervalCLDiplayCS.push_back( displayCoordTransform->transformToDisplayCoord(point));
}
}
cvf::ref<RivObjectSourceInfo> objectSourceInfo = new RivObjectSourceInfo(perforation);
cvf::Collection<cvf::Part> parts;
geoGenerator.cylinderWithCenterLineParts(&parts, perfIntervalCLDiplayCS, cvf::Color3f::GREEN, perforationRadius);
for (auto part : parts)
{
part->setSourceInfo(objectSourceInfo.p());
model->addPart(part.p());
cvf::ref<RivObjectSourceInfo> objectSourceInfo = new RivObjectSourceInfo(perforation);
cvf::Collection<cvf::Part> parts;
geoGenerator.cylinderWithCenterLineParts(&parts, perfIntervalCLDiplayCS, cvf::Color3f::GREEN, perforationRadius);
for (auto part : parts)
{
part->setSourceInfo(objectSourceInfo.p());
model->addPart(part.p());
}
}
appendPerforationValvesToModel(model, perforation, wellPathRadius, displayCoordTransform, geoGenerator);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivWellPathPartMgr::appendPerforationValvesToModel(cvf::ModelBasicList* model, RimPerforationInterval* perforation, double wellPathRadius, const caf::DisplayCoordTransform* displayCoordTransform, RivPipeGeometryGenerator &geoGenerator)
{
// Valves
{
for (RimWellPathValve* valve : perforation->valves())
{
if (!valve->isChecked()) continue;
std::vector<double> measuredDepthsRelativeToStartMD;
std::vector<double> radii;
cvf::Color3f valveColor = valve->defaultComponentColor();
if (valve->componentType() == RiaDefines::ICV)
{
measuredDepthsRelativeToStartMD = { 0.0, 1.0, 1.5, 4.0, 5.0, 5.5, 8.0, 9.0 };
radii = { wellPathRadius, wellPathRadius * 1.8, wellPathRadius * 2.0,
wellPathRadius * 2.0, wellPathRadius * 1.8,
wellPathRadius * 1.7, wellPathRadius * 1.7, wellPathRadius };
}
else if (valve->componentType() == RiaDefines::ICD || valve->componentType() == RiaDefines::AICD)
{
int size = 16;
measuredDepthsRelativeToStartMD.resize(size);
radii.resize(size);
for (int i = 0; i < size; i += 2)
{
measuredDepthsRelativeToStartMD[i] = double(i / 2);
measuredDepthsRelativeToStartMD[i + 1] = double(i / 2 + 0.5);
}
radii[0] = wellPathRadius;
bool inner = false;
int nInners = 0;
for (size_t i = 1; i < size; i += 2)
{
if (inner && valve->componentType() == RiaDefines::AICD && nInners > 0)
{
radii[i + 1] = radii[i] = wellPathRadius * 1.7;
nInners = 0;
}
else if (inner)
{
radii[i + 1] = radii[i] = wellPathRadius * 1.9;
nInners++;
}
else
{
radii[i + 1] = radii[i] = wellPathRadius * 2.0;
}
inner = !inner;
}
radii[size - 1] = wellPathRadius;
}
double startMD = valve->startMD();
std::vector<cvf::Vec3d> displayCoords;
for (double mdRelativeToStart : measuredDepthsRelativeToStartMD)
{
displayCoords.push_back(displayCoordTransform->transformToDisplayCoord(
m_rimWellPath->wellPathGeometry()->interpolatedPointAlongWellPath(mdRelativeToStart + startMD)));
}
cvf::ref<RivObjectSourceInfo> objectSourceInfo = new RivObjectSourceInfo(valve);
cvf::Collection<cvf::Part> parts;
geoGenerator.tubeWithCenterLinePartsAndVariableWidth(&parts, displayCoords, radii, valveColor);
for (auto part : parts)
{
part->setSourceInfo(objectSourceInfo.p());
model->addPart(part.p());
}
}
}
}
@@ -502,6 +631,7 @@ void RivWellPathPartMgr::appendStaticGeometryPartsToModel(cvf::ModelBasicList*
appendFishboneSubsPartsToModel(model, displayCoordTransform, characteristicCellSize);
appendImportedFishbonesToModel(model, displayCoordTransform, characteristicCellSize);
appendCasingShoesToModel(model, displayCoordTransform, characteristicCellSize);
RimGridView* gridView = dynamic_cast<RimGridView*>(m_rimView.p());
if (!gridView) return;

View File

@@ -43,6 +43,7 @@ class RivPipeGeometryGenerator;
class RimProject;
class RimWellPath;
class RivFishbonesSubsPartMgr;
class RimPerforationInterval;
class RimWellPathCollection;
class Rim3dView;
class Riv3dWellLogPlanePartMgr;
@@ -88,6 +89,10 @@ private:
const caf::DisplayCoordTransform* displayCoordTransform,
double characteristicCellSize);
void appendCasingShoesToModel(cvf::ModelBasicList* model,
const caf::DisplayCoordTransform* displayCoordTransform,
double characteristicCellSize);
void appendImportedFishbonesToModel(cvf::ModelBasicList* model,
const caf::DisplayCoordTransform* displayCoordTransform,
double characteristicCellSize);
@@ -98,6 +103,12 @@ private:
double characteristicCellSize,
bool doFlatten);
void appendPerforationValvesToModel(cvf::ModelBasicList* model,
RimPerforationInterval* perforation,
double wellPathRadius,
const caf::DisplayCoordTransform* displayCoordTransform,
RivPipeGeometryGenerator& geoGenerator);
void appendVirtualTransmissibilitiesToModel(cvf::ModelBasicList* model,
size_t timeStepIndex,
const caf::DisplayCoordTransform* displayCoordTransform,