Merge branch 'master' into fs_QuadricEdgeCollapse
This commit is contained in:
commit
cc88b1e86b
@ -2,10 +2,10 @@
|
||||
# Building PrusaSlicer on UNIX/Linux
|
||||
|
||||
PrusaSlicer uses the CMake build system and requires several dependencies.
|
||||
The dependencies can be listed in `deps/deps-linux.cmake` and `deps/deps-unix-common.cmake`, although they don't necessarily need to be as recent
|
||||
as the versions listed - generally versions available on conservative Linux distros such as Debian stable or CentOS should suffice.
|
||||
The dependencies can be listed in the `deps` directory in individual subdirectories, although they don't necessarily need to be as recent
|
||||
as the versions listed - generally versions available on conservative Linux distros such as Debian stable, Ubuntu LTS releases or Fedora are likely sufficient.
|
||||
|
||||
Perl is not required any more.
|
||||
Perl is not required anymore.
|
||||
|
||||
In a typical situation, one would open a command line, go to the PrusaSlicer sources (**the root directory of the repository**), create a directory called `build` or similar,
|
||||
`cd` into it and call:
|
||||
|
@ -45,16 +45,38 @@ static float max_brim_width(const ConstPrintObjectPtrsAdaptor &objects)
|
||||
}));
|
||||
}
|
||||
|
||||
static ConstPrintObjectPtrs get_top_level_objects_with_brim(const Print &print)
|
||||
// Returns ExPolygons of the bottom layer of the print object after elephant foot compensation.
|
||||
static ExPolygons get_print_object_bottom_layer_expolygons(const PrintObject &print_object)
|
||||
{
|
||||
ExPolygons ex_polygons;
|
||||
for (LayerRegion *region : print_object.layers().front()->regions())
|
||||
Slic3r::append(ex_polygons, offset_ex(offset_ex(region->slices.surfaces, float(SCALED_EPSILON)), -float(SCALED_EPSILON)));
|
||||
return ex_polygons;
|
||||
}
|
||||
|
||||
// Returns ExPolygons of bottom layer for every print object in Print after elephant foot compensation.
|
||||
static std::vector<ExPolygons> get_print_bottom_layers_expolygons(const Print &print)
|
||||
{
|
||||
std::vector<ExPolygons> bottom_layers_expolygons;
|
||||
bottom_layers_expolygons.reserve(print.objects().size());
|
||||
for (const PrintObject *object : print.objects())
|
||||
bottom_layers_expolygons.emplace_back(get_print_object_bottom_layer_expolygons(*object));
|
||||
|
||||
return bottom_layers_expolygons;
|
||||
}
|
||||
|
||||
static ConstPrintObjectPtrs get_top_level_objects_with_brim(const Print &print, const std::vector<ExPolygons> &bottom_layers_expolygons)
|
||||
{
|
||||
assert(print.objects().size() == bottom_layers_expolygons.size());
|
||||
Polygons islands;
|
||||
ConstPrintObjectPtrs island_to_object;
|
||||
for (const PrintObject *object : print.objects()) {
|
||||
for(size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx) {
|
||||
Polygons islands_object;
|
||||
islands_object.reserve(object->layers().front()->lslices.size());
|
||||
for (const ExPolygon &ex_poly : object->layers().front()->lslices)
|
||||
islands_object.reserve(bottom_layers_expolygons[print_object_idx].size());
|
||||
for (const ExPolygon &ex_poly : bottom_layers_expolygons[print_object_idx])
|
||||
islands_object.emplace_back(ex_poly.contour);
|
||||
|
||||
const PrintObject *object = print.objects()[print_object_idx];
|
||||
islands.reserve(islands.size() + object->instances().size() * islands_object.size());
|
||||
for (const PrintInstance &instance : object->instances())
|
||||
for (Polygon &poly : islands_object) {
|
||||
@ -110,7 +132,7 @@ static Polygons top_level_outer_brim_islands(const ConstPrintObjectPtrs &top_lev
|
||||
//FIXME how about the brim type?
|
||||
auto brim_offset = float(scale_(object->config().brim_offset.value));
|
||||
Polygons islands_object;
|
||||
for (const ExPolygon &ex_poly : object->layers().front()->lslices) {
|
||||
for (const ExPolygon &ex_poly : get_print_object_bottom_layer_expolygons(*object)) {
|
||||
Polygons contour_offset = offset(ex_poly.contour, brim_offset);
|
||||
for (Polygon &poly : contour_offset)
|
||||
poly.douglas_peucker(SCALED_RESOLUTION);
|
||||
@ -124,8 +146,12 @@ static Polygons top_level_outer_brim_islands(const ConstPrintObjectPtrs &top_lev
|
||||
return islands;
|
||||
}
|
||||
|
||||
static ExPolygons top_level_outer_brim_area(const Print &print, const ConstPrintObjectPtrs &top_level_objects_with_brim, const float no_brim_offset)
|
||||
static ExPolygons top_level_outer_brim_area(const Print &print,
|
||||
const ConstPrintObjectPtrs &top_level_objects_with_brim,
|
||||
const std::vector<ExPolygons> &bottom_layers_expolygons,
|
||||
const float no_brim_offset)
|
||||
{
|
||||
assert(print.objects().size() == bottom_layers_expolygons.size());
|
||||
std::unordered_set<size_t> top_level_objects_idx;
|
||||
top_level_objects_idx.reserve(top_level_objects_with_brim.size());
|
||||
for (const PrintObject *object : top_level_objects_with_brim)
|
||||
@ -133,15 +159,16 @@ static ExPolygons top_level_outer_brim_area(const Print &print, const ConstPrint
|
||||
|
||||
ExPolygons brim_area;
|
||||
ExPolygons no_brim_area;
|
||||
for (const PrintObject *object : print.objects()) {
|
||||
const BrimType brim_type = object->config().brim_type.value;
|
||||
const float brim_offset = scale_(object->config().brim_offset.value);
|
||||
const float brim_width = scale_(object->config().brim_width.value);
|
||||
const bool is_top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end();
|
||||
for(size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx) {
|
||||
const PrintObject *object = print.objects()[print_object_idx];
|
||||
const BrimType brim_type = object->config().brim_type.value;
|
||||
const float brim_offset = scale_(object->config().brim_offset.value);
|
||||
const float brim_width = scale_(object->config().brim_width.value);
|
||||
const bool is_top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end();
|
||||
|
||||
ExPolygons brim_area_object;
|
||||
ExPolygons no_brim_area_object;
|
||||
for (const ExPolygon &ex_poly : object->layers().front()->lslices) {
|
||||
for (const ExPolygon &ex_poly : bottom_layers_expolygons[print_object_idx]) {
|
||||
if ((brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner) && is_top_outer_brim)
|
||||
append(brim_area_object, diff_ex(offset(ex_poly.contour, brim_width + brim_offset), offset(ex_poly.contour, brim_offset)));
|
||||
|
||||
@ -166,8 +193,12 @@ static ExPolygons top_level_outer_brim_area(const Print &print, const ConstPrint
|
||||
return diff_ex(brim_area, no_brim_area);
|
||||
}
|
||||
|
||||
static ExPolygons inner_brim_area(const Print &print, const ConstPrintObjectPtrs &top_level_objects_with_brim, const float no_brim_offset)
|
||||
static ExPolygons inner_brim_area(const Print &print,
|
||||
const ConstPrintObjectPtrs &top_level_objects_with_brim,
|
||||
const std::vector<ExPolygons> &bottom_layers_expolygons,
|
||||
const float no_brim_offset)
|
||||
{
|
||||
assert(print.objects().size() == bottom_layers_expolygons.size());
|
||||
std::unordered_set<size_t> top_level_objects_idx;
|
||||
top_level_objects_idx.reserve(top_level_objects_with_brim.size());
|
||||
for (const PrintObject *object : top_level_objects_with_brim)
|
||||
@ -176,16 +207,17 @@ static ExPolygons inner_brim_area(const Print &print, const ConstPrintObjectPtrs
|
||||
ExPolygons brim_area;
|
||||
ExPolygons no_brim_area;
|
||||
Polygons holes;
|
||||
for (const PrintObject *object : print.objects()) {
|
||||
const BrimType brim_type = object->config().brim_type.value;
|
||||
const float brim_offset = scale_(object->config().brim_offset.value);
|
||||
const float brim_width = scale_(object->config().brim_width.value);
|
||||
const bool top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end();
|
||||
for(size_t print_object_idx = 0; print_object_idx < print.objects().size(); ++print_object_idx) {
|
||||
const PrintObject *object = print.objects()[print_object_idx];
|
||||
const BrimType brim_type = object->config().brim_type.value;
|
||||
const float brim_offset = scale_(object->config().brim_offset.value);
|
||||
const float brim_width = scale_(object->config().brim_width.value);
|
||||
const bool top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end();
|
||||
|
||||
ExPolygons brim_area_object;
|
||||
ExPolygons no_brim_area_object;
|
||||
Polygons holes_object;
|
||||
for (const ExPolygon &ex_poly : object->layers().front()->lslices) {
|
||||
for (const ExPolygon &ex_poly : bottom_layers_expolygons[print_object_idx]) {
|
||||
if (brim_type == BrimType::btOuterOnly || brim_type == BrimType::btOuterAndInner) {
|
||||
if (top_outer_brim)
|
||||
no_brim_area_object.emplace_back(ex_poly);
|
||||
@ -204,7 +236,7 @@ static ExPolygons inner_brim_area(const Print &print, const ConstPrintObjectPtrs
|
||||
|
||||
append(holes_object, ex_poly.holes);
|
||||
}
|
||||
append(no_brim_area_object, offset_ex(object->layers().front()->lslices, brim_offset));
|
||||
append(no_brim_area_object, offset_ex(bottom_layers_expolygons[print_object_idx], brim_offset));
|
||||
|
||||
for (const PrintInstance &instance : object->instances()) {
|
||||
append_and_translate(brim_area, brim_area_object, instance);
|
||||
@ -236,7 +268,7 @@ static void optimize_polylines_by_reversing(Polylines *polylines)
|
||||
static Polylines connect_brim_lines(Polylines &&polylines, const Polygons &brim_area, float max_connection_length)
|
||||
{
|
||||
if (polylines.empty())
|
||||
return Polylines();
|
||||
return {};
|
||||
|
||||
BoundingBox bbox = get_extents(polylines);
|
||||
bbox.merge(get_extents(brim_area));
|
||||
@ -305,16 +337,20 @@ static Polylines connect_brim_lines(Polylines &&polylines, const Polygons &brim_
|
||||
}
|
||||
}
|
||||
if (end < polylines.size())
|
||||
polylines.erase(polylines.begin() + end, polylines.end());
|
||||
polylines.erase(polylines.begin() + int(end), polylines.end());
|
||||
}
|
||||
|
||||
return std::move(polylines);
|
||||
}
|
||||
|
||||
static void make_inner_brim(const Print &print, const ConstPrintObjectPtrs &top_level_objects_with_brim, ExtrusionEntityCollection &brim)
|
||||
static void make_inner_brim(const Print &print,
|
||||
const ConstPrintObjectPtrs &top_level_objects_with_brim,
|
||||
const std::vector<ExPolygons> &bottom_layers_expolygons,
|
||||
ExtrusionEntityCollection &brim)
|
||||
{
|
||||
assert(print.objects().size() == bottom_layers_expolygons.size());
|
||||
Flow flow = print.brim_flow();
|
||||
ExPolygons islands_ex = inner_brim_area(print, top_level_objects_with_brim, float(flow.scaled_spacing()));
|
||||
ExPolygons islands_ex = inner_brim_area(print, top_level_objects_with_brim, bottom_layers_expolygons, float(flow.scaled_spacing()));
|
||||
Polygons loops;
|
||||
islands_ex = offset_ex(islands_ex, -0.5f * float(flow.scaled_spacing()), jtSquare);
|
||||
for (size_t i = 0; !islands_ex.empty(); ++i) {
|
||||
@ -334,11 +370,12 @@ static void make_inner_brim(const Print &print, const ConstPrintObjectPtrs &top_
|
||||
// Collect islands_area to be merged into the final 1st layer convex hull.
|
||||
ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cancel, Polygons &islands_area)
|
||||
{
|
||||
Flow flow = print.brim_flow();
|
||||
ConstPrintObjectPtrs top_level_objects_with_brim = get_top_level_objects_with_brim(print);
|
||||
Polygons islands = top_level_outer_brim_islands(top_level_objects_with_brim);
|
||||
ExPolygons islands_area_ex = top_level_outer_brim_area(print, top_level_objects_with_brim, float(flow.scaled_spacing()));
|
||||
islands_area = to_polygons(islands_area_ex);
|
||||
Flow flow = print.brim_flow();
|
||||
std::vector<ExPolygons> bottom_layers_expolygons = get_print_bottom_layers_expolygons(print);
|
||||
ConstPrintObjectPtrs top_level_objects_with_brim = get_top_level_objects_with_brim(print, bottom_layers_expolygons);
|
||||
Polygons islands = top_level_outer_brim_islands(top_level_objects_with_brim);
|
||||
ExPolygons islands_area_ex = top_level_outer_brim_area(print, top_level_objects_with_brim, bottom_layers_expolygons, float(flow.scaled_spacing()));
|
||||
islands_area = to_polygons(islands_area_ex);
|
||||
|
||||
Polygons loops;
|
||||
size_t num_loops = size_t(floor(max_brim_width(print.objects()) / flow.spacing()));
|
||||
@ -536,7 +573,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
|
||||
extrusion_entities_append_loops_and_paths(brim.entities, std::move(all_loops), erSkirt, float(flow.mm3_per_mm()), float(flow.width()), float(print.skirt_first_layer_height()));
|
||||
}
|
||||
|
||||
make_inner_brim(print, top_level_objects_with_brim, brim);
|
||||
make_inner_brim(print, top_level_objects_with_brim, bottom_layers_expolygons, brim);
|
||||
return brim;
|
||||
}
|
||||
|
||||
|
@ -295,7 +295,7 @@ void PrintConfigDef::init_common_params()
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.2));
|
||||
def->set_default_value(new ConfigOptionFloat(0.));
|
||||
|
||||
// Options used by physical printers
|
||||
|
||||
@ -491,10 +491,11 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("brim_offset", coFloat);
|
||||
def->label = L("Brim offset");
|
||||
def->category = L("Skirt and brim");
|
||||
def->tooltip = L("The offset of the brim from the printed object.");
|
||||
def->tooltip = L("The offset of the brim from the printed object. The offset is applied after the elephant foot compensation.");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
def->set_default_value(new ConfigOptionFloat(0.f));
|
||||
|
||||
def = this->add("clip_multipart_objects", coBool);
|
||||
def->label = L("Clip multi-part objects");
|
||||
|
@ -58,29 +58,6 @@ T sum_score(AccessFn &&accessfn, size_t facecount, size_t Nthreads)
|
||||
return execution::reduce(ex_tbb, from, to, initv, mergefn, accessfn, grainsize);
|
||||
}
|
||||
|
||||
// Try to guess the number of support points needed to support a mesh
|
||||
double get_misalginment_score(const TriangleMesh &mesh, const Transform3f &tr)
|
||||
{
|
||||
if (mesh.its.vertices.empty()) return std::nan("");
|
||||
|
||||
auto accessfn = [&mesh, &tr](size_t fi) {
|
||||
auto triangle = get_transformed_triangle(mesh, tr, fi);
|
||||
Vec3f U = triangle[1] - triangle[0];
|
||||
Vec3f V = triangle[2] - triangle[0];
|
||||
Vec3f C = U.cross(V);
|
||||
|
||||
// We should score against the alignment with the reference planes
|
||||
return scaled<int_fast64_t>(std::abs(C.dot(Vec3f::UnitX())) +
|
||||
std::abs(C.dot(Vec3f::UnitY())));
|
||||
};
|
||||
|
||||
size_t facecount = mesh.its.indices.size();
|
||||
size_t Nthreads = std::thread::hardware_concurrency();
|
||||
double S = unscaled(sum_score<int_fast64_t>(accessfn, facecount, Nthreads));
|
||||
|
||||
return S / facecount;
|
||||
}
|
||||
|
||||
// Get area and normal of a triangle
|
||||
struct Facestats {
|
||||
Vec3f normal;
|
||||
@ -96,21 +73,45 @@ struct Facestats {
|
||||
}
|
||||
};
|
||||
|
||||
// Try to guess the number of support points needed to support a mesh
|
||||
double get_misalginment_score(const TriangleMesh &mesh, const Transform3f &tr)
|
||||
{
|
||||
if (mesh.its.vertices.empty()) return std::nan("");
|
||||
|
||||
auto accessfn = [&mesh, &tr](size_t fi) {
|
||||
Facestats fc{get_transformed_triangle(mesh, tr, fi)};
|
||||
|
||||
float score = fc.area
|
||||
* (std::abs(fc.normal.dot(Vec3f::UnitX()))
|
||||
+ std::abs(fc.normal.dot(Vec3f::UnitY()))
|
||||
+ std::abs(fc.normal.dot(Vec3f::UnitZ())));
|
||||
|
||||
// We should score against the alignment with the reference planes
|
||||
return scaled<int_fast64_t>(score);
|
||||
};
|
||||
|
||||
size_t facecount = mesh.its.indices.size();
|
||||
size_t Nthreads = std::thread::hardware_concurrency();
|
||||
double S = unscaled(sum_score<int_fast64_t>(accessfn, facecount, Nthreads));
|
||||
|
||||
return S / facecount;
|
||||
}
|
||||
|
||||
// The score function for a particular face
|
||||
inline double get_supportedness_score(const Facestats &fc)
|
||||
{
|
||||
// Simply get the angle (acos of dot product) between the face normal and
|
||||
// the DOWN vector.
|
||||
float phi = 1. - std::acos(fc.normal.dot(DOWN)) / float(PI);
|
||||
|
||||
// Only consider faces that have slopes below 90 deg:
|
||||
phi = phi * (phi >= 0.5f);
|
||||
float cosphi = fc.normal.dot(DOWN);
|
||||
float phi = 1.f - std::acos(cosphi) / float(PI);
|
||||
|
||||
// Make the huge slopes more significant than the smaller slopes
|
||||
phi = phi * phi * phi;
|
||||
|
||||
// Multiply with the area of the current face
|
||||
return fc.area * POINTS_PER_UNIT_AREA * phi;
|
||||
// Multiply with the square root of face area of the current face,
|
||||
// the area is less important as it grows.
|
||||
// This makes many smaller overhangs a bigger impact.
|
||||
return std::sqrt(fc.area) * POINTS_PER_UNIT_AREA * phi;
|
||||
}
|
||||
|
||||
// Try to guess the number of support points needed to support a mesh
|
||||
@ -120,8 +121,7 @@ double get_supportedness_score(const TriangleMesh &mesh, const Transform3f &tr)
|
||||
|
||||
auto accessfn = [&mesh, &tr](size_t fi) {
|
||||
Facestats fc{get_transformed_triangle(mesh, tr, fi)};
|
||||
|
||||
return get_supportedness_score(fc);
|
||||
return scaled<int_fast64_t>(get_supportedness_score(fc));
|
||||
};
|
||||
|
||||
size_t facecount = mesh.its.indices.size();
|
||||
@ -164,7 +164,7 @@ float get_supportedness_onfloor_score(const TriangleMesh &mesh,
|
||||
Facestats fc{tri};
|
||||
|
||||
if (tri[0].z() <= zlvl && tri[1].z() <= zlvl && tri[2].z() <= zlvl)
|
||||
return -fc.area * POINTS_PER_UNIT_AREA;
|
||||
return -2 * fc.area * POINTS_PER_UNIT_AREA;
|
||||
|
||||
return get_supportedness_score(fc);
|
||||
};
|
||||
@ -283,6 +283,26 @@ std::array<double, N> find_min_score(Fn &&fn, It from, It to, StopCond &&stopfn)
|
||||
|
||||
} // namespace
|
||||
|
||||
// Assemble the mesh with the correct transformation to be used in rotation
|
||||
// optimization.
|
||||
TriangleMesh get_mesh_to_rotate(const ModelObject &mo)
|
||||
{
|
||||
TriangleMesh mesh = mo.raw_mesh();
|
||||
mesh.require_shared_vertices();
|
||||
|
||||
ModelInstance *mi = mo.instances[0];
|
||||
auto rotation = Vec3d::Zero();
|
||||
auto offset = Vec3d::Zero();
|
||||
Transform3d trafo_instance = Geometry::assemble_transform(offset,
|
||||
rotation,
|
||||
mi->get_scaling_factor(),
|
||||
mi->get_mirror());
|
||||
|
||||
mesh.transform(trafo_instance);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
Vec2d find_best_misalignment_rotation(const ModelObject & mo,
|
||||
const RotOptimizeParams ¶ms)
|
||||
{
|
||||
@ -293,8 +313,7 @@ Vec2d find_best_misalignment_rotation(const ModelObject & mo,
|
||||
|
||||
// We will use only one instance of this converted mesh to examine different
|
||||
// rotations
|
||||
TriangleMesh mesh = mo.raw_mesh();
|
||||
mesh.require_shared_vertices();
|
||||
TriangleMesh mesh = get_mesh_to_rotate(mo);
|
||||
|
||||
// To keep track of the number of iterations
|
||||
int status = 0;
|
||||
@ -326,7 +345,7 @@ Vec2d find_best_misalignment_rotation(const ModelObject & mo,
|
||||
// We are searching rotations around only two axes x, y. Thus the
|
||||
// problem becomes a 2 dimensional optimization task.
|
||||
// We can specify the bounds for a dimension in the following way:
|
||||
auto bounds = opt::bounds({ {-PI/2, PI/2}, {-PI/2, PI/2} });
|
||||
auto bounds = opt::bounds({ {-PI, PI}, {-PI, PI} });
|
||||
|
||||
auto result = solver.to_max().optimize(
|
||||
[&mesh, &statusfn] (const XYRotation &rot)
|
||||
@ -350,8 +369,7 @@ Vec2d find_least_supports_rotation(const ModelObject & mo,
|
||||
|
||||
// We will use only one instance of this converted mesh to examine different
|
||||
// rotations
|
||||
TriangleMesh mesh = mo.raw_mesh();
|
||||
mesh.require_shared_vertices();
|
||||
TriangleMesh mesh = get_mesh_to_rotate(mo);
|
||||
|
||||
// To keep track of the number of iterations
|
||||
unsigned status = 0;
|
||||
|
@ -519,7 +519,7 @@ bool SupportTreeBuildsteps::create_ground_pillar(const Vec3d &hjp,
|
||||
auto [polar, azimuth] = dir_to_spheric(dir);
|
||||
polar = PI - m_cfg.bridge_slope;
|
||||
Vec3d d = spheric_to_dir(polar, azimuth).normalized();
|
||||
double t = bridge_mesh_distance(endp, dir, radius);
|
||||
double t = bridge_mesh_distance(endp, d, radius);
|
||||
double tmax = std::min(m_cfg.max_bridge_length_mm, t);
|
||||
t = 0.;
|
||||
|
||||
|
@ -303,13 +303,16 @@ void GLVolume::SinkingContours::render()
|
||||
|
||||
void GLVolume::SinkingContours::update()
|
||||
{
|
||||
if (m_parent.is_sinking() && !m_parent.is_below_printbed()) {
|
||||
int object_idx = m_parent.object_idx();
|
||||
Model& model = GUI::wxGetApp().plater()->model();
|
||||
|
||||
if (0 <= object_idx && object_idx < (int)model.objects.size() && m_parent.is_sinking() && !m_parent.is_below_printbed()) {
|
||||
const BoundingBoxf3& box = m_parent.transformed_convex_hull_bounding_box();
|
||||
if (!m_old_box.size().isApprox(box.size()) || m_old_box.min.z() != box.min.z()) {
|
||||
m_old_box = box;
|
||||
m_shift = Vec3d::Zero();
|
||||
|
||||
const TriangleMesh& mesh = GUI::wxGetApp().plater()->model().objects[m_parent.object_idx()]->volumes[m_parent.volume_idx()]->mesh();
|
||||
const TriangleMesh& mesh = model.objects[object_idx]->volumes[m_parent.volume_idx()]->mesh();
|
||||
assert(mesh.has_shared_vertices());
|
||||
|
||||
m_model.reset();
|
||||
|
@ -6373,7 +6373,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
|
||||
case EWarning::ObjectOutside: text = _u8L("An object outside the print area was detected."); break;
|
||||
case EWarning::ToolpathOutside: text = _u8L("A toolpath outside the print area was detected."); error = ErrorType::SLICING_ERROR; break;
|
||||
case EWarning::SlaSupportsOutside: text = _u8L("SLA supports outside the print area were detected."); error = ErrorType::PLATER_ERROR; break;
|
||||
case EWarning::SomethingNotShown: text = _u8L("Some objects are not visible."); break;
|
||||
case EWarning::SomethingNotShown: text = _u8L("Some objects are not visible during editing."); break;
|
||||
case EWarning::ObjectClashed:
|
||||
text = _u8L("An object outside the print area was detected.\n"
|
||||
"Resolve the current problem to continue slicing.");
|
||||
|
@ -1778,10 +1778,8 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
|
||||
del_layers_from_object(obj_idx);
|
||||
else if (type & itLayer && obj_idx != -1)
|
||||
del_layer_from_object(obj_idx, m_objects_model->GetLayerRangeByItem(item));
|
||||
else if (type & itInfo && obj_idx != -1) {
|
||||
Unselect(item);
|
||||
Select(parent);
|
||||
}
|
||||
else if (type & itInfo && obj_idx != -1)
|
||||
del_info_item(obj_idx, m_objects_model->GetInfoItemType(item));
|
||||
else if (idx == -1)
|
||||
return;
|
||||
else if (!del_subobject_from_object(obj_idx, idx, type))
|
||||
@ -1795,6 +1793,52 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
|
||||
update_info_items(obj_idx);
|
||||
}
|
||||
|
||||
void ObjectList::del_info_item(const int obj_idx, InfoItemType type)
|
||||
{
|
||||
Plater* plater = wxGetApp().plater();
|
||||
GLCanvas3D* cnv = plater->canvas3D();
|
||||
|
||||
switch (type) {
|
||||
case InfoItemType::CustomSupports:
|
||||
cnv->get_gizmos_manager().reset_all_states();
|
||||
Plater::TakeSnapshot(plater, _L("Remove paint-on supports"));
|
||||
for (ModelVolume* mv : (*m_objects)[obj_idx]->volumes)
|
||||
mv->supported_facets.clear();
|
||||
break;
|
||||
|
||||
case InfoItemType::CustomSeam:
|
||||
cnv->get_gizmos_manager().reset_all_states();
|
||||
Plater::TakeSnapshot(plater, _L("Remove paint-on seam"));
|
||||
for (ModelVolume* mv : (*m_objects)[obj_idx]->volumes)
|
||||
mv->seam_facets.clear();
|
||||
break;
|
||||
|
||||
case InfoItemType::MmuSegmentation:
|
||||
cnv->get_gizmos_manager().reset_all_states();
|
||||
Plater::TakeSnapshot(plater, _L("Remove Multi Material painting"));
|
||||
for (ModelVolume* mv : (*m_objects)[obj_idx]->volumes)
|
||||
mv->mmu_segmentation_facets.clear();
|
||||
break;
|
||||
|
||||
case InfoItemType::Sinking:
|
||||
Plater::TakeSnapshot(plater, _L("Shift objects to bed"));
|
||||
(*m_objects)[obj_idx]->ensure_on_bed();
|
||||
cnv->reload_scene(true, true);
|
||||
break;
|
||||
|
||||
case InfoItemType::VariableLayerHeight:
|
||||
Plater::TakeSnapshot(plater, _L("Remove variable layer height"));
|
||||
(*m_objects)[obj_idx]->layer_height_profile.clear();
|
||||
if (cnv->is_layers_editing_enabled())
|
||||
//cnv->post_event(SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING));
|
||||
cnv->force_main_toolbar_left_action(cnv->get_main_toolbar_item_id("layersediting"));
|
||||
break;
|
||||
|
||||
case InfoItemType::Undef : assert(false); break;
|
||||
}
|
||||
cnv->post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
|
||||
void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item)
|
||||
{
|
||||
const bool is_layer_settings = m_objects_model->GetItemType(parent_item) == itLayer;
|
||||
|
@ -254,6 +254,7 @@ public:
|
||||
void del_layer_from_object(const int obj_idx, const t_layer_height_range& layer_range);
|
||||
void del_layers_from_object(const int obj_idx);
|
||||
bool del_subobject_from_object(const int obj_idx, const int idx, const int type);
|
||||
void del_info_item(const int obj_idx, InfoItemType type);
|
||||
void split();
|
||||
void merge(bool to_multipart_object);
|
||||
void layers_editing();
|
||||
|
@ -789,8 +789,8 @@ void Preview::update_layers_slider_mode()
|
||||
return false;
|
||||
|
||||
for (ModelVolume* volume : object->volumes)
|
||||
if (volume->config.has("extruder") &&
|
||||
volume->config.option("extruder")->getInt() != extruder ||
|
||||
if ((volume->config.has("extruder") &&
|
||||
volume->config.option("extruder")->getInt() != extruder) ||
|
||||
!volume->mmu_segmentation_facets.empty())
|
||||
return false;
|
||||
|
||||
|
@ -55,8 +55,15 @@ std::string GLGizmoCut::on_get_name() const
|
||||
void GLGizmoCut::on_set_state()
|
||||
{
|
||||
// Reset m_cut_z on gizmo activation
|
||||
#if ENABLE_SINKING_CONTOURS
|
||||
if (get_state() == On) {
|
||||
m_cut_z = bounding_box().center().z();
|
||||
m_cut_contours.reset();
|
||||
}
|
||||
#else
|
||||
if (get_state() == On)
|
||||
m_cut_z = bounding_box().center().z();
|
||||
#endif // ENABLE_SINKING_CONTOURS
|
||||
}
|
||||
|
||||
bool GLGizmoCut::on_is_activable() const
|
||||
@ -209,8 +216,12 @@ void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit)
|
||||
|
||||
m_imgui->end();
|
||||
|
||||
if (cut_clicked && (m_keep_upper || m_keep_lower))
|
||||
if (cut_clicked && (m_keep_upper || m_keep_lower)) {
|
||||
perform_cut(m_parent.get_selection());
|
||||
#if ENABLE_SINKING_CONTOURS
|
||||
m_cut_contours.reset();
|
||||
#endif // ENABLE_SINKING_CONTOURS
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoCut::set_cut_z(double cut_z)
|
||||
@ -308,9 +319,8 @@ void GLGizmoCut::update_contours()
|
||||
m_cut_contours.contours.set_color(-1, { 1.0f, 1.0f, 1.0f, 1.0f });
|
||||
}
|
||||
}
|
||||
else if (box.center() != m_cut_contours.position) {
|
||||
else if (box.center() != m_cut_contours.position)
|
||||
m_cut_contours.shift = box.center() - m_cut_contours.position;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_cut_contours.contours.reset();
|
||||
|
@ -35,6 +35,16 @@ class GLGizmoCut : public GLGizmoBase
|
||||
Vec3d shift{ Vec3d::Zero() };
|
||||
int object_idx{ -1 };
|
||||
int instance_idx{ -1 };
|
||||
|
||||
void reset() {
|
||||
mesh.clear();
|
||||
contours.reset();
|
||||
cut_z = 0.0;
|
||||
position = Vec3d::Zero();
|
||||
shift = Vec3d::Zero();
|
||||
object_idx = -1;
|
||||
instance_idx = -1;
|
||||
}
|
||||
};
|
||||
|
||||
CutContours m_cut_contours;
|
||||
|
@ -497,9 +497,6 @@ void GLGizmoRotate3D::on_render()
|
||||
m_gizmos[Z].render();
|
||||
}
|
||||
|
||||
const char * GLGizmoRotate3D::RotoptimzeWindow::options[RotoptimizeJob::get_methods_count()];
|
||||
bool GLGizmoRotate3D::RotoptimzeWindow::options_valid = false;
|
||||
|
||||
GLGizmoRotate3D::RotoptimzeWindow::RotoptimzeWindow(ImGuiWrapper * imgui,
|
||||
State & state,
|
||||
const Alignment &alignment)
|
||||
@ -515,21 +512,26 @@ GLGizmoRotate3D::RotoptimzeWindow::RotoptimzeWindow(ImGuiWrapper * imgui,
|
||||
y = std::min(y, alignment.bottom_limit - win_h);
|
||||
ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always);
|
||||
|
||||
ImGui::PushItemWidth(200.f);
|
||||
ImGui::PushItemWidth(300.f);
|
||||
|
||||
size_t methods_cnt = RotoptimizeJob::get_methods_count();
|
||||
if (!options_valid) {
|
||||
for (size_t i = 0; i < methods_cnt; ++i)
|
||||
options[i] = RotoptimizeJob::get_method_names()[i].c_str();
|
||||
if (ImGui::BeginCombo(_L("Choose goal").c_str(), RotoptimizeJob::get_method_name(state.method_id).c_str())) {
|
||||
for (size_t i = 0; i < RotoptimizeJob::get_methods_count(); ++i) {
|
||||
if (ImGui::Selectable(RotoptimizeJob::get_method_name(i).c_str())) {
|
||||
state.method_id = i;
|
||||
wxGetApp().app_config->set("sla_auto_rotate",
|
||||
"method_id",
|
||||
std::to_string(state.method_id));
|
||||
}
|
||||
|
||||
options_valid = true;
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", RotoptimizeJob::get_method_description(i).c_str());
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
int citem = state.method_id;
|
||||
if (ImGui::Combo(_L("Choose goal").c_str(), &citem, options, methods_cnt) ) {
|
||||
state.method_id = citem;
|
||||
wxGetApp().app_config->set("sla_auto_rotate", "method_id", std::to_string(state.method_id));
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", RotoptimizeJob::get_method_description(state.method_id).c_str());
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
|
@ -138,10 +138,6 @@ private:
|
||||
|
||||
class RotoptimzeWindow {
|
||||
ImGuiWrapper *m_imgui = nullptr;
|
||||
|
||||
static const char * options [];
|
||||
static bool options_valid;
|
||||
|
||||
public:
|
||||
|
||||
struct State {
|
||||
|
@ -447,7 +447,8 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||
}
|
||||
|
||||
if (action == SLAGizmoEventType::DiscardChanges) {
|
||||
editing_mode_discard_changes();
|
||||
ask_about_changes_call_after([this](){ editing_mode_apply_changes(); },
|
||||
[this](){ editing_mode_discard_changes(); });
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -879,6 +880,22 @@ CommonGizmosDataID GLGizmoSlaSupports::on_get_requirements() const
|
||||
|
||||
|
||||
|
||||
void GLGizmoSlaSupports::ask_about_changes_call_after(std::function<void()> on_yes, std::function<void()> on_no)
|
||||
{
|
||||
wxGetApp().CallAfter([this, on_yes, on_no]() {
|
||||
// Following is called through CallAfter, because otherwise there was a problem
|
||||
// on OSX with the wxMessageDialog being shown several times when clicked into.
|
||||
MessageDialog dlg(GUI::wxGetApp().mainframe, _L("Do you want to save your manually "
|
||||
"edited support points?") + "\n",_L("Save support points?"), wxICON_QUESTION | wxYES | wxNO | wxCANCEL );
|
||||
int ret = dlg.ShowModal();
|
||||
if (ret == wxID_YES)
|
||||
on_yes();
|
||||
else if (ret == wxID_NO)
|
||||
on_no();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoSlaSupports::on_set_state()
|
||||
{
|
||||
if (m_state == m_old_state)
|
||||
@ -901,18 +918,8 @@ void GLGizmoSlaSupports::on_set_state()
|
||||
if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off
|
||||
bool will_ask = m_editing_mode && unsaved_changes() && on_is_activable();
|
||||
if (will_ask) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
// Following is called through CallAfter, because otherwise there was a problem
|
||||
// on OSX with the wxMessageDialog being shown several times when clicked into.
|
||||
//wxMessageDialog dlg(GUI::wxGetApp().mainframe, _L("Do you want to save your manually "
|
||||
MessageDialog dlg(GUI::wxGetApp().mainframe, _L("Do you want to save your manually "
|
||||
"edited support points?") + "\n",_L("Save support points?"), wxICON_QUESTION | wxYES | wxNO | wxCANCEL );
|
||||
int ret = dlg.ShowModal();
|
||||
if (ret == wxID_YES)
|
||||
editing_mode_apply_changes();
|
||||
else if (ret == wxID_NO)
|
||||
editing_mode_discard_changes();
|
||||
});
|
||||
ask_about_changes_call_after([this](){ editing_mode_apply_changes(); },
|
||||
[this](){ editing_mode_discard_changes(); });
|
||||
// refuse to be turned off so the gizmo is active when the CallAfter is executed
|
||||
m_state = m_old_state;
|
||||
}
|
||||
|
@ -117,6 +117,7 @@ private:
|
||||
void auto_generate();
|
||||
void switch_to_editing_mode();
|
||||
void disable_editing_mode();
|
||||
void ask_about_changes_call_after(std::function<void()> on_yes, std::function<void()> on_no);
|
||||
|
||||
protected:
|
||||
void on_set_state() override;
|
||||
|
@ -15,14 +15,21 @@ class RotoptimizeJob : public PlaterJob
|
||||
using FindFn = std::function<Vec2d(const ModelObject & mo,
|
||||
const sla::RotOptimizeParams ¶ms)>;
|
||||
|
||||
struct FindMethod { std::string name; FindFn findfn; };
|
||||
struct FindMethod { std::string name; FindFn findfn; std::string descr; };
|
||||
|
||||
static inline const FindMethod Methods[] = {
|
||||
{ L("Best surface quality"), sla::find_best_misalignment_rotation },
|
||||
{ L("Least supports"), sla::find_least_supports_rotation },
|
||||
// Just a min area bounding box that is done for all methods anyway.
|
||||
{ L("Z axis only"), nullptr }
|
||||
};
|
||||
static inline const FindMethod Methods[]
|
||||
= {{L("Best surface quality"),
|
||||
sla::find_best_misalignment_rotation,
|
||||
L("Optimize object rotation for best surface quality.")},
|
||||
{L("Reduced overhang slopes"),
|
||||
sla::find_least_supports_rotation,
|
||||
L("Optimize object rotation to have minimum amount of overhangs needing support "
|
||||
"structures.\nNote that this method will try to find the best surface of the object "
|
||||
"for touching the print bed if no elevation is set.")},
|
||||
// Just a min area bounding box that is done for all methods anyway.
|
||||
{L("Smallest bounding box (Z axis only)"),
|
||||
nullptr,
|
||||
L("Rotate the object only in Z axis to have the smallest bounding box.")}};
|
||||
|
||||
size_t m_method_id = 0;
|
||||
float m_accuracy = 0.75;
|
||||
@ -52,20 +59,15 @@ public:
|
||||
void finalize() override;
|
||||
|
||||
static constexpr size_t get_methods_count() { return std::size(Methods); }
|
||||
static const auto & get_method_names()
|
||||
|
||||
static std::string get_method_name(size_t i)
|
||||
{
|
||||
static bool m_method_names_valid = false;
|
||||
static std::array<std::string, std::size(Methods)> m_method_names;
|
||||
return _utf8(Methods[i].name);
|
||||
}
|
||||
|
||||
if (!m_method_names_valid) {
|
||||
|
||||
for (size_t i = 0; i < std::size(Methods); ++i)
|
||||
m_method_names[i] = _utf8(Methods[i].name);
|
||||
|
||||
m_method_names_valid = true;
|
||||
}
|
||||
|
||||
return m_method_names;
|
||||
static std::string get_method_description(size_t i)
|
||||
{
|
||||
return _utf8(Methods[i].descr);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1141,7 +1141,7 @@ void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type
|
||||
if (!node ||
|
||||
node->GetIdx() <-1 ||
|
||||
( node->GetIdx() == -1 &&
|
||||
!(node->GetType() & (itObject | itSettings | itInstanceRoot | itLayerRoot/* | itLayer*/))
|
||||
!(node->GetType() & (itObject | itSettings | itInstanceRoot | itLayerRoot | itInfo))
|
||||
)
|
||||
)
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user