Start building mesh primitives.

This commit is contained in:
James Grogan 2022-11-18 15:11:54 +00:00
parent a20c0183df
commit fcd90b5db4
30 changed files with 856 additions and 97 deletions

View file

@ -7,6 +7,8 @@ list(APPEND client_HEADERS
audio_editor/AudioEditorView.h
image_editor/ImageEditorView.h
image_editor/ImageViewWidget.h
canvas/CanvasView.h
canvas/CanvasController.h
web_client/WebClientView.h)
@ -18,6 +20,8 @@ list(APPEND client_LIB_INCLUDES
audio_editor/AudioEditorView.cpp
image_editor/ImageEditorView.cpp
image_editor/ImageViewWidget.cpp
canvas/CanvasView.cpp
canvas/CanvasController.cpp
web_client/WebClientView.cpp
MediaTool.cpp)
@ -37,6 +41,7 @@ target_include_directories(sample_gui PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/audio_editor"
"${CMAKE_CURRENT_SOURCE_DIR}/image_editor"
"${CMAKE_CURRENT_SOURCE_DIR}/web_client"
"${CMAKE_CURRENT_SOURCE_DIR}/canvas"
)
target_link_libraries(sample_gui PUBLIC client windows console core network database geometry audio web)
set_property(TARGET sample_gui PROPERTY FOLDER apps)

View file

@ -4,6 +4,8 @@
#include "AudioEditorView.h"
#include "ImageEditorView.h"
#include "WebClientView.h"
#include "CanvasView.h"
#include "TabbedPanelWidget.h"
#include "TopBar.h"
#include "TextNode.h"
@ -31,9 +33,9 @@ void MediaTool::initializeViews()
auto path = mMainApplication->getCommandLineArgs()->getLaunchPath();
path /= "out.txt";
textEditor->setName("TextEditor");
textEditor->GetController()->SetSavePath(path);
textEditor->GetController()->SetLoadPath(path);
textEditor->Initialize();
textEditor->getController()->SetSavePath(path);
textEditor->getController()->SetLoadPath(path);
textEditor->initialize();
tabbedPanel->addPanel(std::move(textEditor), "Text Editor");
auto audioEditor = AudioEditorView::Create();
@ -48,6 +50,10 @@ void MediaTool::initializeViews()
webClient->setName("webClient");
tabbedPanel->addPanel(std::move(webClient), "Web Client");
auto canvas = CanvasView::Create();
canvas->setName("CanvasView");
tabbedPanel->addPanel(std::move(canvas), "Canvas");
auto topBar = TopBar::Create();
auto statusBar = StatusBar::Create();

View file

@ -0,0 +1,6 @@
#include "CanvasController.h"
std::unique_ptr<CanvasController> CanvasController::Create()
{
return std::make_unique<CanvasController>();
}

View file

@ -0,0 +1,9 @@
#pragma once
#include <memory>
class CanvasController
{
public:
static std::unique_ptr<CanvasController> Create();
};

View file

@ -0,0 +1,75 @@
#include "CanvasView.h"
#include "HorizontalSpacer.h"
#include "VerticalSpacer.h"
#include "CanvasController.h"
#include "Theme.h"
#include "TextNode.h"
#include "Label.h"
#include "Button.h"
#include <iostream>
CanvasView::CanvasView()
: mController(CanvasController::Create())
{
initialize();
}
CanvasView::~CanvasView()
{
}
std::unique_ptr<CanvasView> CanvasView::Create()
{
return std::make_unique<CanvasView>();
}
void CanvasView::initialize()
{
auto label = Label::Create();
label->setLabel("Canvas");
label->setBackgroundColor(Theme::getBannerBackground());
label->setMargin(1);
auto hSpacer = HorizontalSpacer::Create();
hSpacer->addWidgetWithScale(std::move(label), 1);
//hSpacer->addWidgetWithScale(std::move(textBox), 14);
auto cache_button_spacer = initializeCacheButtons();
hSpacer->addWidgetWithScale(std::move(cache_button_spacer), 1);
addWidget(std::move(hSpacer));
}
std::unique_ptr<Widget> CanvasView::initializeCacheButtons()
{
auto saveButton = Button::Create();
saveButton->setLabel("Save");
saveButton->setBackgroundColor(Theme::getButtonPrimaryBackground());
saveButton->setMargin(2);
auto clearButton = Button::Create();
clearButton->setLabel("Clear");
clearButton->setBackgroundColor(Theme::getButtonPrimaryBackground());
clearButton->setMargin(2);
auto loadButton = Button::Create();
loadButton->setLabel("Load");
loadButton->setBackgroundColor(Theme::getButtonPrimaryBackground());
loadButton->setMargin(2);
auto buttonSpacer = VerticalSpacer::Create();
buttonSpacer->AddWidgetWithScale(std::move(saveButton), 1);
buttonSpacer->AddWidgetWithScale(std::move(clearButton), 1);
buttonSpacer->AddWidgetWithScale(std::move(loadButton), 1);
return buttonSpacer;
}

View file

@ -0,0 +1,26 @@
#pragma once
#include "Widget.h"
class CanvasController;
class CanvasView : public Widget
{
public:
CanvasView();
~CanvasView();
static std::unique_ptr<CanvasView> Create();
private:
void initialize();
std::unique_ptr<Widget> initializeCacheButtons();
//std::unique_ptr<Widget> initializeCacheButtons();
std::unique_ptr<CanvasController> mController;
};
using CanvasViewPtr = std::unique_ptr<CanvasView>;

View file

@ -5,10 +5,6 @@
class TextEditorController
{
TextEditorModelUPtr mModel;
std::filesystem::path mSavePath;
std::filesystem::path mLoadPath;
public:
TextEditorController();
@ -28,6 +24,11 @@ public:
void SetSavePath(const std::filesystem::path& path);
void SetLoadPath(const std::filesystem::path& path);
private:
TextEditorModelUPtr mModel;
std::filesystem::path mSavePath;
std::filesystem::path mLoadPath;
};
using TextEditorControllerUPtr = std::unique_ptr<TextEditorController>;

View file

@ -16,12 +16,12 @@ TextEditorView::TextEditorView()
}
TextEditorController* TextEditorView::GetController()
TextEditorController* TextEditorView::getController()
{
return mController.get();
}
void TextEditorView::Initialize()
void TextEditorView::initialize()
{
auto label = Label::Create();
label->setLabel("Text Editor");

View file

@ -5,21 +5,23 @@
#include "Label.h"
#include "TextBox.h"
#include "TextEditorController.h"
#include <functional>
class TextEditorView : public Widget
{
TextBox* mTextBox;
TextEditorControllerUPtr mController;
public:
TextEditorView();
static std::unique_ptr<TextEditorView> Create();
TextEditorController* GetController();
TextEditorController* getController();
void Initialize();
void initialize();
private:
TextBox* mTextBox;
TextEditorControllerUPtr mController;
};
using TextEditorViewUPtr = std::unique_ptr<TextEditorView>;

View file

@ -1,11 +1,18 @@
#include "AbstractFace.h"
#include "Edge.h"
AbstractFace::AbstractFace(unsigned id)
: mId(id)
{
}
AbstractFace::~AbstractFace()
{
}
void AbstractFace::addVectorAttribute(const std::string& tag, const std::vector<double>& values)
{
mVectorAttributes[tag] = values;
@ -20,3 +27,8 @@ std::vector<double> AbstractFace::getVectorAttribute(const std::string& tag) con
}
return {};
}
void AbstractFace::setIndex(std::size_t idx)
{
mId = idx;
}

View file

@ -5,12 +5,14 @@
#include <unordered_map>
#include <string>
class Edge;
class AbstractFace
{
public:
AbstractFace(unsigned id=0);
virtual ~AbstractFace() = default;
virtual ~AbstractFace();
virtual std::vector<unsigned> getNodeIds() const = 0;
@ -18,6 +20,16 @@ public:
std::vector<double> getVectorAttribute(const std::string& tag) const;
void setIndex(std::size_t idx);
virtual unsigned getNumNodes() const = 0;
virtual void associateWidthEdges() = 0;
virtual void replaceEdge(Edge* original, Edge* replacement) = 0;
virtual std::vector<unsigned> getEdgeIds() const = 0;
protected:
unsigned mId{0};
std::unordered_map<std::string, std::vector<double> > mVectorAttributes;

View file

@ -40,6 +40,8 @@ public:
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;

View file

@ -7,6 +7,7 @@ list(APPEND mesh_LIB_INCLUDES
Node.cpp
QuadMesh.cpp
TriMesh.cpp
FaceMesh.cpp
LineMesh.cpp
MeshPrimitives.cpp
MeshBuilder.cpp)

View file

@ -28,3 +28,95 @@ unsigned 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;
}
}
unsigned Edge::getId() const
{
return mId;
}
void Edge::setState(State state)
{
mState = state;
}
Edge::State Edge::getState() const
{
return mState;
}
void Edge::clearConnectivity()
{
mAssociatedFaceIds.clear();
}
unsigned Edge::getNumConnectedFaces() const
{
return mAssociatedFaceIds.size();
}
void Edge::associateFace(unsigned faceId)
{
mAssociatedFaceIds.push_back(faceId);
}
unsigned Edge::getConnectedFaceId(std::size_t idx) const
{
return mAssociatedFaceIds[idx];
}
void Edge::associateWithNodes()
{
mNode0->associateEdge(mId);
mNode1->associateEdge(mId);
}
void Edge::setIndex(unsigned idx)
{
mId = idx;
}

View file

@ -1,23 +1,65 @@
#pragma once
class Node;
#include <memory>
#include <vector>
class Node;
class Edge
{
public:
enum class State
{
HEALTHY,
DIRTY
};
Edge(Node* node0, Node* node1, unsigned id = 0);
~Edge();
static std::unique_ptr<Edge> Create(Node* node0, Node* node1, unsigned id = 0);
void associateFace(unsigned faceId);
void associateWithNodes();
void clearConnectivity();
unsigned getConnectedFaceId(std::size_t idx) const;
State getState() const;
unsigned getId() const;
unsigned getNode0Id() const;
unsigned getNode1Id() const;
Node* getNode0() const;
Node* getNode1() const;
unsigned 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(unsigned idx);
private:
unsigned mId{0};
Node* mNode0{nullptr};
Node* mNode1{nullptr};
std::vector<unsigned> mAssociatedFaceIds;
State mState{State::HEALTHY};
};

182
src/mesh/FaceMesh.cpp Normal file
View file

@ -0,0 +1,182 @@
#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();
}
std::vector<unsigned> FaceMesh::getFaceNodeIds() const
{
if (mFaces.empty())
{
return {};
}
auto nodes_per_face = mFaces[0]->getNumNodes();
std::vector<unsigned> 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()
{
unsigned count = 0;
for (auto& node : mNodes)
{
node->setIndex(count);
}
count = 0;
for (auto& edge : mEdges)
{
edge->setIndex(count);
}
count = 0;
for (auto& face : mFaces)
{
face->setIndex(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 (unsigned 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 (unsigned idx=0; idx<2; idx++)
{
auto face = mesh->mFaces[idx].get();
face->replaceEdge(target_edge, edge.get());
}
break;
}
}
}
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();
}

47
src/mesh/FaceMesh.h Normal file
View file

@ -0,0 +1,47 @@
#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<unsigned> getFaceNodeIds() 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);
protected:
void resetConnectivity();
void resetIds();
void replaceIfOverlapping(FaceMesh* mesh, Node* node) const;
void replaceIfOverlapping(FaceMesh* mesh, Edge* edge) const;
VecEdges mEdges;
VecFaces mFaces;
};

View file

@ -13,6 +13,16 @@ void LineMesh::populate(VecNodes& nodes, VecEdges& edges)
mEdges = std::move(edges);
}
std::unique_ptr<AbstractMesh> LineMesh::copy() const
{
return nullptr;
}
LineMesh::MeshType LineMesh::getType() const
{
return LineMesh::MeshType::LINE;
}
std::vector<unsigned> LineMesh::getEdgeNodeIds() const
{
std::vector<unsigned> ids(2*mEdges.size());

View file

@ -20,10 +20,9 @@ public:
std::vector<unsigned> getEdgeNodeIds() const;
MeshType getType() const override
{
return MeshType::LINE;
}
MeshType getType() const override;
std::unique_ptr<AbstractMesh> copy() const override;
private:
VecEdges mEdges;

View file

@ -2,6 +2,8 @@
#include "MeshBuilder.h"
#include <math.h>
#include <iostream>
std::unique_ptr<TriMesh> MeshPrimitives::buildRectangleAsTriMesh()
@ -29,6 +31,85 @@ std::unique_ptr<TriMesh> MeshPrimitives::buildRectangleAsTriMesh()
return MeshBuilder::buildTriMesh(locations, edge_ids, face_ids);
}
std::unique_ptr<TriMesh> MeshPrimitives::buildRoundedRectangleAsTriMesh(double radius, double aspect_ratio, unsigned num_segments)
{
unsigned num_fans = 4;
unsigned 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};
unsigned offset = 1;
for (unsigned 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 (unsigned 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 (unsigned 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 (unsigned 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;
}
unsigned num_edges_per_fan = 2*num_segments + 1;
unsigned num_inner_rect_edges = 3*num_fans;
EdgeIds edge_ids(num_edges_per_fan*num_fans + num_inner_rect_edges + 1);
// Fan edges
for (unsigned jdx=0; jdx< num_fans; jdx++)
{
unsigned node_offset = jdx*num_nodes_per_fan;
unsigned edge_offset = jdx*num_edges_per_fan;
// Inner edges
for(unsigned idx=0; idx<=num_segments; idx++)
{
edge_ids[edge_offset + idx] = {node_offset, node_offset + idx + 1};
}
// Outer edges
for(unsigned 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
unsigned edge_offset = num_edges_per_fan*num_fans;
}
std::unique_ptr<LineMesh> MeshPrimitives::buildRectangleAsLineMesh()
{
VecPoints locations = {

View file

@ -14,4 +14,6 @@ public:
static std::unique_ptr<TriMesh> buildExplodedGridAsTriMesh(unsigned numX, unsigned numY);
static std::unique_ptr<LineMesh> buildExplodedGridAsLineMesh(unsigned numX, unsigned numY);
static std::unique_ptr<TriMesh> buildRoundedRectangleAsTriMesh(double radius, double aspect_ratio = 1.0, unsigned num_segments = 4);
};

View file

@ -42,4 +42,75 @@ std::vector<double> Node::getVectorAttribute(const std::string& tag) const
return {};
}
const Point& Node::getPoint() const
{
return mPoint;
}
void Node::scale(double x, double y)
{
mPoint.scale(x, y);
}
void Node::translate(double x, double y, double z)
{
mPoint.translate(x, y, z);
}
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();
}
unsigned Node::getNumConnectedEdges() const
{
return mAssociatedEdgeIds.size();
}
unsigned Node::getNumConnectedFaces() const
{
return mAssociatedFaceIds.size();
}
void Node::associateEdge(unsigned edgeId)
{
mAssociatedEdgeIds.push_back(edgeId);
}
void Node::associateFace(unsigned faceId)
{
mAssociatedFaceIds.push_back(faceId);
}
unsigned Node::getConnectedEdgeId(std::size_t idx) const
{
return mAssociatedEdgeIds[idx];
}
unsigned Node::getConnectedFaceId(std::size_t idx) const
{
return mAssociatedFaceIds[idx];
}
void Node::setIndex(std::size_t idx)
{
mIndex = idx;
}

View file

@ -6,41 +6,65 @@
#include <string>
#include <vector>
class Node
{
public:
enum class State
{
HEALTHY,
DIRTY
};
Node(const Point& p, unsigned index = 0);
static std::unique_ptr<Node> Create(const Point& p, unsigned index = 0);
~Node();
unsigned getIndex() const;
void associateEdge(unsigned edgeId);
void updateIndex(unsigned index);
const Point& getPoint() const
{
return mPoint;
}
void associateFace(unsigned faceId);
void addVectorAttribute(const std::string& tag, const std::vector<double>& values);
void clearConnectivity();
unsigned getIndex() const;
unsigned getNumConnectedEdges() const;
unsigned getNumConnectedFaces() const;
unsigned getConnectedEdgeId(std::size_t idx) const;
unsigned getConnectedFaceId(std::size_t idx) const;
State getState() const;
const Point& getPoint() const;
std::vector<double> getVectorAttribute(const std::string& tag) const;
void scale(double x, double y)
{
mPoint.scale(x, y);
}
bool isCoincident(Node* node) const;
void translate(double x, double y, double z = 0.0)
{
mPoint.translate(x, y, z);
}
void setState(State state);
void setIndex(std::size_t idx);
void updateIndex(unsigned index);
void scale(double x, double y);
void translate(double x, double y, double z = 0.0);
private:
std::unordered_map<std::string, std::vector<double> > mVectorAttributes;
unsigned mIndex{0};
Point mPoint;
std::vector<unsigned> mAssociatedEdgeIds;
std::vector<unsigned> mAssociatedFaceIds;
State mState{State::HEALTHY};
};

View file

@ -25,3 +25,51 @@ std::vector<unsigned> TriFace::getNodeIds() const
{
return {mEdge0->getNode0Id(), mEdge0->getNode1Id(), mEdge1->getNode1Id()};
}
unsigned 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;
}
}
unsigned TriFace::getEdge0Id () const
{
return mEdge0->getId();
}
unsigned TriFace::getEdge1Id () const
{
return mEdge1->getId();
}
unsigned TriFace::getEdge2Id () const
{
return mEdge2->getId();
}
std::vector<unsigned> TriFace::getEdgeIds() const
{
return {mEdge0->getId(), mEdge1->getId(), mEdge2->getId()};
}
void TriFace::associateWidthEdges()
{
mEdge0->associateFace(mId);
mEdge1->associateFace(mId);
mEdge2->associateFace(mId);
}

View file

@ -11,12 +11,22 @@ public:
~TriFace();
std::vector<unsigned> getNodeIds() const override;
static std::unique_ptr<TriFace> Create(Edge* edge0, Edge* edge1, Edge* edge2, unsigned id=0);
private:
void associateWidthEdges() override;
std::vector<unsigned> getNodeIds() const override;
unsigned getNumNodes() const override;
void replaceEdge(Edge* original, Edge* replacement);
unsigned getEdge0Id () const;
unsigned getEdge1Id () const;
unsigned getEdge2Id () const;
std::vector<unsigned> getEdgeIds() const override;
private:
Edge* mEdge0{nullptr};
Edge* mEdge1{nullptr};
Edge* mEdge2{nullptr};

View file

@ -1,6 +1,5 @@
#include "TriMesh.h"
#include "Node.h"
#include "Edge.h"
#include "TriFace.h"
@ -9,43 +8,39 @@ TriMesh::~TriMesh()
}
void TriMesh::populate(VecNodes& nodes, VecEdges& edges, VecFaces& faces)
AbstractMesh::MeshType TriMesh::getType() const
{
mNodes = std::move(nodes);
mEdges = std::move(edges);
mFaces = std::move(faces);
return AbstractMesh::MeshType::TRI;
}
std::vector<unsigned> TriMesh::getFaceNodeIds() const
std::unique_ptr<AbstractMesh> TriMesh::copy() const
{
unsigned nodes_per_face = 3;
std::vector<unsigned> ids(nodes_per_face*mFaces.size());
VecNodes nodes(mNodes.size());
unsigned count = 0;
for (auto& node : mNodes)
{
nodes[count] = std::make_unique<Node>(node->getPoint());
count++;
}
for(std::size_t idx=0; idx<mFaces.size(); idx++)
VecEdges edges(mEdges.size());
count = 0;
for (auto& edge : mEdges)
{
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];
edges[count] = std::make_unique<Edge>(nodes[edge->getNode0Id()].get(), nodes[edge->getNode0Id()].get());
count++;
}
}
return ids;
}
std::vector<std::vector<double> > TriMesh::getFaceVectorAttributes(const std::string& tag)
{
std::vector<std::vector<double> > attribs(mFaces.size());
for(std::size_t idx=0; idx<mFaces.size(); idx++)
VecFaces faces(mFaces.size());
count = 0;
for (auto& face : mFaces)
{
attribs[idx] = {mFaces[idx]->getVectorAttribute(tag)};
auto ids = face->getEdgeIds();
faces[count] = std::make_unique<TriFace>(edges[ids[0]].get(), edges[ids[1]].get(), edges[ids[2]].get());
count++;
}
return attribs;
}
void TriMesh::addConstantFaceVectorAttribute(const std::string& tag, const std::vector<double>& values)
{
for (const auto& face : mFaces)
{
face->addVectorAttribute(tag, values);
}
auto mesh = std::make_unique<TriMesh>();
mesh->populate(nodes, edges, faces);
return mesh;
}

View file

@ -1,40 +1,15 @@
#pragma once
#include "AbstractMesh.h"
#include "FaceMesh.h"
#include <string>
#include <unordered_map>
class Edge;
class TriFace;
using EdgePtr = std::unique_ptr<Edge>;
using TriFacePtr = std::unique_ptr<TriFace>;
using VecEdges = std::vector<EdgePtr>;
using VecFaces = std::vector<TriFacePtr>;
class TriMesh : public AbstractMesh
class TriMesh : public FaceMesh
{
public:
TriMesh() = default;
~TriMesh();
void populate(VecNodes& nodes, VecEdges& edges, VecFaces& faces);
std::unique_ptr<AbstractMesh> copy() const override;
std::vector<unsigned> getFaceNodeIds() const;
void addConstantFaceVectorAttribute(const std::string& tag, const std::vector<double>& values);
std::vector<std::vector<double> > getFaceVectorAttributes(const std::string& tag);
MeshType getType() const
{
return MeshType::TRI;
}
private:
VecEdges mEdges;
VecFaces mFaces;
MeshType getType() const;
};

View file

@ -16,6 +16,7 @@ list(APPEND ui_elements_LIB_INCLUDES
ui_events/ResizeEvent.cpp
widgets/Widget.cpp
widgets/Button.cpp
widgets/ButtonGroup.cpp
widgets/Label.cpp
widgets/HorizontalSpacer.cpp
widgets/VerticalSpacer.cpp

View file

View file

@ -0,0 +1,23 @@
#pragma once
#include "Widget.h"
class ButtonGroup : public Widget
{
public:
enum class Orientation
{
HORIZONTAL,
VERTICAL
};
ButtonGroup();
~ButtonGroup();
static std::unique_ptr<ButtonGroup> Create();
private:
bool mExclusiveActivation{true};
};