separate triangulation into cgal project
This commit is contained in:
parent
325a391988
commit
77209abbcd
@ -289,8 +289,9 @@ cmake_policy(SET CMP0011 NEW)
|
||||
find_package(CGAL REQUIRED)
|
||||
cmake_policy(POP)
|
||||
|
||||
add_library(libslic3r_cgal STATIC MeshBoolean.cpp MeshBoolean.hpp TryCatchSignal.hpp
|
||||
TryCatchSignal.cpp)
|
||||
add_library(libslic3r_cgal STATIC MeshBoolean.hpp MeshBoolean.cpp
|
||||
TryCatchSignal.hpp TryCatchSignal.cpp
|
||||
Triangulation.hpp Triangulation.cpp)
|
||||
target_include_directories(libslic3r_cgal PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# Reset compile options of libslic3r_cgal. Despite it being linked privately, CGAL options
|
||||
|
@ -6,6 +6,8 @@
|
||||
#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
|
||||
#include "imgui/imstb_truetype.h" // stbtt_fontinfo
|
||||
|
||||
#include <Triangulation.hpp> // CGAL project
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
Emboss::FontItem::FontItem(const std::string &name, const std::string &path)
|
||||
@ -371,7 +373,10 @@ Emboss::FontList Emboss::get_font_list_by_folder() {
|
||||
}
|
||||
|
||||
#else
|
||||
void Emboss::get_font_list() {}
|
||||
Emboss::FontList Emboss::get_font_list() {
|
||||
// not implemented
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<std::wstring> Emboss::get_font_path(const std::wstring &font_face_name){
|
||||
// not implemented
|
||||
@ -545,7 +550,7 @@ indexed_triangle_set Emboss::polygons2model(const Polygons &shape2d,
|
||||
std::make_move_iterator(back_points.end()));
|
||||
|
||||
// CW order of triangle indices
|
||||
std::vector<Vec3i> shape_triangles = triangulate(shape2d);
|
||||
std::vector<Vec3i> shape_triangles = Triangulation::triangulate(shape2d);
|
||||
result.indices.reserve(shape_triangles.size() * 2 + count_point * 2);
|
||||
// top triangles - change to CCW
|
||||
for (const Vec3i &t : shape_triangles)
|
||||
@ -575,164 +580,6 @@ indexed_triangle_set Emboss::polygons2model(const Polygons &shape2d,
|
||||
return result;
|
||||
}
|
||||
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
|
||||
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
|
||||
Emboss::Indices Emboss::triangulate(const Points &points, const HalfEdges &half_edges)
|
||||
{
|
||||
// IMPROVE use int point insted of float !!!
|
||||
|
||||
// use cgal triangulation
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using Itag = CGAL::Exact_predicates_tag;
|
||||
using CDT = CGAL::Constrained_Delaunay_triangulation_2<K, CGAL::Default, Itag>;
|
||||
using Point = CDT::Point;
|
||||
|
||||
// construct a constrained triangulation
|
||||
CDT cdt;
|
||||
std::map<CDT::Vertex_handle, uint32_t> map; // for indices
|
||||
std::vector<CDT::Vertex_handle> vertices_handle; // for constriants
|
||||
vertices_handle.reserve(points.size());
|
||||
for (const auto& p: points) {
|
||||
Point cdt_p(p.x(), p.y());
|
||||
auto handl = cdt.insert(cdt_p);
|
||||
vertices_handle.push_back(handl);
|
||||
// point index
|
||||
uint32_t pi = &p - &points.front();
|
||||
map[handl] = pi;
|
||||
}
|
||||
|
||||
// triangle can not contain forbiden edge
|
||||
for (const std::pair<uint32_t, uint32_t> &edge : half_edges) {
|
||||
const CDT::Vertex_handle& vh1 = vertices_handle[edge.first];
|
||||
const CDT::Vertex_handle& vh2 = vertices_handle[edge.second];
|
||||
cdt.insert_constraint(vh1, vh2);
|
||||
}
|
||||
|
||||
auto faces = cdt.finite_face_handles();
|
||||
std::vector<Vec3i> indices;
|
||||
indices.reserve(faces.size());
|
||||
for (CDT::Face_handle face : faces) {
|
||||
// point indices
|
||||
std::array<uint32_t, 3> pi;
|
||||
for (size_t i = 0; i < 3; ++i)
|
||||
pi[i] = map[face->vertex(i)];
|
||||
|
||||
// Do not use triangles with opposit edges
|
||||
if (half_edges.find(std::make_pair(pi[1], pi[0])) != half_edges.end()) continue;
|
||||
if (half_edges.find(std::make_pair(pi[2], pi[1])) != half_edges.end()) continue;
|
||||
if (half_edges.find(std::make_pair(pi[0], pi[2])) != half_edges.end()) continue;
|
||||
|
||||
indices.emplace_back(pi[0], pi[1], pi[2]);
|
||||
}
|
||||
return indices;
|
||||
}
|
||||
|
||||
Emboss::Indices Emboss::triangulate(const Polygon &polygon)
|
||||
{
|
||||
const Points &pts = polygon.points;
|
||||
std::set<std::pair<uint32_t, uint32_t>> edges;
|
||||
for (uint32_t i = 1; i < pts.size(); ++i) edges.insert({i - 1, i});
|
||||
edges.insert({(uint32_t)pts.size() - 1, uint32_t(0)});
|
||||
Emboss::Indices indices = triangulate(pts, edges);
|
||||
remove_outer(indices, edges);
|
||||
return indices;
|
||||
}
|
||||
|
||||
Emboss::Indices Emboss::triangulate(const Polygons &polygons)
|
||||
{
|
||||
size_t count = count_points(polygons);
|
||||
Points points;
|
||||
points.reserve(count);
|
||||
for (const Polygon &polygon : polygons)
|
||||
points.insert(points.end(), polygon.points.begin(),
|
||||
polygon.points.end());
|
||||
|
||||
std::set<std::pair<uint32_t, uint32_t>> edges;
|
||||
uint32_t offset = 0;
|
||||
for (const Polygon& polygon : polygons) {
|
||||
const Points &pts = polygon.points;
|
||||
for (uint32_t i = 1; i < pts.size(); ++i) {
|
||||
uint32_t i2 = i + offset;
|
||||
edges.insert({i2 - 1, i2});
|
||||
}
|
||||
uint32_t size = static_cast<uint32_t>(pts.size());
|
||||
// add connection from first to last point
|
||||
edges.insert({offset + size - 1, offset});
|
||||
offset += size;
|
||||
}
|
||||
Emboss::Indices indices = triangulate(points, edges);
|
||||
remove_outer(indices, edges);
|
||||
return indices;
|
||||
}
|
||||
|
||||
void Emboss::remove_outer(Indices &indices, const HalfEdges &half_edges) {
|
||||
uint32_t no_triangle = indices.size();
|
||||
std::map<HalfEdge, uint32_t> edge2triangle;
|
||||
// triangles with all edges out of half_edge, candidate to remove
|
||||
std::vector<uint32_t> triangles_to_check;
|
||||
triangles_to_check.reserve(indices.size()/3);
|
||||
for (const auto& t : indices) {
|
||||
uint32_t index = &t - &indices.front();
|
||||
bool is_border = false;
|
||||
for (size_t j = 0; j < 3; ++j) {
|
||||
size_t j2 = (j == 0) ? 2 : (j - 1);
|
||||
HalfEdge he(t[j2], t[j]);
|
||||
if (half_edges.find(he) != half_edges.end())
|
||||
is_border = true;
|
||||
else
|
||||
edge2triangle[he] = index;
|
||||
}
|
||||
if (!is_border) {
|
||||
triangles_to_check.push_back(index);
|
||||
}
|
||||
}
|
||||
|
||||
std::set<uint32_t> remove;
|
||||
std::queue<uint32_t> insert;
|
||||
for (uint32_t index : triangles_to_check) {
|
||||
auto it = remove.find(index);
|
||||
if (it != remove.end()) continue; // already removed
|
||||
|
||||
bool is_edge = false;
|
||||
const Vec3i &t = indices[index];
|
||||
for (size_t j = 0; j < 3; ++j) {
|
||||
size_t j2 = (j == 0) ? 2 : (j - 1);
|
||||
// opposit
|
||||
HalfEdge he(t[j], t[j2]);
|
||||
if (edge2triangle.find(he) == edge2triangle.end()) is_edge = true;
|
||||
}
|
||||
|
||||
if (!is_edge) continue; // correct
|
||||
|
||||
insert.push(index);
|
||||
while (!insert.empty()) {
|
||||
uint32_t i = insert.front();
|
||||
insert.pop();
|
||||
if (remove.find(i) != remove.end()) continue;
|
||||
remove.insert(i);
|
||||
|
||||
for (size_t j = 0; j < 3; ++j) {
|
||||
size_t j2 = (j == 0) ? 2 : (j - 1);
|
||||
// opposit
|
||||
HalfEdge he(t[j], t[j2]);
|
||||
auto it = edge2triangle.find(he);
|
||||
if (it == edge2triangle.end()) continue; // edge
|
||||
insert.push(it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove indices
|
||||
std::vector<uint32_t> rem(remove.begin(), remove.end());
|
||||
std::sort(rem.begin(), rem.end());
|
||||
uint32_t offset = 0;
|
||||
for (uint32_t i : rem) {
|
||||
indices.erase(indices.begin() + (i - offset));
|
||||
++offset;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<Vec3f, Vec3f> Emboss::ProjectZ::project(const Point &p) const
|
||||
{
|
||||
Vec3f front(p.x(),p.y(),0.f);
|
||||
|
@ -146,28 +146,6 @@ public:
|
||||
/// <returns>Projected shape into space</returns>
|
||||
static indexed_triangle_set polygons2model(const Polygons &shape2d, const IProject& projection);
|
||||
|
||||
// define oriented connection of 2 vertices(defined by its index)
|
||||
using HalfEdge = std::pair<uint32_t, uint32_t>;
|
||||
using HalfEdges = std::set<HalfEdge>;
|
||||
using Indices = std::vector<Vec3i>;
|
||||
/// <summary>
|
||||
/// Connect points by triangulation to create filled surface by triangle indices
|
||||
/// </summary>
|
||||
/// <param name="points">Points to connect</param>
|
||||
/// <param name="edges">Constraint for edges, pair is from point(first) to point(second)</param>
|
||||
/// <returns>Triangles</returns>
|
||||
static Indices triangulate(const Points &points, const HalfEdges &half_edges);
|
||||
static Indices triangulate(const Polygon &polygon);
|
||||
static Indices triangulate(const Polygons &polygons);
|
||||
|
||||
/// <summary>
|
||||
/// Filter out triagles without both side edge or inside half edges
|
||||
/// Main purpose: Filter out triangles which lay outside of ExPolygon given to triangulation
|
||||
/// </summary>
|
||||
/// <param name="indices">Triangles</param>
|
||||
/// <param name="half_edges">Only outer edges</param>
|
||||
static void remove_outer(Indices &indices, const HalfEdges &half_edges);
|
||||
|
||||
class ProjectZ : public IProject
|
||||
{
|
||||
public:
|
||||
|
165
src/libslic3r/Triangulation.cpp
Normal file
165
src/libslic3r/Triangulation.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
#include "Triangulation.hpp"
|
||||
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
|
||||
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
Triangulation::Indices Triangulation::triangulate(const Points & points,
|
||||
const HalfEdges &half_edges)
|
||||
{
|
||||
// IMPROVE use int point insted of float !!!
|
||||
|
||||
// use cgal triangulation
|
||||
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using Itag = CGAL::Exact_predicates_tag;
|
||||
using CDT =
|
||||
CGAL::Constrained_Delaunay_triangulation_2<K, CGAL::Default, Itag>;
|
||||
using Point = CDT::Point;
|
||||
|
||||
// construct a constrained triangulation
|
||||
CDT cdt;
|
||||
std::map<CDT::Vertex_handle, uint32_t> map; // for indices
|
||||
std::vector<CDT::Vertex_handle> vertices_handle; // for constriants
|
||||
vertices_handle.reserve(points.size());
|
||||
for (const auto &p : points) {
|
||||
Point cdt_p(p.x(), p.y());
|
||||
auto handl = cdt.insert(cdt_p);
|
||||
vertices_handle.push_back(handl);
|
||||
// point index
|
||||
uint32_t pi = &p - &points.front();
|
||||
map[handl] = pi;
|
||||
}
|
||||
|
||||
// triangle can not contain forbiden edge
|
||||
for (const std::pair<uint32_t, uint32_t> &edge : half_edges) {
|
||||
const CDT::Vertex_handle &vh1 = vertices_handle[edge.first];
|
||||
const CDT::Vertex_handle &vh2 = vertices_handle[edge.second];
|
||||
cdt.insert_constraint(vh1, vh2);
|
||||
}
|
||||
|
||||
auto faces = cdt.finite_face_handles();
|
||||
std::vector<Vec3i> indices;
|
||||
indices.reserve(faces.size());
|
||||
for (CDT::Face_handle face : faces) {
|
||||
// point indices
|
||||
std::array<uint32_t, 3> pi;
|
||||
for (size_t i = 0; i < 3; ++i) pi[i] = map[face->vertex(i)];
|
||||
|
||||
// Do not use triangles with opposit edges
|
||||
if (half_edges.find(std::make_pair(pi[1], pi[0])) != half_edges.end())
|
||||
continue;
|
||||
if (half_edges.find(std::make_pair(pi[2], pi[1])) != half_edges.end())
|
||||
continue;
|
||||
if (half_edges.find(std::make_pair(pi[0], pi[2])) != half_edges.end())
|
||||
continue;
|
||||
|
||||
indices.emplace_back(pi[0], pi[1], pi[2]);
|
||||
}
|
||||
return indices;
|
||||
}
|
||||
|
||||
Triangulation::Indices Triangulation::triangulate(const Polygon &polygon)
|
||||
{
|
||||
const Points & pts = polygon.points;
|
||||
std::set<std::pair<uint32_t, uint32_t>> edges;
|
||||
for (uint32_t i = 1; i < pts.size(); ++i) edges.insert({i - 1, i});
|
||||
edges.insert({(uint32_t) pts.size() - 1, uint32_t(0)});
|
||||
Triangulation::Indices indices = triangulate(pts, edges);
|
||||
remove_outer(indices, edges);
|
||||
return indices;
|
||||
}
|
||||
|
||||
Triangulation::Indices Triangulation::triangulate(const Polygons &polygons)
|
||||
{
|
||||
size_t count = count_points(polygons);
|
||||
Points points;
|
||||
points.reserve(count);
|
||||
for (const Polygon &polygon : polygons)
|
||||
points.insert(points.end(), polygon.points.begin(),
|
||||
polygon.points.end());
|
||||
|
||||
std::set<std::pair<uint32_t, uint32_t>> edges;
|
||||
uint32_t offset = 0;
|
||||
for (const Polygon &polygon : polygons) {
|
||||
const Points &pts = polygon.points;
|
||||
for (uint32_t i = 1; i < pts.size(); ++i) {
|
||||
uint32_t i2 = i + offset;
|
||||
edges.insert({i2 - 1, i2});
|
||||
}
|
||||
uint32_t size = static_cast<uint32_t>(pts.size());
|
||||
// add connection from first to last point
|
||||
edges.insert({offset + size - 1, offset});
|
||||
offset += size;
|
||||
}
|
||||
Triangulation::Indices indices = triangulate(points, edges);
|
||||
remove_outer(indices, edges);
|
||||
return indices;
|
||||
}
|
||||
|
||||
void Triangulation::remove_outer(Indices &indices, const HalfEdges &half_edges)
|
||||
{
|
||||
uint32_t no_triangle = indices.size();
|
||||
std::map<HalfEdge, uint32_t> edge2triangle;
|
||||
// triangles with all edges out of half_edge, candidate to remove
|
||||
std::vector<uint32_t> triangles_to_check;
|
||||
triangles_to_check.reserve(indices.size() / 3);
|
||||
for (const auto &t : indices) {
|
||||
uint32_t index = &t - &indices.front();
|
||||
bool is_border = false;
|
||||
for (size_t j = 0; j < 3; ++j) {
|
||||
size_t j2 = (j == 0) ? 2 : (j - 1);
|
||||
HalfEdge he(t[j2], t[j]);
|
||||
if (half_edges.find(he) != half_edges.end())
|
||||
is_border = true;
|
||||
else
|
||||
edge2triangle[he] = index;
|
||||
}
|
||||
if (!is_border) { triangles_to_check.push_back(index); }
|
||||
}
|
||||
|
||||
std::set<uint32_t> remove;
|
||||
std::queue<uint32_t> insert;
|
||||
for (uint32_t index : triangles_to_check) {
|
||||
auto it = remove.find(index);
|
||||
if (it != remove.end()) continue; // already removed
|
||||
|
||||
bool is_edge = false;
|
||||
const Vec3i &t = indices[index];
|
||||
for (size_t j = 0; j < 3; ++j) {
|
||||
size_t j2 = (j == 0) ? 2 : (j - 1);
|
||||
// opposit
|
||||
HalfEdge he(t[j], t[j2]);
|
||||
if (edge2triangle.find(he) == edge2triangle.end()) is_edge = true;
|
||||
}
|
||||
|
||||
if (!is_edge) continue; // correct
|
||||
|
||||
insert.push(index);
|
||||
while (!insert.empty()) {
|
||||
uint32_t i = insert.front();
|
||||
insert.pop();
|
||||
if (remove.find(i) != remove.end()) continue;
|
||||
remove.insert(i);
|
||||
|
||||
for (size_t j = 0; j < 3; ++j) {
|
||||
size_t j2 = (j == 0) ? 2 : (j - 1);
|
||||
// opposit
|
||||
HalfEdge he(t[j], t[j2]);
|
||||
auto it = edge2triangle.find(he);
|
||||
if (it == edge2triangle.end()) continue; // edge
|
||||
insert.push(it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove indices
|
||||
std::vector<uint32_t> rem(remove.begin(), remove.end());
|
||||
std::sort(rem.begin(), rem.end());
|
||||
uint32_t offset = 0;
|
||||
for (uint32_t i : rem) {
|
||||
indices.erase(indices.begin() + (i - offset));
|
||||
++offset;
|
||||
}
|
||||
}
|
46
src/libslic3r/Triangulation.hpp
Normal file
46
src/libslic3r/Triangulation.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef libslic3r_MeshBoolean_hpp_
|
||||
#define libslic3r_MeshBoolean_hpp_
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <libslic3r/Point.hpp>
|
||||
#include <libslic3r/Polygon.hpp>
|
||||
#include <libslic3r/ExPolygon.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Triangulation
|
||||
{
|
||||
public:
|
||||
Triangulation() = delete;
|
||||
|
||||
// define oriented connection of 2 vertices(defined by its index)
|
||||
using HalfEdge = std::pair<uint32_t, uint32_t>;
|
||||
using HalfEdges = std::set<HalfEdge>;
|
||||
using Indices = std::vector<Vec3i>;
|
||||
|
||||
/// <summary>
|
||||
/// Connect points by triangulation to create filled surface by triangle
|
||||
/// indices
|
||||
/// </summary>
|
||||
/// <param name="points">Points to connect</param>
|
||||
/// <param name="edges">Constraint for edges, pair is from point(first) to
|
||||
/// point(second)</param> <returns>Triangles</returns>
|
||||
static Indices triangulate(const Points & points,
|
||||
const HalfEdges &half_edges);
|
||||
static Indices triangulate(const Polygon &polygon);
|
||||
static Indices triangulate(const Polygons &polygons);
|
||||
|
||||
/// <summary>
|
||||
/// Filter out triagles without both side edge or inside half edges
|
||||
/// Main purpose: Filter out triangles which lay outside of ExPolygon
|
||||
/// given to triangulation
|
||||
/// </summary>
|
||||
/// <param name="indices">Triangles</param>
|
||||
/// <param name="half_edges">Only outer edges</param>
|
||||
static void remove_outer(Indices &indices, const HalfEdges &half_edges);
|
||||
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
#endif // libslic3r_MeshBoolean_hpp_
|
@ -335,9 +335,11 @@ void GLGizmoEmboss::draw_add_button() {
|
||||
|
||||
Emboss::FontList font_list;
|
||||
font_list.reserve(input_files.size());
|
||||
for (auto &input_file : input_files) {
|
||||
std::string name = input_file.AfterLast('\\').c_str();
|
||||
std::string path = input_file.c_str();
|
||||
for (auto &input_file : input_files) {
|
||||
std::string path = std::string(input_file.c_str());
|
||||
size_t pos = path.find_last_of('\\');
|
||||
size_t pos2 = path.find_last_of('.');
|
||||
std::string name = path.substr(pos + 1, pos2 - pos-1);
|
||||
font_list.emplace_back(name, path);
|
||||
}
|
||||
// set last added font as active
|
||||
|
Loading…
Reference in New Issue
Block a user