Clean project structure.
This commit is contained in:
parent
78a4fa99ff
commit
947bf937fd
496 changed files with 206 additions and 137 deletions
34
src/rendering/mesh/AbstractFace.cpp
Normal file
34
src/rendering/mesh/AbstractFace.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
#include "AbstractFace.h"
|
||||
|
||||
#include "Edge.h"
|
||||
|
||||
AbstractFace::AbstractFace(std::size_t id)
|
||||
: mId(id)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AbstractFace::~AbstractFace()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AbstractFace::addVectorAttribute(const std::string& tag, const std::vector<double>& values)
|
||||
{
|
||||
mVectorAttributes[tag] = values;
|
||||
}
|
||||
|
||||
std::vector<double> AbstractFace::getVectorAttribute(const std::string& tag) const
|
||||
{
|
||||
auto iter = mVectorAttributes.find(tag);
|
||||
if (iter != mVectorAttributes.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void AbstractFace::setIndex(std::size_t idx)
|
||||
{
|
||||
mId = idx;
|
||||
}
|
47
src/rendering/mesh/AbstractFace.h
Normal file
47
src/rendering/mesh/AbstractFace.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include "Point.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
class Edge;
|
||||
|
||||
class AbstractFace
|
||||
{
|
||||
public:
|
||||
|
||||
enum class Orientation
|
||||
{
|
||||
CW,
|
||||
CCW
|
||||
};
|
||||
|
||||
AbstractFace(std::size_t id=0);
|
||||
|
||||
virtual ~AbstractFace();
|
||||
|
||||
virtual std::vector<std::size_t> getNodeIds() const = 0;
|
||||
|
||||
void addVectorAttribute(const std::string& tag, const std::vector<double>& values);
|
||||
|
||||
std::vector<double> getVectorAttribute(const std::string& tag) const;
|
||||
|
||||
virtual std::size_t getNumNodes() const = 0;
|
||||
|
||||
virtual void associateWidthEdges() = 0;
|
||||
|
||||
virtual std::vector<std::size_t> getEdgeIds() const = 0;
|
||||
|
||||
virtual std::vector<Point> getNodeLocations(Orientation orientation = Orientation::CCW) const = 0;
|
||||
|
||||
virtual void replaceEdge(Edge* original, Edge* replacement) = 0;
|
||||
|
||||
void setIndex(std::size_t idx);
|
||||
|
||||
protected:
|
||||
std::size_t mId{0};
|
||||
std::unordered_map<std::string, std::vector<double> > mVectorAttributes;
|
||||
};
|
75
src/rendering/mesh/AbstractMesh.cpp
Normal file
75
src/rendering/mesh/AbstractMesh.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
#include "AbstractMesh.h"
|
||||
|
||||
void AbstractMesh::addConstantNodeVectorAttribute(const std::string& tag, const std::vector<double>& values)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::vector<double> > AbstractMesh::getNodeVectorAttributes(const std::string& tag)
|
||||
{
|
||||
std::vector<std::vector<double> > attribs(mNodes.size());
|
||||
return attribs;
|
||||
}
|
||||
|
||||
void AbstractMesh::addVectorAttribute(const std::string& tag, const std::vector<double>& values)
|
||||
{
|
||||
mVectorAttributes[tag] = values;
|
||||
}
|
||||
|
||||
bool AbstractMesh::hasVectorAttribute(const std::string& tag) const
|
||||
{
|
||||
return mVectorAttributes.find(tag) != mVectorAttributes.end();
|
||||
}
|
||||
|
||||
unsigned AbstractMesh::getNumNodes() const
|
||||
{
|
||||
return unsigned(mNodes.size());
|
||||
}
|
||||
|
||||
const VecNodes& AbstractMesh::getNodes() const
|
||||
{
|
||||
return mNodes;
|
||||
}
|
||||
|
||||
std::vector<double> AbstractMesh::getVectorAttribute(const std::string& tag) const
|
||||
{
|
||||
auto iter = mVectorAttributes.find(tag);
|
||||
if (iter != mVectorAttributes.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void AbstractMesh::scale(double scaleX, double scaleY)
|
||||
{
|
||||
Transform transform({ 0.0, 0.0 }, scaleX, scaleY);
|
||||
|
||||
for (auto& node : mNodes)
|
||||
{
|
||||
node->apply(transform);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractMesh::transform(const Transform& transform)
|
||||
{
|
||||
for (auto& node : mNodes)
|
||||
{
|
||||
node->apply(transform);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractMesh::translate(double offsetX, double offsetY, double offsetZ)
|
||||
{
|
||||
const Point loc {-offsetX, -offsetY, -offsetZ};
|
||||
Transform transform(loc);
|
||||
for (auto& node : mNodes)
|
||||
{
|
||||
node->apply(transform);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractMesh::translate(const Point& offset)
|
||||
{
|
||||
translate(offset.getX(), offset.getY(), offset.getZ());
|
||||
}
|
68
src/rendering/mesh/AbstractMesh.h
Normal file
68
src/rendering/mesh/AbstractMesh.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
#pragma once
|
||||
|
||||
#include "Point.h"
|
||||
#include "Node.h"
|
||||
#include "Transform.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using NodePtr = std::unique_ptr<Node>;
|
||||
using VecNodes = std::vector<NodePtr>;
|
||||
|
||||
class AbstractMesh
|
||||
{
|
||||
public:
|
||||
enum class MeshType
|
||||
{
|
||||
LINE,
|
||||
TRI,
|
||||
QUAD
|
||||
};
|
||||
|
||||
virtual ~AbstractMesh() = default;
|
||||
|
||||
void addVectorAttribute(const std::string& tag, const std::vector<double>& values);
|
||||
|
||||
void addConstantNodeVectorAttribute(const std::string& tag, const std::vector<double>& values);
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> getVerticesFlat(T scaleX = 1.0, T scaleY = 1.0, T scaleZ = 1.0) const
|
||||
{
|
||||
std::vector<T> ret(3*mNodes.size());
|
||||
for(std::size_t idx = 0; idx<mNodes.size(); idx++)
|
||||
{
|
||||
auto node = mNodes[idx].get();
|
||||
ret[3*idx] = node->getPoint().getX()/scaleX;
|
||||
ret[3*idx + 1] = node->getPoint().getY()/scaleY;
|
||||
ret[3*idx + 2] = node->getPoint().getZ()/scaleZ;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<AbstractMesh> copy() const = 0;
|
||||
|
||||
std::vector<std::vector<double> > getNodeVectorAttributes(const std::string& tag);
|
||||
|
||||
std::vector<double> getVectorAttribute(const std::string& tag) const;
|
||||
|
||||
virtual MeshType getType() const = 0;
|
||||
|
||||
bool hasVectorAttribute(const std::string& tag) const;
|
||||
|
||||
void scale(double scaleX, double scaleY);
|
||||
|
||||
void translate(const Point& offset);
|
||||
|
||||
void translate(double offsetX, double offsetY, double offsetZ = 0.0);
|
||||
|
||||
void transform(const Transform& transform);
|
||||
|
||||
unsigned getNumNodes() const;
|
||||
|
||||
const VecNodes& getNodes() const;
|
||||
|
||||
protected:
|
||||
std::unordered_map<std::string, std::vector<double> > mVectorAttributes;
|
||||
VecNodes mNodes;
|
||||
};
|
38
src/rendering/mesh/CMakeLists.txt
Normal file
38
src/rendering/mesh/CMakeLists.txt
Normal file
|
@ -0,0 +1,38 @@
|
|||
list(APPEND mesh_LIB_INCLUDES
|
||||
AbstractMesh.cpp
|
||||
AbstractMesh.h
|
||||
Edge.cpp
|
||||
Edge.h
|
||||
AbstractFace.cpp
|
||||
AbstractFace.h
|
||||
QuadFace.cpp
|
||||
QuadFace.h
|
||||
TriFace.cpp
|
||||
TriFace.h
|
||||
Node.cpp
|
||||
Node.h
|
||||
QuadMesh.cpp
|
||||
QuadMesh.h
|
||||
TriMesh.cpp
|
||||
TriMesh.h
|
||||
FaceMesh.cpp
|
||||
FaceMesh.h
|
||||
LineMesh.cpp
|
||||
LineMesh.h
|
||||
MeshPrimitives.cpp
|
||||
MeshPrimitives.h
|
||||
MeshBuilder.cpp
|
||||
MeshBuilder.h
|
||||
MeshObjWriter.h
|
||||
MeshObjWriter.cpp
|
||||
)
|
||||
|
||||
|
||||
# add the library
|
||||
add_library(mesh SHARED ${mesh_LIB_INCLUDES})
|
||||
target_link_libraries(mesh core geometry)
|
||||
|
||||
target_include_directories(mesh PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/")
|
||||
|
||||
set_target_properties( mesh PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
||||
set_property(TARGET mesh PROPERTY FOLDER src/rendering)
|
122
src/rendering/mesh/Edge.cpp
Normal file
122
src/rendering/mesh/Edge.cpp
Normal file
|
@ -0,0 +1,122 @@
|
|||
#include "Edge.h"
|
||||
|
||||
#include "Node.h"
|
||||
|
||||
Edge::Edge(Node* node0, Node* node1, std::size_t id)
|
||||
: mNode0(node0),
|
||||
mNode1(node1),
|
||||
mId(id)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<Edge> Edge::Create(Node* node0, Node* node1, std::size_t id)
|
||||
{
|
||||
return std::make_unique<Edge>(node0, node1, id);
|
||||
}
|
||||
|
||||
Edge::~Edge()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::size_t Edge::getNode0Id() const
|
||||
{
|
||||
return mNode0->getIndex();
|
||||
}
|
||||
|
||||
std::size_t Edge::getNode1Id() const
|
||||
{
|
||||
return mNode1->getIndex();
|
||||
}
|
||||
|
||||
bool Edge::isOverlapping(Edge* edge) const
|
||||
{
|
||||
auto overlaps = edge->getNode0()->isCoincident(mNode0) && edge->getNode1()->isCoincident(mNode1);
|
||||
if (overlaps)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return edge->getNode1()->isCoincident(mNode0) && edge->getNode0()->isCoincident(mNode1);
|
||||
}
|
||||
}
|
||||
|
||||
bool Edge::hasSameNodes(Edge* edge) const
|
||||
{
|
||||
return edge->getNode0() == edge->getNode1() || edge->getNode1() == edge->getNode0();
|
||||
}
|
||||
|
||||
void Edge::replaceNodes(Node* node0, Node* node1)
|
||||
{
|
||||
mNode0 = node0;
|
||||
mNode1 = node1;
|
||||
}
|
||||
|
||||
Node* Edge::getNode0() const
|
||||
{
|
||||
return mNode0;
|
||||
}
|
||||
|
||||
Node* Edge::getNode1() const
|
||||
{
|
||||
return mNode1;
|
||||
}
|
||||
|
||||
Node* Edge::getOtherNode(Node* node) const
|
||||
{
|
||||
if (node == mNode0)
|
||||
{
|
||||
return mNode1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return mNode0;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t Edge::getId() const
|
||||
{
|
||||
return mId;
|
||||
}
|
||||
|
||||
void Edge::setState(State state)
|
||||
{
|
||||
mState = state;
|
||||
}
|
||||
|
||||
Edge::State Edge::getState() const
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
void Edge::clearConnectivity()
|
||||
{
|
||||
mAssociatedFaceIds.clear();
|
||||
}
|
||||
|
||||
std::size_t Edge::getNumConnectedFaces() const
|
||||
{
|
||||
return mAssociatedFaceIds.size();
|
||||
}
|
||||
|
||||
void Edge::associateFace(std::size_t faceId)
|
||||
{
|
||||
mAssociatedFaceIds.push_back(faceId);
|
||||
}
|
||||
|
||||
std::size_t Edge::getConnectedFaceId(std::size_t idx) const
|
||||
{
|
||||
return mAssociatedFaceIds[idx];
|
||||
}
|
||||
|
||||
void Edge::associateWithNodes()
|
||||
{
|
||||
mNode0->associateEdge(mId);
|
||||
mNode1->associateEdge(mId);
|
||||
}
|
||||
|
||||
void Edge::setIndex(std::size_t idx)
|
||||
{
|
||||
mId = idx;
|
||||
}
|
65
src/rendering/mesh/Edge.h
Normal file
65
src/rendering/mesh/Edge.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class Node;
|
||||
|
||||
class Edge
|
||||
{
|
||||
public:
|
||||
enum class State
|
||||
{
|
||||
HEALTHY,
|
||||
DIRTY
|
||||
};
|
||||
|
||||
Edge(Node* node0, Node* node1, std::size_t id = 0);
|
||||
|
||||
~Edge();
|
||||
|
||||
static std::unique_ptr<Edge> Create(Node* node0, Node* node1, std::size_t id = 0);
|
||||
|
||||
void associateFace(std::size_t faceId);
|
||||
|
||||
void associateWithNodes();
|
||||
|
||||
void clearConnectivity();
|
||||
|
||||
std::size_t getConnectedFaceId(std::size_t idx) const;
|
||||
|
||||
State getState() const;
|
||||
|
||||
std::size_t getId() const;
|
||||
|
||||
std::size_t getNode0Id() const;
|
||||
|
||||
std::size_t getNode1Id() const;
|
||||
|
||||
Node* getNode0() const;
|
||||
|
||||
Node* getNode1() const;
|
||||
|
||||
std::size_t getNumConnectedFaces() const;
|
||||
|
||||
Node* getOtherNode(Node* node) const;
|
||||
|
||||
bool isOverlapping(Edge* edge) const;
|
||||
|
||||
bool hasSameNodes(Edge* edge) const;
|
||||
|
||||
void replaceNodes(Node* node0, Node* node1);
|
||||
|
||||
void setState(State state);
|
||||
|
||||
void setIndex(std::size_t idx);
|
||||
|
||||
private:
|
||||
std::size_t mId{0};
|
||||
Node* mNode0{nullptr};
|
||||
Node* mNode1{nullptr};
|
||||
|
||||
std::vector<std::size_t> mAssociatedFaceIds;
|
||||
|
||||
State mState{State::HEALTHY};
|
||||
};
|
201
src/rendering/mesh/FaceMesh.cpp
Normal file
201
src/rendering/mesh/FaceMesh.cpp
Normal file
|
@ -0,0 +1,201 @@
|
|||
#include "FaceMesh.h"
|
||||
|
||||
#include "Node.h"
|
||||
#include "Edge.h"
|
||||
#include "AbstractFace.h"
|
||||
|
||||
FaceMesh::~FaceMesh()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void FaceMesh::populate(VecNodes& nodes, VecEdges& edges, VecFaces& faces)
|
||||
{
|
||||
mNodes = std::move(nodes);
|
||||
mEdges = std::move(edges);
|
||||
mFaces = std::move(faces);
|
||||
|
||||
resetIds();
|
||||
resetConnectivity();
|
||||
}
|
||||
|
||||
const VecFaces& FaceMesh::getFaces() const
|
||||
{
|
||||
return mFaces;
|
||||
}
|
||||
|
||||
std::vector<std::size_t> FaceMesh::getFaceNodeIds() const
|
||||
{
|
||||
if (mFaces.empty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto nodes_per_face = mFaces[0]->getNumNodes();
|
||||
std::vector<std::size_t> ids(nodes_per_face*mFaces.size());
|
||||
|
||||
for(std::size_t idx=0; idx<mFaces.size(); idx++)
|
||||
{
|
||||
const auto nodeIds = mFaces[idx]->getNodeIds();
|
||||
for(std::size_t jdx=0; jdx<nodes_per_face; jdx++)
|
||||
{
|
||||
ids[nodes_per_face*idx + jdx] = nodeIds[jdx];
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double> > FaceMesh::getFaceVectorAttributes(const std::string& tag)
|
||||
{
|
||||
std::vector<std::vector<double> > attribs(mFaces.size());
|
||||
for(std::size_t idx=0; idx<mFaces.size(); idx++)
|
||||
{
|
||||
attribs[idx] = {mFaces[idx]->getVectorAttribute(tag)};
|
||||
}
|
||||
return attribs;
|
||||
}
|
||||
|
||||
void FaceMesh::addConstantFaceVectorAttribute(const std::string& tag, const std::vector<double>& values)
|
||||
{
|
||||
for (const auto& face : mFaces)
|
||||
{
|
||||
face->addVectorAttribute(tag, values);
|
||||
}
|
||||
}
|
||||
|
||||
void FaceMesh::resetIds()
|
||||
{
|
||||
std::size_t count = 0;
|
||||
for (auto& node : mNodes)
|
||||
{
|
||||
node->setIndex(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
for (auto& edge : mEdges)
|
||||
{
|
||||
edge->setIndex(count);
|
||||
count++;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
for (auto& face : mFaces)
|
||||
{
|
||||
face->setIndex(count);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
void FaceMesh::resetConnectivity()
|
||||
{
|
||||
for (auto& node : mNodes)
|
||||
{
|
||||
node->clearConnectivity();
|
||||
}
|
||||
|
||||
for (auto& edge : mEdges)
|
||||
{
|
||||
edge->associateWithNodes();
|
||||
edge->clearConnectivity();
|
||||
}
|
||||
|
||||
for (auto& face : mFaces)
|
||||
{
|
||||
face->associateWidthEdges();
|
||||
}
|
||||
}
|
||||
|
||||
void FaceMesh::replaceIfOverlapping(FaceMesh* mesh, Node* target_node) const
|
||||
{
|
||||
for (auto& node : mNodes)
|
||||
{
|
||||
if (node->getNumConnectedEdges() == 3 && node->isCoincident(target_node))
|
||||
{
|
||||
target_node->setState(Node::State::DIRTY);
|
||||
for (std::size_t idx=0; idx<3; idx++)
|
||||
{
|
||||
auto edge = mesh->mEdges[idx].get();
|
||||
edge->replaceNodes(target_node, node.get());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FaceMesh::replaceIfOverlapping(FaceMesh* mesh, Edge* target_edge) const
|
||||
{
|
||||
for (auto& edge : mEdges)
|
||||
{
|
||||
if (edge->getNumConnectedFaces() == 2 && target_edge->hasSameNodes(edge.get()))
|
||||
{
|
||||
target_edge->setState(Edge::State::DIRTY);
|
||||
for (std::size_t idx=0; idx<2; idx++)
|
||||
{
|
||||
auto face = mesh->mFaces[idx].get();
|
||||
face->replaceEdge(target_edge, edge.get());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::size_t> FaceMesh::getEdgeNodeIds() const
|
||||
{
|
||||
std::vector<std::size_t> ids(2*mEdges.size());
|
||||
for(std::size_t idx=0; idx<mEdges.size(); idx++)
|
||||
{
|
||||
ids[2*idx] = mEdges[idx]->getNode0Id();
|
||||
ids[2*idx + 1] = mEdges[idx]->getNode1Id();
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
void FaceMesh::merge(std::unique_ptr<FaceMesh> mesh)
|
||||
{
|
||||
if (mesh->getType() != getType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& node : mesh->mNodes)
|
||||
{
|
||||
if (node->getNumConnectedEdges() == 3)
|
||||
{
|
||||
replaceIfOverlapping(mesh.get(), node.get());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& node : mesh->mNodes)
|
||||
{
|
||||
if (node->getState() == Node::State::HEALTHY)
|
||||
{
|
||||
mNodes.push_back(std::move(node));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& edge : mesh->mEdges)
|
||||
{
|
||||
if (edge->getNumConnectedFaces() == 2)
|
||||
{
|
||||
replaceIfOverlapping(mesh.get(), edge.get());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& edge : mesh->mEdges)
|
||||
{
|
||||
if (edge->getState() == Edge::State::HEALTHY)
|
||||
{
|
||||
mEdges.push_back(std::move(edge));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& face : mesh->mFaces)
|
||||
{
|
||||
mFaces.push_back(std::move(face));
|
||||
}
|
||||
|
||||
mesh.reset();
|
||||
resetIds();
|
||||
resetConnectivity();
|
||||
}
|
51
src/rendering/mesh/FaceMesh.h
Normal file
51
src/rendering/mesh/FaceMesh.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractMesh.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class Edge;
|
||||
class AbstractFace;
|
||||
|
||||
using EdgePtr = std::unique_ptr<Edge>;
|
||||
using AbstractFacePtr = std::unique_ptr<AbstractFace>;
|
||||
|
||||
using VecEdges = std::vector<EdgePtr>;
|
||||
using VecFaces = std::vector<AbstractFacePtr>;
|
||||
|
||||
class FaceMesh : public AbstractMesh
|
||||
{
|
||||
public:
|
||||
FaceMesh() = default;
|
||||
|
||||
~FaceMesh();
|
||||
|
||||
virtual std::unique_ptr<AbstractMesh> copy() const = 0;
|
||||
|
||||
void populate(VecNodes& nodes, VecEdges& edges, VecFaces& faces);
|
||||
|
||||
std::vector<std::size_t> getFaceNodeIds() const;
|
||||
|
||||
std::vector<std::size_t> getEdgeNodeIds() const;
|
||||
|
||||
void addConstantFaceVectorAttribute(const std::string& tag, const std::vector<double>& values);
|
||||
|
||||
std::vector<std::vector<double> > getFaceVectorAttributes(const std::string& tag);
|
||||
|
||||
void merge(std::unique_ptr<FaceMesh> mesh);
|
||||
|
||||
const VecFaces& getFaces() const;
|
||||
|
||||
protected:
|
||||
void resetConnectivity();
|
||||
|
||||
void resetIds();
|
||||
|
||||
void replaceIfOverlapping(FaceMesh* mesh, Node* node) const;
|
||||
|
||||
void replaceIfOverlapping(FaceMesh* mesh, Edge* edge) const;
|
||||
|
||||
VecEdges mEdges;
|
||||
VecFaces mFaces;
|
||||
};
|
35
src/rendering/mesh/LineMesh.cpp
Normal file
35
src/rendering/mesh/LineMesh.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include "LineMesh.h"
|
||||
|
||||
#include "Edge.h"
|
||||
|
||||
LineMesh::~LineMesh()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LineMesh::populate(VecNodes& nodes, VecEdges& edges)
|
||||
{
|
||||
mNodes = std::move(nodes);
|
||||
mEdges = std::move(edges);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractMesh> LineMesh::copy() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LineMesh::MeshType LineMesh::getType() const
|
||||
{
|
||||
return LineMesh::MeshType::LINE;
|
||||
}
|
||||
|
||||
std::vector<std::size_t> LineMesh::getEdgeNodeIds() const
|
||||
{
|
||||
std::vector<std::size_t> ids(2*mEdges.size());
|
||||
for(std::size_t idx=0; idx<mEdges.size(); idx++)
|
||||
{
|
||||
ids[2*idx] = mEdges[idx]->getNode0Id();
|
||||
ids[2*idx + 1] = mEdges[idx]->getNode1Id();
|
||||
}
|
||||
return ids;
|
||||
}
|
29
src/rendering/mesh/LineMesh.h
Normal file
29
src/rendering/mesh/LineMesh.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractMesh.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class Edge;
|
||||
using EdgePtr = std::unique_ptr<Edge>;
|
||||
using VecEdges = std::vector<EdgePtr>;
|
||||
|
||||
class LineMesh : public AbstractMesh
|
||||
{
|
||||
public:
|
||||
LineMesh() = default;
|
||||
|
||||
~LineMesh();
|
||||
|
||||
void populate(VecNodes& nodes, VecEdges& edges);
|
||||
|
||||
std::vector<std::size_t> getEdgeNodeIds() const;
|
||||
|
||||
MeshType getType() const override;
|
||||
|
||||
std::unique_ptr<AbstractMesh> copy() const override;
|
||||
|
||||
private:
|
||||
VecEdges mEdges;
|
||||
};
|
55
src/rendering/mesh/MeshBuilder.cpp
Normal file
55
src/rendering/mesh/MeshBuilder.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
#include "MeshBuilder.h"
|
||||
|
||||
#include "Node.h"
|
||||
#include "Edge.h"
|
||||
#include "TriFace.h"
|
||||
|
||||
std::unique_ptr<TriMesh> MeshBuilder::buildTriMesh(const VecPoints& locations, const EdgeIds& edgeIds, const FaceIds& faceIds)
|
||||
{
|
||||
auto mesh = std::make_unique<TriMesh>();
|
||||
|
||||
VecNodes nodes(locations.size());
|
||||
for (std::size_t idx=0; idx<locations.size(); idx++)
|
||||
{
|
||||
nodes[idx] = Node::Create(locations[idx], idx);
|
||||
}
|
||||
|
||||
VecEdges edges(edgeIds.size());
|
||||
for (std::size_t idx=0; idx<edgeIds.size(); idx++)
|
||||
{
|
||||
edges[idx] = Edge::Create(nodes[edgeIds[idx].first].get(), nodes[edgeIds[idx].second].get(), idx);
|
||||
}
|
||||
|
||||
VecFaces faces(faceIds.size());
|
||||
for (std::size_t idx=0; idx<faceIds.size(); idx++)
|
||||
{
|
||||
faces[idx] = TriFace::Create(
|
||||
edges[faceIds[idx][0]].get(),
|
||||
edges[faceIds[idx][1]].get(),
|
||||
edges[faceIds[idx][2]].get(),
|
||||
idx);
|
||||
}
|
||||
|
||||
mesh->populate(nodes, edges, faces);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
std::unique_ptr<LineMesh> MeshBuilder::buildLineMesh(const VecPoints& locations, const EdgeIds& edgeIds)
|
||||
{
|
||||
auto mesh = std::make_unique<LineMesh>();
|
||||
|
||||
VecNodes nodes(locations.size());
|
||||
for (std::size_t idx=0; idx<locations.size(); idx++)
|
||||
{
|
||||
nodes[idx] = Node::Create(locations[idx], idx);
|
||||
}
|
||||
|
||||
VecEdges edges(edgeIds.size());
|
||||
for (std::size_t idx=0; idx<edgeIds.size(); idx++)
|
||||
{
|
||||
edges[idx] = Edge::Create(nodes[edgeIds[idx].first].get(), nodes[edgeIds[idx].second].get(), idx);
|
||||
}
|
||||
|
||||
mesh->populate(nodes, edges);
|
||||
return mesh;
|
||||
}
|
19
src/rendering/mesh/MeshBuilder.h
Normal file
19
src/rendering/mesh/MeshBuilder.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "TriMesh.h"
|
||||
#include "LineMesh.h"
|
||||
#include "Point.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
using EdgeIds = std::vector<std::pair<std::size_t, std::size_t> >;
|
||||
using FaceIds = std::vector<std::vector<std::size_t> >;
|
||||
using VecPoints = std::vector<Point>;
|
||||
|
||||
class MeshBuilder
|
||||
{
|
||||
public:
|
||||
static std::unique_ptr<TriMesh> buildTriMesh(const VecPoints& locations, const EdgeIds& edgeIds, const FaceIds& faceIds);
|
||||
|
||||
static std::unique_ptr<LineMesh> buildLineMesh(const VecPoints& locations, const EdgeIds& edgeIds);
|
||||
};
|
32
src/rendering/mesh/MeshObjWriter.cpp
Normal file
32
src/rendering/mesh/MeshObjWriter.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#include "MeshObjWriter.h"
|
||||
|
||||
#include "File.h"
|
||||
#include "TriMesh.h"
|
||||
#include "AbstractFace.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
std::string MeshObjWriter::serialize(TriMesh* mesh)
|
||||
{
|
||||
std::stringstream output;
|
||||
for (const auto& node : mesh->getNodes())
|
||||
{
|
||||
const auto x = node->getPoint().getX();
|
||||
const auto y = node->getPoint().getY();
|
||||
const auto z = node->getPoint().getZ();
|
||||
output << "v "<< x << " " << y << " " << z << "\n";
|
||||
}
|
||||
|
||||
for (const auto& face : mesh->getFaces())
|
||||
{
|
||||
auto ids = face->getNodeIds();
|
||||
output << "f " << 1 + ids[0] << " " << 1 + ids[1] << " " << 1 + ids[2] << "\n";
|
||||
}
|
||||
return output.str();
|
||||
}
|
||||
|
||||
void MeshObjWriter::write(const Path& path, TriMesh* mesh)
|
||||
{
|
||||
File file(path);
|
||||
file.writeText(serialize(mesh));
|
||||
}
|
14
src/rendering/mesh/MeshObjWriter.h
Normal file
14
src/rendering/mesh/MeshObjWriter.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
using Path = std::filesystem::path;
|
||||
class TriMesh;
|
||||
|
||||
class MeshObjWriter
|
||||
{
|
||||
public:
|
||||
static std::string serialize(TriMesh* mesh);
|
||||
static void write(const Path& path, TriMesh* mesh);
|
||||
};
|
305
src/rendering/mesh/MeshPrimitives.cpp
Normal file
305
src/rendering/mesh/MeshPrimitives.cpp
Normal file
|
@ -0,0 +1,305 @@
|
|||
#include "MeshPrimitives.h"
|
||||
|
||||
#include "MeshBuilder.h"
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
std::unique_ptr<TriMesh> MeshPrimitives::buildRectangleAsTriMesh()
|
||||
{
|
||||
VecPoints locations = {
|
||||
{0, 0},
|
||||
{1, 0},
|
||||
{1, 1},
|
||||
{0, 1}
|
||||
};
|
||||
|
||||
EdgeIds edge_ids = {
|
||||
{0, 1},
|
||||
{1, 2},
|
||||
{2, 0},
|
||||
{2, 3},
|
||||
{3, 0}
|
||||
};
|
||||
|
||||
FaceIds face_ids = {
|
||||
{0, 1, 2},
|
||||
{2, 3, 4}
|
||||
};
|
||||
|
||||
return MeshBuilder::buildTriMesh(locations, edge_ids, face_ids);
|
||||
}
|
||||
|
||||
std::unique_ptr<TriMesh> MeshPrimitives::buildCircleAsTriMesh(std::size_t numSegments)
|
||||
{
|
||||
VecPoints locations(numSegments + 1);
|
||||
locations[0] = {0, 0};
|
||||
|
||||
const double delta_theta = (2.0*M_PI)/double(numSegments);
|
||||
double theta = 0.0;
|
||||
for(std::size_t idx=1; idx<=numSegments; idx++)
|
||||
{
|
||||
const double x = sin(theta);
|
||||
const double y = cos(theta);
|
||||
locations[idx] = {x, y};
|
||||
theta += delta_theta;
|
||||
std::cout << "Adding node at: " << x << " | " << y << std::endl;
|
||||
}
|
||||
|
||||
EdgeIds edge_ids(2*numSegments);
|
||||
for(std::size_t idx=0; idx<numSegments; idx++)
|
||||
{
|
||||
edge_ids[idx] = {0, idx+1};
|
||||
|
||||
auto wrap_node = idx + 2;
|
||||
if (wrap_node > numSegments)
|
||||
{
|
||||
wrap_node = 1;
|
||||
}
|
||||
edge_ids[idx + numSegments] = {idx + 1, wrap_node};
|
||||
}
|
||||
|
||||
FaceIds face_ids(numSegments);
|
||||
for(std::size_t idx=0; idx<numSegments; idx++)
|
||||
{
|
||||
auto top_edge_inner = idx + 1;
|
||||
if (top_edge_inner == numSegments)
|
||||
{
|
||||
top_edge_inner = 0;
|
||||
}
|
||||
|
||||
const auto outer_edge = idx + numSegments;
|
||||
face_ids[idx] = {idx, outer_edge, top_edge_inner};
|
||||
}
|
||||
return MeshBuilder::buildTriMesh(locations, edge_ids, face_ids);
|
||||
}
|
||||
|
||||
std::unique_ptr<LineMesh> MeshPrimitives::buildCircleAsLineMesh(std::size_t numSegments)
|
||||
{
|
||||
VecPoints locations(numSegments);
|
||||
const double delta_theta = (2.0*M_PI)/double(numSegments);
|
||||
double theta = 0.0;
|
||||
for(unsigned idx=0; idx<numSegments; idx++)
|
||||
{
|
||||
const double x = sin(theta);
|
||||
const double y = cos(theta);
|
||||
locations[idx] = {x, y};
|
||||
}
|
||||
|
||||
EdgeIds edge_ids(2*numSegments);
|
||||
for(unsigned idx=0; idx<numSegments; idx++)
|
||||
{
|
||||
auto top_node = idx + 1;
|
||||
if (top_node == numSegments)
|
||||
{
|
||||
top_node = 0;
|
||||
}
|
||||
edge_ids[idx] = {idx, top_node};
|
||||
}
|
||||
return MeshBuilder::buildLineMesh(locations, edge_ids);
|
||||
}
|
||||
|
||||
std::unique_ptr<TriMesh> MeshPrimitives::buildRoundedRectangleAsTriMesh(double radius, double aspect_ratio, std::size_t num_segments)
|
||||
{
|
||||
std::size_t num_fans = 4;
|
||||
std::size_t num_nodes_per_fan = num_segments + 2;
|
||||
VecPoints locations(num_fans * num_nodes_per_fan);
|
||||
|
||||
double rect_start_x = radius;
|
||||
double rect_end_x = 1.0 - radius;
|
||||
double rect_end_y = 1.0 - radius;
|
||||
|
||||
double delta_theta = (M_PI/4.0) / double (num_segments);
|
||||
double running_theta = 0;
|
||||
|
||||
locations[0] = {rect_end_x, radius};
|
||||
std::size_t offset = 1;
|
||||
for (std::size_t idx=0; idx<=num_segments; idx++)
|
||||
{
|
||||
locations[offset + idx] = {rect_end_x + radius*sin(running_theta), radius*(1.0 - cos(running_theta))};
|
||||
running_theta += delta_theta;
|
||||
}
|
||||
offset += num_segments;
|
||||
|
||||
locations[offset] = {rect_end_x, rect_end_y};
|
||||
offset++;
|
||||
running_theta = 0;
|
||||
for (std::size_t idx=0; idx<=num_segments;idx++)
|
||||
{
|
||||
locations[offset + idx] = {rect_end_x + radius*cos(running_theta), rect_end_y + radius*sin(running_theta)};
|
||||
running_theta += delta_theta;
|
||||
}
|
||||
offset += num_segments;
|
||||
|
||||
locations[offset] = {rect_start_x, rect_end_y};
|
||||
offset ++;
|
||||
running_theta = 0;
|
||||
for (std::size_t idx=0; idx<=num_segments;idx++)
|
||||
{
|
||||
locations[offset + idx] = {rect_start_x - radius*sin(running_theta), rect_end_y + radius*cos(running_theta)};
|
||||
running_theta += delta_theta;
|
||||
}
|
||||
offset += num_segments;
|
||||
|
||||
locations[offset] = {rect_start_x, radius};
|
||||
offset++;
|
||||
running_theta = 0;
|
||||
for (std::size_t idx=0; idx<=num_segments;idx++)
|
||||
{
|
||||
locations[offset + idx] = {rect_start_x - radius*cos(running_theta), radius *(1 - sin(running_theta))};
|
||||
running_theta += delta_theta;
|
||||
}
|
||||
|
||||
std::size_t num_edges_per_fan = 2*num_segments + 1;
|
||||
std::size_t num_inner_rect_edges = 3*num_fans;
|
||||
EdgeIds edge_ids(num_edges_per_fan*num_fans + num_inner_rect_edges + 1);
|
||||
|
||||
// Fan edges
|
||||
for (std::size_t jdx=0; jdx< num_fans; jdx++)
|
||||
{
|
||||
std::size_t node_offset = jdx*num_nodes_per_fan;
|
||||
std::size_t edge_offset = jdx*num_edges_per_fan;
|
||||
|
||||
// Inner edges
|
||||
for(std::size_t idx=0; idx<=num_segments; idx++)
|
||||
{
|
||||
edge_ids[edge_offset + idx] = {node_offset, node_offset + idx + 1};
|
||||
}
|
||||
|
||||
// Outer edges
|
||||
for(std::size_t idx=0; idx<num_segments; idx++)
|
||||
{
|
||||
edge_ids[edge_offset + num_segments + 1 + idx] = {node_offset + idx + 1, node_offset + idx + 2};
|
||||
}
|
||||
}
|
||||
|
||||
// Inner rect edges
|
||||
std::size_t edge_offset = num_edges_per_fan*num_fans;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<LineMesh> MeshPrimitives::buildRectangleAsLineMesh()
|
||||
{
|
||||
VecPoints locations = {
|
||||
{0, 0},
|
||||
{1, 0},
|
||||
{1, 1},
|
||||
{0, 1}
|
||||
};
|
||||
|
||||
EdgeIds edge_ids = {
|
||||
{0, 1},
|
||||
{1, 2},
|
||||
{2, 3},
|
||||
{3, 0}
|
||||
};
|
||||
|
||||
return MeshBuilder::buildLineMesh(locations, edge_ids);
|
||||
}
|
||||
|
||||
std::unique_ptr<TriMesh> MeshPrimitives::buildExplodedGridAsTriMesh(std::size_t numX, std::size_t numY)
|
||||
{
|
||||
double delta_x = 1.0/double(numX);
|
||||
double delta_y = 1.0/double(numY);
|
||||
|
||||
VecPoints locations (4 * numX * numY);
|
||||
double offset_x = delta_x/2.0;
|
||||
double offset_y = delta_y/2.0;
|
||||
for (std::size_t idx=0; idx<numY; idx++)
|
||||
{
|
||||
for(std::size_t jdx=0; jdx<numX; jdx++)
|
||||
{
|
||||
auto locX0 = offset_x - delta_x/2.0;
|
||||
auto locX1 = offset_x + delta_x/2.0;
|
||||
auto locY0 = offset_y - delta_y/2.0;
|
||||
auto locY1 = offset_y + delta_y/2.0;
|
||||
|
||||
auto id_offset = 4* (jdx + numX*idx);
|
||||
locations[id_offset] = Point(locX0, locY0);
|
||||
locations[id_offset + 1] = Point(locX1, locY0);
|
||||
locations[id_offset + 2] = Point(locX1, locY1);
|
||||
locations[id_offset + 3] = Point(locX0, locY1);
|
||||
|
||||
offset_x += delta_x;
|
||||
}
|
||||
offset_x = delta_x/2.0;
|
||||
offset_y += delta_y;
|
||||
}
|
||||
|
||||
EdgeIds edge_ids(5 * numX * numY);
|
||||
for (std::size_t idx=0; idx<numY; idx++)
|
||||
{
|
||||
for(std::size_t jdx=0; jdx<numX; jdx++)
|
||||
{
|
||||
std::size_t node_offset = 4 * (jdx + numX * idx);
|
||||
auto id_offset = 5* (jdx + numX*idx);
|
||||
edge_ids[id_offset] = {node_offset, node_offset + 1};
|
||||
edge_ids[id_offset + 1] = {node_offset + 1, node_offset + 2};
|
||||
edge_ids[id_offset + 2] = {node_offset + 2, node_offset + 3};
|
||||
edge_ids[id_offset + 3] = {node_offset + 3, node_offset};
|
||||
edge_ids[id_offset + 4] = {node_offset + 2, node_offset};
|
||||
}
|
||||
}
|
||||
|
||||
FaceIds face_ids(2 *numX * numY);
|
||||
for (std::size_t idx=0; idx<numY; idx++)
|
||||
{
|
||||
for(std::size_t jdx=0; jdx<numX; jdx++)
|
||||
{
|
||||
std::size_t edge_offset = 5 * (jdx + numX * idx);
|
||||
std::size_t face_offset = 2 * (jdx + numX * idx);
|
||||
face_ids[face_offset] = {edge_offset, edge_offset + 1, edge_offset + 4};
|
||||
face_ids[face_offset + 1] = {edge_offset + 4, edge_offset + 2, edge_offset + 3};
|
||||
}
|
||||
}
|
||||
|
||||
return MeshBuilder::buildTriMesh(locations, edge_ids, face_ids);
|
||||
}
|
||||
|
||||
std::unique_ptr<LineMesh> MeshPrimitives::buildExplodedGridAsLineMesh(std::size_t numX, std::size_t numY)
|
||||
{
|
||||
double delta_x = 1.0/double(numX);
|
||||
double delta_y = 1.0/double(numY);
|
||||
|
||||
VecPoints locations (4 * numX * numY);
|
||||
double offset_x = delta_x/2.0;
|
||||
double offset_y = delta_y/2.0;
|
||||
for (std::size_t idx=0; idx<numY; idx++)
|
||||
{
|
||||
for(std::size_t jdx=0; jdx<numX; jdx++)
|
||||
{
|
||||
auto locX0 = offset_x - delta_x/2.0;
|
||||
auto locX1 = offset_x + delta_x/2.0;
|
||||
auto locY0 = offset_y - delta_y/2.0;
|
||||
auto locY1 = offset_y + delta_y/2.0;
|
||||
|
||||
auto id_offset = 4* (jdx + numX*idx);
|
||||
locations[id_offset] = Point(locX0, locY0);
|
||||
locations[id_offset + 1] = Point(locX1, locY0);
|
||||
locations[id_offset + 2] = Point(locX1, locY1);
|
||||
locations[id_offset + 3] = Point(locX0, locY1);
|
||||
|
||||
offset_x += delta_x;
|
||||
}
|
||||
offset_x = delta_x/2.0;
|
||||
offset_y += delta_y;
|
||||
}
|
||||
|
||||
EdgeIds edge_ids(4 * numX * numY);
|
||||
for (std::size_t idx=0; idx<numY; idx++)
|
||||
{
|
||||
for(std::size_t jdx=0; jdx<numX; jdx++)
|
||||
{
|
||||
std::size_t node_offset = 4 * (jdx + numX * idx);
|
||||
auto id_offset = 4* (jdx + numX*idx);
|
||||
edge_ids[id_offset] = {node_offset, node_offset + 1};
|
||||
edge_ids[id_offset + 1] = {node_offset + 1, node_offset + 2};
|
||||
edge_ids[id_offset + 2] = {node_offset + 2, node_offset + 3};
|
||||
edge_ids[id_offset + 3] = {node_offset + 3, node_offset};
|
||||
}
|
||||
}
|
||||
|
||||
return MeshBuilder::buildLineMesh(locations, edge_ids);
|
||||
}
|
22
src/rendering/mesh/MeshPrimitives.h
Normal file
22
src/rendering/mesh/MeshPrimitives.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "TriMesh.h"
|
||||
#include "LineMesh.h"
|
||||
|
||||
class MeshPrimitives
|
||||
{
|
||||
public:
|
||||
static std::unique_ptr<TriMesh> buildCircleAsTriMesh(std::size_t numSegments = 24);
|
||||
|
||||
static std::unique_ptr<LineMesh> buildCircleAsLineMesh(std::size_t numSegments = 24);
|
||||
|
||||
static std::unique_ptr<TriMesh> buildRectangleAsTriMesh();
|
||||
|
||||
static std::unique_ptr<LineMesh> buildRectangleAsLineMesh();
|
||||
|
||||
static std::unique_ptr<TriMesh> buildExplodedGridAsTriMesh(std::size_t numX, std::size_t numY);
|
||||
|
||||
static std::unique_ptr<LineMesh> buildExplodedGridAsLineMesh(std::size_t numX, std::size_t numY);
|
||||
|
||||
static std::unique_ptr<TriMesh> buildRoundedRectangleAsTriMesh(double radius, double aspect_ratio = 1.0, std::size_t num_segments = 4);
|
||||
};
|
111
src/rendering/mesh/Node.cpp
Normal file
111
src/rendering/mesh/Node.cpp
Normal file
|
@ -0,0 +1,111 @@
|
|||
#include "Node.h"
|
||||
|
||||
std::unique_ptr<Node> Node::Create(const Point& p, std::size_t index)
|
||||
{
|
||||
return std::make_unique<Node>(p, index);
|
||||
}
|
||||
|
||||
Node::~Node()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Node::Node(const Point& p, std::size_t index)
|
||||
: mPoint(p),
|
||||
mIndex(index)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::size_t Node::getIndex() const
|
||||
{
|
||||
return mIndex;
|
||||
}
|
||||
|
||||
void Node::updateIndex(std::size_t index)
|
||||
{
|
||||
mIndex = index;
|
||||
}
|
||||
|
||||
void Node::addVectorAttribute(const std::string& tag, const std::vector<double>& values)
|
||||
{
|
||||
mVectorAttributes[tag] = values;
|
||||
}
|
||||
|
||||
std::vector<double> Node::getVectorAttribute(const std::string& tag) const
|
||||
{
|
||||
auto iter = mVectorAttributes.find(tag);
|
||||
if (iter != mVectorAttributes.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
const Point& Node::getPoint() const
|
||||
{
|
||||
return mPoint;
|
||||
}
|
||||
|
||||
void Node::apply(const Transform& transform)
|
||||
{
|
||||
mPoint.apply(transform);
|
||||
}
|
||||
|
||||
bool Node::isCoincident(Node* node) const
|
||||
{
|
||||
return node->getPoint() == mPoint;
|
||||
}
|
||||
|
||||
void Node::setState(State state)
|
||||
{
|
||||
mState = state;
|
||||
}
|
||||
|
||||
Node::State Node::getState() const
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
void Node::clearConnectivity()
|
||||
{
|
||||
mAssociatedEdgeIds.clear();
|
||||
mAssociatedFaceIds.clear();
|
||||
}
|
||||
|
||||
std::size_t Node::getNumConnectedEdges() const
|
||||
{
|
||||
return mAssociatedEdgeIds.size();
|
||||
}
|
||||
|
||||
std::size_t Node::getNumConnectedFaces() const
|
||||
{
|
||||
return mAssociatedFaceIds.size();
|
||||
}
|
||||
|
||||
void Node::associateEdge(std::size_t edgeId)
|
||||
{
|
||||
mAssociatedEdgeIds.push_back(edgeId);
|
||||
}
|
||||
|
||||
void Node::associateFace(std::size_t faceId)
|
||||
{
|
||||
mAssociatedFaceIds.push_back(faceId);
|
||||
}
|
||||
|
||||
std::size_t Node::getConnectedEdgeId(std::size_t idx) const
|
||||
{
|
||||
return mAssociatedEdgeIds[idx];
|
||||
}
|
||||
|
||||
std::size_t Node::getConnectedFaceId(std::size_t idx) const
|
||||
{
|
||||
return mAssociatedFaceIds[idx];
|
||||
}
|
||||
|
||||
void Node::setIndex(std::size_t idx)
|
||||
{
|
||||
mIndex = idx;
|
||||
}
|
||||
|
||||
|
69
src/rendering/mesh/Node.h
Normal file
69
src/rendering/mesh/Node.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
|
||||
#include "Point.h"
|
||||
#include "Transform.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Node
|
||||
{
|
||||
public:
|
||||
|
||||
enum class State
|
||||
{
|
||||
HEALTHY,
|
||||
DIRTY
|
||||
};
|
||||
|
||||
Node(const Point& p, std::size_t index = 0);
|
||||
|
||||
static std::unique_ptr<Node> Create(const Point& p, std::size_t index = 0);
|
||||
|
||||
~Node();
|
||||
|
||||
void apply(const Transform& transform);
|
||||
|
||||
void associateEdge(std::size_t edgeId);
|
||||
|
||||
void associateFace(std::size_t faceId);
|
||||
|
||||
void addVectorAttribute(const std::string& tag, const std::vector<double>& values);
|
||||
|
||||
void clearConnectivity();
|
||||
|
||||
std::size_t getIndex() const;
|
||||
|
||||
std::size_t getNumConnectedEdges() const;
|
||||
|
||||
std::size_t getNumConnectedFaces() const;
|
||||
|
||||
std::size_t getConnectedEdgeId(std::size_t idx) const;
|
||||
|
||||
std::size_t getConnectedFaceId(std::size_t idx) const;
|
||||
|
||||
State getState() const;
|
||||
|
||||
const Point& getPoint() const;
|
||||
|
||||
std::vector<double> getVectorAttribute(const std::string& tag) const;
|
||||
|
||||
bool isCoincident(Node* node) const;
|
||||
|
||||
void setState(State state);
|
||||
|
||||
void setIndex(std::size_t idx);
|
||||
|
||||
void updateIndex(std::size_t index);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, std::vector<double> > mVectorAttributes;
|
||||
std::size_t mIndex{0};
|
||||
Point mPoint;
|
||||
|
||||
std::vector<std::size_t> mAssociatedEdgeIds;
|
||||
std::vector<std::size_t> mAssociatedFaceIds;
|
||||
|
||||
State mState{State::HEALTHY};
|
||||
};
|
0
src/rendering/mesh/QuadFace.cpp
Normal file
0
src/rendering/mesh/QuadFace.cpp
Normal file
8
src/rendering/mesh/QuadFace.h
Normal file
8
src/rendering/mesh/QuadFace.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
class Edge;
|
||||
|
||||
class QuadFace
|
||||
{
|
||||
|
||||
};
|
0
src/rendering/mesh/QuadMesh.cpp
Normal file
0
src/rendering/mesh/QuadMesh.cpp
Normal file
0
src/rendering/mesh/QuadMesh.h
Normal file
0
src/rendering/mesh/QuadMesh.h
Normal file
108
src/rendering/mesh/TriFace.cpp
Normal file
108
src/rendering/mesh/TriFace.cpp
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include "TriFace.h"
|
||||
|
||||
#include "Edge.h"
|
||||
#include "Node.h"
|
||||
|
||||
TriFace::TriFace(Edge* edge0, Edge* edge1, Edge* edge2, std::size_t id)
|
||||
: AbstractFace(id),
|
||||
mEdge0(edge0),
|
||||
mEdge1(edge1),
|
||||
mEdge2(edge2)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<TriFace> TriFace::Create(Edge* edge0, Edge* edge1, Edge* edge2, std::size_t id)
|
||||
{
|
||||
return std::make_unique<TriFace>(edge0, edge1, edge2, id);
|
||||
}
|
||||
|
||||
TriFace::~TriFace()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::size_t> TriFace::getNodeIds() const
|
||||
{
|
||||
return {mEdge0->getNode0Id(), mEdge0->getNode1Id(), mEdge1->getNode1Id()};
|
||||
}
|
||||
|
||||
std::size_t TriFace::getNumNodes() const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
void TriFace::replaceEdge(Edge* original, Edge* replacement)
|
||||
{
|
||||
if (original == mEdge0)
|
||||
{
|
||||
mEdge0 = replacement;
|
||||
}
|
||||
else if (original == mEdge1)
|
||||
{
|
||||
mEdge1 = replacement;
|
||||
}
|
||||
else if (original == mEdge2)
|
||||
{
|
||||
mEdge2 = replacement;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t TriFace::getEdge0Id () const
|
||||
{
|
||||
return mEdge0->getId();
|
||||
}
|
||||
|
||||
std::size_t TriFace::getEdge1Id () const
|
||||
{
|
||||
return mEdge1->getId();
|
||||
}
|
||||
|
||||
std::size_t TriFace::getEdge2Id () const
|
||||
{
|
||||
return mEdge2->getId();
|
||||
}
|
||||
|
||||
std::vector<std::size_t> TriFace::getEdgeIds() const
|
||||
{
|
||||
return {mEdge0->getId(), mEdge1->getId(), mEdge2->getId()};
|
||||
}
|
||||
|
||||
void TriFace::associateWidthEdges()
|
||||
{
|
||||
mEdge0->associateFace(mId);
|
||||
mEdge1->associateFace(mId);
|
||||
mEdge2->associateFace(mId);
|
||||
}
|
||||
|
||||
std::vector<Point> TriFace::getNodeLocations(Orientation orientation) const
|
||||
{
|
||||
if (orientation != getOrientation())
|
||||
{
|
||||
return { mEdge0->getNode0()->getPoint(), mEdge0->getNode1()->getPoint(), mEdge1->getNode1()->getPoint() };
|
||||
}
|
||||
else
|
||||
{
|
||||
return { mEdge0->getNode0()->getPoint(), mEdge1->getNode1()->getPoint(), mEdge0->getNode1()->getPoint() };
|
||||
}
|
||||
}
|
||||
|
||||
Vector TriFace::getNormal() const
|
||||
{
|
||||
auto v0 = mEdge0->getNode0()->getPoint().getDelta(mEdge0->getNode1()->getPoint());
|
||||
auto v1 = mEdge0->getNode0()->getPoint().getDelta(mEdge1->getNode1()->getPoint());
|
||||
return v0.crossProduct(v1).getNormalized();
|
||||
}
|
||||
|
||||
AbstractFace::Orientation TriFace::getOrientation() const
|
||||
{
|
||||
Vector z_norm(0, 0, 1);
|
||||
if (z_norm.dotProduct(getNormal()) < 0.0)
|
||||
{
|
||||
return Orientation::CW;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Orientation::CCW;
|
||||
}
|
||||
}
|
40
src/rendering/mesh/TriFace.h
Normal file
40
src/rendering/mesh/TriFace.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractFace.h"
|
||||
#include "Vector.h"
|
||||
|
||||
class Edge;
|
||||
|
||||
class TriFace : public AbstractFace
|
||||
{
|
||||
public:
|
||||
TriFace(Edge* edge0, Edge* edge1, Edge* edge2, std::size_t id=0);
|
||||
|
||||
~TriFace();
|
||||
|
||||
static std::unique_ptr<TriFace> Create(Edge* edge0, Edge* edge1, Edge* edge2, std::size_t id=0);
|
||||
|
||||
void associateWidthEdges() override;
|
||||
|
||||
std::vector<std::size_t> getNodeIds() const override;
|
||||
|
||||
std::size_t getNumNodes() const override;
|
||||
|
||||
void replaceEdge(Edge* original, Edge* replacement);
|
||||
|
||||
std::size_t getEdge0Id () const;
|
||||
std::size_t getEdge1Id () const;
|
||||
std::size_t getEdge2Id () const;
|
||||
std::vector<std::size_t> getEdgeIds() const override;
|
||||
|
||||
std::vector<Point> getNodeLocations(Orientation orientation = Orientation::CCW) const override;
|
||||
|
||||
Vector getNormal() const;
|
||||
|
||||
AbstractFace::Orientation getOrientation() const;
|
||||
|
||||
private:
|
||||
Edge* mEdge0{nullptr};
|
||||
Edge* mEdge1{nullptr};
|
||||
Edge* mEdge2{nullptr};
|
||||
};
|
46
src/rendering/mesh/TriMesh.cpp
Normal file
46
src/rendering/mesh/TriMesh.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
#include "TriMesh.h"
|
||||
|
||||
#include "Edge.h"
|
||||
#include "TriFace.h"
|
||||
|
||||
TriMesh::~TriMesh()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AbstractMesh::MeshType TriMesh::getType() const
|
||||
{
|
||||
return AbstractMesh::MeshType::TRI;
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractMesh> TriMesh::copy() const
|
||||
{
|
||||
VecNodes nodes(mNodes.size());
|
||||
unsigned count = 0;
|
||||
for (auto& node : mNodes)
|
||||
{
|
||||
nodes[count] = std::make_unique<Node>(node->getPoint());
|
||||
count++;
|
||||
}
|
||||
|
||||
VecEdges edges(mEdges.size());
|
||||
count = 0;
|
||||
for (auto& edge : mEdges)
|
||||
{
|
||||
edges[count] = std::make_unique<Edge>(nodes[edge->getNode0Id()].get(), nodes[edge->getNode0Id()].get());
|
||||
count++;
|
||||
}
|
||||
|
||||
VecFaces faces(mFaces.size());
|
||||
count = 0;
|
||||
for (auto& face : mFaces)
|
||||
{
|
||||
auto ids = face->getEdgeIds();
|
||||
faces[count] = std::make_unique<TriFace>(edges[ids[0]].get(), edges[ids[1]].get(), edges[ids[2]].get());
|
||||
count++;
|
||||
}
|
||||
|
||||
auto mesh = std::make_unique<TriMesh>();
|
||||
mesh->populate(nodes, edges, faces);
|
||||
return mesh;
|
||||
}
|
15
src/rendering/mesh/TriMesh.h
Normal file
15
src/rendering/mesh/TriMesh.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "FaceMesh.h"
|
||||
|
||||
class TriMesh : public FaceMesh
|
||||
{
|
||||
public:
|
||||
TriMesh() = default;
|
||||
|
||||
~TriMesh();
|
||||
|
||||
std::unique_ptr<AbstractMesh> copy() const override;
|
||||
|
||||
MeshType getType() const;
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue