2020-11-27 11:47:21 +01:00
|
|
|
#include "edgemesh.hpp"
|
|
|
|
#include "vcg/simplex/face/topology.h"
|
2021-03-15 18:04:29 +01:00
|
|
|
#include <wrap/nanoply/include/nanoplyWrapper.hpp>
|
2020-11-27 11:47:21 +01:00
|
|
|
|
|
|
|
Eigen::MatrixX2i VCGEdgeMesh::getEigenEdges() const { return eigenEdges; }
|
|
|
|
|
|
|
|
Eigen::MatrixX3d VCGEdgeMesh::getEigenVertices() const {
|
|
|
|
// getVertices(eigenVertices);
|
|
|
|
return eigenVertices;
|
|
|
|
}
|
|
|
|
|
|
|
|
Eigen::MatrixX3d VCGEdgeMesh::getEigenEdgeNormals() const {
|
|
|
|
return eigenEdgeNormals;
|
|
|
|
}
|
|
|
|
|
2020-12-14 17:02:54 +01:00
|
|
|
bool VCGEdgeMesh::savePly(const std::string plyFilename) {
|
|
|
|
unsigned int mask = 0;
|
|
|
|
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTCOORD;
|
|
|
|
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEINDEX;
|
|
|
|
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTNORMAL;
|
|
|
|
if (nanoply::NanoPlyWrapper<VCGEdgeMesh>::SaveModel(
|
|
|
|
plyFilename.c_str(), *this, mask, false) != 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2020-11-27 11:47:21 +01:00
|
|
|
|
|
|
|
void VCGEdgeMesh::GeneratedRegularSquaredPattern(
|
|
|
|
const double angleDeg, std::vector<std::vector<vcg::Point2d>> &pattern,
|
|
|
|
const size_t &desiredNumberOfSamples) {
|
|
|
|
static const size_t piSamples = 10;
|
|
|
|
|
|
|
|
// generate a pattern in a 1x1 quad
|
|
|
|
const vcg::Point2d offset(0, 0);
|
|
|
|
|
|
|
|
const size_t samplesNo = desiredNumberOfSamples;
|
|
|
|
// std::max(desiredNumberOfSamples, size_t(piSamples * (angleDeg /
|
|
|
|
// 180)));
|
|
|
|
const double angle = vcg::math::ToRad(angleDeg);
|
|
|
|
|
|
|
|
pattern.clear();
|
|
|
|
|
|
|
|
// first arm
|
|
|
|
std::vector<vcg::Point2d> arm;
|
|
|
|
{
|
|
|
|
for (int k = 0; k <= samplesNo; k++) {
|
|
|
|
const double t = double(k) / samplesNo;
|
|
|
|
const double a = (1 - t) * angle;
|
2021-03-15 18:04:29 +01:00
|
|
|
// const double r = vcg::math::Sin(t*M_PI_2) /*(1-((1-t)*(1-t)))*/ *
|
|
|
|
// 0.5;
|
2020-11-27 11:47:21 +01:00
|
|
|
const double r = t * 0.5; // linear
|
|
|
|
|
|
|
|
vcg::Point2d p(vcg::math::Cos(a), vcg::math::Sin(a));
|
|
|
|
|
|
|
|
arm.push_back((p * r));
|
|
|
|
}
|
|
|
|
pattern.push_back(arm);
|
|
|
|
}
|
|
|
|
|
|
|
|
// other arms
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
for (vcg::Point2d &p : arm) {
|
|
|
|
p = vcg::Point2d(-p.Y(), p.X());
|
|
|
|
}
|
|
|
|
pattern.push_back(arm);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(pattern.size() == 4);
|
|
|
|
|
|
|
|
// offset all
|
|
|
|
for (auto &arm : pattern) {
|
|
|
|
for (vcg::Point2d &p : arm) {
|
|
|
|
p += offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VCGEdgeMesh::createSpiral(const float °reesOfArm,
|
|
|
|
const size_t &numberOfSamples) {
|
|
|
|
std::vector<std::vector<vcg::Point2d>> spiralPoints;
|
|
|
|
GeneratedRegularSquaredPattern(degreesOfArm, spiralPoints, numberOfSamples);
|
|
|
|
|
|
|
|
for (size_t armIndex = 0; armIndex < spiralPoints.size(); armIndex++) {
|
|
|
|
for (size_t pointIndex = 0; pointIndex < spiralPoints[armIndex].size() - 1;
|
|
|
|
pointIndex++) {
|
|
|
|
const vcg::Point2d p0 = spiralPoints[armIndex][pointIndex];
|
|
|
|
const vcg::Point2d p1 = spiralPoints[armIndex][pointIndex + 1];
|
|
|
|
CoordType n(0, 0, 1);
|
|
|
|
auto ei = vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(
|
|
|
|
*this, VCGEdgeMesh::CoordType(p0.X(), p0.Y(), 0),
|
|
|
|
VCGEdgeMesh::CoordType(p1.X(), p1.Y(), 0));
|
|
|
|
ei->cV(0)->N() = n;
|
|
|
|
ei->cV(1)->N() = n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// setDefaultAttributes();
|
|
|
|
}
|
|
|
|
|
2020-12-03 19:56:03 +01:00
|
|
|
bool VCGEdgeMesh::createSpanGrid(const size_t squareGridDimension) {
|
|
|
|
return createSpanGrid(squareGridDimension, squareGridDimension);
|
2020-11-27 11:47:21 +01:00
|
|
|
}
|
|
|
|
|
2020-12-03 19:56:03 +01:00
|
|
|
bool VCGEdgeMesh::createSpanGrid(const size_t desiredWidth,
|
2020-12-14 17:02:54 +01:00
|
|
|
const size_t desiredHeight) {
|
2020-11-27 11:47:21 +01:00
|
|
|
std::cout << "Grid of dimensions:" << desiredWidth << "," << desiredHeight
|
|
|
|
<< std::endl;
|
|
|
|
const VCGEdgeMesh::CoordType n(0, 0, 1);
|
|
|
|
int x = 0;
|
|
|
|
int y = 0;
|
|
|
|
// for (size_t vi = 0; vi < numberOfVertices; vi++) {
|
|
|
|
while (y <= desiredHeight) {
|
|
|
|
// std::cout << x << " " << y << std::endl;
|
|
|
|
auto p = VCGEdgeMesh::CoordType(x, y, 0);
|
|
|
|
vcg::tri::Allocator<VCGEdgeMesh>::AddVertex(*this, p, n);
|
|
|
|
x++;
|
|
|
|
if (x > desiredWidth) {
|
|
|
|
x = 0;
|
|
|
|
y++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t vi = 0; vi < VN(); vi++) {
|
|
|
|
int x = vi % (desiredWidth + 1);
|
|
|
|
int y = vi / (desiredWidth + 1);
|
|
|
|
const bool isCornerNode = (y == 0 && x == 0) ||
|
|
|
|
(y == 0 && x == desiredWidth) ||
|
|
|
|
(y == desiredHeight && x == 0) ||
|
|
|
|
(y == desiredHeight && x == desiredWidth);
|
|
|
|
if (isCornerNode) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (y == 0) { // row 0.Connect with node above
|
|
|
|
vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi,
|
|
|
|
vi + desiredWidth + 1);
|
|
|
|
continue;
|
|
|
|
} else if (x == 0) { // col 0.Connect with node to the right
|
|
|
|
vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi, vi + 1);
|
|
|
|
continue;
|
|
|
|
} else if (y == desiredHeight) { // row 0.Connect with node below
|
|
|
|
// vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi,
|
|
|
|
// vi - (desiredWidth +
|
|
|
|
// 1));
|
|
|
|
continue;
|
|
|
|
} else if (x == desiredWidth) { // row 0.Connect with node to the left
|
|
|
|
// vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi, vi - 1);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi, vi + desiredWidth + 1);
|
|
|
|
vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi, vi + 1);
|
|
|
|
// vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi,
|
|
|
|
// vi - (desiredWidth + 1));
|
|
|
|
// vcg::tri::Allocator<VCGEdgeMesh>::AddEdge(*this, vi, vi - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
vcg::tri::Allocator<VCGEdgeMesh>::DeleteVertex(*this, vert[0]);
|
|
|
|
vcg::tri::Allocator<VCGEdgeMesh>::DeleteVertex(*this, vert[desiredWidth]);
|
|
|
|
vcg::tri::Allocator<VCGEdgeMesh>::DeleteVertex(
|
|
|
|
*this, vert[desiredHeight * (desiredWidth + 1)]);
|
|
|
|
vcg::tri::Allocator<VCGEdgeMesh>::DeleteVertex(
|
|
|
|
*this, vert[(desiredHeight + 1) * (desiredWidth + 1) - 1]);
|
|
|
|
vcg::tri::Allocator<VCGEdgeMesh>::CompactVertexVector(*this);
|
|
|
|
getEdges(eigenEdges);
|
|
|
|
getVertices(eigenVertices);
|
|
|
|
// vcg::tri::Allocator<VCGEdgeMesh>::CompactEdgeVector(*this);
|
|
|
|
|
|
|
|
// const size_t numberOfEdges =
|
|
|
|
// desiredHeight * (desiredWidth - 1) + desiredWidth * (desiredHeight -
|
|
|
|
// 1);
|
|
|
|
// handleBeamDimensions._handle->data.resize(
|
|
|
|
// numberOfEdges, CylindricalElementDimensions(0.03, 0.026));
|
|
|
|
// handleBeamMaterial._handle->data.resize(numberOfEdges,
|
|
|
|
// ElementMaterial(0.3, 200));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-03-15 18:04:29 +01:00
|
|
|
bool VCGEdgeMesh::load(const string &plyFilename) {
|
2021-01-04 13:30:22 +01:00
|
|
|
|
2020-11-27 11:47:21 +01:00
|
|
|
std::string usedPath = plyFilename;
|
|
|
|
if (std::filesystem::path(plyFilename).is_relative()) {
|
|
|
|
usedPath = std::filesystem::absolute(plyFilename).string();
|
|
|
|
}
|
|
|
|
assert(std::filesystem::exists(usedPath));
|
|
|
|
this->Clear();
|
2021-03-01 14:44:35 +01:00
|
|
|
if (!loadUsingNanoply(usedPath)) {
|
|
|
|
std::cerr << "Error: Unable to open " + usedPath << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
2021-02-04 13:58:41 +01:00
|
|
|
|
2020-11-27 11:47:21 +01:00
|
|
|
getEdges(eigenEdges);
|
|
|
|
getVertices(eigenVertices);
|
|
|
|
vcg::tri::UpdateTopology<VCGEdgeMesh>::VertexEdge(*this);
|
2021-01-04 13:30:22 +01:00
|
|
|
label = std::filesystem::path(plyFilename).stem().string();
|
2020-11-27 11:47:21 +01:00
|
|
|
|
2021-03-01 14:44:35 +01:00
|
|
|
const bool printDebugInfo = false;
|
|
|
|
if (printDebugInfo) {
|
|
|
|
std::cout << plyFilename << " was loaded successfuly." << std::endl;
|
|
|
|
std::cout << "Mesh has " << EN() << " edges." << std::endl;
|
|
|
|
}
|
2020-11-27 11:47:21 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VCGEdgeMesh::loadUsingNanoply(const std::string &plyFilename) {
|
|
|
|
|
|
|
|
this->Clear();
|
|
|
|
// assert(plyFileHasAllRequiredFields(plyFilename));
|
|
|
|
// Load the ply file
|
|
|
|
unsigned int mask = 0;
|
|
|
|
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTCOORD;
|
|
|
|
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_VERTNORMAL;
|
|
|
|
mask |= nanoply::NanoPlyWrapper<VCGEdgeMesh>::IO_EDGEINDEX;
|
2020-12-03 19:56:03 +01:00
|
|
|
if (nanoply::NanoPlyWrapper<VCGEdgeMesh>::LoadModel(plyFilename.c_str(),
|
|
|
|
*this, mask) != 0) {
|
2020-11-27 11:47:21 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-03-15 18:04:29 +01:00
|
|
|
// bool VCGEdgeMesh::plyFileHasAllRequiredFields(const std::string
|
|
|
|
// &plyFilename)
|
2020-12-03 19:56:03 +01:00
|
|
|
// {
|
|
|
|
// const nanoply::Info info(plyFilename);
|
|
|
|
// const std::vector<nanoply::PlyElement>::const_iterator edgeElemIt =
|
|
|
|
// std::find_if(info.elemVec.begin(), info.elemVec.end(),
|
|
|
|
// [&](const nanoply::PlyElement &plyElem) {
|
|
|
|
// return plyElem.plyElem == nanoply::NNP_EDGE_ELEM;
|
|
|
|
// });
|
|
|
|
// if (edgeElemIt == info.elemVec.end()) {
|
|
|
|
// std::cerr << "Ply file is missing edge elements." << std::endl;
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// const std::vector<nanoply::PlyProperty> &edgePropertyVector =
|
|
|
|
// edgeElemIt->propVec;
|
|
|
|
// return hasPlyEdgeProperty(plyFilename, edgePropertyVector,
|
|
|
|
// plyPropertyBeamDimensionsID) &&
|
|
|
|
// hasPlyEdgeProperty(plyFilename, edgePropertyVector,
|
|
|
|
// plyPropertyBeamMaterialID);
|
|
|
|
//}
|
2020-11-27 11:47:21 +01:00
|
|
|
|
|
|
|
Eigen::MatrixX3d VCGEdgeMesh::getNormals() const {
|
|
|
|
Eigen::MatrixX3d vertexNormals;
|
|
|
|
vertexNormals.resize(VN(), 3);
|
|
|
|
|
|
|
|
for (int vertexIndex = 0; vertexIndex < VN(); vertexIndex++) {
|
|
|
|
VCGEdgeMesh::CoordType vertexNormal =
|
|
|
|
vert[static_cast<size_t>(vertexIndex)].cN();
|
|
|
|
vertexNormals.row(vertexIndex) =
|
|
|
|
vertexNormal.ToEigenVector<Eigen::Vector3d>();
|
|
|
|
}
|
|
|
|
|
|
|
|
return vertexNormals;
|
|
|
|
}
|
|
|
|
void VCGEdgeMesh::getEdges(Eigen::MatrixX3d &edgeStartingPoints,
|
|
|
|
Eigen::MatrixX3d &edgeEndingPoints) const {
|
|
|
|
edgeStartingPoints.resize(EN(), 3);
|
|
|
|
edgeEndingPoints.resize(EN(), 3);
|
|
|
|
for (int edgeIndex = 0; edgeIndex < EN(); edgeIndex++) {
|
|
|
|
const VCGEdgeMesh::EdgeType &edge = this->edge[edgeIndex];
|
|
|
|
edgeStartingPoints.row(edgeIndex) =
|
|
|
|
edge.cP(0).ToEigenVector<Eigen::Vector3d>();
|
|
|
|
edgeEndingPoints.row(edgeIndex) =
|
|
|
|
edge.cP(1).ToEigenVector<Eigen::Vector3d>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-03 19:56:03 +01:00
|
|
|
VCGEdgeMesh::VCGEdgeMesh() {}
|
2020-11-27 11:47:21 +01:00
|
|
|
|
|
|
|
void VCGEdgeMesh::updateEigenEdgeAndVertices() {
|
2021-03-15 18:04:29 +01:00
|
|
|
#ifdef POLYSCOPE_DEFINED
|
2020-11-27 11:47:21 +01:00
|
|
|
getEdges(eigenEdges);
|
|
|
|
getVertices(eigenVertices);
|
2021-03-15 18:04:29 +01:00
|
|
|
#endif
|
2020-11-27 11:47:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void VCGEdgeMesh::copy(VCGEdgeMesh &mesh) {
|
|
|
|
vcg::tri::Append<VCGEdgeMesh, VCGEdgeMesh>::MeshCopy(*this, mesh);
|
|
|
|
label = mesh.getLabel();
|
|
|
|
eigenEdges = mesh.getEigenEdges();
|
|
|
|
if (eigenEdges.rows() == 0) {
|
|
|
|
getEdges(eigenEdges);
|
|
|
|
}
|
|
|
|
eigenVertices = mesh.getEigenVertices();
|
|
|
|
if (eigenVertices.rows() == 0) {
|
|
|
|
getVertices(eigenVertices);
|
|
|
|
}
|
|
|
|
vcg::tri::UpdateTopology<VCGEdgeMesh>::VertexEdge(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VCGEdgeMesh::getVertices(Eigen::MatrixX3d &vertices) {
|
|
|
|
vertices = Eigen::MatrixX3d();
|
|
|
|
vertices.resize(VN(), 3);
|
|
|
|
for (int vi = 0; vi < VN(); vi++) {
|
|
|
|
if (vert[vi].IsD()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
VCGEdgeMesh::CoordType vertexCoordinates =
|
|
|
|
vert[static_cast<size_t>(vi)].cP();
|
|
|
|
vertices.row(vi) = vertexCoordinates.ToEigenVector<Eigen::Vector3d>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string VCGEdgeMesh::getLabel() const { return label; }
|
|
|
|
|
|
|
|
void VCGEdgeMesh::setLabel(const std::string &value) { label = value; }
|
|
|
|
|
|
|
|
void VCGEdgeMesh::getEdges(Eigen::MatrixX2i &edges) {
|
|
|
|
edges = Eigen::MatrixX2i();
|
|
|
|
edges.resize(EN(), 2);
|
|
|
|
for (int edgeIndex = 0; edgeIndex < EN(); edgeIndex++) {
|
|
|
|
const VCGEdgeMesh::EdgeType &edge = this->edge[edgeIndex];
|
2021-03-15 18:04:29 +01:00
|
|
|
assert(!edge.IsD());
|
|
|
|
auto vp0 = edge.cV(0);
|
|
|
|
auto vp1 = edge.cV(1);
|
|
|
|
assert(vcg::tri::IsValidPointer(*this, vp0) &&
|
|
|
|
vcg::tri::IsValidPointer(*this, vp1));
|
|
|
|
const size_t vi0 = vcg::tri::Index<VCGEdgeMesh>(*this, vp0);
|
|
|
|
const size_t vi1 = vcg::tri::Index<VCGEdgeMesh>(*this, vp1);
|
|
|
|
assert(vi0 != -1 && vi1 != -1);
|
|
|
|
edges.row(edgeIndex) = Eigen::Vector2i(vi0, vi1);
|
2020-11-27 11:47:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VCGEdgeMesh::printVertexCoordinates(const size_t &vi) const {
|
|
|
|
std::cout << "vi:" << vi << " " << vert[vi].cP()[0] << " " << vert[vi].cP()[1]
|
|
|
|
<< " " << vert[vi].cP()[2] << std::endl;
|
|
|
|
}
|
|
|
|
|
2021-03-01 14:44:35 +01:00
|
|
|
#ifdef POLYSCOPE_DEFINED
|
|
|
|
void VCGEdgeMesh::registerForDrawing(
|
2021-03-15 18:04:29 +01:00
|
|
|
const std::optional<glm::vec3> &desiredColor,
|
|
|
|
const bool &shouldEnable) const {
|
2020-11-27 11:47:21 +01:00
|
|
|
initPolyscope();
|
2021-03-01 14:44:35 +01:00
|
|
|
const double drawingRadius = 0.002;
|
2021-03-15 18:04:29 +01:00
|
|
|
auto polyscopeHandle_edgeMesh = polyscope::registerCurveNetwork(
|
|
|
|
label, getEigenVertices(), getEigenEdges());
|
|
|
|
polyscopeHandle_edgeMesh->setEnabled(shouldEnable);
|
|
|
|
polyscopeHandle_edgeMesh->setRadius(drawingRadius, true);
|
2021-03-01 14:44:35 +01:00
|
|
|
if (desiredColor.has_value()) {
|
|
|
|
polyscopeHandle_edgeMesh->setColor(desiredColor.value());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VCGEdgeMesh::unregister() const {
|
|
|
|
if (!polyscope::hasCurveNetwork(label)) {
|
|
|
|
std::cerr << "No curve network registered with a name: " << getLabel()
|
|
|
|
<< std::endl;
|
|
|
|
std::cerr << "Nothing to remove." << std::endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
polyscope::removeCurveNetwork(label);
|
2020-11-27 11:47:21 +01:00
|
|
|
}
|
2021-03-01 14:44:35 +01:00
|
|
|
#endif
|