diff --git a/src/libslic3r/CutSurface.cpp b/src/libslic3r/CutSurface.cpp index 74ebfe094e..a2b5c4602b 100644 --- a/src/libslic3r/CutSurface.cpp +++ b/src/libslic3r/CutSurface.cpp @@ -20,9 +20,10 @@ /// patches/patch{O}.off /// result.obj - Merged result its /// result_contours/{O}.obj - visualization of contours for result patches -//#define DEBUG_OUTPUT_DIR std::string("C:/data/temp/cutSurface/") +#define DEBUG_OUTPUT_DIR std::string("C:/data/temp/cutSurface/") using namespace Slic3r; +#include "ExPolygonsIndex.hpp" #include #include @@ -33,11 +34,12 @@ using namespace Slic3r; // libslic3r #include "TriangleMesh.hpp" // its_merge #include "Utils.hpp" // next_highest_power_of_2 +#include "ClipperUtils.hpp" // union_ex + offset_ex namespace priv { using Project = Emboss::IProjection; -using Project3f = Emboss::IProject3f; +using Project3d = Emboss::IProject3d; /// /// Set true for indices out of area of interest @@ -62,7 +64,7 @@ void set_skip_for_out_of_aoi(std::vector &skip_indicies, /// projection direction [in DEG] void set_skip_by_angle(std::vector &skip_indicies, const indexed_triangle_set &its, - const Project3f &projection, + const Project3d &projection, double max_angle = 89.); @@ -99,6 +101,9 @@ CutMesh to_cgal(const indexed_triangle_set &its, /// Define transformation 2d point into 3d /// CGAL model of extruded shape CutMesh to_cgal(const ExPolygons &shapes, const Project &projection); +// function to check result of projection. 2d int32_t -> 3d double +bool exist_duplicit_vertex(const CutMesh& mesh); + /// /// IntersectingElement @@ -186,19 +191,6 @@ const std::string face_shape_map_name = "f:IntersectingElement"; // stored in surface source const std::string vert_shape_map_name = "v:IntersectingElement"; -/// -/// Identify contour (or hole) point from ExPolygons -/// -struct ShapePointId -{ - // index of ExPolygons - uint32_t expolygons_index; - // index of Polygon - uint32_t polygon_index; - // index of point in polygon - uint32_t point_index; -}; - /// /// Flag for faces in CGAL mesh /// @@ -252,24 +244,6 @@ using CutAOIs = std::vector; // vector of CutAOIs for each model using VCutAOIs = std::vector; -/// -/// Keep conversion from ShapePointId to Index and vice versa -/// ShapePoint .. contour(or hole) poin from ExPolygons -/// Index .. continous number -/// -class ShapePoint2index -{ - std::vector> m_offsets; - // for check range of index - uint32_t m_count; - -public: - ShapePoint2index(const ExPolygons &shapes); - uint32_t calc_index(const ShapePointId &id) const; - ShapePointId calc_id(uint32_t index) const; - uint32_t get_count() const; -}; - /// /// Create AOIs(area of interest) on model surface /// @@ -286,7 +260,7 @@ CutAOIs cut_from_model(CutMesh &cgal_model, const ExPolygons &shapes, /*const*/ CutMesh &cgal_shape, float projection_ratio, - const ShapePoint2index &s2i); + const ExPolygonsIndices &s2i); using Loop = std::vector; using Loops = std::vector; @@ -371,7 +345,7 @@ public: SurfacePatches diff_models(VCutAOIs &cuts, /*const*/ CutMeshes &cut_models, /*const*/ CutMeshes &models, - const Project3f &projection); + const Project3d &projection); /// /// Checking whether patch is uninterrupted cover of whole expolygon it belongs. @@ -394,8 +368,21 @@ bool is_over_whole_expoly(const SurfacePatch &patch, const ExPolygons &shapes, const VCutAOIs &cutAOIs, const CutMeshes &meshes); +/// +/// Unptoject points from outline loops of patch +/// +/// Contain loops and vertices +/// Know how to project from 3d to 2d +/// Unprojected points in loops +Polygons unproject_loops(const SurfacePatch &patch, const Project &projection); -ExPolygon to_expoly(const SurfacePatch &patch, const Project &unproject); +/// +/// Unproject points from loops and create expolygons +/// +/// +/// Convert 3d point to 2d +/// +ExPolygon to_expoly(const SurfacePatch &patch, const Project &projection); /// /// To select surface near projection distance @@ -414,7 +401,7 @@ struct ProjectionDistance // signed distance to projection float distance = std::numeric_limits::max(); }; -// addresed by ShapePoint2index +// addresed by ExPolygonsIndices using ProjectionDistances = std::vector; // each point in shapes has its ProjectionDistances @@ -437,43 +424,52 @@ VDistances calc_distances(const SurfacePatches &patches, size_t count_shapes_points, float projection_ratio); -/// -/// Fill area of expolygons by patches -/// Not used patches are discarded(removed from vector) -/// -/// In/Out parts of surface to be filtered -/// Depth distances for outline points -/// Shapes to be filled by patches -/// Starting point for select correct depth -/// Help struct to address point inside of shapes by one index -void filter_patches(SurfacePatches &patches, - const VDistances &distances, - const ExPolygons &shapes, - const Point ¢er, - const ShapePoint2index &s2i); - /// /// Select distances in similar depth between expolygons /// /// All distances - Vector distances for each shape point /// Vector of letters -/// Center of projection -/// Convert index to addresss inside of shape -/// Best projection distances +/// Pivot for start projection in 2d +/// Convert index to addresss inside of shape +/// Cutted parts from surface +/// Closest distance projection indexed by points in shapes(see s2i) ProjectionDistances choose_best_distance( const VDistances &distances, const ExPolygons &shapes, - const Point ¢er, - const ShapePoint2index &shape_point_2_index); + const Point &start, + const ExPolygonsIndices &s2i, + const SurfacePatches &patches); /// /// Create mask for patches /// -/// -/// +/// For each point selected closest distance +/// All patches +/// All patches /// Mask of used patch std::vector select_patches(const ProjectionDistances &best_distances, - const SurfacePatches &patches); + const SurfacePatches &patches, + + const ExPolygons &shapes, + const ExPolygonsIndices &s2i, + const VCutAOIs &cutAOIs, + const CutMeshes &meshes, + const Project &projection); + +/// +/// Merge two surface cuts together +/// Added surface cut will be consumed +/// +/// Surface cut to extend +/// Surface cut to consume +void append(SurfaceCut &sc, SurfaceCut &&sc_add); + +/// +/// Convert patch to indexed_triangle_set +/// +/// Part of surface +/// Converted patch +SurfaceCut patch2cut(SurfacePatch &patch); /// /// Merge masked patches to one surface cut @@ -495,11 +491,12 @@ void initialize_store(const std::string& dir_to_clear); /// Color source /// File to store void store(const CutMesh &mesh, const FaceTypeMap &face_type_map, const std::string &dir, bool is_filled = false); +void store(const ExPolygons &shapes, const std::string &svg_file); void store(const CutMesh &mesh, const ReductionMap &reduction_map, const std::string &dir); void store(const CutAOIs &aois, const CutMesh &mesh, const std::string &dir); void store(const SurfacePatches &patches, const std::string &dir); void store(const Vec3f &vertex, const Vec3f &normal, const std::string &file, float size = 2.f); -void store(const ProjectionDistances &pds, const VCutAOIs &aois, const CutMeshes &meshes, const std::string &file, float width = 0.2f/* [in mm] */); +//void store(const ProjectionDistances &pds, const VCutAOIs &aois, const CutMeshes &meshes, const std::string &file, float width = 0.2f/* [in mm] */); void store(const ExPolygons& shapes, const std::vector& mask_distances, const std::vector>& connections, const std::string& file_svg); void store(const SurfaceCut &cut, const std::string &file, const std::string &contour_dir); void store(const std::vector &models, const std::string &obj_filename); @@ -508,7 +505,10 @@ void store(const Emboss::IProjection &projection, const Point &point_to_project, #endif // DEBUG_OUTPUT_DIR } // namespace privat +#ifdef DEBUG_OUTPUT_DIR #include "libslic3r/SVG.hpp" +#include +#endif // DEBUG_OUTPUT_DIR SurfaceCut Slic3r::cut_surface(const ExPolygons &shapes, const std::vector &models, @@ -522,6 +522,7 @@ SurfaceCut Slic3r::cut_surface(const ExPolygons &shapes, #ifdef DEBUG_OUTPUT_DIR priv::initialize_store(DEBUG_OUTPUT_DIR); priv::store(models, DEBUG_OUTPUT_DIR + "models_input.obj"); + priv::store(shapes, DEBUG_OUTPUT_DIR + "shapes.svg"); #endif // DEBUG_OUTPUT_DIR // for filter out triangles out of bounding box @@ -556,9 +557,9 @@ SurfaceCut Slic3r::cut_surface(const ExPolygons &shapes, #ifdef DEBUG_OUTPUT_DIR CGAL::IO::write_OFF(DEBUG_OUTPUT_DIR + "shape.off", cgal_shape); // only debug #endif // DEBUG_OUTPUT_DIR - + // create tool for convert index to shape Point adress and vice versa - priv::ShapePoint2index s2i(shapes); + ExPolygonsIndices s2i(shapes); priv::VCutAOIs model_cuts; // cut shape from each cgal model for (priv::CutMesh &cgal_model : cgal_models) { @@ -580,7 +581,7 @@ SurfaceCut Slic3r::cut_surface(const ExPolygons &shapes, // fix - convert shape_point_id to expolygon index // save 1 param(s2i) from diff_models call for (priv::SurfacePatch &patch : patches) - patch.shape_id = s2i.calc_id(patch.shape_id).expolygons_index; + patch.shape_id = s2i.cvt(patch.shape_id).expolygons_index; //// Only for create function //std::vector is_filling; @@ -605,15 +606,21 @@ SurfaceCut Slic3r::cut_surface(const ExPolygons &shapes, uint32_t shapes_points = s2i.get_count(); // for each point collect all projection distances priv::VDistances distances = priv::calc_distances(patches, cgal_models, cgal_shape, shapes_points, projection_ratio); + + Point start = shapes_bb.center(); // only align center + + //SurfaceCut result; + //for (priv::SurfacePatch &patch : patches) + // priv::append(result, priv::patch2cut(patch)); - //assert(shapes_bb.center().x() == 0 && shapes_bb.center().y() == 0); - //Point start = shapes_bb.center(); - //priv::filter_patches(patches, distances, shapes, start, s2i); - + // Use only outline points // for each point select best projection - priv::ProjectionDistances best_projection = priv::choose_best_distance(distances, shapes, shapes_bb.center(), s2i); - std::vector use_patch = priv::select_patches(best_projection, patches); + priv::ProjectionDistances best_projection = priv::choose_best_distance(distances, shapes, start, s2i, patches); + std::vector use_patch = priv::select_patches(best_projection, patches, + shapes, s2i,model_cuts, cgal_models, projection); SurfaceCut result = merge_patches(patches, use_patch); + //*/ + #ifdef DEBUG_OUTPUT_DIR priv::store(result, DEBUG_OUTPUT_DIR + "result.obj", DEBUG_OUTPUT_DIR + "result_contours/"); #endif // DEBUG_OUTPUT_DIR @@ -621,7 +628,7 @@ SurfaceCut Slic3r::cut_surface(const ExPolygons &shapes, } indexed_triangle_set Slic3r::cut2model(const SurfaceCut &cut, - const Emboss::IProject3f &projection) + const Emboss::IProject3d &projection) { assert(!cut.empty()); size_t count_vertices = cut.vertices.size() * 2; @@ -644,9 +651,10 @@ indexed_triangle_set Slic3r::cut2model(const SurfaceCut &cut, cut.indices.begin(), cut.indices.end()); // back - for (const auto &v : cut.vertices) { - Vec3f v2 = projection.project(v); - result.vertices.push_back(v2); + for (const Vec3f &v : cut.vertices) { + Vec3d vd = v.cast(); + Vec3d vd2 = projection.project(vd); + result.vertices.push_back(vd2.cast()); } size_t back_offset = cut.vertices.size(); @@ -744,7 +752,7 @@ void priv::set_skip_for_out_of_aoi(std::vector &skip_indicies, // | |/ // 0 *----* 3 ////////////////// - std::array, 4> bb; + std::array, 4> bb; int index = 0; for (Point v : {shapes_bb.min, Point{shapes_bb.min.x(), shapes_bb.max.y()}, @@ -760,20 +768,20 @@ void priv::set_skip_for_out_of_aoi(std::vector &skip_indicies, // plane is defined by point and normal PointNormals point_normals; for (size_t i = 0; i < 4; i++) { - const Vec3f &p1 = bb[i].first; - const Vec3f &p2 = bb[i].second; - const Vec3f &p3 = bb[prev_i].first; + const Vec3d &p1 = bb[i].first; + const Vec3d &p2 = bb[i].second; + const Vec3d &p3 = bb[prev_i].first; prev_i = i; - Vec3d v1 = (p2 - p1).cast(); + Vec3d v1 = p2 - p1; v1.normalize(); - Vec3d v2 = (p3 - p1).cast(); + Vec3d v2 = p3 - p1; v2.normalize(); Vec3d normal = v2.cross(v1); normal.normalize(); - point_normals[i] = {p1.cast(), normal}; + point_normals[i] = {p1, normal}; } // same meaning as point normal IsOnSides is_on_sides(its.vertices.size(), {false,false,false,false}); @@ -865,7 +873,7 @@ indexed_triangle_set Slic3r::its_cut_AoI(const indexed_triangle_set &its, void priv::set_skip_by_angle(std::vector &skip_indicies, const indexed_triangle_set &its, - const Project3f &projection, + const Project3d &projection, double max_angle) { assert(max_angle < 90. && max_angle > 89.); @@ -875,9 +883,11 @@ void priv::set_skip_by_angle(std::vector &skip_indicies, size_t index = &face - &its.indices.front(); if (skip_indicies[index]) continue; Vec3f n = its_face_normal(its, face); - const Vec3f v = its.vertices[face[0]]; + const Vec3f& v = its.vertices[face[0]]; + const Vec3d vd = v.cast(); // Improve: For Orthogonal Projection it is same for each vertex - Vec3f projected = projection.project(v); + Vec3d projectedd = projection.project(vd); + Vec3f projected = projectedd.cast(); Vec3f project_dir = projected - v; project_dir.normalize(); float cos_alpha = project_dir.dot(n); @@ -959,6 +969,26 @@ priv::CutMesh priv::to_cgal(const indexed_triangle_set &its, return result; } +bool priv::exist_duplicit_vertex(const CutMesh &mesh) { + std::vector points; + points.reserve(mesh.vertices().size()); + // copy points + for (VI vi : mesh.vertices()) { + const P3 &p = mesh.point(vi); + points.emplace_back(p.x(), p.y(), p.z()); + } + std::sort(points.begin(), points.end(), [](const Vec3d &v1, const Vec3d &v2) { + return v1.x() < v2.x() || + (v1.x() == v2.x() && + (v1.y() < v2.y() || + (v1.y() == v2.y() && + v1.z() < v2.z()))); + }); + // find first duplicit + auto it = std::adjacent_find(points.begin(), points.end()); + return it != points.end(); +} + priv::CutMesh priv::to_cgal(const ExPolygons &shapes, const Project &projection) { @@ -1028,67 +1058,10 @@ priv::CutMesh priv::to_cgal(const ExPolygons &shapes, for (const Polygon &hole : shape.holes) insert_contour(hole); } + assert(!exist_duplicit_point(result)); return result; } -priv::ShapePoint2index::ShapePoint2index(const ExPolygons &shapes) -{ - // prepare offsets - m_offsets.reserve(shapes.size()); - uint32_t offset = 0; - for (const auto &shape : shapes) { - assert(!shape.contour.points.empty()); - std::vector shape_offsets(shape.holes.size() + 1); - - shape_offsets[0] = offset; - offset += shape.contour.points.size(); - - for (uint32_t i = 0; i < shape.holes.size(); i++) { - shape_offsets[i + 1] = offset; - offset += shape.holes[i].points.size(); - } - m_offsets.push_back(std::move(shape_offsets)); - } - m_count = offset; -} - -uint32_t priv::ShapePoint2index::calc_index(const ShapePointId &id) const -{ - assert(id.expolygons_index < m_offsets.size()); - const std::vector &shape_offset = m_offsets[id.expolygons_index]; - assert(id.polygon_index < shape_offset.size()); - uint32_t res = shape_offset[id.polygon_index] + id.point_index; - assert(res < m_count); - return res; -} - -priv::ShapePointId priv::ShapePoint2index::calc_id(uint32_t index) const -{ - assert(index < m_count); - ShapePointId result{0,0,0}; - // find shape index - for (size_t i = 1; i < m_offsets.size(); i++) { - if (m_offsets[i][0] > index) break; - result.expolygons_index = i; - } - - // find contour index - const std::vector &shape_offset = - m_offsets[result.expolygons_index]; - for (size_t i = 1; i < shape_offset.size(); i++) { - if (shape_offset[i] > index) break; - result.polygon_index = i; - } - - // calculate point index - uint32_t polygon_offset = shape_offset[result.polygon_index]; - assert(index >= polygon_offset); - result.point_index = index - polygon_offset; - return result; -} - -uint32_t priv::ShapePoint2index::get_count() const { return m_count; } - priv::ModelCut2index::ModelCut2index(const VCutAOIs &cuts) { // prepare offsets @@ -1219,7 +1192,7 @@ bool is_face_inside(HI hi, const CutMesh &mesh, const CutMesh &shape_mesh, const VertexShapeMap &vertex_shape_map, - const ShapePoint2index &shape2index); + const ExPolygonsIndices &shape2index); /// /// Face with constrained edge are inside/outside by type of intersection @@ -1236,7 +1209,7 @@ void set_face_type(FaceTypeMap &face_type_map, const VertexShapeMap &vertex_shape_map, const EdgeBoolMap &ecm, const CutMesh &shape_mesh, - const ShapePoint2index &shape2index); + const ExPolygonsIndices &shape2index); /// /// Change FaceType from not_constrained to inside @@ -1315,6 +1288,8 @@ void priv::Visitor::intersection_point_detected(std::size_t i_id, assert(&tm_f == &shape && &tm_e == &object); assert(!is_target_coplanar); assert(!is_source_coplanar); + if (is_target_coplanar || is_source_coplanar) + *is_valid = false; intersection_ptr = &edge_shape_map[shape.edge(h_f)]; if (sdim == 0) vert_shape_map[object.target(h_e)] = intersection_ptr; } @@ -1343,7 +1318,7 @@ bool priv::is_face_inside(HI hi, const CutMesh &mesh, const CutMesh &shape_mesh, const VertexShapeMap &vertex_shape_map, - const ShapePoint2index &shape2index) + const ExPolygonsIndices &shape2index) { VI vi_from = mesh.source(hi); VI vi_to = mesh.target(hi); @@ -1370,9 +1345,9 @@ bool priv::is_face_inside(HI hi, // j is next contour point in vertices uint32_t j = i + 2; if (shape_from.is_last()) { - ShapePointId point_id = shape2index.calc_id(i_from); + ExPolygonsIndex point_id = shape2index.cvt(i_from); point_id.point_index = 0; - j = shape2index.calc_index(point_id)*2; + j = shape2index.cvt(point_id)*2; } // opposit point(in triangle face) to edge @@ -1410,7 +1385,7 @@ void priv::set_face_type(FaceTypeMap &face_type_map, const VertexShapeMap &vertex_shape_map, const EdgeBoolMap &ecm, const CutMesh &shape_mesh, - const ShapePoint2index &shape2index) + const ExPolygonsIndices &shape2index) { for (EI ei : mesh.edges()) { if (!ecm[ei]) continue; @@ -1432,7 +1407,7 @@ priv::CutAOIs priv::cut_from_model(CutMesh &cgal_model, const ExPolygons &shapes, CutMesh &cgal_shape, float projection_ratio, - const ShapePoint2index &s2i) + const ExPolygonsIndices &s2i) { // pointer to edge or face shape_map VertexShapeMap vert_shape_map = cgal_model.add_property_map(vert_shape_map_name, nullptr).first; @@ -1787,24 +1762,25 @@ AABBTreeIndirect::Tree<2, double> tree; }; SearchData create_search_data(const ExPolygons &shapes, const std::vector& mask); -uint32_t get_closest_point_index(const SearchData &sd, size_t line_idx, const Vec2d &hit_point, const ExPolygons &shapes, const ShapePoint2index &s2i); +uint32_t get_closest_point_index(const SearchData &sd, size_t line_idx, const Vec2d &hit_point, const ExPolygons &shapes, const ExPolygonsIndices &s2i); // use AABB Tree Lines to find closest point -uint32_t find_closest_point_index(const Point &p, const ExPolygons &shapes, const ShapePoint2index &s2i, const std::vector &mask); +uint32_t find_closest_point_index(const Point &p, const ExPolygons &shapes, const ExPolygonsIndices &s2i, const std::vector &mask); -std::pair find_closest_point_pair(const ExPolygons &shapes, const std::vector &done_shapes, const ShapePoint2index &s2i, const std::vector &mask); +std::pair find_closest_point_pair(const ExPolygons &shapes, const std::vector &done_shapes, const ExPolygonsIndices &s2i, const std::vector &mask); // Search for closest projection to wanted distance const ProjectionDistance *get_closest_projection(const ProjectionDistances &distance, float wanted_distance); // fill result around known index inside one polygon -void fill_polygon_distances(const ProjectionDistance &pd, uint32_t index, const ShapePointId &id, ProjectionDistances & result, const ExPolygons &shapes, const VDistances &distances); +void fill_polygon_distances(const ProjectionDistance &pd, uint32_t index, const ExPolygonsIndex &id, ProjectionDistances & result, const ExPolygon &shape, const VDistances &distances); +// search for closest projection for expolygon // choose correct cut by source point -void fill_shape_distances(uint32_t known_point, const ProjectionDistance &pd, ProjectionDistances &result, std::vector& finished_shapes, const ShapePoint2index &s2i, const ExPolygons &shapes, const VDistances &distances); +void fill_shape_distances(uint32_t start_index, const ProjectionDistance *start_pd, ProjectionDistances &result, const ExPolygonsIndices &s2i, const ExPolygon &shape, const VDistances &distances); // find close points between finished and unfinished ExPolygons -ClosePoint find_close_point(const Point &p, ProjectionDistances &result, std::vector& finished_shapes,const ShapePoint2index &s2i, const ExPolygons &shapes); +ClosePoint find_close_point(const Point &p, ProjectionDistances &result, std::vector& finished_shapes,const ExPolygonsIndices &s2i, const ExPolygons &shapes); } @@ -1853,7 +1829,7 @@ uint32_t priv::get_closest_point_index(const SearchData &sd, size_t line_idx, const Vec2d &hit_point, const ExPolygons &shapes, - const ShapePoint2index &s2i) + const ExPolygonsIndices &s2i) { const Linef &line = sd.lines[line_idx]; Vec2d dir = line.a - line.b; @@ -1868,7 +1844,7 @@ uint32_t priv::get_closest_point_index(const SearchData &sd, // Lambda used only for check result [[maybe_unused]] auto is_same = [&s2i, &shapes] (const Vec2d &p, size_t i) -> bool { - auto id = s2i.calc_id(i); + auto id = s2i.cvt(i); const ExPolygon &shape = shapes[id.expolygons_index]; const Polygon &poly = (id.polygon_index == 0) ? shape.contour : @@ -1881,7 +1857,7 @@ uint32_t priv::get_closest_point_index(const SearchData &sd, assert(is_same(line.b, point_index)); return point_index; } - auto id = s2i.calc_id(point_index); + auto id = s2i.cvt(point_index); if (id.point_index != 0) { assert(is_same(line.a, point_index - 1)); return point_index - 1; @@ -1899,7 +1875,7 @@ uint32_t priv::get_closest_point_index(const SearchData &sd, // use AABB Tree Lines uint32_t priv::find_closest_point_index(const Point &p, const ExPolygons &shapes, - const ShapePoint2index &s2i, + const ExPolygonsIndices &s2i, const std::vector &mask) { SearchData sd = create_search_data(shapes, mask); @@ -1918,7 +1894,7 @@ uint32_t priv::find_closest_point_index(const Point &p, std::pair priv::find_closest_point_pair( const ExPolygons &shapes, const std::vector &done_shapes, - const ShapePoint2index &s2i, + const ExPolygonsIndices &s2i, const std::vector &mask) { assert(mask.size() == s2i.get_count()); @@ -1962,8 +1938,9 @@ std::pair priv::find_closest_point_pair( Vec2d hit_point; double distance_sq = AABBTreeLines::squared_distance_to_indexed_lines( sd.lines, sd.tree, p_d, line_idx, hit_point, cp.distance_sq); - if (distance_sq < 0) continue; - assert(distance_sq <= cp.distance_sq); + if (distance_sq < 0 || + distance_sq >= cp.distance_sq) continue; + assert(line_idx < sd.lines.size()); cp.distance_sq = distance_sq; cp.unfinished_line_idx = line_idx; cp.hit_point = hit_point; @@ -2004,13 +1981,12 @@ const priv::ProjectionDistance *priv::get_closest_projection( void priv::fill_polygon_distances(const ProjectionDistance &pd, uint32_t index, - const ShapePointId &id, + const ExPolygonsIndex &id, ProjectionDistances &result, - const ExPolygons &shapes, + const ExPolygon &shape, const VDistances &distances) { - const ExPolygon &shape = shapes[id.expolygons_index]; - const Points & points = (id.polygon_index == 0) ? + const Points& points = (id.polygon_index == 0) ? shape.contour.points : shape.holes[id.polygon_index - 1].points; // border of indexes for Polygon @@ -2069,21 +2045,18 @@ void priv::fill_polygon_distances(const ProjectionDistance &pd, } while (true); } -void priv::fill_shape_distances(uint32_t known_point, - const ProjectionDistance &pd, +// IMPROVE: when select distance fill in all distances from Patch +void priv::fill_shape_distances(uint32_t start_index, + const ProjectionDistance *start_pd, ProjectionDistances &result, - std::vector &finished_shapes, - const ShapePoint2index &s2i, - const ExPolygons &shapes, + const ExPolygonsIndices &s2i, + const ExPolygon &shape, const VDistances &distances) { - const ProjectionDistance *start_pd = &pd; - uint32_t start_index = known_point; - uint32_t expolygons_index = s2i.calc_id(known_point).expolygons_index; - uint32_t first_shape_index = s2i.calc_index({expolygons_index, 0, 0}); - const ExPolygon &shape = shapes[expolygons_index]; + uint32_t expolygons_index = s2i.cvt(start_index).expolygons_index; + uint32_t first_shape_index = s2i.cvt({expolygons_index, 0, 0}); do { - fill_polygon_distances(*start_pd, start_index, s2i.calc_id(start_index),result, shapes, distances); + fill_polygon_distances(*start_pd, start_index, s2i.cvt(start_index),result, shape, distances); // seaching only inside shape, return index of closed finished point auto find_close_finished_point = [&first_shape_index, &shape, &result] (const Point &p) -> ClosePoint { @@ -2143,13 +2116,12 @@ void priv::fill_shape_distances(uint32_t known_point, for (const Polygon &h : shape.holes) check_unfinished_points(h.points); } while (start_index != std::numeric_limits::max()); - finished_shapes[expolygons_index] = true; } priv::ClosePoint priv::find_close_point(const Point &p, ProjectionDistances &result, std::vector &finished_shapes, - const ShapePoint2index &s2i, + const ExPolygonsIndices &s2i, const ExPolygons &shapes) { // result @@ -2158,7 +2130,7 @@ priv::ClosePoint priv::find_close_point(const Point &p, for (uint32_t shape_index = 0; shape_index < shapes.size(); ++shape_index) { if (!finished_shapes[shape_index]) continue; const ExPolygon &shape = shapes[shape_index]; - uint32_t index = s2i.calc_index({shape_index, 0, 0}); + uint32_t index = s2i.cvt({shape_index, 0, 0}); auto find_close_point_in_points = [&p, &cp, &index, &result] (const Points &pts){ for (const Point &p_ : pts) { @@ -2184,79 +2156,17 @@ priv::ClosePoint priv::find_close_point(const Point &p, return cp; } -void priv::filter_patches(SurfacePatches &patches, - const VDistances &distances, - const ExPolygons &shapes, - const Point ¢er, - const ShapePoint2index &s2i) +// IMPROVE: when select distance fill in all distances from Patch +priv::ProjectionDistances priv::choose_best_distance( + const VDistances &distances, const ExPolygons &shapes, const Point &start, const ExPolygonsIndices &s2i, const SurfacePatches &patches) { assert(distances.size() == count_points(shapes)); - // collect closest projection for source shape point(outline point) - ProjectionDistances closest(distances.size()); - // store info about finished shapes - std::vector finished_shapes(shapes.size(), {false}); - - // wanted distance from ideal projection - // Distances are relative to projection distance - // so first wanted distance is the closest one (ZERO) - float wanted_distance = 0.f; - - // For each shape point flag wether exist some distance. - std::vector mask_distances(s2i.get_count(), {true}); - for (const auto &d : distances) - if (d.empty()) mask_distances[&d - &distances.front()] = false; + // vector of patches for shape + std::vector> shapes_patches(shapes.size()); + for (const SurfacePatch &patch : patches) + shapes_patches[patch.shape_id].push_back(&patch-&patches.front()); - // Select point from shapes(text contour) which is closest to center (all in 2d) - uint32_t unfinished_index = find_closest_point_index(center, shapes, s2i, mask_distances); - -#ifdef DEBUG_OUTPUT_DIR - std::vector> connections; - connections.reserve(shapes.size()); - connections.emplace_back(unfinished_index, unfinished_index); -#endif // DEBUG_OUTPUT_DIR - - do { - const ProjectionDistance* pd = get_closest_projection(distances[unfinished_index], wanted_distance); - // selection of closest_id should proove that pd has value - // (functions: get_closest_point_index and find_close_point_in_points) - assert(pd != nullptr); - fill_shape_distances(unfinished_index, *pd, closest, finished_shapes, s2i, shapes, distances); - - // The most close points between finished and unfinished shapes - auto [finished, unfinished] = find_closest_point_pair( - shapes, finished_shapes, s2i, mask_distances); - - // detection of end (best doesn't have value) - if (finished == std::numeric_limits::max()) break; - - assert(unfinished != std::numeric_limits::max()); - const ProjectionDistance &closest_pd = closest[finished]; - // check that best_cp is finished and has result - assert(closest_pd.aoi_index != std::numeric_limits::max()); - wanted_distance = closest_pd.distance; - unfinished_index = unfinished; - -#ifdef DEBUG_OUTPUT_DIR - connections.emplace_back(finished, unfinished); -#endif // DEBUG_OUTPUT_DIR - } while (true); //(unfinished_index != std::numeric_limits::max()); -#ifdef DEBUG_OUTPUT_DIR - store(shapes, mask_distances, connections, DEBUG_OUTPUT_DIR + "closest_points.svg"); -#endif // DEBUG_OUTPUT_DIR - - - - -} - -// IMPROVE2: when select distance fill in all distances from Patch -priv::ProjectionDistances priv::choose_best_distance( - const VDistances &distances, - const ExPolygons &shapes, - const Point ¢er, - const ShapePoint2index &s2i) -{ // collect one closest projection for each outline point ProjectionDistances result(distances.size()); @@ -2273,7 +2183,7 @@ priv::ProjectionDistances priv::choose_best_distance( if (d.empty()) mask_distances[&d - &distances.front()] = false; // Select point from shapes(text contour) which is closest to center (all in 2d) - uint32_t unfinished_index = find_closest_point_index(center, shapes, s2i, mask_distances); + uint32_t unfinished_index = find_closest_point_index(start, shapes, s2i, mask_distances); #ifdef DEBUG_OUTPUT_DIR std::vector> connections; @@ -2286,8 +2196,42 @@ priv::ProjectionDistances priv::choose_best_distance( // selection of closest_id should proove that pd has value // (functions: get_closest_point_index and find_close_point_in_points) assert(pd != nullptr); - fill_shape_distances(unfinished_index, *pd, result, finished_shapes, s2i, shapes, distances); + uint32_t expolygons_index = s2i.cvt(unfinished_index).expolygons_index; + const ExPolygon &shape = shapes[expolygons_index]; + std::vector &shape_patches = shapes_patches[expolygons_index]; + if (shape_patches.size() == 1){ + // Speed up, only one patch so copy distance from patch + uint32_t first_shape_index = s2i.cvt({expolygons_index, 0, 0}); + uint32_t laset_shape_index = first_shape_index + count_points(shape); + for (uint32_t i = first_shape_index; i < laset_shape_index; ++i) { + const ProjectionDistances &pds = distances[i]; + if (pds.empty()) continue; + // check that index belongs to patch + assert(pds.front().patch_index == shape_patches.front()); + result[i] = pds.front(); + if (pds.size() == 1) continue; + float relative_distance = fabs(result[i].distance - pd->distance); + // patch could contain multiple value for one outline point + // so choose closest to start point + for (uint32_t pds_index = 1; pds_index < pds.size(); ++pds_index) { + // check that index still belongs to same patch + assert(pds[pds_index].patch_index == shape_patches.front()); + float relative_distance2 = fabs(pds[pds_index].distance - pd->distance); + if (relative_distance > relative_distance2) { + relative_distance = relative_distance2; + result[i] = pds[pds_index]; + } + } + } + } else { + // multiple patches for expolygon + // check that exist patch to fill shape + assert(!shape_patches.empty()); + fill_shape_distances(unfinished_index, pd, result, s2i, shape, distances); + } + + finished_shapes[expolygons_index] = true; // The most close points between finished and unfinished shapes auto [finished, unfinished] = find_closest_point_pair( shapes, finished_shapes, s2i, mask_distances); @@ -2786,7 +2730,7 @@ bool has_bb_intersection(const BoundingBoxf3 &bb, /// otherwise FALSE bool is_patch_inside_of_model(const SurfacePatch &patch, const Tree &tree, - const Project3f &projection); + const Project3d &projection); /// /// Return some shape point index which identify shape @@ -2875,12 +2819,12 @@ bool priv::has_bb_intersection(const BoundingBoxf3 &bb, bool priv::is_patch_inside_of_model(const SurfacePatch &patch, const Tree &tree, - const Project3f &projection) + const Project3d &projection) { // TODO: Solve model with hole in projection direction !!! const P3 &a = patch.mesh.point(VI(0)); - Vec3f a_(a.x(), a.y(), a.z()); - Vec3f b_ = projection.project(a_); + Vec3d a_(a.x(), a.y(), a.z()); + Vec3d b_ = projection.project(a_); P3 b(b_.x(), b_.y(), b_.z()); Ray ray_query(a, b); @@ -3026,7 +2970,7 @@ void priv::collect_open_edges(SurfacePatches &patches) { priv::SurfacePatches priv::diff_models(VCutAOIs &cuts, /*const*/ CutMeshes &cut_models, /*const*/ CutMeshes &models, - const Project3f &projection) + const Project3d &projection) { // IMPROVE: when models contain ONE mesh. It is only about convert cuts to patches // and reduce unneccessary triangles on contour @@ -3215,16 +3159,99 @@ bool priv::is_over_whole_expoly(const CutAOI &cutAOI, return true; } -std::vector priv::select_patches( - const ProjectionDistances &best_distances, - const SurfacePatches &patches) +std::vector priv::select_patches(const ProjectionDistances &best_distances, + const SurfacePatches &patches, + + const ExPolygons &shapes, + const ExPolygonsIndices &s2i, + const VCutAOIs &cutAOIs, + const CutMeshes &meshes, + const Project &projection) { + // extension to cover numerical mistake made by back projection patch from 3d to 2d + const float extend_delta = 5.f / Emboss::SHAPE_SCALE; // [Font points scaled by Emboss::SHAPE_SCALE] + + // vector of patches for shape + std::vector> used_shapes_patches(shapes.size()); std::vector in_distances(patches.size(), {false}); for (const ProjectionDistance &d : best_distances) { // exist valid projection for shape point? if (d.patch_index == std::numeric_limits::max()) continue; + if (in_distances[d.patch_index]) continue; in_distances[d.patch_index] = true; + + ExPolygonsIndex id = s2i.cvt(&d - &best_distances.front()); + used_shapes_patches[id.expolygons_index].push_back(d.patch_index); } + + // vector of patches for shape + std::vector> shapes_patches(shapes.size()); + for (const SurfacePatch &patch : patches) + shapes_patches[patch.shape_id].push_back(&patch - &patches.front()); + + for (size_t shape_index = 0; shape_index < shapes.size(); shape_index++) + { + const ExPolygon &shape = shapes[shape_index]; + const std::vector &used_shape_patches = used_shapes_patches[shape_index]; + if (used_shape_patches.empty()) continue; + if (used_shape_patches.size() == 1) { + uint32_t patch_index = used_shape_patches.front(); + const SurfacePatch &patch = patches[patch_index]; + if (is_over_whole_expoly(patch, shapes, cutAOIs, meshes)) continue; + } + + // only shapes contain multiple patches + // or not full filled are hard processed + + // convert patch to 2d + ExPolygons fill; + fill.reserve(used_shape_patches.size()); + for (uint32_t patch_index : used_shape_patches) { + ExPolygon patch_area = to_expoly(patches[patch_index], projection); + //*/ + // add save offset extension to cover numerical mistake made by back projection to 2d + const float extend_delta = 5.f; + ExPolygons patch_areas = offset_ex(patch_area, extend_delta); + fill.insert(fill.end(), patch_areas.begin(), patch_areas.end()); + /*/ + // without save extension + fill.push_back(patch_area); + //*/ + } + ExPolygons rest = diff_ex(ExPolygons{shape}, fill, ApplySafetyOffset::Yes); + if (rest.empty()) continue; + + // find patches overlaed rest area + fill = union_ex(fill); + struct PatchShape{ + uint32_t patch_index; + ExPolygon shape; + ExPolygons intersection; + }; + using PatchShapes = std::vector; + PatchShapes patch_shapes; + for (uint32_t patch_index : shapes_patches[shape_index]) { + // check is patch already used + auto it = std::lower_bound(used_shape_patches.begin(), used_shape_patches.end(), patch_index); + if (it != used_shape_patches.end() && *it == patch_index) continue; + ExPolygon patch_shape = to_expoly(patches[patch_index], projection); + ExPolygons patch_intersection = intersection_ex(ExPolygons{patch_shape}, rest); + if (patch_intersection.empty()) continue; + + patch_shapes.push_back({patch_index, patch_shape, patch_intersection}); + } + + // how to select which patch to use + // + // by depth: + // how to calc wanted depth - idealy by depth of hole outline points + // + // how to calc patch depth - by average outline depth + + + } + + // For sure of the bounding boxes intersection const double bb_extension = 1e-10; const Vec3d bb_ext(bb_extension, bb_extension, bb_extension); @@ -3276,16 +3303,6 @@ std::vector priv::select_patches( return result; } -// help function to 'merge_patches' -namespace priv { -/// -/// Convert patch to indexed_triangle_set -/// -/// Part of surface -/// Converted patch -SurfaceCut patch2cut(SurfacePatch &patch); -} // namespace priv - priv::Loops priv::create_loops(const std::vector &outlines, const CutMesh& mesh) { Loops loops; @@ -3349,8 +3366,7 @@ priv::Loops priv::create_loops(const std::vector &outlines, const CutMesh& m return loops; } -#include "ClipperUtils.hpp" -ExPolygon priv::to_expoly(const SurfacePatch &patch, const Project &project) +Polygons priv::unproject_loops(const SurfacePatch &patch, const Project &projection) { assert(!patch.loops.empty()); if (patch.loops.empty()) return {}; @@ -3364,11 +3380,11 @@ ExPolygon priv::to_expoly(const SurfacePatch &patch, const Project &project) for (const Loop &l : patch.loops) { pts.clear(); pts.reserve(l.size()); - for (VI vi : l) { + for (VI vi : l) { const P3 &p3 = patch.mesh.point(vi); - Vec3f p(p3.x(), p3.y(), p3.z()); - std::optional p2_opt = project.unproject(p); - + Vec3d p(p3.x(), p3.y(), p3.z()); + std::optional p2_opt = projection.unproject(p); + // Check when appear that skip is enough for poit which can't be unprojected // - it could break contour assert(p2_opt.has_value()); @@ -3384,13 +3400,17 @@ ExPolygon priv::to_expoly(const SurfacePatch &patch, const Project &project) } assert(!polys.empty()); - if (polys.empty()) return {}; - - ExPolygons expolys = Slic3r::union_ex(polys, ClipperLib::PolyFillType::pftEvenOdd); + return polys; +} +ExPolygon priv::to_expoly(const SurfacePatch &patch, const Project &projection) +{ + Polygons polys = unproject_loops(patch, projection); + // should not be used when no opposit triangle are counted so should not create overlaps + ClipperLib::PolyFillType fill_type = ClipperLib::PolyFillType::pftEvenOdd; + ExPolygons expolys = Slic3r::union_ex(polys, fill_type); assert(expolys.size() == 1); if (expolys.empty()) return {}; - return expolys.front(); } @@ -3448,18 +3468,6 @@ SurfaceCut priv::patch2cut(SurfacePatch &patch) return sc; } -namespace priv { - -/// -/// Merge two surface cuts together -/// Added surface cut will be consumed -/// -/// Surface cut to extend -/// Surface cut to consume -void append(SurfaceCut &sc, SurfaceCut &&sc_add); - -}// namespace priv - void priv::append(SurfaceCut &sc, SurfaceCut &&sc_add) { if (sc.empty()) { @@ -3491,7 +3499,7 @@ SurfaceCut priv::merge_patches(SurfacePatches &patches, const std::vector& } #ifdef DEBUG_OUTPUT_DIR - +#include "libslic3r/SVG.hpp" #include namespace priv{ void prepare_dir(const std::string &dir){ @@ -3578,6 +3586,11 @@ void priv::store(const CutMesh &mesh, const FaceTypeMap &face_type_map, const st mesh_.remove_property_map(face_colors); } +void priv::store(const ExPolygons &shapes, const std::string &svg_file) { + SVG svg(svg_file); + svg.draw(shapes); +} + void priv::store(const CutMesh &mesh, const ReductionMap &reduction_map, const std::string& dir) { if (reduction_order == 0) prepare_dir(dir); @@ -3707,52 +3720,52 @@ void priv::store(const SurfacePatches &patches, const std::string &dir) { CGAL::IO::write_OFF(dir + "patch" + std::to_string(index) + ".off", patch.mesh); } } - -void priv::store(const ProjectionDistances &pds, - const VCutAOIs &aois, - const CutMeshes &meshes, - const std::string &file, - float width) -{ - // create rectangle for each half edge from projection distances - indexed_triangle_set its; - its.vertices.reserve(4 * pds.size()); - its.indices.reserve(2 * pds.size()); - for (const ProjectionDistance &pd : pds) { - if (pd.aoi_index == std::numeric_limits::max()) continue; - HI hi = aois[pd.model_index][pd.aoi_index].second[pd.hi_index]; - const CutMesh &mesh = meshes[pd.model_index]; - VI vi1 = mesh.source(hi); - VI vi2 = mesh.target(hi); - VI vi3 = mesh.target(mesh.next(hi)); - const P3 &p1 = mesh.point(vi1); - const P3 &p2 = mesh.point(vi2); - const P3 &p3 = mesh.point(vi3); - Vec3f v1(p1.x(), p1.y(), p1.z()); - Vec3f v2(p2.x(), p2.y(), p2.z()); - Vec3f v3(p3.x(), p3.y(), p3.z()); - - Vec3f v12 = v2 - v1; - v12.normalize(); - Vec3f v13 = v3 - v1; - v13.normalize(); - Vec3f n = v12.cross(v13); - n.normalize(); - Vec3f side = n.cross(v12); - side.normalize(); - side *= -width; - - uint32_t i = its.vertices.size(); - its.vertices.push_back(v1); - its.vertices.push_back(v1+side); - its.vertices.push_back(v2); - its.vertices.push_back(v2+side); - - its.indices.emplace_back(i, i + 1, i + 2); - its.indices.emplace_back(i + 2, i + 1, i + 3); - } - its_write_obj(its, file.c_str()); -} +// +//void priv::store(const ProjectionDistances &pds, +// const VCutAOIs &aois, +// const CutMeshes &meshes, +// const std::string &file, +// float width) +//{ +// // create rectangle for each half edge from projection distances +// indexed_triangle_set its; +// its.vertices.reserve(4 * pds.size()); +// its.indices.reserve(2 * pds.size()); +// for (const ProjectionDistance &pd : pds) { +// if (pd.aoi_index == std::numeric_limits::max()) continue; +// HI hi = aois[pd.model_index][pd.aoi_index].second[pd.hi_index]; +// const CutMesh &mesh = meshes[pd.model_index]; +// VI vi1 = mesh.source(hi); +// VI vi2 = mesh.target(hi); +// VI vi3 = mesh.target(mesh.next(hi)); +// const P3 &p1 = mesh.point(vi1); +// const P3 &p2 = mesh.point(vi2); +// const P3 &p3 = mesh.point(vi3); +// Vec3f v1(p1.x(), p1.y(), p1.z()); +// Vec3f v2(p2.x(), p2.y(), p2.z()); +// Vec3f v3(p3.x(), p3.y(), p3.z()); +// +// Vec3f v12 = v2 - v1; +// v12.normalize(); +// Vec3f v13 = v3 - v1; +// v13.normalize(); +// Vec3f n = v12.cross(v13); +// n.normalize(); +// Vec3f side = n.cross(v12); +// side.normalize(); +// side *= -width; +// +// uint32_t i = its.vertices.size(); +// its.vertices.push_back(v1); +// its.vertices.push_back(v1+side); +// its.vertices.push_back(v2); +// its.vertices.push_back(v2+side); +// +// its.indices.emplace_back(i, i + 1, i + 2); +// its.indices.emplace_back(i + 2, i + 1, i + 3); +// } +// its_write_obj(its, file.c_str()); +//} #include "SVG.hpp" void priv::store(const ExPolygons &shapes, @@ -3766,9 +3779,9 @@ void priv::store(const ExPolygons &shapes, SVG svg(file_svg, bb); svg.draw(shapes); - ShapePoint2index s2i(shapes); + ExPolygonsIndices s2i(shapes); auto get_point = [&shapes, &s2i](size_t i)->Point { - auto id = s2i.calc_id(i); + auto id = s2i.cvt(i); const ExPolygon &s = shapes[id.expolygons_index]; const Polygon &p = (id.polygon_index == 0) ? s.contour : @@ -3948,10 +3961,19 @@ void priv::store(const Emboss::IProjection &projection, const std::string &obj_filename) { auto [front, back] = projection.create_front_back(point_to_project); - Vec3f diff = back - front; - Vec3f pos = front + diff * projection_ratio; - priv::store(pos, diff.normalized(), + Vec3d diff = back - front; + Vec3d pos = front + diff * projection_ratio; + priv::store(pos.cast(), diff.normalized().cast(), DEBUG_OUTPUT_DIR + "projection_center.obj"); // only debug } #endif // DEBUG_OUTPUT_DIR + +bool Slic3r::corefine_test(const std::string &model_path, const std::string &shape_path) { + priv::CutMesh model, shape; + if (!CGAL::IO::read_OFF(model_path, model)) return false; + if (!CGAL::IO::read_OFF(shape_path, shape)) return false; + + CGAL::Polygon_mesh_processing::corefine(model, shape); + return true; +} diff --git a/src/libslic3r/CutSurface.hpp b/src/libslic3r/CutSurface.hpp index f923bb7e0b..9f4e3159cf 100644 --- a/src/libslic3r/CutSurface.hpp +++ b/src/libslic3r/CutSurface.hpp @@ -46,7 +46,7 @@ SurfaceCut cut_surface(const ExPolygons &shapes, /// Way of emboss /// Mesh indexed_triangle_set cut2model(const SurfaceCut &cut, - const Emboss::IProject3f &projection); + const Emboss::IProject3d &projection); /// /// Separate (A)rea (o)f (I)nterest .. AoI from model @@ -68,5 +68,7 @@ indexed_triangle_set its_cut_AoI(const indexed_triangle_set &its, /// Copy of indices by mask(with their vertices) indexed_triangle_set its_mask(const indexed_triangle_set &its, const std::vector &mask); +bool corefine_test(const std::string &model_path, const std::string &shape_path); + } // namespace Slic3r #endif // slic3r_CutSurface_hpp_ diff --git a/src/libslic3r/Emboss.cpp b/src/libslic3r/Emboss.cpp index c6dd8a3a58..5194c80649 100644 --- a/src/libslic3r/Emboss.cpp +++ b/src/libslic3r/Emboss.cpp @@ -303,6 +303,7 @@ ExPolygons Emboss::heal_shape(const Polygons &shape) { return res; } +#define HEAL_CLOSE_POINTS bool Emboss::heal_shape(ExPolygons &shape, unsigned max_iteration) { if (shape.empty()) return true; @@ -313,11 +314,11 @@ bool Emboss::heal_shape(ExPolygons &shape, unsigned max_iteration) Pointfs intersections = intersection_points(shape); Points duplicits = collect_duplications(to_points(shape)); - Points close = priv::collect_close_points(shape); - if (intersections.empty() && duplicits.empty() && close.empty()) break; + //Points close = priv::collect_close_points(shape, 1.); + if (intersections.empty() && duplicits.empty() /* && close.empty() */) break; holes.clear(); - holes.reserve(intersections.size() + duplicits.size() + close.size()); + holes.reserve(intersections.size() + duplicits.size() /* + close.size()*/); // Fix self intersection in result by subtracting hole 2x2 for (const Vec2d &p : intersections) { @@ -335,11 +336,11 @@ bool Emboss::heal_shape(ExPolygons &shape, unsigned max_iteration) } // fix close points in simmilar way as duplicits - for (const Point &p : close) { - Slic3r::Polygon hole(priv::pts_3x3); - hole.translate(p); - holes.push_back(hole); - } + //for (const Point &p : close) { + // Slic3r::Polygon hole(priv::pts_3x3); + // hole.translate(p); + // holes.push_back(hole); + //} holes = Slic3r::union_(holes); shape = Slic3r::diff_ex(shape, holes, ApplySafetyOffset::Yes); @@ -1063,8 +1064,8 @@ indexed_triangle_set polygons2model_unique( for (const Point &p : points) { auto p2 = projection.create_front_back(p); - front_points.push_back(p2.first); - back_points.push_back(p2.second); + front_points.push_back(p2.first.cast()); + back_points.push_back(p2.second.cast()); } // insert back points, front are already in @@ -1132,8 +1133,8 @@ indexed_triangle_set polygons2model_duplicit( max_index = index; const Point &p = points[i]; auto p2 = projection.create_front_back(p); - front_points.push_back(p2.first); - back_points.push_back(p2.second); + front_points.push_back(p2.first.cast()); + back_points.push_back(p2.second.cast()); } assert(max_index+1 == count_point); @@ -1185,23 +1186,23 @@ indexed_triangle_set Emboss::polygons2model(const ExPolygons &shape2d, priv::polygons2model_duplicit(shape2d, projection, points, duplicits); } -std::pair Emboss::ProjectZ::create_front_back(const Point &p) const +std::pair Emboss::ProjectZ::create_front_back(const Point &p) const { - Vec3f front( - static_cast(p.x() * SHAPE_SCALE), - static_cast(p.y() * SHAPE_SCALE), - 0.f); + Vec3d front( + p.x() * SHAPE_SCALE, + p.y() * SHAPE_SCALE, + 0.); return std::make_pair(front, project(front)); } -Vec3f Emboss::ProjectZ::project(const Vec3f &point) const +Vec3d Emboss::ProjectZ::project(const Vec3d &point) const { - Vec3f res = point; // copy + Vec3d res = point; // copy res.z() = m_depth; return res; } -std::optional Emboss::ProjectZ::unproject(const Vec3f &p) const { +std::optional Emboss::ProjectZ::unproject(const Vec3d &p) const { return Point(p.x() / SHAPE_SCALE, p.y() / SHAPE_SCALE); } @@ -1267,18 +1268,18 @@ Transform3d Emboss::create_transformation_onto_surface(const Vec3f &position, // OrthoProject -std::pair Emboss::OrthoProject::create_front_back(const Point &p) const { +std::pair Emboss::OrthoProject::create_front_back(const Point &p) const { Vec3d front(p.x(), p.y(), 0.); - Vec3f front_tr = (m_matrix * front).cast(); + Vec3d front_tr = m_matrix * front; return std::make_pair(front_tr, project(front_tr)); } -Vec3f Emboss::OrthoProject::project(const Vec3f &point) const +Vec3d Emboss::OrthoProject::project(const Vec3d &point) const { return point + m_direction; } -std::optional Emboss::OrthoProject::unproject(const Vec3f &p) const { - Vec3d pp = m_matrix_inv * p.cast(); +std::optional Emboss::OrthoProject::unproject(const Vec3d &p) const { + Vec3d pp = m_matrix_inv * p; return Point(pp.x(), pp.y()); } \ No newline at end of file diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp index d649f67eb8..f2df0257e2 100644 --- a/src/libslic3r/Emboss.hpp +++ b/src/libslic3r/Emboss.hpp @@ -215,10 +215,10 @@ public: /// /// Project spatial point /// - class IProject3f + class IProject3d { public: - virtual ~IProject3f() = default; + virtual ~IProject3d() = default; /// /// Move point with respect to projection direction /// e.g. Orthogonal projection will move with point by direction @@ -226,14 +226,14 @@ public: /// /// Spatial point coordinate /// Projected spatial point - virtual Vec3f project(const Vec3f &point) const = 0; + virtual Vec3d project(const Vec3d &point) const = 0; }; /// /// Project 2d point into space /// Could be plane, sphere, cylindric, ... /// - class IProjection : public IProject3f + class IProjection : public IProject3d { public: virtual ~IProjection() = default; @@ -246,9 +246,9 @@ public: /// first - front spatial point /// second - back spatial point /// - virtual std::pair create_front_back(const Point &p) const = 0; + virtual std::pair create_front_back(const Point &p) const = 0; - virtual std::optional unproject(const Vec3f &p) const = 0; + virtual std::optional unproject(const Vec3d &p) const = 0; }; /// @@ -272,59 +272,59 @@ public: class ProjectZ : public IProjection { public: - ProjectZ(float depth) : m_depth(depth) {} + ProjectZ(double depth) : m_depth(depth) {} // Inherited via IProject - std::pair create_front_back(const Point &p) const override; - Vec3f project(const Vec3f &point) const override; - std::optional unproject(const Vec3f &p) const override; - float m_depth; + std::pair create_front_back(const Point &p) const override; + Vec3d project(const Vec3d &point) const override; + std::optional unproject(const Vec3d &p) const override; + double m_depth; }; class ProjectScale : public IProjection { std::unique_ptr core; - float m_scale; + double m_scale; public: - ProjectScale(std::unique_ptr core, float scale) + ProjectScale(std::unique_ptr core, double scale) : core(std::move(core)), m_scale(scale) {} // Inherited via IProject - std::pair create_front_back(const Point &p) const override + std::pair create_front_back(const Point &p) const override { auto res = core->create_front_back(p); return std::make_pair(res.first * m_scale, res.second * m_scale); } - Vec3f project(const Vec3f &point) const override{ + Vec3d project(const Vec3d &point) const override{ return core->project(point); } - std::optional unproject(const Vec3f &p) const override { + std::optional unproject(const Vec3d &p) const override { return core->unproject(p / m_scale); } }; - class OrthoProject3f : public Emboss::IProject3f + class OrthoProject3d : public Emboss::IProject3d { // size and direction of emboss for ortho projection - Vec3f m_direction; + Vec3d m_direction; public: - OrthoProject3f(Vec3f direction) : m_direction(direction) {} - Vec3f project(const Vec3f &point) const override{ return point + m_direction;} + OrthoProject3d(Vec3d direction) : m_direction(direction) {} + Vec3d project(const Vec3d &point) const override{ return point + m_direction;} }; class OrthoProject: public Emboss::IProjection { Transform3d m_matrix; // size and direction of emboss for ortho projection - Vec3f m_direction; + Vec3d m_direction; Transform3d m_matrix_inv; public: - OrthoProject(Transform3d matrix, Vec3f direction) + OrthoProject(Transform3d matrix, Vec3d direction) : m_matrix(matrix), m_direction(direction), m_matrix_inv(matrix.inverse()) {} // Inherited via IProject - std::pair create_front_back(const Point &p) const override; - Vec3f project(const Vec3f &point) const override; - std::optional unproject(const Vec3f &p) const override; + std::pair create_front_back(const Point &p) const override; + Vec3d project(const Vec3d &point) const override; + std::optional unproject(const Vec3d &p) const override; }; }; diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index 5d0b515b8c..5e78eb838c 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -97,7 +97,7 @@ static Emboss::OrthoProject create_projection_for_cut( /// Text voliume transformation inside object /// Cutted surface from model /// Projection -static Emboss::OrthoProject3f create_emboss_projection( +static Emboss::OrthoProject3d create_emboss_projection( bool is_outside, float emboss, Transform3d tr, SurfaceCut &cut); static void create_message(const std::string &message); // only in finalize @@ -428,7 +428,7 @@ void UseSurfaceJob::process(Ctl &ctl) { if (was_canceled()) return; // !! Projection needs to transform cut - Emboss::OrthoProject3f projection = priv::create_emboss_projection( + Emboss::OrthoProject3d projection = priv::create_emboss_projection( m_input.is_outside, fp.emboss, emboss_tr, cut); indexed_triangle_set new_its = cut2model(cut, projection); @@ -664,8 +664,8 @@ Emboss::OrthoProject priv::create_projection_for_cut( double shape_scale, const std::pair &z_range) { - float min_z = z_range.first - priv::safe_extension; - float max_z = z_range.second + priv::safe_extension; + double min_z = z_range.first - priv::safe_extension; + double max_z = z_range.second + priv::safe_extension; assert(min_z < max_z); // range between min and max value double projection_size = max_z - min_z; @@ -676,8 +676,7 @@ Emboss::OrthoProject priv::create_projection_for_cut( // Y .. from bottom to top // Z .. from text to eye Vec3d untransformed_direction(0., 0., projection_size); - Vec3f project_direction = - (transformation_for_vector * untransformed_direction).cast(); + Vec3d project_direction = transformation_for_vector * untransformed_direction; // Projection is in direction from far plane tr.translate(Vec3d(0., 0., min_z)); @@ -685,7 +684,7 @@ Emboss::OrthoProject priv::create_projection_for_cut( return Emboss::OrthoProject(tr, project_direction); } -Emboss::OrthoProject3f priv::create_emboss_projection( +Emboss::OrthoProject3d priv::create_emboss_projection( bool is_outside, float emboss, Transform3d tr, SurfaceCut &cut) { // Offset of clossed side to model @@ -694,8 +693,8 @@ Emboss::OrthoProject3f priv::create_emboss_projection( front_move = (is_outside) ? emboss : surface_offset, back_move = -((is_outside) ? surface_offset : emboss); its_transform(cut, tr.pretranslate(Vec3d(0., 0., front_move))); - Vec3f from_front_to_back(0.f, 0.f, back_move - front_move); - return Emboss::OrthoProject3f(from_front_to_back); + Vec3d from_front_to_back(0., 0., back_move - front_move); + return Emboss::OrthoProject3d(from_front_to_back); } bool priv::process(std::exception_ptr &eptr) { diff --git a/tests/libslic3r/test_cut_surface.cpp b/tests/libslic3r/test_cut_surface.cpp index 3f813a03e1..ffc762b865 100644 --- a/tests/libslic3r/test_cut_surface.cpp +++ b/tests/libslic3r/test_cut_surface.cpp @@ -11,7 +11,7 @@ TEST_CASE("Cut character from surface", "[]") char letter = '%'; float flatness = 2.; unsigned int font_index = 0; // collection - float z_depth = 50.f; // projection size + double z_depth = 50.f; // projection size auto font = Emboss::create_font_file(font_path.c_str()); REQUIRE(font != nullptr); @@ -24,7 +24,7 @@ TEST_CASE("Cut character from surface", "[]") Transform3d tr = Transform3d::Identity(); tr.translate(Vec3d(0., 0., -z_depth)); tr.scale(Emboss::SHAPE_SCALE); - Emboss::OrthoProject cut_projection(tr, Vec3f(0.f, 0.f, z_depth)); + Emboss::OrthoProject cut_projection(tr, Vec3d(0., 0., z_depth)); auto object = its_make_cube(782 - 49 + 50, 724 + 10 + 50, 5); its_translate(object, Vec3f(49 - 25, -10 - 25, -40)); @@ -38,7 +38,7 @@ TEST_CASE("Cut character from surface", "[]") CHECK(!surfaces.empty()); Emboss::OrthoProject projection(Transform3d::Identity(), - Vec3f(0.f, 0.f, 10.f)); + Vec3d(0.f, 0.f, 10.f)); its_translate(surfaces, Vec3f(0.f, 0.f, 10)); indexed_triangle_set its = cut2model(surfaces, projection); @@ -81,8 +81,8 @@ static Emboss::OrthoProject create_projection_for_cut( { // create sure that emboss object is bigger than source object const float safe_extension = 1.0f; - float min_z = z_range.first - safe_extension; - float max_z = z_range.second + safe_extension; + double min_z = z_range.first - safe_extension; + double max_z = z_range.second + safe_extension; assert(min_z < max_z); // range between min and max value double projection_size = max_z - min_z; @@ -93,8 +93,7 @@ static Emboss::OrthoProject create_projection_for_cut( // Y .. from bottom to top // Z .. from text to eye Vec3d untransformed_direction(0., 0., projection_size); - Vec3f project_direction = - (transformation_for_vector * untransformed_direction).cast(); + Vec3d project_direction = transformation_for_vector * untransformed_direction; // Projection is in direction from far plane tr.translate(Vec3d(0., 0., min_z)); diff --git a/tests/libslic3r/test_emboss.cpp b/tests/libslic3r/test_emboss.cpp index f2c4315353..31bb1459a8 100644 --- a/tests/libslic3r/test_emboss.cpp +++ b/tests/libslic3r/test_emboss.cpp @@ -433,8 +433,8 @@ TEST_CASE("Cut surface", "[]") std::string font_path = get_font_filepath(); char letter = '%'; float flatness = 2.; - unsigned int font_index = 0; // collection - float z_depth = 50.f; // projection size + unsigned int font_index = 0; // collection + double z_depth = 50.; // projection size auto font = Emboss::create_font_file(font_path.c_str()); REQUIRE(font != nullptr); @@ -451,7 +451,7 @@ TEST_CASE("Cut surface", "[]") Transform3d tr = Transform3d::Identity(); tr.translate(Vec3d(0., 0., -z_depth)); tr.scale(Emboss::SHAPE_SCALE); - Emboss::OrthoProject cut_projection(tr, Vec3f(0.f, 0.f, z_depth)); + Emboss::OrthoProject cut_projection(tr, Vec3d(0., 0., z_depth)); auto object = its_make_cube(782 - 49 + 50, 724 + 10 + 50, 5); its_translate(object, Vec3f(49 - 25, -10 - 25, -40)); @@ -462,8 +462,8 @@ TEST_CASE("Cut surface", "[]") auto surfaces = cut_surface(shape, {object}, cut_projection, 0); CHECK(!surfaces.empty()); - Emboss::OrthoProject projection(Transform3d::Identity(), Vec3f(0.f, 0.f, 10.f)); - its_translate(surfaces, Vec3f(0.f, 0.f, 10)); + Emboss::OrthoProject projection(Transform3d::Identity(), Vec3d(0., 0., 10.)); + its_translate(surfaces, Vec3f(0., 0., 10.)); indexed_triangle_set its = cut2model(surfaces, projection); CHECK(!its.empty());