mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-21 21:58:03 -06:00
Add parallel version of neighbors index creation, make it default
This commit is contained in:
parent
b4d540ec4c
commit
97529ff6b7
6 changed files with 112 additions and 116 deletions
|
@ -4,6 +4,8 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "ItsNeighborIndex.hpp"
|
#include "ItsNeighborIndex.hpp"
|
||||||
|
#include "libslic3r/Execution/ExecutionTBB.hpp"
|
||||||
|
#include "libslic3r/Execution/ExecutionSeq.hpp"
|
||||||
|
|
||||||
#include "tbb/parallel_sort.h"
|
#include "tbb/parallel_sort.h"
|
||||||
|
|
||||||
|
@ -343,20 +345,20 @@ std::vector<std::vector<size_t>> create_vertex_faces_index(const indexed_triangl
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_vertex_index(size_t vertex_index, const stl_triangle_vertex_indices &triangle_indices) {
|
//static int get_vertex_index(size_t vertex_index, const stl_triangle_vertex_indices &triangle_indices) {
|
||||||
if (vertex_index == triangle_indices[0]) return 0;
|
// if (vertex_index == triangle_indices[0]) return 0;
|
||||||
if (vertex_index == triangle_indices[1]) return 1;
|
// if (vertex_index == triangle_indices[1]) return 1;
|
||||||
if (vertex_index == triangle_indices[2]) return 2;
|
// if (vertex_index == triangle_indices[2]) return 2;
|
||||||
return -1;
|
// return -1;
|
||||||
}
|
//}
|
||||||
|
|
||||||
static Vec2crd get_edge_indices(int edge_index, const stl_triangle_vertex_indices &triangle_indices)
|
//static Vec2crd get_edge_indices(int edge_index, const stl_triangle_vertex_indices &triangle_indices)
|
||||||
{
|
//{
|
||||||
int next_edge_index = (edge_index == 2) ? 0 : edge_index + 1;
|
// int next_edge_index = (edge_index == 2) ? 0 : edge_index + 1;
|
||||||
coord_t vi0 = triangle_indices[edge_index];
|
// coord_t vi0 = triangle_indices[edge_index];
|
||||||
coord_t vi1 = triangle_indices[next_edge_index];
|
// coord_t vi1 = triangle_indices[next_edge_index];
|
||||||
return Vec2crd(vi0, vi1);
|
// return Vec2crd(vi0, vi1);
|
||||||
}
|
//}
|
||||||
|
|
||||||
static std::vector<std::vector<size_t>> create_vertex_faces_index(
|
static std::vector<std::vector<size_t>> create_vertex_faces_index(
|
||||||
const std::vector<stl_triangle_vertex_indices>& indices, size_t count_vertices)
|
const std::vector<stl_triangle_vertex_indices>& indices, size_t count_vertices)
|
||||||
|
@ -600,42 +602,12 @@ FaceNeighborIndex its_create_neighbors_index_8(const indexed_triangle_set &its)
|
||||||
|
|
||||||
std::vector<Vec3crd> its_create_neighbors_index_9(const indexed_triangle_set &its)
|
std::vector<Vec3crd> its_create_neighbors_index_9(const indexed_triangle_set &its)
|
||||||
{
|
{
|
||||||
const std::vector<stl_triangle_vertex_indices> &indices = its.indices;
|
return create_neighbors_index(ex_seq, its);
|
||||||
size_t vertices_size = its.vertices.size();
|
}
|
||||||
|
|
||||||
if (indices.empty() || vertices_size == 0) return {};
|
std::vector<Vec3i> its_create_neighbors_index_10(const indexed_triangle_set &its)
|
||||||
// std::vector<std::vector<size_t>> vertex_triangles = create_vertex_faces_index(indices, vertices_size);
|
{
|
||||||
auto vertex_triangles = VertexFaceIndex{its};
|
return create_neighbors_index(ex_tbb, its);
|
||||||
coord_t no_value = -1;
|
|
||||||
std::vector<Vec3crd> neighbors(indices.size(), Vec3crd(no_value, no_value, no_value));
|
|
||||||
for (const stl_triangle_vertex_indices& triangle_indices : indices) {
|
|
||||||
coord_t index = &triangle_indices - &indices.front();
|
|
||||||
Vec3crd& neighbor = neighbors[index];
|
|
||||||
for (int edge_index = 0; edge_index < 3; ++edge_index) {
|
|
||||||
// check if done
|
|
||||||
coord_t& neighbor_edge = neighbor[edge_index];
|
|
||||||
if (neighbor_edge != no_value) continue;
|
|
||||||
Vec2crd edge_indices = get_edge_indices(edge_index, triangle_indices);
|
|
||||||
// IMPROVE: use same vector for 2 sides of triangle
|
|
||||||
const auto &faces_range = vertex_triangles[edge_indices[0]];
|
|
||||||
for (const size_t &face : faces_range) {
|
|
||||||
if (face <= index) continue;
|
|
||||||
const stl_triangle_vertex_indices &face_indices = indices[face];
|
|
||||||
int vertex_index = get_vertex_index(edge_indices[1], face_indices);
|
|
||||||
// NOT Contain second vertex?
|
|
||||||
if (vertex_index < 0) continue;
|
|
||||||
// Has NOT oposit direction?
|
|
||||||
if (edge_indices[0] != face_indices[(vertex_index + 1) % 3]) continue;
|
|
||||||
neighbor_edge = face;
|
|
||||||
neighbors[face][vertex_index] = index;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// must be paired
|
|
||||||
assert(neighbor_edge != no_value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return neighbors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "libslic3r/MeshSplitImpl.hpp"
|
#include "libslic3r/MeshSplitImpl.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
using FaceNeighborIndex = std::vector<std::array<size_t, 3>>;
|
||||||
FaceNeighborIndex its_create_neighbors_index_1(const indexed_triangle_set &its);
|
FaceNeighborIndex its_create_neighbors_index_1(const indexed_triangle_set &its);
|
||||||
std::vector<Vec3i> its_create_neighbors_index_2(const indexed_triangle_set &its);
|
std::vector<Vec3i> its_create_neighbors_index_2(const indexed_triangle_set &its);
|
||||||
std::vector<Vec3i> its_create_neighbors_index_3(const indexed_triangle_set &its);
|
std::vector<Vec3i> its_create_neighbors_index_3(const indexed_triangle_set &its);
|
||||||
|
@ -12,6 +13,7 @@ std::vector<std::array<size_t, 3>> its_create_neighbors_index_6(const indexed_tr
|
||||||
std::vector<std::array<size_t, 3>> its_create_neighbors_index_7(const indexed_triangle_set &its);
|
std::vector<std::array<size_t, 3>> its_create_neighbors_index_7(const indexed_triangle_set &its);
|
||||||
FaceNeighborIndex its_create_neighbors_index_8(const indexed_triangle_set &its);
|
FaceNeighborIndex its_create_neighbors_index_8(const indexed_triangle_set &its);
|
||||||
std::vector<Vec3crd> its_create_neighbors_index_9(const indexed_triangle_set &its);
|
std::vector<Vec3crd> its_create_neighbors_index_9(const indexed_triangle_set &its);
|
||||||
|
std::vector<Vec3i> its_create_neighbors_index_10(const indexed_triangle_set &its);
|
||||||
|
|
||||||
std::vector<std::vector<size_t>> create_vertex_faces_index(const indexed_triangle_set &its);
|
std::vector<std::vector<size_t>> create_vertex_faces_index(const indexed_triangle_set &its);
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,18 +138,18 @@ static const std::pair<const std::string, indexed_triangle_set> ToMeasure[] = {
|
||||||
{"two_spheres_64x", two_spheres(8. * 60.)},
|
{"two_spheres_64x", two_spheres(8. * 60.)},
|
||||||
{"two_spheres_128x", two_spheres(sq2 * 8. * 60.)},
|
{"two_spheres_128x", two_spheres(sq2 * 8. * 60.)},
|
||||||
{"two_spheres_256x", two_spheres(16. * 60.)},
|
{"two_spheres_256x", two_spheres(16. * 60.)},
|
||||||
{"two_spheres_512x", two_spheres(sq2 * 16. * 60.)}
|
{"two_spheres_512x", two_spheres(sq2 * 16. * 60.)},
|
||||||
|
|
||||||
// {"2_spheres", make_spheres(2, 60.)},
|
{"2_spheres", make_spheres(2, 60.)},
|
||||||
// {"4_spheres", make_spheres(4, 60.)},
|
{"4_spheres", make_spheres(4, 60.)},
|
||||||
// {"8_spheres", make_spheres(8, 60.)},
|
{"8_spheres", make_spheres(8, 60.)},
|
||||||
// {"16_spheres", make_spheres(16, 60.)},
|
{"16_spheres", make_spheres(16, 60.)},
|
||||||
// {"32_spheres", make_spheres(32, 60.)},
|
{"32_spheres", make_spheres(32, 60.)},
|
||||||
// {"64_spheres", make_spheres(64, 60.)},
|
{"64_spheres", make_spheres(64, 60.)},
|
||||||
// {"128_spheres", make_spheres(128, 60.)},
|
{"128_spheres", make_spheres(128, 60.)},
|
||||||
// {"256_spheres", make_spheres(256, 60.)},
|
{"256_spheres", make_spheres(256, 60.)},
|
||||||
// {"512_spheres", make_spheres(512, 60.)},
|
{"512_spheres", make_spheres(512, 60.)},
|
||||||
// {"1024_spheres", make_spheres(1024, 60.)}
|
{"1024_spheres", make_spheres(1024, 60.)}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const auto IndexFunctions = std::make_tuple(
|
static const auto IndexFunctions = std::make_tuple(
|
||||||
|
@ -158,6 +158,7 @@ static const auto IndexFunctions = std::make_tuple(
|
||||||
std::make_pair("vojta tbb::parallel_sort based", [](const auto &its) { return measure_index(its, its_create_neighbors_index_3); }),
|
std::make_pair("vojta tbb::parallel_sort based", [](const auto &its) { return measure_index(its, its_create_neighbors_index_3); }),
|
||||||
std::make_pair("filip's vertex->face based", [](const auto &its) { return measure_index(its, its_create_neighbors_index_5); }),
|
std::make_pair("filip's vertex->face based", [](const auto &its) { return measure_index(its, its_create_neighbors_index_5); }),
|
||||||
std::make_pair("vojta's vertex->face", [](const auto &its) { return measure_index(its, its_create_neighbors_index_9); }),
|
std::make_pair("vojta's vertex->face", [](const auto &its) { return measure_index(its, its_create_neighbors_index_9); }),
|
||||||
|
std::make_pair("vojta's vertex->face parallel", [](const auto &its) { return measure_index(its, its_create_neighbors_index_10); }),
|
||||||
std::make_pair("tamas's std::sort based", [](const auto &its) { return measure_index(its, its_create_neighbors_index_6); }),
|
std::make_pair("tamas's std::sort based", [](const auto &its) { return measure_index(its, its_create_neighbors_index_6); }),
|
||||||
std::make_pair("tamas's tbb::parallel_sort based", [](const auto &its) { return measure_index(its, its_create_neighbors_index_7); }),
|
std::make_pair("tamas's tbb::parallel_sort based", [](const auto &its) { return measure_index(its, its_create_neighbors_index_7); }),
|
||||||
std::make_pair("tamas's map based", [](const auto &its) { return measure_index(its, its_create_neighbors_index_8); }),
|
std::make_pair("tamas's map based", [](const auto &its) { return measure_index(its, its_create_neighbors_index_8); }),
|
||||||
|
|
|
@ -3,8 +3,13 @@
|
||||||
|
|
||||||
#include "TriangleMesh.hpp"
|
#include "TriangleMesh.hpp"
|
||||||
#include "libnest2d/tools/benchmark.h"
|
#include "libnest2d/tools/benchmark.h"
|
||||||
|
#include "Execution/ExecutionTBB.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
template<class ExPolicy>
|
||||||
|
std::vector<Vec3i> create_neighbors_index(ExPolicy &&ex, const indexed_triangle_set &its);
|
||||||
|
|
||||||
namespace meshsplit_detail {
|
namespace meshsplit_detail {
|
||||||
|
|
||||||
template<class Its, class Enable = void> struct ItsWithNeighborsIndex_ {
|
template<class Its, class Enable = void> struct ItsWithNeighborsIndex_ {
|
||||||
|
@ -19,7 +24,7 @@ template<> struct ItsWithNeighborsIndex_<indexed_triangle_set> {
|
||||||
static const indexed_triangle_set &get_its(const indexed_triangle_set &its) noexcept { return its; }
|
static const indexed_triangle_set &get_its(const indexed_triangle_set &its) noexcept { return its; }
|
||||||
static Index get_index(const indexed_triangle_set &its) noexcept
|
static Index get_index(const indexed_triangle_set &its) noexcept
|
||||||
{
|
{
|
||||||
return its_create_neighbors_index(its);
|
return create_neighbors_index(ex_tbb, its);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -152,12 +157,68 @@ template<class Its> bool its_is_splittable(const Its &m)
|
||||||
const auto& neighbor_index = ItsWithNeighborsIndex_<Its>::get_index(m);
|
const auto& neighbor_index = ItsWithNeighborsIndex_<Its>::get_index(m);
|
||||||
|
|
||||||
std::vector<char> visited(its.indices.size(), false);
|
std::vector<char> visited(its.indices.size(), false);
|
||||||
its_find_unvisited_neighbors(its, neighbor_index, visited);
|
auto faces = its_find_unvisited_neighbors(its, neighbor_index, visited);
|
||||||
|
|
||||||
// Try finding an unvisited facet. If there are none, the mesh is not splittable.
|
return !faces.empty();
|
||||||
auto it = std::find(visited.begin(), visited.end(), false);
|
}
|
||||||
|
|
||||||
return it != visited.end();
|
inline int get_vertex_index(size_t vertex_index, const stl_triangle_vertex_indices &triangle_indices) {
|
||||||
|
if (int(vertex_index) == triangle_indices[0]) return 0;
|
||||||
|
if (int(vertex_index) == triangle_indices[1]) return 1;
|
||||||
|
if (int(vertex_index) == triangle_indices[2]) return 2;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vec2crd get_edge_indices(int edge_index, const stl_triangle_vertex_indices &triangle_indices)
|
||||||
|
{
|
||||||
|
int next_edge_index = (edge_index == 2) ? 0 : edge_index + 1;
|
||||||
|
int vi0 = triangle_indices[edge_index];
|
||||||
|
int vi1 = triangle_indices[next_edge_index];
|
||||||
|
return Vec2crd(vi0, vi1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ExPolicy>
|
||||||
|
std::vector<Vec3i> create_neighbors_index(ExPolicy &&ex, const indexed_triangle_set &its)
|
||||||
|
{
|
||||||
|
const std::vector<stl_triangle_vertex_indices> &indices = its.indices;
|
||||||
|
size_t vertices_size = its.vertices.size();
|
||||||
|
|
||||||
|
if (indices.empty() || vertices_size == 0) return {};
|
||||||
|
|
||||||
|
auto vertex_triangles = VertexFaceIndex{its};
|
||||||
|
constexpr int no_value = -1;
|
||||||
|
std::vector<Vec3i> neighbors(indices.size(),
|
||||||
|
Vec3i(no_value, no_value, no_value));
|
||||||
|
|
||||||
|
//for (const stl_triangle_vertex_indices& triangle_indices : indices) {
|
||||||
|
execution::for_each(ex, size_t(0), indices.size(),
|
||||||
|
[&neighbors, &indices, &vertex_triangles] (size_t index)
|
||||||
|
{
|
||||||
|
Vec3i& neighbor = neighbors[index];
|
||||||
|
const stl_triangle_vertex_indices & triangle_indices = indices[index];
|
||||||
|
for (int edge_index = 0; edge_index < 3; ++edge_index) {
|
||||||
|
// check if done
|
||||||
|
int& neighbor_edge = neighbor[edge_index];
|
||||||
|
if (neighbor_edge != no_value) continue;
|
||||||
|
Vec2crd edge_indices = get_edge_indices(edge_index, triangle_indices);
|
||||||
|
// IMPROVE: use same vector for 2 sides of triangle
|
||||||
|
const auto &faces_range = vertex_triangles[edge_indices[0]];
|
||||||
|
for (const size_t &face : faces_range) {
|
||||||
|
if (face <= index) continue;
|
||||||
|
const stl_triangle_vertex_indices &face_indices = indices[face];
|
||||||
|
int vertex_index = get_vertex_index(edge_indices[1], face_indices);
|
||||||
|
// NOT Contain second vertex?
|
||||||
|
if (vertex_index < 0) continue;
|
||||||
|
// Has NOT oposit direction?
|
||||||
|
if (edge_indices[0] != face_indices[(vertex_index + 1) % 3]) continue;
|
||||||
|
neighbor_edge = face;
|
||||||
|
neighbors[face][vertex_index] = index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, execution::max_concurrency(ex));
|
||||||
|
|
||||||
|
return neighbors;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include "ClipperUtils.hpp"
|
#include "ClipperUtils.hpp"
|
||||||
#include "Geometry.hpp"
|
#include "Geometry.hpp"
|
||||||
#include "Point.hpp"
|
#include "Point.hpp"
|
||||||
|
#include "Execution/ExecutionTBB.hpp"
|
||||||
|
#include "Execution/ExecutionSeq.hpp"
|
||||||
|
|
||||||
#include <libqhullcpp/Qhull.h>
|
#include <libqhullcpp/Qhull.h>
|
||||||
#include <libqhullcpp/QhullFacetList.h>
|
#include <libqhullcpp/QhullFacetList.h>
|
||||||
|
@ -1204,56 +1206,14 @@ void VertexFaceIndex::create(const indexed_triangle_set &its)
|
||||||
m_vertex_to_face_start.front() = 0;
|
m_vertex_to_face_start.front() = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_vertex_index(size_t vertex_index, const stl_triangle_vertex_indices &triangle_indices) {
|
|
||||||
if (int(vertex_index) == triangle_indices[0]) return 0;
|
|
||||||
if (int(vertex_index) == triangle_indices[1]) return 1;
|
|
||||||
if (int(vertex_index) == triangle_indices[2]) return 2;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Vec2crd get_edge_indices(int edge_index, const stl_triangle_vertex_indices &triangle_indices)
|
|
||||||
{
|
|
||||||
int next_edge_index = (edge_index == 2) ? 0 : edge_index + 1;
|
|
||||||
coord_t vi0 = triangle_indices[edge_index];
|
|
||||||
coord_t vi1 = triangle_indices[next_edge_index];
|
|
||||||
return Vec2crd(vi0, vi1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Vec3i> its_create_neighbors_index(const indexed_triangle_set &its)
|
std::vector<Vec3i> its_create_neighbors_index(const indexed_triangle_set &its)
|
||||||
{
|
{
|
||||||
const std::vector<stl_triangle_vertex_indices> &indices = its.indices;
|
return create_neighbors_index(ex_seq, its);
|
||||||
size_t vertices_size = its.vertices.size();
|
}
|
||||||
|
|
||||||
if (indices.empty() || vertices_size == 0) return {};
|
std::vector<Vec3i> its_create_neighbors_index_par(const indexed_triangle_set &its)
|
||||||
auto vertex_triangles = VertexFaceIndex{its};
|
{
|
||||||
coord_t no_value = -1;
|
return create_neighbors_index(ex_tbb, its);
|
||||||
std::vector<Vec3i> neighbors(indices.size(), Vec3i(no_value, no_value, no_value));
|
|
||||||
for (const stl_triangle_vertex_indices& triangle_indices : indices) {
|
|
||||||
coord_t index = &triangle_indices - &indices.front();
|
|
||||||
Vec3i& neighbor = neighbors[index];
|
|
||||||
for (int edge_index = 0; edge_index < 3; ++edge_index) {
|
|
||||||
// check if done
|
|
||||||
coord_t& neighbor_edge = neighbor[edge_index];
|
|
||||||
if (neighbor_edge != no_value) continue;
|
|
||||||
Vec2crd edge_indices = get_edge_indices(edge_index, triangle_indices);
|
|
||||||
// IMPROVE: use same vector for 2 sides of triangle
|
|
||||||
const auto &faces_range = vertex_triangles[edge_indices[0]];
|
|
||||||
for (const size_t &face : faces_range) {
|
|
||||||
if (int(face) <= index) continue;
|
|
||||||
const stl_triangle_vertex_indices &face_indices = indices[face];
|
|
||||||
int vertex_index = get_vertex_index(edge_indices[1], face_indices);
|
|
||||||
// NOT Contain second vertex?
|
|
||||||
if (vertex_index < 0) continue;
|
|
||||||
// Has NOT oposit direction?
|
|
||||||
if (edge_indices[0] != face_indices[(vertex_index + 1) % 3]) continue;
|
|
||||||
neighbor_edge = face;
|
|
||||||
neighbors[face][vertex_index] = index;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return neighbors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -142,6 +142,11 @@ private:
|
||||||
std::vector<Vec3i> create_face_neighbors_index(const indexed_triangle_set &its);
|
std::vector<Vec3i> create_face_neighbors_index(const indexed_triangle_set &its);
|
||||||
std::vector<Vec3i> create_face_neighbors_index(const indexed_triangle_set &its, std::function<void()> throw_on_cancel_callback);
|
std::vector<Vec3i> create_face_neighbors_index(const indexed_triangle_set &its, std::function<void()> throw_on_cancel_callback);
|
||||||
|
|
||||||
|
// Create index that gives neighbor faces for each face. Ignores face orientations.
|
||||||
|
// TODO: naming...
|
||||||
|
std::vector<Vec3i> its_create_neighbors_index(const indexed_triangle_set &its);
|
||||||
|
std::vector<Vec3i> its_create_neighbors_index_par(const indexed_triangle_set &its);
|
||||||
|
|
||||||
// After applying a transformation with negative determinant, flip the faces to keep the transformed mesh volume positive.
|
// After applying a transformation with negative determinant, flip the faces to keep the transformed mesh volume positive.
|
||||||
void its_flip_triangles(indexed_triangle_set &its);
|
void its_flip_triangles(indexed_triangle_set &its);
|
||||||
|
|
||||||
|
@ -156,11 +161,6 @@ int its_remove_degenerate_faces(indexed_triangle_set &its, bool shrink_to_fit =
|
||||||
// Remove vertices, which none of the faces references. Return number of freed vertices.
|
// Remove vertices, which none of the faces references. Return number of freed vertices.
|
||||||
int its_compactify_vertices(indexed_triangle_set &its, bool shrink_to_fit = true);
|
int its_compactify_vertices(indexed_triangle_set &its, bool shrink_to_fit = true);
|
||||||
|
|
||||||
using FaceNeighborIndex = std::vector< std::array<size_t, 3> >;
|
|
||||||
|
|
||||||
// Create index that gives neighbor faces for each face. Ignores face orientations.
|
|
||||||
std::vector<Vec3i> its_create_neighbors_index(const indexed_triangle_set &its);
|
|
||||||
|
|
||||||
std::vector<indexed_triangle_set> its_split(const indexed_triangle_set &its);
|
std::vector<indexed_triangle_set> its_split(const indexed_triangle_set &its);
|
||||||
|
|
||||||
bool its_is_splittable(const indexed_triangle_set &its);
|
bool its_is_splittable(const indexed_triangle_set &its);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue