mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
715 lines
22 KiB
C++
715 lines
22 KiB
C++
//##################################################################################################
|
|
//
|
|
// Custom Visualization Core library
|
|
// Copyright (C) 2011-2013 Ceetron AS
|
|
//
|
|
// This library may be used under the terms of either the GNU General Public License or
|
|
// the GNU Lesser General Public License as follows:
|
|
//
|
|
// GNU General Public License Usage
|
|
// This library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU General Public License at <<http://www.gnu.org/licenses/gpl.html>>
|
|
// for more details.
|
|
//
|
|
// GNU Lesser General Public License Usage
|
|
// This library is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation; either version 2.1 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
|
|
// for more details.
|
|
//
|
|
//##################################################################################################
|
|
|
|
|
|
#include "cvfBase.h"
|
|
#include "cvfModelBasicTree.h"
|
|
#include "cvfPart.h"
|
|
#include "cvfCamera.h"
|
|
#include "cvfCullSettings.h"
|
|
#include "cvfPartRenderHintCollection.h"
|
|
#include "cvfRayIntersectSpec.h"
|
|
#include "cvfRay.h"
|
|
#include "cvfDrawableGeo.h"
|
|
|
|
namespace cvf {
|
|
|
|
|
|
|
|
//==================================================================================================
|
|
///
|
|
/// \class cvf::ModelBasicTreeNode
|
|
/// \ingroup Viewing
|
|
///
|
|
/// A node in a ModelBasicTree.
|
|
///
|
|
/// Contains a list of part at this level and a list of children.
|
|
///
|
|
//==================================================================================================
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Constructor
|
|
//--------------------------------------------------------------------------------------------------
|
|
ModelBasicTreeNode::ModelBasicTreeNode()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Destructor
|
|
//--------------------------------------------------------------------------------------------------
|
|
ModelBasicTreeNode::~ModelBasicTreeNode()
|
|
{
|
|
uint numChildren = childCount();
|
|
uint i;
|
|
for (i = 0; i < numChildren; i++)
|
|
{
|
|
ModelBasicTreeNode* c = child(i);
|
|
CVF_ASSERT(c);
|
|
|
|
delete c;
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Add a part to this node
|
|
//--------------------------------------------------------------------------------------------------
|
|
void ModelBasicTreeNode::addPart(Part* part)
|
|
{
|
|
CVF_ASSERT(part);
|
|
|
|
if (m_partList.isNull())
|
|
{
|
|
m_partList = new ModelBasicList;
|
|
}
|
|
|
|
m_partList->addPart(part);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Get the part at the given index
|
|
//--------------------------------------------------------------------------------------------------
|
|
Part* ModelBasicTreeNode::part(uint index)
|
|
{
|
|
CVF_ASSERT(m_partList.notNull());
|
|
CVF_ASSERT(index < partCount());
|
|
|
|
return m_partList->part(index);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns the number of parts in this node
|
|
//--------------------------------------------------------------------------------------------------
|
|
uint ModelBasicTreeNode::partCount() const
|
|
{
|
|
if (m_partList.notNull())
|
|
{
|
|
return static_cast<uint>(m_partList->partCount());
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void ModelBasicTreeNode::removePart(Part* part)
|
|
{
|
|
if (m_partList.notNull())
|
|
{
|
|
m_partList->removePart(part);
|
|
}
|
|
|
|
uint numChildren = childCount();
|
|
uint i;
|
|
for (i = 0; i < numChildren; i++)
|
|
{
|
|
ModelBasicTreeNode* c = child(i);
|
|
CVF_ASSERT(c);
|
|
|
|
c->removePart(part);
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Add a child node to this node. The node can have any number of childern.
|
|
//--------------------------------------------------------------------------------------------------
|
|
void ModelBasicTreeNode::addChild(ModelBasicTreeNode* child)
|
|
{
|
|
CVF_ASSERT(child);
|
|
|
|
m_children.push_back(child);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns the child node at the given index
|
|
//--------------------------------------------------------------------------------------------------
|
|
ModelBasicTreeNode* ModelBasicTreeNode::child(uint index)
|
|
{
|
|
CVF_ASSERT(index < childCount());
|
|
|
|
return m_children[index];
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns a const ptr to the child node at the given index
|
|
//--------------------------------------------------------------------------------------------------
|
|
const ModelBasicTreeNode* ModelBasicTreeNode::child(uint index) const
|
|
{
|
|
CVF_ASSERT(index < childCount());
|
|
|
|
return m_children[index];
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns the number of children in this node
|
|
//--------------------------------------------------------------------------------------------------
|
|
uint ModelBasicTreeNode::childCount() const
|
|
{
|
|
return static_cast<uint>(m_children.size());
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns the number of children in this node
|
|
//--------------------------------------------------------------------------------------------------
|
|
void ModelBasicTreeNode::removeChild(ModelBasicTreeNode* child)
|
|
{
|
|
std::vector<ModelBasicTreeNode*>::iterator it = std::find(m_children.begin(), m_children.end(), child);
|
|
if (it != m_children.end())
|
|
{
|
|
m_children.erase(it);
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Update the bounding box of this node (recursive)
|
|
//--------------------------------------------------------------------------------------------------
|
|
void ModelBasicTreeNode::updateBoundingBoxesRecursive()
|
|
{
|
|
m_boundingBox.reset();
|
|
|
|
uint numChildren = childCount();
|
|
uint i;
|
|
for (i = 0; i < numChildren; i++)
|
|
{
|
|
ModelBasicTreeNode* c = child(i);
|
|
CVF_ASSERT(c);
|
|
|
|
c->updateBoundingBoxesRecursive();
|
|
m_boundingBox.add(c->boundingBox());
|
|
}
|
|
|
|
if (m_partList.notNull())
|
|
{
|
|
m_partList->updateBoundingBoxesRecursive();
|
|
m_boundingBox.add(m_partList->boundingBox());
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Compute and append the visible parts in this node and all child nodes (recursive)
|
|
//--------------------------------------------------------------------------------------------------
|
|
void ModelBasicTreeNode::findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, uint enableMask)
|
|
{
|
|
if (!m_boundingBox.isValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
const size_t numChildren = m_children.size();
|
|
const size_t numParts = m_partList.notNull() ? m_partList->partCount() : 0;
|
|
|
|
if (numChildren > 0 || numParts > 1)
|
|
{
|
|
// View Frustum culling
|
|
if (cullSettings.isViewFrustumCullingEnabled())
|
|
{
|
|
if (camera.frustum().isOutside(m_boundingBox))
|
|
{
|
|
// No parts on this level (or below) are visible. So just return
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Pixel size culling
|
|
if (cullSettings.isPixelSizeCullingEnabled())
|
|
{
|
|
double area = camera.computeProjectedBoundingSpherePixelArea(m_boundingBox.center(), m_boundingBox.radius());
|
|
if (area < cullSettings.pixelSizeCullingAreaThreshold())
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
size_t i;
|
|
for (i = 0; i < numChildren; i++)
|
|
{
|
|
ModelBasicTreeNode* c = m_children[i];
|
|
CVF_ASSERT(c);
|
|
|
|
c->findVisibleParts(visibleParts, camera, cullSettings, enableMask);
|
|
}
|
|
|
|
if (m_partList.notNull())
|
|
{
|
|
m_partList->findVisibleParts(visibleParts, camera, cullSettings, enableMask);
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Get all parts in this node and all child nodes (recursive)
|
|
//--------------------------------------------------------------------------------------------------
|
|
void ModelBasicTreeNode::allParts(Collection<Part>* partCollection)
|
|
{
|
|
uint numChildren = childCount();
|
|
uint i;
|
|
for (i = 0; i < numChildren; i++)
|
|
{
|
|
ModelBasicTreeNode* c = child(i);
|
|
CVF_ASSERT(c);
|
|
|
|
c->allParts(partCollection);
|
|
}
|
|
|
|
if (m_partList.notNull())
|
|
{
|
|
m_partList->allParts(partCollection);
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Compute a ray intersection with all parts in this node and all child nodes (recursive)
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool ModelBasicTreeNode::rayIntersect(const RayIntersectSpec& rayIntersectSpec, HitItemCollection* hitItemCollection)
|
|
{
|
|
bool hit = false;
|
|
|
|
if (!m_boundingBox.isValid())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Early reject: Check if bounding box is hit
|
|
if (!rayIntersectSpec.ray()->boxIntersect(m_boundingBox))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint numChildren = childCount();
|
|
uint i;
|
|
for (i = 0; i < numChildren; i++)
|
|
{
|
|
ModelBasicTreeNode* c = child(i);
|
|
CVF_ASSERT(c);
|
|
|
|
hit |= c->rayIntersect(rayIntersectSpec, hitItemCollection);
|
|
}
|
|
|
|
if (m_partList.notNull())
|
|
{
|
|
hit |= m_partList->rayIntersect(rayIntersectSpec, hitItemCollection);
|
|
}
|
|
|
|
return hit;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Get the bounding box of this node
|
|
//--------------------------------------------------------------------------------------------------
|
|
const BoundingBox& ModelBasicTreeNode::boundingBox() const
|
|
{
|
|
return m_boundingBox;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns the first part found with the given ID. NULL if not found.
|
|
//--------------------------------------------------------------------------------------------------
|
|
Part* ModelBasicTreeNode::findPartByID(int id)
|
|
{
|
|
if (m_partList.notNull())
|
|
{
|
|
uint numParts = partCount();
|
|
uint i;
|
|
for (i = 0; i < numParts; i++)
|
|
{
|
|
Part* p = m_partList->part(i);
|
|
CVF_ASSERT(p);
|
|
|
|
if (p->id() == id)
|
|
{
|
|
return p;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint numChildren = childCount();
|
|
uint i;
|
|
for (i = 0; i < numChildren; i++)
|
|
{
|
|
ModelBasicTreeNode* c = child(i);
|
|
CVF_ASSERT(c);
|
|
|
|
Part* p = c->findPartByID(id);
|
|
|
|
if (p)
|
|
{
|
|
return p;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns the first part found with the given name. NULL if not found.
|
|
//--------------------------------------------------------------------------------------------------
|
|
Part* ModelBasicTreeNode::findPartByName(String name)
|
|
{
|
|
if (m_partList.notNull())
|
|
{
|
|
uint numParts = partCount();
|
|
uint i;
|
|
for (i = 0; i < numParts; i++)
|
|
{
|
|
Part* p = m_partList->part(i);
|
|
CVF_ASSERT(p);
|
|
|
|
if (p->name() == name)
|
|
{
|
|
return p;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint numChildren = childCount();
|
|
uint i;
|
|
for (i = 0; i < numChildren; i++)
|
|
{
|
|
ModelBasicTreeNode* c = child(i);
|
|
CVF_ASSERT(c);
|
|
|
|
Part* p = c->findPartByName(name);
|
|
|
|
if (p)
|
|
{
|
|
return p;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void ModelBasicTreeNode::mergeParts(double maxExtent, uint minimumPrimitiveCount)
|
|
{
|
|
uint numChildren = childCount();
|
|
|
|
std::vector<ModelBasicTreeNode*> childrenToBeRemoved;
|
|
|
|
uint i;
|
|
for (i = 0; i < numChildren; i++)
|
|
{
|
|
ModelBasicTreeNode* c = child(i);
|
|
CVF_ASSERT(c);
|
|
|
|
c->mergeParts(maxExtent, minimumPrimitiveCount);
|
|
|
|
// Devour any child node being too small.
|
|
// Any candidate child node for being devoured is a leaf node because we have already recursed downwards.
|
|
// Check if this is a leaf node
|
|
if (c->childCount() == 0)
|
|
{
|
|
size_t primCount = c->primitiveCount();
|
|
if (primCount < minimumPrimitiveCount)
|
|
{
|
|
size_t numChildParts = 0;
|
|
if (c->m_partList.notNull())
|
|
{
|
|
numChildParts = c->m_partList->partCount();
|
|
}
|
|
|
|
size_t j;
|
|
for (j = 0; j < numChildParts; j++)
|
|
{
|
|
addPart(c->m_partList->part(j));
|
|
}
|
|
|
|
childrenToBeRemoved.push_back(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (childrenToBeRemoved.size() > 0)
|
|
{
|
|
// Remove children from last to first index to make sure the indices are valid
|
|
std::vector<ModelBasicTreeNode*>::iterator it;
|
|
for (it = childrenToBeRemoved.begin(); it != childrenToBeRemoved.end(); it++)
|
|
{
|
|
removeChild(*it);
|
|
}
|
|
}
|
|
|
|
|
|
// Merge too small parts in own list of parts. Any child node being devoured by the above code is
|
|
// in own list of parts. They are too small, but will be merged also by the statement below.
|
|
m_partList->mergeParts(maxExtent, minimumPrimitiveCount);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Count primitives of part in this node - do not recurse
|
|
//--------------------------------------------------------------------------------------------------
|
|
size_t ModelBasicTreeNode::primitiveCount()
|
|
{
|
|
size_t totalPrimitiveCount = 0;
|
|
|
|
size_t j;
|
|
for (j = 0; j < m_partList->partCount(); j++)
|
|
{
|
|
Part* part = m_partList->part(j);
|
|
DrawableGeo* drawable = dynamic_cast<DrawableGeo*>(part->drawable());
|
|
if (drawable)
|
|
{
|
|
totalPrimitiveCount += drawable->faceCount();
|
|
}
|
|
}
|
|
|
|
return totalPrimitiveCount;
|
|
}
|
|
|
|
|
|
|
|
//==================================================================================================
|
|
///
|
|
/// \class cvf::ModelBasicTree
|
|
/// \ingroup Viewing
|
|
///
|
|
/// A simple model implementation using a tree.
|
|
///
|
|
//==================================================================================================
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Constructor
|
|
//--------------------------------------------------------------------------------------------------
|
|
ModelBasicTree::ModelBasicTree()
|
|
{
|
|
m_root = NULL;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Destructor
|
|
//--------------------------------------------------------------------------------------------------
|
|
ModelBasicTree::~ModelBasicTree()
|
|
{
|
|
delete m_root;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
String ModelBasicTree::name() const
|
|
{
|
|
return m_modelName;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void ModelBasicTree::setName(const String& name)
|
|
{
|
|
m_modelName = name;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Set the root node of the tree.
|
|
///
|
|
/// If set to NULL, all current nodes will be deleted.
|
|
//--------------------------------------------------------------------------------------------------
|
|
void ModelBasicTree::setRoot(ModelBasicTreeNode* root)
|
|
{
|
|
if (m_root != root)
|
|
{
|
|
delete m_root;
|
|
m_root = root;
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns a pointer to the root node.
|
|
//--------------------------------------------------------------------------------------------------
|
|
ModelBasicTreeNode* ModelBasicTree::root()
|
|
{
|
|
return m_root;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns a const pointer to the root node
|
|
//--------------------------------------------------------------------------------------------------
|
|
const ModelBasicTreeNode* ModelBasicTree::root() const
|
|
{
|
|
return m_root;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void ModelBasicTree::removePart(Part* part)
|
|
{
|
|
if (m_root)
|
|
{
|
|
m_root->removePart(part);
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Update the bounding boxes in the entire tree
|
|
//--------------------------------------------------------------------------------------------------
|
|
void ModelBasicTree::updateBoundingBoxesRecursive()
|
|
{
|
|
m_boundingBox.reset();
|
|
|
|
if (m_root)
|
|
{
|
|
m_root->updateBoundingBoxesRecursive();
|
|
m_boundingBox.add(m_root->boundingBox());
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns the bounding box of all parts in the tree
|
|
//--------------------------------------------------------------------------------------------------
|
|
BoundingBox ModelBasicTree::boundingBox() const
|
|
{
|
|
return m_boundingBox;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void ModelBasicTree::findVisibleParts(PartRenderHintCollection* visibleParts, const Camera& camera, const CullSettings& cullSettings, uint enableMask)
|
|
{
|
|
// Add in the model's enable mask before delegating to root node
|
|
uint combinedEnableMask = (partEnableMask() & enableMask);
|
|
|
|
if (m_root)
|
|
{
|
|
m_root->findVisibleParts(visibleParts, camera, cullSettings, combinedEnableMask);
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void ModelBasicTree::allParts(Collection<Part>* partCollection)
|
|
{
|
|
if (m_root)
|
|
{
|
|
m_root->allParts(partCollection);
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Intersect all parts in the model with the given ray.
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool ModelBasicTree::rayIntersect(const RayIntersectSpec& rayIntersectSpec, HitItemCollection* hitItemCollection)
|
|
{
|
|
if (!m_root)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return m_root->rayIntersect(rayIntersectSpec, hitItemCollection);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns the first part found with the given ID. NULL if not found.
|
|
//--------------------------------------------------------------------------------------------------
|
|
Part* ModelBasicTree::findPartByID(int id)
|
|
{
|
|
if (!m_root)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return m_root->findPartByID(id);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns the first part found with the given name. NULL if not found.
|
|
//--------------------------------------------------------------------------------------------------
|
|
Part* ModelBasicTree::findPartByName(String name)
|
|
{
|
|
if (!m_root)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return m_root->findPartByName(name);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void ModelBasicTree::mergeParts(double maxExtent, uint minimumPrimitiveCount)
|
|
{
|
|
if (m_root)
|
|
{
|
|
m_root->mergeParts(maxExtent, minimumPrimitiveCount);
|
|
}
|
|
}
|
|
|
|
|
|
} // namespace cvf
|
|
|