Initial commit of ResInsight version 0.4.8

This commit is contained in:
Alf B. Rustad
2012-05-18 09:45:23 +02:00
parent a680bf941e
commit dfe97efb1b
657 changed files with 176690 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
cmake_minimum_required(VERSION 2.8)
project(LibGeometry)
# Use our strict compile flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CEE_STRICT_CXX_FLAGS}")
include_directories(../LibCore)
set(CEE_HEADER_FILES
cvfArrowGenerator.h
cvfBoundingBox.h
cvfBoxGenerator.h
cvfEdgeKey.h
cvfFrustum.h
cvfGeometryBuilder.h
cvfGeometryBuilderFaceList.h
cvfGeometryBuilderTriangles.h
cvfGeometryUtils.h
cvfLibGeometry.h
cvfMeshEdgeExtractor.h
cvfOutlineEdgeExtractor.h
cvfPatchGenerator.h
cvfRay.h
cvfTriangleMeshEdgeExtractor.h
cvfTriangleVertexSplitter.h
cvfVertexCompactor.h
cvfVertexWelder.h
)
set(CEE_SOURCE_FILES
cvfArrowGenerator.cpp
cvfBoundingBox.cpp
cvfBoxGenerator.cpp
cvfFrustum.cpp
cvfEdgeKey.cpp
cvfGeometryBuilder.cpp
cvfGeometryBuilderFaceList.cpp
cvfGeometryBuilderTriangles.cpp
cvfGeometryUtils.cpp
cvfMeshEdgeExtractor.cpp
cvfOutlineEdgeExtractor.cpp
cvfPatchGenerator.cpp
cvfRay.cpp
cvfTriangleMeshEdgeExtractor.cpp
cvfTriangleVertexSplitter.cpp
cvfVertexCompactor.cpp
cvfVertexWelder.cpp
)
add_library(${PROJECT_NAME} ${CEE_HEADER_FILES} ${CEE_SOURCE_FILES})

View File

@@ -0,0 +1,100 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfArrowGenerator.h"
#include "cvfGeometryUtils.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::ArrowGenerator
/// \ingroup Geometry
///
/// Creates an arrow starting in origin and pointing in the direction of the +Z axis
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ArrowGenerator::ArrowGenerator()
: m_shaftRelativeRadius(0.025f),
m_headRelativeRadius(0.085f),
m_headRelativeLength(0.25f),
m_numSlices(20)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ArrowGenerator::setShaftRelativeRadius(float shaftRelativeRadius)
{
m_shaftRelativeRadius = shaftRelativeRadius;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ArrowGenerator::setHeadRelativeRadius(float headRelativeRadius)
{
m_headRelativeRadius = headRelativeRadius;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ArrowGenerator::setHeadRelativeLength(float headRelativeLength)
{
m_headRelativeLength = headRelativeLength;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ArrowGenerator::setNumSlices(uint numSlices)
{
m_numSlices = numSlices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void ArrowGenerator::generate(GeometryBuilder* builder)
{
const uint numPolysZDir = 1;
GeometryUtils::createObliqueCylinder(m_shaftRelativeRadius, m_shaftRelativeRadius, 1.0f - m_headRelativeLength, 0, 0, m_numSlices, true, true, false, numPolysZDir, builder);
uint startIdx = builder->vertexCount();
GeometryUtils::createCone(m_headRelativeRadius, m_headRelativeLength, m_numSlices, true, true, true, builder);
uint endIdx = builder->vertexCount() - 1;
Mat4f mat = Mat4f::fromTranslation(Vec3f(0, 0, 1.0f - m_headRelativeLength));
builder->transformVertexRange(startIdx, endIdx, mat);
}
} // namespace cvf

View File

@@ -0,0 +1,52 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
namespace cvf {
class GeometryBuilder;
//==================================================================================================
//
// Generates an arrow with base in origin and pointing in the +Z direction
//
//==================================================================================================
class ArrowGenerator
{
public:
ArrowGenerator();
void setShaftRelativeRadius(float shaftRelativeRadius);
void setHeadRelativeRadius(float headRelativeRadius);
void setHeadRelativeLength(float headRelativeLength);
void setNumSlices(uint numSlices);
void generate(GeometryBuilder* builder);
private:
float m_shaftRelativeRadius;
float m_headRelativeRadius;
float m_headRelativeLength;
uint m_numSlices;
};
}

View File

@@ -0,0 +1,401 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfBoundingBox.h"
#include "cvfString.h"
#include <limits>
namespace cvf {
//==================================================================================================
///
/// \class cvf::BoundingBox
/// \ingroup Geometry
///
/// The BoundingBox class implements an axis-aligned bounding box.
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
BoundingBox::BoundingBox()
{
reset();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
BoundingBox::BoundingBox(const Vec3d& min, const Vec3d& max)
: m_min(min), m_max(max)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
BoundingBox::BoundingBox(const Vec3f& min, const Vec3f& max)
: m_min(min), m_max(max)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
BoundingBox::BoundingBox(const BoundingBox& other)
: m_min(other.m_min),
m_max(other.m_max)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
BoundingBox& BoundingBox::operator=(const BoundingBox& rhs)
{
m_min = rhs.m_min;
m_max = rhs.m_max;
return *this;
}
//--------------------------------------------------------------------------------------------------
/// Initialize bounding box
//--------------------------------------------------------------------------------------------------
void BoundingBox::reset()
{
const double maxDouble = std::numeric_limits<double>::max();
m_max.set(-maxDouble, -maxDouble, -maxDouble);
m_min.set( maxDouble, maxDouble, maxDouble);
}
//--------------------------------------------------------------------------------------------------
/// Returns false if no input has been given
//--------------------------------------------------------------------------------------------------
bool BoundingBox::isValid() const
{
if (m_min.x() <= m_max.x() &&
m_min.y() <= m_max.y() &&
m_min.z() <= m_max.z())
{
return true;
}
else
{
return false;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void BoundingBox::add(const Vec3d& point)
{
if (point.x() < m_min.x()) m_min.x() = point.x();
if (point.y() < m_min.y()) m_min.y() = point.y();
if (point.z() < m_min.z()) m_min.z() = point.z();
if (point.x() > m_max.x()) m_max.x() = point.x();
if (point.y() > m_max.y()) m_max.y() = point.y();
if (point.z() > m_max.z()) m_max.z() = point.z();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void BoundingBox::add(const Vec3f& point)
{
if (point.x() < m_min.x()) m_min.x() = point.x();
if (point.y() < m_min.y()) m_min.y() = point.y();
if (point.z() < m_min.z()) m_min.z() = point.z();
if (point.x() > m_max.x()) m_max.x() = point.x();
if (point.y() > m_max.y()) m_max.y() = point.y();
if (point.z() > m_max.z()) m_max.z() = point.z();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void BoundingBox::add(const Vec3dArray& points)
{
size_t i;
for (i = 0; i < points.size(); i++)
{
add(points[i]);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void BoundingBox::add(const Vec3fArray& points)
{
size_t i;
for (i = 0; i < points.size(); i++)
{
add(points[i]);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void BoundingBox::add(const BoundingBox& bb)
{
if (bb.isValid())
{
add(bb.min());
add(bb.max());
}
}
//--------------------------------------------------------------------------------------------------
/// Computes center of the bounding box
//--------------------------------------------------------------------------------------------------
Vec3d BoundingBox::center() const
{
CVF_TIGHT_ASSERT(isValid());
return (m_min + m_max) / 2.0;
}
//--------------------------------------------------------------------------------------------------
/// Computes the total size of the bounding box
//--------------------------------------------------------------------------------------------------
Vec3d BoundingBox::extent() const
{
CVF_TIGHT_ASSERT(isValid());
return (m_max - m_min);
}
//--------------------------------------------------------------------------------------------------
/// Compute radius as half the length of the box's diagonal
//--------------------------------------------------------------------------------------------------
double BoundingBox::radius() const
{
CVF_TIGHT_ASSERT(isValid());
return extent().length() / 2.0;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const Vec3d& BoundingBox::min() const
{
CVF_TIGHT_ASSERT(isValid());
return m_min;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const Vec3d& BoundingBox::max() const
{
CVF_TIGHT_ASSERT(isValid());
return m_max;
}
//--------------------------------------------------------------------------------------------------
/// Check if the bounding box contains the specified point
///
/// Note that a point on the box's surface is classified as being contained
//--------------------------------------------------------------------------------------------------
bool BoundingBox::contains(const Vec3d& point) const
{
CVF_TIGHT_ASSERT(isValid());
if (point.x() >= m_min.x() && point.x() <= m_max.x() &&
point.y() >= m_min.y() && point.y() <= m_max.y() &&
point.z() >= m_min.z() && point.z() <= m_max.z())
{
return true;
}
else
{
return false;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool BoundingBox::intersects(const BoundingBox& box) const
{
CVF_TIGHT_ASSERT(isValid());
CVF_TIGHT_ASSERT(box.isValid());
if (m_max.x() < box.m_min.x() || m_min.x() > box.m_max.x()) return false;
if (m_max.y() < box.m_min.y() || m_min.y() > box.m_max.y()) return false;
if (m_max.z() < box.m_min.z() || m_min.z() > box.m_max.z()) return false;
return true;
}
//--------------------------------------------------------------------------------------------------
/// Get corner points of box
///
/// \param corners Array of Vec3d. Must be allocated 8 vectors long.
///
/// <PRE>
/// 7---------6
/// /| /| |z
/// / | / | | / y
/// 4---------5 | |/
/// | 3------|--2 *---x
/// | / | /
/// |/ |/
/// 0---------1 </PRE>
///
//--------------------------------------------------------------------------------------------------
void BoundingBox::cornerVertices(Vec3d corners[8]) const
{
corners[0].set(m_min.x(), m_min.y(), m_min.z());
corners[1].set(m_max.x(), m_min.y(), m_min.z());
corners[2].set(m_max.x(), m_max.y(), m_min.z());
corners[3].set(m_min.x(), m_max.y(), m_min.z());
corners[4].set(m_min.x(), m_min.y(), m_max.z());
corners[5].set(m_max.x(), m_min.y(), m_max.z());
corners[6].set(m_max.x(), m_max.y(), m_max.z());
corners[7].set(m_min.x(), m_max.y(), m_max.z());
}
//--------------------------------------------------------------------------------------------------
/// Expands the bounding box by the given amount in all three directions
///
/// If a bounding box is expanded by 2, the bounding box's size will increase by 2 in each direction
/// \sa extent()
//--------------------------------------------------------------------------------------------------
void BoundingBox::expand(double amount)
{
double half = amount/2;
m_min.x() -= half;
m_min.y() -= half;
m_min.z() -= half;
m_max.x() += half;
m_max.y() += half;
m_max.z() += half;
}
//--------------------------------------------------------------------------------------------------
/// Transform the min and max coordinate with the given transformation matrix
//--------------------------------------------------------------------------------------------------
void BoundingBox::transform(const Mat4d& matrix)
{
// Check if box is invalid, and don't transform if so
if (!isValid()) return;
BoundingBox newBox;
newBox.reset();
Vec3d node;
node.set(m_min.x(), m_min.y(), m_min.z());
node.transformPoint(matrix);
newBox.add(node);
node.set(m_max.x(), m_min.y(), m_min.z());
node.transformPoint(matrix);
newBox.add(node);
node.set(m_max.x(), m_max.y(), m_min.z());
node.transformPoint(matrix);
newBox.add(node);
node.set(m_min.x(), m_max.y(), m_min.z());
node.transformPoint(matrix);
newBox.add(node);
node.set(m_min.x(), m_min.y(), m_max.z());
node.transformPoint(matrix);
newBox.add(node);
node.set(m_max.x(), m_min.y(), m_max.z());
node.transformPoint(matrix);
newBox.add(node);
node.set(m_max.x(), m_max.y(), m_max.z());
node.transformPoint(matrix);
newBox.add(node);
node.set(m_min.x(), m_max.y(), m_max.z());
node.transformPoint(matrix);
newBox.add(node);
*this = newBox;
}
//--------------------------------------------------------------------------------------------------
/// Returns this BoundingBox transformed with the given transformation matrix
//--------------------------------------------------------------------------------------------------
const BoundingBox BoundingBox::getTransformed(const Mat4d& matrix) const
{
BoundingBox box(*this);
box.transform(matrix);
return box;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
String BoundingBox::toString() const
{
String str = "BoundingBox:";
str += " min: x=" + String::number(m_min.x()) + " y=" + String::number(m_min.y()) + " z=" + String::number(m_min.z());
str += " max: x=" + String::number(m_max.x()) + " y=" + String::number(m_max.y()) + " z=" + String::number(m_max.z());
return str;
}
} // namespace cvf

View File

@@ -0,0 +1,77 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
#include "cvfArray.h"
#include "cvfMatrix4.h"
#include "cvfString.h"
namespace cvf {
//==================================================================================================
//
// Axis aligned bounding box
//
//==================================================================================================
class BoundingBox
{
public:
BoundingBox();
BoundingBox(const Vec3f& min, const Vec3f& max);
BoundingBox(const Vec3d& min, const Vec3d& max);
BoundingBox(const BoundingBox& other);
BoundingBox& operator=(const BoundingBox& rhs);
void reset();
bool isValid() const;
void add(const Vec3f& vertex);
void add(const Vec3d& vertex);
void add(const Vec3fArray& vertices);
void add(const Vec3dArray& vertices);
void add(const BoundingBox& bb);
const Vec3d& min() const;
const Vec3d& max() const;
Vec3d center() const;
Vec3d extent() const;
double radius() const;
bool contains(const Vec3d& point) const;
bool intersects(const BoundingBox& box) const;
void cornerVertices(Vec3d corners[8]) const;
void expand(double amount);
void transform(const Mat4d& matrix);
const BoundingBox getTransformed(const Mat4d& matrix) const;
String toString() const;
private:
Vec3d m_min;
Vec3d m_max;
};
}

View File

@@ -0,0 +1,173 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfBoxGenerator.h"
#include "cvfPatchGenerator.h"
#include "cvfGeometryUtils.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::BoxGenerator
/// \ingroup Geometry
///
/// Generates axis aligned box
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
/// Default constructor
///
/// Will generate a box with one corner in (0,0,0) and the other corner in (1,1,1).
/// Tesselation will be done using one quad for each of the box's six faces.
//--------------------------------------------------------------------------------------------------
BoxGenerator::BoxGenerator()
: m_minCoord(0, 0, 0),
m_maxCoord(1, 1, 1),
m_subdivisions(1, 1, 1)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void BoxGenerator::setMinMax(const Vec3d& minCoord, const Vec3d& maxCoord)
{
m_minCoord = minCoord;
m_maxCoord = maxCoord;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void BoxGenerator::setOriginAndExtent(const Vec3d& origin, const Vec3d& extent)
{
m_minCoord = origin;
m_maxCoord = origin + extent;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void BoxGenerator::setCenterAndExtent(const Vec3d& center, const Vec3d& extent)
{
m_minCoord = center - extent/2;
m_maxCoord = center + extent/2;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void BoxGenerator::setSubdivisions(uint subdivX, uint subdivY, uint subdivZ)
{
CVF_ASSERT(subdivX > 0);
CVF_ASSERT(subdivY > 0);
CVF_ASSERT(subdivZ > 0);
m_subdivisions.set(subdivX, subdivY, subdivZ);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void BoxGenerator::generate(GeometryBuilder* builder)
{
uint cellCountX = m_subdivisions.x();
uint cellCountY = m_subdivisions.y();
uint cellCountZ = m_subdivisions.z();
CVF_ASSERT(cellCountX > 0);
CVF_ASSERT(cellCountY > 0);
CVF_ASSERT(cellCountZ > 0);
if (cellCountX == 1 && cellCountY == 1 && cellCountZ == 1)
{
GeometryUtils::createBox(Vec3f(m_minCoord), Vec3f(m_maxCoord), builder);
return;
}
// Face ordering is
//
// *---------* Faces:
// /| /| |z 0 bottom
// / | / | | /y 1 top
// *---------* | |/ 2 front
// | 3------|--* *---x 3 right
// | / | / 4 back
// |/ |/ 5 left
// *---------*
const Vec3d extent(m_maxCoord - m_minCoord);
PatchGenerator patchGen;
// Bottom
patchGen.setOrigin(Vec3d(m_minCoord.x(), m_minCoord.y(), m_minCoord.z()));
patchGen.setAxes(Vec3d::Y_AXIS, Vec3d::X_AXIS);
patchGen.setExtent(extent.y(), extent.x());
patchGen.setSubdivisions(cellCountY, cellCountX);
patchGen.generate(builder);
// Top
patchGen.setOrigin(Vec3d(m_minCoord.x(), m_minCoord.y(), m_maxCoord.z()));
patchGen.setAxes(Vec3d::X_AXIS, Vec3d::Y_AXIS);
patchGen.setExtent(extent.x(), extent.y());
patchGen.setSubdivisions(cellCountX, cellCountY);
patchGen.generate(builder);
// Front
patchGen.setOrigin(Vec3d(m_minCoord.x(), m_minCoord.y(), m_minCoord.z()));
patchGen.setAxes(Vec3d::X_AXIS, Vec3d::Z_AXIS);
patchGen.setExtent(extent.x(), extent.z());
patchGen.setSubdivisions(cellCountX, cellCountZ);
patchGen.generate(builder);
// Right
patchGen.setOrigin(Vec3d(m_maxCoord.x(), m_minCoord.y(), m_minCoord.z()));
patchGen.setAxes(Vec3d::Y_AXIS, Vec3d::Z_AXIS);
patchGen.setExtent(extent.y(), extent.z());
patchGen.setSubdivisions(cellCountY, cellCountZ);
patchGen.generate(builder);
// Back
patchGen.setOrigin(Vec3d(m_maxCoord.x(), m_maxCoord.y(), m_minCoord.z()));
patchGen.setAxes(-Vec3d::X_AXIS, Vec3d::Z_AXIS);
patchGen.setExtent(extent.x(), extent.z());
patchGen.setSubdivisions(cellCountX, cellCountZ);
patchGen.generate(builder);
// Left
patchGen.setOrigin(Vec3d(m_minCoord.x(), m_maxCoord.y(), m_minCoord.z()));
patchGen.setAxes(-Vec3d::Y_AXIS, Vec3d::Z_AXIS);
patchGen.setExtent(extent.y(), extent.z());
patchGen.setSubdivisions(cellCountY, cellCountZ);
patchGen.generate(builder);
}
} // namespace cvf

View File

@@ -0,0 +1,54 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
#include "cvfVector3.h"
namespace cvf {
class GeometryBuilder;
//==================================================================================================
//
// Generates an axis aligned box
//
//==================================================================================================
class BoxGenerator
{
public:
BoxGenerator();
void setMinMax(const Vec3d& minCoord, const Vec3d& maxCoord);
void setOriginAndExtent(const Vec3d& origin, const Vec3d& extent);
void setCenterAndExtent(const Vec3d& center, const Vec3d& extent);
void setSubdivisions(uint subdivX, uint subdivY, uint subdivZ);
void generate(GeometryBuilder* builder);
private:
Vec3d m_minCoord;
Vec3d m_maxCoord;
Vec3ui m_subdivisions; // Number of cells/quads in each direction. Default (1, 1, 1)
};
}

View File

@@ -0,0 +1,112 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfEdgeKey.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::EdgeKey
/// \ingroup Geometry
///
///
///
//==================================================================================================
EdgeKey::EdgeKey(uint vertexIdx1, uint vertexIdx2)
{
if (vertexIdx1 <= vertexIdx2)
{
m_vertexIdx1 = vertexIdx1;
m_vertexIdx2 = vertexIdx2;
}
else
{
m_vertexIdx1 = vertexIdx2;
m_vertexIdx2 = vertexIdx1;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool EdgeKey::operator==(const EdgeKey& rhs) const
{
if (m_vertexIdx1 == rhs.m_vertexIdx1 && m_vertexIdx2 == rhs.m_vertexIdx2)
{
return true;
}
else
{
return false;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool EdgeKey::operator<(const EdgeKey& rhs) const
{
if (m_vertexIdx1 == rhs.m_vertexIdx1)
{
return (m_vertexIdx2 < rhs.m_vertexIdx2);
}
else
{
return (m_vertexIdx1 < rhs.m_vertexIdx1);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int64 EdgeKey::toKeyVal() const
{
int64 edgeKey = m_vertexIdx1;
edgeKey <<= 32;
edgeKey += m_vertexIdx2;
return edgeKey;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
EdgeKey EdgeKey::fromkeyVal(int64 edgeKeyVal)
{
uint vertexIdx2 = static_cast<uint>(edgeKeyVal);
edgeKeyVal >>= 32;
uint vertexIdx1 = static_cast<uint>(edgeKeyVal);
return EdgeKey(vertexIdx1, vertexIdx2);
}
} // namespace cvf

View File

@@ -0,0 +1,53 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
namespace cvf {
//==================================================================================================
//
//
//
//==================================================================================================
class EdgeKey
{
public:
EdgeKey(uint vertexIdx1, uint vertexIdx2);
bool operator==(const EdgeKey& rhs) const;
bool operator<(const EdgeKey& rhs) const;
uint index1() const { return m_vertexIdx1; }
uint index2() const { return m_vertexIdx2; }
int64 toKeyVal() const;
static EdgeKey fromkeyVal(int64 edgeKeyVal);
private:
uint m_vertexIdx1; // The constructor ensures that index 1 is always the smallest
uint m_vertexIdx2; // of the two indices
};
}

View File

@@ -0,0 +1,213 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfBoundingBox.h"
#include "cvfFrustum.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::Frustum
/// \ingroup Geometry
///
/// Class defining a frustum
///
/// The frustum consists of 6 \link Plane Planes\endlink
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
/// Default constructor
//--------------------------------------------------------------------------------------------------
Frustum::Frustum()
{
}
//--------------------------------------------------------------------------------------------------
/// Copy constructor
//--------------------------------------------------------------------------------------------------
Frustum::Frustum(const Frustum& other)
: Object()
{
*this = other;
}
//--------------------------------------------------------------------------------------------------
/// Destructor
//--------------------------------------------------------------------------------------------------
Frustum::~Frustum()
{
}
//--------------------------------------------------------------------------------------------------
/// Assignment operator
//--------------------------------------------------------------------------------------------------
const Frustum& Frustum::operator=(const Frustum& rhs)
{
m_planes.clear();
std::map<int, Plane>::const_iterator it;
for (it = rhs.m_planes.begin(); it != rhs.m_planes.end(); it++)
{
m_planes[it->first] = it->second;
}
return *this;
}
//--------------------------------------------------------------------------------------------------
/// Equality operator
//--------------------------------------------------------------------------------------------------
bool Frustum::operator==(const Frustum& rhs) const
{
if (m_planes.size() != rhs.m_planes.size()) return false;
std::map<int, Plane>::const_iterator thisIt, rhsIt;
size_t i;
for (i = 0; i < m_planes.size(); i++)
{
int sideIdx = static_cast<int>(i);
thisIt = m_planes.find(sideIdx);
rhsIt = rhs.m_planes.find(sideIdx);
if (thisIt->first != rhsIt->first) return false;
if (thisIt->second != rhsIt->second) return false;
}
return true;
}
//--------------------------------------------------------------------------------------------------
/// Inequality operator
//--------------------------------------------------------------------------------------------------
bool Frustum::operator!=(const Frustum& rhs) const
{
return !operator==(rhs);
}
//--------------------------------------------------------------------------------------------------
/// Set one of the planes building up the frustum
//--------------------------------------------------------------------------------------------------
void Frustum::setPlane(Side side, const Plane& plane)
{
CVF_ASSERT(side < COUNT);
CVF_ASSERT(plane.isValid());
m_planes[side] = plane;
}
//--------------------------------------------------------------------------------------------------
/// Get one given Plane of the frustum.
///
/// \return The Plane queried or an invalid Plane if it does not exist.
//--------------------------------------------------------------------------------------------------
Plane Frustum::plane(Side side) const
{
std::map<int, Plane>::const_iterator it = m_planes.find(side);
return (it != m_planes.end()) ? it->second : Plane();
}
//--------------------------------------------------------------------------------------------------
/// Transforms all planes in the frustum with the given matrix
//--------------------------------------------------------------------------------------------------
void Frustum::transform(const Mat4d& matrix)
{
std::map<int, Plane>::iterator it;
for (it = m_planes.begin(); it != m_planes.end(); it++)
{
it->second.transform(matrix);
}
}
//--------------------------------------------------------------------------------------------------
/// Test point to see if it's outside the frustum or not
///
/// \return true if outside or exactly on the boundary. false if inside.
//--------------------------------------------------------------------------------------------------
bool Frustum::isOutside(const Vec3d& point) const
{
CVF_ASSERT(m_planes.size() == 6);
std::map<int, Plane>::const_iterator it;
for (it = m_planes.begin(); it != m_planes.end(); it++)
{
if (it->second.distanceSquared(point) < 0.0)
{
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
/// Test bounding box to see if it's outside the frustum or not
///
/// \return true if outside or exactly on the boundary. false if inside.
//--------------------------------------------------------------------------------------------------
bool Frustum::isOutside(const BoundingBox& bbox) const
{
CVF_ASSERT(m_planes.size() == 6);
const Vec3d& boxMin = bbox.min();
const Vec3d& boxMax = bbox.max();
Vec3d point;
Vec3d planeNormal;
std::map<int, Plane>::const_iterator it;
for (it = m_planes.begin(); it != m_planes.end(); it++)
{
planeNormal = it->second.normal();
point.x() = (planeNormal.x() <= 0.0) ? boxMin.x() : boxMax.x();
point.y() = (planeNormal.y() <= 0.0) ? boxMin.y() : boxMax.y();
point.z() = (planeNormal.z() <= 0.0) ? boxMin.z() : boxMax.z();
if (it->second.distanceSquared(point) < 0.0)
{
return true;
}
}
return false;
}
} // namespace cvf

View File

@@ -0,0 +1,73 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
#include "cvfObject.h"
#include "cvfPlane.h"
#include <map>
namespace cvf {
class BoundingBox;
//=================================================================================================
//
// Frustum class
//
//=================================================================================================
class Frustum : public Object
{
public:
/// Sides of the frustum
enum Side
{
BOTTOM = 0, // Index based -> Must start with zero
TOP,
LEFT,
RIGHT,
FRONT,
BACK,
COUNT ///< Number of sides
};
public:
Frustum();
Frustum(const Frustum& other);
~Frustum();
const Frustum& operator=(const Frustum& other);
bool operator==(const Frustum& other) const;
bool operator!=(const Frustum& other) const;
void setPlane(Side side, const Plane& plane);
Plane plane(Side side) const;
void transform(const Mat4d& matrix);
bool isOutside(const Vec3d& point) const;
bool isOutside(const BoundingBox& bbox) const;
private:
std::map<int, Plane> m_planes;
};
}

View File

@@ -0,0 +1,347 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfGeometryBuilder.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::GeometryBuilder
/// \ingroup Geometry
///
/// Abstract base class for building geometry using the Builder pattern.
/// \sa GeometryUtils
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void GeometryBuilder::setTotalVertexCountHint(size_t totalVertexCountHint)
{
CVF_UNUSED(totalVertexCountHint);
// Nothing here, may be used in derived classes
}
//--------------------------------------------------------------------------------------------------
/// \fn virtual int GeometryBuilder::addVertices(const Vec3fArray& vertices) = 0;
///
/// Add vertex coordinates
///
/// \return The resulting index of the first vertex in the \a vertices array.
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
/// \fn virtual int GeometryBuilder::addTriangle(int i0, int i1, int i2) = 0;
///
/// Add a single triangle by specifying the indices into the vertex array.
///
/// \sa addTriangles()
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
/// Add multiple triangles
///
/// \remarks There must be at least 3 entries in the \a indices array, and the total number of
/// entries must be a multiple of 3.
//--------------------------------------------------------------------------------------------------
void GeometryBuilder::addTriangles(const UIntArray& indices)
{
size_t numIndices = indices.size();
CVF_ASSERT(numIndices >= 3);
CVF_ASSERT(numIndices % 3 == 0);
size_t numTriangles = numIndices/3;
CVF_ASSERT(numTriangles >= 1);
CVF_ASSERT(3*numTriangles == numIndices);
size_t i;
for (i = 0; i < numTriangles; i++)
{
addTriangle(indices[3*i], indices[3*i + 1], indices[3*i + 2]);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void GeometryBuilder::addTriangles(const IntArray& indices)
{
size_t numIndices = indices.size();
CVF_ASSERT(numIndices >= 3);
CVF_ASSERT(numIndices % 3 == 0);
size_t numTriangles = numIndices/3;
CVF_ASSERT(numTriangles >= 1);
CVF_ASSERT(3*numTriangles == numIndices);
size_t i;
for (i = 0; i < numTriangles; i++)
{
CVF_ASSERT(indices[3*i] >= 0 && indices[3*i + 1] && indices[3*i + 2]);
addTriangle(static_cast<uint>(indices[3*i]), static_cast<uint>(indices[3*i + 1]), static_cast<uint>(indices[3*i + 2]));
}
}
//--------------------------------------------------------------------------------------------------
/// Add a triangle fan
///
/// Vertex ordering for triangle fans:
/// <PRE>
/// v4 *-------* v3 Resulting triangles:
/// \ / \ t1: v0, v1, v2
/// \ / \ t2: v0, v2, v3
/// \ / \ t3: v0, v3, v4
/// v0 *-------* v2
/// \ /
/// \ /
/// \ /
/// * v1 </PRE>
///
/// \remarks The number of entries in the \a indices array must be at least 3.
//--------------------------------------------------------------------------------------------------
void GeometryBuilder::addTriangleFan(const UIntArray& indices)
{
size_t numIndices = indices.size();
CVF_ASSERT(numIndices >= 3);
size_t numTriangles = numIndices - 2;
CVF_ASSERT(numTriangles >= 1);
size_t i;
for (i = 0; i < numTriangles; i++)
{
addTriangle(indices[0], indices[i + 1], indices[i + 2]);
}
}
//--------------------------------------------------------------------------------------------------
/// Add a triangle strip
///
/// Vertex ordering for triangle strips:
/// <PRE>
/// v0 v2 v4 Resulting triangles:
/// *-------*-------* t1: v0, v1, v2
/// \ / \ / \ t2: v2, v1, v3
/// \ / \ / \ t3: v2, v3, v4
/// \ / \ / \ t4: v4, v3, v5
/// *-------*-------*
/// v1 v3 v5 </PRE>
///
/// \remarks The number of entries in the \a indices array must be at least 3.
//--------------------------------------------------------------------------------------------------
void GeometryBuilder::addTriangleStrip(const UIntArray& indices)
{
size_t numIndices = indices.size();
CVF_ASSERT(numIndices >= 3);
size_t numTriangles = numIndices - 2;
CVF_ASSERT(numTriangles >= 1);
size_t i;
for (i = 0; i < numTriangles; i++)
{
if (i % 2 == 0)
{
addTriangle(indices[i], indices[i + 1], indices[i + 2]);
}
else
{
addTriangle(indices[i + 1], indices[i], indices[i + 2]);
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void GeometryBuilder::addTriangleByVertices(const Vec3f& v0, const Vec3f& v1, const Vec3f& v2)
{
Vec3fArray verts;
verts.resize(3);
verts[0] = v0;
verts[1] = v1;
verts[2] = v2;
uint firstVertexIdx = addVertices(verts);
addTriangle(firstVertexIdx, firstVertexIdx + 1, firstVertexIdx + 2);
}
//--------------------------------------------------------------------------------------------------
/// Add a single quad by specifying the indices into the vertex array
///
/// The default implementation will split the quad into two triangles (i0,i1,i2 and i0,i2,i3) and
/// add them using addTriangle().
///
/// \sa addTriangle(), addQuads()
//--------------------------------------------------------------------------------------------------
void GeometryBuilder::addQuad(uint i0, uint i1, uint i2, uint i3)
{
addTriangle(i0, i1, i2);
addTriangle(i0, i2, i3);
}
//--------------------------------------------------------------------------------------------------
/// Add multiple quads
///
/// The default implementation utilizes addQuad() to add each quad separately.
///
/// \remarks There must be at least 4 entries in the \a indices array, and the total number of
/// entries must be a multiple of 4.
//--------------------------------------------------------------------------------------------------
void GeometryBuilder::addQuads(const UIntArray& indices)
{
size_t numIndices = indices.size();
CVF_ASSERT(numIndices >= 4);
CVF_ASSERT(numIndices % 4 == 0);
size_t numQuads = numIndices/4;
CVF_ASSERT(numQuads >= 1);
CVF_ASSERT(4*numQuads == numIndices);
size_t i;
for (i = 0; i < numQuads; i++)
{
addQuad(indices[4*i], indices[4*i + 1], indices[4*i + 2], indices[4*i + 3]);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void GeometryBuilder::addQuads(const IntArray& indices)
{
size_t numIndices = indices.size();
CVF_ASSERT(numIndices >= 4);
CVF_ASSERT(numIndices % 4 == 0);
size_t numQuads = numIndices/4;
CVF_ASSERT(numQuads >= 1);
CVF_ASSERT(4*numQuads == numIndices);
size_t i;
for (i = 0; i < numQuads; i++)
{
CVF_ASSERT(indices[4*i] >= 0 && indices[4*i + 1] && indices[4*i + 2] && indices[4*i + 3]);
addQuad(static_cast<uint>(indices[4*i]), static_cast<uint>(indices[4*i + 1]), static_cast<uint>(indices[4*i + 2]), static_cast<uint>(indices[4*i + 3]));
}
}
//--------------------------------------------------------------------------------------------------
/// Add a quad strip
///
/// Vertex ordering for quad strips:
/// <PRE>
/// v0 v2 v4 v6 Resulting quads:
/// *-----*-----*-----* q1: v0, v1, v3, v2
/// | | | | q2: v2, v3, v5, v4
/// | | | | q3: v4, v5, v7, v6
/// | | | |
/// *-----*-----*-----*
/// v1 v3 v5 v7 </PRE>
///
/// \remarks There must be at least 4 entries in the \a indices array, and the total number of
/// entries must be a multiple of 2.
//--------------------------------------------------------------------------------------------------
void GeometryBuilder::addQuadStrip(const UIntArray& indices)
{
size_t numIndices = indices.size();
CVF_ASSERT(numIndices >= 4);
CVF_ASSERT(numIndices % 2 == 0);
size_t numQuads = (numIndices - 2)/2;
CVF_ASSERT(numQuads >= 1);
size_t i;
for (i = 0; i < numQuads; i++)
{
addQuad(indices[2*i], indices[2*i + 1], indices[2*i + 3], indices[2*i + 2]);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void GeometryBuilder::addQuadByVertices(const Vec3f& v0, const Vec3f& v1, const Vec3f& v2, const Vec3f& v3)
{
Vec3fArray verts;
verts.resize(4);
verts[0] = v0;
verts[1] = v1;
verts[2] = v2;
verts[3] = v3;
uint firstVertexIdx = addVertices(verts);
addQuad(firstVertexIdx, firstVertexIdx + 1, firstVertexIdx + 2, firstVertexIdx + 3);
}
//--------------------------------------------------------------------------------------------------
/// Add one face
///
/// The type of primitive added will be determined from the number of indices passed in \a indices
///
/// \remarks Currently, points and lines are not supported. Faces with more than 4 indices will
/// be triangulated using fanning
//--------------------------------------------------------------------------------------------------
void GeometryBuilder::addFace(const UIntArray& indices)
{
size_t numIndices = indices.size();
CVF_ASSERT(numIndices >= 3);
if (numIndices == 3)
{
addTriangle(indices[0], indices[1], indices[2]);
}
else if (numIndices == 4)
{
addQuad(indices[0], indices[1], indices[2], indices[3]);
}
else
{
size_t numTriangles = numIndices - 2;
size_t i;
for (i = 0; i < numTriangles; i++)
{
addTriangle(indices[0], indices[i + 1], indices[i + 2]);
}
}
}
} // namespace cvf

View File

@@ -0,0 +1,61 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
#include "cvfObject.h"
#include "cvfArray.h"
#include "cvfMatrix4.h"
namespace cvf {
//==================================================================================================
//
// Abstract base class for building geometry using the Builder pattern
//
//==================================================================================================
class GeometryBuilder : public Object
{
public:
virtual void setTotalVertexCountHint(size_t totalVertexCountHint);
virtual uint addVertices(const Vec3fArray& vertices) = 0;
virtual uint vertexCount() const = 0;
virtual void transformVertexRange(uint startIdx, uint endIdx, const Mat4f& mat) = 0;
virtual void addTriangle(uint i0, uint i1, uint i2) = 0;
virtual void addTriangles(const UIntArray& indices);
virtual void addTriangles(const IntArray& indices);
virtual void addTriangleFan(const UIntArray& indices);
virtual void addTriangleStrip(const UIntArray& indices);
virtual void addTriangleByVertices(const Vec3f& v0, const Vec3f& v1, const Vec3f& v2);
virtual void addQuad(uint i0, uint i1, uint i2, uint i3);
virtual void addQuads(const UIntArray& indices);
virtual void addQuads(const IntArray& indices);
virtual void addQuadStrip(const UIntArray& indices);
virtual void addQuadByVertices(const Vec3f& v0, const Vec3f& v1, const Vec3f& v2, const Vec3f& v3);
virtual void addFace(const UIntArray& indices);
};
}

View File

@@ -0,0 +1,145 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfGeometryBuilderFaceList.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::GeometryBuilderFaceList
/// \ingroup Geometry
///
/// Builds geometry represented as a face list.
///
/// A face list is an array of integers. The first integer is the number of connectivity indices for
/// the first face, followed by an integer for each vertex int the face, which are indices into
/// the vertex array. For example, if the face list contains (3 0 1 2), then a triangle is formed
/// from the first three points in the vertex array. The next entry in the face list starts another
/// face, and so on.
///
/// A face list representing a geometry with two triangles, one quad and finally one line would
/// look something like this:
/// \code
/// 3, 0, 1, 2,
/// 3, 0, 2, 3,
/// 4, 4, 5, 6, 7,
/// 2, 8, 9
/// \endcode
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
GeometryBuilderFaceList::GeometryBuilderFaceList()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
uint GeometryBuilderFaceList::addVertices(const Vec3fArray& vertices)
{
uint numExistingVerts = static_cast<uint>(m_vertices.size());
uint numNewVerts = static_cast<uint>(vertices.size());
uint i;
for (i = 0; i < numNewVerts; i++)
{
m_vertices.push_back(vertices[i]);
}
return numExistingVerts;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
uint GeometryBuilderFaceList::vertexCount() const
{
return static_cast<uint>(m_vertices.size());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void GeometryBuilderFaceList::transformVertexRange(uint startIdx, uint endIdx, const Mat4f& mat)
{
uint i;
for (i = startIdx; i <= endIdx; i++)
{
m_vertices[i].transformPoint(mat);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void GeometryBuilderFaceList::addTriangle(uint i0, uint i1, uint i2)
{
m_faceList.push_back(3);
m_faceList.push_back(i0);
m_faceList.push_back(i1);
m_faceList.push_back(i2);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void GeometryBuilderFaceList::addQuad(uint i0, uint i1, uint i2, uint i3)
{
m_faceList.push_back(4);
m_faceList.push_back(i0);
m_faceList.push_back(i1);
m_faceList.push_back(i2);
m_faceList.push_back(i3);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ref<Vec3fArray> GeometryBuilderFaceList::vertices() const
{
ref<Vec3fArray> verts = new Vec3fArray(m_vertices);
return verts;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ref<UIntArray> GeometryBuilderFaceList::faceList() const
{
ref<UIntArray> fList = new UIntArray(m_faceList);
return fList;
}
} // namespace cvf

View File

@@ -0,0 +1,53 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
#include "cvfGeometryBuilder.h"
namespace cvf {
//==================================================================================================
//
// Concrete geometry builder class for building geometry to a face lists
//
//==================================================================================================
class GeometryBuilderFaceList : public GeometryBuilder
{
public:
GeometryBuilderFaceList();
virtual uint addVertices(const Vec3fArray& vertices);
virtual uint vertexCount() const;
virtual void transformVertexRange(uint startIdx, uint endIdx, const Mat4f& mat);
virtual void addTriangle(uint i0, uint i1, uint i2);
virtual void addQuad(uint i0, uint i1, uint i2, uint i3);
ref<Vec3fArray> vertices() const;
ref<UIntArray> faceList() const;
private:
std::vector<Vec3f> m_vertices;
std::vector<uint> m_faceList;
};
}

View File

@@ -0,0 +1,133 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfGeometryBuilderTriangles.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::GeometryBuilderTriangles
/// \ingroup Geometry
///
/// Builds geometry represented as triangles.
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
GeometryBuilderTriangles::GeometryBuilderTriangles()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
uint GeometryBuilderTriangles::addVertices(const Vec3fArray& vertices)
{
uint numExistingVerts = static_cast<uint>(m_vertices.size());
uint numNewVerts = static_cast<uint>(vertices.size());
uint i;
for (i = 0; i < numNewVerts; i++)
{
m_vertices.push_back(vertices[i]);
}
return numExistingVerts;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
uint GeometryBuilderTriangles::vertexCount() const
{
return static_cast<uint>(m_vertices.size());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void GeometryBuilderTriangles::transformVertexRange(uint startIdx, uint endIdx, const Mat4f& mat)
{
uint i;
for (i = startIdx; i <= endIdx; i++)
{
m_vertices[i].transformPoint(mat);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void GeometryBuilderTriangles::addTriangle(uint i0, uint i1, uint i2)
{
m_triangles.push_back(i0);
m_triangles.push_back(i1);
m_triangles.push_back(i2);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ref<Vec3fArray> GeometryBuilderTriangles::vertices() const
{
ref<Vec3fArray> verts = new Vec3fArray(m_vertices);
return verts;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ref<UIntArray> GeometryBuilderTriangles::triangles() const
{
ref<UIntArray> tris = new UIntArray(m_triangles);
return tris;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ref<UShortArray> GeometryBuilderTriangles::trianglesUShort() const
{
ref<UShortArray> tris = new UShortArray;
tris->resize(m_triangles.size());
size_t i;
for (i = 0; i < m_triangles.size(); i++)
{
tris->set(i, static_cast<ushort>(m_triangles[i]));
}
return tris;
}
} // namespace cvf

View File

@@ -0,0 +1,52 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
#include "cvfGeometryBuilder.h"
namespace cvf {
//==================================================================================================
//
// Concrete geometry builder class for building geometry to only triangles
//
//==================================================================================================
class GeometryBuilderTriangles : public GeometryBuilder
{
public:
GeometryBuilderTriangles();
virtual uint addVertices(const Vec3fArray& vertices);
virtual uint vertexCount() const;
virtual void transformVertexRange(uint startIdx, uint endIdx, const Mat4f& mat);
virtual void addTriangle(uint i0, uint i1, uint i2);
ref<Vec3fArray> vertices() const;
ref<UIntArray> triangles() const;
ref<UShortArray> trianglesUShort() const;
private:
std::vector<Vec3f> m_vertices;
std::vector<uint> m_triangles;
};
}

View File

@@ -0,0 +1,881 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfGeometryBuilder.h"
#include "cvfGeometryUtils.h"
#include "cvfMatrix4.h"
#include <map>
namespace cvf {
//==================================================================================================
///
/// \class cvf::GeometryUtils
/// \ingroup Geometry
///
/// Static helper class for creating geometries from primitive shapes.
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
/// Create a 2D patch
///
/// \param origin The start point of the patch
/// \param uUnit Direction vector u. First point 'to the right of' origin is origin + uUnit.
/// \param vUnit Direction vector v. Coordinates of first point 'above' origin is origin + vunit.
/// \param uCellCount The number of cells/quads to generate along the uUnit dimension.
/// \param vCellCount The number of cells/quads to generate along the vUnit dimension.
/// \param builder Geometry builder to use when creating geometry
///
/// The figure below illustrates how the patch is constructed from the specified parameters.
///
/// <PRE>
/// v8-----v9----v10----v11 Parameters: Resulting vertices:
/// | | | | origin = (10,20,0) v0 = (10,20,0)
/// origin | | | | uUnit = (2,0,0) v1 = (12,20,0)
/// + vunit v4-----v5-----v6-----v7 |y vUnit = (0,1,0) v2 = (14,20,0)
/// | | | | | uCellCount = 3 v3 = (16,20,0)
/// | | | | | vCellCount = 2 v4 = (10,21,0)
/// v0-----v1-----v2-----v3 *----x v5 = (12,21,0)
/// origin origin :
/// + uUnit </PRE>
///
/// The following quad connectivities will be produced:\n
/// <TT> &nbsp; &nbsp; (v4,v0,v1,v5) (v5,v1,v2,v6) (v6,v2,v3,v5) ... (v10,v6,v7,v11)</TT>
//--------------------------------------------------------------------------------------------------
void GeometryUtils::createPatch(const Vec3f& origin, const Vec3f& uUnit, const Vec3f& vUnit, uint uCellCount, uint vCellCount, GeometryBuilder* builder)
{
CVF_ASSERT(uCellCount > 0);
CVF_ASSERT(vCellCount > 0);
uint numVertices = (uCellCount + 1)*(vCellCount + 1);
uint numQuads = uCellCount*vCellCount;
Vec3fArray vertices;
vertices.reserve(numVertices);
uint u, v;
for (v = 0; v <= vCellCount; v++)
{
for (u = 0; u <= uCellCount; u++)
{
vertices.add(origin + static_cast<float>(u)*uUnit + static_cast<float>(v)*vUnit);
}
}
uint baseNodeIdx = builder->addVertices(vertices);
UIntArray conn;
conn.reserve(4*numQuads);
for (v = 0; v < vCellCount; v++)
{
for (u = 0; u < uCellCount; u++)
{
conn.add(baseNodeIdx + u + (v + 1)*(uCellCount + 1));
conn.add(baseNodeIdx + u + v*(uCellCount + 1));
conn.add(baseNodeIdx + u + 1 + v*(uCellCount + 1));
conn.add(baseNodeIdx + u + 1 + (v + 1)*(uCellCount + 1));
}
}
builder->addQuads(conn);
}
//--------------------------------------------------------------------------------------------------
/// Create a 3D solid box spanning diagonally from min to max
///
/// \param min The coordinate that represent one corner of the box.
/// \param max The coordinate that lie diagonal from max on the opposite face of the box
/// \param builder Geometry builder to use when creating geometry
///
/// This method creates a box with no shared vertices resulting in sharp corners during shading.
//--------------------------------------------------------------------------------------------------
void GeometryUtils::createBox(const Vec3f& min, const Vec3f& max, GeometryBuilder* builder)
{
// The ordering of the faces is consistent with GLviewAPI's hexahedron element.
// Note that the vertex ordering within a face is not consistent
//
// 7---------6 Faces:
// /| /| |z 0 bottom 0, 3, 2, 1
// / | / | | /y 1 top 4, 5, 6, 7
// 4---------5 | |/ 2 front 4, 0, 1, 5
// | 3------|--2 *---x 3 right 5, 1, 2, 6
// | / | / 4 back 6, 2, 3, 7
// |/ |/ 5 left 7, 3, 0, 4
// 0---------1
Vec3f v0(min.x(), min.y(), min.z());
Vec3f v1(max.x(), min.y(), min.z());
Vec3f v2(max.x(), max.y(), min.z());
Vec3f v3(min.x(), max.y(), min.z());
Vec3f v4(min.x(), min.y(), max.z());
Vec3f v5(max.x(), min.y(), max.z());
Vec3f v6(max.x(), max.y(), max.z());
Vec3f v7(min.x(), max.y(), max.z());
builder->addQuadByVertices(v0, v3, v2, v1);
builder->addQuadByVertices(v4, v5, v6, v7);
builder->addQuadByVertices(v4, v0, v1, v5);
builder->addQuadByVertices(v5, v1, v2, v6);
builder->addQuadByVertices(v6, v2, v3, v7);
builder->addQuadByVertices(v7, v3, v0, v4);
}
//--------------------------------------------------------------------------------------------------
/// Create a 3D solid box at the specified position and with the given total extents
///
/// \param centerPos Position of center of box
/// \param extentX Total extent of box along x-axis
/// \param extentY Total extent of box along y-axis
/// \param extentZ Total extent of box along z-axis
/// \param builder Geometry builder to use when creating geometry
//--------------------------------------------------------------------------------------------------
void GeometryUtils::createBox(const Vec3f& centerPos, float extentX, float extentY, float extentZ, GeometryBuilder* builder)
{
Vec3f halfExtent(extentX/2, extentY/2, extentZ/2);
Vec3f min(centerPos - halfExtent);
Vec3f max(centerPos + halfExtent);
createBox(min, max, builder);
}
//--------------------------------------------------------------------------------------------------
/// Create a disc centered at origin with its normal along positive z-axis
///
/// \param radius Outer radius of the disc
/// \param numSlices The number of subdivisions around the z-axis. Must be >= 4
/// \param builder Geometry builder to use when creating geometry
///
/// Creates a disc on the z = 0 plane, centered at origin and with its surface normal pointing
/// along the positive z-axis.
///
/// The disk is subdivided around the z axis into numSlices (as in pizza slices).
///
/// The sourceNodes that will be produced by this method:
/// <PRE>
/// 1
/// /-----\ 8
/// 2/\ | /\ |y
/// / \ | / \ |
/// | \|/ | |
/// 3|----0----|7 |
/// | /|\ | *-----x
/// \ / | \ / /
/// 4\/ | \/6 /z
/// \-----/
/// 5 </PRE>
///
/// The following triangle connectivities will be produced:\n
/// <TT> &nbsp; &nbsp; (0,1,2) (0,2,3) (0,3,4) ... (0,8,1)</TT>
//--------------------------------------------------------------------------------------------------
void GeometryUtils::createDisc(double radius, uint numSlices, GeometryBuilder* builder)
{
CVF_ASSERT(numSlices >= 4);
CVF_ASSERT(builder);
double da = 2*PI_D/numSlices;
Vec3fArray verts;
verts.reserve(numSlices + 1);
// Center of disc
verts.add(Vec3f::ZERO);
Vec3f point = Vec3f::ZERO;
uint i;
for (i = 0; i < numSlices; i++)
{
// Precompute this one (A = i*da;)
double sinA = Math::sin(i*da);
double cosA = Math::cos(i*da);
point.x() = static_cast<float>(-sinA*radius);
point.y() = static_cast<float>( cosA*radius);
verts.add(point);
}
uint baseNodeIdx = builder->addVertices(verts);
// Vec3fArray myArray;
// myArray.resize(10);
// generatePointsOnCircle(radius, numSlices, &myArray);
uint conn[3] = { baseNodeIdx, 0, 0};
for (i = numSlices; i > 0; i--)
{
conn[1] = baseNodeIdx + i + 1;
conn[2] = baseNodeIdx + i + 0;
if (i == numSlices) conn[1] = baseNodeIdx + 1;
builder->addTriangle(conn[0], conn[1], conn[2]);
}
}
// void GeometryUtils::generatePointsOnCircle(double radius, int numPoints, Vec3fArray* generatedPoints)
// {
// CVF_ASSERT(generatedPoints);
// generatedPoints->reserve(generatedPoints->size() + numPoints);
//
// double da = 2*PI_D/numPoints;
//
// Vec3f point = Vec3f::ZERO;
//
// int i;
// for (i = 0; i < numPoints; i++)
// {
// // Precompute this one (A = i*da;)
// double sinA = sin(i*da);
// double cosA = cos(i*da);
//
// point.x() = static_cast<float>(-sinA*radius);
// point.y() = static_cast<float>( cosA*radius);
//
// generatedPoints->add(point);
// }
// }
//
// void GeometryUtils::createDiscUsingFan(double radius, int numSlices, GeometryBuilder* geometryBuilder)
// {
// CVF_ASSERT(numSlices >= 4);
// CVF_ASSERT(geometryBuilder);
//
//
// double da = 2*PI_D/numSlices;
//
// Vec3fArray verts;
// verts.preAllocBuffer(numSlices + 1);
//
// // Center of disc
// verts.addToPreAlloc(Vec3f::ZERO);
//
//
// Vec3f point = Vec3f::ZERO;
//
// int i;
// for (i = 0; i < numSlices; i++)
// {
// // Precompute this one (A = i*da;)
// double sinA = sin(i*da);
// double cosA = cos(i*da);
//
// point.x() = static_cast<float>(-sinA*radius);
// point.y() = static_cast<float>( cosA*radius);
//
// verts.addToPreAlloc(point);
// }
//
// int baseNodeIdx = geometryBuilder->addVertices(verts);
//
//
// IntArray conns;
// conns.resize(numSlices + 2);
//
// for (i = 0; i < numSlices + 1; i++)
// {
// conns[i] = baseNodeIdx + i;
// }
//
// conns[numSlices + 1] = baseNodeIdx + 1;
//
// geometryBuilder->addTriangleFan(conns);
// }
//--------------------------------------------------------------------------------------------------
/// Create a sphere with center in origin
///
/// \param radius Radius of sphere
/// \param numSlices The number of subdivisions around the z-axis (similar to lines of longitude).
/// \param numStacks The number of subdivisions along the z-axis (similar to lines of latitude).
/// \param builder Geometry builder to use when creating geometry
//--------------------------------------------------------------------------------------------------
void GeometryUtils::createSphere(double radius, uint numSlices, uint numStacks, GeometryBuilder* builder)
{
// Code is strongly inspired by mesa.
// From GLviewAPI:
// float nsign = bNormalsOutwards ? 1.0f : -1.0f;
// Could be added as a param if needed (e.g. dome)
const double nsign = 1.0;
double rho = PI_D/numStacks;
double theta = 2.0*PI_D/static_cast<double>(numSlices);
// Array to receive the node coordinates
Vec3fArray vertices;
uint vertexCount = 1 + 2*numSlices + (numStacks - 2)*numSlices;
vertices.reserve(vertexCount);
// Create the +Z end as triangles
Vec3d vTop(0.0, 0.0, nsign*radius);
vertices.add(Vec3f(vTop));
ref<UIntArray> triangleFan = new UIntArray;
triangleFan->reserve(numSlices + 2);
triangleFan->add(0);
uint j;
for (j = 0; j < numSlices; j++)
{
double localTheta = j * theta;
Vec3d v;
v.x() = -Math::sin(localTheta) * Math::sin(rho);
v.y() = Math::cos(localTheta) * Math::sin(rho);
v.z() = nsign * Math::cos(rho);
v *= radius;
vertices.add(Vec3f(v));
triangleFan->add(j + 1);
}
// Close top fan
triangleFan->add(1);
builder->addTriangleFan(*triangleFan);
// Intermediate stacks as quad-strips
// First and last stacks are handled separately
ref<UIntArray> quadStrip = new UIntArray;
quadStrip->reserve(numSlices*2 + 2);
uint i;
for (i = 1; i < numStacks - 1; i++)
{
double localRho = i * rho;
quadStrip->setSizeZero();
for (j = 0; j < numSlices; j++)
{
double localTheta = j * theta;
Vec3d v;
v.x() = -Math::sin(localTheta) * Math::sin(localRho + rho);
v.y() = Math::cos(localTheta) * Math::sin(localRho + rho);
v.z() = nsign * Math::cos(localRho + rho);
v *= radius;
vertices.add(Vec3f(v));
uint iC1 = (i*numSlices) + 1 + j;
uint iC0 = iC1 - numSlices;
quadStrip->add(iC0);
quadStrip->add(iC1);
}
// Close quad-strip
uint iStartC1 = (i*numSlices) + 1;
uint iStartC0 = iStartC1 - numSlices;
quadStrip->add(iStartC0);
quadStrip->add(iStartC1);
builder->addQuadStrip(*quadStrip);
}
// Create -Z end as triangles
Vec3d vBot( 0.0, 0.0, -radius*nsign );
vertices.add(Vec3f(vBot));
uint endNodeIndex = static_cast<uint>(vertices.size()) - 1;
triangleFan->setSizeZero();
triangleFan->add(endNodeIndex);
for (j = 0; j < numSlices; j++)
{
triangleFan->add(endNodeIndex - j - 1);
}
// Close bottom fan
triangleFan->add(endNodeIndex - 1);
builder->addTriangleFan(*triangleFan);
builder->addVertices(vertices);
}
//--------------------------------------------------------------------------------------------------
/// Create a (possibly oblique) cylinder oriented along the z-axis
///
/// \param bottomRadius Bottom radius of cylinder
/// \param topRadius Top radius of cylinder
/// \param height Height of cylinder
/// \param topOffsetX Offset top disc relative to bottom in X direction
/// \param topOffsetY Offset top disc relative to bottom in Y direction
/// \param numSlices Number of slices
/// \param normalsOutwards true to generate polygons with outward facing normals.
/// \param closedBot true to close the bottom of the cylinder with a disc
/// \param closedTop true to close the top of the cylinder with a disc
/// \param numPolysZDir Number of (subdivisions) polygons along the Z axis.
/// \param builder Geometry builder to use when creating geometry
///
/// An oblique cylinder is a cylinder with bases that are not aligned one directly above the other
/// The base of the cylinder is placed at z = 0, and the top at z = height.
/// Cylinder is subdivided around the z-axis into slices.
/// Use the cone functions instead of setting one of the radius params to 0
//--------------------------------------------------------------------------------------------------
void GeometryUtils::createObliqueCylinder(float bottomRadius, float topRadius, float height, float topOffsetX, float topOffsetY, uint numSlices, bool normalsOutwards, bool closedBot, bool closedTop, uint numPolysZDir, GeometryBuilder* builder)
{
// Create cylinder...
Vec3f centBot(0, 0, 0);
Vec3f centTop(topOffsetX, topOffsetY, height);
// Create vertices
uint zPoly;
for (zPoly = 0; zPoly <= numPolysZDir; zPoly++)
{
float fT = static_cast<float>((1.0/numPolysZDir)*(zPoly));
float radius = bottomRadius + fT*(topRadius - bottomRadius);
Vec3f center(fT*topOffsetX, fT*topOffsetY, fT*height);
Vec3fArray verts;
verts.reserve(numSlices);
Vec3f point = Vec3f::ZERO;
double da = 2*PI_D/numSlices;
uint i;
for (i = 0; i < numSlices; i++)
{
// Precompute this one (A = i*da;)
double sinA = Math::sin(i*da);
double cosA = Math::cos(i*da);
point.x() = static_cast<float>(-sinA*radius);
point.y() = static_cast<float>( cosA*radius);
point.z() = 0;
point += center;
verts.add(point);
}
uint baseNodeIdx = builder->addVertices(verts);
// First time we only create the sourceNodes
if (zPoly != 0)
{
uint offset = baseNodeIdx - numSlices;
uint piConn[4] = { 0, 0, 0, 0 };
// Normals facing outwards
if (normalsOutwards)
{
uint i;
for (i = 0; i < numSlices; i++)
{
piConn[0] = offset + i;
piConn[1] = offset + i + 1;
piConn[2] = offset + i + numSlices + 1;
piConn[3] = offset + i + numSlices;
if (i == numSlices - 1)
{
piConn[1] = offset;
piConn[2] = offset + numSlices;
}
builder->addQuad(piConn[0], piConn[1], piConn[2], piConn[3]);
}
}
// Normals facing inwards
else
{
uint i;
for (i = 0; i < numSlices; i++)
{
piConn[0] = offset + i + 1;
piConn[1] = offset + i;
piConn[2] = offset + i + numSlices;
piConn[3] = offset + i + numSlices + 1;
if (i == numSlices - 1)
{
piConn[0] = offset;
piConn[3] = offset + numSlices;
}
builder->addQuad(piConn[0], piConn[1], piConn[2], piConn[3]);
}
}
}
}
if (closedBot)
{
createDisc(bottomRadius, numSlices, builder);
}
if (closedTop)
{
uint startIdx = builder->vertexCount();
createDisc(topRadius, numSlices, builder);
uint endIdx = builder->vertexCount() - 1;
// Translate the top disc sourceNodes, also flip it to get the normals the right way
Mat4f mat = Mat4f::fromRotation(Vec3f(1.0f, 0.0f, 0.0f), Math::toRadians(180.0f));
mat.translatePreMultiply(Vec3f(topOffsetX, topOffsetY, height));
builder->transformVertexRange(startIdx, endIdx, mat);
}
}
//--------------------------------------------------------------------------------------------------
/// Create a cone oriented along the z-axis
///
/// \param bottomRadius Bottom radius of cone
/// \param height Height of cone
/// \param numSlices Number of slices
/// \param normalsOutwards true to generate polygons with outward facing normals.
/// \param closedBot true to close the bottom of the cone with a disc
/// \param singleTopNode Specify if a single top node should be used, or if each side triangle
/// should have its own top node.
/// \param builder Geometry builder to use when creating geometry
///
//--------------------------------------------------------------------------------------------------
void GeometryUtils::createCone(float bottomRadius, float height, uint numSlices, bool normalsOutwards, bool closedBot, bool singleTopNode, GeometryBuilder* builder)
{
Vec3fArray verts;
if (singleTopNode)
{
verts.reserve(numSlices + 1);
}
else
{
verts.reserve(numSlices*2);
}
Vec3f point = Vec3f::ZERO;
double da = 2*PI_D/numSlices;
uint i;
for (i = 0; i < numSlices; i++)
{
// Precompute this one (A = i*da;)
double sinA = Math::sin(i*da);
double cosA = Math::cos(i*da);
point.x() = static_cast<float>(-sinA*bottomRadius);
point.y() = static_cast<float>( cosA*bottomRadius);
verts.add(point);
}
if (singleTopNode)
{
verts.add(Vec3f(0, 0, height));
}
else
{
// Unique sourceNodes at apex of cone
Vec3f topNode(0, 0, height);
uint i;
for (i = 0; i < numSlices; i++)
{
verts.add(topNode);
}
}
uint baseNodeIdx = builder->addVertices(verts);
uint piConn[3] = { 0, 0, 0 };
// Normals facing outwards
if (normalsOutwards)
{
uint i;
for (i = 0; i < numSlices; i++)
{
piConn[0] = baseNodeIdx + i;
piConn[1] = baseNodeIdx + i + 1;
piConn[2] = singleTopNode ? baseNodeIdx + numSlices : baseNodeIdx + i + numSlices;
if (i == numSlices - 1)
{
piConn[1] = baseNodeIdx;
}
if (normalsOutwards)
{
builder->addTriangle(piConn[0], piConn[1], piConn[2]);
}
else
{
builder->addTriangle(piConn[1], piConn[0], piConn[2]);
}
}
}
if (closedBot)
{
createDisc(bottomRadius, numSlices, builder);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void GeometryUtils::tesselatePatchAsQuads(uint pointCountU, uint pointCountV, uint indexOffset, bool windingCCW, UIntArray* indices)
{
CVF_ASSERT(pointCountU >= 2);
CVF_ASSERT(pointCountV >= 2);
uint uCellCount = pointCountU - 1;
uint vCellCount = pointCountV - 1;
uint numQuads = uCellCount*vCellCount;
indices->reserve(indices->size() + 4*numQuads);
uint u, v;
for (v = 0; v < vCellCount; v++)
{
for (u = 0; u < uCellCount; u++)
{
if (windingCCW)
{
indices->add(indexOffset + u + (v+1)*pointCountU);
indices->add(indexOffset + u + v*pointCountU);
indices->add(indexOffset + u+1 + v*pointCountU);
indices->add(indexOffset + u+1 + (v+1)*pointCountU);
}
else
{
indices->add(indexOffset + u + v*pointCountU);
indices->add(indexOffset + u + (v+1)*pointCountU);
indices->add(indexOffset + u+1 + (v+1)*pointCountU);
indices->add(indexOffset + u+1 + v*pointCountU);
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void GeometryUtils::tesselatePatchAsTriangles(uint pointCountU, uint pointCountV, uint indexOffset, bool windingCCW, UIntArray* indices)
{
CVF_ASSERT(pointCountU >= 2);
CVF_ASSERT(pointCountV >= 2);
uint uCellCount = pointCountU - 1;
uint vCellCount = pointCountV - 1;
uint numTris = 2*uCellCount*vCellCount;
indices->reserve(indices->size() + 3*numTris);
uint u, v;
for (v = 0; v < vCellCount; v++)
{
for (u = 0; u < uCellCount; u++)
{
if (windingCCW)
{
indices->add(indexOffset + u + (v+1)*pointCountU);
indices->add(indexOffset + u + v*pointCountU);
indices->add(indexOffset + u+1 + v*pointCountU);
indices->add(indexOffset + u + (v+1)*pointCountU);
indices->add(indexOffset + u+1 + v*pointCountU);
indices->add(indexOffset + u+1 + (v+1)*pointCountU);
}
else
{
indices->add(indexOffset + u + v*pointCountU);
indices->add(indexOffset + u + (v+1)*pointCountU);
indices->add(indexOffset + u+1 + (v+1)*pointCountU);
indices->add(indexOffset + u + v*pointCountU);
indices->add(indexOffset + u+1 + (v+1)*pointCountU);
indices->add(indexOffset + u+1 + v*pointCountU);
}
}
}
}
//--------------------------------------------------------------------------------------------------
/// Check if the specified quad is convex
//--------------------------------------------------------------------------------------------------
bool GeometryUtils::isConvexQuad(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& d)
{
// From "Real Time Collision Detection", p60
// Quad is nonconvex if dot(cross(bd, ba), cross(bd, bc)) >= 0
const Vec3f bda = (d - b) ^ (a - b);
const Vec3f bdc = (d - b) ^ (c - b);
if (bda*bdc >= 0)
{
return false;
}
// Quad is now convex if dot(cross(ac, ad), cross(ac, ab)) < 0
const Vec3f acd = (c - a) ^ (d - a);
const Vec3f acb = (c - a) ^ (b - a);
if (acd*acb < 0)
{
return true;
}
else
{
return false;
}
}
//--------------------------------------------------------------------------------------------------
/// Compute surface normal for a quad
//--------------------------------------------------------------------------------------------------
Vec3f GeometryUtils::quadNormal(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& d)
{
// From "Real Time Collision Detection", p. 495
Vec3f normal = (c - a) ^ (d - b);
normal.normalize();
return normal;
}
//--------------------------------------------------------------------------------------------------
/// Compute polygon normal using Newell's method
//--------------------------------------------------------------------------------------------------
Vec3f GeometryUtils::polygonNormal(const Vec3fValueArray& vertices, const uint* indices, uint indexCount)
{
// From "Real Time Collision Detection", p. 495
// Compute normal as being proportional to projected areas of polygon onto the yz, xz, and xy planes.
Vec3f normal(0, 0, 0);
uint n;
for (n = 0; n < indexCount; n++)
{
uint i = indices[(n > 0) ? n - 1 : indexCount - 1];
uint j = indices[n];
normal.x() += (vertices.val(i).y() - vertices.val(j).y()) * (vertices.val(i).z() + vertices.val(j).z()); // projection on yz
normal.y() += (vertices.val(i).z() - vertices.val(j).z()) * (vertices.val(i).x() + vertices.val(j).x()); // projection on xz
normal.z() += (vertices.val(i).x() - vertices.val(j).x()) * (vertices.val(i).y() + vertices.val(j).y()); // projection on xy
}
normal.normalize();
return normal;
}
//--------------------------------------------------------------------------------------------------
/// Compact an array of vertex indices by removing 'unused' indices
///
/// \param[in] vertexIndices The original vertex indices
/// \param[out] newVertexIndices New compacted vertex indices
/// \param[out] newToOldMapping For each 'new' vertex, will contain its original index
/// \param[in] maxVertexCount The maximum resulting vertex count after removing unused vertices
//--------------------------------------------------------------------------------------------------
void GeometryUtils::removeUnusedVertices(const UIntValueArray& vertexIndices, UIntArray* newVertexIndices, UIntArray* newToOldMapping, uint maxVertexCount)
{
if (vertexIndices.size() == 0 || maxVertexCount == 0)
{
return;
}
std::map<uint, uint> oldToNewVertexIndexMap;
std::map<uint, uint>::const_iterator it;
CVF_ASSERT(newVertexIndices);
CVF_ASSERT(newToOldMapping);
newVertexIndices->reserve(vertexIndices.size());
newToOldMapping->reserve(maxVertexCount);
size_t i;
uint newVertexIndex = 0;
for (i = 0; i < vertexIndices.size(); i++)
{
uint vertexIdx = vertexIndices.val(i);
uint currentIndex = UNDEFINED_UINT;
it = oldToNewVertexIndexMap.find(vertexIdx);
if (it == oldToNewVertexIndexMap.end())
{
currentIndex = newVertexIndex++;
oldToNewVertexIndexMap[vertexIdx] = currentIndex;
newToOldMapping->add(vertexIdx);
}
else
{
currentIndex = it->second;
}
CVF_ASSERT(currentIndex != UNDEFINED_UINT);
newVertexIndices->add(currentIndex);
}
newToOldMapping->squeeze();
}
bool GeometryUtils::project(const Mat4d& projectionMultViewMatrix, const Vec2ui& viewportPosition, const Vec2ui& viewportSize, const Vec3d& point, Vec3d* out)
{
CVF_ASSERT(out);
Vec4d v = projectionMultViewMatrix * Vec4d(point, 1.0);
if (v.w() == 0.0f)
{
return false;
}
v.x() /= v.w();
v.y() /= v.w();
v.z() /= v.w();
// map to range 0-1
out->x() = v.x()*0.5 + 0.5;
out->y() = v.y()*0.5 + 0.5;
out->z() = v.z()*0.5 + 0.5;
// map to viewport
out->x() = out->x() * viewportSize.x() + viewportPosition.x();
out->y() = out->y() * viewportSize.y() + viewportPosition.y();
return true;
}
} // namespace cvf

View File

@@ -0,0 +1,63 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
#include "cvfVector3.h"
#include "cvfGeometryBuilder.h"
namespace cvf {
//==================================================================================================
//
// Static helper class for building geometry
//
//==================================================================================================
class GeometryUtils
{
public:
static void createPatch(const Vec3f& origin, const Vec3f& uUnit, const Vec3f& vUnit, uint uCellCount, uint vCellCount, GeometryBuilder* builder);
static void createBox(const Vec3f& min, const Vec3f& max, GeometryBuilder* builder);
static void createBox(const Vec3f& centerPos, float extentX, float extentY, float extentZ, GeometryBuilder* builder);
static void createDisc(double radius, uint numSlices, GeometryBuilder* builder);
static void createSphere(double radius, uint numSlices, uint numStacks, GeometryBuilder* builder);
// These two should be refactored out into separate generator classes
static void createObliqueCylinder(float bottomRadius, float topRadius, float height, float topOffsetX, float topOffsetY, uint numSlices, bool normalsOutwards, bool closedBot, bool closedTop, uint numPolysZDir, GeometryBuilder* builder);
static void createCone(float bottomRadius, float height, uint numSlices, bool normalsOutwards, bool closedBot, bool singleTopNode, GeometryBuilder* builder);
//static void generatePointsOnCircle(double radius, int numPoints, Vec3fArray* generatedPoints);
static void tesselatePatchAsQuads(uint pointCountU, uint pointCountV, uint indexOffset, bool windingCCW, UIntArray* indices);
static void tesselatePatchAsTriangles(uint pointCountU, uint pointCountV, uint indexOffset, bool windingCCW, UIntArray* indices);
static bool isConvexQuad(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& d);
static Vec3f quadNormal(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& d);
static Vec3f polygonNormal(const Vec3fValueArray& vertices, const uint* indices, uint indexCount);
static void removeUnusedVertices(const UIntValueArray& vertexIndices, UIntArray* newVertexIndices, UIntArray* newToOldMapping, uint maxVertexCount);
static bool project(const Mat4d& projectionMultViewMatrix, const Vec2ui& viewportPosition, const Vec2ui& viewportSize, const Vec3d& point, Vec3d* out);
};
}

View File

@@ -0,0 +1,41 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
// Doxygen module definition
/// \ingroup CeeVizFramework
/// @{
/// \defgroup Geometry Geometry module
/// @}
#include "cvfArrowGenerator.h"
#include "cvfBoundingBox.h"
#include "cvfBoxGenerator.h"
#include "cvfFrustum.h"
#include "cvfEdgeKey.h"
#include "cvfGeometryBuilder.h"
#include "cvfGeometryBuilderFaceList.h"
#include "cvfGeometryBuilderTriangles.h"
#include "cvfGeometryUtils.h"
#include "cvfMeshEdgeExtractor.h"
#include "cvfOutlineEdgeExtractor.h"
#include "cvfPatchGenerator.h"
#include "cvfRay.h"
#include "cvfVertexWelder.h"

View File

@@ -0,0 +1,151 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfMeshEdgeExtractor.h"
#include "cvfEdgeKey.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::MeshEdgeExtractor
/// \ingroup Geometry
///
///
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
MeshEdgeExtractor::MeshEdgeExtractor()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void MeshEdgeExtractor::addPrimitives(uint verticesPerPrimitive, const uint* indices, size_t indexCount)
{
CVF_ASSERT(verticesPerPrimitive > 0);
CVF_ASSERT(indices);
CVF_ASSERT(indexCount > 0);
// Points will never become edges
if (verticesPerPrimitive < 2)
{
return;
}
size_t numPrimitives = indexCount/verticesPerPrimitive;
size_t ip;
for (ip = 0; ip < numPrimitives; ip++)
{
size_t firstIdxInPrimitive = ip*verticesPerPrimitive;
uint i;
for (i = 0; i < verticesPerPrimitive; i++)
{
uint vertexIdx1 = indices[firstIdxInPrimitive + i];
uint vertexIdx2 = (i < verticesPerPrimitive - 1) ? indices[firstIdxInPrimitive + i + 1] : indices[firstIdxInPrimitive];
// Don't add collapsed edges
if (vertexIdx1 != vertexIdx2)
{
int64 edgeKeyVal = EdgeKey(vertexIdx1, vertexIdx2).toKeyVal();
m_edgeSet.insert(edgeKeyVal);
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void MeshEdgeExtractor::addPrimitives(uint verticesPerPrimitive, const UIntArray& indices)
{
CVF_ASSERT(verticesPerPrimitive > 0);
size_t indexCount = indices.size();
size_t numPrimitives = indexCount/verticesPerPrimitive;
if (numPrimitives > 0)
{
const uint* indexPtr = indices.ptr();
addPrimitives(verticesPerPrimitive, indexPtr, indexCount);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void MeshEdgeExtractor::addFaceList(const UIntArray& faceList)
{
size_t numFaceListEntries = faceList.size();
size_t i = 0;
while (i < numFaceListEntries)
{
uint numVerticesInFace = faceList[i++];
CVF_ASSERT(numVerticesInFace > 0);
CVF_ASSERT(i + numVerticesInFace <= numFaceListEntries);
const uint* indexPtr = &faceList[i];
addPrimitives(numVerticesInFace, indexPtr, numVerticesInFace);
i += numVerticesInFace;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ref<UIntArray> MeshEdgeExtractor::lineIndices() const
{
ref<UIntArray> indices = new UIntArray;
size_t numEdges = m_edgeSet.size();
if (numEdges == 0)
{
return indices;
}
indices->reserve(2*numEdges);
std::set<cvf::int64>::const_iterator it;
for (it = m_edgeSet.begin(); it != m_edgeSet.end(); ++it)
{
EdgeKey ek = EdgeKey::fromkeyVal(*it);
indices->add(ek.index1());
indices->add(ek.index2());
}
return indices;
}
} // namespace cvf

View File

@@ -0,0 +1,51 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
#include "cvfArray.h"
namespace cvf {
//==================================================================================================
//
//
//
//==================================================================================================
class MeshEdgeExtractor
{
public:
MeshEdgeExtractor();
void addPrimitives(uint verticesPerPrimitive, const uint* indices, size_t indexCount);
void addPrimitives(uint verticesPerPrimitive, const UIntArray& indices);
void addFaceList(const UIntArray& faceList);
ref<UIntArray> lineIndices() const;
private:
std::set<cvf::int64> m_edgeSet;
};
}

View File

@@ -0,0 +1,269 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfOutlineEdgeExtractor.h"
#include "cvfEdgeKey.h"
#include "cvfGeometryUtils.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::OutlineEdgeExtractor
/// \ingroup Geometry
///
///
///
//==================================================================================================
static const size_t OEE_OUTLINE_EDGE = cvf::UNDEFINED_SIZE_T; // This is an outline edge
static const size_t OEE_NON_OUTLINE_EDGE = cvf::UNDEFINED_SIZE_T - 1; // Marked as an interior edge
static const size_t OEE_MULTIREF_EDGE = cvf::UNDEFINED_SIZE_T - 2; // An edge with more than two faces connected to it.
//--------------------------------------------------------------------------------------------------
/// Constructor
///
/// creaseAngle is specified in radians
//--------------------------------------------------------------------------------------------------
OutlineEdgeExtractor::OutlineEdgeExtractor(double creaseAngle, const Vec3fValueArray& vertexArray)
: m_creaseAngle(creaseAngle),
m_vertexArray(vertexArray)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void OutlineEdgeExtractor::addPrimitives(uint verticesPerPrimitive, const uint* indices, size_t indexCount)
{
CVF_ASSERT(verticesPerPrimitive > 0);
CVF_ASSERT(indices);
CVF_ASSERT(indexCount > 0);
// Points will never become edges
if (verticesPerPrimitive < 2)
{
return;
}
size_t numPrimitives = indexCount/verticesPerPrimitive;
size_t ip;
for (ip = 0; ip < numPrimitives; ip++)
{
size_t myFaceIndex = m_faceNormals.size();
size_t firstIdxInPrimitive = ip*verticesPerPrimitive;
// Normal computation accepts points and lines, but in that case returns a zero vector
Vec3f faceNormal = computeFaceNormal(&indices[firstIdxInPrimitive], verticesPerPrimitive);
m_faceNormals.push_back(faceNormal);
uint i;
for (i = 0; i < verticesPerPrimitive; i++)
{
const uint vertexIdx1 = indices[firstIdxInPrimitive + i];
const uint vertexIdx2 = (i < verticesPerPrimitive - 1) ? indices[firstIdxInPrimitive + i + 1] : indices[firstIdxInPrimitive];
// Never add collapsed edges
if (vertexIdx1 == vertexIdx2)
{
continue;
}
int64 edgeKeyVal = EdgeKey(vertexIdx1, vertexIdx2).toKeyVal();
std::map<int64, size_t>::iterator it = m_edgeToFaceIndexMap.find(edgeKeyVal);
if (it == m_edgeToFaceIndexMap.end())
{
// Not found, so add and register face index
m_edgeToFaceIndexMap[edgeKeyVal] = myFaceIndex;
}
else
{
size_t otherFaceIdx = it->second;
if (otherFaceIdx < OEE_MULTIREF_EDGE)
{
// An edge is already there, check angle
if (isFaceAngleAboveThreshold(myFaceIndex, otherFaceIdx))
{
m_edgeToFaceIndexMap[edgeKeyVal] = OEE_OUTLINE_EDGE;
}
else
{
m_edgeToFaceIndexMap[edgeKeyVal] = OEE_NON_OUTLINE_EDGE;
}
}
else
{
// Three or more faces share an edge
m_edgeToFaceIndexMap[edgeKeyVal] = OEE_MULTIREF_EDGE;
}
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void OutlineEdgeExtractor::addPrimitives(uint verticesPerPrimitive, const UIntArray& indices)
{
CVF_ASSERT(verticesPerPrimitive > 0);
size_t indexCount = indices.size();
size_t numPrimitives = indexCount/verticesPerPrimitive;
if (numPrimitives > 0)
{
const uint* indexPtr = indices.ptr();
addPrimitives(verticesPerPrimitive, indexPtr, indexCount);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void OutlineEdgeExtractor::addFaceList(const UIntArray& faceList)
{
size_t numFaceListEntries = faceList.size();
size_t i = 0;
while (i < numFaceListEntries)
{
uint numVerticesInFace = faceList[i++];
CVF_ASSERT(numVerticesInFace > 0);
CVF_ASSERT(i + numVerticesInFace <= numFaceListEntries);
const uint* indexPtr = &faceList[i];
addPrimitives(numVerticesInFace, indexPtr, numVerticesInFace);
i += numVerticesInFace;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ref<UIntArray> OutlineEdgeExtractor::lineIndices() const
{
ref<UIntArray> indices = new UIntArray;
size_t numEdges = m_edgeToFaceIndexMap.size();
if (numEdges == 0)
{
return indices;
}
indices->reserve(2*numEdges);
std::map<int64, size_t>::const_iterator it;
for (it = m_edgeToFaceIndexMap.begin(); it != m_edgeToFaceIndexMap.end(); ++it)
{
size_t otherFaceIdx = it->second;
if (otherFaceIdx != OEE_NON_OUTLINE_EDGE)
{
EdgeKey ek = EdgeKey::fromkeyVal(it->first);
indices->add(ek.index1());
indices->add(ek.index2());
}
}
return indices;
}
//--------------------------------------------------------------------------------------------------
/// Returns the worker array with one normal per face (primitive)
//--------------------------------------------------------------------------------------------------
const std::vector<Vec3f>& OutlineEdgeExtractor::faceNormals()
{
return m_faceNormals;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Vec3f OutlineEdgeExtractor::computeFaceNormal(const uint* faceVertexIndices, uint numVerticesInFace) const
{
// Init to zero so that points and lines return a zero normal
Vec3f normal(Vec3f::ZERO);
if (numVerticesInFace == 3)
{
const Vec3f& v0 = m_vertexArray.val(faceVertexIndices[0]);
Vec3f v1 = m_vertexArray.val(faceVertexIndices[1]) - v0;
Vec3f v2 = m_vertexArray.val(faceVertexIndices[2]) - v0;
normal = v1 ^ v2;
normal.normalize();
}
else if (numVerticesInFace == 4)
{
// Quad surface normal,
// From "Real Time Collision Detection" p 495
const Vec3f& A = m_vertexArray.val(faceVertexIndices[0]);
const Vec3f& B = m_vertexArray.val(faceVertexIndices[1]);
const Vec3f& C = m_vertexArray.val(faceVertexIndices[2]);
const Vec3f& D = m_vertexArray.val(faceVertexIndices[3]);
normal = GeometryUtils::quadNormal(A, B, C, D);
}
else if (numVerticesInFace > 4)
{
normal = GeometryUtils::polygonNormal(m_vertexArray, faceVertexIndices, numVerticesInFace);
}
return normal;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool OutlineEdgeExtractor::isFaceAngleAboveThreshold(size_t faceIdx1, size_t faceIdx2) const
{
const Vec3f& n1 = m_faceNormals[faceIdx1];
const Vec3f& n2 = m_faceNormals[faceIdx2];
// If either vector is 0, the face is probably a line
// Therefore just return true to flag this as an outline edge
if (n1.isZero() || n2.isZero())
{
return true;
}
double angle = Math::acos(n1*n2);
if (Math::abs(angle) > m_creaseAngle)
{
return true;
}
else
{
return false;
}
}
} // namespace cvf

View File

@@ -0,0 +1,62 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
#include "cvfArray.h"
#include <map>
namespace cvf {
//==================================================================================================
//
//
//
//==================================================================================================
class OutlineEdgeExtractor
{
public:
OutlineEdgeExtractor(double creaseAngle, const Vec3fValueArray& vertexArray);
public:
void addPrimitives(uint verticesPerPrimitive, const uint* indices, size_t indexCount);
void addPrimitives(uint verticesPerPrimitive, const UIntArray& indices);
void addFaceList(const UIntArray& faceList);
ref<UIntArray> lineIndices() const;
const std::vector<Vec3f>& faceNormals(); // Surface normals for the faces, normalized
private:
Vec3f computeFaceNormal(const uint* faceVertexIndices, uint numVerticesInFace) const;
bool isFaceAngleAboveThreshold(size_t faceIdx1, size_t faceIdx2) const;
private:
double m_creaseAngle; // Threshold crease angle in radians
const Vec3fValueArray& m_vertexArray;
std::map<int64, size_t> m_edgeToFaceIndexMap;
std::vector<Vec3f> m_faceNormals; // Surface normals for the faces, normalized
};
}

View File

@@ -0,0 +1,162 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfPatchGenerator.h"
#include "cvfGeometryUtils.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::PatchGenerator
/// \ingroup Geometry
///
/// Generates 2D patches
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PatchGenerator::PatchGenerator()
: m_origin(0, 0, 0),
m_axisU(Vec3d::X_AXIS),
m_axisV(Vec3d::Y_AXIS),
m_extentU(1),
m_extentV(1),
m_cellCountU(1),
m_cellCountV(1),
m_useQuads(true),
m_windingCCW(true)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PatchGenerator::setOrigin(const Vec3d& origin)
{
m_origin = origin;
}
//--------------------------------------------------------------------------------------------------
/// Set the axes
///
/// The specified axes will be normalized
//--------------------------------------------------------------------------------------------------
void PatchGenerator::setAxes(const Vec3d& axisU, const Vec3d& axisV)
{
m_axisU = axisU.getNormalized();
m_axisV = axisV.getNormalized();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PatchGenerator::setExtent(double extentU, double extentV)
{
m_extentU = extentU;
m_extentV = extentV;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PatchGenerator::setSubdivisions(uint subdivU, uint subdivV)
{
CVF_ASSERT(subdivU > 0 && subdivV > 0);
m_cellCountU = subdivU;
m_cellCountV = subdivV;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PatchGenerator::setQuads(bool useQuads)
{
m_useQuads = useQuads;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PatchGenerator::setWindingCCW(bool windingCCW)
{
m_windingCCW = windingCCW;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PatchGenerator::generate(GeometryBuilder* builder)
{
CVF_ASSERT(m_cellCountU > 0);
CVF_ASSERT(m_cellCountV > 0);
size_t numVertices = (m_cellCountU + 1)*(m_cellCountV + 1);
Vec3fArray vertices;
vertices.reserve(numVertices);
const Vec3d unitU = (m_extentU*m_axisU)/m_cellCountU;
const Vec3d unitV = (m_extentV*m_axisV)/m_cellCountV;
uint v;
for (v = 0; v <= m_cellCountV; v++)
{
Vec3d rowOrigo(m_origin + unitV*v);
uint u;
for (u = 0; u <= m_cellCountU; u++)
{
vertices.add(Vec3f(rowOrigo + unitU*u));
}
}
uint baseNodeIdx = builder->addVertices(vertices);
if (m_useQuads)
{
UIntArray conn;
GeometryUtils::tesselatePatchAsQuads(m_cellCountU + 1, m_cellCountV + 1, baseNodeIdx, m_windingCCW, &conn);
builder->addQuads(conn);
}
else
{
UIntArray conn;
GeometryUtils::tesselatePatchAsTriangles(m_cellCountU + 1, m_cellCountV + 1, baseNodeIdx, m_windingCCW, &conn);
builder->addTriangles(conn);
}
}
} // namespace cvf

View File

@@ -0,0 +1,63 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
#include "cvfVector3.h"
namespace cvf {
class GeometryBuilder;
//==================================================================================================
//
// Generates 2D patches
//
//==================================================================================================
class PatchGenerator
{
public:
PatchGenerator();
void setOrigin(const Vec3d& origin);
void setAxes(const Vec3d& axisU, const Vec3d& axisV);
void setExtent(double extentU, double extentV);
void setSubdivisions(uint subdivU, uint subdivV);
void setQuads(bool useQuads);
void setWindingCCW(bool windingCCW);
void generate(GeometryBuilder* builder);
private:
Vec3d m_origin; // Origin. Default (0, 0, 0)
Vec3d m_axisU; // First axis of patch. Default is global X-axis
Vec3d m_axisV; // Second axis of patch. Default is global Y-axis
double m_extentU; // Extent along U axis
double m_extentV; // Extent along V axis
uint m_cellCountU; // Number of cells/quads in each direction. Default 1
uint m_cellCountV; // :
bool m_useQuads; // If true, quads will be generated, otherwise triangles. Default is quads
bool m_windingCCW; // Winding of the generated quads. Controls which side of the patch will be front facing.
};
}

View File

@@ -0,0 +1,378 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfRay.h"
#include "cvfBoundingBox.h"
#include "cvfPlane.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::Ray
/// \ingroup Geometry
///
/// A ray that can be used for intersection testing.
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Ray::Ray()
{
m_origin = Vec3d::ZERO;
m_direction = -Vec3d::Z_AXIS;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Ray::Ray(const Ray& other) : Object()
{
m_origin = other.origin();
m_direction = other.direction();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Ray::~Ray()
{
}
//--------------------------------------------------------------------------------------------------
/// Sets the origin (starting point) of the ray
//--------------------------------------------------------------------------------------------------
void Ray::setOrigin(const Vec3d& orig)
{
m_origin = orig;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const Vec3d& Ray::origin() const
{
return m_origin;
}
//--------------------------------------------------------------------------------------------------
/// Sets the direction of the ray
//--------------------------------------------------------------------------------------------------
void Ray::setDirection(const Vec3d& dir)
{
m_direction = dir;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const Vec3d& Ray::direction() const
{
return m_direction;
}
//--------------------------------------------------------------------------------------------------
/// Transforms the origin and direction with the given transformation matrix
//--------------------------------------------------------------------------------------------------
void Ray::transform(const Mat4d& matrix)
{
m_origin.transformPoint(matrix);
m_direction.transformVector(matrix);
}
//--------------------------------------------------------------------------------------------------
/// Returns this ray transformed with the given transformation matrix
//--------------------------------------------------------------------------------------------------
const Ray Ray::getTransformed(const Mat4d& matrix) const
{
Ray ray(*this);
ray.transform(matrix);
return ray;
}
//--------------------------------------------------------------------------------------------------
/// Returns true if the ray intersects the triangle.
///
/// intersectionPoint (if not NULL) will be set to the ray intersection point on the triangle.
//--------------------------------------------------------------------------------------------------
bool Ray::triangleIntersect(const Vec3d& v1, const Vec3d& v2, const Vec3d& v3, Vec3d* intersectionPoint) const
{
Vec3d v12 = v2 - v1;
Vec3d v13 = v3 - v1;
Vec3d n = (v12 ^ v13).getNormalized();
double det = n * direction();
if (det == 0.0f)
{
return false;
}
double t = n * ((v1 - origin()) / det);
if (t < 0)
{
return false;
}
Vec3d fp = origin() + direction()*t;
Vec3d pts[] = { v1, v2, v3, v1 };
int i;
for(i = 0; i < 3; i++)
{
Vec3d bi_norm = -((pts[i+1]-pts[i]) ^ n).getNormalized();
if (((fp-pts[i]) * bi_norm) < 0)
{
return false;
}
}
if (intersectionPoint)
{
*intersectionPoint = fp;
}
return true;
}
//--------------------------------------------------------------------------------------------------
/// Returns true if the ray intersects the quad.
///
/// intersectionPoint (if not NULL) will be set to the ray intersection point on the quad.
//--------------------------------------------------------------------------------------------------
bool Ray::quadIntersect(const Vec3d& v1, const Vec3d& v2, const Vec3d& v3, const Vec3d& v4, Vec3d* intersectionPoint) const
{
Vec3d v12 = v2 - v1;
Vec3d v13 = v3 - v1;
Vec3d n = (v12 ^ v13).getNormalized();
double det = n * direction();
if (det == 0.0f)
{
return false;
}
double t = n * ((v1 - origin()) / det);
if (t < 0)
{
return false;
}
Vec3d fp = origin() + direction()*t;
Vec3d pts[] = { v1, v2, v3, v4, v1 };
int i;
for(i = 0; i < 4; i++)
{
Vec3d bi_norm = -((pts[i+1]-pts[i]) ^ n).getNormalized();
if (((fp-pts[i]) * bi_norm) < 0)
{
return false;
}
}
if (intersectionPoint)
{
*intersectionPoint = fp;
}
return true;
}
//--------------------------------------------------------------------------------------------------
/// Returns true if the ray intersects the bounding box.
///
/// intersectionPoint (if not NULL) will be set to the ray intersection point on the bounding box.
//--------------------------------------------------------------------------------------------------
bool Ray::boxIntersect(const BoundingBox& box, Vec3d* intersectionPoint) const
{
if (!box.isValid()) return false;
const int RIGHT = 0;
const int LEFT = 1;
const int MIDDLE = 2;
// Find candidate planes; this loop can be avoided if rays cast all from the eye(assume perpsective view)
bool inside = true;
char quadrant[3];
double candidatePlane[3];
Vec3d min = box.min();
Vec3d max = box.max();
int i;
for (i = 0; i < 3; i++)
{
if(m_origin[i] < min[i])
{
quadrant[i] = LEFT;
candidatePlane[i] = min[i];
inside = false;
}
else if (m_origin[i] > max[i])
{
quadrant[i] = RIGHT;
candidatePlane[i] = max[i];
inside = false;
}
else
{
quadrant[i] = MIDDLE;
}
}
// Ray origin inside bounding box
if (inside)
{
// Return intersection point
if (intersectionPoint) *intersectionPoint = m_origin;
return true;
}
// Calculate T distances to candidate planes
double maxT[3];
for (i = 0; i < 3; i++)
{
if (quadrant[i] != MIDDLE && m_direction[i] !=0.0f)
{
maxT[i] = (candidatePlane[i] - m_origin[i]) / m_direction[i];
}
else
{
maxT[i] = -1.0f;
}
}
// Get largest of the maxT's for final choice of intersection
int whichPlane = 0;
for (i = 1; i < 3; i++)
{
if (maxT[whichPlane] < maxT[i]) whichPlane = i;
}
// Check final candidate actually inside box
if (maxT[whichPlane] < 0.0f) return false;
Vec3d hitPoint;
for (i = 0; i < 3; i++)
{
if (whichPlane != i)
{
hitPoint[i] = m_origin[i] + maxT[whichPlane] * m_direction[i];
if (hitPoint[i] < min[i] || hitPoint[i] > max[i]) return false;
}
else
{
hitPoint[i] = candidatePlane[i];
}
}
if (intersectionPoint)
{
*intersectionPoint = hitPoint;
}
// Ray hits box
return true;
}
//--------------------------------------------------------------------------------------------------
/// Returns true if the ray intersects the ray
//--------------------------------------------------------------------------------------------------
bool Ray::planeIntersect(const Plane& plane, Vec3d* intersectionPoint) const
{
Vec3d pn = plane.normal();
double D = plane.D();
double vd = pn*m_direction;
// If vd > 0, the plane normal is pointing 'away' from the ray
// We want the plane normal facing the ray so flip direction of the plane
if (vd > 0)
{
pn *= -1;
D *= -1;
vd *= -1;
}
// No intersection ray and plane normal are parallel
if (Math::abs(vd) > std::numeric_limits<double>::epsilon())
{
double v0 = -(pn*m_origin + D);
double t = v0/vd;
if (t >= 0)
{
if (intersectionPoint)
{
*intersectionPoint = m_origin + t*m_direction;
}
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
String Ray::toString() const
{
String str = "Ray: ";
str += " origin: x=" + String::number(m_origin.x()) + " y=" + String::number(m_origin.y()) + " z=" + String::number(m_origin.z());
str += " direction: x=" + String::number(m_direction.x()) + " y=" + String::number(m_direction.y()) + " z=" + String::number(m_direction.z());
return str;
}
} // namespace cvf

View File

@@ -0,0 +1,65 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
#include "cvfObject.h"
#include "cvfVector3.h"
#include "cvfMatrix4.h"
#include "cvfString.h"
namespace cvf {
class BoundingBox;
class Plane;
//==================================================================================================
//
// Ray
//
//==================================================================================================
class Ray : public Object
{
public:
Ray();
Ray(const Ray& other);
~Ray();
void setOrigin(const Vec3d& orig);
const Vec3d& origin() const;
void setDirection(const Vec3d& dir);
const Vec3d& direction() const;
void transform(const Mat4d& matrix);
const Ray getTransformed(const Mat4d& matrix) const;
bool triangleIntersect(const Vec3d& v1, const Vec3d& v2, const Vec3d& v3, Vec3d* intersectionPoint = NULL) const;
bool quadIntersect(const Vec3d& v1, const Vec3d& v2, const Vec3d& v3, const Vec3d& v4, Vec3d* intersectionPoint = NULL) const;
bool boxIntersect(const BoundingBox& box, Vec3d* intersectionPoint = NULL) const;
bool planeIntersect(const Plane& plane, Vec3d* intersectionPoint = NULL) const;
String toString() const;
private:
Vec3d m_origin; ///< Starting point of ray
Vec3d m_direction; ///< Vector specifying ray direction
};
}

View File

@@ -0,0 +1,135 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfTriangleMeshEdgeExtractor.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::TriangleMeshEdgeExtractor
/// \ingroup Geometry
///
///
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TriangleMeshEdgeExtractor::TriangleMeshEdgeExtractor()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void TriangleMeshEdgeExtractor::addTriangles(const UIntArray& indices, const UIntArray& triangleKeys)
{
size_t index = 0;
size_t numTris = indices.size()/3;
size_t tri;
for (tri = 0; tri < numTris; tri++)
{
uint key = triangleKeys[tri];
uint v1 = indices[index++];
uint v2 = indices[index++];
uint v3 = indices[index++];
addEdge(v1, v2, key);
addEdge(v2, v3, key);
addEdge(v3, v1, key);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void TriangleMeshEdgeExtractor::addEdge(uint v1, uint v2, uint key)
{
int64 edgeKeyVal = 0;
if (v1 < v2)
{
edgeKeyVal = v2;
edgeKeyVal <<= 32;
edgeKeyVal += v1;
}
else
{
edgeKeyVal = v1;
edgeKeyVal <<= 32;
edgeKeyVal += v2;
}
std::map<int64, uint>::iterator it = m_edgeMap.find(edgeKeyVal);
if (it != m_edgeMap.end())
{
uint foundKey = it->second;
if (foundKey == key)
{
// Remove edge from map and return
m_edgeMap.erase(it);
}
}
else
{
m_edgeMap[edgeKeyVal] = key;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ref<UIntArray> TriangleMeshEdgeExtractor::lineIndices() const
{
ref<UIntArray> indices = new UIntArray;
size_t numEdges = m_edgeMap.size();
if (numEdges == 0)
{
return indices;
}
indices->reserve(2*numEdges);
std::map<cvf::int64, uint>::const_iterator it;
for (it = m_edgeMap.begin(); it != m_edgeMap.end(); ++it)
{
int64 edgeKey = it->first;
uint v1 = static_cast<uint>(edgeKey);
uint v2 = static_cast<uint>(edgeKey>>32);
indices->add(v1);
indices->add(v2);
}
return indices;
}
} // namespace cvf

View File

@@ -0,0 +1,63 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
#include "cvfArray.h"
#include <map>
namespace cvf {
//==================================================================================================
//
// Extract mesh from triangles with a key per triangle. Mesh edges will not be produced between
// triangles with the same key.
//
//==================================================================================================
class TriangleMeshEdgeExtractor
{
public:
TriangleMeshEdgeExtractor();
void addTriangles(const UIntArray& indices, const UIntArray& triangleKeys);
ref<UIntArray> lineIndices() const;
private:
std::map<int64, uint> m_edgeMap;
inline int64 edgeKey(uint v1, uint v2)
{
if (v1 < v2)
{
int64 key = v2;
key <<= 32;
return key + v1;
}
int64 key = v1;
key <<= 32;
return key + v2;
}
void addEdge(uint v1, uint v2, uint key);
};
}

View File

@@ -0,0 +1,322 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfTriangleVertexSplitter.h"
#include "cvfFrustum.h"
#include "cvfOutlineEdgeExtractor.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::TriangleVertexSplitter
/// \ingroup Geometry
///
/// This class takes a triangle mesh and duplicates nodes on edges where the normal of the two triangles
/// on the edge differ more than the given crease angle.
///
/// The vertices are also compacted, so the returned vertexArray() contains only the vertices
/// referenced by the triangles.
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TriangleVertexSplitter::TriangleVertexSplitter(double creaseAngle, const cvf::UIntValueArray& origTriangleIndices, const cvf::Vec3fValueArray& origVertexArray)
: m_creaseAngle(creaseAngle),
m_origTriangleIndices(origTriangleIndices),
m_origVertexArray(origVertexArray),
m_isComputed(false)
{
}
//--------------------------------------------------------------------------------------------------
/// Returns the new connectivity table for the triangles. Same size as the input origTriangleIndices
/// array
//--------------------------------------------------------------------------------------------------
ref<UIntArray> TriangleVertexSplitter::triangleIndices()
{
if (!m_isComputed)
{
splitVertices();
}
return m_triangleIndices;
}
//--------------------------------------------------------------------------------------------------
/// Returns the new vertex array containg only the referenced nodes in the triangle mesh, but with
/// split nodes wherever needed.
//--------------------------------------------------------------------------------------------------
ref<Vec3fArray> TriangleVertexSplitter::vertexArray()
{
if (!m_isComputed)
{
splitVertices();
}
ref<Vec3fArray> output = new Vec3fArray(m_vertexArray);
return output;
}
//--------------------------------------------------------------------------------------------------
/// Returns an array with vertex indices into the input origVertexArray for each vertex in the
/// output vertexArray(). Used to keep track of the original index of the compacted and split output
/// array.
//--------------------------------------------------------------------------------------------------
ref<UIntArray> TriangleVertexSplitter::perVertexOriginalIndices()
{
if (!m_isComputed)
{
splitVertices();
}
size_t numUsedVertices = m_vertexArray.size();
ref<UIntArray> output = new UIntArray;
if (numUsedVertices == 0)
{
return output;
}
output->resize(numUsedVertices);
output->setAll(UNDEFINED_UINT);
size_t numOrigVertices = m_origVertexArray.size();
size_t i;
for (i = 0; i < numOrigVertices; i++)
{
uint usedIdx = m_origToUsedNodeMap[i];
if (usedIdx != UNDEFINED_UINT)
{
output->set(usedIdx, static_cast<uint>(i));
}
}
for (i = 0; i < numUsedVertices; i++)
{
if (output->get(i) != UNDEFINED_UINT)
{
uint origIndex = output->get(i);
uint nextSplit = m_nextSplitVertexIdx[i];
m_nextSplitVertexIdx[i] = UNDEFINED_UINT;
while (nextSplit != UNDEFINED_UINT)
{
CVF_TIGHT_ASSERT(output->get(nextSplit) == UNDEFINED_UINT);
output->set(nextSplit, origIndex);
uint nextSplitThis = nextSplit;
nextSplit = m_nextSplitVertexIdx[nextSplit];
m_nextSplitVertexIdx[nextSplitThis] = UNDEFINED_UINT;
}
}
}
return output;
}
//--------------------------------------------------------------------------------------------------
/// Returns an array of smooth per vertex normals corresponding to the output vertexArray().
//--------------------------------------------------------------------------------------------------
ref<Vec3fArray> TriangleVertexSplitter::vertexNormals()
{
if (!m_isComputed)
{
splitVertices();
}
size_t numVertices = m_normalArray.size();
ref<Vec3fArray> output = new Vec3fArray;
if (numVertices == 0)
{
return output;
}
output->reserve(numVertices);
size_t i;
for (i = 0; i < numVertices; i++)
{
output->add(m_normalArray[i].getNormalized());
}
return output;
}
//--------------------------------------------------------------------------------------------------
/// Worker. Split the vertices that needs splitting and compact the vertexArray and indices.
//--------------------------------------------------------------------------------------------------
void TriangleVertexSplitter::splitVertices()
{
CVF_ASSERT(!m_isComputed);
m_isComputed = true;
// Handle empty data;
if (m_origTriangleIndices.size() == 0)
{
m_triangleIndices = new UIntArray;
return;
}
size_t origVertexCount = m_origVertexArray.size();
m_triangleIndices = new UIntArray(m_origTriangleIndices);
m_vertexArray.reserve(origVertexCount);
m_normalArray.reserve(origVertexCount);
m_nextSplitVertexIdx.reserve(origVertexCount);
m_origToUsedNodeMap.resize(origVertexCount);
m_origToUsedNodeMap.setAll(UNDEFINED_UINT);
size_t origConnIndex = 0;
size_t numTris = m_triangleIndices->size() / 3;
size_t tri;
for (tri = 0; tri < numTris; tri++)
{
uint c0 = m_origTriangleIndices.val(origConnIndex);
uint c1 = m_origTriangleIndices.val(origConnIndex + 1);
uint c2 = m_origTriangleIndices.val(origConnIndex + 2);
// Compute normal
Vec3f v0 = m_origVertexArray.val(c0);
Vec3f v1 = m_origVertexArray.val(c1);
Vec3f v2 = m_origVertexArray.val(c2);
Vec3f normal = (v1 - v0) ^ (v2 - v0);
normal.normalize();
uint newConn1 = processVertex(c0, normal);
uint newConn2 = processVertex(c1, normal);
uint newConn3 = processVertex(c2, normal);
m_triangleIndices->set(origConnIndex, newConn1);
m_triangleIndices->set(origConnIndex + 1, newConn2);
m_triangleIndices->set(origConnIndex + 2, newConn3);
origConnIndex += 3;
}
}
//--------------------------------------------------------------------------------------------------
/// Returns the new index of the given vertex based on if the vertex will be split or not.
//--------------------------------------------------------------------------------------------------
uint TriangleVertexSplitter::processVertex(uint origVertexIndex, const Vec3f& faceNormal)
{
uint vertexIndex = m_origToUsedNodeMap[origVertexIndex];
if (vertexIndex == UNDEFINED_UINT)
{
vertexIndex = static_cast<uint>(m_vertexArray.size());
m_origToUsedNodeMap[origVertexIndex] = vertexIndex;
m_vertexArray.push_back(m_origVertexArray.val(origVertexIndex));
m_normalArray.push_back(faceNormal);
m_nextSplitVertexIdx.push_back(UNDEFINED_UINT);
return vertexIndex;
}
uint outputIndex = vertexIndex;
for(;;)
{
const Vec3f& vertexNormal = m_normalArray[outputIndex].getNormalized();
if (isNormalDifferenceBelowThreshold(faceNormal, vertexNormal))
{
m_normalArray[outputIndex] += faceNormal;
return outputIndex;
}
else
{
uint nextVertexIndex = m_nextSplitVertexIdx[outputIndex];
if (nextVertexIndex == UNDEFINED_UINT)
{
// Cannot average with any existing normal in orig or new split vertices
uint newVertexIndex = static_cast<uint>(m_vertexArray.size());
m_nextSplitVertexIdx[outputIndex] = newVertexIndex;
outputIndex = newVertexIndex;
m_vertexArray.push_back(m_vertexArray[vertexIndex]);
m_normalArray.push_back(faceNormal);
m_nextSplitVertexIdx.push_back(UNDEFINED_UINT);
return outputIndex;
}
outputIndex = nextVertexIndex;
}
}
}
//--------------------------------------------------------------------------------------------------
/// Return true if the angle between the two normals are below the current crease angle.
//--------------------------------------------------------------------------------------------------
bool TriangleVertexSplitter::isNormalDifferenceBelowThreshold(const Vec3f& n1, const Vec3f& n2)
{
if (n1.isZero() || n2.isZero())
{
return false;
}
double dotProduct = n1*n2;
// Guard acos against out-of-domain input
if (dotProduct <= -1.0)
{
dotProduct = -1.0;
}
else if (dotProduct >= 1.0)
{
dotProduct = 1.0;
}
double angle = Math::acos(dotProduct);
if (Math::abs(angle) < m_creaseAngle)
{
return true;
}
else if (Math::abs(angle) >= m_creaseAngle)
{
return false;
}
return false;
}
} // namespace cvf

View File

@@ -0,0 +1,59 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
#include "cvfArray.h"
namespace cvf {
//=================================================================================================
//
// Triangle Vertex Splitter Class
//
//=================================================================================================
class TriangleVertexSplitter
{
public:
TriangleVertexSplitter(double creaseAngle, const UIntValueArray& origTriangleIndices, const Vec3fValueArray& origVertexArray);
ref<UIntArray> triangleIndices();
ref<Vec3fArray> vertexArray();
ref<Vec3fArray> vertexNormals();
ref<UIntArray> perVertexOriginalIndices(); // Per vertex (source) indices into origVertexArray
private:
void splitVertices();
uint processVertex(uint origVertexIndex, const Vec3f& faceNormal);
bool isNormalDifferenceBelowThreshold(const Vec3f& n1, const Vec3f& n2);
private:
double m_creaseAngle;
const UIntValueArray& m_origTriangleIndices;
const Vec3fValueArray& m_origVertexArray;
bool m_isComputed;
ref<UIntArray> m_triangleIndices;
UIntArray m_origToUsedNodeMap;
std::vector<uint> m_nextSplitVertexIdx;
std::vector<Vec3f> m_vertexArray;
std::vector<Vec3f> m_normalArray;
};
}

View File

@@ -0,0 +1,119 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfVertexCompactor.h"
#include "cvfGeometryUtils.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::VertexCompactor
/// \ingroup Geometry
///
/// Worker class for creating compact indices based on a "global" index array
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VertexCompactor::VertexCompactor(const UIntValueArray& origIndices, const Vec3fValueArray& origVertexArray)
: m_origIndices(origIndices),
m_origVertexArray(origVertexArray)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void VertexCompactor::computeCompactedIndices()
{
m_newIndices = new UIntArray;
m_newToOldVertexIndexMapping = new UIntArray;
uint maxNumResultingVertices = static_cast<uint>(m_origVertexArray.size());
GeometryUtils::removeUnusedVertices(m_origIndices, m_newIndices.p(), m_newToOldVertexIndexMapping.p(), maxNumResultingVertices);
}
//--------------------------------------------------------------------------------------------------
/// Get indices into new vertex array
///
/// \return Newly allocated array with the new indices. An array is always returned, but may have zero entries.
//--------------------------------------------------------------------------------------------------
ref<UIntArray> VertexCompactor::indices()
{
if (m_newIndices.isNull())
{
computeCompactedIndices();
}
CVF_ASSERT(m_newIndices.notNull());
return m_newIndices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ref<Vec3fArray> VertexCompactor::vertexArray()
{
if (m_newIndices.isNull())
{
computeCompactedIndices();
}
CVF_ASSERT(m_newToOldVertexIndexMapping.notNull());
ref<Vec3fArray> vertices = new Vec3fArray;
size_t numNewVertices = m_newToOldVertexIndexMapping->size();
if (numNewVertices > 0)
{
vertices->reserve(numNewVertices);
size_t i;
for (i = 0; i < numNewVertices; i++)
{
vertices->add(m_origVertexArray.val(m_newToOldVertexIndexMapping->get(i)));
}
}
return vertices;
}
//--------------------------------------------------------------------------------------------------
/// Get array of original indices per new vertex.
///
/// The returned array will be the same size as the array of vertices returned by vertexArray().
/// The indices are the original/source indices of the vertices
//--------------------------------------------------------------------------------------------------
ref<UIntArray> VertexCompactor::perVertexOriginalIndices()
{
if (m_newToOldVertexIndexMapping.isNull())
{
computeCompactedIndices();
}
CVF_ASSERT(m_newToOldVertexIndexMapping.notNull());
return m_newToOldVertexIndexMapping;
}
} // namespace cvf

View File

@@ -0,0 +1,52 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
#include "cvfArray.h"
#include "cvfVector3.h"
namespace cvf {
//=================================================================================================
//
// Vertex Compactor class
//
//=================================================================================================
class VertexCompactor
{
public:
VertexCompactor(const UIntValueArray& origIndices, const Vec3fValueArray& origVertexArray);
ref<UIntArray> indices();
ref<Vec3fArray> vertexArray();
ref<UIntArray> perVertexOriginalIndices();
private:
void computeCompactedIndices();
private:
const UIntValueArray& m_origIndices; // Indices into the original vertex array
const Vec3fValueArray& m_origVertexArray; // Original vertex array
ref<UIntArray> m_newIndices; // Indices into new vertex array
ref<UIntArray> m_newToOldVertexIndexMapping; // For each new vertex, this array will store the vertex' original (source) index into origVertexArray
};
}

View File

@@ -0,0 +1,260 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#include "cvfBase.h"
#include "cvfVertexWelder.h"
namespace cvf {
//==================================================================================================
///
/// \class cvf::VertexWelder
/// \ingroup Geometry
///
/// Supports welding of vertices based on vertex distance
///
/// \internal Adapted from the book: "Real time collision detection' by Christer Ericson
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VertexWelder::VertexWelder()
{
m_weldEpsilon = 0;
m_cellSize = 0;
m_numBuckets = 0;
}
//--------------------------------------------------------------------------------------------------
/// Initialize, must be done before usage of object
///
/// The cell size must be at least 2*weldingDistance, but should normally be much larger. If the
/// specified cell size is too small, it will be set to approximately 2*weldingDistance
//--------------------------------------------------------------------------------------------------
void VertexWelder::initialize(double weldingDistance, double cellSize, uint numBuckets)
{
CVF_ASSERT(weldingDistance >= 0);
CVF_ASSERT(cellSize > 2*weldingDistance);
CVF_ASSERT(numBuckets > 0);
m_weldEpsilon = weldingDistance;
m_cellSize = cellSize;
if (m_cellSize < 2.1*weldingDistance)
{
m_cellSize = 2.1*weldingDistance;
}
m_numBuckets = numBuckets;
m_first.resize(numBuckets);
m_first.setAll(UNDEFINED_UINT);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void VertexWelder::reserveVertices(uint vertexCount)
{
m_vertex.reserve(vertexCount);
m_next.reserve(vertexCount);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
uint VertexWelder::weldVertex(const Vec3f& vertex, bool* wasWelded)
{
// Must be initialized
CVF_ASSERT(m_cellSize > 0 && m_numBuckets > 0);
// Make sure welding distance (epsilon) is not too small for the coordinates used!
// Not sure if we need to handle this case - unsure of what happens if epsilon gets too small.
// Guess the only trouble is that we won't look into neighbor cells, which in turn
// means that we won't be able to weld vertices even if they are closer than epsilon.
//CVF_ASSERT(vertex.x() - m_weldEpsilon != vertex.x() && vertex.x() + m_weldEpsilon != vertex.x());
//CVF_ASSERT(vertex.y() - m_weldEpsilon != vertex.y() && vertex.y() + m_weldEpsilon != vertex.y());
//CVF_ASSERT(vertex.z() - m_weldEpsilon != vertex.z() && vertex.z() + m_weldEpsilon != vertex.z());
// Compute cell coordinates of bounding box of vertex epsilon neighborhood
int left = int((vertex.x() - m_weldEpsilon) / m_cellSize);
int right = int((vertex.x() + m_weldEpsilon) / m_cellSize);
int front = int((vertex.y() - m_weldEpsilon) / m_cellSize);
int back = int((vertex.y() + m_weldEpsilon) / m_cellSize);
int bottom = int((vertex.z() - m_weldEpsilon) / m_cellSize);
int top = int((vertex.z() + m_weldEpsilon) / m_cellSize);
// To lessen effects of worst-case behavior, track previously tested buckets
// 4 in 2D, 8 in 3D
uint prevBucket[8];
int numPrevBuckets = 0;
// Loop over all overlapped cells and test against their buckets
int i;
for (i = left; i <= right; i++)
{
int j;
for (j = front; j <= back; j++)
{
int k;
for (k = bottom; k <= top; k++)
{
uint bucket = getGridCellBucket(i, j, k);
// If this bucket already tested, don't test it again
bool bucketAlreadyTested = false;
for (int b = 0; b < numPrevBuckets; b++)
{
if (bucket == prevBucket[b])
{
bucketAlreadyTested = true;
break;
}
}
if (!bucketAlreadyTested)
{
// Add this bucket to visited list, then test against its contents
CVF_ASSERT(numPrevBuckets < 8);
prevBucket[numPrevBuckets++] = bucket;
// Call function to step through linked list of bucket, testing
// if vertex is within the epsilon of one of the vertices in the bucket
uint indexOfLocatedVertex = locateVertexInBucket(vertex, bucket);
if (indexOfLocatedVertex != UNDEFINED_UINT)
{
if (wasWelded) *wasWelded = true;
return indexOfLocatedVertex;
}
}
}
}
}
// Couldn't locate vertex, so add it to grid
int x = int(vertex.x() / m_cellSize);
int y = int(vertex.y() / m_cellSize);
int z = int(vertex.z() / m_cellSize);
uint indexOfAddedVertex = addVertexToBucket(vertex, getGridCellBucket(x, y, z));
if (wasWelded) *wasWelded = false;
return indexOfAddedVertex;
}
//--------------------------------------------------------------------------------------------------
/// Maps unbounded grid cell coordinates (x, y, z) into an index into a fixed-size array of hash buckets
//--------------------------------------------------------------------------------------------------
uint VertexWelder::getGridCellBucket(int x, int y, int z) const
{
// Large multiplicative constants; here arbitrarily chosen primes
const uint magic1 = 0x8da6b343;
const uint magic2 = 0xd8163841;
const uint magic3 = 0xcb1ab31f;
uint index = magic1*x + magic2*y + z*magic3;
// Bring index into [0, m_numBuckets) range
return index % m_numBuckets;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
uint VertexWelder::locateVertexInBucket(const Vec3f& v, uint bucket) const
{
const double weldEpsilonSqared = m_weldEpsilon*m_weldEpsilon;
// Scan through linked list of vertices at this bucket
uint index = m_first[bucket];
while (index != UNDEFINED_UINT)
{
// Weld this vertex to existing vertex if within given distance tolerance
float sqDistPointPoint = (m_vertex[index] - v).lengthSquared();
if (sqDistPointPoint < weldEpsilonSqared)
{
return index;
}
index = m_next[index];
}
// No vertex found to weld to.
return UNDEFINED_UINT;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
uint VertexWelder::addVertexToBucket(const Vec3f& v, uint bucket)
{
CVF_TIGHT_ASSERT(bucket < m_numBuckets);
CVF_TIGHT_ASSERT(m_numBuckets == m_first.size());
// Fill next available vertex buffer entry and link it into vertex list
m_vertex.push_back(v);
m_next.push_back(m_first[bucket]);
CVF_TIGHT_ASSERT(m_vertex.size() == m_next.size());
uint indexOfAddedVertex = static_cast<uint>(m_vertex.size() - 1);
m_first[bucket] = indexOfAddedVertex;
return indexOfAddedVertex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
uint VertexWelder::vertexCount() const
{
return static_cast<uint>(m_vertex.size());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const Vec3f& VertexWelder::vertex(uint index) const
{
return m_vertex[index];
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
ref<Vec3fArray> VertexWelder::createVertexArray() const
{
ref<Vec3fArray> va = new Vec3fArray(m_vertex);
return va;
}
} // namespace cvf

View File

@@ -0,0 +1,68 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2012 Ceetron AS
//
// 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.
//
//##################################################################################################
#pragma once
#include "cvfArray.h"
namespace cvf {
//==================================================================================================
//
//
//
//==================================================================================================
class VertexWelder
{
public:
VertexWelder();
void initialize(double weldingDistance, double cellSize, uint numBuckets);
void reserveVertices(uint vertexCount);
uint weldVertex(const Vec3f& vertex, bool* wasWelded);
uint vertexCount() const;
const Vec3f& vertex(uint index) const;
ref<Vec3fArray> createVertexArray() const;
private:
uint getGridCellBucket(int x, int y, int z) const;
uint locateVertexInBucket(const Vec3f& v, uint bucket) const;
uint addVertexToBucket(const Vec3f& v, uint bucket);
private:
double m_weldEpsilon; // Welding tolerance, radius around vertex defining welding neighborhood
double m_cellSize; // Grid cell size; must be at least 2*m_weldEpsilon
uint m_numBuckets; // Number of hash buckets to map grid cells into
UIntArray m_first; // Start of linked list for each bucket. Number of buckets long
std::vector<uint> m_next; // Links each vertex to next in linked list. Always numVertices long, will grow as vertices are added
std::vector<Vec3f> m_vertex; // Unique vertices within tolerance
};
}