Reduced copy of triangle inside of thread

This commit is contained in:
Filip Sykala - NTB T15p 2022-07-19 16:42:50 +02:00
parent f93cefb668
commit 621e6c8932
7 changed files with 450 additions and 163 deletions

View File

@ -53,7 +53,7 @@ public:
PointClass size() const; PointClass size() const;
double radius() const; double radius() const;
void translate(coordf_t x, coordf_t y) { assert(this->defined); PointClass v(x, y); this->min += v; this->max += v; } void translate(coordf_t x, coordf_t y) { assert(this->defined); PointClass v(x, y); this->min += v; this->max += v; }
void translate(const Vec2d &v) { this->min += v; this->max += v; } void translate(const PointClass &v) { this->min += v; this->max += v; }
void offset(coordf_t delta); void offset(coordf_t delta);
BoundingBoxBase<PointClass> inflated(coordf_t delta) const throw() { BoundingBoxBase<PointClass> out(*this); out.offset(delta); return out; } BoundingBoxBase<PointClass> inflated(coordf_t delta) const throw() { BoundingBoxBase<PointClass> out(*this); out.offset(delta); return out; }
PointClass center() const; PointClass center() const;

View File

@ -2,6 +2,7 @@
#define slic3r_ClosestPoint_hpp_ #define slic3r_ClosestPoint_hpp_
#include <vector> #include <vector>
#include <type_traits>
namespace Slic3r { namespace Slic3r {
@ -11,51 +12,9 @@ namespace Slic3r {
/// <param name="p">Seach for closest index to this point</param> /// <param name="p">Seach for closest index to this point</param>
/// <param name="pts">Search inside of thoose points</param> /// <param name="pts">Search inside of thoose points</param>
/// <returns>Index of closest point from sorted_pts</returns> /// <returns>Index of closest point from sorted_pts</returns>
template<class P> size_t find_closest(const P &p, const std::vector<P> &pts);
/// <summary>
/// Use a plane sweep algorithm to find closest point in sorted points
/// https://www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairPS.html
/// </summary>
/// <param name="p">Seach for closest index to this point</param>
/// <param name="sorted_pts">Sorted points by X coordinate</param>
/// <returns>Index of closest point from sorted_pts</returns>
template<class P> template<class P>
size_t find_closest_in_sorted(const P &p, const std::vector<P> &sorted_pts); // /*SFINAE*/ typename std::enable_if<std::is_member_function_pointer_v<decltype(&P::x)>>::type * = nullptr >
size_t find_closest(const P &p, const std::vector<P> &pts){
/// <summary>
/// Use a plane sweep algorithm to find closest point from pts in sorted_pts
/// https://www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairPS.html
/// </summary>
/// <param name="pts">Seach for closest index to thoose points</param>
/// <param name="sorted_pts">Sorted points by X coordinate</param>
/// <returns>Indices to pts(first) and sorted_pts(second)</returns>
template<class P>
std::pair<size_t, size_t> find_closest_in_sorted(
const std::vector<P> &pts, const std::vector<P> &sorted_pts);
namespace closestPoint {
/// <summary>
/// Function used to sort points before searching for closest
/// </summary>
/// <param name="p1">First point</param>
/// <param name="p2">Second Point</param>
/// <returns>True when, p1.x < p2.x </returns>
template<class P> bool sort_fnc(const P &p1, const P &p2){ return p1.x() < p2.x(); }
/// <summary> Function used to find upper bound in sorted points. </summary>
template<class P, typename V> bool upper_fnc(V value, const P &p){ return value < p.x(); }
/// <summary> Function used to find lower bound in sorted points. </summary>
template<class P, typename V> bool lower_fnc(const P &p, V value){ return value > p.x(); }
/// <summary> Calc manhatn size of point. Mainly to explain meaning</summary>
template<class P> uint32_t manhattan_size(const P &p1, const P &p2)
{ return std::abs(p1.x()-p2.x()) + abs(p1.y()-p2.y()); }
} // namespace closestPoint
} // namespace Slic3r
template<class P>
size_t Slic3r::find_closest(const P &p, const std::vector<P> &pts)
{
// check input // check input
if (pts.empty()) return std::numeric_limits<size_t>::max(); if (pts.empty()) return std::numeric_limits<size_t>::max();
if (pts.size() == 1) return 0; if (pts.size() == 1) return 0;
@ -79,6 +38,94 @@ size_t Slic3r::find_closest(const P &p, const std::vector<P> &pts)
return pts_ord[closest_index].ord; return pts_ord[closest_index].ord;
} }
/// <summary>
/// Use a plane sweep algorithm to find closest point in sorted points
/// https://www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairPS.html
/// </summary>
/// <param name="p">Seach for closest index to this point</param>
/// <param name="sorted_pts">Sorted points by X coordinate</param>
/// <returns>Index of closest point from sorted_pts</returns>
template<class P>
size_t find_closest_in_sorted(const P &p, const std::vector<P> &sorted_pts);
/// <summary>
/// Use a plane sweep algorithm to find closest point from pts in sorted_pts
/// https://www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairPS.html
/// </summary>
/// <param name="pts">Seach for closest index from thoose points</param>
/// <param name="sorted_pts">Seach for closest index to thoose points
/// Sorted points by X coordinate(by function closestPoint::sort_fnc)</param>
/// <returns>Indices to pts(first) and sorted_pts(second)</returns>
template<class P>
std::pair<size_t, size_t> find_closest_in_sorted(
const std::vector<P> &pts, const std::vector<P> &sorted_pts);
namespace closestPoint {
/// <summary>
/// Function used to sort points before searching for closest
/// </summary>
/// <param name="p1">First point</param>
/// <param name="p2">Second Point</param>
/// <returns>True when, p1.x < p2.x </returns>
template<class P> bool sort_fnc(const P &p1, const P &p2){ return p1.x() < p2.x(); }
/// <summary> Function used to find upper bound in sorted points. </summary>
template<class P, typename V> bool upper_fnc(V value, const P &p){ return value < p.x(); }
/// <summary> Function used to find lower bound in sorted points. </summary>
template<class P, typename V> bool lower_fnc(const P &p, V value){ return value > p.x(); }
/// <summary> Calc manhatn size of point. Mainly to explain meaning</summary>
template<class P> uint32_t manhattan_size(const P &p1, const P &p2)
{ return std::abs(p1.x()-p2.x()) + abs(p1.y()-p2.y()); }
template<class P>
typename std::vector<P>::const_iterator get_lower_bound(uint32_t& dist, const P &p,
typename std::vector<P>::const_iterator it_x, const std::vector<P>& pts)
{
if(it_x == pts.begin()) return pts.begin();
assert(it_x > pts.begin() && it_x < pts.end());
using V = decltype(p.x());
using It = std::vector<P>::const_iterator;
It res = std::lower_bound(pts.begin(), it_x, p.x() - dist, lower_fnc<P,V>);
for (auto it = it_x - 1; it > res; --it) {
uint32_t diff_y = std::abs(it->y() - p.y());
if (diff_y > dist) continue;
uint32_t diff_x = std::abs(it->x() - p.x());
uint32_t act_dist = diff_y + diff_x;
if (dist > act_dist) {
dist = act_dist;
res = std::lower_bound(res, it_x, p.x() - dist, lower_fnc<P,V>);
}
}
return res;
}
template<class P>
typename std::vector<P>::const_iterator get_uppper_bound(uint32_t& dist, const P &p,
typename std::vector<P>::const_iterator it_x, const std::vector<P>& pts)
{
assert(it_x >= pts.begin() && it_x < pts.end());
using V = decltype(p.x());
using It = std::vector<P>::const_iterator;
It res = std::upper_bound(it_x, pts.end(), p.x() + dist, upper_fnc<P,V>);
for (auto it = it_x + 1; it < res; ++it) {
uint32_t diff_y = std::abs(it->y() - p.y());
if (diff_y > dist) continue;
uint32_t diff_x = std::abs(it->x() - p.x());
uint32_t act_dist = diff_y + diff_x;
if (dist > act_dist) {
// IMPROVE: calc euclid distance when e.g. (diff_Biggery < 2*diff_smaller)
dist = act_dist;
res = std::upper_bound(it_x, res, p.x() + dist, upper_fnc<P,V>);
}
}
return res;
}
} // namespace closestPoint
} // namespace Slic3r
template<class P> template<class P>
size_t Slic3r::find_closest_in_sorted(const P &p, const std::vector<P> &pts) size_t Slic3r::find_closest_in_sorted(const P &p, const std::vector<P> &pts)
{ {
@ -99,44 +146,12 @@ size_t Slic3r::find_closest_in_sorted(const P &p, const std::vector<P> &pts)
if (is_it_x_end) --it_x; if (is_it_x_end) --it_x;
// manhatn distance to closest point // manhatn distance to closest point
uint32_t manhattan_dist = manhattan_size(*it_x, p); uint32_t manhattan_dist = manhattan_size(*it_x, p);
It it_l = get_lower_bound(manhattan_dist,p, it_x, pts);
// node for lower bound
It it_l;
if (it_x == pts.begin()) {
it_l = it_x;
} else {
it_l = std::lower_bound(pts.begin(), it_x, p.x() - manhattan_dist, lower_fnc<P,V>);
for (auto it = it_x - 1; it > it_l; --it) {
uint32_t diff_y = std::abs(it->y() - p.y());
if (diff_y > manhattan_dist) continue;
uint32_t diff_x = std::abs(it->x() - p.x());
uint32_t act_dist = diff_y + diff_x;
if (manhattan_dist > act_dist) {
manhattan_dist = act_dist;
it_l = std::lower_bound(it_l, it_x, p.x() - manhattan_dist, lower_fnc<P,V>);
}
}
}
// node for upper bound // node for upper bound
It it_u; It it_u = (is_it_x_end) ? pts.end() :
if (is_it_x_end) { get_uppper_bound(manhattan_dist, p, it_x, pts);
it_u = pts.end();
} else {
it_u = std::upper_bound(it_x, pts.end(), p.x() + manhattan_dist, upper_fnc<P,V>);
for (auto it = it_x + 1; it < it_u; ++it) {
uint32_t diff_y = std::abs(it->y() - p.y());
if (diff_y > manhattan_dist) continue;
uint32_t diff_x = std::abs(it->x() - p.x());
uint32_t act_dist = diff_y + diff_x;
if (manhattan_dist > act_dist) {
// IMPROVE: calc euclid distance when e.g. (diff_Biggery < 2*diff_smaller)
manhattan_dist = act_dist;
it_u = std::upper_bound(it_x, it_u, p.x() + manhattan_dist, upper_fnc<P,V>);
}
}
}
// find closest by squer distance // find closest by squer distance
float dist_sq = std::numeric_limits<float>::max(); float dist_sq = std::numeric_limits<float>::max();
size_t result = it_x - pts.begin(); size_t result = it_x - pts.begin();
@ -155,10 +170,83 @@ size_t Slic3r::find_closest_in_sorted(const P &p, const std::vector<P> &pts)
} }
template<class P> template<class P>
std::pair<size_t, size_t> find_closest_in_sorted( std::pair<size_t, size_t> Slic3r::find_closest_in_sorted(
const std::vector<P> &pts, const std::vector<P> &sorted_pts) const std::vector<P> &pts, const std::vector<P> &sorted_pts)
{ {
return {0, 0}; using namespace closestPoint;
// check that input is really sorted
assert(std::is_sorted(sorted_pts.begin(), sorted_pts.end(), sort_fnc<P>));
std::pair<size_t, size_t> res = {std::numeric_limits<size_t>::max(),
std::numeric_limits<size_t>::max()};
// check inputs
if (pts.empty() || sorted_pts.empty()) return res;
// Speed up for one element in vector
if (pts.size() == 1)
return {0, find_closest_in_sorted(pts.front(), sorted_pts)};
if (sorted_pts.size() == 1)
return {find_closest(sorted_pts.front(), pts), 0};
using V = decltype(p.x());
using It = std::vector<P>::const_iterator;
uint32_t res_dist = std::numeric_limits<uint32_t>::max();
float res_dist_sq = std::numeric_limits<float>::max();
auto set_res_dist_sq = [&res_dist_sq, &res_dist](float dist_sq) {
res_dist_sq = dist_sq;
float dist = sqrt(dist_sq);
// crop dist to unsigned int
uint32_t dist_ui = static_cast<uint32_t>(std::ceil(dist));
if (res_dist < dist_ui) res_dist = dist_ui;
};
// find limit for manhatn distance
bool is_first = true;
for (const P &p : pts) {
if (is_first) {
is_first = false;
size_t index = find_closest_in_sorted(p, sorted_pts);
res = {0, index};
const P &p2 = sorted_pts[index];
V d_x = p.x()-p2.x();
V d_y = p.y()-p2.y();
set_res_dist_sq(d_x * d_x + d_y * d_y);
continue;
}
// closest point node in X
It it_x = std::upper_bound(pts.begin(), pts.end(), p.x(), upper_fnc<P, V>);
bool is_it_x_end = it_x == pts.end();
// it_x can't pointing to end so change to last point
if (is_it_x_end) --it_x;
// manhatn distance to closest point
uint32_t p_dist = manhattan_size(*it_x, p);
It it_l = get_lower_bound(res_dist, p, it_x, pts);
// node for upper bound
It it_u = pts.end();
if (!is_it_x_end) it_u = get_uppper_bound(res_dist, p, it_x, pts);
// find closest by squer distance
float dist_sq = res_dist_sq;
for (It it = it_l; it < it_u; ++it) {
uint32_t diff_y = std::abs(it->y() - p.y());
if (diff_y > res_dist) continue;
float diff_x = it->x() - p.x();
// calculate square distance
float d = (float) diff_y * diff_y + diff_x * diff_x;
if (dist_sq > d) {
dist_sq = d;
size_t i1 = &p - &pts.begin();
size_t i2 = it - pts.begin();
res = {i1, i2};
}
}
// found closer?
if (res_dist_sq > dist_sq)
set_res_dist_sq(dist_sq);
}
return res;
} }
#endif // slic3r_ClosestPoint_hpp_ #endif // slic3r_ClosestPoint_hpp_

View File

@ -409,14 +409,14 @@ VDistances calc_distances(const SurfacePatches &patches,
/// <summary> /// <summary>
/// Select distances in similar depth between expolygons /// Select distances in similar depth between expolygons
/// </summary> /// </summary>
/// <param name="distances">All distances</param> /// <param name="distances">All distances - Vector distances for each shape point</param>
/// <param name="shapes">Vector of letters</param> /// <param name="shapes">Vector of letters</param>
/// <param name="shape_point_2_index">Convert index to addresss inside of shape</param> /// <param name="shape_point_2_index">Convert index to addresss inside of shape</param>
/// <returns>Best projection distances</returns> /// <returns>Best projection distances</returns>
ProjectionDistances choose_best_distance( ProjectionDistances choose_best_distance(
const std::vector<ProjectionDistances> &distances, const VDistances &distances,
const ExPolygons &shapes, const ExPolygons &shapes,
const ShapePoint2index &shape_point_2_index); const ShapePoint2index &shape_point_2_index);
/// <summary> /// <summary>
/// Create mask for patches /// Create mask for patches
@ -667,7 +667,6 @@ void priv::set_skip_for_out_of_aoi(std::vector<bool> &skip_indicies,
const BoundingBox &shapes_bb) const BoundingBox &shapes_bb)
{ {
assert(skip_indicies.size() == its.indices.size()); assert(skip_indicies.size() == its.indices.size());
// 1`*----* 2` // 1`*----* 2`
// / 2 /| // / 2 /|
// 1 *----* | // 1 *----* |
@ -739,6 +738,59 @@ void priv::set_skip_for_out_of_aoi(std::vector<bool> &skip_indicies,
} }
} }
indexed_triangle_set Slic3r::its_mask(const indexed_triangle_set &its,
const std::vector<bool> &mask)
{
if (its.indices.size() != mask.size()) {
assert(false);
return {};
}
std::vector<uint32_t> cvt_vetices(its.vertices.size(), {std::numeric_limits<uint32_t>::max()});
size_t vertices_count = 0;
size_t faces_count = 0;
for (const auto &t : its.indices) {
size_t index = &t - &its.indices.front();
if (!mask[index]) continue;
++faces_count;
for (const auto vi : t) {
uint32_t &cvt = cvt_vetices[vi];
if (cvt == std::numeric_limits<uint32_t>::max())
cvt = vertices_count++;
}
}
if (faces_count == 0) return {};
assert(vertices_count <= vertices.size());
assert(faces_count <= indices.size());
indexed_triangle_set result;
result.indices.reserve(faces_count);
result.vertices = std::vector<Vec3f>(vertices_count);
for (size_t i = 0; i < its.vertices.size(); ++i) {
uint32_t index = cvt_vetices[i];
if (index == std::numeric_limits<uint32_t>::max()) continue;
result.vertices[index] = its.vertices[i];
}
for (const stl_triangle_vertex_indices &f : its.indices)
if (mask[&f - &its.indices.front()])
result.indices.push_back(stl_triangle_vertex_indices(
cvt_vetices[f[0]], cvt_vetices[f[1]], cvt_vetices[f[2]]));
return result;
}
indexed_triangle_set Slic3r::its_cut_AoI(const indexed_triangle_set &its,
const BoundingBox &bb,
const Emboss::IProjection &projection)
{
std::vector<bool> skip_indicies(its.indices.size(), false);
priv::set_skip_for_out_of_aoi(skip_indicies, its, projection, bb);
// invert values in vector of bool
skip_indicies.flip();
return its_mask(its, skip_indicies);
}
void priv::set_skip_by_angle(std::vector<bool> &skip_indicies, void priv::set_skip_by_angle(std::vector<bool> &skip_indicies,
const indexed_triangle_set &its, const indexed_triangle_set &its,
const Project3f &projection, const Project3f &projection,
@ -769,7 +821,6 @@ priv::CutMesh priv::to_cgal(const indexed_triangle_set &its,
const std::vector<stl_vertex> &vertices = its.vertices; const std::vector<stl_vertex> &vertices = its.vertices;
const std::vector<stl_triangle_vertex_indices> &indices = its.indices; const std::vector<stl_triangle_vertex_indices> &indices = its.indices;
std::vector<bool> use_indices(indices.size(), {false});
std::vector<bool> use_vetices(vertices.size(), {false}); std::vector<bool> use_vetices(vertices.size(), {false});
size_t vertices_count = 0; size_t vertices_count = 0;
@ -780,7 +831,6 @@ priv::CutMesh priv::to_cgal(const indexed_triangle_set &its,
size_t index = &t - &indices.front(); size_t index = &t - &indices.front();
if (skip_indicies[index]) continue; if (skip_indicies[index]) continue;
++faces_count; ++faces_count;
use_indices[index] = true;
size_t count_used_vertices = 0; size_t count_used_vertices = 0;
for (const auto vi : t) { for (const auto vi : t) {
if (!use_vetices[vi]) { if (!use_vetices[vi]) {
@ -820,14 +870,14 @@ priv::CutMesh priv::to_cgal(const indexed_triangle_set &its,
if (!flip) { if (!flip) {
for (const stl_triangle_vertex_indices &f : indices) { for (const stl_triangle_vertex_indices &f : indices) {
if (!use_indices[&f - &indices.front()]) continue; if (skip_indicies[&f - &indices.front()]) continue;
result.add_face(to_filtrated_vertices_index[f[0]], result.add_face(to_filtrated_vertices_index[f[0]],
to_filtrated_vertices_index[f[1]], to_filtrated_vertices_index[f[1]],
to_filtrated_vertices_index[f[2]]); to_filtrated_vertices_index[f[2]]);
} }
} else { } else {
for (const stl_triangle_vertex_indices &f : indices) { for (const stl_triangle_vertex_indices &f : indices) {
if (!use_indices[&f - &indices.front()]) continue; if (skip_indicies[&f - &indices.front()]) continue;
result.add_face(to_filtrated_vertices_index[f[2]], result.add_face(to_filtrated_vertices_index[f[2]],
to_filtrated_vertices_index[f[1]], to_filtrated_vertices_index[f[1]],
to_filtrated_vertices_index[f[0]]); to_filtrated_vertices_index[f[0]]);
@ -1655,6 +1705,18 @@ struct ClosePoint
// search in all shapes points to found closest point to given point // search in all shapes points to found closest point to given point
uint32_t get_closest_point_index(const Point &p, const ExPolygons &shapes, const VDistances &distances); uint32_t get_closest_point_index(const Point &p, const ExPolygons &shapes, const VDistances &distances);
using PNode = std::pair<Point, uint32_t>;
using PNodes = std::vector<PNode>;
PNodes create_nodes(const ExPolygons &shapes, const VDistances &distances, size_t shapes_point_count);
/// <summary>
/// Search in all shapes points(nodes) to found closest point to given point
/// </summary>
/// <param name="p">Point to search closest</param>
/// <param name="nodes">Points sorted by X</param>
/// <returns>Index into shapes of point closest to given point</returns>
uint32_t get_closest_point_index2(const Point &p, const PNodes& nodes);
// Search for closest projection to wanted distance // Search for closest projection to wanted distance
const ProjectionDistance *get_closest_projection(const ProjectionDistances &distance, float wanted_distance); const ProjectionDistance *get_closest_projection(const ProjectionDistances &distance, float wanted_distance);
@ -1702,6 +1764,105 @@ uint32_t priv::get_closest_point_index(const Point &p,
return cp.index; return cp.index;
} }
priv::PNodes priv::create_nodes(const ExPolygons &shapes, const VDistances &distances, size_t shapes_point_count) {
PNodes pts;
pts.reserve(shapes_point_count);
uint32_t index = 0;
auto add_polygon = [&pts, &index, &distances](const Polygon &poly) {
for (const Point &p : poly.points) {
// skip empty distances
if (distances[index].empty()) {
++index;
continue;
}
pts.emplace_back(p, index++);
}
};
for (const ExPolygon s : shapes) {
add_polygon(s.contour);
for (const Polygon &h : s.holes) add_polygon(h);
}
std::sort(pts.begin(), pts.end(), [](const PNode &n1, const PNode &n2) {
return n1.first.x() < n2.first.x();
});
return pts;
}
uint32_t priv::get_closest_point_index2(const Point &p, const PNodes &nodes)
{
assert(!nodes.empty());
// function to find upper point node
auto f_u = [](coord_t value, const PNode& n) {
return value < n.first.x();
};
// function to find lower point node
auto f_l = [](const PNode &n, coord_t value) {
return value > n.first.x();
};
// closest point node in X
auto it_x = std::upper_bound(nodes.begin(), nodes.end(), p.x(), f_u);
// manhatn distance to closest point
auto manhattan_size = [](const Point &p) -> uint32_t {
return std::abs(p.x()) + abs(p.y());
};
uint32_t manhattan_dist = (it_x != nodes.end())?
manhattan_size(it_x->first - p) :
manhattan_size(nodes.back().first - p);
// node for lower bound
auto it_l = std::lower_bound(nodes.begin(), it_x, p.x() - manhattan_dist, f_l);
auto it = it_x;
while (it > it_l) {
uint32_t diff_y = std::abs(it->first.y() - p.y());
if (diff_y > manhattan_dist) {
--it;
continue;
}
uint32_t diff_x = std::abs(it->first.x() - p.x());
uint32_t act_dist = diff_y + diff_x;
if (manhattan_dist > act_dist) {
manhattan_dist = act_dist;
it_l = std::lower_bound(it_l, it_x, p.x() - manhattan_dist, f_l);
}
--it;
}
// node for upper bound
auto it_u = std::upper_bound(it_x, nodes.end(), p.x() + manhattan_dist, f_u);
it = it_x;
while (it < it_u) {
++it;
uint32_t diff_y = std::abs(it->first.y() - p.y());
if (diff_y > manhattan_dist) continue;
uint32_t diff_x = std::abs(it->first.x() - p.x());
uint32_t act_dist = diff_y + diff_x;
if (manhattan_dist > act_dist) {
// IMPROVE: calc euclid distance when e.g. (diff_Biggery < 2*diff_smaller)
manhattan_dist = act_dist;
it_u = std::upper_bound(it_x, it_u, p.x() + manhattan_dist, f_u);
}
}
// find closest by squer distance
it = it_l;
ClosePoint cp;
for (it = it_l; it < it_u; ++it) {
uint32_t diff_y = std::abs(it->first.y() - p.y());
if (diff_y > manhattan_dist) continue;
float diff_x = it->first.x() - p.x();
// calculate square distance
float d = (float) diff_y * diff_y + diff_x * diff_x;
if (cp.dist_sq > d) {
cp.dist_sq = d;
cp.index = it->second;
}
}
return cp.index;
}
const priv::ProjectionDistance *priv::get_closest_projection( const priv::ProjectionDistance *priv::get_closest_projection(
const ProjectionDistances &distance, float wanted_distance) const ProjectionDistances &distance, float wanted_distance)
{ {
@ -1904,9 +2065,9 @@ priv::ClosePoint priv::find_close_point(const Point &p,
// IMPROVE: create better structure to find closest points e.g. Tree // IMPROVE: create better structure to find closest points e.g. Tree
// IMPROVE2: when select distance fill in all distances from Patch // IMPROVE2: when select distance fill in all distances from Patch
priv::ProjectionDistances priv::choose_best_distance( priv::ProjectionDistances priv::choose_best_distance(
const std::vector<ProjectionDistances> &distances, const VDistances &distances,
const ExPolygons &shapes, const ExPolygons &shapes,
const ShapePoint2index &s2i) const ShapePoint2index &s2i)
{ {
// collect one closest projection for each outline point // collect one closest projection for each outline point
ProjectionDistances result(distances.size()); ProjectionDistances result(distances.size());
@ -1924,6 +2085,9 @@ priv::ProjectionDistances priv::choose_best_distance(
// Select point from shapes(text contour) which is closest to center (all in 2d) // Select point from shapes(text contour) which is closest to center (all in 2d)
uint32_t unfinished_index = get_closest_point_index(center, shapes, distances); uint32_t unfinished_index = get_closest_point_index(center, shapes, distances);
//PNodes pts = create_nodes(shapes, distances, s2i.get_count());
//uint32_t unfinished_index2 = get_closest_point_index2(center, pts);
do { do {
const ProjectionDistance* pd = get_closest_projection(distances[unfinished_index], wanted_distance); const ProjectionDistance* pd = get_closest_projection(distances[unfinished_index], wanted_distance);
// selection of closest_id should proove that pd has value // selection of closest_id should proove that pd has value

View File

@ -48,5 +48,25 @@ SurfaceCut cut_surface(const ExPolygons &shapes,
indexed_triangle_set cut2model(const SurfaceCut &cut, indexed_triangle_set cut2model(const SurfaceCut &cut,
const Emboss::IProject3f &projection); const Emboss::IProject3f &projection);
/// <summary>
/// Separate (A)rea (o)f (I)nterest .. AoI from model
/// NOTE: Only 2d filtration, do not filtrate by Z coordinate
/// </summary>
/// <param name="its">Input model</param>
/// <param name="bb">Bounding box to project into space</param>
/// <param name="projection">Define tranformation of BB into space</param>
/// <returns>Triangles lay at least partialy inside of projected Bounding box</returns>
indexed_triangle_set its_cut_AoI(const indexed_triangle_set &its,
const BoundingBox &bb,
const Emboss::IProjection &projection);
/// <summary>
/// Separate triangles by mask
/// </summary>
/// <param name="its">Input model</param>
/// <param name="mask">Mask - same size as its::indices</param>
/// <returns>Copy of indices by mask(with their vertices)</returns>
indexed_triangle_set its_mask(const indexed_triangle_set &its, const std::vector<bool> &mask);
} // namespace Slic3r } // namespace Slic3r
#endif // slic3r_CutSurface_hpp_ #endif // slic3r_CutSurface_hpp_

View File

@ -940,8 +940,8 @@ bool GLGizmoEmboss::process()
const TextConfiguration &tc = data.text_configuration; const TextConfiguration &tc = data.text_configuration;
if (tc.font_item.prop.use_surface) { if (tc.font_item.prop.use_surface) {
// Model to cut surface from. // Model to cut surface from.
UseSurfaceData::ModelSource source = UseSurfaceData::create_source(m_volume); UseSurfaceData::ModelSources sources = UseSurfaceData::create_sources(m_volume);
if (source.its.empty()) return false; if (sources.empty()) return false;
Transform3d text_tr = m_volume->get_matrix(); Transform3d text_tr = m_volume->get_matrix();
auto& fix_3mf = m_volume->text_configuration->fix_3mf_tr; auto& fix_3mf = m_volume->text_configuration->fix_3mf_tr;
@ -953,7 +953,7 @@ bool GLGizmoEmboss::process()
assert(is_outside || m_volume->is_negative_volume() || assert(is_outside || m_volume->is_negative_volume() ||
m_volume->is_modifier()); m_volume->is_modifier());
UseSurfaceData surface_data{std::move(data), text_tr, is_outside, UseSurfaceData surface_data{std::move(data), text_tr, is_outside,
std::move(source)}; std::move(sources)};
job = std::make_unique<UseSurfaceJob>(std::move(surface_data)); job = std::make_unique<UseSurfaceJob>(std::move(surface_data));
} else { } else {
job = std::make_unique<EmbossUpdateJob>(std::move(data)); job = std::make_unique<EmbossUpdateJob>(std::move(data));

View File

@ -318,7 +318,7 @@ void EmbossUpdateJob::finalize(bool canceled, std::exception_ptr &eptr)
priv::update_volume(std::move(m_result), m_input); priv::update_volume(std::move(m_result), m_input);
} }
UseSurfaceData::ModelSource UseSurfaceData::create_source( UseSurfaceData::ModelSources UseSurfaceData::create_sources(
const ModelVolume *text_volume) const ModelVolume *text_volume)
{ {
if (text_volume == nullptr) return {}; if (text_volume == nullptr) return {};
@ -326,54 +326,17 @@ UseSurfaceData::ModelSource UseSurfaceData::create_source(
const ModelVolumePtrs &volumes = text_volume->get_object()->volumes; const ModelVolumePtrs &volumes = text_volume->get_object()->volumes;
// no other volume in object // no other volume in object
if (volumes.size() <= 1) return {}; if (volumes.size() <= 1) return {};
// One volume transformation is used for transform others
// Most common cut is into one volume so it is cheaper to do not transform this volume
// NOTE: Preparation is made on Main thred!
auto find_biggest = [&text_volume]
(const ModelVolumePtrs& volumes, const ObjectID& text_volume_id)->const ModelVolume * {
const ModelVolume *biggest = nullptr;
size_t biggest_size = 0;
for (const ModelVolume *v: volumes) {
if (v->id() == text_volume_id) continue;
if (!v->is_model_part()) continue;
const TriangleMesh &tm = v->mesh();
if (tm.empty()) continue;
if (tm.its.empty()) continue;
if (biggest_size > tm.its.indices.size()) continue;
biggest_size = tm.its.indices.size();
biggest = v;
}
assert(biggest != nullptr);
return biggest;
};
const ModelVolume *biggest_volume = find_biggest(volumes, text_volume->id()); ModelSources result;
const TriangleMesh &biggest_tm = biggest_volume->mesh(); result.reserve(volumes.size() - 1);
// IMPROVE: Copy only AOI by shapes and projection
// NOTE: copy of source mesh tringles and it slows down on big meshes
ModelSource result{
{biggest_tm.its}, // copy !!!
biggest_volume->get_transformation().get_matrix(),
biggest_tm.bounding_box()
};
Transform3d tr_inv = result.tr.inverse();
// Improve create object from part or use gl_volume
// Get first model part in object
for (const ModelVolume *v : volumes) { for (const ModelVolume *v : volumes) {
if (v->id() == text_volume->id()) continue; if (v->id() == text_volume->id()) continue;
if (v->id() == biggest_volume->id()) continue; // skip modifiers and negative volumes, ...
if (!v->is_model_part()) continue; if (!v->is_model_part()) continue;
const TriangleMesh &tm = v->mesh(); const TriangleMesh &tm = v->mesh();
if (tm.empty()) continue; if (tm.empty()) continue;
if (tm.its.empty()) continue; if (tm.its.empty()) continue;
result.push_back({v->get_mesh_shared_ptr(), v->get_matrix()});
Transform3d tr = v->get_matrix() * tr_inv;
indexed_triangle_set its = tm.its; // copy !!!
its_transform(its, tr);
result.its.emplace_back(std::move(its));
} }
return result; return result;
} }
@ -386,6 +349,22 @@ UseSurfaceJob::UseSurfaceJob(UseSurfaceData &&input)
assert(priv::check(m_input, true)); assert(priv::check(m_input, true));
} }
static const UseSurfaceData::ModelSource* get_biggest(
const UseSurfaceData::ModelSources &sources)
{
const UseSurfaceData::ModelSource *biggest = nullptr;
for (const UseSurfaceData::ModelSource &s : sources) {
if (biggest == nullptr) {
biggest = &s;
continue;
}
if (biggest->mesh->its.indices.size() < s.mesh->its.indices.size()) {
biggest = &s;
}
}
return biggest;
}
void UseSurfaceJob::process(Ctl &ctl) { void UseSurfaceJob::process(Ctl &ctl) {
if (!priv::check(m_input)) if (!priv::check(m_input))
throw std::runtime_error("Bad input data for UseSurfaceJob."); throw std::runtime_error("Bad input data for UseSurfaceJob.");
@ -406,28 +385,66 @@ void UseSurfaceJob::process(Ctl &ctl) {
if (was_canceled()) return; if (was_canceled()) return;
Transform3d mesh_tr_inv = m_input.source.tr.inverse(); // Define alignment of text - left, right, center, top bottom, ....
Transform3d cut_projection_tr = mesh_tr_inv * m_input.text_tr; BoundingBox bb = get_extents(shapes);
Transform3d emboss_tr = cut_projection_tr.inverse(); Point projection_center = bb.center();
BoundingBoxf3 mesh_bb_tr = m_input.source.bb.transformed(emboss_tr); for (ExPolygon &shape : shapes) shape.translate(-projection_center);
std::pair<float, float> z_range{mesh_bb_tr.min.z(), mesh_bb_tr.max.z()}; bb.translate(-projection_center);
const Emboss::FontFile &ff = *m_input.font_file.font_file; const Emboss::FontFile &ff = *m_input.font_file.font_file;
double shape_scale = Emboss::get_shape_scale(fp, ff); double shape_scale = Emboss::get_shape_scale(fp, ff);
size_t biggest_count = 0;
size_t biggest_index = 0;
const UseSurfaceData::ModelSource *biggest = nullptr;
std::vector<size_t> s_to_itss(m_input.sources.size(), std::numeric_limits<size_t>::max());
std::vector<indexed_triangle_set> itss;
itss.reserve(m_input.sources.size());
for (const UseSurfaceData::ModelSource &s : m_input.sources) {
Transform3d mesh_tr_inv = s.tr.inverse();
Transform3d cut_projection_tr = mesh_tr_inv * m_input.text_tr;
std::pair<float, float> z_range{0., 1.};
Emboss::OrthoProject cut_projection =
priv::create_projection_for_cut(cut_projection_tr, shape_scale, z_range);
// copy only part of source model
indexed_triangle_set its = its_cut_AoI(s.mesh->its, bb, cut_projection);
if (its.indices.empty()) continue;
if (biggest_count < its.vertices.size()) {
biggest_count = its.vertices.size();
biggest = &s;
}
s_to_itss[&s - &m_input.sources.front()] = itss.size();
itss.emplace_back(std::move(its));
}
if (itss.empty())
throw priv::EmbossJobException(_u8L("There is no volume in projection direction.").c_str());
Transform3d tr_inv = biggest->tr.inverse();
size_t itss_index = s_to_itss[biggest - &m_input.sources.front()];
BoundingBoxf3 mesh_bb = bounding_box(itss[itss_index]);
for (const UseSurfaceData::ModelSource &s : m_input.sources) {
if (&s == biggest) continue;
size_t itss_index = s_to_itss[&s - &m_input.sources.front()];
if (itss_index == std::numeric_limits<size_t>::max()) continue;
Transform3d tr = s.tr * tr_inv;
indexed_triangle_set &its = itss[itss_index];
its_transform(its, tr);
BoundingBoxf3 bb = bounding_box(its);
mesh_bb.merge(bb);
}
Transform3d mesh_tr_inv = tr_inv;
Transform3d cut_projection_tr = mesh_tr_inv * m_input.text_tr;
Transform3d emboss_tr = cut_projection_tr.inverse();
BoundingBoxf3 mesh_bb_tr = mesh_bb.transformed(emboss_tr);
std::pair<float, float> z_range{mesh_bb_tr.min.z(), mesh_bb_tr.max.z()};
Emboss::OrthoProject cut_projection = priv::create_projection_for_cut( Emboss::OrthoProject cut_projection = priv::create_projection_for_cut(
cut_projection_tr, shape_scale, z_range); cut_projection_tr, shape_scale, z_range);
float projection_ratio = (-z_range.first + priv::safe_extension) / float projection_ratio = (-z_range.first + priv::safe_extension) /
(z_range.second - z_range.first + 2 * priv::safe_extension); (z_range.second - z_range.first + 2 * priv::safe_extension);
// Define alignment of text - left, right, center, top bottom, ....
BoundingBox bb = get_extents(shapes);
Point projection_center = bb.center();
for (ExPolygon &shape : shapes)
shape.translate(-projection_center);
// Use CGAL to cut surface from triangle mesh // Use CGAL to cut surface from triangle mesh
SurfaceCut cut = cut_surface(shapes, m_input.source.its, SurfaceCut cut = cut_surface(shapes, itss, cut_projection, projection_ratio);
cut_projection, projection_ratio);
if (cut.empty()) if (cut.empty())
throw priv::EmbossJobException( throw priv::EmbossJobException(
_u8L("There is no valid surface for text projection.").c_str()); _u8L("There is no valid surface for text projection.").c_str());
@ -512,8 +529,8 @@ bool priv::check(const EmbossDataUpdate &input, bool is_main_thread){
} }
bool priv::check(const UseSurfaceData &input, bool is_main_thread){ bool priv::check(const UseSurfaceData &input, bool is_main_thread){
bool res = check((EmbossDataUpdate) input, is_main_thread); bool res = check((EmbossDataUpdate) input, is_main_thread);
assert(!input.source.its.empty()); assert(!input.sources.empty());
res &= !input.source.its.empty(); res &= !input.sources.empty();
return res; return res;
} }

View File

@ -161,22 +161,20 @@ struct UseSurfaceData : public EmbossDataUpdate
struct ModelSource struct ModelSource
{ {
// IMPROVE: Copy only AOI by shapes and projection // source volumes
// NOTE: copy of source mesh tringles and it slows down on big meshes std::shared_ptr<const TriangleMesh> mesh;
std::vector<indexed_triangle_set> its;
// Transformation of volume inside of object // Transformation of volume inside of object
Transform3d tr; Transform3d tr;
// extract bounds for projection
BoundingBoxf3 bb;
}; };
ModelSource source; using ModelSources = std::vector<ModelSource>;
ModelSources sources;
/// <summary> /// <summary>
/// Copied triangles from object to be able create mesh for cut surface from /// Copied triangles from object to be able create mesh for cut surface from
/// </summary> /// </summary>
/// <param name="text_volume">Define text in object</param> /// <param name="text_volume">Define text in object</param>
/// <returns>Source data for cut surface from</returns> /// <returns>Source data for cut surface from</returns>
static ModelSource create_source(const ModelVolume *text_volume); static ModelSources create_sources(const ModelVolume *text_volume);
}; };
/// <summary> /// <summary>