Reduced copy of triangle inside of thread
This commit is contained in:
parent
f93cefb668
commit
621e6c8932
@ -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;
|
||||||
|
@ -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_
|
||||||
|
@ -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
|
||||||
|
@ -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_
|
||||||
|
@ -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));
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user