mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-31 13:31:58 +08:00
Merge branch 'master' of https://github.com/Prusa-Development/PrusaSlicerPrivate into et_picking_parts_fix
This commit is contained in:
commit
a0f1b0313a
7
.github/ISSUE_TEMPLATE/config.yml
vendored
7
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,7 +1,10 @@
|
||||
contact_links:
|
||||
- name: PrusaSlicer Manual and Support
|
||||
- name: Do you need Support?
|
||||
url: https://www.prusa3d.com/page/prusaslicer-support-form_233563/
|
||||
about: If you are not sure whether what you are reporting is a bug, please contact our support team first. We are providing full 24/7 customer support.
|
||||
- name: PrusaSlicer Manual
|
||||
url: https://help.prusa3d.com/en/article/customer-support_2287/
|
||||
about: If you are not sure that what you are reporting is really a bug, please, consult the manual first.
|
||||
about: We have a comprehensive customer support page and help documentation that could be helpful for troubleshooting.
|
||||
- name: PrusaPrinters Forum
|
||||
url: https://forum.prusaprinters.org/forum/prusaslicer/
|
||||
about: Please get in touch on our PrusaPrinters Community Forum! (Not an official support channel.)
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,5 @@
|
||||
min_slic3r_version = 2.6.0-alpha5
|
||||
1.0.1 General rework. Fix start gcodes.
|
||||
min_slic3r_version = 2.6.0-alpha0
|
||||
1.0.0 Initial Rigid3D bundle
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
name = Rigid3D
|
||||
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
||||
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
||||
config_version = 1.0.0
|
||||
config_version = 1.0.1
|
||||
# Where to get the updates from?
|
||||
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Rigid3D/
|
||||
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
|
||||
@ -64,7 +64,7 @@ bridge_angle = 0
|
||||
bridge_flow_ratio = 1
|
||||
bridge_speed = 60
|
||||
brim_separation = 0
|
||||
brim_type = no_brim
|
||||
brim_type = outer_only
|
||||
brim_width = 0
|
||||
clip_multipart_objects = 1
|
||||
compatible_printers =
|
||||
@ -75,19 +75,19 @@ dont_support_bridges = 1
|
||||
draft_shield = disabled
|
||||
elefant_foot_compensation = 0
|
||||
ensure_vertical_shell_thickness = 0
|
||||
external_perimeter_extrusion_width = 0.45
|
||||
external_perimeter_extrusion_width = 0
|
||||
external_perimeter_speed = 50%
|
||||
external_perimeters_first = 1
|
||||
extra_perimeters = 1
|
||||
extruder_clearance_height = 20
|
||||
extruder_clearance_radius = 20
|
||||
extrusion_width = 0.45
|
||||
extrusion_width = 0
|
||||
fill_angle = 45
|
||||
fill_density = 10%
|
||||
fill_pattern = line
|
||||
first_layer_acceleration = 0
|
||||
first_layer_acceleration_over_raft = 0
|
||||
first_layer_extrusion_width = 0.42
|
||||
first_layer_extrusion_width = 0
|
||||
first_layer_height = 0.2
|
||||
first_layer_speed = 50%
|
||||
first_layer_speed_over_raft = 30
|
||||
@ -105,8 +105,8 @@ infill_anchor = 2.5
|
||||
infill_anchor_max = 12
|
||||
infill_every_layers = 1
|
||||
infill_extruder = 1
|
||||
infill_extrusion_width = 0.45
|
||||
infill_first = 1
|
||||
infill_extrusion_width = 0
|
||||
infill_first = 0
|
||||
infill_only_where_needed = 0
|
||||
infill_overlap = 25%
|
||||
infill_speed = 60
|
||||
@ -124,11 +124,11 @@ mmu_segmented_region_max_width = 0
|
||||
notes =
|
||||
only_retract_when_crossing_perimeters = 0
|
||||
ooze_prevention = 0
|
||||
output_filename_format = {input_filename_base}_{layer_height}mm_{initial_filament_type}_{printer_model}_{print_time}.gcode
|
||||
output_filename_format = {input_filename_base}_{layer_height}mm_{initial_filament_type}_{printer_model}.gcode
|
||||
overhangs = 1
|
||||
perimeter_acceleration = 0
|
||||
perimeter_extruder = 1
|
||||
perimeter_extrusion_width = 0.45
|
||||
perimeter_extrusion_width = 0
|
||||
perimeter_speed = 60
|
||||
perimeters = 2
|
||||
post_process =
|
||||
@ -139,7 +139,7 @@ raft_first_layer_density = 90%
|
||||
raft_first_layer_expansion = 3
|
||||
raft_layers = 0
|
||||
resolution = 0
|
||||
seam_position = rear
|
||||
seam_position = random
|
||||
single_extruder_multi_material_priming = 1
|
||||
skirt_distance = 6
|
||||
skirt_height = 1
|
||||
@ -147,14 +147,14 @@ skirts = 0
|
||||
slice_closing_radius = 0.049
|
||||
slicing_mode = regular
|
||||
small_perimeter_speed = 15
|
||||
solid_infill_below_area = 70
|
||||
solid_infill_below_area = 0
|
||||
solid_infill_every_layers = 0
|
||||
solid_infill_extruder = 1
|
||||
solid_infill_extrusion_width = 0.45
|
||||
solid_infill_extrusion_width = 0
|
||||
solid_infill_speed = 100%
|
||||
spiral_vase = 0
|
||||
standby_temperature_delta = -5
|
||||
support_material = 0
|
||||
support_material = 1
|
||||
support_material_angle = 0
|
||||
support_material_auto = 1
|
||||
support_material_bottom_contact_distance = 0
|
||||
@ -164,7 +164,7 @@ support_material_closing_radius = 2
|
||||
support_material_contact_distance = 0.2
|
||||
support_material_enforce_layers = 0
|
||||
support_material_extruder = 1
|
||||
support_material_extrusion_width = 0.35
|
||||
support_material_extrusion_width = 0
|
||||
support_material_interface_contact_loops = 0
|
||||
support_material_interface_extruder = 1
|
||||
support_material_interface_layers = 3
|
||||
@ -174,7 +174,7 @@ support_material_interface_speed = 100%
|
||||
support_material_pattern = rectilinear
|
||||
support_material_spacing = 2.5
|
||||
support_material_speed = 60
|
||||
support_material_style = grid
|
||||
support_material_style = organic
|
||||
support_material_synchronize_layers = 0
|
||||
support_material_threshold = 0
|
||||
support_material_with_sheath = 1
|
||||
@ -182,7 +182,7 @@ support_material_xy_spacing = 50%
|
||||
thick_bridges = 0
|
||||
thin_walls = 1
|
||||
top_fill_pattern = monotonic
|
||||
top_infill_extrusion_width = 0.4
|
||||
top_infill_extrusion_width = 0
|
||||
top_solid_infill_speed = 100%
|
||||
top_solid_min_thickness = 0.8
|
||||
travel_speed = 80
|
||||
@ -408,7 +408,7 @@ pause_print_gcode = M0
|
||||
printer_settings_id =
|
||||
printer_technology = FFF
|
||||
printer_variant = 0.4
|
||||
remaining_times = 1
|
||||
remaining_times = 0
|
||||
retract_before_travel = 2
|
||||
retract_before_wipe = 0%
|
||||
retract_layer_change = 0
|
||||
@ -438,7 +438,7 @@ bed_shape = 0x0,200x0,200x200,0x200
|
||||
max_print_height = 190
|
||||
printer_model = Zero2
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_RIGID3D\nPRINTER_MODEL_ZERO2\nPRINTER_HAS_HEATEDBED\n
|
||||
start_gcode = G21\nG92 E0\nG28\nM420 S1\nM107\nG90\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X190.0 Y0.1 Z0.3 F1500.0 E15\nG1 X190 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E30\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
start_gcode = G21\nG92 E0\nM140 S[first_layer_bed_temperature]\nM104 S[first_layer_temperature]\nG28\nM420 S1\nM107\nG90\nM190 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X190.0 Y0.1 Z0.3 F1500.0 E15\nG1 X190 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E30\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
end_gcode = G1 X0 Y180\nM107\nG91\nG0 Z20\nT0\nG1 E-1\nM104 T0 S0\nG90\nG92 E0\nM140 S0\nM84\nM300 S2093 P150\nM300 S2637 P150\nM300 S3135 P150\nM300 S4186 P150\nM300 S3135 P150\nM300 S2637 P150\nM300 S2793 P150\nM300 S2349 P150\nM300 S1975 P150\nM300 S2093 P450\n
|
||||
|
||||
[printer:Rigid3D Zero3]
|
||||
@ -447,7 +447,7 @@ bed_shape = 0x0,200x0,200x200,0x200
|
||||
max_print_height = 200
|
||||
printer_model = Zero3
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_RIGID3D\nPRINTER_MODEL_ZERO3\nPRINTER_HAS_HEATEDBED\n
|
||||
start_gcode = G21\nG92 E0\nG28\nM420 S1\nM107\nG90\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X190.0 Y0.1 Z0.3 F1500.0 E15\nG1 X190 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E30\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
start_gcode = G21\nG92 E0\nM140 S[first_layer_bed_temperature]\nM104 S[first_layer_temperature]\nG28\nM420 S1\nM107\nG90\nM190 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X190.0 Y0.1 Z0.3 F1500.0 E15\nG1 X190 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E30\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
end_gcode = G92 E0\nT0\nG1 F1800 E-2\nG27 P2\nM107\nM104 T0 S0\nM140 S0\nG90\nG92 E0\nM18\n
|
||||
|
||||
[printer:Rigid3D Mucit]
|
||||
@ -456,7 +456,7 @@ bed_shape = 0x0,150x0,150x150,0x150
|
||||
max_print_height = 150
|
||||
printer_model = Mucit
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_RIGID3D\nPRINTER_MODEL_MUCIT\n
|
||||
start_gcode = G21\nG92 E0\nG28\nM420 S1\nM107\nG90\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X140.0 Y0.1 Z0.3 F1500.0 E10\nG1 X140 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E20\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
start_gcode = G21\nG92 E0\nM140 S[first_layer_bed_temperature]\nM104 S[first_layer_temperature]\nG28\nM420 S1\nM107\nG90\nM190 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X140.0 Y0.1 Z0.3 F1500.0 E10\nG1 X140 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E20\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
end_gcode = G1 X0 Y140\nM107\nG91\nG0 Z20\nT0\nG1 E-2\nM104 T0 S0\nG90\nG92 E0\nM140 S0\nM84\nM300 S2093 P150\nM300 S2637 P150\nM300 S3135 P150\nM300 S4186 P150\nM300 S3135 P150\nM300 S2637 P150\nM300 S2793 P150\nM300 S2349 P150\nM300 S1975 P150\nM300 S2093 P450\n
|
||||
|
||||
[printer:Rigid3D Mucit2]
|
||||
@ -465,5 +465,5 @@ bed_shape = 0x0,150x0,150x150,0x150
|
||||
max_print_height = 150
|
||||
printer_model = Mucit2
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_RIGID3D\nPRINTER_MODEL_MUCIT2\nPRINTER_HAS_HEATEDBED\n
|
||||
start_gcode = G21\nG92 E0\nG28\nM420 S1\nM107\nG90\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X140.0 Y0.1 Z0.3 F1500.0 E10\nG1 X140 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E20\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
start_gcode = G21\nG92 E0\nM140 S[first_layer_bed_temperature]\nM104 S[first_layer_temperature]\nG28\nM420 S1\nM107\nG90\nM190 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X140.0 Y0.1 Z0.3 F1500.0 E10\nG1 X140 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E20\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
end_gcode = G92 E0\nT0\nG1 F1800 E-2\nG27 P2\nM107\nM104 T0 S0\nM140 S0\nG90\nG92 E0\nM18\n
|
||||
|
@ -51,7 +51,7 @@ void remove_bad(ExPolygons &expolygons);
|
||||
|
||||
// helpr for heal shape
|
||||
// Return true when erase otherwise false
|
||||
bool remove_same_neighbor(Points &points);
|
||||
bool remove_same_neighbor(Polygon &points);
|
||||
bool remove_same_neighbor(Polygons &polygons);
|
||||
bool remove_same_neighbor(ExPolygons &expolygons);
|
||||
|
||||
@ -272,14 +272,22 @@ void priv::remove_bad(ExPolygons &expolygons) {
|
||||
remove_bad(expolygon.holes);
|
||||
}
|
||||
|
||||
bool priv::remove_same_neighbor(Slic3r::Points &points)
|
||||
bool priv::remove_same_neighbor(Slic3r::Polygon &polygon)
|
||||
{
|
||||
Points &points = polygon.points;
|
||||
if (points.empty()) return false;
|
||||
auto last = std::unique(points.begin(), points.end());
|
||||
if (last == points.end()) return false;
|
||||
|
||||
// remove first and last neighbor duplication
|
||||
if (const Point& last_point = *(last - 1);
|
||||
last_point == points.front()) {
|
||||
--last;
|
||||
}
|
||||
|
||||
// no duplicits
|
||||
if (last == points.end()) return false;
|
||||
|
||||
points.erase(last, points.end());
|
||||
// clear points without area
|
||||
if (points.size() <= 2) points.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -287,34 +295,30 @@ bool priv::remove_same_neighbor(Polygons &polygons) {
|
||||
if (polygons.empty()) return false;
|
||||
bool exist = false;
|
||||
for (Polygon& polygon : polygons)
|
||||
exist |= remove_same_neighbor(polygon.points);
|
||||
exist |= remove_same_neighbor(polygon);
|
||||
// remove empty polygons
|
||||
polygons.erase(
|
||||
std::remove_if(polygons.begin(), polygons.end(),
|
||||
[](const Polygon &p) { return p.empty(); }),
|
||||
[](const Polygon &p) { return p.points.size() <= 2; }),
|
||||
polygons.end());
|
||||
return exist;
|
||||
}
|
||||
|
||||
bool priv::remove_same_neighbor(ExPolygons &expolygons) {
|
||||
if(expolygons.empty()) return false;
|
||||
bool exist = false;
|
||||
bool remove_from_holes = false;
|
||||
bool remove_from_contour = false;
|
||||
for (ExPolygon &expoly : expolygons) {
|
||||
exist |= remove_same_neighbor(expoly.contour.points);
|
||||
Polygons &holes = expoly.holes;
|
||||
for (Polygon &hole : holes)
|
||||
exist |= remove_same_neighbor(hole.points);
|
||||
holes.erase(
|
||||
std::remove_if(holes.begin(), holes.end(),
|
||||
[](const Polygon &p) { return p.size() < 3; }),
|
||||
holes.end());
|
||||
remove_from_contour |= remove_same_neighbor(expoly.contour);
|
||||
remove_from_holes |= remove_same_neighbor(expoly.holes);
|
||||
}
|
||||
|
||||
// Removing of point could create polygon with less than 3 points
|
||||
if (exist)
|
||||
remove_bad(expolygons);
|
||||
|
||||
return exist;
|
||||
// Removing of expolygons without contour
|
||||
if (remove_from_contour)
|
||||
expolygons.erase(
|
||||
std::remove_if(expolygons.begin(), expolygons.end(),
|
||||
[](const ExPolygon &p) { return p.contour.points.size() <=2; }),
|
||||
expolygons.end());
|
||||
return remove_from_holes || remove_from_contour;
|
||||
}
|
||||
|
||||
Points priv::collect_close_points(const ExPolygons &expolygons, double distance) {
|
||||
@ -502,9 +506,9 @@ bool priv::remove_self_intersections(ExPolygons &shape, unsigned max_iteration)
|
||||
hole.translate(p);
|
||||
holes.push_back(hole);
|
||||
}
|
||||
// union overlapped holes
|
||||
if (holes.size() > 1)
|
||||
holes = Slic3r::union_(holes);
|
||||
// Union of overlapped holes is not neccessary
|
||||
// Clipper calculate winding number separately for each input parameter
|
||||
// if (holes.size() > 1) holes = Slic3r::union_(holes);
|
||||
shape = Slic3r::diff_ex(shape, holes, ApplySafetyOffset::Yes);
|
||||
|
||||
// TODO: find where diff ex could create same neighbor
|
||||
@ -630,7 +634,6 @@ bool priv::heal_dupl_inter(ExPolygons &shape, unsigned max_iteration)
|
||||
holes.push_back(hole);
|
||||
}
|
||||
|
||||
holes = Slic3r::union_(holes);
|
||||
shape = Slic3r::diff_ex(shape, holes, ApplySafetyOffset::Yes);
|
||||
|
||||
// prepare for next loop
|
||||
|
@ -975,7 +975,7 @@ namespace Slic3r {
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
add_error("Error while extracting model data from zip archive");
|
||||
add_error("Error while extracting model data from ZIP archive");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -119,10 +119,14 @@ namespace Slic3r {
|
||||
// we assume that heating is always slower than cooling, so no need to block
|
||||
gcode += gcodegen.writer().set_temperature
|
||||
(this->_get_temp(gcodegen) + gcodegen.config().standby_temperature_delta.value, false, extruder_id);
|
||||
gcode.pop_back();
|
||||
gcode += " ;cooldown\n"; // this is a marker for GCodeProcessor, so it can supress the commands when needed
|
||||
}
|
||||
} else {
|
||||
// Use the value from filament settings. That one is absolute, not delta.
|
||||
gcode += gcodegen.writer().set_temperature(filament_idle_temp.get_at(extruder_id), false, extruder_id);
|
||||
gcode.pop_back();
|
||||
gcode += " ;cooldown\n"; // this is a marker for GCodeProcessor, so it can supress the commands when needed
|
||||
}
|
||||
|
||||
return gcode;
|
||||
|
@ -441,6 +441,9 @@ void GCodeProcessorResult::reset() {
|
||||
max_print_height = 0.0f;
|
||||
settings_ids.reset();
|
||||
extruders_count = 0;
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
backtrace_enabled = false;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
extruder_colors = std::vector<std::string>();
|
||||
filament_diameters = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
|
||||
filament_densities = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
|
||||
@ -458,6 +461,9 @@ void GCodeProcessorResult::reset() {
|
||||
max_print_height = 0.0f;
|
||||
settings_ids.reset();
|
||||
extruders_count = 0;
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
backtrace_enabled = false;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
extruder_colors = std::vector<std::string>();
|
||||
filament_diameters = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
|
||||
filament_densities = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
|
||||
@ -551,6 +557,10 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
m_producer = EProducer::PrusaSlicer;
|
||||
m_flavor = config.gcode_flavor;
|
||||
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
m_result.backtrace_enabled = is_XL_printer(config);
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
size_t extruders_count = config.nozzle_diameter.values.size();
|
||||
m_result.extruders_count = extruders_count;
|
||||
|
||||
@ -560,10 +570,15 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
m_result.filament_densities.resize(extruders_count);
|
||||
m_result.filament_cost.resize(extruders_count);
|
||||
m_extruder_temps.resize(extruders_count);
|
||||
m_extruder_temps_config.resize(extruders_count);
|
||||
m_extruder_temps_first_layer_config.resize(extruders_count);
|
||||
m_is_XL_printer = is_XL_printer(config);
|
||||
|
||||
for (size_t i = 0; i < extruders_count; ++ i) {
|
||||
m_extruder_offsets[i] = to_3d(config.extruder_offset.get_at(i).cast<float>().eval(), 0.f);
|
||||
m_extruder_colors[i] = static_cast<unsigned char>(i);
|
||||
m_extruder_temps_config[i] = static_cast<int>(config.temperature.get_at(i));
|
||||
m_extruder_temps_first_layer_config[i] = static_cast<int>(config.first_layer_temperature.get_at(i));
|
||||
m_result.filament_diameters[i] = static_cast<float>(config.filament_diameter.get_at(i));
|
||||
m_result.filament_densities[i] = static_cast<float>(config.filament_density.get_at(i));
|
||||
m_result.filament_cost[i] = static_cast<float>(config.filament_cost.get_at(i));
|
||||
@ -3461,18 +3476,261 @@ void GCodeProcessor::post_process()
|
||||
last_exported_stop[i] = time_in_minutes(m_time_processor.machines[i].time);
|
||||
}
|
||||
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
// Helper class to modify and export gcode to file
|
||||
class ExportLines
|
||||
{
|
||||
public:
|
||||
struct Backtrace
|
||||
{
|
||||
float time{ 60.0f };
|
||||
unsigned int steps{ 10 };
|
||||
float time_step() const { return time / float(steps); }
|
||||
};
|
||||
|
||||
enum class EWriteType
|
||||
{
|
||||
BySize,
|
||||
ByTime
|
||||
};
|
||||
|
||||
private:
|
||||
struct LineData
|
||||
{
|
||||
std::string line;
|
||||
float time;
|
||||
};
|
||||
|
||||
#ifndef NDEBUG
|
||||
class Statistics
|
||||
{
|
||||
ExportLines& m_parent;
|
||||
size_t m_max_size{ 0 };
|
||||
size_t m_lines_count{ 0 };
|
||||
size_t m_max_lines_count{ 0 };
|
||||
|
||||
public:
|
||||
explicit Statistics(ExportLines& parent)
|
||||
: m_parent(parent)
|
||||
{}
|
||||
|
||||
void add_line(size_t line_size) {
|
||||
++m_lines_count;
|
||||
m_max_size = std::max(m_max_size, m_parent.get_size() + line_size);
|
||||
m_max_lines_count = std::max(m_max_lines_count, m_lines_count);
|
||||
}
|
||||
|
||||
void remove_line() { --m_lines_count; }
|
||||
void remove_all_lines() { m_lines_count = 0; }
|
||||
};
|
||||
|
||||
Statistics m_statistics;
|
||||
#endif // NDEBUG
|
||||
|
||||
EWriteType m_write_type{ EWriteType::BySize };
|
||||
// Time machine containing g1 times cache
|
||||
TimeMachine& m_machine;
|
||||
// Current time
|
||||
float m_time{ 0.0f };
|
||||
// Current size in bytes
|
||||
size_t m_size{ 0 };
|
||||
|
||||
// gcode lines cache
|
||||
std::deque<LineData> m_lines;
|
||||
size_t m_added_lines_counter{ 0 };
|
||||
// map of gcode line ids from original to final
|
||||
// used to update m_result.moves[].gcode_id
|
||||
std::vector<std::pair<size_t, size_t>> m_gcode_lines_map;
|
||||
|
||||
size_t m_curr_g1_id{ 0 };
|
||||
size_t m_out_file_pos{ 0 };
|
||||
|
||||
public:
|
||||
ExportLines(EWriteType type, TimeMachine& machine)
|
||||
#ifndef NDEBUG
|
||||
: m_statistics(*this), m_write_type(type), m_machine(machine) {}
|
||||
#else
|
||||
: m_write_type(type), m_machine(machine) {}
|
||||
#endif // NDEBUG
|
||||
|
||||
void update(size_t lines_counter, size_t g1_lines_counter) {
|
||||
m_gcode_lines_map.push_back({ lines_counter, 0 });
|
||||
|
||||
if (g1_lines_counter == 0)
|
||||
return;
|
||||
|
||||
auto init_it = m_machine.g1_times_cache.begin() + m_curr_g1_id;
|
||||
auto it = init_it;
|
||||
while (it != m_machine.g1_times_cache.end() && it->id < g1_lines_counter + 1) {
|
||||
++it;
|
||||
++m_curr_g1_id;
|
||||
}
|
||||
|
||||
if (it != init_it || m_curr_g1_id == 0)
|
||||
m_time = it->elapsed_time;
|
||||
}
|
||||
|
||||
// add the given gcode line to the cache
|
||||
void append_line(const std::string& line) {
|
||||
m_lines.push_back({ line, m_time });
|
||||
#ifndef NDEBUG
|
||||
m_statistics.add_line(line.length());
|
||||
#endif // NDEBUG
|
||||
m_size += line.length();
|
||||
++m_added_lines_counter;
|
||||
assert(!m_gcode_lines_map.empty());
|
||||
m_gcode_lines_map.back().second = m_added_lines_counter;
|
||||
}
|
||||
|
||||
// Insert the gcode lines required by the command cmd by backtracing into the cache
|
||||
void insert_lines(const Backtrace& backtrace, const std::string& cmd, std::function<std::string(unsigned int, float, float)> line_inserter,
|
||||
std::function<std::string(const std::string&)> line_replacer) {
|
||||
assert(!m_lines.empty());
|
||||
const float time_step = backtrace.time_step();
|
||||
size_t rev_it_dist = 0; // distance from the end of the cache of the starting point of the backtrace
|
||||
float last_time_insertion = 0.0f; // used to avoid inserting two lines at the same time
|
||||
for (unsigned int i = 0; i < backtrace.steps; ++i) {
|
||||
const float backtrace_time_i = (i + 1) * time_step;
|
||||
const float time_threshold_i = m_time - backtrace_time_i;
|
||||
auto rev_it = m_lines.rbegin() + rev_it_dist;
|
||||
auto start_rev_it = rev_it;
|
||||
|
||||
// backtrace into the cache to find the place where to insert the line
|
||||
while (rev_it != m_lines.rend() && rev_it->time > time_threshold_i && GCodeReader::GCodeLine::extract_cmd(rev_it->line) != cmd) {
|
||||
rev_it->line = line_replacer(rev_it->line);
|
||||
++rev_it;
|
||||
}
|
||||
|
||||
// we met the previous evenience of cmd. stop inserting lines
|
||||
if (rev_it != m_lines.rend() && GCodeReader::GCodeLine::extract_cmd(rev_it->line) == cmd)
|
||||
break;
|
||||
|
||||
// insert the line for the current step
|
||||
if (rev_it != m_lines.rend() && rev_it != start_rev_it && rev_it->time != last_time_insertion) {
|
||||
last_time_insertion = rev_it->time;
|
||||
const std::string out_line = line_inserter(i + 1, last_time_insertion, m_time - last_time_insertion);
|
||||
rev_it_dist = std::distance(m_lines.rbegin(), rev_it) + 1;
|
||||
const auto new_it = m_lines.insert(rev_it.base(), { out_line, rev_it->time });
|
||||
#ifndef NDEBUG
|
||||
m_statistics.add_line(out_line.length());
|
||||
#endif // NDEBUG
|
||||
m_size += out_line.length();
|
||||
// synchronize gcode lines map
|
||||
for (auto map_it = m_gcode_lines_map.rbegin(); map_it != m_gcode_lines_map.rbegin() + rev_it_dist - 1; ++map_it) {
|
||||
++map_it->second;
|
||||
}
|
||||
|
||||
++m_added_lines_counter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write to file:
|
||||
// m_write_type == EWriteType::ByTime - all lines older than m_time - backtrace_time
|
||||
// m_write_type == EWriteType::BySize - all lines if current size is greater than 65535 bytes
|
||||
void write(FilePtr& out, float backtrace_time, GCodeProcessorResult& result, const std::string& out_path) {
|
||||
if (m_lines.empty())
|
||||
return;
|
||||
|
||||
// collect lines to write into a single string
|
||||
std::string out_string;
|
||||
if (!m_lines.empty()) {
|
||||
if (m_write_type == EWriteType::ByTime) {
|
||||
while (m_lines.front().time < m_time - backtrace_time) {
|
||||
const LineData& data = m_lines.front();
|
||||
out_string += data.line;
|
||||
m_size -= data.line.length();
|
||||
m_lines.pop_front();
|
||||
#ifndef NDEBUG
|
||||
m_statistics.remove_line();
|
||||
#endif // NDEBUG
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (m_size > 65535) {
|
||||
while (!m_lines.empty()) {
|
||||
out_string += m_lines.front().line;
|
||||
m_lines.pop_front();
|
||||
}
|
||||
m_size = 0;
|
||||
#ifndef NDEBUG
|
||||
m_statistics.remove_all_lines();
|
||||
#endif // NDEBUG
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
write_to_file(out, out_string, result, out_path);
|
||||
}
|
||||
|
||||
// flush the current content of the cache to file
|
||||
void flush(FilePtr& out, GCodeProcessorResult& result, const std::string& out_path) {
|
||||
// collect lines to flush into a single string
|
||||
std::string out_string;
|
||||
while (!m_lines.empty()) {
|
||||
out_string += m_lines.front().line;
|
||||
m_lines.pop_front();
|
||||
}
|
||||
m_size = 0;
|
||||
#ifndef NDEBUG
|
||||
m_statistics.remove_all_lines();
|
||||
#endif // NDEBUG
|
||||
|
||||
write_to_file(out, out_string, result, out_path);
|
||||
}
|
||||
|
||||
void synchronize_moves(GCodeProcessorResult& result) const {
|
||||
auto it = m_gcode_lines_map.begin();
|
||||
for (GCodeProcessorResult::MoveVertex& move : result.moves) {
|
||||
while (it != m_gcode_lines_map.end() && it->first < move.gcode_id) {
|
||||
++it;
|
||||
}
|
||||
if (it != m_gcode_lines_map.end() && it->first == move.gcode_id)
|
||||
move.gcode_id = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
size_t get_size() const { return m_size; }
|
||||
|
||||
private:
|
||||
void write_to_file(FilePtr& out, const std::string& out_string, GCodeProcessorResult& result, const std::string& out_path) {
|
||||
if (!out_string.empty()) {
|
||||
fwrite((const void*)out_string.c_str(), 1, out_string.length(), out.f);
|
||||
if (ferror(out.f)) {
|
||||
out.close();
|
||||
boost::nowide::remove(out_path.c_str());
|
||||
throw Slic3r::RuntimeError(std::string("GCode processor post process export failed.\nIs the disk full?\n"));
|
||||
}
|
||||
for (size_t i = 0; i < out_string.size(); ++i) {
|
||||
if (out_string[i] == '\n')
|
||||
result.lines_ends.emplace_back(m_out_file_pos + i + 1);
|
||||
}
|
||||
m_out_file_pos += out_string.size();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ExportLines export_lines(m_result.backtrace_enabled ? ExportLines::EWriteType::ByTime : ExportLines::EWriteType::BySize, m_time_processor.machines[0]);
|
||||
#else
|
||||
// buffer line to export only when greater than 64K to reduce writing calls
|
||||
std::string export_line;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
// replace placeholder lines with the proper final value
|
||||
// gcode_line is in/out parameter, to reduce expensive memory allocation
|
||||
auto process_placeholders = [&](std::string& gcode_line) {
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
bool processed = false;
|
||||
#else
|
||||
unsigned int extra_lines_count = 0;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
// remove trailing '\n'
|
||||
auto line = std::string_view(gcode_line).substr(0, gcode_line.length() - 1);
|
||||
|
||||
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
std::string ret;
|
||||
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
if (line.length() > 1) {
|
||||
line = line.substr(1);
|
||||
if (m_time_processor.export_remaining_time_enabled &&
|
||||
@ -3481,17 +3739,29 @@ void GCodeProcessor::post_process()
|
||||
const TimeMachine& machine = m_time_processor.machines[i];
|
||||
if (machine.enabled) {
|
||||
// export pair <percent, remaining time>
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.append_line(format_line_M73_main(machine.line_m73_main_mask.c_str(),
|
||||
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? 0 : 100,
|
||||
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? time_in_minutes(machine.time) : 0));
|
||||
processed = true;
|
||||
#else
|
||||
ret += format_line_M73_main(machine.line_m73_main_mask.c_str(),
|
||||
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? 0 : 100,
|
||||
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? time_in_minutes(machine.time) : 0);
|
||||
++extra_lines_count;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
// export remaining time to next printer stop
|
||||
if (line == reserved_tag(ETags::First_Line_M73_Placeholder) && !machine.stop_times.empty()) {
|
||||
int to_export_stop = time_in_minutes(machine.stop_times.front().elapsed_time);
|
||||
const int to_export_stop = time_in_minutes(machine.stop_times.front().elapsed_time);
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop));
|
||||
last_exported_stop[i] = to_export_stop;
|
||||
#else
|
||||
ret += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop);
|
||||
last_exported_stop[i] = to_export_stop;
|
||||
++extra_lines_count;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3505,7 +3775,12 @@ void GCodeProcessor::post_process()
|
||||
sprintf(buf, "; estimated printing time (%s mode) = %s\n",
|
||||
(mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent",
|
||||
get_time_dhms(machine.time).c_str());
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.append_line(buf);
|
||||
processed = true;
|
||||
#else
|
||||
ret += buf;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||
@ -3516,16 +3791,25 @@ void GCodeProcessor::post_process()
|
||||
sprintf(buf, "; estimated first layer printing time (%s mode) = %s\n",
|
||||
(mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent",
|
||||
get_time_dhms(machine.layers_time.empty() ? 0.f : machine.layers_time.front()).c_str());
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.append_line(buf);
|
||||
processed = true;
|
||||
#else
|
||||
ret += buf;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
return processed;
|
||||
#else
|
||||
if (!ret.empty())
|
||||
// Not moving the move operator on purpose, so that the gcode_line allocation will grow and it will not be reallocated after handful of lines are processed.
|
||||
gcode_line = ret;
|
||||
return std::tuple(!ret.empty(), (extra_lines_count == 0) ? extra_lines_count : extra_lines_count - 1);
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
};
|
||||
|
||||
std::vector<double> filament_mm(m_result.extruders_count, 0.0);
|
||||
@ -3599,10 +3883,16 @@ void GCodeProcessor::post_process()
|
||||
time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute,
|
||||
// Caches, to be modified
|
||||
&g1_times_cache_it, &last_exported_main, &last_exported_stop,
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
&export_lines]
|
||||
#else
|
||||
// String output
|
||||
&export_line]
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
(const size_t g1_lines_counter) {
|
||||
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
unsigned int exported_lines_count = 0;
|
||||
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
if (m_time_processor.export_remaining_time_enabled) {
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||
const TimeMachine& machine = m_time_processor.machines[i];
|
||||
@ -3616,10 +3906,17 @@ void GCodeProcessor::post_process()
|
||||
std::pair<int, int> to_export_main = { int(100.0f * it->elapsed_time / machine.time),
|
||||
time_in_minutes(machine.time - it->elapsed_time) };
|
||||
if (last_exported_main[i] != to_export_main) {
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.append_line(format_line_M73_main(machine.line_m73_main_mask.c_str(),
|
||||
to_export_main.first, to_export_main.second));
|
||||
#else
|
||||
export_line += format_line_M73_main(machine.line_m73_main_mask.c_str(),
|
||||
to_export_main.first, to_export_main.second);
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
last_exported_main[i] = to_export_main;
|
||||
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
++exported_lines_count;
|
||||
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
}
|
||||
// export remaining time to next printer stop
|
||||
auto it_stop = std::upper_bound(machine.stop_times.begin(), machine.stop_times.end(), it->elapsed_time,
|
||||
@ -3629,9 +3926,15 @@ void GCodeProcessor::post_process()
|
||||
if (last_exported_stop[i] != to_export_stop) {
|
||||
if (to_export_stop > 0) {
|
||||
if (last_exported_stop[i] != to_export_stop) {
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop));
|
||||
#else
|
||||
export_line += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop);
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
last_exported_stop[i] = to_export_stop;
|
||||
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
++exported_lines_count;
|
||||
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -3650,13 +3953,22 @@ void GCodeProcessor::post_process()
|
||||
}
|
||||
|
||||
if (is_last) {
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
if (std::distance(machine.stop_times.begin(), it_stop) == static_cast<ptrdiff_t>(machine.stop_times.size() - 1))
|
||||
export_lines.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop));
|
||||
else
|
||||
export_lines.append_line(format_line_M73_stop_float(machine.line_m73_stop_mask.c_str(), time_in_last_minute(it_stop->elapsed_time - it->elapsed_time)));
|
||||
#else
|
||||
if (std::distance(machine.stop_times.begin(), it_stop) == static_cast<ptrdiff_t>(machine.stop_times.size() - 1))
|
||||
export_line += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop);
|
||||
else
|
||||
export_line += format_line_M73_stop_float(machine.line_m73_stop_mask.c_str(), time_in_last_minute(it_stop->elapsed_time - it->elapsed_time));
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
last_exported_stop[i] = to_export_stop;
|
||||
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
++exported_lines_count;
|
||||
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3665,12 +3977,50 @@ void GCodeProcessor::post_process()
|
||||
}
|
||||
}
|
||||
}
|
||||
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
return exported_lines_count;
|
||||
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
};
|
||||
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
// add lines XXX to exported gcode
|
||||
auto process_line_T = [this, &export_lines](const std::string& gcode_line, const size_t g1_lines_counter, const ExportLines::Backtrace& backtrace) {
|
||||
const std::string cmd = GCodeReader::GCodeLine::extract_cmd(gcode_line);
|
||||
if (cmd.size() >= 2) {
|
||||
std::stringstream ss(cmd.substr(1));
|
||||
int tool_number = -1;
|
||||
ss >> tool_number;
|
||||
if (tool_number != -1)
|
||||
export_lines.insert_lines(backtrace, cmd,
|
||||
// line inserter
|
||||
[tool_number, this](unsigned int id, float time, float time_diff) {
|
||||
int temperature = int( m_layer_id != 1 ? m_extruder_temps_config[tool_number] : m_extruder_temps_first_layer_config[tool_number]);
|
||||
const std::string out = "M104 T" + std::to_string(tool_number) + " P" + std::to_string(int(std::round(time_diff))) + " S" + std::to_string(temperature) + "\n";
|
||||
return out;
|
||||
},
|
||||
// line replacer
|
||||
[this, tool_number](const std::string& line) {
|
||||
if (GCodeReader::GCodeLine::cmd_is(line, "M104")) {
|
||||
GCodeReader::GCodeLine gline;
|
||||
GCodeReader reader;
|
||||
reader.parse_line(line, [&gline](GCodeReader& reader, const GCodeReader::GCodeLine& l) { gline = l; });
|
||||
|
||||
float val;
|
||||
if (gline.has_value('T', val) && gline.raw().find("cooldown") != std::string::npos && m_is_XL_printer) {
|
||||
if (static_cast<int>(val) == tool_number)
|
||||
return std::string("; removed M104\n");
|
||||
}
|
||||
}
|
||||
return line;
|
||||
});
|
||||
}
|
||||
};
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
m_result.lines_ends.clear();
|
||||
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
// helper function to write to disk
|
||||
size_t out_file_pos = 0;
|
||||
m_result.lines_ends.clear();
|
||||
auto write_string = [this, &export_line, &out, &out_path, &out_file_pos](const std::string& str) {
|
||||
fwrite((const void*)export_line.c_str(), 1, export_line.length(), out.f);
|
||||
if (ferror(out.f)) {
|
||||
@ -3684,9 +4034,18 @@ void GCodeProcessor::post_process()
|
||||
out_file_pos += export_line.size();
|
||||
export_line.clear();
|
||||
};
|
||||
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
unsigned int line_id = 0;
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
// Backtrace data for Tx gcode lines
|
||||
static const ExportLines::Backtrace backtrace_T = { 120.0f, 10 };
|
||||
// In case there are multiple sources of backtracing, keeps track of the longest backtrack time needed
|
||||
// to flush the backtrace cache accordingly
|
||||
float max_backtrace_time = 120.0f;
|
||||
#else
|
||||
std::vector<std::pair<unsigned int, unsigned int>> offsets;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
{
|
||||
// Read the input stream 64kB at a time, extract lines and process them.
|
||||
@ -3710,14 +4069,39 @@ void GCodeProcessor::post_process()
|
||||
gcode_line.insert(gcode_line.end(), it, it_end);
|
||||
if (eol) {
|
||||
++line_id;
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.update(line_id, g1_lines_counter);
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
gcode_line += "\n";
|
||||
// replace placeholder lines
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
bool processed = process_placeholders(gcode_line);
|
||||
if (processed)
|
||||
gcode_line.clear();
|
||||
#else
|
||||
auto [processed, lines_added_count] = process_placeholders(gcode_line);
|
||||
if (processed && lines_added_count > 0)
|
||||
offsets.push_back({ line_id, lines_added_count });
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
if (!processed)
|
||||
processed = process_used_filament(gcode_line);
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
if (!processed && !is_temporary_decoration(gcode_line)) {
|
||||
if (GCodeReader::GCodeLine::cmd_is(gcode_line, "G1"))
|
||||
// add lines M73 where needed
|
||||
process_line_G1(g1_lines_counter++);
|
||||
else if (m_result.backtrace_enabled && GCodeReader::GCodeLine::cmd_starts_with(gcode_line, "T")) {
|
||||
// add lines XXX where needed
|
||||
process_line_T(gcode_line, g1_lines_counter, backtrace_T);
|
||||
max_backtrace_time = std::max(max_backtrace_time, backtrace_T.time);
|
||||
}
|
||||
}
|
||||
|
||||
if (!gcode_line.empty())
|
||||
export_lines.append_line(gcode_line);
|
||||
export_lines.write(out, 1.1f * max_backtrace_time, m_result, out_path);
|
||||
#else
|
||||
if (!processed && !is_temporary_decoration(gcode_line) && GCodeReader::GCodeLine::cmd_is(gcode_line, "G1")) {
|
||||
// remove temporary lines, add lines M73 where needed
|
||||
unsigned int extra_lines_count = process_line_G1(g1_lines_counter++);
|
||||
@ -3728,6 +4112,7 @@ void GCodeProcessor::post_process()
|
||||
export_line += gcode_line;
|
||||
if (export_line.length() > 65535)
|
||||
write_string(export_line);
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
gcode_line.clear();
|
||||
}
|
||||
// Skip EOL.
|
||||
@ -3742,12 +4127,19 @@ void GCodeProcessor::post_process()
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.flush(out, m_result, out_path);
|
||||
#else
|
||||
if (!export_line.empty())
|
||||
write_string(export_line);
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
out.close();
|
||||
in.close();
|
||||
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.synchronize_moves(m_result);
|
||||
#else
|
||||
// updates moves' gcode ids which have been modified by the insertion of the M73 lines
|
||||
unsigned int curr_offset_id = 0;
|
||||
unsigned int total_offset = 0;
|
||||
@ -3758,6 +4150,7 @@ void GCodeProcessor::post_process()
|
||||
}
|
||||
move.gcode_id += total_offset;
|
||||
}
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
if (rename_file(out_path, m_result.filename))
|
||||
throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + m_result.filename + '\n' +
|
||||
@ -3908,6 +4301,8 @@ void GCodeProcessor::set_travel_acceleration(PrintEstimatedStatistics::ETimeMode
|
||||
|
||||
float GCodeProcessor::get_filament_load_time(size_t extruder_id)
|
||||
{
|
||||
if (m_is_XL_printer)
|
||||
return 4.5f; // FIXME
|
||||
return (m_time_processor.filament_load_times.empty() || m_time_processor.extruder_unloaded) ?
|
||||
0.0f :
|
||||
((extruder_id < m_time_processor.filament_load_times.size()) ?
|
||||
@ -3916,6 +4311,8 @@ float GCodeProcessor::get_filament_load_time(size_t extruder_id)
|
||||
|
||||
float GCodeProcessor::get_filament_unload_time(size_t extruder_id)
|
||||
{
|
||||
if (m_is_XL_printer)
|
||||
return 0.f; // FIXME
|
||||
return (m_time_processor.filament_unload_times.empty() || m_time_processor.extruder_unloaded) ?
|
||||
0.0f :
|
||||
((extruder_id < m_time_processor.filament_unload_times.size()) ?
|
||||
|
@ -125,6 +125,9 @@ namespace Slic3r {
|
||||
float max_print_height;
|
||||
SettingsIds settings_ids;
|
||||
size_t extruders_count;
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
bool backtrace_enabled;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
std::vector<std::string> extruder_colors;
|
||||
std::vector<float> filament_diameters;
|
||||
std::vector<float> filament_densities;
|
||||
@ -543,6 +546,9 @@ namespace Slic3r {
|
||||
unsigned char m_extruder_id;
|
||||
ExtruderColors m_extruder_colors;
|
||||
ExtruderTemps m_extruder_temps;
|
||||
ExtruderTemps m_extruder_temps_config;
|
||||
ExtruderTemps m_extruder_temps_first_layer_config;
|
||||
bool m_is_XL_printer = false;
|
||||
float m_parking_position;
|
||||
float m_extra_loading_move;
|
||||
float m_extruded_last_z;
|
||||
|
@ -1346,6 +1346,36 @@ std::pair<double, double> WipeTower::get_wipe_tower_cone_base(double width, doub
|
||||
return std::make_pair(R, support_scale);
|
||||
}
|
||||
|
||||
// Static method to extract wipe_volumes[from][to] from the configuration.
|
||||
std::vector<std::vector<float>> WipeTower::extract_wipe_volumes(const PrintConfig& config)
|
||||
{
|
||||
// Get wiping matrix to get number of extruders and convert vector<double> to vector<float>:
|
||||
std::vector<float> wiping_matrix(cast<float>(config.wiping_volumes_matrix.values));
|
||||
|
||||
// The values shall only be used when SEMM is enabled. The purging for other printers
|
||||
// is determined by filament_minimal_purge_on_wipe_tower.
|
||||
if (! config.single_extruder_multi_material.value)
|
||||
std::fill(wiping_matrix.begin(), wiping_matrix.end(), 0.f);
|
||||
|
||||
// Extract purging volumes for each extruder pair:
|
||||
std::vector<std::vector<float>> wipe_volumes;
|
||||
const unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+EPSILON);
|
||||
for (unsigned int i = 0; i<number_of_extruders; ++i)
|
||||
wipe_volumes.push_back(std::vector<float>(wiping_matrix.begin()+i*number_of_extruders, wiping_matrix.begin()+(i+1)*number_of_extruders));
|
||||
|
||||
// Also include filament_minimal_purge_on_wipe_tower. This is needed for the preview.
|
||||
for (unsigned int i = 0; i<number_of_extruders; ++i) {
|
||||
for (unsigned int j = 0; j<number_of_extruders; ++j) {
|
||||
float w = wipe_volumes[i][j];
|
||||
|
||||
if (wipe_volumes[i][j] < config.filament_minimal_purge_on_wipe_tower.get_at(j))
|
||||
wipe_volumes[i][j] = config.filament_minimal_purge_on_wipe_tower.get_at(j);
|
||||
}
|
||||
}
|
||||
|
||||
return wipe_volumes;
|
||||
}
|
||||
|
||||
// Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box
|
||||
void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool,
|
||||
unsigned int new_tool, float wipe_volume)
|
||||
|
@ -22,8 +22,8 @@ class WipeTower
|
||||
{
|
||||
public:
|
||||
static const std::string never_skip_tag() { return "_GCODE_WIPE_TOWER_NEVER_SKIP_TAG"; }
|
||||
|
||||
static std::pair<double, double> get_wipe_tower_cone_base(double width, double height, double depth, double angle_deg);
|
||||
static std::vector<std::vector<float>> extract_wipe_volumes(const PrintConfig& config);
|
||||
|
||||
struct Extrusion
|
||||
{
|
||||
|
@ -71,6 +71,19 @@ public:
|
||||
return strncmp(cmd, cmd_test, len) == 0 && GCodeReader::is_end_of_word(cmd[len]);
|
||||
}
|
||||
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
static bool cmd_starts_with(const std::string& gcode_line, const char* cmd_test) {
|
||||
return strncmp(GCodeReader::skip_whitespaces(gcode_line.c_str()), cmd_test, strlen(cmd_test)) == 0;
|
||||
}
|
||||
|
||||
static std::string extract_cmd(const std::string& gcode_line) {
|
||||
GCodeLine temp;
|
||||
temp.m_raw = gcode_line;
|
||||
const std::string_view cmd = temp.cmd();
|
||||
return { cmd.begin(), cmd.end() };
|
||||
}
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
private:
|
||||
std::string m_raw;
|
||||
float m_axis[NUM_AXES];
|
||||
|
@ -395,7 +395,6 @@ Vec3d extract_rotation(const Transform3d& transform)
|
||||
return extract_rotation(m);
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Transform3d Transformation::get_offset_matrix() const
|
||||
{
|
||||
return translation_transform(get_offset());
|
||||
@ -461,57 +460,12 @@ Transform3d Transformation::get_rotation_matrix() const
|
||||
{
|
||||
return extract_rotation_matrix(m_matrix);
|
||||
}
|
||||
#else
|
||||
bool Transformation::Flags::needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
|
||||
{
|
||||
return (this->dont_translate != dont_translate) || (this->dont_rotate != dont_rotate) || (this->dont_scale != dont_scale) || (this->dont_mirror != dont_mirror);
|
||||
}
|
||||
|
||||
void Transformation::Flags::set(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror)
|
||||
{
|
||||
this->dont_translate = dont_translate;
|
||||
this->dont_rotate = dont_rotate;
|
||||
this->dont_scale = dont_scale;
|
||||
this->dont_mirror = dont_mirror;
|
||||
}
|
||||
|
||||
Transformation::Transformation()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
Transformation::Transformation(const Transform3d& transform)
|
||||
{
|
||||
set_from_transform(transform);
|
||||
}
|
||||
|
||||
void Transformation::set_offset(const Vec3d& offset)
|
||||
{
|
||||
set_offset(X, offset.x());
|
||||
set_offset(Y, offset.y());
|
||||
set_offset(Z, offset.z());
|
||||
}
|
||||
|
||||
void Transformation::set_offset(Axis axis, double offset)
|
||||
{
|
||||
if (m_offset(axis) != offset) {
|
||||
m_offset(axis) = offset;
|
||||
m_dirty = true;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void Transformation::set_rotation(const Vec3d& rotation)
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = rotation_transform(rotation) * extract_scale(m_matrix);
|
||||
m_matrix.translation() = offset;
|
||||
#else
|
||||
set_rotation(X, rotation.x());
|
||||
set_rotation(Y, rotation.y());
|
||||
set_rotation(Z, rotation.z());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void Transformation::set_rotation(Axis axis, double rotation)
|
||||
@ -520,7 +474,6 @@ void Transformation::set_rotation(Axis axis, double rotation)
|
||||
if (is_approx(std::abs(rotation), 2.0 * double(PI)))
|
||||
rotation = 0.0;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
auto [curr_rotation, scale] = extract_rotation_scale(m_matrix);
|
||||
Vec3d angles = extract_rotation(curr_rotation);
|
||||
angles[axis] = rotation;
|
||||
@ -528,15 +481,8 @@ void Transformation::set_rotation(Axis axis, double rotation)
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = rotation_transform(angles) * scale;
|
||||
m_matrix.translation() = offset;
|
||||
#else
|
||||
if (m_rotation(axis) != rotation) {
|
||||
m_rotation(axis) = rotation;
|
||||
m_dirty = true;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d Transformation::get_scaling_factor() const
|
||||
{
|
||||
const Transform3d scale = extract_scale(m_matrix);
|
||||
@ -551,26 +497,18 @@ Transform3d Transformation::get_scaling_factor_matrix() const
|
||||
scale(2, 2) = std::abs(scale(2, 2));
|
||||
return scale;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void Transformation::set_scaling_factor(const Vec3d& scaling_factor)
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
assert(scaling_factor.x() > 0.0 && scaling_factor.y() > 0.0 && scaling_factor.z() > 0.0);
|
||||
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = extract_rotation_matrix(m_matrix) * scale_transform(scaling_factor);
|
||||
m_matrix.translation() = offset;
|
||||
#else
|
||||
set_scaling_factor(X, scaling_factor.x());
|
||||
set_scaling_factor(Y, scaling_factor.y());
|
||||
set_scaling_factor(Z, scaling_factor.z());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void Transformation::set_scaling_factor(Axis axis, double scaling_factor)
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
assert(scaling_factor > 0.0);
|
||||
|
||||
auto [rotation, scale] = extract_rotation_scale(m_matrix);
|
||||
@ -579,15 +517,8 @@ void Transformation::set_scaling_factor(Axis axis, double scaling_factor)
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = rotation * scale;
|
||||
m_matrix.translation() = offset;
|
||||
#else
|
||||
if (m_scaling_factor(axis) != std::abs(scaling_factor)) {
|
||||
m_scaling_factor(axis) = std::abs(scaling_factor);
|
||||
m_dirty = true;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d Transformation::get_mirror() const
|
||||
{
|
||||
const Transform3d scale = extract_scale(m_matrix);
|
||||
@ -602,11 +533,9 @@ Transform3d Transformation::get_mirror_matrix() const
|
||||
scale(2, 2) = scale(2, 2) / std::abs(scale(2, 2));
|
||||
return scale;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void Transformation::set_mirror(const Vec3d& mirror)
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d copy(mirror);
|
||||
const Vec3d abs_mirror = copy.cwiseAbs();
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
@ -627,11 +556,6 @@ void Transformation::set_mirror(const Vec3d& mirror)
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = rotation * scale;
|
||||
m_matrix.translation() = offset;
|
||||
#else
|
||||
set_mirror(X, mirror.x());
|
||||
set_mirror(Y, mirror.y());
|
||||
set_mirror(Z, mirror.z());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void Transformation::set_mirror(Axis axis, double mirror)
|
||||
@ -642,7 +566,6 @@ void Transformation::set_mirror(Axis axis, double mirror)
|
||||
else if (abs_mirror != 1.0)
|
||||
mirror /= abs_mirror;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
auto [rotation, scale] = extract_rotation_scale(m_matrix);
|
||||
const double curr_scale = scale(axis, axis);
|
||||
const double sign = curr_scale * mirror;
|
||||
@ -652,74 +575,18 @@ void Transformation::set_mirror(Axis axis, double mirror)
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = rotation * scale;
|
||||
m_matrix.translation() = offset;
|
||||
#else
|
||||
if (m_mirror(axis) != mirror) {
|
||||
m_mirror(axis) = mirror;
|
||||
m_dirty = true;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
bool Transformation::has_skew() const
|
||||
{
|
||||
return contains_skew(m_matrix);
|
||||
}
|
||||
#else
|
||||
void Transformation::set_from_transform(const Transform3d& transform)
|
||||
{
|
||||
// offset
|
||||
set_offset(transform.matrix().block(0, 3, 3, 1));
|
||||
|
||||
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> m3x3 = transform.matrix().block(0, 0, 3, 3);
|
||||
|
||||
// mirror
|
||||
// it is impossible to reconstruct the original mirroring factors from a matrix,
|
||||
// we can only detect if the matrix contains a left handed reference system
|
||||
// in which case we reorient it back to right handed by mirroring the x axis
|
||||
Vec3d mirror = Vec3d::Ones();
|
||||
if (m3x3.col(0).dot(m3x3.col(1).cross(m3x3.col(2))) < 0.0) {
|
||||
mirror.x() = -1.0;
|
||||
// remove mirror
|
||||
m3x3.col(0) *= -1.0;
|
||||
}
|
||||
set_mirror(mirror);
|
||||
|
||||
// scale
|
||||
set_scaling_factor(Vec3d(m3x3.col(0).norm(), m3x3.col(1).norm(), m3x3.col(2).norm()));
|
||||
|
||||
// remove scale
|
||||
m3x3.col(0).normalize();
|
||||
m3x3.col(1).normalize();
|
||||
m3x3.col(2).normalize();
|
||||
|
||||
// rotation
|
||||
set_rotation(extract_rotation(m3x3));
|
||||
|
||||
// forces matrix recalculation matrix
|
||||
m_matrix = get_matrix();
|
||||
|
||||
// // debug check
|
||||
// if (!m_matrix.isApprox(transform))
|
||||
// std::cout << "something went wrong in extracting data from matrix" << std::endl;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void Transformation::reset()
|
||||
{
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
m_offset = Vec3d::Zero();
|
||||
m_rotation = Vec3d::Zero();
|
||||
m_scaling_factor = Vec3d::Ones();
|
||||
m_mirror = Vec3d::Ones();
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
m_matrix = Transform3d::Identity();
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
m_dirty = false;
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void Transformation::reset_rotation()
|
||||
{
|
||||
const Geometry::TransformationSVD svd(*this);
|
||||
@ -755,88 +622,12 @@ Transform3d Transformation::get_matrix_no_scaling_factor() const
|
||||
copy.reset_scaling_factor();
|
||||
return copy.get_matrix();
|
||||
}
|
||||
#else
|
||||
const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
|
||||
{
|
||||
if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror)) {
|
||||
m_matrix = Geometry::assemble_transform(
|
||||
dont_translate ? Vec3d::Zero() : m_offset,
|
||||
dont_rotate ? Vec3d::Zero() : m_rotation,
|
||||
dont_scale ? Vec3d::Ones() : m_scaling_factor,
|
||||
dont_mirror ? Vec3d::Ones() : m_mirror
|
||||
);
|
||||
|
||||
m_flags.set(dont_translate, dont_rotate, dont_scale, dont_mirror);
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
return m_matrix;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
Transformation Transformation::operator * (const Transformation& other) const
|
||||
{
|
||||
return Transformation(get_matrix() * other.get_matrix());
|
||||
}
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
Transformation Transformation::volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox)
|
||||
{
|
||||
Transformation out;
|
||||
|
||||
if (instance_transformation.is_scaling_uniform()) {
|
||||
// No need to run the non-linear least squares fitting for uniform scaling.
|
||||
// Just set the inverse.
|
||||
out.set_from_transform(instance_transformation.get_matrix(true).inverse());
|
||||
}
|
||||
else if (is_rotation_ninety_degrees(instance_transformation.get_rotation())) {
|
||||
// Anisotropic scaling, rotation by multiples of ninety degrees.
|
||||
Eigen::Matrix3d instance_rotation_trafo =
|
||||
(Eigen::AngleAxisd(instance_transformation.get_rotation().z(), Vec3d::UnitZ()) *
|
||||
Eigen::AngleAxisd(instance_transformation.get_rotation().y(), Vec3d::UnitY()) *
|
||||
Eigen::AngleAxisd(instance_transformation.get_rotation().x(), Vec3d::UnitX())).toRotationMatrix();
|
||||
Eigen::Matrix3d volume_rotation_trafo =
|
||||
(Eigen::AngleAxisd(-instance_transformation.get_rotation().x(), Vec3d::UnitX()) *
|
||||
Eigen::AngleAxisd(-instance_transformation.get_rotation().y(), Vec3d::UnitY()) *
|
||||
Eigen::AngleAxisd(-instance_transformation.get_rotation().z(), Vec3d::UnitZ())).toRotationMatrix();
|
||||
|
||||
// 8 corners of the bounding box.
|
||||
auto pts = Eigen::MatrixXd(8, 3);
|
||||
pts(0, 0) = bbox.min.x(); pts(0, 1) = bbox.min.y(); pts(0, 2) = bbox.min.z();
|
||||
pts(1, 0) = bbox.min.x(); pts(1, 1) = bbox.min.y(); pts(1, 2) = bbox.max.z();
|
||||
pts(2, 0) = bbox.min.x(); pts(2, 1) = bbox.max.y(); pts(2, 2) = bbox.min.z();
|
||||
pts(3, 0) = bbox.min.x(); pts(3, 1) = bbox.max.y(); pts(3, 2) = bbox.max.z();
|
||||
pts(4, 0) = bbox.max.x(); pts(4, 1) = bbox.min.y(); pts(4, 2) = bbox.min.z();
|
||||
pts(5, 0) = bbox.max.x(); pts(5, 1) = bbox.min.y(); pts(5, 2) = bbox.max.z();
|
||||
pts(6, 0) = bbox.max.x(); pts(6, 1) = bbox.max.y(); pts(6, 2) = bbox.min.z();
|
||||
pts(7, 0) = bbox.max.x(); pts(7, 1) = bbox.max.y(); pts(7, 2) = bbox.max.z();
|
||||
|
||||
// Corners of the bounding box transformed into the modifier mesh coordinate space, with inverse rotation applied to the modifier.
|
||||
auto qs = pts *
|
||||
(instance_rotation_trafo *
|
||||
Eigen::Scaling(instance_transformation.get_scaling_factor().cwiseProduct(instance_transformation.get_mirror())) *
|
||||
volume_rotation_trafo).inverse().transpose();
|
||||
// Fill in scaling based on least squares fitting of the bounding box corners.
|
||||
Vec3d scale;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
scale(i) = pts.col(i).dot(qs.col(i)) / pts.col(i).dot(pts.col(i));
|
||||
|
||||
out.set_rotation(Geometry::extract_rotation(volume_rotation_trafo));
|
||||
out.set_scaling_factor(Vec3d(std::abs(scale.x()), std::abs(scale.y()), std::abs(scale.z())));
|
||||
out.set_mirror(Vec3d(scale.x() > 0 ? 1. : -1, scale.y() > 0 ? 1. : -1, scale.z() > 0 ? 1. : -1));
|
||||
}
|
||||
else {
|
||||
// General anisotropic scaling, general rotation.
|
||||
// Keep the modifier mesh in the instance coordinate system, so the modifier mesh will not be aligned with the world.
|
||||
// Scale it to get the required size.
|
||||
out.set_scaling_factor(instance_transformation.get_scaling_factor().cwiseInverse());
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationSVD::TransformationSVD(const Transform3d& trafo)
|
||||
{
|
||||
const auto &m0 = trafo.matrix().block<3, 3>(0, 0);
|
||||
@ -883,7 +674,6 @@ TransformationSVD::TransformationSVD(const Transform3d& trafo)
|
||||
} else
|
||||
skew = false;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// For parsing a transformation matrix from 3MF / AMF.
|
||||
Transform3d transform3d_from_string(const std::string& transform_str)
|
||||
|
@ -383,32 +383,9 @@ Vec3d extract_rotation(const Transform3d& transform);
|
||||
|
||||
class Transformation
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Transform3d m_matrix{ Transform3d::Identity() };
|
||||
#else
|
||||
struct Flags
|
||||
{
|
||||
bool dont_translate{ true };
|
||||
bool dont_rotate{ true };
|
||||
bool dont_scale{ true };
|
||||
bool dont_mirror{ true };
|
||||
|
||||
bool needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const;
|
||||
void set(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror);
|
||||
};
|
||||
|
||||
Vec3d m_offset{ Vec3d::Zero() }; // In unscaled coordinates
|
||||
Vec3d m_rotation{ Vec3d::Zero() }; // Rotation around the three axes, in radians around mesh center point
|
||||
Vec3d m_scaling_factor{ Vec3d::Ones() }; // Scaling factors along the three axes
|
||||
Vec3d m_mirror{ Vec3d::Ones() }; // Mirroring along the three axes
|
||||
|
||||
mutable Transform3d m_matrix{ Transform3d::Identity() };
|
||||
mutable Flags m_flags;
|
||||
mutable bool m_dirty{ false };
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
public:
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Transformation() = default;
|
||||
explicit Transformation(const Transform3d& transform) : m_matrix(transform) {}
|
||||
|
||||
@ -424,26 +401,10 @@ public:
|
||||
double get_rotation(Axis axis) const { return get_rotation()[axis]; }
|
||||
|
||||
Transform3d get_rotation_matrix() const;
|
||||
#else
|
||||
Transformation();
|
||||
explicit Transformation(const Transform3d& transform);
|
||||
|
||||
const Vec3d& get_offset() const { return m_offset; }
|
||||
double get_offset(Axis axis) const { return m_offset(axis); }
|
||||
|
||||
void set_offset(const Vec3d& offset);
|
||||
void set_offset(Axis axis, double offset);
|
||||
|
||||
const Vec3d& get_rotation() const { return m_rotation; }
|
||||
double get_rotation(Axis axis) const { return m_rotation(axis); }
|
||||
|
||||
Transform3d get_rotation_matrix() const { return rotation_transform(get_rotation()); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void set_rotation(const Vec3d& rotation);
|
||||
void set_rotation(Axis axis, double rotation);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_scaling_factor() const;
|
||||
double get_scaling_factor(Axis axis) const { return get_scaling_factor()[axis]; }
|
||||
|
||||
@ -453,17 +414,10 @@ public:
|
||||
const Vec3d scale = get_scaling_factor();
|
||||
return std::abs(scale.x() - scale.y()) < 1e-8 && std::abs(scale.x() - scale.z()) < 1e-8;
|
||||
}
|
||||
#else
|
||||
const Vec3d& get_scaling_factor() const { return m_scaling_factor; }
|
||||
double get_scaling_factor(Axis axis) const { return m_scaling_factor(axis); }
|
||||
|
||||
Transform3d get_scaling_factor_matrix() const { return scale_transform(get_scaling_factor()); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void set_scaling_factor(const Vec3d& scaling_factor);
|
||||
void set_scaling_factor(Axis axis, double scaling_factor);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_mirror() const;
|
||||
double get_mirror(Axis axis) const { return get_mirror()[axis]; }
|
||||
|
||||
@ -472,25 +426,13 @@ public:
|
||||
bool is_left_handed() const {
|
||||
return m_matrix.linear().determinant() < 0;
|
||||
}
|
||||
#else
|
||||
bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; }
|
||||
|
||||
const Vec3d& get_mirror() const { return m_mirror; }
|
||||
double get_mirror(Axis axis) const { return m_mirror(axis); }
|
||||
bool is_left_handed() const { return m_mirror.x() * m_mirror.y() * m_mirror.z() < 0.; }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void set_mirror(const Vec3d& mirror);
|
||||
void set_mirror(Axis axis, double mirror);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
bool has_skew() const;
|
||||
#else
|
||||
void set_from_transform(const Transform3d& transform);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void reset();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void reset_offset() { set_offset(Vec3d::Zero()); }
|
||||
void reset_rotation();
|
||||
void reset_scaling_factor();
|
||||
@ -502,22 +444,11 @@ public:
|
||||
Transform3d get_matrix_no_scaling_factor() const;
|
||||
|
||||
void set_matrix(const Transform3d& transform) { m_matrix = transform; }
|
||||
#else
|
||||
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
Transformation operator * (const Transformation& other) const;
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
// Find volume transformation, so that the chained (instance_trafo * volume_trafo) will be as close to identity
|
||||
// as possible in least squares norm in regard to the 8 corners of bbox.
|
||||
// Bounding box is expected to be centered around zero in all axes.
|
||||
static Transformation volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox);
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
template<class Archive> void serialize(Archive& ar) { ar(m_matrix); }
|
||||
explicit Transformation(int) {}
|
||||
template <class Archive> static void load_and_construct(Archive& ar, cereal::construct<Transformation>& construct)
|
||||
@ -526,24 +457,13 @@ private:
|
||||
construct(1);
|
||||
ar(construct.ptr()->m_matrix);
|
||||
}
|
||||
#else
|
||||
template<class Archive> void serialize(Archive& ar) { ar(m_offset, m_rotation, m_scaling_factor, m_mirror); }
|
||||
explicit Transformation(int) : m_dirty(true) {}
|
||||
template <class Archive> static void load_and_construct(Archive& ar, cereal::construct<Transformation>& construct)
|
||||
{
|
||||
// Calling a private constructor with special "int" parameter to indicate that no construction is necessary.
|
||||
construct(1);
|
||||
ar(construct.ptr()->m_offset, construct.ptr()->m_rotation, construct.ptr()->m_scaling_factor, construct.ptr()->m_mirror);
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
};
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
struct TransformationSVD
|
||||
{
|
||||
Matrix3d u = Matrix3d::Identity();
|
||||
Matrix3d s = Matrix3d::Identity();
|
||||
Matrix3d v = Matrix3d::Identity();
|
||||
Matrix3d u{ Matrix3d::Identity() };
|
||||
Matrix3d s{ Matrix3d::Identity() };
|
||||
Matrix3d v{ Matrix3d::Identity() };
|
||||
|
||||
bool mirror{ false };
|
||||
bool scale{ false };
|
||||
@ -557,7 +477,6 @@ struct TransformationSVD
|
||||
|
||||
Eigen::DiagonalMatrix<double, 3, 3> mirror_matrix() const { return Eigen::DiagonalMatrix<double, 3, 3>(this->mirror ? -1. : 1., 1., 1.); }
|
||||
};
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// For parsing a transformation matrix from 3MF / AMF.
|
||||
extern Transform3d transform3d_from_string(const std::string& transform_str);
|
||||
|
@ -1030,11 +1030,7 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const
|
||||
if (this->instances.empty())
|
||||
throw Slic3r::InvalidArgument("Can't call raw_bounding_box() with no instances");
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d inst_matrix = this->instances.front()->get_transformation().get_matrix_no_offset();
|
||||
#else
|
||||
const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
for (const ModelVolume *v : this->volumes)
|
||||
if (v->is_model_part())
|
||||
m_raw_bounding_box.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
|
||||
@ -1046,14 +1042,10 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const
|
||||
BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_translate) const
|
||||
{
|
||||
BoundingBoxf3 bb;
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d inst_matrix = dont_translate ?
|
||||
this->instances[instance_idx]->get_transformation().get_matrix_no_offset() :
|
||||
this->instances[instance_idx]->get_transformation().get_matrix();
|
||||
|
||||
#else
|
||||
const Transform3d& inst_matrix = this->instances[instance_idx]->get_transformation().get_matrix(dont_translate);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
for (ModelVolume *v : this->volumes) {
|
||||
if (v->is_model_part())
|
||||
bb.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
|
||||
@ -1688,17 +1680,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, const Transform3d& cut_matrix,
|
||||
// in the transformation matrix and not applied to the mesh transform.
|
||||
|
||||
// const auto instance_matrix = instances[instance]->get_matrix(true);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const auto instance_matrix = instances[instance]->get_transformation().get_matrix_no_offset();
|
||||
#else
|
||||
const auto instance_matrix = assemble_transform(
|
||||
Vec3d::Zero(), // don't apply offset
|
||||
instances[instance]->get_rotation(),
|
||||
instances[instance]->get_scaling_factor(),
|
||||
instances[instance]->get_mirror()
|
||||
);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
const Transformation cut_transformation = Transformation(cut_matrix);
|
||||
const Transform3d inverse_cut_matrix = cut_transformation.get_rotation_matrix().inverse() * translation_transform(-1. * cut_transformation.get_offset());
|
||||
|
||||
@ -1840,11 +1822,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
||||
new_vol->config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||
|
||||
for (ModelInstance* model_instance : new_object->instances) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d shift = model_instance->get_transformation().get_matrix_no_offset() * new_vol->get_offset();
|
||||
#else
|
||||
Vec3d shift = model_instance->get_transformation().get_matrix(true) * new_vol->get_offset();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const Vec3d shift = model_instance->get_transformation().get_matrix_no_offset() * new_vol->get_offset();
|
||||
model_instance->set_offset(model_instance->get_offset() + shift);
|
||||
}
|
||||
|
||||
@ -1885,13 +1863,7 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
|
||||
{
|
||||
assert(instance_idx < this->instances.size());
|
||||
|
||||
const Geometry::Transformation reference_trafo = this->instances[instance_idx]->get_transformation();
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
if (Geometry::is_rotation_ninety_degrees(reference_trafo.get_rotation()))
|
||||
// nothing to do, scaling in the world coordinate space is possible in the representation of Geometry::Transformation.
|
||||
return;
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
const Geometry::Transformation reference_trafo = this->instances[instance_idx]->get_transformation();
|
||||
bool left_handed = reference_trafo.is_left_handed();
|
||||
bool has_mirrorring = ! reference_trafo.get_mirror().isApprox(Vec3d(1., 1., 1.));
|
||||
bool uniform_scaling = std::abs(reference_trafo.get_scaling_factor().x() - reference_trafo.get_scaling_factor().y()) < EPSILON &&
|
||||
@ -1908,7 +1880,6 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
|
||||
|
||||
// Adjust the meshes.
|
||||
// Transformation to be applied to the meshes.
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Geometry::Transformation reference_trafo_mod = reference_trafo;
|
||||
reference_trafo_mod.reset_offset();
|
||||
if (uniform_scaling)
|
||||
@ -1916,9 +1887,6 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
|
||||
if (!has_mirrorring)
|
||||
reference_trafo_mod.reset_mirror();
|
||||
Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo_mod.get_matrix().matrix().block<3, 3>(0, 0);
|
||||
#else
|
||||
Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo.get_matrix(true, false, uniform_scaling, ! has_mirrorring).matrix().block<3, 3>(0, 0);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
Transform3d volume_offset_correction = this->instances[instance_idx]->get_transformation().get_matrix().inverse() * reference_trafo.get_matrix();
|
||||
for (ModelVolume *model_volume : this->volumes) {
|
||||
const Geometry::Transformation volume_trafo = model_volume->get_transformation();
|
||||
@ -1928,7 +1896,6 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
|
||||
std::abs(volume_trafo.get_scaling_factor().x() - volume_trafo.get_scaling_factor().z()) < EPSILON;
|
||||
double volume_new_scaling_factor = volume_uniform_scaling ? volume_trafo.get_scaling_factor().x() : 1.;
|
||||
// Transform the mesh.
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Geometry::Transformation volume_trafo_mod = volume_trafo;
|
||||
volume_trafo_mod.reset_offset();
|
||||
if (volume_uniform_scaling)
|
||||
@ -1936,11 +1903,8 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
|
||||
if (!volume_has_mirrorring)
|
||||
volume_trafo_mod.reset_mirror();
|
||||
Eigen::Matrix3d volume_trafo_3x3 = volume_trafo_mod.get_matrix().matrix().block<3, 3>(0, 0);
|
||||
#else
|
||||
Matrix3d volume_trafo_3x3 = volume_trafo.get_matrix(true, false, volume_uniform_scaling, !volume_has_mirrorring).matrix().block<3, 3>(0, 0);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// Following method creates a new shared_ptr<TriangleMesh>
|
||||
model_volume->transform_this_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed);
|
||||
model_volume->transform_this_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed);
|
||||
// Reset the rotation, scaling and mirroring.
|
||||
model_volume->set_rotation(Vec3d(0., 0., 0.));
|
||||
model_volume->set_scaling_factor(Vec3d(volume_new_scaling_factor, volume_new_scaling_factor, volume_new_scaling_factor));
|
||||
@ -1959,11 +1923,7 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const
|
||||
double min_z = DBL_MAX;
|
||||
|
||||
const ModelInstance* inst = instances[instance_idx];
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d mi = inst->get_matrix_no_offset();
|
||||
#else
|
||||
const Transform3d& mi = inst->get_matrix(true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
for (const ModelVolume* v : volumes) {
|
||||
if (!v->is_model_part())
|
||||
@ -1984,11 +1944,7 @@ double ModelObject::get_instance_max_z(size_t instance_idx) const
|
||||
double max_z = -DBL_MAX;
|
||||
|
||||
const ModelInstance* inst = instances[instance_idx];
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d mi = inst->get_matrix_no_offset();
|
||||
#else
|
||||
const Transform3d& mi = inst->get_matrix(true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
for (const ModelVolume* v : volumes) {
|
||||
if (!v->is_model_part())
|
||||
@ -2428,29 +2384,17 @@ void ModelVolume::convert_from_meters()
|
||||
|
||||
void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
mesh->transform(dont_translate ? get_matrix_no_offset() : get_matrix());
|
||||
#else
|
||||
mesh->transform(get_matrix(dont_translate));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate) const
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
return bbox.transformed(dont_translate ? get_matrix_no_offset() : get_matrix());
|
||||
#else
|
||||
return bbox.transformed(get_matrix(dont_translate));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
Vec3d ModelInstance::transform_vector(const Vec3d& v, bool dont_translate) const
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
return dont_translate ? get_matrix_no_offset() * v : get_matrix() * v;
|
||||
#else
|
||||
return get_matrix(dont_translate) * v;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void ModelInstance::transform_polygon(Polygon* polygon) const
|
||||
|
@ -881,26 +881,16 @@ public:
|
||||
|
||||
const Geometry::Transformation& get_transformation() const { return m_transformation; }
|
||||
void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; }
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void set_transformation(const Transform3d& trafo) { m_transformation.set_matrix(trafo); }
|
||||
|
||||
Vec3d get_offset() const { return m_transformation.get_offset(); }
|
||||
#else
|
||||
void set_transformation(const Transform3d &trafo) { m_transformation.set_from_transform(trafo); }
|
||||
|
||||
const Vec3d& get_offset() const { return m_transformation.get_offset(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
double get_offset(Axis axis) const { return m_transformation.get_offset(axis); }
|
||||
|
||||
void set_offset(const Vec3d& offset) { m_transformation.set_offset(offset); }
|
||||
void set_offset(Axis axis, double offset) { m_transformation.set_offset(axis, offset); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_rotation() const { return m_transformation.get_rotation(); }
|
||||
#else
|
||||
const Vec3d& get_rotation() const { return m_transformation.get_rotation(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_rotation(Axis axis) const { return m_transformation.get_rotation(axis); }
|
||||
|
||||
void set_rotation(const Vec3d& rotation) { m_transformation.set_rotation(rotation); }
|
||||
@ -912,11 +902,7 @@ public:
|
||||
void set_scaling_factor(const Vec3d& scaling_factor) { m_transformation.set_scaling_factor(scaling_factor); }
|
||||
void set_scaling_factor(Axis axis, double scaling_factor) { m_transformation.set_scaling_factor(axis, scaling_factor); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_mirror() const { return m_transformation.get_mirror(); }
|
||||
#else
|
||||
const Vec3d& get_mirror() const { return m_transformation.get_mirror(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); }
|
||||
bool is_left_handed() const { return m_transformation.is_left_handed(); }
|
||||
|
||||
@ -925,12 +911,8 @@ public:
|
||||
void convert_from_imperial_units();
|
||||
void convert_from_meters();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d& get_matrix() const { return m_transformation.get_matrix(); }
|
||||
Transform3d get_matrix_no_offset() const { return m_transformation.get_matrix_no_offset(); }
|
||||
#else
|
||||
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void set_new_unique_id() {
|
||||
ObjectBase::set_new_unique_id();
|
||||
@ -1142,43 +1124,27 @@ public:
|
||||
const Geometry::Transformation& get_transformation() const { return m_transformation; }
|
||||
void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_offset() const { return m_transformation.get_offset(); }
|
||||
#else
|
||||
const Vec3d& get_offset() const { return m_transformation.get_offset(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_offset(Axis axis) const { return m_transformation.get_offset(axis); }
|
||||
|
||||
void set_offset(const Vec3d& offset) { m_transformation.set_offset(offset); }
|
||||
void set_offset(Axis axis, double offset) { m_transformation.set_offset(axis, offset); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_rotation() const { return m_transformation.get_rotation(); }
|
||||
#else
|
||||
const Vec3d& get_rotation() const { return m_transformation.get_rotation(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_rotation(Axis axis) const { return m_transformation.get_rotation(axis); }
|
||||
|
||||
void set_rotation(const Vec3d& rotation) { m_transformation.set_rotation(rotation); }
|
||||
void set_rotation(Axis axis, double rotation) { m_transformation.set_rotation(axis, rotation); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_scaling_factor() const { return m_transformation.get_scaling_factor(); }
|
||||
#else
|
||||
const Vec3d& get_scaling_factor() const { return m_transformation.get_scaling_factor(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_scaling_factor(Axis axis) const { return m_transformation.get_scaling_factor(axis); }
|
||||
|
||||
void set_scaling_factor(const Vec3d& scaling_factor) { m_transformation.set_scaling_factor(scaling_factor); }
|
||||
void set_scaling_factor(Axis axis, double scaling_factor) { m_transformation.set_scaling_factor(axis, scaling_factor); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_mirror() const { return m_transformation.get_mirror(); }
|
||||
#else
|
||||
const Vec3d& get_mirror() const { return m_transformation.get_mirror(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); }
|
||||
bool is_left_handed() const { return m_transformation.is_left_handed(); }
|
||||
bool is_left_handed() const { return m_transformation.is_left_handed(); }
|
||||
|
||||
void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); }
|
||||
void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); }
|
||||
@ -1192,12 +1158,8 @@ public:
|
||||
// To be called on an external polygon. It does not translate the polygon, only rotates and scales.
|
||||
void transform_polygon(Polygon* polygon) const;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d& get_matrix() const { return m_transformation.get_matrix(); }
|
||||
Transform3d get_matrix_no_offset() const { return m_transformation.get_matrix_no_offset(); }
|
||||
#else
|
||||
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
bool is_printable() const { return object->printable && printable && (print_volume_state == ModelInstancePVS_Inside); }
|
||||
|
||||
|
@ -1033,6 +1033,18 @@ std::tuple<std::vector<ExtrusionPaths>, Polygons> generate_extra_perimeters_over
|
||||
};
|
||||
if (!first_overhang_is_closed_and_anchored) {
|
||||
std::reverse(overhang_region.begin(), overhang_region.end());
|
||||
} else {
|
||||
size_t min_dist_idx = 0;
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
for (size_t i = 0; i < overhang_region.front().polyline.size(); i++) {
|
||||
Point p = overhang_region.front().polyline[i];
|
||||
if (double d = lower_layer_aabb_tree.distance_from_lines<true>(p) < min_dist) {
|
||||
min_dist = d;
|
||||
min_dist_idx = i;
|
||||
}
|
||||
}
|
||||
std::rotate(overhang_region.front().polyline.begin(), overhang_region.front().polyline.begin() + min_dist_idx,
|
||||
overhang_region.front().polyline.end());
|
||||
}
|
||||
auto first_unanchored = std::stable_partition(overhang_region.begin(), overhang_region.end(), is_anchored);
|
||||
int index_of_first_unanchored = first_unanchored - overhang_region.begin();
|
||||
|
@ -396,7 +396,6 @@ bool Print::sequential_print_horizontal_clearance_valid(const Print& print, Poly
|
||||
// FIXME: Arrangement has different parameters for offsetting (jtMiter, limit 2)
|
||||
// which causes that the warning will be showed after arrangement with the
|
||||
// appropriate object distance. Even if I set this to jtMiter the warning still shows up.
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Geometry::Transformation trafo = model_instance0->get_transformation();
|
||||
trafo.set_offset({ 0.0, 0.0, model_instance0->get_offset().z() });
|
||||
it_convex_hull = map_model_object_to_convex_hull.emplace_hint(it_convex_hull, model_object_id,
|
||||
@ -405,15 +404,6 @@ bool Print::sequential_print_horizontal_clearance_valid(const Print& print, Poly
|
||||
// exactly by satisfying the extruder_clearance_radius, this test will not trigger collision.
|
||||
float(scale_(0.5 * print.config().extruder_clearance_radius.value - BuildVolume::BedEpsilon)),
|
||||
jtRound, scale_(0.1)).front());
|
||||
#else
|
||||
it_convex_hull = map_model_object_to_convex_hull.emplace_hint(it_convex_hull, model_object_id,
|
||||
offset(print_object->model_object()->convex_hull_2d(
|
||||
Geometry::assemble_transform({ 0.0, 0.0, model_instance0->get_offset().z() }, model_instance0->get_rotation(), model_instance0->get_scaling_factor(), model_instance0->get_mirror())),
|
||||
// Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects
|
||||
// exactly by satisfying the extruder_clearance_radius, this test will not trigger collision.
|
||||
float(scale_(0.5 * print.config().extruder_clearance_radius.value - BuildVolume::BedEpsilon)),
|
||||
jtRound, scale_(0.1)).front());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
// Make a copy, so it may be rotated for instances.
|
||||
Polygon convex_hull0 = it_convex_hull->second;
|
||||
@ -1347,11 +1337,23 @@ const WipeTowerData& Print::wipe_tower_data(size_t extruders_cnt) const
|
||||
{
|
||||
// If the wipe tower wasn't created yet, make sure the depth and brim_width members are set to default.
|
||||
if (! is_step_done(psWipeTower) && extruders_cnt !=0) {
|
||||
const_cast<Print*>(this)->m_wipe_tower_data.brim_width = m_config.wipe_tower_brim_width;
|
||||
|
||||
// Calculating depth should take into account currently set wiping volumes.
|
||||
// For a long time, the initial preview would just use 900/width per toolchange (15mm on a 60mm wide tower)
|
||||
// and it worked well enough. Let's try to do slightly better by accounting for the purging volumes.
|
||||
std::vector<std::vector<float>> wipe_volumes = WipeTower::extract_wipe_volumes(m_config);
|
||||
std::vector<float> max_wipe_volumes;
|
||||
for (const std::vector<float>& v : wipe_volumes)
|
||||
max_wipe_volumes.emplace_back(*std::max_element(v.begin(), v.end()));
|
||||
float maximum = std::accumulate(max_wipe_volumes.begin(), max_wipe_volumes.end(), 0.f);
|
||||
maximum = maximum * extruders_cnt / max_wipe_volumes.size();
|
||||
|
||||
float width = float(m_config.wipe_tower_width);
|
||||
float layer_height = 0.2f; // just assume fixed value, it will still be better than before.
|
||||
|
||||
const_cast<Print*>(this)->m_wipe_tower_data.depth = (900.f/width) * float(extruders_cnt - 1);
|
||||
const_cast<Print*>(this)->m_wipe_tower_data.brim_width = m_config.wipe_tower_brim_width;
|
||||
const_cast<Print*>(this)->m_wipe_tower_data.depth = (maximum/layer_height)/width;
|
||||
const_cast<Print*>(this)->m_wipe_tower_data.height = -1.f; // unknown yet
|
||||
}
|
||||
|
||||
return m_wipe_tower_data;
|
||||
@ -1363,13 +1365,7 @@ void Print::_make_wipe_tower()
|
||||
if (! this->has_wipe_tower())
|
||||
return;
|
||||
|
||||
// Get wiping matrix to get number of extruders and convert vector<double> to vector<float>:
|
||||
std::vector<float> wiping_matrix(cast<float>(m_config.wiping_volumes_matrix.values));
|
||||
// Extract purging volumes for each extruder pair:
|
||||
std::vector<std::vector<float>> wipe_volumes;
|
||||
const unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+EPSILON);
|
||||
for (unsigned int i = 0; i<number_of_extruders; ++i)
|
||||
wipe_volumes.push_back(std::vector<float>(wiping_matrix.begin()+i*number_of_extruders, wiping_matrix.begin()+(i+1)*number_of_extruders));
|
||||
std::vector<std::vector<float>> wipe_volumes = WipeTower::extract_wipe_volumes(m_config);
|
||||
|
||||
// Let the ToolOrdering class know there will be initial priming extrusions at the start of the print.
|
||||
m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, true);
|
||||
@ -1422,7 +1418,7 @@ void Print::_make_wipe_tower()
|
||||
//wipe_tower.set_zhop();
|
||||
|
||||
// Set the extruder & material properties at the wipe tower object.
|
||||
for (size_t i = 0; i < number_of_extruders; ++ i)
|
||||
for (size_t i = 0; i < m_config.nozzle_diameter.size(); ++ i)
|
||||
wipe_tower.set_extruder(i, m_config);
|
||||
|
||||
m_wipe_tower_data.priming = Slic3r::make_unique<std::vector<WipeTower::ToolChangeResult>>(
|
||||
|
@ -791,13 +791,8 @@ void update_volume_bboxes(
|
||||
if (it != volumes_old.end() && it->volume_id == model_volume->id())
|
||||
layer_range.volumes.emplace_back(*it);
|
||||
} else
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
layer_range.volumes.push_back({ model_volume->id(),
|
||||
transformed_its_bbox2d(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix()), offset) });
|
||||
#else
|
||||
layer_range.volumes.push_back({ model_volume->id(),
|
||||
transformed_its_bbox2d(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix(false)), offset) });
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
} else {
|
||||
std::vector<std::vector<PrintObjectRegions::VolumeExtents>> volumes_old;
|
||||
@ -829,11 +824,7 @@ void update_volume_bboxes(
|
||||
layer_range.volumes.emplace_back(*it);
|
||||
}
|
||||
} else {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
transformed_its_bboxes_in_z_ranges(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix()), ranges, bboxes, offset);
|
||||
#else
|
||||
transformed_its_bboxes_in_z_ranges(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix(false)), ranges, bboxes, offset);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
for (PrintObjectRegions::LayerRangeRegions &layer_range : layer_ranges)
|
||||
if (auto &bbox = bboxes[&layer_range - layer_ranges.data()]; bbox.second)
|
||||
layer_range.volumes.push_back({ model_volume->id(), bbox.first });
|
||||
|
@ -584,8 +584,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionBools{false});
|
||||
|
||||
// TRN FilamentSettings : "Dynamic fan speeds"
|
||||
auto fan_speed_setting_description = L(
|
||||
"Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: "
|
||||
auto fan_speed_setting_description = L("Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: "
|
||||
"100% would be full overlap (no overhang), while 0% represents full overhang (floating extrusion, bridge). "
|
||||
"Fan speeds for overhang sizes in between are calculated via linear interpolation.");
|
||||
|
||||
@ -2907,7 +2906,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->label = L("Tip Diameter");
|
||||
def->category = L("Support material");
|
||||
// TRN PrintSettings: "Organic supports" > "Tip Diameter"
|
||||
def->tooltip = L("The diameter of the top of the tip of the branches of organic support.");
|
||||
def->tooltip = L("Branch tip diameter for organic supports.");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
@ -4666,7 +4665,7 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
def = this->add("opengl-version", coString);
|
||||
def->label = L("OpenGL version");
|
||||
def->tooltip = L("Select the specified OpenGL version");
|
||||
def->tooltip = L("Select a specific version of OpenGL");
|
||||
def->cli = "opengl-version";
|
||||
def->set_default_value(new ConfigOptionString());
|
||||
|
||||
@ -4935,18 +4934,21 @@ std::string get_sla_suptree_prefix(const DynamicPrintConfig &config)
|
||||
return slatree;
|
||||
}
|
||||
|
||||
bool is_XL_printer(const DynamicPrintConfig &cfg)
|
||||
static bool is_XL_printer(const std::string& printer_model)
|
||||
{
|
||||
static constexpr const char *ALIGN_ONLY_FOR = "XL";
|
||||
return boost::algorithm::contains(printer_model, ALIGN_ONLY_FOR);
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
|
||||
bool is_XL_printer(const DynamicPrintConfig &cfg)
|
||||
{
|
||||
auto *printer_model = cfg.opt<ConfigOptionString>("printer_model");
|
||||
return printer_model && is_XL_printer(printer_model->value);
|
||||
}
|
||||
|
||||
if (printer_model)
|
||||
ret = boost::algorithm::contains(printer_model->value, ALIGN_ONLY_FOR);
|
||||
|
||||
return ret;
|
||||
bool is_XL_printer(const PrintConfig &cfg)
|
||||
{
|
||||
return is_XL_printer(cfg.printer_model.value);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -1192,6 +1192,7 @@ private:
|
||||
};
|
||||
|
||||
bool is_XL_printer(const DynamicPrintConfig &cfg);
|
||||
bool is_XL_printer(const PrintConfig &cfg);
|
||||
|
||||
Points get_bed_shape(const DynamicPrintConfig &cfg);
|
||||
Points get_bed_shape(const PrintConfig &cfg);
|
||||
|
@ -1651,7 +1651,8 @@ void PrintObject::bridge_over_infill()
|
||||
unsupported_area = closing(unsupported_area, SCALED_EPSILON);
|
||||
// By expanding the lower layer solids, we avoid making bridges from the tiny internal overhangs that are (very likely) supported by previous layer solids
|
||||
// NOTE that we cannot filter out polygons worth bridging by their area, because sometimes there is a very small internal island that will grow into large hole
|
||||
lower_layer_solids = expand(lower_layer_solids, 3 * spacing);
|
||||
lower_layer_solids = shrink(lower_layer_solids, 1 * spacing); // first remove thin regions that will not support anything
|
||||
lower_layer_solids = expand(lower_layer_solids, (1 + 3) * spacing); // then expand back (opening), and further for parts supported by internal solids
|
||||
// By shrinking the unsupported area, we avoid making bridges from narrow ensuring region along perimeters.
|
||||
unsupported_area = shrink(unsupported_area, 3 * spacing);
|
||||
unsupported_area = diff(unsupported_area, lower_layer_solids);
|
||||
@ -1825,23 +1826,28 @@ void PrintObject::bridge_over_infill()
|
||||
|
||||
std::map<double, int> counted_directions;
|
||||
for (const Polygon &p : bridged_area) {
|
||||
double acc_distance = 0;
|
||||
for (int point_idx = 0; point_idx < int(p.points.size()) - 1; ++point_idx) {
|
||||
Vec2d start = p.points[point_idx].cast<double>();
|
||||
Vec2d next = p.points[point_idx + 1].cast<double>();
|
||||
Vec2d v = next - start; // vector from next to current
|
||||
double dist_to_next = v.norm();
|
||||
v.normalize();
|
||||
int lines_count = int(std::ceil(dist_to_next / scaled(3.0)));
|
||||
float step_size = dist_to_next / lines_count;
|
||||
for (int i = 0; i < lines_count; ++i) {
|
||||
Point a = (start + v * (i * step_size)).cast<coord_t>();
|
||||
auto [distance, index, p] = lines_tree.distance_from_lines_extra<false>(a);
|
||||
double angle = lines_tree.get_line(index).orientation();
|
||||
if (angle > PI) {
|
||||
angle -= PI;
|
||||
acc_distance += dist_to_next;
|
||||
if (acc_distance > scaled(2.0)) {
|
||||
acc_distance = 0.0;
|
||||
v.normalize();
|
||||
int lines_count = int(std::ceil(dist_to_next / scaled(2.0)));
|
||||
float step_size = dist_to_next / lines_count;
|
||||
for (int i = 0; i < lines_count; ++i) {
|
||||
Point a = (start + v * (i * step_size)).cast<coord_t>();
|
||||
auto [distance, index, p] = lines_tree.distance_from_lines_extra<false>(a);
|
||||
double angle = lines_tree.get_line(index).orientation();
|
||||
if (angle > PI) {
|
||||
angle -= PI;
|
||||
}
|
||||
angle += PI * 0.5;
|
||||
counted_directions[angle]++;
|
||||
}
|
||||
angle += PI * 0.5;
|
||||
counted_directions[angle]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2083,27 +2089,43 @@ void PrintObject::bridge_over_infill()
|
||||
};
|
||||
return a.min.x() < b.min.x();
|
||||
});
|
||||
if (surfaces_by_layer[lidx].size() > 2) {
|
||||
Vec2d origin = get_extents(surfaces_by_layer[lidx].front().new_polys).max.cast<double>();
|
||||
std::stable_sort(surfaces_by_layer[lidx].begin() + 1, surfaces_by_layer[lidx].end(),
|
||||
[origin](const CandidateSurface &left, const CandidateSurface &right) {
|
||||
auto a = get_extents(left.new_polys);
|
||||
auto b = get_extents(right.new_polys);
|
||||
|
||||
return (origin - a.min.cast<double>()).squaredNorm() <
|
||||
(origin - b.min.cast<double>()).squaredNorm();
|
||||
});
|
||||
}
|
||||
|
||||
// Gather deep infill areas, where thick bridges fit
|
||||
coordf_t spacing = surfaces_by_layer[lidx].front().region->flow(frSolidInfill, true).scaled_spacing();
|
||||
coordf_t target_flow_height = surfaces_by_layer[lidx].front().region->flow(frSolidInfill, true).height() * target_flow_height_factor;
|
||||
Polygons deep_infill_area = gather_areas_w_depth(po, lidx, target_flow_height);
|
||||
|
||||
// Now also remove area that has been already filled on lower layers by bridging expansion - For this
|
||||
// reason we did the clustering of layers per thread.
|
||||
double bottom_z = layer->print_z - target_flow_height - EPSILON;
|
||||
if (job_idx > 0) {
|
||||
for (int lower_job_idx = job_idx - 1; lower_job_idx >= 0; lower_job_idx--) {
|
||||
size_t lower_layer_idx = clustered_layers_for_threads[cluster_idx][lower_job_idx];
|
||||
const Layer *lower_layer = po->get_layer(lower_layer_idx);
|
||||
if (lower_layer->print_z >= bottom_z) {
|
||||
for (const auto &c : surfaces_by_layer[lower_layer_idx]) {
|
||||
deep_infill_area = diff(deep_infill_area, c.new_polys);
|
||||
{
|
||||
// Now also remove area that has been already filled on lower layers by bridging expansion - For this
|
||||
// reason we did the clustering of layers per thread.
|
||||
Polygons filled_polyons_on_lower_layers;
|
||||
double bottom_z = layer->print_z - target_flow_height - EPSILON;
|
||||
if (job_idx > 0) {
|
||||
for (int lower_job_idx = job_idx - 1; lower_job_idx >= 0; lower_job_idx--) {
|
||||
size_t lower_layer_idx = clustered_layers_for_threads[cluster_idx][lower_job_idx];
|
||||
const Layer *lower_layer = po->get_layer(lower_layer_idx);
|
||||
if (lower_layer->print_z >= bottom_z) {
|
||||
for (const auto &c : surfaces_by_layer[lower_layer_idx]) {
|
||||
filled_polyons_on_lower_layers.insert(filled_polyons_on_lower_layers.end(), c.new_polys.begin(),
|
||||
c.new_polys.end());
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
deep_infill_area = diff(deep_infill_area, filled_polyons_on_lower_layers);
|
||||
}
|
||||
|
||||
deep_infill_area = expand(deep_infill_area, spacing * 1.5);
|
||||
@ -2123,9 +2145,8 @@ void PrintObject::bridge_over_infill()
|
||||
Polylines anchors = intersection_pl(infill_lines[lidx - 1], shrink(expansion_area, spacing));
|
||||
|
||||
#ifdef DEBUG_BRIDGE_OVER_INFILL
|
||||
debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" +
|
||||
"_total_area",
|
||||
to_lines(total_fill_area), to_lines(expansion_area), to_lines(deep_infill_area), to_lines(anchors));
|
||||
debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" + "_total_area",
|
||||
to_lines(total_fill_area), to_lines(expansion_area), to_lines(deep_infill_area), to_lines(anchors));
|
||||
#endif
|
||||
|
||||
|
||||
@ -2186,6 +2207,7 @@ void PrintObject::bridge_over_infill()
|
||||
}
|
||||
|
||||
bridging_area = opening(bridging_area, flow.scaled_spacing());
|
||||
bridging_area = closing(bridging_area, flow.scaled_spacing());
|
||||
bridging_area = intersection(bridging_area, limiting_area);
|
||||
bridging_area = intersection(bridging_area, total_fill_area);
|
||||
expansion_area = diff(expansion_area, bridging_area);
|
||||
@ -2220,35 +2242,33 @@ void PrintObject::bridge_over_infill()
|
||||
for (LayerRegion *region : layer->regions()) {
|
||||
Surfaces new_surfaces;
|
||||
|
||||
SurfacesPtr internal_infills = region->m_fill_surfaces.filter_by_type(stInternal);
|
||||
ExPolygons new_internal_infills = diff_ex(internal_infills, cut_from_infill);
|
||||
for (const ExPolygon &ep : new_internal_infills) {
|
||||
new_surfaces.emplace_back(*internal_infills.front(), ep);
|
||||
}
|
||||
|
||||
SurfacesPtr internal_solids = region->m_fill_surfaces.filter_by_type(stInternalSolid);
|
||||
for (const CandidateSurface &cs : surfaces_by_layer.at(lidx)) {
|
||||
for (Surface &surface : region->m_fill_surfaces.surfaces) {
|
||||
if (cs.original_surface == &surface) {
|
||||
Surface tmp(surface, {});
|
||||
for (const ExPolygon &expoly : diff_ex(surface.expolygon, cs.new_polys)) {
|
||||
if (expoly.area() > region->flow(frSolidInfill).scaled_width() * scale_(4.0)) {
|
||||
new_surfaces.emplace_back(tmp, expoly);
|
||||
}
|
||||
}
|
||||
for (const Surface *surface : internal_solids) {
|
||||
if (cs.original_surface == surface) {
|
||||
Surface tmp{*surface, {}};
|
||||
tmp.surface_type = stInternalBridge;
|
||||
tmp.bridge_angle = cs.bridge_angle;
|
||||
for (const ExPolygon &expoly : union_ex(cs.new_polys)) {
|
||||
new_surfaces.emplace_back(tmp, expoly);
|
||||
for (const ExPolygon &ep : union_ex(cs.new_polys)) {
|
||||
new_surfaces.emplace_back(tmp, ep);
|
||||
}
|
||||
surface.clear();
|
||||
} else if (surface.surface_type == stInternal) {
|
||||
Surface tmp(surface, {});
|
||||
for (const ExPolygon &expoly : diff_ex(surface.expolygon, cut_from_infill)) {
|
||||
new_surfaces.emplace_back(tmp, expoly);
|
||||
}
|
||||
surface.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
region->m_fill_surfaces.surfaces.insert(region->m_fill_surfaces.surfaces.end(), new_surfaces.begin(), new_surfaces.end());
|
||||
region->m_fill_surfaces.surfaces.erase(std::remove_if(region->m_fill_surfaces.surfaces.begin(),
|
||||
region->m_fill_surfaces.surfaces.end(),
|
||||
[](const Surface &s) { return s.empty(); }),
|
||||
region->m_fill_surfaces.surfaces.end());
|
||||
ExPolygons new_internal_solids = diff_ex(internal_solids, cut_from_infill);
|
||||
for (const ExPolygon &ep : new_internal_solids) {
|
||||
new_surfaces.emplace_back(*internal_solids.front(), ep);
|
||||
}
|
||||
|
||||
region->m_fill_surfaces.remove_types({stInternalSolid, stInternal});
|
||||
region->m_fill_surfaces.append(new_surfaces);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -300,18 +300,8 @@ struct RotfinderBoilerplate {
|
||||
TriangleMesh mesh = mo.raw_mesh();
|
||||
|
||||
ModelInstance *mi = mo.instances[0];
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Geometry::Transformation trafo = mi->get_transformation();
|
||||
Transform3d trafo_instance = trafo.get_scaling_factor_matrix() * trafo.get_mirror_matrix();
|
||||
#else
|
||||
auto rotation = Vec3d::Zero();
|
||||
auto offset = Vec3d::Zero();
|
||||
Transform3d trafo_instance =
|
||||
Geometry::assemble_transform(offset, rotation,
|
||||
mi->get_scaling_factor(),
|
||||
mi->get_mirror());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
mesh.transform(trafo_instance);
|
||||
|
||||
return mesh;
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "I18N.hpp"
|
||||
|
||||
#include <libnest2d/tools/benchmark.h>
|
||||
|
||||
#include "format.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -290,8 +290,7 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st
|
||||
|
||||
if (!handled) { // Last resort to voxelization.
|
||||
po.active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL,
|
||||
_u8L("Can't perform full mesh booleans! "
|
||||
"Some parts of the print will be previewed with approximated meshes. "
|
||||
_u8L("Some parts of the print will be previewed with approximated meshes. "
|
||||
"This does not affect the quality of slices or the physical print in any way."));
|
||||
m = generate_preview_vdb(po, step);
|
||||
}
|
||||
@ -510,8 +509,7 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po)
|
||||
|
||||
if(slindex_it == po.m_slice_index.end())
|
||||
//TRN To be shown at the status bar on SLA slicing error.
|
||||
throw Slic3r::RuntimeError(
|
||||
format(_u8L("Model named: %s can not be sliced. Please check if the model is sane."), po.model_object()->name));
|
||||
throw Slic3r::RuntimeError(format("Model named: %s can not be sliced. Please check if the model is sane.", po.model_object()->name));
|
||||
|
||||
po.m_model_height_levels.clear();
|
||||
po.m_model_height_levels.reserve(po.m_slice_index.size());
|
||||
|
@ -32,6 +32,10 @@
|
||||
#define ENABLE_RAYCAST_PICKING_DEBUG 0
|
||||
// Shows an imgui dialog with GLModel statistics data
|
||||
#define ENABLE_GLMODEL_STATISTICS 0
|
||||
// Shows an imgui dialog containing the matrices of the selected volumes
|
||||
#define ENABLE_MATRICES_DEBUG 0
|
||||
// Shows an imgui dialog containing data from class ObjectManipulation
|
||||
#define ENABLE_OBJECT_MANIPULATION_DEBUG 0
|
||||
|
||||
|
||||
// Enable rendering of objects using environment map
|
||||
@ -39,24 +43,23 @@
|
||||
// Enable smoothing of objects normals
|
||||
#define ENABLE_SMOOTH_NORMALS 0
|
||||
|
||||
|
||||
//====================
|
||||
// 2.6.0.alpha1 techs
|
||||
//====================
|
||||
#define ENABLE_2_6_0_ALPHA1 1
|
||||
|
||||
// Enable OpenGL ES
|
||||
#define ENABLE_OPENGL_ES 0
|
||||
// Enable OpenGL core profile context (tested against Mesa 20.1.8 on Windows)
|
||||
#define ENABLE_GL_CORE_PROFILE (1 && !ENABLE_OPENGL_ES)
|
||||
// Enable OpenGL debug messages using debug context
|
||||
#define ENABLE_OPENGL_DEBUG_OPTION (1 && ENABLE_GL_CORE_PROFILE)
|
||||
// Enable editing volumes transformation in world coordinates and instances in local coordinates
|
||||
#define ENABLE_WORLD_COORDINATE (1 && ENABLE_2_6_0_ALPHA1)
|
||||
// Shows an imgui dialog containing the matrices of the selected volumes
|
||||
#define ENABLE_WORLD_COORDINATE_DEBUG (0 && ENABLE_WORLD_COORDINATE)
|
||||
|
||||
|
||||
//====================
|
||||
// 2.6.0.alpha1 techs
|
||||
//====================
|
||||
#define ENABLE_2_6_0_ALPHA1 1
|
||||
|
||||
// Enable alternative version of file_wildcards()
|
||||
#define ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR (1 && ENABLE_2_6_0_ALPHA1)
|
||||
// Enable gcode postprocess modified to allow for backward insertion of new lines
|
||||
#define ENABLE_GCODE_POSTPROCESS_BACKTRACE (1 && ENABLE_2_6_0_ALPHA1)
|
||||
|
||||
|
||||
#endif // _prusaslicer_technologies_h_
|
||||
|
@ -20,7 +20,7 @@ public:
|
||||
|
||||
std::string formatted_errorstr() const
|
||||
{
|
||||
return _u8L("Error with zip archive") + " " + m_zipname + ": " +
|
||||
return _u8L("Error with ZIP archive") + " " + m_zipname + ": " +
|
||||
get_errorstr();
|
||||
}
|
||||
|
||||
|
@ -29,54 +29,6 @@ static const Slic3r::ColorRGBA DEFAULT_TRANSPARENT_GRID_COLOR = { 0.9f, 0.9f, 0
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
const float Bed3D::Axes::DefaultStemRadius = 0.5f;
|
||||
const float Bed3D::Axes::DefaultStemLength = 25.0f;
|
||||
const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius;
|
||||
const float Bed3D::Axes::DefaultTipLength = 5.0f;
|
||||
|
||||
void Bed3D::Axes::render()
|
||||
{
|
||||
auto render_axis = [this](GLShaderProgram* shader, const Transform3d& transform) {
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
const Transform3d& view_matrix = camera.get_view_matrix();
|
||||
shader->set_uniform("view_model_matrix", view_matrix * transform);
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * transform.matrix().block(0, 0, 3, 3).inverse().transpose();
|
||||
shader->set_uniform("view_normal_matrix", view_normal_matrix);
|
||||
m_arrow.render();
|
||||
};
|
||||
|
||||
if (!m_arrow.is_initialized())
|
||||
m_arrow.init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length));
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
shader->start_using();
|
||||
shader->set_uniform("emission_factor", 0.0f);
|
||||
|
||||
// x axis
|
||||
m_arrow.set_color(ColorRGBA::X());
|
||||
render_axis(shader, Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0 }));
|
||||
|
||||
// y axis
|
||||
m_arrow.set_color(ColorRGBA::Y());
|
||||
render_axis(shader, Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0 }));
|
||||
|
||||
// z axis
|
||||
m_arrow.set_color(ColorRGBA::Z());
|
||||
render_axis(shader, Geometry::assemble_transform(m_origin));
|
||||
|
||||
shader->stop_using();
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
}
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom)
|
||||
{
|
||||
auto check_texture = [](const std::string& texture) {
|
||||
@ -201,11 +153,7 @@ BoundingBoxf3 Bed3D::calc_extended_bounding_box() const
|
||||
out.merge(m_axes.get_origin());
|
||||
// extend to contain axes
|
||||
out.merge(m_axes.get_origin() + m_axes.get_total_length() * Vec3d::Ones());
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
out.merge(out.min + Vec3d(-m_axes.get_tip_radius(), -m_axes.get_tip_radius(), out.max.z()));
|
||||
#else
|
||||
out.merge(out.min + Vec3d(-Axes::DefaultTipRadius, -Axes::DefaultTipRadius, out.max.z()));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// extend to contain model, if any
|
||||
BoundingBoxf3 model_bb = m_model.model.get_bounding_box();
|
||||
if (model_bb.defined) {
|
||||
@ -364,11 +312,7 @@ std::tuple<Bed3D::Type, std::string, std::string> Bed3D::detect_type(const Point
|
||||
void Bed3D::render_axes()
|
||||
{
|
||||
if (m_build_volume.valid())
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_axes.render(Transform3d::Identity(), 0.25f);
|
||||
#else
|
||||
m_axes.render();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void Bed3D::render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture)
|
||||
|
@ -3,11 +3,7 @@
|
||||
|
||||
#include "GLTexture.hpp"
|
||||
#include "3DScene.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "CoordAxes.hpp"
|
||||
#else
|
||||
#include "GLModel.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#include "MeshUtils.hpp"
|
||||
|
||||
#include "libslic3r/BuildVolume.hpp"
|
||||
@ -23,32 +19,6 @@ class GLCanvas3D;
|
||||
|
||||
class Bed3D
|
||||
{
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
class Axes
|
||||
{
|
||||
public:
|
||||
static const float DefaultStemRadius;
|
||||
static const float DefaultStemLength;
|
||||
static const float DefaultTipRadius;
|
||||
static const float DefaultTipLength;
|
||||
|
||||
private:
|
||||
Vec3d m_origin{ Vec3d::Zero() };
|
||||
float m_stem_length{ DefaultStemLength };
|
||||
GLModel m_arrow;
|
||||
|
||||
public:
|
||||
const Vec3d& get_origin() const { return m_origin; }
|
||||
void set_origin(const Vec3d& origin) { m_origin = origin; }
|
||||
void set_stem_length(float length) {
|
||||
m_stem_length = length;
|
||||
m_arrow.reset();
|
||||
}
|
||||
float get_total_length() const { return m_stem_length + DefaultTipLength; }
|
||||
void render();
|
||||
};
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
public:
|
||||
enum class Type : unsigned char
|
||||
{
|
||||
@ -77,11 +47,7 @@ private:
|
||||
GLTexture m_temp_texture;
|
||||
PickingModel m_model;
|
||||
Vec3d m_model_offset{ Vec3d::Zero() };
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
CoordAxes m_axes;
|
||||
#else
|
||||
Axes m_axes;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
float m_scale_factor{ 1.0f };
|
||||
|
||||
|
@ -488,13 +488,11 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
||||
float rotation_angle, bool size_unknown, float brim_width)
|
||||
#endif // ENABLE_OPENGL_ES
|
||||
{
|
||||
if (depth < 0.01f)
|
||||
return int(this->volumes.size() - 1);
|
||||
if (height == 0.0f)
|
||||
height = 0.1f;
|
||||
|
||||
static const float brim_height = 0.2f;
|
||||
const float scaled_brim_height = brim_height / height;
|
||||
// const float scaled_brim_height = brim_height / height;
|
||||
|
||||
TriangleMesh mesh;
|
||||
ColorRGBA color = ColorRGBA::DARK_YELLOW();
|
||||
|
@ -212,23 +212,15 @@ public:
|
||||
|
||||
const Geometry::Transformation& get_instance_transformation() const { return m_instance_transformation; }
|
||||
void set_instance_transformation(const Geometry::Transformation& transformation) { m_instance_transformation = transformation; set_bounding_boxes_as_dirty(); }
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void set_instance_transformation(const Transform3d& transform) { m_instance_transformation.set_matrix(transform); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
Vec3d get_instance_offset() const { return m_instance_transformation.get_offset(); }
|
||||
#else
|
||||
const Vec3d& get_instance_offset() const { return m_instance_transformation.get_offset(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_instance_offset(Axis axis) const { return m_instance_transformation.get_offset(axis); }
|
||||
|
||||
void set_instance_offset(const Vec3d& offset) { m_instance_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
|
||||
void set_instance_offset(Axis axis, double offset) { m_instance_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_instance_rotation() const { return m_instance_transformation.get_rotation(); }
|
||||
#else
|
||||
const Vec3d& get_instance_rotation() const { return m_instance_transformation.get_rotation(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_instance_rotation(Axis axis) const { return m_instance_transformation.get_rotation(axis); }
|
||||
|
||||
void set_instance_rotation(const Vec3d& rotation) { m_instance_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
|
||||
@ -240,11 +232,7 @@ public:
|
||||
void set_instance_scaling_factor(const Vec3d& scaling_factor) { m_instance_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
|
||||
void set_instance_scaling_factor(Axis axis, double scaling_factor) { m_instance_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_instance_mirror() const { return m_instance_transformation.get_mirror(); }
|
||||
#else
|
||||
const Vec3d& get_instance_mirror() const { return m_instance_transformation.get_mirror(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_instance_mirror(Axis axis) const { return m_instance_transformation.get_mirror(axis); }
|
||||
|
||||
void set_instance_mirror(const Vec3d& mirror) { m_instance_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }
|
||||
@ -252,43 +240,27 @@ public:
|
||||
|
||||
const Geometry::Transformation& get_volume_transformation() const { return m_volume_transformation; }
|
||||
void set_volume_transformation(const Geometry::Transformation& transformation) { m_volume_transformation = transformation; set_bounding_boxes_as_dirty(); }
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void set_volume_transformation(const Transform3d& transform) { m_volume_transformation.set_matrix(transform); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
Vec3d get_volume_offset() const { return m_volume_transformation.get_offset(); }
|
||||
#else
|
||||
const Vec3d& get_volume_offset() const { return m_volume_transformation.get_offset(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_volume_offset(Axis axis) const { return m_volume_transformation.get_offset(axis); }
|
||||
|
||||
void set_volume_offset(const Vec3d& offset) { m_volume_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
|
||||
void set_volume_offset(Axis axis, double offset) { m_volume_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_volume_rotation() const { return m_volume_transformation.get_rotation(); }
|
||||
#else
|
||||
const Vec3d& get_volume_rotation() const { return m_volume_transformation.get_rotation(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_volume_rotation(Axis axis) const { return m_volume_transformation.get_rotation(axis); }
|
||||
|
||||
void set_volume_rotation(const Vec3d& rotation) { m_volume_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
|
||||
void set_volume_rotation(Axis axis, double rotation) { m_volume_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_volume_scaling_factor() const { return m_volume_transformation.get_scaling_factor(); }
|
||||
#else
|
||||
const Vec3d& get_volume_scaling_factor() const { return m_volume_transformation.get_scaling_factor(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_volume_scaling_factor(Axis axis) const { return m_volume_transformation.get_scaling_factor(axis); }
|
||||
|
||||
void set_volume_scaling_factor(const Vec3d& scaling_factor) { m_volume_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
|
||||
void set_volume_scaling_factor(Axis axis, double scaling_factor) { m_volume_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_volume_mirror() const { return m_volume_transformation.get_mirror(); }
|
||||
#else
|
||||
const Vec3d& get_volume_mirror() const { return m_volume_transformation.get_mirror(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_volume_mirror(Axis axis) const { return m_volume_transformation.get_mirror(axis); }
|
||||
|
||||
void set_volume_mirror(const Vec3d& mirror) { m_volume_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }
|
||||
|
@ -719,7 +719,7 @@ void BackgroundSlicingProcess::prepare_upload()
|
||||
m_print->set_status(95, _u8L("Running post-processing scripts"));
|
||||
std::string error_message;
|
||||
if (copy_file(m_temp_output_path, source_path.string(), error_message) != SUCCESS)
|
||||
throw Slic3r::RuntimeError(_u8L("Copying of the temporary G-code to the output G-code failed"));
|
||||
throw Slic3r::RuntimeError("Copying of the temporary G-code to the output G-code failed");
|
||||
m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
|
||||
// Make a copy of the source path, as run_post_process_scripts() is allowed to change it when making a copy of the source file
|
||||
// (not here, but when the final target is a file).
|
||||
|
@ -1425,8 +1425,7 @@ PageDownloader::PageDownloader(ConfigWizard* parent)
|
||||
append(box_allow_downloads);
|
||||
|
||||
// TRN ConfigWizard : Downloader : %1% = "PrusaSlicer"
|
||||
append_text(format_wxstr(_L(
|
||||
"If enabled, %1% registers to start on custom URL on www.printables.com."
|
||||
append_text(format_wxstr(_L("If enabled, %1% registers to start on custom URL on www.printables.com."
|
||||
" You will be able to use button with %1% logo to open models in this %1%."
|
||||
" The model will be downloaded into folder you choose bellow."
|
||||
), SLIC3R_APP_NAME));
|
||||
@ -1761,7 +1760,7 @@ PageBuildVolume::PageBuildVolume(ConfigWizard* parent)
|
||||
: ConfigWizardPage(parent, _L("Build Volume"), _L("Build Volume"), 1)
|
||||
, build_volume(new DiamTextCtrl(this))
|
||||
{
|
||||
append_text(_L("Set vertical size of your printer."));
|
||||
append_text(_L("Set the printer height."));
|
||||
|
||||
wxString value = "200";
|
||||
build_volume->SetValue(value);
|
||||
|
@ -8,8 +8,6 @@
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
@ -69,5 +67,3 @@ void CoordAxes::render(const Transform3d& trafo, float emission_factor)
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
@ -1,7 +1,6 @@
|
||||
#ifndef slic3r_CoordAxes_hpp_
|
||||
#define slic3r_CoordAxes_hpp_
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "GLModel.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
@ -55,6 +54,4 @@ public:
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#endif // slic3r_CoordAxes_hpp_
|
||||
|
@ -147,7 +147,7 @@ void Downloader::start_download(const std::string& full_url)
|
||||
std::string escaped_url = FileGet::escape_url(full_url.substr(24));
|
||||
#endif
|
||||
if (!boost::starts_with(escaped_url, "https://") || !FileGet::is_subdomain(escaped_url, "printables.com")) {
|
||||
std::string msg = format(_L("Download won't start. Download URL doesn't point to https://files.printables.com : %1%"), escaped_url);
|
||||
std::string msg = format(_L("Download won't start. Download URL doesn't point to https://printables.com : %1%"), escaped_url);
|
||||
BOOST_LOG_TRIVIAL(error) << msg;
|
||||
NotificationManager* ntf_mngr = wxGetApp().notification_manager();
|
||||
ntf_mngr->push_notification(NotificationType::CustomNotification, NotificationManager::NotificationLevel::RegularNotificationLevel, msg);
|
||||
|
@ -191,7 +191,7 @@ void FileGet::priv::get_perform()
|
||||
if (file == NULL) {
|
||||
wxCommandEvent* evt = new wxCommandEvent(EVT_DWNLDR_FILE_ERROR);
|
||||
// TRN %1% = file path
|
||||
evt->SetString(GUI::format_wxstr(_L("Can't create file at %1%."), temp_path_wstring));
|
||||
evt->SetString(GUI::format_wxstr(_L("Can't create file at %1%"), temp_path_wstring));
|
||||
evt->SetInt(m_id);
|
||||
m_evt_handler->QueueEvent(evt);
|
||||
return;
|
||||
|
@ -954,9 +954,7 @@ wxDEFINE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event<int>);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_RESET_SKEW, SimpleEvent);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_FORCE_UPDATE, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
|
||||
@ -1641,6 +1639,9 @@ void GLCanvas3D::render()
|
||||
#if ENABLE_GLMODEL_STATISTICS
|
||||
GLModel::render_statistics();
|
||||
#endif // ENABLE_GLMODEL_STATISTICS
|
||||
#if ENABLE_OBJECT_MANIPULATION_DEBUG
|
||||
wxGetApp().obj_manipul()->render_debug_window();
|
||||
#endif // ENABLE_OBJECT_MANIPULATION_DEBUG
|
||||
|
||||
std::string tooltip;
|
||||
|
||||
@ -1811,7 +1812,6 @@ std::vector<int> GLCanvas3D::load_object(const Model& model, int obj_idx)
|
||||
|
||||
void GLCanvas3D::mirror_selection(Axis axis)
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationType transformation_type;
|
||||
if (wxGetApp().obj_manipul()->is_local_coordinates())
|
||||
transformation_type.set_local();
|
||||
@ -1822,9 +1822,7 @@ void GLCanvas3D::mirror_selection(Axis axis)
|
||||
|
||||
m_selection.setup_cache();
|
||||
m_selection.mirror(axis, transformation_type);
|
||||
#else
|
||||
m_selection.mirror(axis);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
do_mirror(L("Mirror Object"));
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
}
|
||||
@ -2135,8 +2133,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||
const bool co = dynamic_cast<const ConfigOptionBool*>(m_config->option("complete_objects"))->value;
|
||||
|
||||
if (extruders_count > 1 && wt && !co) {
|
||||
// Height of a print (Show at least a slab)
|
||||
const double height = std::max(m_model->max_z(), 10.0);
|
||||
|
||||
const float x = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_x"))->value;
|
||||
const float y = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_y"))->value;
|
||||
@ -2147,6 +2143,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||
|
||||
const Print *print = m_process->fff_print();
|
||||
const float depth = print->wipe_tower_data(extruders_count).depth;
|
||||
const float height_real = print->wipe_tower_data(extruders_count).height; // -1.f = unknown
|
||||
|
||||
// Height of a print (Show at least a slab).
|
||||
const double height = height_real < 0.f ? std::max(m_model->max_z(), 10.0) : height_real;
|
||||
|
||||
#if ENABLE_OPENGL_ES
|
||||
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
|
||||
@ -2719,13 +2719,9 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
|
||||
else
|
||||
displacement = multiplier * direction;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationType trafo_type;
|
||||
trafo_type.set_relative();
|
||||
m_selection.translate(displacement, trafo_type);
|
||||
#else
|
||||
m_selection.translate(displacement);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_dirty = true;
|
||||
}
|
||||
);
|
||||
@ -3332,14 +3328,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_moving = true;
|
||||
TransformationType trafo_type;
|
||||
trafo_type.set_relative();
|
||||
m_selection.translate(cur_pos - m_mouse.drag.start_position_3D, trafo_type);
|
||||
#else
|
||||
m_selection.translate(cur_pos - m_mouse.drag.start_position_3D);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
if (current_printer_technology() == ptFFF && fff_print()->config().complete_objects)
|
||||
update_sequential_clearance();
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
@ -3607,17 +3599,9 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
|
||||
ModelObject* model_object = m_model->objects[object_idx];
|
||||
if (model_object != nullptr) {
|
||||
if (selection_mode == Selection::Instance)
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
#else
|
||||
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
else if (selection_mode == Selection::Volume)
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
|
||||
#else
|
||||
model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
object_moved = true;
|
||||
model_object->invalidate_bounding_box();
|
||||
@ -3688,13 +3672,9 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
|
||||
for (const GLVolume* v : m_volumes.volumes) {
|
||||
if (v->is_wipe_tower) {
|
||||
const Vec3d offset = v->get_volume_offset();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d rot_unit_x = v->get_volume_transformation().get_matrix().linear() * Vec3d::UnitX();
|
||||
double z_rot = std::atan2(rot_unit_x.y(), rot_unit_x.x());
|
||||
post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3d(offset.x(), offset.y(), z_rot)));
|
||||
#else
|
||||
post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3d(offset.x(), offset.y(), v->get_volume_rotation().z())));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
const int object_idx = v->object_idx();
|
||||
if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)
|
||||
@ -3711,22 +3691,10 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
|
||||
// Rotate instances/volumes.
|
||||
ModelObject* model_object = m_model->objects[object_idx];
|
||||
if (model_object != nullptr) {
|
||||
if (selection_mode == Selection::Instance) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (selection_mode == Selection::Instance)
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
#else
|
||||
model_object->instances[instance_idx]->set_rotation(v->get_instance_rotation());
|
||||
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
else if (selection_mode == Selection::Volume) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
else if (selection_mode == Selection::Volume)
|
||||
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
|
||||
#else
|
||||
model_object->volumes[volume_idx]->set_rotation(v->get_volume_rotation());
|
||||
model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
model_object->invalidate_bounding_box();
|
||||
}
|
||||
}
|
||||
@ -3790,23 +3758,11 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
|
||||
// Rotate instances/volumes
|
||||
ModelObject* model_object = m_model->objects[object_idx];
|
||||
if (model_object != nullptr) {
|
||||
if (selection_mode == Selection::Instance) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (selection_mode == Selection::Instance)
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
#else
|
||||
model_object->instances[instance_idx]->set_scaling_factor(v->get_instance_scaling_factor());
|
||||
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
else if (selection_mode == Selection::Volume) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
|
||||
#else
|
||||
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
|
||||
model_object->volumes[volume_idx]->set_scaling_factor(v->get_volume_scaling_factor());
|
||||
model_object->volumes[volume_idx]->set_offset(v->get_volume_offset());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
model_object->invalidate_bounding_box();
|
||||
}
|
||||
@ -3868,18 +3824,9 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
|
||||
ModelObject* model_object = m_model->objects[object_idx];
|
||||
if (model_object != nullptr) {
|
||||
if (selection_mode == Selection::Instance)
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
#else
|
||||
model_object->instances[instance_idx]->set_mirror(v->get_instance_mirror());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
else if (selection_mode == Selection::Volume)
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
|
||||
#else
|
||||
model_object->volumes[volume_idx]->set_mirror(v->get_volume_mirror());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
model_object->invalidate_bounding_box();
|
||||
}
|
||||
}
|
||||
@ -3902,7 +3849,6 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void GLCanvas3D::do_reset_skew(const std::string& snapshot_type)
|
||||
{
|
||||
if (m_model == nullptr)
|
||||
@ -3964,7 +3910,6 @@ void GLCanvas3D::do_reset_skew(const std::string& snapshot_type)
|
||||
|
||||
m_dirty = true;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void GLCanvas3D::update_gizmos_on_off_state()
|
||||
{
|
||||
@ -4143,7 +4088,6 @@ void GLCanvas3D::update_sequential_clearance()
|
||||
for (size_t i = 0; i < m_model->objects.size(); ++i) {
|
||||
ModelObject* model_object = m_model->objects[i];
|
||||
ModelInstance* model_instance0 = model_object->instances.front();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Geometry::Transformation trafo = model_instance0->get_transformation();
|
||||
trafo.set_offset({ 0.0, 0.0, model_instance0->get_offset().z() });
|
||||
const Polygon hull_2d = offset(model_object->convex_hull_2d(trafo.get_matrix()),
|
||||
@ -4151,14 +4095,6 @@ void GLCanvas3D::update_sequential_clearance()
|
||||
// exactly by satisfying the extruder_clearance_radius, this test will not trigger collision.
|
||||
shrink_factor,
|
||||
jtRound, mitter_limit).front();
|
||||
#else
|
||||
Polygon hull_2d = offset(model_object->convex_hull_2d(Geometry::assemble_transform({ 0.0, 0.0, model_instance0->get_offset().z() }, model_instance0->get_rotation(),
|
||||
model_instance0->get_scaling_factor(), model_instance0->get_mirror())),
|
||||
// Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects
|
||||
// exactly by satisfying the extruder_clearance_radius, this test will not trigger collision.
|
||||
shrink_factor,
|
||||
jtRound, mitter_limit).front();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
Pointf3s& cache_hull_2d = m_sequential_print_clearance.m_hull_2d_cache.emplace_back(Pointf3s());
|
||||
cache_hull_2d.reserve(hull_2d.points.size());
|
||||
@ -5745,9 +5681,9 @@ void GLCanvas3D::_render_selection()
|
||||
if (!m_gizmos.is_running())
|
||||
m_selection.render(scale_factor);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_DEBUG
|
||||
#if ENABLE_MATRICES_DEBUG
|
||||
m_selection.render_debug_window();
|
||||
#endif // ENABLE_WORLD_COORDINATE_DEBUG
|
||||
#endif // ENABLE_MATRICES_DEBUG
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_sequential_clearance()
|
||||
@ -6163,18 +6099,11 @@ void GLCanvas3D::_render_sla_slices()
|
||||
|
||||
for (const SLAPrintObject::Instance& inst : obj->instances()) {
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Transform3d view_model_matrix = camera.get_view_matrix() *
|
||||
Geometry::translation_transform({ unscale<double>(inst.shift.x()), unscale<double>(inst.shift.y()), 0.0 }) *
|
||||
Geometry::rotation_transform(inst.rotation * Vec3d::UnitZ());
|
||||
if (obj->is_left_handed())
|
||||
view_model_matrix = view_model_matrix * Geometry::scale_transform({ -1.0f, 1.0f, 1.0f });
|
||||
#else
|
||||
const Transform3d view_model_matrix = camera.get_view_matrix() *
|
||||
Geometry::assemble_transform(Vec3d(unscale<double>(inst.shift.x()), unscale<double>(inst.shift.y()), 0.0),
|
||||
inst.rotation * Vec3d::UnitZ(), Vec3d::Ones(),
|
||||
obj->is_left_handed() ? /* The polygons are mirrored by X */ Vec3d(-1.0f, 1.0f, 1.0f) : Vec3d::Ones());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
shader->set_uniform("view_model_matrix", view_model_matrix);
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
@ -7325,11 +7254,10 @@ const ModelVolume *get_model_volume(const GLVolume &v, const Model &model)
|
||||
{
|
||||
const ModelVolume * ret = nullptr;
|
||||
|
||||
if (v.object_idx() < model.objects.size()) {
|
||||
if (v.object_idx() < (int)model.objects.size()) {
|
||||
const ModelObject *obj = model.objects[v.object_idx()];
|
||||
if (v.volume_idx() < obj->volumes.size()) {
|
||||
if (v.volume_idx() < (int)obj->volumes.size())
|
||||
ret = obj->volumes[v.volume_idx()];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -157,9 +157,7 @@ wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_FORCE_UPDATE, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_RESET_SKEW, SimpleEvent);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3dEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>);
|
||||
@ -771,11 +769,7 @@ public:
|
||||
|
||||
void update_volumes_colors_by_extruder();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
bool is_dragging() const { return m_gizmos.is_dragging() || (m_moving && !m_mouse.scene_position.isApprox(m_mouse.drag.start_position_3D)); }
|
||||
#else
|
||||
bool is_dragging() const { return m_gizmos.is_dragging() || m_moving; }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void render();
|
||||
// printable_only == false -> render also non printable volumes as grayed
|
||||
@ -845,9 +839,7 @@ public:
|
||||
void do_rotate(const std::string& snapshot_type);
|
||||
void do_scale(const std::string& snapshot_type);
|
||||
void do_mirror(const std::string& snapshot_type);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void do_reset_skew(const std::string& snapshot_type);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void update_gizmos_on_off_state();
|
||||
void reset_all_gizmos() { m_gizmos.reset_all_states(); }
|
||||
|
@ -216,7 +216,11 @@ public:
|
||||
// load bitmap for logo
|
||||
BitmapCache bmp_cache;
|
||||
int logo_size = lround(width * 0.25);
|
||||
wxBitmap logo_bmp = *bmp_cache.load_svg(wxGetApp().logo_name(), logo_size, logo_size);
|
||||
wxBitmap* logo_bmp_ptr = bmp_cache.load_svg(wxGetApp().logo_name(), logo_size, logo_size);
|
||||
if (logo_bmp_ptr == nullptr)
|
||||
return;
|
||||
|
||||
wxBitmap logo_bmp = *logo_bmp_ptr;
|
||||
|
||||
wxCoord margin = int(m_scale * 20);
|
||||
|
||||
@ -957,16 +961,14 @@ void GUI_App::init_app_config()
|
||||
if (!error.empty()) {
|
||||
// Error while parsing config file. We'll customize the error message and rethrow to be displayed.
|
||||
if (is_editor()) {
|
||||
throw Slic3r::RuntimeError(
|
||||
_u8L("Error parsing PrusaSlicer config file, it is probably corrupted. "
|
||||
"Try to manually delete the file to recover from the error. Your user profiles will not be affected.") +
|
||||
"\n\n" + app_config->config_path() + "\n\n" + error);
|
||||
throw Slic3r::RuntimeError(format("Error parsing PrusaSlicer config file, it is probably corrupted. "
|
||||
"Try to manually delete the file to recover from the error. Your user profiles will not be affected."
|
||||
"\n\n%1%\n\n%2%", app_config->config_path(), error));
|
||||
}
|
||||
else {
|
||||
throw Slic3r::RuntimeError(
|
||||
_u8L("Error parsing PrusaGCodeViewer config file, it is probably corrupted. "
|
||||
"Try to manually delete the file to recover from the error.") +
|
||||
"\n\n" + app_config->config_path() + "\n\n" + error);
|
||||
throw Slic3r::RuntimeError(format("Error parsing PrusaGCodeViewer config file, it is probably corrupted. "
|
||||
"Try to manually delete the file to recover from the error."
|
||||
"\n\n%1%\n\n%2%", app_config->config_path(), error));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1054,16 +1056,14 @@ std::string GUI_App::check_older_app_config(Semver current_version, bool backup)
|
||||
if (!error.empty()) {
|
||||
// Error while parsing config file. We'll customize the error message and rethrow to be displayed.
|
||||
if (is_editor()) {
|
||||
throw Slic3r::RuntimeError(
|
||||
_u8L("Error parsing PrusaSlicer config file, it is probably corrupted. "
|
||||
"Try to manually delete the file to recover from the error. Your user profiles will not be affected.") +
|
||||
"\n\n" + app_config->config_path() + "\n\n" + error);
|
||||
throw Slic3r::RuntimeError(format("Error parsing PrusaSlicer config file, it is probably corrupted. "
|
||||
"Try to manually delete the file to recover from the error. Your user profiles will not be affected."
|
||||
"\n\n%1%\n\n%2%", app_config->config_path(), error));
|
||||
}
|
||||
else {
|
||||
throw Slic3r::RuntimeError(
|
||||
_u8L("Error parsing PrusaGCodeViewer config file, it is probably corrupted. "
|
||||
"Try to manually delete the file to recover from the error.") +
|
||||
"\n\n" + app_config->config_path() + "\n\n" + error);
|
||||
throw Slic3r::RuntimeError(format("Error parsing PrusaGCodeViewer config file, it is probably corrupted. "
|
||||
"Try to manually delete the file to recover from the error."
|
||||
"\n\n%1%\n\n%2%", app_config->config_path(), error));
|
||||
}
|
||||
}
|
||||
if (!snapshot_id.empty())
|
||||
@ -2316,7 +2316,7 @@ bool GUI_App::load_language(wxString language, bool initial)
|
||||
m_imgui->set_language(into_u8(language_info->CanonicalName));
|
||||
//FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only.
|
||||
//wxSetlocale(LC_NUMERIC, "C");
|
||||
Preset::update_suffix_modified((" (" + _L("modified") + ")").ToUTF8().data());
|
||||
Preset::update_suffix_modified(format(" (%1%)", _L("modified")));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3378,8 +3378,8 @@ void GUI_App::on_version_read(wxCommandEvent& evt)
|
||||
if (m_app_updater->get_triggered_by_user())
|
||||
{
|
||||
std::string text = (*Semver::parse(into_u8(evt.GetString())) == Semver())
|
||||
? Slic3r::format(_u8L("Check for application update has failed."))
|
||||
: Slic3r::format(_u8L("No new version is available. Latest release version is %1%."), evt.GetString());
|
||||
? _u8L("Check for application update has failed.")
|
||||
: Slic3r::format(_u8L("You are currently running the latest released version %1%."), evt.GetString());
|
||||
|
||||
this->plater_->get_notification_manager()->push_version_notification(NotificationType::NoNewReleaseAvailable
|
||||
, NotificationManager::NotificationLevel::RegularNotificationLevel
|
||||
@ -3450,7 +3450,7 @@ void GUI_App::app_version_check(bool from_user)
|
||||
{
|
||||
if (from_user) {
|
||||
if (m_app_updater->get_download_ongoing()) {
|
||||
MessageDialog msgdlg(nullptr, _L("Download of new version is already ongoing. Do you wish to continue?"), _L("Notice"), wxYES_NO);
|
||||
MessageDialog msgdlg(nullptr, _L("Downloading of the new version is in progress. Do you want to continue?"), _L("Notice"), wxYES_NO);
|
||||
if (msgdlg.ShowModal() != wxID_YES)
|
||||
return;
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
enum class ECoordinatesType : unsigned char
|
||||
{
|
||||
World,
|
||||
@ -73,8 +72,6 @@ private:
|
||||
Enum m_value;
|
||||
};
|
||||
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
} // namespace Slic3r
|
||||
} // namespace GUI
|
||||
|
||||
|
@ -420,7 +420,7 @@ MeshErrorsInfo ObjectList::get_mesh_errors_info(const int obj_idx, const int vol
|
||||
const ModelObject* object = (*m_objects)[obj_idx];
|
||||
if (vol_idx != -1 && vol_idx >= int(object->volumes.size())) {
|
||||
if (sidebar_info)
|
||||
*sidebar_info = _L("Wrong volume index") + " ";
|
||||
*sidebar_info = _L("Invalid object part index") + " ";
|
||||
return { {}, {} }; // hide tooltip
|
||||
}
|
||||
|
||||
@ -1603,11 +1603,7 @@ void ObjectList::load_modifier(const wxArrayString& input_files, ModelObject& mo
|
||||
// First (any) GLVolume of the selected instance. They all share the same instance matrix.
|
||||
const GLVolume* v = selection.get_first_volume();
|
||||
const Geometry::Transformation inst_transform = v->get_instance_transformation();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d inv_inst_transform = inst_transform.get_matrix_no_offset().inverse();
|
||||
#else
|
||||
const Transform3d inv_inst_transform = inst_transform.get_matrix(true).inverse();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const Vec3d instance_offset = v->get_instance_offset();
|
||||
|
||||
for (size_t i = 0; i < input_files.size(); ++i) {
|
||||
@ -1655,15 +1651,9 @@ void ObjectList::load_modifier(const wxArrayString& input_files, ModelObject& mo
|
||||
new_volume->source.mesh_offset = model.objects.front()->volumes.front()->source.mesh_offset;
|
||||
|
||||
if (from_galery) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
// Transform the new modifier to be aligned with the print bed.
|
||||
new_volume->set_transformation(v->get_instance_transformation().get_matrix_no_offset().inverse());
|
||||
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
|
||||
#else
|
||||
// Transform the new modifier to be aligned with the print bed.
|
||||
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
|
||||
new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(inst_transform, mesh_bb));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// Set the modifier position.
|
||||
// Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed.
|
||||
const Vec3d offset = Vec3d(instance_bb.max.x(), instance_bb.min.y(), instance_bb.min.z()) + 0.5 * mesh_bb.size() - instance_offset;
|
||||
@ -1732,15 +1722,9 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
|
||||
|
||||
// First (any) GLVolume of the selected instance. They all share the same instance matrix.
|
||||
const GLVolume* v = selection.get_first_volume();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
// Transform the new modifier to be aligned with the print bed.
|
||||
new_volume->set_transformation(v->get_instance_transformation().get_matrix_no_offset().inverse());
|
||||
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
|
||||
#else
|
||||
// Transform the new modifier to be aligned with the print bed.
|
||||
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
|
||||
new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// Set the modifier position.
|
||||
Vec3d offset;
|
||||
if (type_name == "Slab") {
|
||||
@ -1752,11 +1736,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
|
||||
// Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed.
|
||||
offset = Vec3d(instance_bb.max.x(), instance_bb.min.y(), instance_bb.min.z()) + 0.5 * mesh_bb.size() - v->get_instance_offset();
|
||||
}
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
new_volume->set_offset(v->get_instance_transformation().get_matrix_no_offset().inverse() * offset);
|
||||
#else
|
||||
new_volume->set_offset(v->get_instance_transformation().get_matrix(true).inverse() * offset);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
const wxString name = _L("Generic") + "-" + _(type_name);
|
||||
new_volume->name = into_u8(name);
|
||||
@ -2064,7 +2044,7 @@ bool ObjectList::del_from_cut_object(bool is_cut_connector, bool is_model_part/*
|
||||
InfoDialog dialog(wxGetApp().plater(), title,
|
||||
_L("This action will break a cut information.\n"
|
||||
"After that PrusaSlicer can't guarantee model consistency.") + "\n\n" +
|
||||
_L("To manipulate with solid parts or negative volumes you have to invalidate cut infornation first." + msg_end ),
|
||||
_L("To manipulate with solid parts or negative volumes you have to invalidate cut information first." + msg_end ),
|
||||
false, buttons_style | wxCANCEL_DEFAULT | wxICON_WARNING);
|
||||
|
||||
dialog.SetButtonLabel(wxID_YES, _L("Invalidate cut info"));
|
||||
@ -2687,6 +2667,8 @@ void ObjectList::part_selection_changed()
|
||||
bool disable_ss_manipulation {false};
|
||||
bool disable_ununiform_scale {false};
|
||||
|
||||
ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||
|
||||
const auto item = GetSelection();
|
||||
|
||||
GLGizmosManager& gizmos_mgr = wxGetApp().plater()->canvas3D()->get_gizmos_manager();
|
||||
@ -2703,6 +2685,7 @@ void ObjectList::part_selection_changed()
|
||||
|
||||
if (selection.is_single_full_object()) {
|
||||
og_name = _L("Object manipulation");
|
||||
coordinates_type = ECoordinatesType::World;
|
||||
update_and_show_manipulations = true;
|
||||
|
||||
obj_idx = selection.get_object_idx();
|
||||
@ -2712,6 +2695,7 @@ void ObjectList::part_selection_changed()
|
||||
}
|
||||
else {
|
||||
og_name = _L("Group manipulation");
|
||||
coordinates_type = ECoordinatesType::World;
|
||||
|
||||
// don't show manipulation panel for case of all Object's parts selection
|
||||
update_and_show_manipulations = !selection.is_single_full_instance();
|
||||
@ -2767,6 +2751,8 @@ void ObjectList::part_selection_changed()
|
||||
|| type == itInfo) {
|
||||
og_name = _L("Object manipulation");
|
||||
m_config = &object->config;
|
||||
if (!scene_selection().is_single_full_instance() || coordinates_type > ECoordinatesType::Instance)
|
||||
coordinates_type = ECoordinatesType::World;
|
||||
update_and_show_manipulations = true;
|
||||
|
||||
if (type == itInfo) {
|
||||
@ -2844,6 +2830,8 @@ void ObjectList::part_selection_changed()
|
||||
|
||||
if (update_and_show_manipulations) {
|
||||
wxGetApp().obj_manipul()->get_og()->set_name(" " + og_name + " ");
|
||||
if (wxGetApp().obj_manipul()->get_coordinates_type() != coordinates_type)
|
||||
wxGetApp().obj_manipul()->set_coordinates_type(coordinates_type);
|
||||
|
||||
if (item) {
|
||||
wxGetApp().obj_manipul()->update_item_name(m_objects_model->GetName(item));
|
||||
@ -2875,7 +2863,6 @@ void ObjectList::part_selection_changed()
|
||||
Sidebar& panel = wxGetApp().sidebar();
|
||||
panel.Freeze();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
std::string opt_key;
|
||||
if (m_selected_object_id >= 0) {
|
||||
const ManipulationEditor* const editor = wxGetApp().obj_manipul()->get_focused_editor();
|
||||
@ -2883,9 +2870,6 @@ void ObjectList::part_selection_changed()
|
||||
opt_key = editor->get_full_opt_name();
|
||||
}
|
||||
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, !opt_key.empty());
|
||||
#else
|
||||
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
wxGetApp().plater()->canvas3D()->enable_moving(enable_manipulation); // ysFIXME
|
||||
wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations);
|
||||
wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings);
|
||||
@ -3714,11 +3698,7 @@ void ObjectList::update_selections()
|
||||
return;
|
||||
sels.Add(m_objects_model->GetItemById(selection.get_object_idx()));
|
||||
}
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
else if (selection.is_single_volume_or_modifier()) {
|
||||
#else
|
||||
else if (selection.is_single_volume() || selection.is_any_modifier()) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const auto gl_vol = selection.get_first_volume();
|
||||
if (m_objects_model->GetVolumeIdByItem(m_objects_model->GetParent(item)) == gl_vol->volume_idx())
|
||||
return;
|
||||
|
@ -53,17 +53,10 @@ static choice_ctrl* create_word_local_combo(wxWindow *parent)
|
||||
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
|
||||
if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
temp->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::World));
|
||||
temp->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Instance));
|
||||
temp->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Local));
|
||||
temp->Select((int)ECoordinatesType::World);
|
||||
#else
|
||||
temp->Append(_L("World coordinates"));
|
||||
temp->Append(_L("Local coordinates"));
|
||||
temp->SetSelection(0);
|
||||
temp->SetValue(temp->GetString(0));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
temp->SetToolTip(_L("Select coordinate space, in which the transformation will be performed."));
|
||||
return temp;
|
||||
@ -89,14 +82,9 @@ void msw_rescale_word_local_combo(choice_ctrl* combo)
|
||||
// Set rescaled size
|
||||
combo->SetSize(size);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
combo->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::World));
|
||||
combo->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Instance));
|
||||
combo->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Local));
|
||||
#else
|
||||
combo->Append(_L("World coordinates"));
|
||||
combo->Append(_L("Local coordinates"));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
combo->SetValue(selection);
|
||||
#else
|
||||
@ -126,10 +114,6 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
|
||||
// Load bitmaps to be used for the mirroring buttons:
|
||||
m_mirror_bitmap_on = ScalableBitmap(parent, "mirroring_on");
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
m_mirror_bitmap_off = ScalableBitmap(parent, "mirroring_off");
|
||||
m_mirror_bitmap_hidden = ScalableBitmap(parent, "mirroring_transparent");
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
const int border = wxOSX ? 0 : 4;
|
||||
const int em = wxGetApp().em_unit();
|
||||
@ -173,13 +157,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
|
||||
// Add world local combobox
|
||||
m_word_local_combo = create_word_local_combo(parent);
|
||||
m_word_local_combo->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent& evt) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
this->set_coordinates_type(evt.GetString());
|
||||
#else
|
||||
this->set_world_coordinates(evt.GetSelection() != 1);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}), m_word_local_combo->GetId());
|
||||
m_word_local_combo->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent& evt) { this->set_coordinates_type(evt.GetString()); }), m_word_local_combo->GetId());
|
||||
|
||||
// Small trick to correct layouting in different view_mode :
|
||||
// Show empty string of a same height as a m_word_local_combo, when m_word_local_combo is hidden
|
||||
@ -236,11 +214,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
|
||||
add_label(&m_scale_Label, L("Scale"), v_sizer);
|
||||
wxStaticText* size_Label {nullptr};
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
add_label(&size_Label, L("Size [World]"), v_sizer);
|
||||
#else
|
||||
add_label(&size_Label, L("Size"), v_sizer);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
if (wxOSX) set_font_and_background_style(size_Label, wxGetApp().normal_font());
|
||||
|
||||
sizer->Add(v_sizer, 0, wxLEFT, border);
|
||||
@ -272,31 +246,15 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
|
||||
// We will add a button to toggle mirroring to each axis:
|
||||
auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
btn->SetToolTip(format_wxstr(_L("Mirror along %1% axis"), label));
|
||||
m_mirror_buttons[axis_idx] = btn;
|
||||
#else
|
||||
btn->SetToolTip(format_wxstr(_L("Toggle %1% axis mirroring"), label));
|
||||
btn->SetBitmapDisabled_(m_mirror_bitmap_hidden);
|
||||
|
||||
m_mirror_buttons[axis_idx].first = btn;
|
||||
m_mirror_buttons[axis_idx].second = mbShown;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
sizer->AddStretchSpacer(2);
|
||||
sizer->Add(btn, 0, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
btn->Bind(wxEVT_BUTTON, [this, axis_idx](wxCommandEvent&) {
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
Axis axis = (Axis)(axis_idx + X);
|
||||
if (m_mirror_buttons[axis_idx].second == mbHidden)
|
||||
return;
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
Selection& selection = canvas->get_selection();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationType transformation_type;
|
||||
if (is_local_coordinates())
|
||||
transformation_type.set_local();
|
||||
@ -307,24 +265,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
|
||||
selection.setup_cache();
|
||||
selection.mirror((Axis)axis_idx, transformation_type);
|
||||
#else
|
||||
if (selection.is_single_volume() || selection.is_single_modifier()) {
|
||||
GLVolume* volume = const_cast<GLVolume*>(selection.get_first_volume());
|
||||
volume->set_volume_mirror(axis, -volume->get_volume_mirror(axis));
|
||||
}
|
||||
else if (selection.is_single_full_instance()) {
|
||||
for (unsigned int idx : selection.get_volume_idxs()) {
|
||||
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(idx));
|
||||
volume->set_instance_mirror(axis, -volume->get_instance_mirror(axis));
|
||||
}
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
// Update mirroring at the GLVolumes.
|
||||
selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
|
||||
selection.synchronize_unselected_volumes();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// Copy mirroring values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
|
||||
canvas->do_mirror(L("Set Mirror"));
|
||||
UpdateAndShow(true);
|
||||
@ -333,12 +274,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
editors_grid_sizer->Add(sizer, 0, wxALIGN_CENTER_HORIZONTAL);
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_mirror_warning_bitmap = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap);
|
||||
editors_grid_sizer->Add(m_mirror_warning_bitmap, 0, wxALIGN_CENTER_VERTICAL);
|
||||
#else
|
||||
editors_grid_sizer->AddStretchSpacer(1);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
editors_grid_sizer->AddStretchSpacer(1);
|
||||
|
||||
// add EditBoxes
|
||||
@ -377,7 +314,6 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
Selection& selection = canvas->get_selection();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (selection.is_single_volume_or_modifier()) {
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
const double min_z = get_volume_min_z(*volume);
|
||||
@ -393,19 +329,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
|
||||
change_position_value(2, m_cache.position.z() - min_z);
|
||||
}
|
||||
#else
|
||||
if (selection.is_single_volume() || selection.is_single_modifier()) {
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix(true).inverse() * (get_volume_min_z(*volume) * Vec3d::UnitZ());
|
||||
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
|
||||
change_position_value(0, diff.x());
|
||||
change_position_value(1, diff.y());
|
||||
change_position_value(2, diff.z());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
else if (selection.is_single_full_instance()) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const double min_z = selection.get_scaled_instance_bounding_box().min.z();
|
||||
if (!is_world_coordinates()) {
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
@ -417,20 +342,9 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
change_position_value(2, diff.z());
|
||||
}
|
||||
else {
|
||||
#else
|
||||
const ModelObjectPtrs& objects = wxGetApp().model().objects;
|
||||
const int idx = selection.get_object_idx();
|
||||
if (0 <= idx && idx < static_cast<int>(objects.size())) {
|
||||
const ModelObject* mo = wxGetApp().model().objects[idx];
|
||||
const double min_z = mo->bounding_box().min.z();
|
||||
if (std::abs(min_z) > SINKING_Z_THRESHOLD) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
|
||||
change_position_value(2, m_cache.position.z() - min_z);
|
||||
}
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
|
||||
change_position_value(2, m_cache.position.z() - min_z);
|
||||
}
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
});
|
||||
editors_grid_sizer->Add(m_drop_to_bed_button);
|
||||
@ -447,17 +361,12 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
Selection& selection = canvas->get_selection();
|
||||
selection.setup_cache();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (selection.is_single_volume_or_modifier()) {
|
||||
GLVolume* vol = const_cast<GLVolume*>(selection.get_first_volume());
|
||||
Geometry::Transformation trafo = vol->get_volume_transformation();
|
||||
trafo.reset_rotation();
|
||||
vol->set_volume_transformation(trafo);
|
||||
}
|
||||
#else
|
||||
if (selection.is_single_volume() || selection.is_single_modifier())
|
||||
const_cast<GLVolume*>(selection.get_first_volume())->set_volume_rotation(Vec3d::Zero());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
else if (selection.is_single_full_instance()) {
|
||||
Geometry::Transformation trafo = selection.get_first_volume()->get_instance_transformation();
|
||||
trafo.reset_rotation();
|
||||
@ -489,7 +398,6 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
m_reset_scale_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
|
||||
m_reset_scale_button->SetToolTip(_L("Reset scale"));
|
||||
m_reset_scale_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
Selection& selection = canvas->get_selection();
|
||||
selection.setup_cache();
|
||||
@ -515,12 +423,6 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
|
||||
canvas->do_scale(L("Reset scale"));
|
||||
UpdateAndShow(true);
|
||||
#else
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset scale"));
|
||||
change_scale_value(0, 100.);
|
||||
change_scale_value(1, 100.);
|
||||
change_scale_value(2, 100.);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
});
|
||||
editors_grid_sizer->Add(m_reset_scale_button);
|
||||
|
||||
@ -531,8 +433,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
|
||||
m_main_grid_sizer->Add(editors_grid_sizer, 1, wxEXPAND);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_skew_label = new wxStaticText(parent, wxID_ANY, _L("Skew"));
|
||||
m_skew_label = new wxStaticText(parent, wxID_ANY, _L("Skew [World]"));
|
||||
m_main_grid_sizer->Add(m_skew_label, 1, wxEXPAND);
|
||||
|
||||
m_reset_skew_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
|
||||
@ -548,7 +449,6 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
}
|
||||
});
|
||||
m_main_grid_sizer->Add(m_reset_skew_button);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
m_check_inch = new wxCheckBox(parent, wxID_ANY, _L("Inches"));
|
||||
m_check_inch->SetFont(wxGetApp().normal_font());
|
||||
@ -568,9 +468,9 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
|
||||
void ObjectManipulation::Show(const bool show)
|
||||
{
|
||||
if (show != IsShown()) {
|
||||
// Show all lines of the panel. Some of these lines will be hidden in the lines below.
|
||||
m_og->Show(show);
|
||||
if (show != IsShown()) {
|
||||
// Show all lines of the panel. Some of these lines will be hidden in the lines below.
|
||||
m_og->Show(show);
|
||||
|
||||
if (show && wxGetApp().get_mode() != comSimple) {
|
||||
// Show the label and the name of the STL in simple mode only.
|
||||
@ -581,9 +481,10 @@ void ObjectManipulation::Show(const bool show)
|
||||
}
|
||||
}
|
||||
|
||||
if (show) {
|
||||
// Show the "World Coordinates" / "Local Coordintes" Combo in Advanced / Expert mode only.
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (show) {
|
||||
ECoordinatesType coordinates_type = m_coordinates_type;
|
||||
|
||||
// Show the "World Coordinates" / "Local Coordintes" Combo in Advanced / Expert mode only.
|
||||
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
bool show_world_local_combo = wxGetApp().get_mode() != comSimple && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier());
|
||||
if (selection.is_single_volume_or_modifier() && m_word_local_combo->GetCount() < 3) {
|
||||
@ -592,20 +493,15 @@ void ObjectManipulation::Show(const bool show)
|
||||
#else
|
||||
m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Local), wxNullBitmap, 2);
|
||||
#endif // __linux__
|
||||
m_word_local_combo->Select((int)ECoordinatesType::World);
|
||||
this->set_coordinates_type(m_word_local_combo->GetString(m_word_local_combo->GetSelection()));
|
||||
}
|
||||
else if (selection.is_single_full_instance() && m_word_local_combo->GetCount() > 2) {
|
||||
m_word_local_combo->Delete(2);
|
||||
m_word_local_combo->Select((int)ECoordinatesType::World);
|
||||
this->set_coordinates_type(m_word_local_combo->GetString(m_word_local_combo->GetSelection()));
|
||||
if (coordinates_type > ECoordinatesType::Instance)
|
||||
coordinates_type = ECoordinatesType::World;
|
||||
}
|
||||
#else
|
||||
bool show_world_local_combo = wxGetApp().plater()->canvas3D()->get_selection().is_single_full_instance() && wxGetApp().get_mode() != comSimple;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_word_local_combo->Show(show_world_local_combo);
|
||||
m_empty_str->Show(!show_world_local_combo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ObjectManipulation::IsShown()
|
||||
@ -628,10 +524,7 @@ void ObjectManipulation::Enable(const bool enadle)
|
||||
for (auto editor : m_editors)
|
||||
editor->Enable(enadle);
|
||||
for (wxWindow* win : std::initializer_list<wxWindow*>{ m_reset_scale_button, m_reset_rotation_button, m_drop_to_bed_button, m_check_inch, m_lock_bnt
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
,m_reset_skew_button
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
})
|
||||
, m_reset_skew_button })
|
||||
win->Enable(enadle);
|
||||
}
|
||||
|
||||
@ -639,11 +532,7 @@ void ObjectManipulation::DisableScale()
|
||||
{
|
||||
for (auto editor : m_editors)
|
||||
editor->Enable(editor->has_opt_key("scale") || editor->has_opt_key("size") ? false : true);
|
||||
for (wxWindow* win : std::initializer_list<wxWindow*>{ m_reset_scale_button, m_lock_bnt
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
,m_reset_skew_button
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
})
|
||||
for (wxWindow* win : std::initializer_list<wxWindow*>{ m_reset_scale_button, m_lock_bnt, m_reset_skew_button })
|
||||
win->Enable(false);
|
||||
}
|
||||
|
||||
@ -717,52 +606,24 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
||||
m_new_rotate_label_string = L("Rotation");
|
||||
m_new_scale_label_string = L("Scale factors");
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
if (wxGetApp().get_mode() == comSimple)
|
||||
m_world_coordinates = true;
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
ObjectList* obj_list = wxGetApp().obj_list();
|
||||
if (selection.is_single_full_instance()) {
|
||||
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
m_new_position = volume->get_instance_offset();
|
||||
|
||||
// Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
|
||||
if (m_world_coordinates && ! m_uniform_scale &&
|
||||
! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
|
||||
// Manipulating an instance in the world coordinate system, rotation is not multiples of ninety degrees, therefore enforce uniform scaling.
|
||||
m_uniform_scale = true;
|
||||
m_lock_bnt->SetLock(true);
|
||||
}
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (is_world_coordinates()) {
|
||||
m_new_position = volume->get_instance_offset();
|
||||
m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
m_new_scale = m_new_size.cwiseQuotient(selection.get_unscaled_instance_bounding_box().size()) * 100.0;
|
||||
m_new_rotate_label_string = L("Rotate (relative)");
|
||||
#else
|
||||
if (m_world_coordinates) {
|
||||
m_new_scale = m_new_size.cwiseQuotient(selection.get_unscaled_instance_bounding_box().size()) * 100.0;
|
||||
m_new_size = selection.get_scaled_instance_bounding_box().size();
|
||||
m_new_rotate_label_string = L("Rotate");
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
}
|
||||
else {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_new_move_label_string = L("Translate (relative) [World]");
|
||||
m_new_rotate_label_string = L("Rotate (relative)");
|
||||
m_new_position = Vec3d::Zero();
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
#else
|
||||
m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI);
|
||||
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_new_scale = m_new_size.cwiseQuotient(selection.get_full_unscaled_instance_local_bounding_box().size()) * 100.0;
|
||||
}
|
||||
|
||||
@ -773,23 +634,14 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
||||
m_new_position = box.center();
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
m_new_scale = Vec3d(100.0, 100.0, 100.0);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
#else
|
||||
m_new_size = box.size();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_new_rotate_label_string = L("Rotate");
|
||||
m_new_scale_label_string = L("Scale");
|
||||
m_new_enabled = true;
|
||||
}
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
else if (selection.is_single_volume_or_modifier()) {
|
||||
#else
|
||||
else if (selection.is_single_modifier() || selection.is_single_volume()) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// the selection contains a single volume
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (is_world_coordinates()) {
|
||||
const Geometry::Transformation trafo(volume->world_matrix());
|
||||
|
||||
@ -811,23 +663,13 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
||||
m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
}
|
||||
else {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_new_position = volume->get_volume_offset();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_new_rotate_label_string = L("Rotate (relative)");
|
||||
#else
|
||||
m_new_rotate_label_string = L("Rotate");
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_new_rotation = Vec3d::Zero();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_new_scale_label_string = L("Scale");
|
||||
m_new_scale = Vec3d(100.0, 100.0, 100.0);
|
||||
m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
}
|
||||
#else
|
||||
m_new_scale = volume->get_volume_scaling_factor() * 100.0;
|
||||
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size()));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_new_enabled = true;
|
||||
}
|
||||
else if (obj_list->is_connectors_item_selected() || obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) {
|
||||
@ -835,11 +677,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
||||
m_new_move_label_string = L("Translate");
|
||||
m_new_rotate_label_string = L("Rotate");
|
||||
m_new_scale_label_string = L("Scale");
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
|
||||
#else
|
||||
m_new_size = selection.get_bounding_box().size();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_new_enabled = true;
|
||||
}
|
||||
}
|
||||
@ -900,29 +738,9 @@ void ObjectManipulation::update_if_dirty()
|
||||
update(m_cache.rotation, m_cache.rotation_rounded, meRotation, m_new_rotation);
|
||||
}
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
if (selection.requires_uniform_scale()) {
|
||||
m_lock_bnt->SetLock(true);
|
||||
m_lock_bnt->SetToolTip(_L("You cannot use non-uniform scaling mode for multiple objects/parts selection"));
|
||||
m_lock_bnt->disable();
|
||||
}
|
||||
else {
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
m_lock_bnt->SetLock(m_uniform_scale);
|
||||
m_lock_bnt->SetToolTip(wxEmptyString);
|
||||
m_lock_bnt->enable();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (m_word_local_combo->GetSelection() != (int)m_coordinates_type)
|
||||
m_word_local_combo->SetSelection((int)m_coordinates_type);
|
||||
#else
|
||||
}
|
||||
|
||||
{
|
||||
int new_selection = m_world_coordinates ? 0 : 1;
|
||||
if (m_word_local_combo->GetSelection() != new_selection)
|
||||
m_word_local_combo->SetSelection(new_selection);
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_lock_bnt->SetLock(m_uniform_scale);
|
||||
m_lock_bnt->SetToolTip(wxEmptyString);
|
||||
m_lock_bnt->enable();
|
||||
|
||||
if (m_new_enabled)
|
||||
m_og->enable();
|
||||
@ -937,9 +755,6 @@ void ObjectManipulation::update_if_dirty()
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void ObjectManipulation::update_reset_buttons_visibility()
|
||||
{
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
@ -965,7 +780,7 @@ void ObjectManipulation::update_reset_buttons_visibility()
|
||||
show_rotation = trafo_svd.rotation;
|
||||
show_scale = trafo_svd.scale;
|
||||
show_mirror = trafo_svd.mirror;
|
||||
show_skew = trafo_svd.skew;
|
||||
show_skew = Geometry::TransformationSVD(volume->world_matrix()).skew;
|
||||
}
|
||||
|
||||
wxGetApp().CallAfter([this, show_drop_to_bed, show_rotation, show_scale, show_mirror, show_skew] {
|
||||
@ -991,109 +806,13 @@ void ObjectManipulation::update_reset_buttons_visibility()
|
||||
}
|
||||
});
|
||||
}
|
||||
#else
|
||||
void ObjectManipulation::update_reset_buttons_visibility()
|
||||
{
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
if (!canvas)
|
||||
return;
|
||||
const Selection& selection = canvas->get_selection();
|
||||
|
||||
bool show_rotation = false;
|
||||
bool show_scale = false;
|
||||
bool show_drop_to_bed = false;
|
||||
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
Vec3d rotation;
|
||||
Vec3d scale;
|
||||
double min_z = 0.0;
|
||||
|
||||
if (selection.is_single_full_instance()) {
|
||||
rotation = volume->get_instance_rotation();
|
||||
scale = volume->get_instance_scaling_factor();
|
||||
min_z = selection.get_scaled_instance_bounding_box().min.z();
|
||||
}
|
||||
else {
|
||||
rotation = volume->get_volume_rotation();
|
||||
scale = volume->get_volume_scaling_factor();
|
||||
min_z = get_volume_min_z(*volume);
|
||||
}
|
||||
show_rotation = !rotation.isApprox(Vec3d::Zero());
|
||||
show_scale = !scale.isApprox(Vec3d::Ones());
|
||||
show_drop_to_bed = std::abs(min_z) > SINKING_Z_THRESHOLD;
|
||||
}
|
||||
|
||||
wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] {
|
||||
// There is a case (under OSX), when this function is called after the Manipulation panel is hidden
|
||||
// So, let check if Manipulation panel is still shown for this moment
|
||||
if (!this->IsShown())
|
||||
return;
|
||||
m_reset_rotation_button->Show(show_rotation);
|
||||
m_reset_scale_button->Show(show_scale);
|
||||
m_drop_to_bed_button->Show(show_drop_to_bed);
|
||||
|
||||
// Because of CallAfter we need to layout sidebar after Show/hide of reset buttons one more time
|
||||
Sidebar& panel = wxGetApp().sidebar();
|
||||
if (!panel.IsFrozen()) {
|
||||
panel.Freeze();
|
||||
panel.Layout();
|
||||
panel.Thaw();
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
|
||||
|
||||
void ObjectManipulation::update_mirror_buttons_visibility()
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const bool can_mirror = wxGetApp().plater()->can_mirror();
|
||||
for (ScalableButton* button : m_mirror_buttons) {
|
||||
button->Enable(can_mirror);
|
||||
}
|
||||
#else
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
Selection& selection = canvas->get_selection();
|
||||
|
||||
std::array<MirrorButtonState, 3> new_states = { mbHidden, mbHidden, mbHidden };
|
||||
|
||||
if (!m_world_coordinates) {
|
||||
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
Vec3d mirror;
|
||||
|
||||
if (selection.is_single_full_instance())
|
||||
mirror = volume->get_instance_mirror();
|
||||
else
|
||||
mirror = volume->get_volume_mirror();
|
||||
|
||||
for (unsigned char i=0; i<3; ++i)
|
||||
new_states[i] = (mirror[i] < 0. ? mbActive : mbShown);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// the mirroring buttons should be hidden in world coordinates,
|
||||
// unless we make it actually mirror in world coords.
|
||||
}
|
||||
|
||||
// Hiding the buttons through Hide() always messed up the sizers. As a workaround, the button
|
||||
// is assigned a transparent bitmap. We must of course remember the actual state.
|
||||
wxGetApp().CallAfter([this, new_states]{
|
||||
for (int i=0; i<3; ++i) {
|
||||
if (new_states[i] != m_mirror_buttons[i].second) {
|
||||
const ScalableBitmap* bmp = nullptr;
|
||||
switch (new_states[i]) {
|
||||
case mbHidden : bmp = &m_mirror_bitmap_hidden; m_mirror_buttons[i].first->Enable(false); break;
|
||||
case mbShown : bmp = &m_mirror_bitmap_off; m_mirror_buttons[i].first->Enable(true); break;
|
||||
case mbActive : bmp = &m_mirror_bitmap_on; m_mirror_buttons[i].first->Enable(true); break;
|
||||
}
|
||||
m_mirror_buttons[i].first->SetBitmap_(*bmp);
|
||||
m_mirror_buttons[i].second = new_states[i];
|
||||
}
|
||||
}
|
||||
});
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
|
||||
@ -1125,7 +844,6 @@ void ObjectManipulation::update_warning_icon_state(const MeshErrorsInfo& warning
|
||||
m_fix_throught_netfab_bitmap->SetToolTip(tooltip);
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
wxString ObjectManipulation::coordinate_type_str(ECoordinatesType type)
|
||||
{
|
||||
switch (type)
|
||||
@ -1136,7 +854,19 @@ wxString ObjectManipulation::coordinate_type_str(ECoordinatesType type)
|
||||
default: { assert(false); return _L("Unknown"); }
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_OBJECT_MANIPULATION_DEBUG
|
||||
void ObjectManipulation::render_debug_window()
|
||||
{
|
||||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||
// ImGui::SetNextWindowCollapsed(true, ImGuiCond_Once);
|
||||
imgui.begin(std::string("ObjectManipulation"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize);
|
||||
imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, "Coordinates type");
|
||||
ImGui::SameLine();
|
||||
imgui.text(coordinate_type_str(m_coordinates_type));
|
||||
imgui.end();
|
||||
}
|
||||
#endif // ENABLE_OBJECT_MANIPULATION_DEBUG
|
||||
|
||||
void ObjectManipulation::reset_settings_value()
|
||||
{
|
||||
@ -1161,7 +891,6 @@ void ObjectManipulation::change_position_value(int axis, double value)
|
||||
auto canvas = wxGetApp().plater()->canvas3D();
|
||||
Selection& selection = canvas->get_selection();
|
||||
selection.setup_cache();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationType trafo_type;
|
||||
trafo_type.set_relative();
|
||||
switch (get_coordinates_type())
|
||||
@ -1171,9 +900,6 @@ void ObjectManipulation::change_position_value(int axis, double value)
|
||||
default: { break; }
|
||||
}
|
||||
selection.translate(position - m_cache.position, trafo_type);
|
||||
#else
|
||||
selection.translate(position - m_cache.position, selection.requires_local_axes());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
canvas->do_move(L("Set Position"));
|
||||
|
||||
m_cache.position = position;
|
||||
@ -1192,7 +918,6 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
Selection& selection = canvas->get_selection();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationType transformation_type;
|
||||
transformation_type.set_relative();
|
||||
if (selection.is_single_full_instance())
|
||||
@ -1203,16 +928,6 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
|
||||
|
||||
if (is_instance_coordinates())
|
||||
transformation_type.set_instance();
|
||||
#else
|
||||
TransformationType transformation_type(TransformationType::World_Relative_Joint);
|
||||
if (selection.is_single_full_instance() || selection.requires_local_axes())
|
||||
transformation_type.set_independent();
|
||||
if (selection.is_single_full_instance() && ! m_world_coordinates) {
|
||||
//FIXME Selection::rotate() does not process absoulte rotations correctly: It does not recognize the axis index, which was changed.
|
||||
// transformation_type.set_absolute();
|
||||
transformation_type.set_local();
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
selection.setup_cache();
|
||||
selection.rotate(
|
||||
@ -1236,7 +951,6 @@ void ObjectManipulation::change_scale_value(int axis, double value)
|
||||
Vec3d scale = m_cache.scale;
|
||||
scale(axis) = value;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
Vec3d ref_scale = m_cache.scale;
|
||||
if (selection.is_single_volume_or_modifier()) {
|
||||
@ -1247,9 +961,6 @@ void ObjectManipulation::change_scale_value(int axis, double value)
|
||||
ref_scale = 100.0 * Vec3d::Ones();
|
||||
|
||||
this->do_scale(axis, scale.cwiseQuotient(ref_scale));
|
||||
#else
|
||||
this->do_scale(axis, 0.01 * scale);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
m_cache.scale = scale;
|
||||
m_cache.scale_rounded(axis) = DBL_MAX;
|
||||
@ -1278,39 +989,18 @@ void ObjectManipulation::change_size_value(int axis, double value)
|
||||
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
|
||||
Vec3d ref_size = m_cache.size;
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (selection.is_single_volume_or_modifier()) {
|
||||
size = size.cwiseQuotient(ref_size);
|
||||
ref_size = Vec3d::Ones();
|
||||
#else
|
||||
if (selection.is_single_volume() || selection.is_single_modifier()) {
|
||||
const GLVolume* v = selection.get_first_volume();
|
||||
const Vec3d local_size = size.cwiseQuotient(v->get_instance_scaling_factor());
|
||||
const Vec3d local_ref_size = v->bounding_box().size().cwiseProduct(v->get_volume_scaling_factor());
|
||||
const Vec3d local_change = local_size.cwiseQuotient(local_ref_size);
|
||||
|
||||
size = local_change.cwiseProduct(v->get_volume_scaling_factor());
|
||||
ref_size = Vec3d::Ones();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
else if (selection.is_single_full_instance()) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (is_world_coordinates())
|
||||
ref_size = selection.get_full_unscaled_instance_bounding_box().size();
|
||||
else
|
||||
ref_size = selection.get_full_unscaled_instance_local_bounding_box().size();
|
||||
#else
|
||||
ref_size = m_world_coordinates ?
|
||||
selection.get_unscaled_instance_bounding_box().size() :
|
||||
wxGetApp().model().objects[selection.get_first_volume()->object_idx()]->raw_mesh_bounding_box().size();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
this->do_size(axis, size.cwiseQuotient(ref_size));
|
||||
#else
|
||||
this->do_scale(axis, size.cwiseQuotient(ref_size));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
m_cache.size = size;
|
||||
m_cache.size_rounded(axis) = DBL_MAX;
|
||||
@ -1319,40 +1009,22 @@ void ObjectManipulation::change_size_value(int axis, double value)
|
||||
|
||||
void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
|
||||
{
|
||||
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
Vec3d scaling_factor = scale;
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationType transformation_type;
|
||||
if (is_local_coordinates())
|
||||
transformation_type.set_local();
|
||||
else if (is_instance_coordinates())
|
||||
transformation_type.set_instance();
|
||||
|
||||
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
if (selection.is_single_volume_or_modifier() && !is_local_coordinates())
|
||||
transformation_type.set_relative();
|
||||
|
||||
const Vec3d scaling_factor = m_uniform_scale ? scale(axis) * Vec3d::Ones() : scale;
|
||||
#else
|
||||
TransformationType transformation_type(TransformationType::World_Relative_Joint);
|
||||
if (selection.is_single_full_instance()) {
|
||||
transformation_type.set_absolute();
|
||||
if (! m_world_coordinates)
|
||||
transformation_type.set_local();
|
||||
}
|
||||
|
||||
if (m_uniform_scale || selection.requires_uniform_scale())
|
||||
scaling_factor = scale(axis) * Vec3d::Ones();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
selection.setup_cache();
|
||||
selection.scale(scaling_factor, transformation_type);
|
||||
wxGetApp().plater()->canvas3D()->do_scale(L("Set Scale"));
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void ObjectManipulation::do_size(int axis, const Vec3d& scale) const
|
||||
{
|
||||
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
@ -1368,7 +1040,6 @@ void ObjectManipulation::do_size(int axis, const Vec3d& scale) const
|
||||
selection.scale(scaling_factor, transformation_type);
|
||||
wxGetApp().plater()->canvas3D()->do_scale(L("Set Size"));
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void ObjectManipulation::on_change(const std::string& opt_key, int axis, double new_value)
|
||||
{
|
||||
@ -1407,51 +1078,14 @@ void ObjectManipulation::on_change(const std::string& opt_key, int axis, double
|
||||
|
||||
void ObjectManipulation::set_uniform_scaling(const bool use_uniform_scale)
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (!use_uniform_scale)
|
||||
// Recalculate cached values at this panel, refresh the screen.
|
||||
this->UpdateAndShow(true);
|
||||
|
||||
m_uniform_scale = use_uniform_scale;
|
||||
|
||||
set_dirty();
|
||||
#else
|
||||
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
if (selection.is_single_full_instance() && m_world_coordinates && !use_uniform_scale) {
|
||||
// Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
|
||||
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
// Is the angle close to a multiple of 90 degrees?
|
||||
if (!Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
|
||||
// Cannot apply scaling in the world coordinate system.
|
||||
//wxMessageDialog dlg(GUI::wxGetApp().mainframe,
|
||||
MessageDialog dlg(GUI::wxGetApp().mainframe,
|
||||
_L("The currently manipulated object is tilted (rotation angles are not multiples of 90°).\n"
|
||||
"Non-uniform scaling of tilted objects is only possible in the World coordinate system,\n"
|
||||
"once the rotation is embedded into the object coordinates.") + "\n" +
|
||||
_L("This operation is irreversible.\n"
|
||||
"Do you want to proceed?"),
|
||||
SLIC3R_APP_NAME,
|
||||
wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_QUESTION);
|
||||
if (dlg.ShowModal() != wxID_YES) {
|
||||
// Enforce uniform scaling.
|
||||
m_lock_bnt->SetLock(true);
|
||||
return;
|
||||
}
|
||||
// Bake the rotation into the meshes of the object.
|
||||
wxGetApp().model().objects[volume->composite_id.object_id]->bake_xy_rotation_into_meshes(volume->composite_id.instance_id);
|
||||
// Update the 3D scene, selections etc.
|
||||
wxGetApp().plater()->update();
|
||||
// Recalculate cached values at this panel, refresh the screen.
|
||||
this->UpdateAndShow(true);
|
||||
}
|
||||
}
|
||||
|
||||
m_uniform_scale = use_uniform_scale;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void ObjectManipulation::set_coordinates_type(ECoordinatesType type)
|
||||
{
|
||||
if (wxGetApp().get_mode() == comSimple)
|
||||
@ -1461,6 +1095,7 @@ void ObjectManipulation::set_coordinates_type(ECoordinatesType type)
|
||||
return;
|
||||
|
||||
m_coordinates_type = type;
|
||||
m_word_local_combo->SetSelection((int)m_coordinates_type);
|
||||
this->UpdateAndShow(true);
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
canvas->get_gizmos_manager().update_data();
|
||||
@ -1470,13 +1105,8 @@ void ObjectManipulation::set_coordinates_type(ECoordinatesType type)
|
||||
|
||||
ECoordinatesType ObjectManipulation::get_coordinates_type() const
|
||||
{
|
||||
const wxString og_name = get_og()->get_name();
|
||||
if (og_name.Contains(_L("Group manipulation")))
|
||||
return ECoordinatesType::World;
|
||||
|
||||
return m_coordinates_type;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void ObjectManipulation::msw_rescale()
|
||||
{
|
||||
@ -1517,37 +1147,25 @@ void ObjectManipulation::sys_color_changed()
|
||||
editor->sys_color_changed(this);
|
||||
|
||||
m_mirror_bitmap_on.sys_color_changed();
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
m_mirror_bitmap_off.sys_color_changed();
|
||||
m_mirror_bitmap_hidden.sys_color_changed();
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
m_reset_scale_button->sys_color_changed();
|
||||
m_reset_rotation_button->sys_color_changed();
|
||||
m_drop_to_bed_button->sys_color_changed();
|
||||
m_lock_bnt->sys_color_changed();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
for (int id = 0; id < 3; ++id) {
|
||||
m_mirror_buttons[id]->sys_color_changed();
|
||||
}
|
||||
#else
|
||||
for (int id = 0; id < 3; ++id)
|
||||
m_mirror_buttons[id].first->sys_color_changed();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void ObjectManipulation::set_coordinates_type(const wxString& type_string)
|
||||
{
|
||||
ECoordinatesType type = ECoordinatesType::World;
|
||||
if (type_string == coordinate_type_str(ECoordinatesType::Instance))
|
||||
type = ECoordinatesType::Instance;
|
||||
else if (type_string == coordinate_type_str(ECoordinatesType::Local))
|
||||
type = ECoordinatesType::Local;
|
||||
|
||||
this->set_coordinates_type(type);
|
||||
if (type_string == coordinate_type_str(ECoordinatesType::Instance))
|
||||
this->set_coordinates_type(ECoordinatesType::Instance);
|
||||
else if (type_string == coordinate_type_str(ECoordinatesType::Local))
|
||||
this->set_coordinates_type(ECoordinatesType::Local);
|
||||
else
|
||||
this->set_coordinates_type(ECoordinatesType::World);
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
static const char axes[] = { 'x', 'y', 'z' };
|
||||
ManipulationEditor::ManipulationEditor(ObjectManipulation* parent,
|
||||
|
@ -5,9 +5,7 @@
|
||||
|
||||
#include "GUI_ObjectSettings.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "GUI_Geometry.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <float.h>
|
||||
|
||||
@ -60,9 +58,7 @@ public:
|
||||
void set_value(const wxString& new_value);
|
||||
void kill_focus(ObjectManipulation *parent);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const std::string& get_full_opt_name() const { return m_full_opt_name; }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
bool has_opt_key(const std::string& key) { return m_opt_key == key; }
|
||||
|
||||
@ -125,31 +121,15 @@ private:
|
||||
// Non-owning pointers to the reset buttons, so we can hide and show them.
|
||||
ScalableButton* m_reset_scale_button{ nullptr };
|
||||
ScalableButton* m_reset_rotation_button{ nullptr };
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
ScalableButton* m_reset_skew_button{ nullptr };
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
ScalableButton* m_drop_to_bed_button{ nullptr };
|
||||
|
||||
wxCheckBox* m_check_inch {nullptr};
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
std::array<ScalableButton*, 3> m_mirror_buttons;
|
||||
#else
|
||||
// Mirroring buttons and their current state
|
||||
enum MirrorButtonState {
|
||||
mbHidden,
|
||||
mbShown,
|
||||
mbActive
|
||||
};
|
||||
std::array<std::pair<ScalableButton*, MirrorButtonState>, 3> m_mirror_buttons;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// Bitmaps for the mirroring buttons.
|
||||
ScalableBitmap m_mirror_bitmap_on;
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
ScalableBitmap m_mirror_bitmap_off;
|
||||
ScalableBitmap m_mirror_bitmap_hidden;
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
// Needs to be updated from OnIdle?
|
||||
bool m_dirty = false;
|
||||
@ -163,37 +143,21 @@ private:
|
||||
Vec3d m_new_size;
|
||||
bool m_new_enabled {true};
|
||||
bool m_uniform_scale {true};
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
ECoordinatesType m_coordinates_type{ ECoordinatesType::World };
|
||||
#else
|
||||
// Does the object manipulation panel work in World or Local coordinates?
|
||||
bool m_world_coordinates = true;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
LockButton* m_lock_bnt{ nullptr };
|
||||
choice_ctrl* m_word_local_combo { nullptr };
|
||||
|
||||
ScalableBitmap m_manifold_warning_bmp;
|
||||
wxStaticBitmap* m_fix_throught_netfab_bitmap{ nullptr };
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
wxStaticBitmap* m_mirror_warning_bitmap{ nullptr };
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
// Currently focused editor (nullptr if none)
|
||||
ManipulationEditor* m_focused_editor{ nullptr };
|
||||
#else
|
||||
#ifndef __APPLE__
|
||||
// Currently focused editor (nullptr if none)
|
||||
ManipulationEditor* m_focused_editor {nullptr};
|
||||
#endif // __APPLE__
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
wxFlexGridSizer* m_main_grid_sizer;
|
||||
wxFlexGridSizer* m_labels_grid_sizer;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
wxStaticText* m_skew_label{ nullptr };
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// sizers, used for msw_rescale
|
||||
wxBoxSizer* m_word_local_combo_sizer;
|
||||
@ -221,17 +185,12 @@ public:
|
||||
|
||||
void set_uniform_scaling(const bool use_uniform_scale);
|
||||
bool get_uniform_scaling() const { return m_uniform_scale; }
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
|
||||
void set_coordinates_type(ECoordinatesType type);
|
||||
ECoordinatesType get_coordinates_type() const;
|
||||
bool is_world_coordinates() const { return m_coordinates_type == ECoordinatesType::World; }
|
||||
bool is_instance_coordinates() const { return m_coordinates_type == ECoordinatesType::Instance; }
|
||||
bool is_local_coordinates() const { return m_coordinates_type == ECoordinatesType::Local; }
|
||||
#else
|
||||
// Does the object manipulation panel work in World or Local coordinates?
|
||||
void set_world_coordinates(const bool world_coordinates) { m_world_coordinates = world_coordinates; this->UpdateAndShow(true); }
|
||||
bool get_world_coordinates() const { return m_world_coordinates; }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void reset_cache() { m_cache.reset(); }
|
||||
#ifndef __APPLE__
|
||||
@ -247,22 +206,16 @@ public:
|
||||
void sys_color_changed();
|
||||
void on_change(const std::string& opt_key, int axis, double new_value);
|
||||
void set_focused_editor(ManipulationEditor* focused_editor) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_focused_editor = focused_editor;
|
||||
#else
|
||||
#ifndef __APPLE__
|
||||
m_focused_editor = focused_editor;
|
||||
#endif // __APPLE__
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
ManipulationEditor* get_focused_editor() { return m_focused_editor; }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
static wxString coordinate_type_str(ECoordinatesType type);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_OBJECT_MANIPULATION_DEBUG
|
||||
void render_debug_window();
|
||||
#endif // ENABLE_OBJECT_MANIPULATION_DEBUG
|
||||
|
||||
private:
|
||||
void reset_settings_value();
|
||||
@ -279,11 +232,9 @@ private:
|
||||
void change_scale_value(int axis, double value);
|
||||
void change_size_value(int axis, double value);
|
||||
void do_scale(int axis, const Vec3d &scale) const;
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void do_size(int axis, const Vec3d& scale) const;
|
||||
|
||||
void set_coordinates_type(const wxString& type_string);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
};
|
||||
|
||||
}}
|
||||
|
@ -268,39 +268,13 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) {
|
||||
return true;
|
||||
}
|
||||
else if (mouse_event.LeftUp() || is_leaving || is_dragging_finished) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
do_stop_dragging(is_leaving);
|
||||
#else
|
||||
for (auto &grabber : m_grabbers) grabber.dragging = false;
|
||||
m_dragging = false;
|
||||
|
||||
// NOTE: This should be part of GLCanvas3D
|
||||
// Reset hover_id when leave window
|
||||
if (is_leaving) m_parent.mouse_up_cleanup();
|
||||
|
||||
on_stop_dragging();
|
||||
|
||||
// There is prediction that after draggign, data are changed
|
||||
// Data are updated twice also by canvas3D::reload_scene.
|
||||
// Should be fixed.
|
||||
m_parent.get_gizmos_manager().update_data();
|
||||
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
|
||||
// Let the plater know that the dragging finished, so a delayed
|
||||
// refresh of the scene with the background processing data should
|
||||
// be performed.
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
|
||||
// updates camera target constraints
|
||||
m_parent.refresh_camera_scene_box();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void GLGizmoBase::do_stop_dragging(bool perform_mouse_cleanup)
|
||||
{
|
||||
for (auto& grabber : m_grabbers) grabber.dragging = false;
|
||||
@ -326,7 +300,6 @@ void GLGizmoBase::do_stop_dragging(bool perform_mouse_cleanup)
|
||||
// updates camera target constraints
|
||||
m_parent.refresh_camera_scene_box();
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
std::string GLGizmoBase::format(float value, unsigned int decimals) const
|
||||
{
|
||||
|
@ -234,9 +234,7 @@ protected:
|
||||
/// <returns>same as on_mouse</returns>
|
||||
bool use_grabbers(const wxMouseEvent &mouse_event);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void do_stop_dragging(bool perform_mouse_cleanup);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
private:
|
||||
// Flag for dirty visible state of Gizmo
|
||||
|
@ -219,7 +219,7 @@ GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename,
|
||||
{"Type" , _u8L("Type")},
|
||||
{"Style" , _u8L("Style")},
|
||||
{"Shape" , _u8L("Shape")},
|
||||
{"Depth ratio" , _u8L("Depth ratio")},
|
||||
{"Depth" , _u8L("Depth")},
|
||||
{"Size" , _u8L("Size")},
|
||||
};
|
||||
|
||||
@ -1413,7 +1413,7 @@ void GLGizmoCut3D::render_debug_input_window(float x)
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (m_imgui->checkbox(_L("Render cut plane as circle"), m_cut_plane_as_circle))
|
||||
if (m_imgui->checkbox(("Render cut plane as disc"), m_cut_plane_as_circle))
|
||||
m_plane.reset();
|
||||
|
||||
ImGui::PushItemWidth(0.5f * m_label_width);
|
||||
@ -1765,7 +1765,7 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors)
|
||||
m_imgui->disabled_end();
|
||||
};
|
||||
|
||||
ImGuiWrapper::text(_L("After cut") + ": ");
|
||||
ImGuiWrapper::text(_L("Cut result") + ": ");
|
||||
add_vertical_scaled_interval(0.5f);
|
||||
|
||||
m_imgui->disabled_begin(has_connectors || m_keep_as_parts);
|
||||
@ -1785,14 +1785,14 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors)
|
||||
add_vertical_scaled_interval(0.75f);
|
||||
|
||||
m_imgui->disabled_begin(has_connectors);
|
||||
ImGuiWrapper::text(_L("Cut to") + ":");
|
||||
ImGuiWrapper::text(_L("Cut into") + ":");
|
||||
|
||||
add_horizontal_scaled_interval(1.2f);
|
||||
// TRN CutGizmo: RadioButton Cut to ...
|
||||
// TRN CutGizmo: RadioButton Cut into ...
|
||||
if (m_imgui->radio_button(_L("Objects"), !m_keep_as_parts))
|
||||
m_keep_as_parts = false;
|
||||
ImGui::SameLine();
|
||||
// TRN CutGizmo: RadioButton Cut to ...
|
||||
// TRN CutGizmo: RadioButton Cut into ...
|
||||
if (m_imgui->radio_button(_L("Parts"), m_keep_as_parts))
|
||||
m_keep_as_parts = true;
|
||||
|
||||
@ -1917,9 +1917,9 @@ void GLGizmoCut3D::render_input_window_warning() const
|
||||
m_imgui->text(out);
|
||||
}
|
||||
if (!m_keep_upper && !m_keep_lower)
|
||||
m_imgui->text(wxString(ImGui::WarningMarkerSmall) + _L("Invalid state. \nNo one part is selected for keep after cut"));
|
||||
m_imgui->text(wxString(ImGui::WarningMarkerSmall) + _L("Select at least one object to keep after cutting."));
|
||||
if (!has_valid_contour())
|
||||
m_imgui->text(wxString(ImGui::WarningMarkerSmall) + _L("Warning state. \nCut plane is placed out of object"));
|
||||
m_imgui->text(wxString(ImGui::WarningMarkerSmall) + _L("Cut plane is placed out of object"));
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::on_render_input_window(float x, float y, float bottom_limit)
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "libslic3r/NSVGUtils.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Preset.hpp"
|
||||
#include "libslic3r/ClipperUtils.hpp" // union_ex
|
||||
#include "libslic3r/AppConfig.hpp" // store/load font list
|
||||
#include "libslic3r/Format/OBJ.hpp" // load obj file for default object
|
||||
@ -1326,7 +1327,7 @@ void GLGizmoEmboss::draw_text_input()
|
||||
// show warning about incorrectness view of font
|
||||
std::string warning_tool_tip;
|
||||
if (!exist_font) {
|
||||
warning_tool_tip = _u8L("Can't write text by selected font.Try to choose another font.");
|
||||
warning_tool_tip = _u8L("The text cannot be written using the selected font. Please try choosing a different font.");
|
||||
} else {
|
||||
auto append_warning = [&warning_tool_tip](std::string t) {
|
||||
if (!warning_tool_tip.empty())
|
||||
@ -1335,15 +1336,15 @@ void GLGizmoEmboss::draw_text_input()
|
||||
};
|
||||
|
||||
if (priv::is_text_empty(m_text))
|
||||
append_warning(_u8L("Embossed text can NOT contain only white spaces."));
|
||||
append_warning(_u8L("Embossed text cannot contain only white spaces."));
|
||||
if (m_text_contain_unknown_glyph)
|
||||
append_warning(_u8L("Text contain character glyph (represented by '?') unknown by font."));
|
||||
append_warning(_u8L("Text contains character glyph (represented by '?') unknown by font."));
|
||||
|
||||
const FontProp &prop = m_style_manager.get_font_prop();
|
||||
if (prop.skew.has_value()) append_warning(_u8L("Text input do not show font skew."));
|
||||
if (prop.boldness.has_value()) append_warning(_u8L("Text input do not show font boldness."));
|
||||
if (prop.skew.has_value()) append_warning(_u8L("Text input doesn't show font skew."));
|
||||
if (prop.boldness.has_value()) append_warning(_u8L("Text input doesn't show font boldness."));
|
||||
if (prop.line_gap.has_value())
|
||||
append_warning(_u8L("Text input do not show gap between lines."));
|
||||
append_warning(_u8L("Text input doesn't show gap between lines."));
|
||||
auto &ff = m_style_manager.get_font_file_with_cache();
|
||||
float imgui_size = StyleManager::get_imgui_font_size(prop, *ff.font_file, scale);
|
||||
if (imgui_size > StyleManager::max_imgui_font_size)
|
||||
@ -1885,7 +1886,7 @@ void GLGizmoEmboss::draw_font_list()
|
||||
if (ImGui::Selectable(face.name_truncated.c_str(), is_selected, flags, selectable_size)) {
|
||||
if (!select_facename(wx_face_name)) {
|
||||
del_index = index;
|
||||
wxMessageBox(GUI::format(_L("Font face \"%1%\" can't be selected."), wx_face_name));
|
||||
MessageDialog(wxGetApp().plater(), GUI::format_wxstr(_L("Font \"%1%\" can't be selected."), wx_face_name));
|
||||
}
|
||||
}
|
||||
// tooltip as full name of font face
|
||||
@ -1959,7 +1960,7 @@ void GLGizmoEmboss::draw_font_list()
|
||||
void GLGizmoEmboss::draw_model_type()
|
||||
{
|
||||
bool is_last_solid_part = m_volume->is_the_only_one_part();
|
||||
std::string title = _u8L("Text is to object");
|
||||
std::string title = _u8L("Operation");
|
||||
if (is_last_solid_part) {
|
||||
ImVec4 color{.5f, .5f, .5f, 1.f};
|
||||
m_imgui->text_colored(color, title.c_str());
|
||||
@ -1973,14 +1974,15 @@ void GLGizmoEmboss::draw_model_type()
|
||||
ModelVolumeType part = ModelVolumeType::MODEL_PART;
|
||||
ModelVolumeType type = m_volume->type();
|
||||
|
||||
if (ImGui::RadioButton(_u8L("Added").c_str(), type == part))
|
||||
//TRN EmbossOperation
|
||||
if (ImGui::RadioButton(_u8L("Join").c_str(), type == part))
|
||||
new_type = part;
|
||||
else if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", _u8L("Click to change text into object part.").c_str());
|
||||
ImGui::SameLine();
|
||||
|
||||
std::string last_solid_part_hint = _u8L("You can't change a type of the last solid part of the object.");
|
||||
if (ImGui::RadioButton(_u8L("Subtracted").c_str(), type == negative))
|
||||
if (ImGui::RadioButton(_CTX_utf8(L_CONTEXT("Cut", "EmbossOperation"), "EmbossOperation").c_str(), type == negative))
|
||||
new_type = negative;
|
||||
else if (ImGui::IsItemHovered()) {
|
||||
if (is_last_solid_part)
|
||||
@ -2187,7 +2189,7 @@ void GLGizmoEmboss::draw_style_add_button()
|
||||
}else if (only_add_style) {
|
||||
ImGui::SetTooltip("%s", _u8L("Add style to my list.").c_str());
|
||||
} else {
|
||||
ImGui::SetTooltip("%s", _u8L("Add as new named style.").c_str());
|
||||
ImGui::SetTooltip("%s", _u8L("Save as new style.").c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2203,32 +2205,47 @@ void GLGizmoEmboss::draw_delete_style_button() {
|
||||
bool is_last = m_style_manager.get_styles().size() == 1;
|
||||
bool can_delete = is_stored && !is_last;
|
||||
|
||||
std::string title = _u8L("Remove style");
|
||||
const char * popup_id = title.c_str();
|
||||
static size_t next_style_index = std::numeric_limits<size_t>::max();
|
||||
if (draw_button(m_icons, IconType::erase, !can_delete)) {
|
||||
std::string style_name = m_style_manager.get_style().name; // copy
|
||||
wxString dialog_title = _L("Remove style");
|
||||
size_t next_style_index = std::numeric_limits<size_t>::max();
|
||||
Plater *plater = wxGetApp().plater();
|
||||
bool exist_change = false;
|
||||
while (true) {
|
||||
// NOTE: can't use previous loaded activ index -> erase could change index
|
||||
size_t active_index = m_style_manager.get_style_index();
|
||||
next_style_index = (active_index > 0) ? active_index - 1 :
|
||||
active_index + 1;
|
||||
|
||||
if (next_style_index >= m_style_manager.get_styles().size()) {
|
||||
// can't remove last font style
|
||||
// TODO: inform user
|
||||
MessageDialog msg(plater, _L("Can't remove the last existing style."), dialog_title, wxICON_ERROR | wxOK);
|
||||
msg.ShowModal();
|
||||
break;
|
||||
}
|
||||
|
||||
// IMPROVE: add function can_load?
|
||||
// clean unactivable styles
|
||||
if (!m_style_manager.load_style(next_style_index)) {
|
||||
m_style_manager.erase(next_style_index);
|
||||
exist_change = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// load back
|
||||
m_style_manager.load_style(active_index);
|
||||
ImGui::OpenPopup(popup_id);
|
||||
wxString message = GUI::format_wxstr(_L("Are you sure you want to permanently remove the \"%1%\" style?"), style_name);
|
||||
MessageDialog msg(plater, message, dialog_title, wxICON_WARNING | wxYES | wxNO);
|
||||
if (msg.ShowModal() == wxID_YES) {
|
||||
// delete style
|
||||
m_style_manager.erase(active_index);
|
||||
exist_change = true;
|
||||
process();
|
||||
} else {
|
||||
// load back style
|
||||
m_style_manager.load_style(active_index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (exist_change)
|
||||
m_style_manager.store_styles_to_app_config(wxGetApp().app_config);
|
||||
}
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
@ -2239,25 +2256,6 @@ void GLGizmoEmboss::draw_delete_style_button() {
|
||||
else/*if(!is_stored)*/ tooltip = GUI::format(_L("Can't delete temporary style \"%1%\"."), style_name);
|
||||
ImGui::SetTooltip("%s", tooltip.c_str());
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupModal(popup_id)) {
|
||||
m_imgui->disable_background_fadeout_animation();
|
||||
const std::string &style_name = m_style_manager.get_style().name;
|
||||
std::string text_in_popup = GUI::format(_L("Are you sure,\nthat you want permanently and unrecoverable \nremove style \"%1%\"?"), style_name);
|
||||
ImGui::Text("%s", text_in_popup.c_str());
|
||||
if (ImGui::Button(_u8L("Yes").c_str())) {
|
||||
size_t active_index = m_style_manager.get_style_index();
|
||||
m_style_manager.load_style(next_style_index);
|
||||
m_style_manager.erase(active_index);
|
||||
m_style_manager.store_styles_to_app_config(wxGetApp().app_config);
|
||||
ImGui::CloseCurrentPopup();
|
||||
process();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(_u8L("No").c_str()))
|
||||
ImGui::CloseCurrentPopup();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
// FIX IT: it should not change volume position before successfull change
|
||||
@ -2304,7 +2302,7 @@ void GLGizmoEmboss::draw_style_list() {
|
||||
trunc_name = ImGuiWrapper::trunc(current_name, max_style_name_width);
|
||||
}
|
||||
|
||||
std::string title = _u8L("Presets");
|
||||
std::string title = _u8L("Styles");
|
||||
if (m_style_manager.exist_stored_style())
|
||||
ImGui::Text("%s", title.c_str());
|
||||
else
|
||||
@ -2313,7 +2311,7 @@ void GLGizmoEmboss::draw_style_list() {
|
||||
ImGui::SetNextItemWidth(m_gui_cfg->input_width);
|
||||
auto add_text_modify = [&is_modified](const std::string& name) {
|
||||
if (!is_modified) return name;
|
||||
return name + " (" + _u8L("modified") + ")";
|
||||
return name + Preset::suffix_modified();
|
||||
};
|
||||
std::optional<size_t> selected_style_index;
|
||||
if (ImGui::BeginCombo("##style_selector", add_text_modify(trunc_name).c_str())) {
|
||||
@ -2374,10 +2372,9 @@ void GLGizmoEmboss::draw_style_list() {
|
||||
|
||||
// Check whether user wants lose actual style modification
|
||||
if (selected_style_index.has_value() && is_modified) {
|
||||
wxString title = _L("Style modification will be lost.");
|
||||
const EmbossStyle &style = m_style_manager.get_styles()[*selected_style_index].style;
|
||||
wxString message = GUI::format_wxstr(_L("Changing style to '%1%' will discard current style modification.\n\n Would you like to continue anyway?"), style.name);
|
||||
MessageDialog not_loaded_style_message(nullptr, message, title, wxICON_WARNING | wxYES|wxNO);
|
||||
wxString message = GUI::format_wxstr(_L("Changing style to \"%1%\" will discard current style modification.\n\nWould you like to continue anyway?"), style.name);
|
||||
MessageDialog not_loaded_style_message(nullptr, message, _L("Warning"), wxICON_WARNING | wxYES | wxNO);
|
||||
if (not_loaded_style_message.ShowModal() != wxID_YES)
|
||||
selected_style_index.reset();
|
||||
}
|
||||
@ -2393,7 +2390,7 @@ void GLGizmoEmboss::draw_style_list() {
|
||||
process();
|
||||
} else {
|
||||
wxString title = _L("Not valid style.");
|
||||
wxString message = GUI::format_wxstr(_L("Style '%1%' can't be used and will be removed from a list."), style.name);
|
||||
wxString message = GUI::format_wxstr(_L("Style \"%1%\" can't be used and will be removed from a list."), style.name);
|
||||
MessageDialog not_loaded_style_message(nullptr, message, title, wxOK);
|
||||
not_loaded_style_message.ShowModal();
|
||||
m_style_manager.erase(*selected_style_index);
|
||||
@ -2792,8 +2789,8 @@ void GLGizmoEmboss::draw_advanced()
|
||||
{
|
||||
const auto &ff = m_style_manager.get_font_file_with_cache();
|
||||
if (!ff.has_value()) {
|
||||
ImGui::Text("%s", _u8L("Advanced font options could be changed only for correct font.\n"
|
||||
"Start with select correct font.").c_str());
|
||||
ImGui::Text("%s", _u8L("Advanced options cannot be changed for the selected font.\n"
|
||||
"Select another font.").c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2846,17 +2843,17 @@ void GLGizmoEmboss::draw_advanced()
|
||||
}
|
||||
m_imgui->disabled_end(); // !can_use_surface
|
||||
// TRN EmbossGizmo: font units
|
||||
std::string units = _u8L("font points");
|
||||
std::string units = _u8L("points");
|
||||
std::string units_fmt = "%.0f " + units;
|
||||
|
||||
// input gap between letters
|
||||
// input gap between characters
|
||||
auto def_char_gap = stored_style ?
|
||||
&stored_style->prop.char_gap : nullptr;
|
||||
|
||||
int half_ascent = font_info.ascent / 2;
|
||||
int min_char_gap = -half_ascent, max_char_gap = half_ascent;
|
||||
if (rev_slider(tr.char_gap, font_prop.char_gap, def_char_gap, _u8L("Revert gap between letters"),
|
||||
min_char_gap, max_char_gap, units_fmt, _L("Distance between letters"))){
|
||||
if (rev_slider(tr.char_gap, font_prop.char_gap, def_char_gap, _u8L("Revert gap between characters"),
|
||||
min_char_gap, max_char_gap, units_fmt, _L("Distance between characters"))){
|
||||
// Condition prevent recalculation when insertint out of limits value by imgui input
|
||||
if (!priv::Limits::apply(font_prop.char_gap, priv::limits.char_gap) ||
|
||||
!m_volume->text_configuration->style.prop.char_gap.has_value() ||
|
||||
@ -2918,7 +2915,7 @@ void GLGizmoEmboss::draw_advanced()
|
||||
m_imgui->disabled_begin(!allowe_surface_distance);
|
||||
|
||||
const std::string undo_move_tooltip = _u8L("Undo translation");
|
||||
const wxString move_tooltip = _L("Distance of the center of text from model surface");
|
||||
const wxString move_tooltip = _L("Distance of the center of the text to the model surface.");
|
||||
bool is_moved = false;
|
||||
bool use_inch = wxGetApp().app_config->get_bool("use_inches");
|
||||
if (use_inch) {
|
||||
@ -3040,7 +3037,7 @@ void GLGizmoEmboss::draw_advanced()
|
||||
if (priv::apply_camera_dir(cam, m_parent) && use_surface)
|
||||
process();
|
||||
} else if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("%s", _u8L("Use camera direction for text orientation").c_str());
|
||||
ImGui::SetTooltip("%s", _u8L("Orient the text towards the camera.").c_str());
|
||||
}
|
||||
#ifdef ALLOW_DEBUG_MODE
|
||||
ImGui::Text("family = %s", (font_prop.family.has_value() ?
|
||||
@ -3123,7 +3120,7 @@ bool GLGizmoEmboss::choose_font_by_wxdialog()
|
||||
(!use_deserialized_font && !m_style_manager.load_style(emboss_style, wx_font))) {
|
||||
m_style_manager.erase(font_index);
|
||||
wxString message = GUI::format_wxstr(
|
||||
"Font '%1%' can't be used. Please select another.",
|
||||
"Font \"%1%\" can't be used. Please select another.",
|
||||
emboss_style.name);
|
||||
wxString title = "Selected font is NOT True-type.";
|
||||
MessageDialog not_loaded_font_message(nullptr, message, title, wxOK);
|
||||
|
@ -358,11 +358,7 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block)
|
||||
|
||||
++mesh_id;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d trafo_matrix = mi->get_matrix_no_offset() * mv->get_matrix_no_offset();
|
||||
#else
|
||||
const Transform3d trafo_matrix = mi->get_matrix(true) * mv->get_matrix(true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
Vec3f down = (trafo_matrix.inverse() * (-Vec3d::UnitZ())).cast<float>().normalized();
|
||||
Vec3f limit = (trafo_matrix.inverse() * Vec3d(std::sin(threshold), 0, -std::cos(threshold))).cast<float>().normalized();
|
||||
|
||||
|
@ -178,11 +178,7 @@ void GLGizmoFlatten::update_planes()
|
||||
ch = ch.convex_hull_3d();
|
||||
m_planes.clear();
|
||||
on_unregister_raycasters_for_picking();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d inst_matrix = mo->instances.front()->get_matrix_no_offset();
|
||||
#else
|
||||
const Transform3d& inst_matrix = mo->instances.front()->get_matrix(true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// Following constants are used for discarding too small polygons.
|
||||
const float minimal_area = 5.f; // in square mm (world coordinates)
|
||||
|
@ -137,11 +137,7 @@ void GLGizmoHollow::render_points(const Selection& selection)
|
||||
trafo.translation()(2) += shift_z;
|
||||
const Geometry::Transformation transformation{trafo};
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d instance_scaling_matrix_inverse = transformation.get_scaling_factor_matrix().inverse();
|
||||
#else
|
||||
const Transform3d instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
const Transform3d& view_matrix = camera.get_view_matrix();
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
|
@ -60,7 +60,7 @@ static std::string surface_feature_type_as_string(Measure::SurfaceFeatureType ty
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
case Measure::SurfaceFeatureType::Undef: { return _u8L("No feature"); }
|
||||
case Measure::SurfaceFeatureType::Undef: { return ("No feature"); }
|
||||
case Measure::SurfaceFeatureType::Point: { return _u8L("Vertex"); }
|
||||
case Measure::SurfaceFeatureType::Edge: { return _u8L("Edge"); }
|
||||
case Measure::SurfaceFeatureType::Circle: { return _u8L("Circle"); }
|
||||
|
@ -1,9 +1,7 @@
|
||||
#include "GLGizmoMove.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
@ -22,8 +20,7 @@ GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filenam
|
||||
|
||||
std::string GLGizmoMove3D::get_tooltip() const
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (m_hover_id == 0)
|
||||
if (m_hover_id == 0)
|
||||
return "X: " + format(m_displacement.x(), 2);
|
||||
else if (m_hover_id == 1)
|
||||
return "Y: " + format(m_displacement.y(), 2);
|
||||
@ -31,20 +28,6 @@ std::string GLGizmoMove3D::get_tooltip() const
|
||||
return "Z: " + format(m_displacement.z(), 2);
|
||||
else
|
||||
return "";
|
||||
#else
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const bool show_position = selection.is_single_full_instance();
|
||||
const Vec3d& position = selection.get_bounding_box().center();
|
||||
|
||||
if (m_hover_id == 0 || m_grabbers[0].dragging)
|
||||
return "X: " + format(show_position ? position.x() : m_displacement.x(), 2);
|
||||
else if (m_hover_id == 1 || m_grabbers[1].dragging)
|
||||
return "Y: " + format(show_position ? position.y() : m_displacement.y(), 2);
|
||||
else if (m_hover_id == 2 || m_grabbers[2].dragging)
|
||||
return "Z: " + format(show_position ? position.z() : m_displacement.z(), 2);
|
||||
else
|
||||
return "";
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) {
|
||||
@ -86,7 +69,6 @@ void GLGizmoMove3D::on_start_dragging()
|
||||
assert(m_hover_id != -1);
|
||||
|
||||
m_displacement = Vec3d::Zero();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||
if (coordinates_type == ECoordinatesType::World)
|
||||
@ -102,13 +84,6 @@ void GLGizmoMove3D::on_start_dragging()
|
||||
m_starting_box_center = m_center;
|
||||
m_starting_box_bottom_center = m_center;
|
||||
m_starting_box_bottom_center.z() = m_bounding_box.min.z();
|
||||
#else
|
||||
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
|
||||
m_starting_drag_position = m_grabbers[m_hover_id].center;
|
||||
m_starting_box_center = box.center();
|
||||
m_starting_box_bottom_center = box.center();
|
||||
m_starting_box_bottom_center.z() = box.min.z();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_stop_dragging()
|
||||
@ -127,7 +102,6 @@ void GLGizmoMove3D::on_dragging(const UpdateData& data)
|
||||
m_displacement.z() = calc_projection(data);
|
||||
|
||||
Selection &selection = m_parent.get_selection();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationType trafo_type;
|
||||
trafo_type.set_relative();
|
||||
switch (wxGetApp().obj_manipul()->get_coordinates_type())
|
||||
@ -137,9 +111,6 @@ void GLGizmoMove3D::on_dragging(const UpdateData& data)
|
||||
default: { break; }
|
||||
}
|
||||
selection.translate(m_displacement, trafo_type);
|
||||
#else
|
||||
selection.translate(m_displacement);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_render()
|
||||
@ -147,7 +118,6 @@ void GLGizmoMove3D::on_render()
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const auto& [box, box_trafo] = selection.get_bounding_box_in_current_reference_system();
|
||||
m_bounding_box = box;
|
||||
@ -171,42 +141,16 @@ void GLGizmoMove3D::on_render()
|
||||
// z axis
|
||||
m_grabbers[2].center = { 0.0, 0.0, half_box_size.z() + Offset };
|
||||
m_grabbers[2].color = AXES_COLOR[2];
|
||||
#else
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
const Vec3d& center = box.center();
|
||||
|
||||
// x axis
|
||||
m_grabbers[0].center = { box.max.x() + Offset, center.y(), center.z() };
|
||||
m_grabbers[0].color = AXES_COLOR[0];
|
||||
|
||||
// y axis
|
||||
m_grabbers[1].center = { center.x(), box.max.y() + Offset, center.z() };
|
||||
m_grabbers[1].color = AXES_COLOR[1];
|
||||
|
||||
// z axis
|
||||
m_grabbers[2].center = { center.x(), center.y(), box.max.z() + Offset };
|
||||
m_grabbers[2].color = AXES_COLOR[2];
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
if (!OpenGLManager::get_gl_info().is_core_profile())
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
auto render_grabber_connection = [this, &zero](unsigned int id) {
|
||||
#else
|
||||
auto render_grabber_connection = [this, ¢er](unsigned int id) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
if (m_grabbers[id].enabled) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(m_grabbers[id].center)) {
|
||||
m_grabber_connections[id].old_center = m_grabbers[id].center;
|
||||
#else
|
||||
if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(center)) {
|
||||
m_grabber_connections[id].old_center = center;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_grabber_connections[id].model.reset();
|
||||
|
||||
GLModel::Geometry init_data;
|
||||
@ -216,11 +160,7 @@ void GLGizmoMove3D::on_render()
|
||||
init_data.indices.reserve(2);
|
||||
|
||||
// vertices
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
init_data.add_vertex((Vec3f)zero.cast<float>());
|
||||
#else
|
||||
init_data.add_vertex((Vec3f)center.cast<float>());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
init_data.add_vertex((Vec3f)m_grabbers[id].center.cast<float>());
|
||||
|
||||
// indices
|
||||
@ -242,11 +182,7 @@ void GLGizmoMove3D::on_render()
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
|
||||
#else
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
@ -264,11 +200,7 @@ void GLGizmoMove3D::on_render()
|
||||
}
|
||||
|
||||
// draw grabbers
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
render_grabbers(m_bounding_box);
|
||||
#else
|
||||
render_grabbers(box);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
else {
|
||||
// draw axis
|
||||
@ -281,11 +213,7 @@ void GLGizmoMove3D::on_render()
|
||||
shader->start_using();
|
||||
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix()* base_matrix);
|
||||
#else
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
@ -303,11 +231,7 @@ void GLGizmoMove3D::on_render()
|
||||
shader->start_using();
|
||||
shader->set_uniform("emission_factor", 0.1f);
|
||||
// draw grabber
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Vec3d box_size = m_bounding_box.size();
|
||||
#else
|
||||
const Vec3d box_size = box.size();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const float mean_size = (float)((box_size.x() + box_size.y() + box_size.z()) / 3.0);
|
||||
m_grabbers[m_hover_id].render(true, mean_size);
|
||||
shader->stop_using();
|
||||
@ -352,7 +276,6 @@ double GLGizmoMove3D::calc_projection(const UpdateData& data) const
|
||||
return projection;
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Transform3d GLGizmoMove3D::local_transform(const Selection& selection) const
|
||||
{
|
||||
Transform3d ret = Geometry::translation_transform(m_center);
|
||||
@ -365,7 +288,6 @@ Transform3d GLGizmoMove3D::local_transform(const Selection& selection) const
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
@ -7,19 +7,15 @@
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
class Selection;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
class GLGizmoMove3D : public GLGizmoBase
|
||||
{
|
||||
static const double Offset;
|
||||
|
||||
Vec3d m_displacement{ Vec3d::Zero() };
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d m_center{ Vec3d::Zero() };
|
||||
BoundingBoxf3 m_bounding_box;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double m_snap_step{ 1.0 };
|
||||
Vec3d m_starting_drag_position{ Vec3d::Zero() };
|
||||
Vec3d m_starting_box_center{ Vec3d::Zero() };
|
||||
@ -65,9 +61,7 @@ protected:
|
||||
|
||||
private:
|
||||
double calc_projection(const UpdateData& data) const;
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Transform3d local_transform(const Selection& selection) const;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
};
|
||||
|
||||
|
||||
|
@ -266,11 +266,7 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d complete_scaling_matrix_inverse = Geometry::Transformation(trafo).get_scaling_factor_matrix().inverse();
|
||||
#else
|
||||
const Transform3d complete_scaling_matrix_inverse = Geometry::Transformation(trafo).get_matrix(true, true, false, true).inverse();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
ColorRGBA render_color = { 0.0f, 0.0f, 0.0f, 0.25f };
|
||||
if (m_button_down == Button::Left)
|
||||
@ -465,11 +461,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
const ModelObject *mo = m_c->selection_info()->model_object();
|
||||
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d trafo_matrix_not_translate = mi->get_transformation().get_matrix_no_offset() * mo->volumes[m_rr.mesh_id]->get_matrix_no_offset();
|
||||
#else
|
||||
const Transform3d trafo_matrix_not_translate = mi->get_transformation().get_matrix(true) * mo->volumes[m_rr.mesh_id]->get_matrix(true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const Transform3d trafo_matrix = mi->get_transformation().get_matrix() * mo->volumes[m_rr.mesh_id]->get_matrix();
|
||||
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, this->get_clipping_plane_in_volume_coordinates(trafo_matrix), m_smart_fill_angle,
|
||||
m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, true);
|
||||
@ -508,11 +500,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||
const ModelObject *mo = m_c->selection_info()->model_object();
|
||||
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
|
||||
const Transform3d instance_trafo = mi->get_transformation().get_matrix();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix_no_offset();
|
||||
#else
|
||||
const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// Precalculate transformations of individual meshes.
|
||||
std::vector<Transform3d> trafo_matrices;
|
||||
@ -520,11 +508,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||
for (const ModelVolume *mv : mo->volumes)
|
||||
if (mv->is_model_part()) {
|
||||
trafo_matrices.emplace_back(instance_trafo * mv->get_matrix());
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix_no_offset());
|
||||
#else
|
||||
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix(true));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
std::vector<std::vector<ProjectedMousePosition>> projected_mouse_positions_by_mesh = get_projected_mouse_positions(mouse_position, 1., trafo_matrices);
|
||||
@ -606,11 +590,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||
const ModelObject *mo = m_c->selection_info()->model_object();
|
||||
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
|
||||
const Transform3d instance_trafo = mi->get_transformation().get_matrix();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix_no_offset();
|
||||
#else
|
||||
const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// Precalculate transformations of individual meshes.
|
||||
std::vector<Transform3d> trafo_matrices;
|
||||
@ -618,11 +598,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||
for (const ModelVolume *mv : mo->volumes)
|
||||
if (mv->is_model_part()) {
|
||||
trafo_matrices.emplace_back(instance_trafo * mv->get_matrix());
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate* mv->get_matrix_no_offset());
|
||||
#else
|
||||
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix(true));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
// Now "click" into all the prepared points and spill paint around them.
|
||||
|
@ -1,9 +1,7 @@
|
||||
#include "GLGizmoRotate.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/ImGuiWrapper.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
@ -100,27 +98,12 @@ bool GLGizmoRotate::on_init()
|
||||
|
||||
void GLGizmoRotate::on_start_dragging()
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
init_data_from_selection(m_parent.get_selection());
|
||||
#else
|
||||
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
|
||||
m_center = box.center();
|
||||
m_radius = Offset + box.radius();
|
||||
m_snap_coarse_in_radius = m_radius / 3.0f;
|
||||
m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius;
|
||||
m_snap_fine_in_radius = m_radius;
|
||||
m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void GLGizmoRotate::on_dragging(const UpdateData &data)
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(data.mouse_ray));
|
||||
#else
|
||||
const Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(data.mouse_ray, m_parent.get_selection()));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
const Vec2d orig_dir = Vec2d::UnitX();
|
||||
const Vec2d new_dir = mouse_pos.normalized();
|
||||
|
||||
@ -155,22 +138,8 @@ void GLGizmoRotate::on_render()
|
||||
return;
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
if (m_hover_id != 0 && !m_grabbers.front().dragging) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (m_hover_id != 0 && !m_grabbers.front().dragging)
|
||||
init_data_from_selection(selection);
|
||||
#else
|
||||
m_center = box.center();
|
||||
m_radius = Offset + box.radius();
|
||||
m_snap_coarse_in_radius = m_radius / 3.0f;
|
||||
m_snap_coarse_out_radius = 2.0f * m_snap_coarse_in_radius;
|
||||
m_snap_fine_in_radius = m_radius;
|
||||
m_snap_fine_out_radius = m_radius * (1.0f + ScaleLongTooth);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
const double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset);
|
||||
m_grabbers.front().center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0);
|
||||
@ -223,14 +192,9 @@ void GLGizmoRotate::on_render()
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
render_grabber(m_bounding_box);
|
||||
#else
|
||||
render_grabber(box);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void GLGizmoRotate::init_data_from_selection(const Selection& selection)
|
||||
{
|
||||
const auto [box, box_trafo] = m_force_local_coordinate ?
|
||||
@ -245,7 +209,6 @@ void GLGizmoRotate::init_data_from_selection(const Selection& selection)
|
||||
m_snap_fine_in_radius = m_radius;
|
||||
m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
@ -472,20 +435,12 @@ Transform3d GLGizmoRotate::local_transform(const Selection& selection) const
|
||||
{
|
||||
case X:
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
ret = Geometry::rotation_transform(0.5 * PI * Vec3d::UnitY()) * Geometry::rotation_transform(-0.5 * PI * Vec3d::UnitZ());
|
||||
#else
|
||||
ret = Geometry::assemble_transform(Vec3d::Zero(), 0.5 * PI * Vec3d::UnitY()) * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
break;
|
||||
}
|
||||
case Y:
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
ret = Geometry::rotation_transform(-0.5 * PI * Vec3d::UnitZ()) * Geometry::rotation_transform(-0.5 * PI * Vec3d::UnitY());
|
||||
#else
|
||||
ret = Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitZ()) * Geometry::assemble_transform(Vec3d::Zero(), -0.5 * PI * Vec3d::UnitY());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -496,21 +451,10 @@ Transform3d GLGizmoRotate::local_transform(const Selection& selection) const
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
return m_orient_matrix * ret;
|
||||
#else
|
||||
if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes())
|
||||
ret = selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true) * ret;
|
||||
|
||||
return Geometry::assemble_transform(m_center) * ret;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray) const
|
||||
#else
|
||||
Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
{
|
||||
const double half_pi = 0.5 * double(PI);
|
||||
|
||||
@ -538,12 +482,7 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, cons
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m = m * Geometry::Transformation(m_orient_matrix).get_matrix_no_offset().inverse();
|
||||
#else
|
||||
if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes())
|
||||
m = m * selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true).inverse();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
m.translate(-m_center);
|
||||
|
||||
@ -577,7 +516,6 @@ bool GLGizmoRotate3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
if (mouse_event.Dragging() && m_dragging) {
|
||||
// Apply new temporary rotations
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationType transformation_type;
|
||||
if (m_parent.get_selection().is_wipe_tower())
|
||||
transformation_type = TransformationType::World_Relative_Joint;
|
||||
@ -590,9 +528,6 @@ bool GLGizmoRotate3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||
case ECoordinatesType::Local: { transformation_type = TransformationType::Local_Relative_Joint; break; }
|
||||
}
|
||||
}
|
||||
#else
|
||||
TransformationType transformation_type(TransformationType::World_Relative_Joint);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
if (mouse_event.AltDown())
|
||||
transformation_type.set_independent();
|
||||
m_parent.get_selection().rotate(get_rotation(), transformation_type);
|
||||
@ -602,26 +537,14 @@ bool GLGizmoRotate3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||
|
||||
void GLGizmoRotate3D::data_changed() {
|
||||
if (m_parent.get_selection().is_wipe_tower()) {
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
const DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
const float wipe_tower_rotation_angle =
|
||||
dynamic_cast<const ConfigOptionFloat*>(
|
||||
config.option("wipe_tower_rotation_angle"))->value;
|
||||
set_rotation(Vec3d(0., 0., (M_PI / 180.) * wipe_tower_rotation_angle));
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
m_gizmos[0].disable_grabber();
|
||||
m_gizmos[1].disable_grabber();
|
||||
}
|
||||
else {
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
set_rotation(Vec3d::Zero());
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
m_gizmos[0].enable_grabber();
|
||||
m_gizmos[1].enable_grabber();
|
||||
}
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
set_rotation(Vec3d::Zero());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
bool GLGizmoRotate3D::on_init()
|
||||
|
@ -35,10 +35,8 @@ private:
|
||||
float m_snap_coarse_out_radius{ 0.0f };
|
||||
float m_snap_fine_in_radius{ 0.0f };
|
||||
float m_snap_fine_out_radius{ 0.0f };
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
BoundingBoxf3 m_bounding_box;
|
||||
Transform3d m_orient_matrix{ Transform3d::Identity() };
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
GLModel m_circle;
|
||||
GLModel m_scale;
|
||||
@ -109,15 +107,9 @@ private:
|
||||
Transform3d local_transform(const Selection& selection) const;
|
||||
|
||||
// returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d mouse_position_in_local_plane(const Linef3& mouse_ray) const;
|
||||
#else
|
||||
Vec3d mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void init_data_from_selection(const Selection& selection);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
};
|
||||
|
||||
class GLGizmoRotate3D : public GLGizmoBase
|
||||
|
@ -1,9 +1,7 @@
|
||||
#include "GLGizmoScale.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
@ -20,7 +18,6 @@ const double GLGizmoScale3D::Offset = 5.0;
|
||||
GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
, m_scale(Vec3d::Ones())
|
||||
, m_offset(Vec3d::Zero())
|
||||
, m_snap_step(0.05)
|
||||
, m_base_color(DEFAULT_BASE_COLOR)
|
||||
, m_drag_color(DEFAULT_DRAG_COLOR)
|
||||
@ -37,17 +34,7 @@ GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filen
|
||||
|
||||
std::string GLGizmoScale3D::get_tooltip() const
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Vec3d scale = 100.0 * m_scale;
|
||||
#else
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
Vec3d scale = 100.0 * Vec3d::Ones();
|
||||
if (selection.is_single_full_instance())
|
||||
scale = 100.0 * selection.get_first_volume()->get_instance_scaling_factor();
|
||||
else if (selection.is_single_modifier() || selection.is_single_volume())
|
||||
scale = 100.0 * selection.get_first_volume()->get_volume_scaling_factor();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
if (m_hover_id == 0 || m_hover_id == 1 || m_grabbers[0].dragging || m_grabbers[1].dragging)
|
||||
return "X: " + format(scale.x(), 4) + "%";
|
||||
@ -67,12 +54,17 @@ std::string GLGizmoScale3D::get_tooltip() const
|
||||
return "";
|
||||
}
|
||||
|
||||
static int constraint_id(int grabber_id)
|
||||
{
|
||||
static const std::vector<int> id_map = { 1, 0, 3, 2, 5, 4, 8, 9, 6, 7 };
|
||||
return (0 <= grabber_id && grabber_id < (int)id_map.size()) ? id_map[grabber_id] : -1;
|
||||
}
|
||||
|
||||
bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
if (mouse_event.Dragging()) {
|
||||
if (m_dragging) {
|
||||
// Apply new temporary scale factors
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationType transformation_type;
|
||||
if (wxGetApp().obj_manipul()->is_local_coordinates())
|
||||
transformation_type.set_local();
|
||||
@ -80,20 +72,22 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
|
||||
transformation_type.set_instance();
|
||||
|
||||
transformation_type.set_relative();
|
||||
#else
|
||||
TransformationType transformation_type(TransformationType::Local_Absolute_Joint);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
if (mouse_event.AltDown())
|
||||
transformation_type.set_independent();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_parent.get_selection().scale_and_translate(m_scale, m_offset, transformation_type);
|
||||
#else
|
||||
Selection& selection = m_parent.get_selection();
|
||||
selection.scale(m_scale, transformation_type);
|
||||
if (mouse_event.CmdDown()) selection.translate(m_offset, true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
if (m_starting.ctrl_down) {
|
||||
// constrained scale:
|
||||
// uses the performed scale to calculate the new position of the constrained grabber
|
||||
// and from that calculates the offset (in world coordinates) to be applied to fullfill the constraint
|
||||
update_render_data();
|
||||
const Vec3d constraint_position = m_grabbers_transform * m_grabbers[constraint_id(m_hover_id)].center;
|
||||
// re-apply the scale because the selection always applies the transformations with respect to the initial state
|
||||
// set into on_start_dragging() with the call to selection.setup_cache()
|
||||
m_parent.get_selection().scale_and_translate(m_scale, m_starting.constraint_position - constraint_position, transformation_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
return use_grabbers(mouse_event);
|
||||
@ -107,29 +101,7 @@ void GLGizmoScale3D::enable_ununiversal_scale(bool enable)
|
||||
|
||||
void GLGizmoScale3D::data_changed()
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
set_scale(Vec3d::Ones());
|
||||
#else
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
bool enable_scale_xyz = selection.is_single_full_instance() ||
|
||||
selection.is_single_volume() ||
|
||||
selection.is_single_modifier();
|
||||
|
||||
for (unsigned int i = 0; i < 6; ++i)
|
||||
m_grabbers[i].enabled = enable_scale_xyz;
|
||||
|
||||
if (enable_scale_xyz) {
|
||||
// all volumes in the selection belongs to the same instance, any of
|
||||
// them contains the needed data, so we take the first
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
if (selection.is_single_full_instance())
|
||||
set_scale(volume->get_instance_scaling_factor());
|
||||
else if (selection.is_single_volume() || selection.is_single_modifier())
|
||||
set_scale(volume->get_volume_scaling_factor());
|
||||
}
|
||||
else
|
||||
set_scale(Vec3d::Ones());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
bool GLGizmoScale3D::on_init()
|
||||
@ -138,20 +110,7 @@ bool GLGizmoScale3D::on_init()
|
||||
m_grabbers.push_back(Grabber());
|
||||
}
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
double half_pi = 0.5 * (double)PI;
|
||||
|
||||
// x axis
|
||||
m_grabbers[0].angles.y() = half_pi;
|
||||
m_grabbers[1].angles.y() = half_pi;
|
||||
|
||||
// y axis
|
||||
m_grabbers[2].angles.x() = half_pi;
|
||||
m_grabbers[3].angles.x() = half_pi;
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
m_shortcut_key = WXK_CONTROL_S;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -170,27 +129,17 @@ void GLGizmoScale3D::on_start_dragging()
|
||||
{
|
||||
assert(m_hover_id != -1);
|
||||
m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_starting.drag_position = m_grabbers_transform * m_grabbers[m_hover_id].center;
|
||||
m_starting.box = m_bounding_box;
|
||||
m_starting.center = m_center;
|
||||
m_starting.instance_center = m_instance_center;
|
||||
#else
|
||||
m_starting.drag_position = m_grabbers[m_hover_id].center;
|
||||
m_starting.box = (m_starting.ctrl_down && m_hover_id < 6) ? m_bounding_box : m_parent.get_selection().get_bounding_box();
|
||||
|
||||
const Vec3d& center = m_starting.box.center();
|
||||
m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max.x(), center.y(), center.z());
|
||||
m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min.x(), center.y(), center.z());
|
||||
m_starting.pivots[2] = m_transform * Vec3d(center.x(), m_starting.box.max.y(), center.z());
|
||||
m_starting.pivots[3] = m_transform * Vec3d(center.x(), m_starting.box.min.y(), center.z());
|
||||
m_starting.pivots[4] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.max.z());
|
||||
m_starting.pivots[5] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.min.z());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
m_starting.constraint_position = m_grabbers_transform * m_grabbers[constraint_id(m_hover_id)].center;
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_stop_dragging() {
|
||||
void GLGizmoScale3D::on_stop_dragging()
|
||||
{
|
||||
m_parent.do_scale(L("Gizmo-Scale"));
|
||||
m_starting.ctrl_down = false;
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_dragging(const UpdateData& data)
|
||||
@ -205,60 +154,18 @@ void GLGizmoScale3D::on_dragging(const UpdateData& data)
|
||||
do_scale_uniform(data);
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void GLGizmoScale3D::on_render()
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
const auto& [box, box_trafo] = selection.get_bounding_box_in_current_reference_system();
|
||||
m_bounding_box = box;
|
||||
m_center = box_trafo.translation();
|
||||
m_grabbers_transform = box_trafo;
|
||||
m_instance_center = (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) ? selection.get_first_volume()->get_instance_offset() : m_center;
|
||||
|
||||
// x axis
|
||||
const Vec3d box_half_size = 0.5 * m_bounding_box.size();
|
||||
bool use_constrain = wxGetKeyState(WXK_CONTROL) && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier());
|
||||
|
||||
m_grabbers[0].center = { -(box_half_size.x() + Offset), 0.0, 0.0 };
|
||||
m_grabbers[0].color = (use_constrain && m_hover_id == 1) ? CONSTRAINED_COLOR : AXES_COLOR[0];
|
||||
m_grabbers[1].center = { box_half_size.x() + Offset, 0.0, 0.0 };
|
||||
m_grabbers[1].color = (use_constrain && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0];
|
||||
|
||||
// y axis
|
||||
m_grabbers[2].center = { 0.0, -(box_half_size.y() + Offset), 0.0 };
|
||||
m_grabbers[2].color = (use_constrain && m_hover_id == 3) ? CONSTRAINED_COLOR : AXES_COLOR[1];
|
||||
m_grabbers[3].center = { 0.0, box_half_size.y() + Offset, 0.0 };
|
||||
m_grabbers[3].color = (use_constrain && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1];
|
||||
|
||||
// z axis
|
||||
m_grabbers[4].center = { 0.0, 0.0, -(box_half_size.z() + Offset) };
|
||||
m_grabbers[4].color = (use_constrain && m_hover_id == 5) ? CONSTRAINED_COLOR : AXES_COLOR[2];
|
||||
m_grabbers[5].center = { 0.0, 0.0, box_half_size.z() + Offset };
|
||||
m_grabbers[5].color = (use_constrain && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2];
|
||||
|
||||
// uniform
|
||||
m_grabbers[6].center = { -(box_half_size.x() + Offset), -(box_half_size.y() + Offset), 0.0 };
|
||||
m_grabbers[6].color = (use_constrain && m_hover_id == 8) ? CONSTRAINED_COLOR : m_highlight_color;
|
||||
m_grabbers[7].center = { box_half_size.x() + Offset, -(box_half_size.y() + Offset), 0.0 };
|
||||
m_grabbers[7].color = (use_constrain && m_hover_id == 9) ? CONSTRAINED_COLOR : m_highlight_color;
|
||||
m_grabbers[8].center = { box_half_size.x() + Offset, box_half_size.y() + Offset, 0.0 };
|
||||
m_grabbers[8].color = (use_constrain && m_hover_id == 6) ? CONSTRAINED_COLOR : m_highlight_color;
|
||||
m_grabbers[9].center = { -(box_half_size.x() + Offset), box_half_size.y() + Offset, 0.0 };
|
||||
m_grabbers[9].color = (use_constrain && m_hover_id == 7) ? CONSTRAINED_COLOR : m_highlight_color;
|
||||
update_render_data();
|
||||
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
if (!OpenGLManager::get_gl_info().is_core_profile())
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
m_grabbers[i].matrix = m_grabbers_transform;
|
||||
}
|
||||
|
||||
const float grabber_mean_size = (float)((m_bounding_box.size().x() + m_bounding_box.size().y() + m_bounding_box.size().z()) / 3.0);
|
||||
|
||||
if (m_hover_id == -1) {
|
||||
@ -423,267 +330,6 @@ void GLGizmoScale3D::on_render()
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void GLGizmoScale3D::on_render()
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
m_bounding_box.reset();
|
||||
m_transform = Transform3d::Identity();
|
||||
// Transforms grabbers' offsets to world refefence system
|
||||
Transform3d offsets_transform = Transform3d::Identity();
|
||||
m_offsets_transform = Transform3d::Identity();
|
||||
Vec3d angles = Vec3d::Zero();
|
||||
|
||||
if (selection.is_single_full_instance()) {
|
||||
// calculate bounding box in instance local reference system
|
||||
const Selection::IndicesList& idxs = selection.get_volume_idxs();
|
||||
for (unsigned int idx : idxs) {
|
||||
const GLVolume& v = *selection.get_volume(idx);
|
||||
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix()));
|
||||
}
|
||||
|
||||
// gets transform from first selected volume
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
m_transform = v.get_instance_transformation().get_matrix();
|
||||
|
||||
// gets angles from first selected volume
|
||||
angles = v.get_instance_rotation();
|
||||
// consider rotation+mirror only components of the transform for offsets
|
||||
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v.get_instance_mirror());
|
||||
m_offsets_transform = offsets_transform;
|
||||
}
|
||||
else if (selection.is_single_modifier() || selection.is_single_volume()) {
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
m_bounding_box = v.bounding_box();
|
||||
m_transform = v.world_matrix();
|
||||
angles = Geometry::extract_rotation(m_transform);
|
||||
// consider rotation+mirror only components of the transform for offsets
|
||||
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v.get_instance_mirror());
|
||||
m_offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), v.get_volume_rotation(), Vec3d::Ones(), v.get_volume_mirror());
|
||||
}
|
||||
else
|
||||
m_bounding_box = selection.get_bounding_box();
|
||||
|
||||
const Vec3d& center = m_bounding_box.center();
|
||||
const Vec3d offset_x = offsets_transform * Vec3d((double)Offset, 0.0, 0.0);
|
||||
const Vec3d offset_y = offsets_transform * Vec3d(0.0, (double)Offset, 0.0);
|
||||
const Vec3d offset_z = offsets_transform * Vec3d(0.0, 0.0, (double)Offset);
|
||||
|
||||
const bool ctrl_down = (m_dragging && m_starting.ctrl_down) || (!m_dragging && wxGetKeyState(WXK_CONTROL));
|
||||
|
||||
// x axis
|
||||
m_grabbers[0].center = m_transform * Vec3d(m_bounding_box.min.x(), center.y(), center.z()) - offset_x;
|
||||
m_grabbers[0].color = (ctrl_down && m_hover_id == 1) ? CONSTRAINED_COLOR : AXES_COLOR[0];
|
||||
m_grabbers[1].center = m_transform * Vec3d(m_bounding_box.max.x(), center.y(), center.z()) + offset_x;
|
||||
m_grabbers[1].color = (ctrl_down && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0];
|
||||
|
||||
// y axis
|
||||
m_grabbers[2].center = m_transform * Vec3d(center.x(), m_bounding_box.min.y(), center.z()) - offset_y;
|
||||
m_grabbers[2].color = (ctrl_down && m_hover_id == 3) ? CONSTRAINED_COLOR : AXES_COLOR[1];
|
||||
m_grabbers[3].center = m_transform * Vec3d(center.x(), m_bounding_box.max.y(), center.z()) + offset_y;
|
||||
m_grabbers[3].color = (ctrl_down && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1];
|
||||
|
||||
// z axis
|
||||
m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_bounding_box.min.z()) - offset_z;
|
||||
m_grabbers[4].color = (ctrl_down && m_hover_id == 5) ? CONSTRAINED_COLOR : AXES_COLOR[2];
|
||||
m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_bounding_box.max.z()) + offset_z;
|
||||
m_grabbers[5].color = (ctrl_down && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2];
|
||||
|
||||
// uniform
|
||||
m_grabbers[6].center = m_transform * Vec3d(m_bounding_box.min.x(), m_bounding_box.min.y(), center.z()) - offset_x - offset_y;
|
||||
m_grabbers[7].center = m_transform * Vec3d(m_bounding_box.max.x(), m_bounding_box.min.y(), center.z()) + offset_x - offset_y;
|
||||
m_grabbers[8].center = m_transform * Vec3d(m_bounding_box.max.x(), m_bounding_box.max.y(), center.z()) + offset_x + offset_y;
|
||||
m_grabbers[9].center = m_transform * Vec3d(m_bounding_box.min.x(), m_bounding_box.max.y(), center.z()) - offset_x + offset_y;
|
||||
|
||||
for (int i = 6; i < 10; ++i) {
|
||||
m_grabbers[i].color = m_highlight_color;
|
||||
}
|
||||
|
||||
// sets grabbers orientation
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
m_grabbers[i].angles = angles;
|
||||
}
|
||||
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
if (!OpenGLManager::get_gl_info().is_core_profile())
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
|
||||
|
||||
const BoundingBoxf3& selection_box = selection.get_bounding_box();
|
||||
const float grabber_mean_size = (float)((selection_box.size().x() + selection_box.size().y() + selection_box.size().z()) / 3.0);
|
||||
|
||||
if (m_hover_id == -1) {
|
||||
// draw connections
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat");
|
||||
#else
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3])));
|
||||
shader->set_uniform("width", 0.25f);
|
||||
shader->set_uniform("gap_size", 0.0f);
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
if (m_grabbers[0].enabled && m_grabbers[1].enabled)
|
||||
render_grabbers_connection(0, 1, m_grabbers[0].color);
|
||||
if (m_grabbers[2].enabled && m_grabbers[3].enabled)
|
||||
render_grabbers_connection(2, 3, m_grabbers[2].color);
|
||||
if (m_grabbers[4].enabled && m_grabbers[5].enabled)
|
||||
render_grabbers_connection(4, 5, m_grabbers[4].color);
|
||||
render_grabbers_connection(6, 7, m_base_color);
|
||||
render_grabbers_connection(7, 8, m_base_color);
|
||||
render_grabbers_connection(8, 9, m_base_color);
|
||||
render_grabbers_connection(9, 6, m_base_color);
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
// draw grabbers
|
||||
render_grabbers(grabber_mean_size);
|
||||
}
|
||||
else if ((m_hover_id == 0 || m_hover_id == 1) && m_grabbers[0].enabled && m_grabbers[1].enabled) {
|
||||
// draw connections
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat");
|
||||
#else
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3])));
|
||||
shader->set_uniform("width", 0.25f);
|
||||
shader->set_uniform("gap_size", 0.0f);
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
render_grabbers_connection(0, 1, m_grabbers[0].color);
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
// draw grabbers
|
||||
shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
shader->set_uniform("emission_factor", 0.1f);
|
||||
m_grabbers[0].render(true, grabber_mean_size);
|
||||
m_grabbers[1].render(true, grabber_mean_size);
|
||||
shader->stop_using();
|
||||
}
|
||||
}
|
||||
else if ((m_hover_id == 2 || m_hover_id == 3) && m_grabbers[2].enabled && m_grabbers[3].enabled) {
|
||||
// draw connections
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat");
|
||||
#else
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3])));
|
||||
shader->set_uniform("width", 0.25f);
|
||||
shader->set_uniform("gap_size", 0.0f);
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
render_grabbers_connection(2, 3, m_grabbers[2].color);
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
// draw grabbers
|
||||
shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
shader->set_uniform("emission_factor", 0.1f);
|
||||
m_grabbers[2].render(true, grabber_mean_size);
|
||||
m_grabbers[3].render(true, grabber_mean_size);
|
||||
shader->stop_using();
|
||||
}
|
||||
}
|
||||
else if ((m_hover_id == 4 || m_hover_id == 5) && m_grabbers[4].enabled && m_grabbers[5].enabled) {
|
||||
// draw connections
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat");
|
||||
#else
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3])));
|
||||
shader->set_uniform("width", 0.25f);
|
||||
shader->set_uniform("gap_size", 0.0f);
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
render_grabbers_connection(4, 5, m_grabbers[4].color);
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
// draw grabbers
|
||||
shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
shader->set_uniform("emission_factor", 0.1f);
|
||||
m_grabbers[4].render(true, grabber_mean_size);
|
||||
m_grabbers[5].render(true, grabber_mean_size);
|
||||
shader->stop_using();
|
||||
}
|
||||
}
|
||||
else if (m_hover_id >= 6) {
|
||||
// draw connections
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
GLShaderProgram* shader = OpenGLManager::get_gl_info().is_core_profile() ? wxGetApp().get_shader("dashed_thick_lines") : wxGetApp().get_shader("flat");
|
||||
#else
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
shader->set_uniform("viewport_size", Vec2d(double(viewport[2]), double(viewport[3])));
|
||||
shader->set_uniform("width", 0.25f);
|
||||
shader->set_uniform("gap_size", 0.0f);
|
||||
#endif // ENABLE_GL_CORE_PROFILE
|
||||
render_grabbers_connection(6, 7, m_drag_color);
|
||||
render_grabbers_connection(7, 8, m_drag_color);
|
||||
render_grabbers_connection(8, 9, m_drag_color);
|
||||
render_grabbers_connection(9, 6, m_drag_color);
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
// draw grabbers
|
||||
shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
shader->set_uniform("emission_factor", 0.1f);
|
||||
for (int i = 6; i < 10; ++i) {
|
||||
m_grabbers[i].render(true, grabber_mean_size);
|
||||
}
|
||||
shader->stop_using();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void GLGizmoScale3D::on_register_raycasters_for_picking()
|
||||
{
|
||||
@ -736,127 +382,27 @@ void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int
|
||||
m_grabber_connections[id].model.render();
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
||||
{
|
||||
double ratio = calc_ratio(data);
|
||||
if (ratio > 0.0) {
|
||||
Vec3d curr_scale = m_scale;
|
||||
const Vec3d starting_scale = m_starting.scale;
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||
|
||||
curr_scale(axis) = starting_scale(axis) * ratio;
|
||||
curr_scale(axis) = m_starting.scale(axis) * ratio;
|
||||
m_scale = curr_scale;
|
||||
|
||||
if (m_starting.ctrl_down && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier())) {
|
||||
double local_offset = 0.5 * (ratio - 1.0) * m_starting.box.size()(axis);
|
||||
|
||||
if (m_hover_id == 2 * axis)
|
||||
local_offset *= -1.0;
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case X: { m_offset = local_offset * Vec3d::UnitX(); break; }
|
||||
case Y: { m_offset = local_offset * Vec3d::UnitY(); break; }
|
||||
case Z: { m_offset = local_offset * Vec3d::UnitZ(); break; }
|
||||
default: { m_offset = Vec3d::Zero(); break; }
|
||||
}
|
||||
|
||||
if (selection.is_single_volume_or_modifier()) {
|
||||
if (coordinates_type == ECoordinatesType::Instance)
|
||||
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() * m_offset;
|
||||
else if (coordinates_type == ECoordinatesType::Local) {
|
||||
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() *
|
||||
selection.get_first_volume()->get_volume_transformation().get_rotation_matrix() * m_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
m_offset = Vec3d::Zero();
|
||||
}
|
||||
}
|
||||
#else
|
||||
void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
||||
{
|
||||
const double ratio = calc_ratio(data);
|
||||
if (ratio > 0.0) {
|
||||
m_scale(axis) = m_starting.scale(axis) * ratio;
|
||||
|
||||
if (m_starting.ctrl_down) {
|
||||
double local_offset = 0.5 * (m_scale(axis) - m_starting.scale(axis)) * m_starting.box.size()(axis);
|
||||
|
||||
if (m_hover_id == 2 * axis)
|
||||
local_offset *= -1.0;
|
||||
|
||||
Vec3d local_offset_vec;
|
||||
switch (axis)
|
||||
{
|
||||
case X: { local_offset_vec = local_offset * Vec3d::UnitX(); break; }
|
||||
case Y: { local_offset_vec = local_offset * Vec3d::UnitY(); break; }
|
||||
case Z: { local_offset_vec = local_offset * Vec3d::UnitZ(); break; }
|
||||
default: break;
|
||||
}
|
||||
|
||||
m_offset = m_offsets_transform * local_offset_vec;
|
||||
}
|
||||
else
|
||||
m_offset = Vec3d::Zero();
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void GLGizmoScale3D::do_scale_uniform(const UpdateData & data)
|
||||
{
|
||||
const double ratio = calc_ratio(data);
|
||||
if (ratio > 0.0) {
|
||||
if (ratio > 0.0)
|
||||
m_scale = m_starting.scale * ratio;
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||
if (m_starting.ctrl_down && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier())) {
|
||||
m_offset = 0.5 * (ratio - 1.0) * m_starting.box.size();
|
||||
|
||||
if (m_hover_id == 6 || m_hover_id == 9)
|
||||
m_offset.x() *= -1.0;
|
||||
if (m_hover_id == 6 || m_hover_id == 7)
|
||||
m_offset.y() *= -1.0;
|
||||
|
||||
if (selection.is_single_volume_or_modifier()) {
|
||||
if (coordinates_type == ECoordinatesType::Instance)
|
||||
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() * m_offset;
|
||||
else if (coordinates_type == ECoordinatesType::Local) {
|
||||
m_offset = selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix().inverse() *
|
||||
selection.get_first_volume()->get_volume_transformation().get_rotation_matrix() * m_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
m_offset = Vec3d::Zero();
|
||||
}
|
||||
}
|
||||
#else
|
||||
void GLGizmoScale3D::do_scale_uniform(const UpdateData& data)
|
||||
{
|
||||
const double ratio = calc_ratio(data);
|
||||
if (ratio > 0.0) {
|
||||
m_scale = m_starting.scale * ratio;
|
||||
m_offset = Vec3d::Zero();
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
|
||||
{
|
||||
double ratio = 0.0;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Vec3d starting_vec = m_starting.drag_position - m_starting.center;
|
||||
#else
|
||||
const Vec3d pivot = (m_starting.ctrl_down && m_hover_id < 6) ? m_starting.pivots[m_hover_id] : m_starting.box.center();
|
||||
const Vec3d starting_vec = m_starting.drag_position - pivot;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
const double len_starting_vec = starting_vec.norm();
|
||||
|
||||
@ -882,5 +428,50 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
|
||||
return ratio;
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::update_render_data()
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const auto& [box, box_trafo] = selection.get_bounding_box_in_current_reference_system();
|
||||
m_bounding_box = box;
|
||||
m_center = box_trafo.translation();
|
||||
m_grabbers_transform = box_trafo;
|
||||
m_instance_center = (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) ? selection.get_first_volume()->get_instance_offset() : m_center;
|
||||
|
||||
const Vec3d box_half_size = 0.5 * m_bounding_box.size();
|
||||
bool use_constrain = wxGetKeyState(WXK_CONTROL);
|
||||
|
||||
// x axis
|
||||
m_grabbers[0].center = { -(box_half_size.x() + Offset), 0.0, 0.0 };
|
||||
m_grabbers[0].color = (use_constrain && m_hover_id == 1) ? CONSTRAINED_COLOR : AXES_COLOR[0];
|
||||
m_grabbers[1].center = { box_half_size.x() + Offset, 0.0, 0.0 };
|
||||
m_grabbers[1].color = (use_constrain && m_hover_id == 0) ? CONSTRAINED_COLOR : AXES_COLOR[0];
|
||||
|
||||
// y axis
|
||||
m_grabbers[2].center = { 0.0, -(box_half_size.y() + Offset), 0.0 };
|
||||
m_grabbers[2].color = (use_constrain && m_hover_id == 3) ? CONSTRAINED_COLOR : AXES_COLOR[1];
|
||||
m_grabbers[3].center = { 0.0, box_half_size.y() + Offset, 0.0 };
|
||||
m_grabbers[3].color = (use_constrain && m_hover_id == 2) ? CONSTRAINED_COLOR : AXES_COLOR[1];
|
||||
|
||||
// z axis
|
||||
m_grabbers[4].center = { 0.0, 0.0, -(box_half_size.z() + Offset) };
|
||||
m_grabbers[4].color = (use_constrain && m_hover_id == 5) ? CONSTRAINED_COLOR : AXES_COLOR[2];
|
||||
m_grabbers[5].center = { 0.0, 0.0, box_half_size.z() + Offset };
|
||||
m_grabbers[5].color = (use_constrain && m_hover_id == 4) ? CONSTRAINED_COLOR : AXES_COLOR[2];
|
||||
|
||||
// uniform
|
||||
m_grabbers[6].center = { -(box_half_size.x() + Offset), -(box_half_size.y() + Offset), 0.0 };
|
||||
m_grabbers[6].color = (use_constrain && m_hover_id == 8) ? CONSTRAINED_COLOR : m_highlight_color;
|
||||
m_grabbers[7].center = { box_half_size.x() + Offset, -(box_half_size.y() + Offset), 0.0 };
|
||||
m_grabbers[7].color = (use_constrain && m_hover_id == 9) ? CONSTRAINED_COLOR : m_highlight_color;
|
||||
m_grabbers[8].center = { box_half_size.x() + Offset, box_half_size.y() + Offset, 0.0 };
|
||||
m_grabbers[8].color = (use_constrain && m_hover_id == 6) ? CONSTRAINED_COLOR : m_highlight_color;
|
||||
m_grabbers[9].center = { -(box_half_size.x() + Offset), box_half_size.y() + Offset, 0.0 };
|
||||
m_grabbers[9].color = (use_constrain && m_hover_id == 7) ? CONSTRAINED_COLOR : m_highlight_color;
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
m_grabbers[i].matrix = m_grabbers_transform;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
@ -3,16 +3,10 @@
|
||||
|
||||
#include "GLGizmoBase.hpp"
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
class Selection;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
class GLGizmoScale3D : public GLGizmoBase
|
||||
{
|
||||
@ -23,28 +17,17 @@ class GLGizmoScale3D : public GLGizmoBase
|
||||
bool ctrl_down{ false };
|
||||
Vec3d scale{ Vec3d::Ones() };
|
||||
Vec3d drag_position{ Vec3d::Zero() };
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d center{ Vec3d::Zero() };
|
||||
Vec3d instance_center{ Vec3d::Zero() };
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
Vec3d constraint_position{ Vec3d::Zero() };
|
||||
BoundingBoxf3 box;
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
std::array<Vec3d, 6> pivots{ Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() };
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
};
|
||||
|
||||
BoundingBoxf3 m_bounding_box;
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Transform3d m_grabbers_transform;
|
||||
Vec3d m_center{ Vec3d::Zero() };
|
||||
Vec3d m_instance_center{ Vec3d::Zero() };
|
||||
#else
|
||||
Transform3d m_transform;
|
||||
// Transforms grabbers offsets to the proper reference system (world for instances, instance for volumes)
|
||||
Transform3d m_offsets_transform;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
Vec3d m_scale{ Vec3d::Ones() };
|
||||
Vec3d m_offset{ Vec3d::Zero() };
|
||||
double m_snap_step{ 0.05 };
|
||||
StartingData m_starting;
|
||||
|
||||
@ -67,11 +50,7 @@ public:
|
||||
void set_snap_step(double step) { m_snap_step = step; }
|
||||
|
||||
const Vec3d& get_scale() const { return m_scale; }
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; m_offset = Vec3d::Zero(); }
|
||||
#else
|
||||
void set_scale(const Vec3d& scale) { m_starting.scale = scale; m_scale = scale; }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
std::string get_tooltip() const override;
|
||||
|
||||
@ -102,6 +81,7 @@ private:
|
||||
void do_scale_uniform(const UpdateData& data);
|
||||
|
||||
double calc_ratio(const UpdateData& data) const;
|
||||
void update_render_data();
|
||||
};
|
||||
|
||||
|
||||
|
@ -104,7 +104,7 @@ GLGizmoSimplify::GLGizmoSimplify(GLCanvas3D &parent)
|
||||
// translation for GUI size
|
||||
, tr_mesh_name(_u8L("Mesh name"))
|
||||
, tr_triangles(_u8L("Triangles"))
|
||||
, tr_detail_level(_u8L("Detail level"))
|
||||
, tr_detail_level(_u8L("Level of detail"))
|
||||
, tr_decimate_ratio(_u8L("Decimate ratio"))
|
||||
{}
|
||||
|
||||
@ -144,7 +144,7 @@ void GLGizmoSimplify::add_simplify_suggestion_notification(
|
||||
|
||||
for (size_t object_id : big_ids) {
|
||||
std::string t = GUI::format(_L(
|
||||
"Processing model '%1%' with more than 1M triangles "
|
||||
"Processing model \"%1%\" with more than 1M triangles "
|
||||
"could be slow. It is highly recommended to reduce "
|
||||
"amount of triangles."), objects[object_id]->name);
|
||||
std::string hypertext = _u8L("Simplify model");
|
||||
@ -318,11 +318,8 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi
|
||||
m_configuration.use_count = !m_configuration.use_count;
|
||||
start_process = true;
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && is_multipart)
|
||||
// TRN %1% = "Detail level", %2% = "Decimate ratio"
|
||||
ImGui::SetTooltip("%s", GUI::format(_L(
|
||||
"Multipart object can be simplified only by %1%. "
|
||||
"If you want specify %2% process it separately."),
|
||||
tr_detail_level, tr_decimate_ratio).c_str());
|
||||
ImGui::SetTooltip("%s", _u8L("A multipart object can be simplified using only a Level of detail. "
|
||||
"If you want to enter a Decimate ratio, do the simplification separately.").c_str());
|
||||
ImGui::SameLine();
|
||||
|
||||
// show preview result triangle count (percent)
|
||||
|
@ -169,11 +169,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection)
|
||||
trafo.translation()(2) += shift_z;
|
||||
const Geometry::Transformation transformation{trafo};
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d instance_scaling_matrix_inverse = transformation.get_scaling_factor_matrix().inverse();
|
||||
#else
|
||||
const Transform3d& instance_scaling_matrix_inverse = transformation.get_matrix(true, true, false, true).inverse();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
const Transform3d& view_matrix = camera.get_view_matrix();
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
|
@ -1678,52 +1678,36 @@ void ImGuiWrapper::init_font(bool compress)
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||
|
||||
// Fill rectangles from the SVG-icons
|
||||
for (auto icon : font_icons) {
|
||||
auto load_icon_from_svg = [this, &io, pixels, width, &rect_id](const std::pair<const wchar_t, std::string> icon, int icon_sz) {
|
||||
if (const ImFontAtlas::CustomRect* rect = io.Fonts->GetCustomRectByIndex(rect_id)) {
|
||||
assert(rect->Width == icon_sz);
|
||||
assert(rect->Height == icon_sz);
|
||||
std::vector<unsigned char> raw_data = load_svg(icon.second, icon_sz, icon_sz);
|
||||
const ImU32* pIn = (ImU32*)raw_data.data();
|
||||
for (int y = 0; y < icon_sz; y++) {
|
||||
ImU32* pOut = (ImU32*)pixels + (rect->Y + y) * width + (rect->X);
|
||||
for (int x = 0; x < icon_sz; x++)
|
||||
*pOut++ = *pIn++;
|
||||
if (!raw_data.empty()) {
|
||||
const ImU32* pIn = (ImU32*)raw_data.data();
|
||||
for (int y = 0; y < icon_sz; y++) {
|
||||
ImU32* pOut = (ImU32*)pixels + (rect->Y + y) * width + (rect->X);
|
||||
for (int x = 0; x < icon_sz; x++)
|
||||
*pOut++ = *pIn++;
|
||||
}
|
||||
}
|
||||
}
|
||||
rect_id++;
|
||||
};
|
||||
|
||||
// Fill rectangles from the SVG-icons
|
||||
for (auto icon : font_icons) {
|
||||
load_icon_from_svg(icon, icon_sz);
|
||||
}
|
||||
|
||||
icon_sz *= 2; // default size of large icon is 32 px
|
||||
for (auto icon : font_icons_large) {
|
||||
if (const ImFontAtlas::CustomRect* rect = io.Fonts->GetCustomRectByIndex(rect_id)) {
|
||||
assert(rect->Width == icon_sz);
|
||||
assert(rect->Height == icon_sz);
|
||||
std::vector<unsigned char> raw_data = load_svg(icon.second, icon_sz, icon_sz);
|
||||
const ImU32* pIn = (ImU32*)raw_data.data();
|
||||
for (int y = 0; y < icon_sz; y++) {
|
||||
ImU32* pOut = (ImU32*)pixels + (rect->Y + y) * width + (rect->X);
|
||||
for (int x = 0; x < icon_sz; x++)
|
||||
*pOut++ = *pIn++;
|
||||
}
|
||||
}
|
||||
rect_id++;
|
||||
load_icon_from_svg(icon, icon_sz);
|
||||
}
|
||||
|
||||
icon_sz *= 2; // default size of extra large icon is 64 px
|
||||
for (auto icon : font_icons_extra_large) {
|
||||
if (const ImFontAtlas::CustomRect* rect = io.Fonts->GetCustomRectByIndex(rect_id)) {
|
||||
assert(rect->Width == icon_sz);
|
||||
assert(rect->Height == icon_sz);
|
||||
std::vector<unsigned char> raw_data = load_svg(icon.second, icon_sz, icon_sz);
|
||||
const ImU32* pIn = (ImU32*)raw_data.data();
|
||||
for (int y = 0; y < icon_sz; y++) {
|
||||
ImU32* pOut = (ImU32*)pixels + (rect->Y + y) * width + (rect->X);
|
||||
for (int x = 0; x < icon_sz; x++)
|
||||
*pOut++ = *pIn++;
|
||||
}
|
||||
}
|
||||
rect_id++;
|
||||
load_icon_from_svg(icon, icon_sz);
|
||||
}
|
||||
|
||||
// Upload texture to graphics system
|
||||
|
@ -212,49 +212,6 @@ static coord_t brim_offset(const PrintObject &po, const ModelInstance &inst)
|
||||
return has_outer_brim ? scaled(brim_width + brim_separation) : 0;
|
||||
}
|
||||
|
||||
template<class It>
|
||||
Polygon support_layers_chull (Points &pts, It from_lyr, It to_lyr) {
|
||||
|
||||
size_t cap = 0;
|
||||
for (auto it = from_lyr; it != to_lyr; ++it) {
|
||||
for (const ExPolygon &expoly : (*it)->support_islands)
|
||||
cap += expoly.contour.points.size();
|
||||
}
|
||||
|
||||
pts.reserve(pts.size() + cap);
|
||||
|
||||
for (auto it = from_lyr; it != to_lyr; ++it) {
|
||||
for (const ExPolygon &expoly : (*it)->support_islands)
|
||||
std::copy(expoly.contour.begin(), expoly.contour.end(),
|
||||
std::back_inserter(pts));
|
||||
}
|
||||
|
||||
Polygon ret = Geometry::convex_hull(pts);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void update_arrangepoly_fffprint(arrangement::ArrangePolygon &ret,
|
||||
const PrintObject &po,
|
||||
const ModelInstance &inst)
|
||||
{
|
||||
auto laststep = po.last_completed_step();
|
||||
|
||||
coord_t infl = brim_offset(po, inst);
|
||||
|
||||
if (laststep < posCount && laststep > posSupportMaterial) {
|
||||
Points pts = std::move(ret.poly.contour.points);
|
||||
Polygon poly = support_layers_chull(pts,
|
||||
po.support_layers().begin(),
|
||||
po.support_layers().end());
|
||||
|
||||
ret.poly.contour = std::move(poly);
|
||||
ret.poly.holes = {};
|
||||
}
|
||||
|
||||
ret.inflation = infl;
|
||||
}
|
||||
|
||||
arrangement::ArrangePolygon ArrangeJob::get_arrange_poly_(ModelInstance *mi)
|
||||
{
|
||||
arrangement::ArrangePolygon ap = get_arrange_poly(mi, m_plater);
|
||||
@ -442,7 +399,7 @@ arrangement::ArrangePolygon get_arrange_poly(ModelInstance *inst,
|
||||
plater->fff_print().get_print_object_by_model_object_id(obj_id);
|
||||
|
||||
if (po) {
|
||||
update_arrangepoly_fffprint(ap, *po, *inst);
|
||||
ap.inflation = brim_offset(*po, *inst);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,7 +244,7 @@ void UpdateJob::process(Ctl &ctl)
|
||||
m_result = priv::try_create_mesh(m_input, was_canceled);
|
||||
if (was_canceled()) return;
|
||||
if (m_result.its.empty())
|
||||
throw priv::JobException(_u8L("Created text volume is empty. Change text or font.").c_str());
|
||||
throw priv::JobException("Created text volume is empty. Change text or font.");
|
||||
|
||||
// center triangle mesh
|
||||
Vec3d shift = m_result.bounding_box().center();
|
||||
|
@ -1768,7 +1768,7 @@ void MainFrame::quick_slice(const int qs)
|
||||
wxGetApp().app_config->update_last_output_dir(get_dir_name(output_file));
|
||||
}
|
||||
else if (qs & qsExportPNG) {
|
||||
wxFileDialog dlg(this, _L("Save zip file as:"),
|
||||
wxFileDialog dlg(this, _L("Save ZIP file as:"),
|
||||
wxGetApp().app_config->get_last_output_dir(get_dir_name(output_file)),
|
||||
get_base_name(output_file), "*.sl1", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
||||
if (dlg.ShowModal() != wxID_OK)
|
||||
|
@ -436,11 +436,7 @@ std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo
|
||||
{
|
||||
std::vector<unsigned> out;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d instance_matrix_no_translation_no_scaling = trafo.get_rotation_matrix();
|
||||
#else
|
||||
const Transform3d& instance_matrix_no_translation_no_scaling = trafo.get_matrix(true,false,true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
Vec3d direction_to_camera = -camera.get_dir_forward();
|
||||
Vec3d direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse() * direction_to_camera).normalized().eval();
|
||||
direction_to_camera_mesh = direction_to_camera_mesh.cwiseProduct(trafo.get_scaling_factor());
|
||||
|
@ -701,11 +701,7 @@ void PhysicalPrinterDialog::on_sys_color_changed()
|
||||
void PhysicalPrinterDialog::OnOK(wxEvent& event)
|
||||
{
|
||||
wxString printer_name = m_printer_name->GetValue();
|
||||
if (printer_name.IsEmpty()) {
|
||||
warning_catcher(this, _L("The supplied name is empty. It can't be saved."));
|
||||
return;
|
||||
}
|
||||
if (printer_name == m_default_name) {
|
||||
if (printer_name.IsEmpty() || printer_name == m_default_name) {
|
||||
warning_catcher(this, _L("You have to enter a printer name."));
|
||||
return;
|
||||
}
|
||||
|
@ -64,9 +64,7 @@
|
||||
#include "GUI_ObjectManipulation.hpp"
|
||||
#include "GUI_ObjectLayers.hpp"
|
||||
#include "GUI_Utils.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "GUI_Geometry.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#include "GUI_Factories.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
@ -812,7 +810,7 @@ Sidebar::Sidebar(Plater *parent)
|
||||
const int margin_5 = int(0.5 * wxGetApp().em_unit());// 5;
|
||||
|
||||
auto init_combo = [this, margin_5](PlaterPresetComboBox **combo, wxString label, Preset::Type preset_type, bool filament) {
|
||||
auto *text = new wxStaticText(p->presets_panel, wxID_ANY, label + " :");
|
||||
auto *text = new wxStaticText(p->presets_panel, wxID_ANY, label + ":");
|
||||
text->SetFont(wxGetApp().small_font());
|
||||
*combo = new PlaterPresetComboBox(p->presets_panel, preset_type);
|
||||
|
||||
@ -1548,10 +1546,8 @@ void Sidebar::update_mode()
|
||||
|
||||
wxWindowUpdateLocker noUpdates(this);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (m_mode == comSimple)
|
||||
p->object_manipulation->set_coordinates_type(ECoordinatesType::World);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
p->object_list->get_sizer()->Show(m_mode > comSimple);
|
||||
|
||||
@ -2117,9 +2113,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_MOVED, &priv::on_wipetower_moved, this);
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_ROTATED, &priv::on_wipetower_rotated, this);
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_ROTATED, [this](SimpleEvent&) { update(); });
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_RESET_SKEW, [this](SimpleEvent&) { update(); });
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_SCALED, [this](SimpleEvent&) { update(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, [this](Event<bool>& evt) { this->sidebar->enable_buttons(evt.data); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_GEOMETRY, &priv::on_update_geometry, this);
|
||||
@ -3544,11 +3538,7 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const
|
||||
new_volume->set_type(old_volume->type());
|
||||
new_volume->set_material_id(old_volume->material_id());
|
||||
new_volume->set_transformation(old_volume->get_transformation());
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
new_volume->translate(new_volume->get_transformation().get_matrix_no_offset() * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
|
||||
#else
|
||||
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
assert(!old_volume->source.is_converted_from_inches || !old_volume->source.is_converted_from_meters);
|
||||
if (old_volume->source.is_converted_from_inches)
|
||||
new_volume->convert_from_imperial_units();
|
||||
@ -3829,19 +3819,12 @@ void Plater::priv::reload_from_disk()
|
||||
new_volume->config.apply(old_volume->config);
|
||||
new_volume->set_type(old_volume->type());
|
||||
new_volume->set_material_id(old_volume->material_id());
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
new_volume->set_transformation(
|
||||
old_volume->get_transformation().get_matrix() *
|
||||
old_volume->source.transform.get_matrix_no_offset() *
|
||||
Geometry::translation_transform(new_volume->source.mesh_offset - old_volume->source.mesh_offset) *
|
||||
new_volume->source.transform.get_matrix_no_offset().inverse()
|
||||
);
|
||||
#else
|
||||
new_volume->set_transformation(Geometry::assemble_transform(old_volume->source.transform.get_offset()) *
|
||||
old_volume->get_transformation().get_matrix(true) *
|
||||
old_volume->source.transform.get_matrix(true));
|
||||
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
new_volume->source.object_idx = old_volume->source.object_idx;
|
||||
new_volume->source.volume_idx = old_volume->source.volume_idx;
|
||||
assert(!old_volume->source.is_converted_from_inches || !old_volume->source.is_converted_from_meters);
|
||||
@ -4370,11 +4353,7 @@ void Plater::priv::on_right_click(RBtnEvent& evt)
|
||||
const bool is_some_full_instances = selection.is_single_full_instance() ||
|
||||
selection.is_single_full_object() ||
|
||||
selection.is_multiple_full_instance();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const bool is_part = selection.is_single_volume_or_modifier() && ! selection.is_any_connector();
|
||||
#else
|
||||
const bool is_part = selection.is_single_volume() || selection.is_single_modifier();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
if (is_some_full_instances)
|
||||
menu = printer_technology == ptSLA ? menus.sla_object_menu() : menus.object_menu();
|
||||
else if (is_part)
|
||||
@ -4672,11 +4651,7 @@ bool Plater::priv::layers_height_allowed() const
|
||||
|
||||
bool Plater::priv::can_mirror() const
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
return !sidebar->obj_list()->has_selected_cut_object();
|
||||
#else
|
||||
return !sidebar->obj_list()->has_selected_cut_object() && get_selection().is_from_single_instance();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
|
||||
@ -5478,7 +5453,7 @@ LoadProjectsDialog::LoadProjectsDialog(const std::vector<fs::path>& paths)
|
||||
int id = 0;
|
||||
|
||||
// all geometry
|
||||
wxRadioButton* btn = new wxRadioButton(this, wxID_ANY, _L("Import geometry"), wxDefaultPosition, wxDefaultSize, id == 0 ? wxRB_GROUP : 0);
|
||||
wxRadioButton* btn = new wxRadioButton(this, wxID_ANY, _L("Import 3D models"), wxDefaultPosition, wxDefaultSize, id == 0 ? wxRB_GROUP : 0);
|
||||
btn->SetValue(id == m_action);
|
||||
btn->Bind(wxEVT_RADIOBUTTON, [this, id, contains_projects](wxCommandEvent&) {
|
||||
m_action = id;
|
||||
@ -5491,7 +5466,7 @@ LoadProjectsDialog::LoadProjectsDialog(const std::vector<fs::path>& paths)
|
||||
id++;
|
||||
// all new window
|
||||
if (instances_allowed) {
|
||||
btn = new wxRadioButton(this, wxID_ANY, _L("Start new PrusaSlicer instance"), wxDefaultPosition, wxDefaultSize, id == 0 ? wxRB_GROUP : 0);
|
||||
btn = new wxRadioButton(this, wxID_ANY, _L("Start a new instance of PrusaSlicer"), wxDefaultPosition, wxDefaultSize, id == 0 ? wxRB_GROUP : 0);
|
||||
btn->SetValue(id == m_action);
|
||||
btn->Bind(wxEVT_RADIOBUTTON, [this, id, contains_projects](wxCommandEvent&) {
|
||||
m_action = id;
|
||||
@ -5516,7 +5491,7 @@ LoadProjectsDialog::LoadProjectsDialog(const std::vector<fs::path>& paths)
|
||||
stb_sizer->Add(m_combo_project, 0, wxEXPAND | wxTOP, 5);
|
||||
// one config
|
||||
id++;
|
||||
btn = new wxRadioButton(this, wxID_ANY, _L("Select one to load config only"), wxDefaultPosition, wxDefaultSize, id == 0 ? wxRB_GROUP : 0);
|
||||
btn = new wxRadioButton(this, wxID_ANY, _L("Select only one file to load the configuration."), wxDefaultPosition, wxDefaultSize, id == 0 ? wxRB_GROUP : 0);
|
||||
btn->SetValue(id == m_action);
|
||||
btn->Bind(wxEVT_RADIOBUTTON, [this, id, instances_allowed](wxCommandEvent&) {
|
||||
m_action = id;
|
||||
@ -5562,7 +5537,8 @@ bool Plater::preview_zip_archive(const boost::filesystem::path& archive_path)
|
||||
mz_zip_zero_struct(&archive);
|
||||
|
||||
if (!open_zip_reader(&archive, archive_path.string())) {
|
||||
std::string err_msg = GUI::format(_u8L("Loading of a zip archive on path %1% has failed."), archive_path.string());
|
||||
// TRN %1% is archive path
|
||||
std::string err_msg = GUI::format(_u8L("Loading of a ZIP archive on path %1% has failed."), archive_path.string());
|
||||
throw Slic3r::FileIOError(err_msg);
|
||||
}
|
||||
mz_uint num_entries = mz_zip_reader_get_num_files(&archive);
|
||||
@ -5841,7 +5817,7 @@ ProjectDropDialog::ProjectDropDialog(const std::string& filename)
|
||||
wxArrayString choices;
|
||||
choices.reserve(4);
|
||||
choices.Add(_L("Open as project"));
|
||||
choices.Add(_L("Import geometry only"));
|
||||
choices.Add(_L("Import 3D models only"));
|
||||
choices.Add(_L("Import config only"));
|
||||
if (!single_instance_only)
|
||||
choices.Add(_L("Start new PrusaSlicer instance"));
|
||||
|
@ -776,7 +776,7 @@ void PlaterPresetComboBox::show_edit_menu()
|
||||
const PhysicalPrinter& pp = m_preset_bundle->physical_printers.get_selected_printer();
|
||||
std::string host = pp.config.opt_string("print_host");
|
||||
if (!host.empty()) {
|
||||
append_menu_item(menu, wxID_ANY, _L("Open physical printer URL"), "",
|
||||
append_menu_item(menu, wxID_ANY, _L("Open the physical printer URL"), "",
|
||||
[this](wxCommandEvent&) { this->open_physical_printer_url(); }, "open_browser", menu, []() { return true; }, wxGetApp().plater());
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,11 @@
|
||||
#include <Dbt.h>
|
||||
#include <Setupapi.h>
|
||||
#include <cfgmgr32.h>
|
||||
|
||||
#include <initguid.h> // include before devpropdef.h
|
||||
#include <devpropdef.h>
|
||||
#include <devpkey.h>
|
||||
#include <usbioctl.h>
|
||||
#else
|
||||
// unix, linux & OSX includes
|
||||
#include <errno.h>
|
||||
@ -73,6 +78,287 @@ std::vector<DriveData> RemovableDriveManager::search_for_removable_drives() cons
|
||||
}
|
||||
|
||||
namespace {
|
||||
int eject_alt(const std::wstring& volume_access_path)
|
||||
{
|
||||
HANDLE handle = CreateFileW(volume_access_path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Alt Ejecting " << volume_access_path << " failed (handle == INVALID_HANDLE_VALUE): " << GetLastError();
|
||||
return 1;
|
||||
}
|
||||
DWORD deviceControlRetVal(0);
|
||||
//these 3 commands should eject device safely but they dont, the device does disappear from file explorer but the "device was safely remove" notification doesnt trigger.
|
||||
//sd cards does trigger WM_DEVICECHANGE messege, usb drives dont
|
||||
BOOL e1 = DeviceIoControl(handle, FSCTL_LOCK_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr);
|
||||
BOOST_LOG_TRIVIAL(debug) << "FSCTL_LOCK_VOLUME " << e1 << " ; " << deviceControlRetVal << " ; " << GetLastError();
|
||||
BOOL e2 = DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr);
|
||||
BOOST_LOG_TRIVIAL(debug) << "FSCTL_DISMOUNT_VOLUME " << e2 << " ; " << deviceControlRetVal << " ; " << GetLastError();
|
||||
|
||||
// some implemenatations also calls IOCTL_STORAGE_MEDIA_REMOVAL here with FALSE as third parameter, which should set PreventMediaRemoval
|
||||
BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr);
|
||||
if (error == 0) {
|
||||
CloseHandle(handle);
|
||||
BOOST_LOG_TRIVIAL(error) << "Alt Ejecting " << volume_access_path << " failed (IOCTL_STORAGE_EJECT_MEDIA)" << deviceControlRetVal << " " << GetLastError();
|
||||
return 1;
|
||||
}
|
||||
CloseHandle(handle);
|
||||
BOOST_LOG_TRIVIAL(info) << "Alt Ejecting finished";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// From https://github.com/microsoft/Windows-driver-samples/tree/main/usb/usbview
|
||||
typedef struct _STRING_DESCRIPTOR_NODE
|
||||
{
|
||||
struct _STRING_DESCRIPTOR_NODE* Next;
|
||||
UCHAR DescriptorIndex;
|
||||
USHORT LanguageID;
|
||||
USB_STRING_DESCRIPTOR StringDescriptor[1];
|
||||
} STRING_DESCRIPTOR_NODE, * PSTRING_DESCRIPTOR_NODE;
|
||||
|
||||
// Based at https://github.com/microsoft/Windows-driver-samples/tree/main/usb/usbview
|
||||
PSTRING_DESCRIPTOR_NODE GetStringDescriptor(
|
||||
HANDLE handle_hub_device,
|
||||
ULONG connection_index,
|
||||
UCHAR descriptor_index,
|
||||
USHORT language_ID
|
||||
)
|
||||
{
|
||||
BOOL success = 0;
|
||||
ULONG nbytes = 0;
|
||||
ULONG nbytes_returned = 0;
|
||||
UCHAR string_desc_req_buf[sizeof(USB_DESCRIPTOR_REQUEST) + MAXIMUM_USB_STRING_LENGTH];
|
||||
PUSB_DESCRIPTOR_REQUEST string_desc_req = NULL;
|
||||
PUSB_STRING_DESCRIPTOR string_desc = NULL;
|
||||
PSTRING_DESCRIPTOR_NODE string_desc_node = NULL;
|
||||
|
||||
nbytes = sizeof(string_desc_req_buf);
|
||||
string_desc_req = (PUSB_DESCRIPTOR_REQUEST)string_desc_req_buf;
|
||||
string_desc = (PUSB_STRING_DESCRIPTOR)(string_desc_req + 1);
|
||||
|
||||
// Zero fill the entire request structure
|
||||
memset(string_desc_req, 0, nbytes);
|
||||
|
||||
// Indicate the port from which the descriptor will be requested
|
||||
string_desc_req->ConnectionIndex = connection_index;
|
||||
|
||||
// USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this
|
||||
// IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.
|
||||
//
|
||||
// USBD will automatically initialize these fields:
|
||||
// bmRequest = 0x80
|
||||
// bRequest = 0x06
|
||||
//
|
||||
// We must inititialize these fields:
|
||||
// wValue = Descriptor Type (high) and Descriptor Index (low byte)
|
||||
// wIndex = Zero (or Language ID for String Descriptors)
|
||||
// wLength = Length of descriptor buffer
|
||||
string_desc_req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8)
|
||||
| descriptor_index;
|
||||
string_desc_req->SetupPacket.wIndex = language_ID;
|
||||
string_desc_req->SetupPacket.wLength = (USHORT)(nbytes - sizeof(USB_DESCRIPTOR_REQUEST));
|
||||
|
||||
// Now issue the get descriptor request.
|
||||
success = DeviceIoControl(handle_hub_device,
|
||||
IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
|
||||
string_desc_req,
|
||||
nbytes,
|
||||
string_desc_req,
|
||||
nbytes,
|
||||
&nbytes_returned,
|
||||
NULL);
|
||||
|
||||
// Do some sanity checks on the return from the get descriptor request.
|
||||
if (!success) {
|
||||
return NULL;
|
||||
}
|
||||
if (nbytes_returned < 2) {
|
||||
return NULL;
|
||||
}
|
||||
if (string_desc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE) {
|
||||
return NULL;
|
||||
}
|
||||
if (string_desc->bLength != nbytes_returned - sizeof(USB_DESCRIPTOR_REQUEST)) {
|
||||
return NULL;
|
||||
}
|
||||
if (string_desc->bLength % 2 != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Looks good, allocate some (zero filled) space for the string descriptor
|
||||
// node and copy the string descriptor to it.
|
||||
string_desc_node = (PSTRING_DESCRIPTOR_NODE)malloc(sizeof(STRING_DESCRIPTOR_NODE) + string_desc->bLength * sizeof(DWORD));
|
||||
if (string_desc_node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
string_desc_node->Next = NULL;
|
||||
string_desc_node->DescriptorIndex = descriptor_index;
|
||||
string_desc_node->LanguageID = language_ID;
|
||||
|
||||
memcpy(string_desc_node->StringDescriptor,
|
||||
string_desc,
|
||||
string_desc->bLength);
|
||||
|
||||
return string_desc_node;
|
||||
}
|
||||
|
||||
// Based at https://github.com/microsoft/Windows-driver-samples/tree/main/usb/usbview
|
||||
HRESULT GetStringDescriptors(
|
||||
_In_ HANDLE handle_hub_device,
|
||||
_In_ ULONG connection_index,
|
||||
_In_ UCHAR descriptor_index,
|
||||
_In_ ULONG num_language_IDs,
|
||||
_In_reads_(num_language_IDs) USHORT* language_IDs,
|
||||
_In_ PSTRING_DESCRIPTOR_NODE string_desc_node_head,
|
||||
std::wstring& result
|
||||
)
|
||||
{
|
||||
PSTRING_DESCRIPTOR_NODE tail = NULL;
|
||||
PSTRING_DESCRIPTOR_NODE trailing = NULL;
|
||||
ULONG i = 0;
|
||||
|
||||
// Go to the end of the linked list, searching for the requested index to
|
||||
// see if we've already retrieved it
|
||||
for (tail = string_desc_node_head; tail != NULL; tail = tail->Next) {
|
||||
if (tail->DescriptorIndex == descriptor_index) {
|
||||
// copy string descriptor to result
|
||||
for(int i = 0; i < tail->StringDescriptor->bLength / 2 - 1; i++) {
|
||||
result += tail->StringDescriptor->bString[i];
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
trailing = tail;
|
||||
}
|
||||
tail = trailing;
|
||||
|
||||
// Get the next String Descriptor. If this is NULL, then we're done (return)
|
||||
// Otherwise, loop through all Language IDs
|
||||
for (i = 0; (tail != NULL) && (i < num_language_IDs); i++) {
|
||||
tail->Next = GetStringDescriptor(handle_hub_device,
|
||||
connection_index,
|
||||
descriptor_index,
|
||||
language_IDs[i]);
|
||||
tail = tail->Next;
|
||||
}
|
||||
|
||||
if (tail == NULL) {
|
||||
return E_FAIL;
|
||||
} else {
|
||||
// copy string descriptor to result
|
||||
for (int i = 0; i < tail->StringDescriptor->bLength / 2 - 1; i++) {
|
||||
result += tail->StringDescriptor->bString[i];
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
bool get_handle_from_devinst(DEVINST devinst, HANDLE& handle)
|
||||
{
|
||||
// create path consisting of device id and guid
|
||||
wchar_t device_id[MAX_PATH];
|
||||
CM_Get_Device_ID(devinst, device_id, MAX_PATH, 0);
|
||||
|
||||
//convert device id string to device path - https://stackoverflow.com/a/32641140/981766
|
||||
std::wstring dev_id_wstr(device_id);
|
||||
dev_id_wstr = std::regex_replace(dev_id_wstr, std::wregex(LR"(\\)"), L"#"); // '\' is special for regex
|
||||
dev_id_wstr = std::regex_replace(dev_id_wstr, std::wregex(L"^"), LR"(\\?\)", std::regex_constants::format_first_only);
|
||||
dev_id_wstr = std::regex_replace(dev_id_wstr, std::wregex(L"$"), L"#", std::regex_constants::format_first_only);
|
||||
|
||||
// guid
|
||||
wchar_t guid_wchar[64];//guid is 32 chars+4 hyphens+2 paranthesis+null => 64 should be more than enough
|
||||
StringFromGUID2(GUID_DEVINTERFACE_USB_HUB, guid_wchar, 64);
|
||||
dev_id_wstr.append(guid_wchar);
|
||||
|
||||
// get handle
|
||||
std::wstring& usb_hub_path = dev_id_wstr;
|
||||
handle = CreateFileW(usb_hub_path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
// Sometimes device is not GUID_DEVINTERFACE_USB_HUB, than we need to check parent recursively
|
||||
DEVINST parent_devinst = 0;
|
||||
if (CM_Get_Parent(&parent_devinst, devinst, 0) != CR_SUCCESS)
|
||||
return false;
|
||||
return get_handle_from_devinst(parent_devinst, handle);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read Configuration Descriptor - configuration string indexed by iConfiguration and decide if card reader
|
||||
bool is_card_reader(HDEVINFO h_dev_info, SP_DEVINFO_DATA& spdd)
|
||||
{
|
||||
// First get port number of device.
|
||||
|
||||
DEVINST parent_devinst = 0;
|
||||
HANDLE handle; // usb hub handle
|
||||
DWORD usb_port_number = 0;
|
||||
DWORD required_size = 0;
|
||||
// First we need handle for GUID_DEVINTERFACE_USB_HUB device.
|
||||
if (CM_Get_Parent(&parent_devinst, spdd.DevInst, 0) != CR_SUCCESS) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "is_card_reader failed: Couldn't get parent DEVINST.";
|
||||
return false;
|
||||
}
|
||||
if(!get_handle_from_devinst(parent_devinst, handle) || handle == INVALID_HANDLE_VALUE) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "is_card_reader failed: Couldn't get HANDLE for parent DEVINST.";
|
||||
return false;
|
||||
}
|
||||
// Get port number to which the usb device is attached on the hub.
|
||||
if (SetupDiGetDeviceRegistryProperty(h_dev_info, &spdd, SPDRP_ADDRESS, nullptr, (PBYTE)&usb_port_number, sizeof(usb_port_number), &required_size) == 0) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "is_card_reader failed: Couldn't get port number.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fill USB request packet to get iConfiguration value.
|
||||
|
||||
int buffer_size = sizeof(USB_DESCRIPTOR_REQUEST) + sizeof(USB_CONFIGURATION_DESCRIPTOR);
|
||||
BYTE* buffer = new BYTE[buffer_size];
|
||||
USB_DESCRIPTOR_REQUEST* request_packet = (USB_DESCRIPTOR_REQUEST*)buffer;
|
||||
USB_CONFIGURATION_DESCRIPTOR* configuration_descriptor = (USB_CONFIGURATION_DESCRIPTOR*)((BYTE*)buffer + sizeof(USB_DESCRIPTOR_REQUEST));
|
||||
DWORD bytes_returned = 0;
|
||||
// Fill information in packet.
|
||||
request_packet->SetupPacket.bmRequest = 0x80;
|
||||
request_packet->SetupPacket.bRequest = USB_REQUEST_GET_CONFIGURATION;
|
||||
request_packet->ConnectionIndex = usb_port_number;
|
||||
request_packet->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8 | 0 /*Since only 1 device descriptor => index : 0*/);
|
||||
request_packet->SetupPacket.wLength = sizeof(USB_CONFIGURATION_DESCRIPTOR);
|
||||
// Issue ioctl.
|
||||
if (DeviceIoControl(handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, buffer, buffer_size, buffer, buffer_size, &bytes_returned, nullptr) == 0) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "is_card_reader failed: Couldn't get Configuration Descriptor.";
|
||||
return false;
|
||||
}
|
||||
// Nothing to read.
|
||||
if (configuration_descriptor->iConfiguration == 0) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "is_card_reader failed: iConfiguration value is 0.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get string descriptor and read string on address given by iConfiguration index .
|
||||
// Based at https://github.com/microsoft/Windows-driver-samples/tree/main/usb/usbview
|
||||
|
||||
PSTRING_DESCRIPTOR_NODE supported_languages_string = NULL;
|
||||
ULONG num_language_IDs = 0;
|
||||
USHORT* language_IDs = NULL;
|
||||
std::wstring configuration_string;
|
||||
// Get languages.
|
||||
supported_languages_string = GetStringDescriptor(handle, usb_port_number, 0, 0);
|
||||
if (supported_languages_string == NULL) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "is_card_reader failed: Couldn't get language string descriptor.";
|
||||
return false;
|
||||
}
|
||||
num_language_IDs = (supported_languages_string->StringDescriptor->bLength - 2) / 2;
|
||||
language_IDs = (USHORT*)&supported_languages_string->StringDescriptor->bString[0];
|
||||
// Get configration string.
|
||||
if (GetStringDescriptors(handle, usb_port_number, configuration_descriptor->iConfiguration, num_language_IDs, language_IDs, supported_languages_string, configuration_string) == E_FAIL) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "is_card_reader failed: Couldn't get configuration string descriptor.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Final compare.
|
||||
BOOST_LOG_TRIVIAL(error) << "Ejecting information: Retrieved configuration string: " << configuration_string;
|
||||
if (configuration_string.find(L"CARD READER") != std::wstring::npos) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Detected external reader.";
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// returns the device instance handle of a storage volume or 0 on error
|
||||
// called from eject_inner, based on https://stackoverflow.com/a/58848961
|
||||
DEVINST get_dev_inst_by_device_number(long device_number, UINT drive_type, WCHAR* dos_device_name)
|
||||
@ -80,7 +366,7 @@ DEVINST get_dev_inst_by_device_number(long device_number, UINT drive_type, WCHAR
|
||||
bool is_floppy = (wcsstr(dos_device_name, L"\\Floppy") != NULL); // TODO: could be tested better?
|
||||
|
||||
if (drive_type != DRIVE_REMOVABLE || is_floppy) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "get_dev_inst_by_device_number failed: Drive is not removable.";
|
||||
BOOST_LOG_TRIVIAL(warning) << "get_dev_inst_by_device_number failed: Drive is not removable.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -89,7 +375,7 @@ DEVINST get_dev_inst_by_device_number(long device_number, UINT drive_type, WCHAR
|
||||
HDEVINFO h_dev_info = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
||||
|
||||
if (h_dev_info == INVALID_HANDLE_VALUE) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "get_dev_inst_by_device_number failed: Invalid dev info handle.";
|
||||
BOOST_LOG_TRIVIAL(warning) << "get_dev_inst_by_device_number failed: Invalid dev info handle.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -135,13 +421,16 @@ DEVINST get_dev_inst_by_device_number(long device_number, UINT drive_type, WCHAR
|
||||
if (device_number != (long)sdn.DeviceNumber) {
|
||||
continue;
|
||||
}
|
||||
// this is the drive, return the device instance
|
||||
|
||||
// check if is sd card reader - if yes, indicate by returning invalid value.
|
||||
bool reader = is_card_reader(h_dev_info, spdd);
|
||||
|
||||
SetupDiDestroyDeviceInfoList(h_dev_info);
|
||||
return spdd.DevInst;
|
||||
return !reader ? spdd.DevInst : 0;
|
||||
}
|
||||
|
||||
SetupDiDestroyDeviceInfoList(h_dev_info);
|
||||
BOOST_LOG_TRIVIAL(debug) << "get_dev_inst_by_device_number failed: Enmurating couldn't find the drive.";
|
||||
BOOST_LOG_TRIVIAL(warning) << "get_dev_inst_by_device_number failed: Enmurating couldn't find the drive.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -194,10 +483,9 @@ int eject_inner(const std::string& path)
|
||||
|
||||
// get the device instance handle of the storage volume by means of a SetupDi enum and matching the device number
|
||||
DEVINST dev_inst = get_dev_inst_by_device_number(device_number, drive_type, dos_device_name);
|
||||
|
||||
if (dev_inst == 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << GUI::format("Ejecting of %1% has failed: Invalid device instance handle.", path);
|
||||
return 1;
|
||||
BOOST_LOG_TRIVIAL(error) << GUI::format("Ejecting of %1%: Invalid device instance handle. Going to try alternative ejecting method.", path);
|
||||
return eject_alt(volume_access_path);
|
||||
}
|
||||
|
||||
PNP_VETO_TYPE veto_type = PNP_VetoTypeUnknown;
|
||||
@ -249,7 +537,7 @@ int eject_inner(const std::string& path)
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
// Called from UI therefore it blocks the UI thread.
|
||||
// It also blocks updates at the worker thread.
|
||||
// Win32 implementation.
|
||||
@ -268,18 +556,21 @@ void RemovableDriveManager::eject_drive()
|
||||
if (it_drive_data != m_current_drives.end()) {
|
||||
if (!eject_inner(m_last_save_path)) {
|
||||
// success
|
||||
assert(m_callback_evt_handler);
|
||||
if (m_callback_evt_handler)
|
||||
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair< DriveData, bool >(std::move(*it_drive_data), true)));
|
||||
BOOST_LOG_TRIVIAL(info) << "Ejecting has succeeded.";
|
||||
assert(m_callback_evt_handler);
|
||||
if (m_callback_evt_handler)
|
||||
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair< DriveData, bool >(std::move(*it_drive_data), true)));
|
||||
} else {
|
||||
// failed to eject
|
||||
// this should not happen, throwing exception might be the way here
|
||||
BOOST_LOG_TRIVIAL(error) << "Ejecting has failed.";
|
||||
assert(m_callback_evt_handler);
|
||||
if (m_callback_evt_handler)
|
||||
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair<DriveData, bool>(*it_drive_data, false)));
|
||||
}
|
||||
} else {
|
||||
// drive not found in m_current_drives
|
||||
BOOST_LOG_TRIVIAL(error) << "Ejecting has failed. Drive not found in m_current_drives.";
|
||||
assert(m_callback_evt_handler);
|
||||
if (m_callback_evt_handler)
|
||||
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair<DriveData, bool>({"",""}, false)));
|
||||
|
@ -166,34 +166,32 @@ void SavePresetDialog::Item::update()
|
||||
const std::string unusable_suffix = PresetCollection::get_suffix_modified();//"(modified)";
|
||||
for (size_t i = 0; i < std::strlen(unusable_symbols); i++) {
|
||||
if (m_preset_name.find_first_of(unusable_symbols[i]) != std::string::npos) {
|
||||
info_line = _L("The supplied name is not valid;") + "\n" +
|
||||
_L("the following characters are not allowed:") + " " + unusable_symbols;
|
||||
info_line = _L("The following characters are not allowed in the name") + ": " + unusable_symbols;
|
||||
m_valid_type = ValidationType::NoValid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_valid_type == ValidationType::Valid && m_preset_name.find(unusable_suffix) != std::string::npos) {
|
||||
info_line = _L("The supplied name is not valid;") + "\n" +
|
||||
_L("the following suffix is not allowed:") + "\n\t" +
|
||||
info_line = _L("The following suffix is not allowed in the name") + ":\n\t" +
|
||||
from_u8(unusable_suffix);
|
||||
m_valid_type = ValidationType::NoValid;
|
||||
}
|
||||
|
||||
if (m_valid_type == ValidationType::Valid && m_preset_name == "- default -") {
|
||||
info_line = _L("The supplied name is not available.");
|
||||
info_line = _L("This name is reserved, use another.");
|
||||
m_valid_type = ValidationType::NoValid;
|
||||
}
|
||||
|
||||
const Preset* existing = get_existing_preset();
|
||||
if (m_valid_type == ValidationType::Valid && existing && (existing->is_default || existing->is_system)) {
|
||||
info_line = m_use_text_ctrl ? _L("The supplied name is used for a system profile.") :
|
||||
info_line = m_use_text_ctrl ? _L("This name is used for a system profile name, use another.") :
|
||||
_L("Cannot overwrite a system profile.");
|
||||
m_valid_type = ValidationType::NoValid;
|
||||
}
|
||||
|
||||
if (m_valid_type == ValidationType::Valid && existing && (existing->is_external)) {
|
||||
info_line = m_use_text_ctrl ? _L("The supplied name is used for a external profile.") :
|
||||
info_line = m_use_text_ctrl ? _L("This name is used for an external profile name, use another.") :
|
||||
_L("Cannot overwrite an external profile.");
|
||||
m_valid_type = ValidationType::NoValid;
|
||||
}
|
||||
|
@ -9,9 +9,7 @@
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#include "Camera.hpp"
|
||||
#include "Plater.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "MsgDialog.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#include "Gizmos/GLGizmoBase.hpp"
|
||||
|
||||
@ -40,18 +38,11 @@ Selection::VolumeCache::TransformCache::TransformCache(const Geometry::Transform
|
||||
, scaling_factor(transform.get_scaling_factor())
|
||||
, mirror(transform.get_mirror())
|
||||
, full_matrix(transform.get_matrix())
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
, transform(transform)
|
||||
, rotation_matrix(transform.get_rotation_matrix())
|
||||
, scale_matrix(transform.get_scaling_factor_matrix())
|
||||
, mirror_matrix(transform.get_mirror_matrix())
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
{
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
rotation_matrix = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
scale_matrix = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scaling_factor);
|
||||
mirror_matrix = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d::Ones(), mirror);
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
Selection::VolumeCache::VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform)
|
||||
@ -118,12 +109,10 @@ Selection::Selection()
|
||||
, m_scale_factor(1.0f)
|
||||
{
|
||||
this->set_bounding_boxes_dirty();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_axes.set_stem_radius(0.5f);
|
||||
m_axes.set_stem_length(20.0f);
|
||||
m_axes.set_tip_radius(1.5f);
|
||||
m_axes.set_tip_length(5.0f);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
|
||||
@ -595,11 +584,7 @@ bool Selection::is_sla_compliant() const
|
||||
|
||||
bool Selection::is_single_text() const
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (!is_single_volume_or_modifier())
|
||||
#else
|
||||
if (!is_single_volume() && !is_single_modifier())
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
return false;
|
||||
|
||||
const GLVolume* gl_volume = (*m_volumes)[*m_list.begin()];
|
||||
@ -653,16 +638,6 @@ bool Selection::matches(const std::vector<unsigned int>& volume_idxs) const
|
||||
return count == (unsigned int)m_list.size();
|
||||
}
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
bool Selection::requires_uniform_scale() const
|
||||
{
|
||||
if (is_single_full_instance() || is_single_modifier() || is_single_volume())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
int Selection::get_object_idx() const
|
||||
{
|
||||
return (m_cache.content.size() == 1) ? m_cache.content.begin()->first : -1;
|
||||
@ -721,11 +696,7 @@ const BoundingBoxf3& Selection::get_unscaled_instance_bounding_box() const
|
||||
const GLVolume& volume = *(*m_volumes)[i];
|
||||
if (volume.is_modifier)
|
||||
continue;
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Transform3d trafo = volume.get_instance_transformation().get_matrix_no_scaling_factor() * volume.get_volume_transformation().get_matrix();
|
||||
#else
|
||||
Transform3d trafo = volume.get_instance_transformation().get_matrix(false, false, true, false) * volume.get_volume_transformation().get_matrix();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
trafo.translation().z() += volume.get_sla_shift_z();
|
||||
(*bbox)->merge(volume.transformed_convex_hull_bounding_box(trafo));
|
||||
}
|
||||
@ -755,7 +726,6 @@ const BoundingBoxf3& Selection::get_scaled_instance_bounding_box() const
|
||||
return *m_scaled_instance_bounding_box;
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const BoundingBoxf3& Selection::get_full_unscaled_instance_bounding_box() const
|
||||
{
|
||||
assert(is_single_full_instance());
|
||||
@ -886,9 +856,7 @@ std::pair<BoundingBoxf3, Transform3d> Selection::get_bounding_box_in_reference_s
|
||||
const Vec3d center = 0.5 * (min + max);
|
||||
out_trafo.set_offset(basis_trafo * center);
|
||||
return { out_box, out_trafo.get_matrix_no_scaling_factor() };
|
||||
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void Selection::setup_cache()
|
||||
{
|
||||
@ -898,7 +866,6 @@ void Selection::setup_cache()
|
||||
set_caches();
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void Selection::translate(const Vec3d& displacement, TransformationType transformation_type)
|
||||
{
|
||||
if (!m_valid)
|
||||
@ -947,50 +914,8 @@ void Selection::translate(const Vec3d& displacement, TransformationType transfor
|
||||
set_bounding_boxes_dirty();
|
||||
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
|
||||
}
|
||||
#else
|
||||
void Selection::translate(const Vec3d& displacement, bool local)
|
||||
{
|
||||
if (!m_valid)
|
||||
return;
|
||||
|
||||
EMode translation_type = m_mode;
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
GLVolume& v = *(*m_volumes)[i];
|
||||
if (m_mode == Volume || v.is_wipe_tower) {
|
||||
if (local)
|
||||
v.set_volume_offset(m_cache.volumes_data[i].get_volume_position() + displacement);
|
||||
else {
|
||||
const Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_instance_mirror_matrix()).inverse() * displacement;
|
||||
v.set_volume_offset(m_cache.volumes_data[i].get_volume_position() + local_displacement);
|
||||
}
|
||||
}
|
||||
else if (m_mode == Instance) {
|
||||
if (is_from_fully_selected_instance(i))
|
||||
v.set_instance_offset(m_cache.volumes_data[i].get_instance_position() + displacement);
|
||||
else {
|
||||
const Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_instance_mirror_matrix()).inverse() * displacement;
|
||||
v.set_volume_offset(m_cache.volumes_data[i].get_volume_position() + local_displacement);
|
||||
translation_type = Volume;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !DISABLE_INSTANCES_SYNCH
|
||||
if (translation_type == Instance)
|
||||
synchronize_unselected_instances(SyncRotationType::NONE);
|
||||
else if (translation_type == Volume)
|
||||
synchronize_unselected_volumes();
|
||||
#endif // !DISABLE_INSTANCES_SYNCH
|
||||
|
||||
ensure_not_below_bed();
|
||||
set_bounding_boxes_dirty();
|
||||
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// Rotate an object around one of the axes. Only one rotation component is expected to be changing.
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void Selection::rotate(const Vec3d& rotation, TransformationType transformation_type)
|
||||
{
|
||||
if (!m_valid)
|
||||
@ -1072,119 +997,6 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
|
||||
set_bounding_boxes_dirty();
|
||||
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
|
||||
}
|
||||
#else
|
||||
void Selection::rotate(const Vec3d& rotation, TransformationType transformation_type)
|
||||
{
|
||||
if (!m_valid)
|
||||
return;
|
||||
|
||||
// Only relative rotation values are allowed in the world coordinate system.
|
||||
assert(!transformation_type.world() || transformation_type.relative());
|
||||
|
||||
if (!is_wipe_tower()) {
|
||||
int rot_axis_max = 0;
|
||||
if (rotation.isApprox(Vec3d::Zero())) {
|
||||
for (unsigned int i : m_list) {
|
||||
GLVolume &v = *(*m_volumes)[i];
|
||||
if (m_mode == Instance) {
|
||||
v.set_instance_rotation(m_cache.volumes_data[i].get_instance_rotation());
|
||||
v.set_instance_offset(m_cache.volumes_data[i].get_instance_position());
|
||||
}
|
||||
else if (m_mode == Volume) {
|
||||
v.set_volume_rotation(m_cache.volumes_data[i].get_volume_rotation());
|
||||
v.set_volume_offset(m_cache.volumes_data[i].get_volume_position());
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // this is not the wipe tower
|
||||
//FIXME this does not work for absolute rotations (transformation_type.absolute() is true)
|
||||
rotation.cwiseAbs().maxCoeff(&rot_axis_max);
|
||||
|
||||
// if ( single instance or single volume )
|
||||
// Rotate around center , if only a single object or volume
|
||||
// transformation_type.set_independent();
|
||||
|
||||
// For generic rotation, we want to rotate the first volume in selection, and then to synchronize the other volumes with it.
|
||||
std::vector<int> object_instance_first(m_model->objects.size(), -1);
|
||||
auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, transformation_type](GLVolume &volume, int i) {
|
||||
const int first_volume_idx = object_instance_first[volume.object_idx()];
|
||||
if (rot_axis_max != 2 && first_volume_idx != -1) {
|
||||
// Generic rotation, but no rotation around the Z axis.
|
||||
// Always do a local rotation (do not consider the selection to be a rigid body).
|
||||
assert(is_approx(rotation.z(), 0.0));
|
||||
const GLVolume &first_volume = *(*m_volumes)[first_volume_idx];
|
||||
const Vec3d &rotation = first_volume.get_instance_rotation();
|
||||
const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation());
|
||||
volume.set_instance_rotation(Vec3d(rotation.x(), rotation.y(), rotation.z() + z_diff));
|
||||
}
|
||||
else {
|
||||
// extracts rotations from the composed transformation
|
||||
const Vec3d new_rotation = transformation_type.world() ?
|
||||
Geometry::extract_rotation(Geometry::assemble_transform(Vec3d::Zero(), rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix()) :
|
||||
transformation_type.absolute() ? rotation : rotation + m_cache.volumes_data[i].get_instance_rotation();
|
||||
if (rot_axis_max == 2 && transformation_type.joint()) {
|
||||
// Only allow rotation of multiple instances as a single rigid body when rotating around the Z axis.
|
||||
const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), new_rotation);
|
||||
volume.set_instance_offset(m_cache.dragging_center + Eigen::AngleAxisd(z_diff, Vec3d::UnitZ()) * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
||||
}
|
||||
volume.set_instance_rotation(new_rotation);
|
||||
object_instance_first[volume.object_idx()] = i;
|
||||
}
|
||||
};
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
GLVolume &v = *(*m_volumes)[i];
|
||||
if (is_single_full_instance())
|
||||
rotate_instance(v, i);
|
||||
else if (is_single_volume() || is_single_modifier()) {
|
||||
if (transformation_type.independent())
|
||||
v.set_volume_rotation(m_cache.volumes_data[i].get_volume_rotation() + rotation);
|
||||
else {
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
const Vec3d new_rotation = Geometry::extract_rotation(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
|
||||
v.set_volume_rotation(new_rotation);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (m_mode == Instance)
|
||||
rotate_instance(v, i);
|
||||
else if (m_mode == Volume) {
|
||||
// extracts rotations from the composed transformation
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
const Vec3d new_rotation = Geometry::extract_rotation(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
|
||||
if (transformation_type.joint()) {
|
||||
const Vec3d local_pivot = m_cache.volumes_data[i].get_instance_full_matrix().inverse() * m_cache.dragging_center;
|
||||
const Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() - local_pivot);
|
||||
v.set_volume_offset(local_pivot + offset);
|
||||
}
|
||||
v.set_volume_rotation(new_rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !DISABLE_INSTANCES_SYNCH
|
||||
if (m_mode == Instance)
|
||||
synchronize_unselected_instances((rot_axis_max == 2) ? SyncRotationType::NONE : SyncRotationType::GENERAL);
|
||||
else if (m_mode == Volume)
|
||||
synchronize_unselected_volumes();
|
||||
#endif // !DISABLE_INSTANCES_SYNCH
|
||||
}
|
||||
else { // it's the wipe tower that's selected and being rotated
|
||||
GLVolume& volume = *((*m_volumes)[*m_list.begin()]); // the wipe tower is always alone in the selection
|
||||
|
||||
// make sure the wipe tower rotates around its center, not origin
|
||||
// we can assume that only Z rotation changes
|
||||
const Vec3d center_local = volume.transformed_bounding_box().center() - volume.get_volume_offset();
|
||||
const Vec3d center_local_new = Eigen::AngleAxisd(rotation.z()-volume.get_volume_rotation().z(), Vec3d::UnitZ()) * center_local;
|
||||
volume.set_volume_rotation(rotation);
|
||||
volume.set_volume_offset(volume.get_volume_offset() + center_local - center_local_new);
|
||||
}
|
||||
|
||||
set_bounding_boxes_dirty();
|
||||
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void Selection::flattening_rotate(const Vec3d& normal)
|
||||
{
|
||||
@ -1199,21 +1011,11 @@ void Selection::flattening_rotate(const Vec3d& normal)
|
||||
for (unsigned int i : m_list) {
|
||||
GLVolume& v = *(*m_volumes)[i];
|
||||
// Normal transformed from the object coordinate space to the world coordinate space.
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Geometry::Transformation& old_inst_trafo = v.get_instance_transformation();
|
||||
const Vec3d tnormal = old_inst_trafo.get_matrix().matrix().block(0, 0, 3, 3).inverse().transpose() * normal;
|
||||
// Additional rotation to align tnormal with the down vector in the world coordinate space.
|
||||
const Transform3d rotation_matrix = Transform3d(Eigen::Quaterniond().setFromTwoVectors(tnormal, -Vec3d::UnitZ()));
|
||||
v.set_instance_transformation(old_inst_trafo.get_offset_matrix() * rotation_matrix * old_inst_trafo.get_matrix_no_offset());
|
||||
#else
|
||||
const auto& voldata = m_cache.volumes_data[i];
|
||||
Vec3d tnormal = (Geometry::assemble_transform(
|
||||
Vec3d::Zero(), voldata.get_instance_rotation(),
|
||||
voldata.get_instance_scaling_factor().cwiseInverse(), voldata.get_instance_mirror()) * normal).normalized();
|
||||
// Additional rotation to align tnormal with the down vector in the world coordinate space.
|
||||
auto extra_rotation = Eigen::Quaterniond().setFromTwoVectors(tnormal, -Vec3d::UnitZ());
|
||||
v.set_instance_rotation(Geometry::extract_rotation(extra_rotation.toRotationMatrix() * m_cache.volumes_data[i].get_instance_rotation_matrix()));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if !DISABLE_INSTANCES_SYNCH
|
||||
@ -1226,79 +1028,10 @@ void Selection::flattening_rotate(const Vec3d& normal)
|
||||
this->set_bounding_boxes_dirty();
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void Selection::scale(const Vec3d& scale, TransformationType transformation_type)
|
||||
{
|
||||
scale_and_translate(scale, Vec3d::Zero(), transformation_type);
|
||||
}
|
||||
#else
|
||||
void Selection::scale(const Vec3d& scale, TransformationType transformation_type)
|
||||
{
|
||||
if (!m_valid)
|
||||
return;
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
GLVolume &v = *(*m_volumes)[i];
|
||||
if (is_single_full_instance()) {
|
||||
if (transformation_type.relative()) {
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale);
|
||||
const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> new_matrix = (m * m_cache.volumes_data[i].get_instance_scale_matrix()).matrix().block(0, 0, 3, 3);
|
||||
// extracts scaling factors from the composed transformation
|
||||
const Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
|
||||
if (transformation_type.joint())
|
||||
v.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
||||
|
||||
v.set_instance_scaling_factor(new_scale);
|
||||
}
|
||||
else {
|
||||
if (transformation_type.world() && (std::abs(scale.x() - scale.y()) > EPSILON || std::abs(scale.x() - scale.z()) > EPSILON)) {
|
||||
// Non-uniform scaling. Transform the scaling factors into the local coordinate system.
|
||||
// This is only possible, if the instance rotation is mulitples of ninety degrees.
|
||||
assert(Geometry::is_rotation_ninety_degrees(v.get_instance_rotation()));
|
||||
v.set_instance_scaling_factor((v.get_instance_transformation().get_matrix(true, false, true, true).matrix().block<3, 3>(0, 0).transpose() * scale).cwiseAbs());
|
||||
}
|
||||
else
|
||||
v.set_instance_scaling_factor(scale);
|
||||
}
|
||||
}
|
||||
else if (is_single_volume() || is_single_modifier())
|
||||
v.set_volume_scaling_factor(scale);
|
||||
else {
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale);
|
||||
if (m_mode == Instance) {
|
||||
const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> new_matrix = (m * m_cache.volumes_data[i].get_instance_scale_matrix()).matrix().block(0, 0, 3, 3);
|
||||
// extracts scaling factors from the composed transformation
|
||||
const Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
|
||||
if (transformation_type.joint())
|
||||
v.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
||||
|
||||
v.set_instance_scaling_factor(new_scale);
|
||||
}
|
||||
else if (m_mode == Volume) {
|
||||
const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> new_matrix = (m * m_cache.volumes_data[i].get_volume_scale_matrix()).matrix().block(0, 0, 3, 3);
|
||||
// extracts scaling factors from the composed transformation
|
||||
const Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
|
||||
if (transformation_type.joint()) {
|
||||
const Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() + m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center);
|
||||
v.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset);
|
||||
}
|
||||
v.set_volume_scaling_factor(new_scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !DISABLE_INSTANCES_SYNCH
|
||||
if (m_mode == Instance)
|
||||
synchronize_unselected_instances(SyncRotationType::NONE);
|
||||
else if (m_mode == Volume)
|
||||
synchronize_unselected_volumes();
|
||||
#endif // !DISABLE_INSTANCES_SYNCH
|
||||
|
||||
ensure_on_bed();
|
||||
set_bounding_boxes_dirty();
|
||||
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void Selection::scale_to_fit_print_volume(const BuildVolume& volume)
|
||||
{
|
||||
@ -1322,13 +1055,9 @@ void Selection::scale_to_fit_print_volume(const BuildVolume& volume)
|
||||
// center selection on print bed
|
||||
setup_cache();
|
||||
offset.z() = -get_bounding_box().min.z();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationType trafo_type;
|
||||
trafo_type.set_relative();
|
||||
translate(offset, trafo_type);
|
||||
#else
|
||||
translate(offset);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
wxGetApp().plater()->canvas3D()->do_move(""); // avoid storing another snapshot
|
||||
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
@ -1435,39 +1164,13 @@ void Selection::scale_to_fit_print_volume(const BuildVolume& volume)
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void Selection::mirror(Axis axis, TransformationType transformation_type)
|
||||
{
|
||||
const Vec3d mirror((axis == X) ? -1.0 : 1.0, (axis == Y) ? -1.0 : 1.0, (axis == Z) ? -1.0 : 1.0);
|
||||
scale_and_translate(mirror, Vec3d::Zero(), transformation_type);
|
||||
}
|
||||
#else
|
||||
void Selection::mirror(Axis axis)
|
||||
{
|
||||
if (!m_valid)
|
||||
return;
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
GLVolume& v = *(*m_volumes)[i];
|
||||
if (is_single_full_instance())
|
||||
v.set_instance_mirror(axis, -v.get_instance_mirror(axis));
|
||||
else if (m_mode == Volume)
|
||||
v.set_volume_mirror(axis, -v.get_volume_mirror(axis));
|
||||
}
|
||||
|
||||
#if !DISABLE_INSTANCES_SYNCH
|
||||
if (m_mode == Instance)
|
||||
synchronize_unselected_instances(SyncRotationType::NONE);
|
||||
else if (m_mode == Volume)
|
||||
synchronize_unselected_volumes();
|
||||
#endif // !DISABLE_INSTANCES_SYNCH
|
||||
|
||||
set_bounding_boxes_dirty();
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation, TransformationType transformation_type)
|
||||
void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& world_translation, TransformationType transformation_type)
|
||||
{
|
||||
if (!m_valid)
|
||||
return;
|
||||
@ -1501,32 +1204,28 @@ void Selection::scale_and_translate(const Vec3d& scale, const Vec3d& translation
|
||||
const Vec3d local_inst_pivot = inst_trafo.get_matrix_no_offset().inverse() * world_inst_pivot;
|
||||
Matrix3d inst_rotation, inst_scale;
|
||||
inst_trafo.get_matrix().computeRotationScaling(&inst_rotation, &inst_scale);
|
||||
const Transform3d offset_trafo = Geometry::translation_transform(inst_trafo.get_offset() + inst_rotation * translation);
|
||||
const Transform3d offset_trafo = Geometry::translation_transform(inst_trafo.get_offset() + world_translation);
|
||||
const Transform3d scale_trafo = Transform3d(inst_scale) * Geometry::scale_transform(relative_scale);
|
||||
v.set_instance_transformation(Geometry::translation_transform(world_inst_pivot) * offset_trafo * Transform3d(inst_rotation) * scale_trafo * Geometry::translation_transform(-local_inst_pivot));
|
||||
}
|
||||
else
|
||||
transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center);
|
||||
transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(relative_scale), m_cache.dragging_center);
|
||||
}
|
||||
else {
|
||||
if (!is_single_volume_or_modifier()) {
|
||||
assert(transformation_type.world());
|
||||
transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(scale), m_cache.dragging_center);
|
||||
transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(scale), m_cache.dragging_center);
|
||||
}
|
||||
else {
|
||||
if (transformation_type.local() && transformation_type.absolute()) {
|
||||
const Geometry::Transformation& vol_trafo = volume_data.get_volume_transform();
|
||||
Matrix3d vol_rotation, vol_scale;
|
||||
vol_trafo.get_matrix().computeRotationScaling(&vol_rotation, &vol_scale);
|
||||
const Transform3d offset_trafo = Geometry::translation_transform(vol_trafo.get_offset() + vol_rotation * translation);
|
||||
const Transform3d scale_trafo = Transform3d(vol_scale) * Geometry::scale_transform(scale);
|
||||
v.set_volume_transformation(offset_trafo * Transform3d(vol_rotation) * scale_trafo);
|
||||
}
|
||||
else {
|
||||
transformation_type.set_independent();
|
||||
transformation_type.set_relative();
|
||||
transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(scale), m_cache.dragging_center);
|
||||
}
|
||||
transformation_type.set_independent();
|
||||
Vec3d translation;
|
||||
if (transformation_type.local())
|
||||
translation = volume_data.get_volume_transform().get_matrix_no_offset().inverse() * inst_trafo.get_matrix_no_offset().inverse() * world_translation;
|
||||
else if (transformation_type.instance())
|
||||
translation = inst_trafo.get_matrix_no_offset().inverse() * world_translation;
|
||||
else
|
||||
translation = world_translation;
|
||||
transform_volume_relative(v, volume_data, transformation_type, Geometry::translation_transform(translation) * Geometry::scale_transform(scale), m_cache.dragging_center);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1604,50 +1303,6 @@ void Selection::reset_skew()
|
||||
set_bounding_boxes_dirty();
|
||||
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
|
||||
}
|
||||
#else
|
||||
void Selection::translate(unsigned int object_idx, const Vec3d& displacement)
|
||||
{
|
||||
if (!m_valid)
|
||||
return;
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
GLVolume& v = *(*m_volumes)[i];
|
||||
if (v.object_idx() == (int)object_idx)
|
||||
v.set_instance_offset(v.get_instance_offset() + displacement);
|
||||
}
|
||||
|
||||
std::set<unsigned int> done; // prevent processing volumes twice
|
||||
done.insert(m_list.begin(), m_list.end());
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
if (done.size() == m_volumes->size())
|
||||
break;
|
||||
|
||||
if ((*m_volumes)[i]->is_wipe_tower)
|
||||
continue;
|
||||
|
||||
int object_idx = (*m_volumes)[i]->object_idx();
|
||||
|
||||
// Process unselected volumes of the object.
|
||||
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) {
|
||||
if (done.size() == m_volumes->size())
|
||||
break;
|
||||
|
||||
if (done.find(j) != done.end())
|
||||
continue;
|
||||
|
||||
GLVolume& v = *(*m_volumes)[j];
|
||||
if (v.object_idx() != object_idx)
|
||||
continue;
|
||||
|
||||
v.set_instance_offset(v.get_instance_offset() + displacement);
|
||||
done.insert(j);
|
||||
}
|
||||
}
|
||||
|
||||
this->set_bounding_boxes_dirty();
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void Selection::translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement)
|
||||
{
|
||||
@ -1657,11 +1312,7 @@ void Selection::translate(unsigned int object_idx, unsigned int instance_idx, co
|
||||
for (unsigned int i : m_list) {
|
||||
GLVolume& v = *(*m_volumes)[i];
|
||||
if (v.object_idx() == (int)object_idx && v.instance_idx() == (int)instance_idx)
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
v.set_instance_transformation(Geometry::translation_transform(displacement) * v.get_instance_transformation().get_matrix());
|
||||
#else
|
||||
v.set_instance_offset(v.get_instance_offset() + displacement);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
std::set<unsigned int> done; // prevent processing volumes twice
|
||||
@ -1688,11 +1339,7 @@ void Selection::translate(unsigned int object_idx, unsigned int instance_idx, co
|
||||
if (v.object_idx() != object_idx || v.instance_idx() != (int)instance_idx)
|
||||
continue;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
v.set_instance_transformation(Geometry::translation_transform(displacement) * v.get_instance_transformation().get_matrix());
|
||||
#else
|
||||
v.set_instance_offset(v.get_instance_offset() + displacement);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
done.insert(j);
|
||||
}
|
||||
}
|
||||
@ -1700,7 +1347,6 @@ void Selection::translate(unsigned int object_idx, unsigned int instance_idx, co
|
||||
this->set_bounding_boxes_dirty();
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
int Selection::bake_transform_if_needed() const
|
||||
{
|
||||
if ((is_single_full_instance() && wxGetApp().obj_manipul()->is_world_coordinates()) ||
|
||||
@ -1751,7 +1397,6 @@ int Selection::bake_transform_if_needed() const
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void Selection::erase()
|
||||
{
|
||||
@ -1865,12 +1510,8 @@ void Selection::render(float scale_factor)
|
||||
|
||||
m_scale_factor = scale_factor;
|
||||
// render cumulative bounding box of selected volumes
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const auto& [box, trafo] = get_bounding_box_in_current_reference_system();
|
||||
render_bounding_box(box, trafo, ColorRGB::WHITE());
|
||||
#else
|
||||
render_bounding_box(get_bounding_box(), ColorRGB::WHITE());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
render_synchronized_volumes();
|
||||
}
|
||||
|
||||
@ -1919,39 +1560,15 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field)
|
||||
const Transform3d base_matrix = Geometry::translation_transform(get_bounding_box().center());
|
||||
Transform3d orient_matrix = Transform3d::Identity();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Vec3d center = get_bounding_box().center();
|
||||
Vec3d axes_center = center;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
if (!boost::starts_with(sidebar_field, "layer")) {
|
||||
shader->set_uniform("emission_factor", 0.05f);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (is_single_full_instance() && !wxGetApp().obj_manipul()->is_world_coordinates()) {
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
|
||||
axes_center = (*m_volumes)[*m_list.begin()]->get_instance_offset();
|
||||
#else
|
||||
const Vec3d& center = get_bounding_box().center();
|
||||
if (is_single_full_instance() && !wxGetApp().obj_manipul()->get_world_coordinates()) {
|
||||
glsafe(::glTranslated(center.x(), center.y(), center.z()));
|
||||
if (!boost::starts_with(sidebar_field, "position")) {
|
||||
if (boost::starts_with(sidebar_field, "scale"))
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
else if (boost::starts_with(sidebar_field, "rotation")) {
|
||||
if (boost::ends_with(sidebar_field, "x"))
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
else if (boost::ends_with(sidebar_field, "y")) {
|
||||
const Vec3d& rotation = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation();
|
||||
if (rotation.x() == 0.0)
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
else
|
||||
orient_matrix.rotate(Eigen::AngleAxisd(rotation.z(), Vec3d::UnitZ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
else if (is_single_volume_or_modifier()) {
|
||||
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
|
||||
if (wxGetApp().obj_manipul()->is_local_coordinates()) {
|
||||
@ -1964,32 +1581,18 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field)
|
||||
axes_center = (*m_volumes)[*m_list.begin()]->get_instance_offset();
|
||||
}
|
||||
}
|
||||
#else
|
||||
else if (is_single_volume() || is_single_modifier()) {
|
||||
glsafe(::glTranslated(center.x(), center.y(), center.z()));
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
if (!boost::starts_with(sidebar_field, "position"))
|
||||
orient_matrix = orient_matrix * (*m_volumes)[*m_list.begin()]->get_volume_transformation().get_matrix(true, false, true, true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
else {
|
||||
if (requires_local_axes())
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation_matrix();
|
||||
#else
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
}
|
||||
|
||||
if (!boost::starts_with(sidebar_field, "layer"))
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (!boost::starts_with(sidebar_field, "layer")) {
|
||||
if (!boost::starts_with(sidebar_field, "layer"))
|
||||
shader->set_uniform("emission_factor", 0.1f);
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
if (boost::starts_with(sidebar_field, "position"))
|
||||
render_sidebar_position_hints(sidebar_field, *shader, base_matrix * orient_matrix);
|
||||
@ -2000,12 +1603,10 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field)
|
||||
else if (boost::starts_with(sidebar_field, "layer"))
|
||||
render_sidebar_layers_hints(sidebar_field, *shader);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (!boost::starts_with(sidebar_field, "layer")) {
|
||||
if (wxGetApp().obj_manipul()->is_instance_coordinates())
|
||||
m_axes.render(Geometry::translation_transform(axes_center) * orient_matrix, 0.25f);
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
shader->stop_using();
|
||||
}
|
||||
@ -2446,11 +2047,9 @@ void Selection::render_synchronized_volumes()
|
||||
if (m_mode == Instance)
|
||||
return;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||
BoundingBoxf3 box;
|
||||
Transform3d trafo;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
const GLVolume& volume = *(*m_volumes)[i];
|
||||
@ -2464,7 +2063,6 @@ void Selection::render_synchronized_volumes()
|
||||
if (v.object_idx() != object_idx || v.volume_idx() != volume_idx)
|
||||
continue;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (coordinates_type == ECoordinatesType::World) {
|
||||
box = v.transformed_convex_hull_bounding_box();
|
||||
trafo = Transform3d::Identity();
|
||||
@ -2478,18 +2076,11 @@ void Selection::render_synchronized_volumes()
|
||||
trafo = v.get_instance_transformation().get_matrix();
|
||||
}
|
||||
render_bounding_box(box, trafo, ColorRGB::YELLOW());
|
||||
#else
|
||||
render_bounding_box(v.transformed_convex_hull_bounding_box(), ColorRGB::YELLOW());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void Selection::render_bounding_box(const BoundingBoxf3& box, const Transform3d& trafo, const ColorRGB& color)
|
||||
#else
|
||||
void Selection::render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color)
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
{
|
||||
const BoundingBoxf3& curr_box = m_box.get_bounding_box();
|
||||
|
||||
@ -2586,11 +2177,7 @@ void Selection::render_bounding_box(const BoundingBoxf3& box, const ColorRGB& co
|
||||
|
||||
shader->start_using();
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * trafo);
|
||||
#else
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
@ -2672,11 +2259,7 @@ void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field,
|
||||
|
||||
void Selection::render_sidebar_scale_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix)
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const bool uniform_scale = wxGetApp().obj_manipul()->get_uniform_scaling();
|
||||
#else
|
||||
const bool uniform_scale = requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
auto render_sidebar_scale_hint = [this, uniform_scale](Axis axis, GLShaderProgram& shader, const Transform3d& view_matrix, const Transform3d& model_matrix) {
|
||||
m_arrow.set_color(uniform_scale ? UNIFORM_SCALE_COLOR : get_color(axis));
|
||||
@ -2808,7 +2391,7 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field, GL
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_DEBUG
|
||||
#if ENABLE_MATRICES_DEBUG
|
||||
void Selection::render_debug_window() const
|
||||
{
|
||||
if (m_list.empty())
|
||||
@ -2928,7 +2511,7 @@ void Selection::render_debug_window() const
|
||||
|
||||
imgui.end();
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE_DEBUG
|
||||
#endif // ENABLE_MATRICES_DEBUG
|
||||
|
||||
static bool is_left_handed(const Transform3d::ConstLinearPart& m)
|
||||
{
|
||||
@ -3027,7 +2610,6 @@ static void verify_instances_rotation_synchronized(const Model &model, const GLV
|
||||
|
||||
#endif /* NDEBUG */
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type)
|
||||
{
|
||||
std::set<unsigned int> done; // prevent processing volumes twice
|
||||
@ -3076,69 +2658,6 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
|
||||
verify_instances_rotation_synchronized(*m_model, *m_volumes);
|
||||
#endif /* NDEBUG */
|
||||
}
|
||||
#else
|
||||
void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type)
|
||||
{
|
||||
std::set<unsigned int> done; // prevent processing volumes twice
|
||||
done.insert(m_list.begin(), m_list.end());
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
if (done.size() == m_volumes->size())
|
||||
break;
|
||||
|
||||
const GLVolume* volume_i = (*m_volumes)[i];
|
||||
if (volume_i->is_wipe_tower)
|
||||
continue;
|
||||
|
||||
const int object_idx = volume_i->object_idx();
|
||||
const int instance_idx = volume_i->instance_idx();
|
||||
const Vec3d& rotation = volume_i->get_instance_rotation();
|
||||
const Vec3d& scaling_factor = volume_i->get_instance_scaling_factor();
|
||||
const Vec3d& mirror = volume_i->get_instance_mirror();
|
||||
|
||||
// Process unselected instances.
|
||||
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) {
|
||||
if (done.size() == m_volumes->size())
|
||||
break;
|
||||
|
||||
if (done.find(j) != done.end())
|
||||
continue;
|
||||
|
||||
GLVolume* volume_j = (*m_volumes)[j];
|
||||
if (volume_j->object_idx() != object_idx || volume_j->instance_idx() == instance_idx)
|
||||
continue;
|
||||
|
||||
assert(is_rotation_xy_synchronized(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation()));
|
||||
|
||||
switch (sync_rotation_type) {
|
||||
case SyncRotationType::NONE: {
|
||||
// z only rotation -> synch instance z
|
||||
// The X,Y rotations should be synchronized from start to end of the rotation.
|
||||
assert(is_rotation_xy_synchronized(rotation, volume_j->get_instance_rotation()));
|
||||
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
|
||||
volume_j->set_instance_offset(Z, volume_i->get_instance_offset().z());
|
||||
break;
|
||||
}
|
||||
case SyncRotationType::GENERAL: {
|
||||
// generic rotation -> update instance z with the delta of the rotation.
|
||||
const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation());
|
||||
volume_j->set_instance_rotation({ rotation.x(), rotation.y(), rotation.z() + z_diff });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
volume_j->set_instance_scaling_factor(scaling_factor);
|
||||
volume_j->set_instance_mirror(mirror);
|
||||
|
||||
done.insert(j);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
verify_instances_rotation_synchronized(*m_model, *m_volumes);
|
||||
#endif /* NDEBUG */
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void Selection::synchronize_unselected_volumes()
|
||||
{
|
||||
@ -3149,14 +2668,7 @@ void Selection::synchronize_unselected_volumes()
|
||||
|
||||
const int object_idx = volume->object_idx();
|
||||
const int volume_idx = volume->volume_idx();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Geometry::Transformation& trafo = volume->get_volume_transformation();
|
||||
#else
|
||||
const Vec3d& offset = volume->get_volume_offset();
|
||||
const Vec3d& rotation = volume->get_volume_rotation();
|
||||
const Vec3d& scaling_factor = volume->get_volume_scaling_factor();
|
||||
const Vec3d& mirror = volume->get_volume_mirror();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// Process unselected volumes.
|
||||
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) {
|
||||
@ -3167,14 +2679,7 @@ void Selection::synchronize_unselected_volumes()
|
||||
if (v->object_idx() != object_idx || v->volume_idx() != volume_idx)
|
||||
continue;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
v->set_volume_transformation(trafo);
|
||||
#else
|
||||
v->set_volume_offset(offset);
|
||||
v->set_volume_rotation(rotation);
|
||||
v->set_volume_scaling_factor(scaling_factor);
|
||||
v->set_volume_mirror(mirror);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3294,13 +2799,8 @@ void Selection::paste_volumes_from_clipboard()
|
||||
{
|
||||
ModelInstance* dst_instance = dst_object->instances[dst_inst_idx];
|
||||
BoundingBoxf3 dst_instance_bb = dst_object->instance_bounding_box(dst_inst_idx);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Transform3d src_matrix = src_object->instances[0]->get_transformation().get_matrix_no_offset();
|
||||
Transform3d dst_matrix = dst_instance->get_transformation().get_matrix_no_offset();
|
||||
#else
|
||||
Transform3d src_matrix = src_object->instances[0]->get_transformation().get_matrix(true);
|
||||
Transform3d dst_matrix = dst_instance->get_transformation().get_matrix(true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
bool from_same_object = (src_object->input_file == dst_object->input_file) && src_matrix.isApprox(dst_matrix);
|
||||
|
||||
// used to keep relative position of multivolume selections when pasting from another object
|
||||
@ -3378,7 +2878,6 @@ void Selection::paste_objects_from_clipboard()
|
||||
#endif /* _DEBUG */
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void Selection::transform_instance_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
||||
const Transform3d& transform, const Vec3d& world_pivot)
|
||||
{
|
||||
@ -3420,7 +2919,6 @@ void Selection::transform_volume_relative(GLVolume& volume, const VolumeCache& v
|
||||
else
|
||||
assert(false);
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
ModelVolume *get_selected_volume(const Selection &selection)
|
||||
{
|
||||
|
@ -2,12 +2,8 @@
|
||||
#define slic3r_GUI_Selection_hpp_
|
||||
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "GUI_Geometry.hpp"
|
||||
#include "CoordAxes.hpp"
|
||||
#else
|
||||
#include "GLModel.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#include <set>
|
||||
#include <optional>
|
||||
@ -30,60 +26,6 @@ using ModelObjectPtrs = std::vector<ModelObject*>;
|
||||
|
||||
|
||||
namespace GUI {
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
class TransformationType
|
||||
{
|
||||
public:
|
||||
enum Enum {
|
||||
// Transforming in a world coordinate system
|
||||
World = 0,
|
||||
// Transforming in a local coordinate system
|
||||
Local = 1,
|
||||
// Absolute transformations, allowed in local coordinate system only.
|
||||
Absolute = 0,
|
||||
// Relative transformations, allowed in both local and world coordinate system.
|
||||
Relative = 2,
|
||||
// For group selection, the transformation is performed as if the group made a single solid body.
|
||||
Joint = 0,
|
||||
// For group selection, the transformation is performed on each object independently.
|
||||
Independent = 4,
|
||||
|
||||
World_Relative_Joint = World | Relative | Joint,
|
||||
World_Relative_Independent = World | Relative | Independent,
|
||||
Local_Absolute_Joint = Local | Absolute | Joint,
|
||||
Local_Absolute_Independent = Local | Absolute | Independent,
|
||||
Local_Relative_Joint = Local | Relative | Joint,
|
||||
Local_Relative_Independent = Local | Relative | Independent,
|
||||
};
|
||||
|
||||
TransformationType() : m_value(World) {}
|
||||
TransformationType(Enum value) : m_value(value) {}
|
||||
TransformationType& operator=(Enum value) { m_value = value; return *this; }
|
||||
|
||||
Enum operator()() const { return m_value; }
|
||||
bool has(Enum v) const { return ((unsigned int)m_value & (unsigned int)v) != 0; }
|
||||
|
||||
void set_world() { this->remove(Local); }
|
||||
void set_local() { this->add(Local); }
|
||||
void set_absolute() { this->remove(Relative); }
|
||||
void set_relative() { this->add(Relative); }
|
||||
void set_joint() { this->remove(Independent); }
|
||||
void set_independent() { this->add(Independent); }
|
||||
|
||||
bool world() const { return !this->has(Local); }
|
||||
bool local() const { return this->has(Local); }
|
||||
bool absolute() const { return !this->has(Relative); }
|
||||
bool relative() const { return this->has(Relative); }
|
||||
bool joint() const { return !this->has(Independent); }
|
||||
bool independent() const { return this->has(Independent); }
|
||||
|
||||
private:
|
||||
void add(Enum v) { m_value = Enum((unsigned int)m_value | (unsigned int)v); }
|
||||
void remove(Enum v) { m_value = Enum((unsigned int)m_value & (~(unsigned int)v)); }
|
||||
|
||||
Enum m_value;
|
||||
};
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
class Selection
|
||||
{
|
||||
@ -126,9 +68,7 @@ private:
|
||||
Transform3d scale_matrix{ Transform3d::Identity() };
|
||||
Transform3d mirror_matrix{ Transform3d::Identity() };
|
||||
Transform3d full_matrix{ Transform3d::Identity() };
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Geometry::Transformation transform;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
TransformCache() = default;
|
||||
explicit TransformCache(const Geometry::Transformation& transform);
|
||||
@ -142,18 +82,11 @@ private:
|
||||
VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform);
|
||||
|
||||
const Vec3d& get_volume_position() const { return m_volume.position; }
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
const Vec3d& get_volume_rotation() const { return m_volume.rotation; }
|
||||
const Vec3d& get_volume_scaling_factor() const { return m_volume.scaling_factor; }
|
||||
const Vec3d& get_volume_mirror() const { return m_volume.mirror; }
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
const Transform3d& get_volume_rotation_matrix() const { return m_volume.rotation_matrix; }
|
||||
const Transform3d& get_volume_scale_matrix() const { return m_volume.scale_matrix; }
|
||||
const Transform3d& get_volume_mirror_matrix() const { return m_volume.mirror_matrix; }
|
||||
const Transform3d& get_volume_full_matrix() const { return m_volume.full_matrix; }
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Geometry::Transformation& get_volume_transform() const { return m_volume.transform; }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
const Vec3d& get_instance_position() const { return m_instance.position; }
|
||||
const Vec3d& get_instance_rotation() const { return m_instance.rotation; }
|
||||
@ -163,9 +96,7 @@ private:
|
||||
const Transform3d& get_instance_scale_matrix() const { return m_instance.scale_matrix; }
|
||||
const Transform3d& get_instance_mirror_matrix() const { return m_instance.mirror_matrix; }
|
||||
const Transform3d& get_instance_full_matrix() const { return m_instance.full_matrix; }
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Geometry::Transformation& get_instance_transform() const { return m_instance.transform; }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
};
|
||||
|
||||
public:
|
||||
@ -233,7 +164,6 @@ private:
|
||||
// Bounding box of a single full instance selection, in world coordinates.
|
||||
// Modifiers are NOT taken in account
|
||||
std::optional<BoundingBoxf3> m_scaled_instance_bounding_box;
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
// Bounding box of a single full instance selection, in world coordinates, with no instance scaling applied.
|
||||
// Modifiers are taken in account
|
||||
std::optional<BoundingBoxf3> m_full_unscaled_instance_bounding_box;
|
||||
@ -246,15 +176,12 @@ private:
|
||||
// Bounding box aligned to the axis of the currently selected reference system (World/Object/Part)
|
||||
// and transform to place and orient it in world coordinates
|
||||
std::optional<std::pair<BoundingBoxf3, Transform3d>> m_bounding_box_in_current_reference_system;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
GLModel m_vbo_sphere;
|
||||
#endif // ENABLE_RENDER_SELECTION_CENTER
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
CoordAxes m_axes;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
GLModel m_arrow;
|
||||
GLModel m_curved_arrow;
|
||||
GLModel m_box;
|
||||
@ -329,9 +256,7 @@ public:
|
||||
bool is_from_single_object() const;
|
||||
bool is_sla_compliant() const;
|
||||
bool is_instance_mode() const { return m_mode == Instance; }
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
bool is_single_volume_or_modifier() const { return is_single_volume() || is_single_modifier(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
bool is_single_volume_instance() const { return is_single_full_instance() && m_list.size() == 1; }
|
||||
bool is_single_text() const;
|
||||
|
||||
@ -345,7 +270,6 @@ public:
|
||||
// returns true if the selection contains all and only the given indices
|
||||
bool matches(const std::vector<unsigned int>& volume_idxs) const;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
enum class EUniformScaleRequiredReason : unsigned char
|
||||
{
|
||||
NotRequired,
|
||||
@ -354,9 +278,6 @@ public:
|
||||
VolumeNotAxisAligned_Instance,
|
||||
MultipleSelection,
|
||||
};
|
||||
#else
|
||||
bool requires_uniform_scale() const;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// Returns the the object id if the selection is from a single object, otherwise is -1
|
||||
int get_object_idx() const;
|
||||
@ -382,7 +303,6 @@ public:
|
||||
// Bounding box of a single full instance selection, in world coordinates.
|
||||
// Modifiers are NOT taken in account
|
||||
const BoundingBoxf3& get_scaled_instance_bounding_box() const;
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
// Bounding box of a single full instance selection, in world coordinates, with no instance scaling applied.
|
||||
// Modifiers are taken in account
|
||||
const BoundingBoxf3& get_full_unscaled_instance_bounding_box() const;
|
||||
@ -398,36 +318,24 @@ public:
|
||||
// Returns the bounding box aligned to the axes of the given reference system
|
||||
// and the transform to place and orient it in world coordinates
|
||||
std::pair<BoundingBoxf3, Transform3d> get_bounding_box_in_reference_system(ECoordinatesType type) const;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void setup_cache();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void translate(const Vec3d& displacement, TransformationType transformation_type);
|
||||
#else
|
||||
void translate(const Vec3d& displacement, bool local = false);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
void rotate(const Vec3d& rotation, TransformationType transformation_type);
|
||||
void flattening_rotate(const Vec3d& normal);
|
||||
void scale(const Vec3d& scale, TransformationType transformation_type);
|
||||
void scale_to_fit_print_volume(const BuildVolume& volume);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void scale_and_translate(const Vec3d& scale, const Vec3d& translation, TransformationType transformation_type);
|
||||
void scale_and_translate(const Vec3d& scale, const Vec3d& world_translation, TransformationType transformation_type);
|
||||
void mirror(Axis axis, TransformationType transformation_type);
|
||||
void reset_skew();
|
||||
#else
|
||||
void mirror(Axis axis);
|
||||
void translate(unsigned int object_idx, const Vec3d& displacement);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
// returns:
|
||||
// -1 if the user refused to proceed with baking when asked
|
||||
// 0 if the baking was performed
|
||||
// 1 if no baking was needed
|
||||
int bake_transform_if_needed() const;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void erase();
|
||||
|
||||
@ -457,9 +365,9 @@ public:
|
||||
// returns the list of idxs of the objects which are in the selection
|
||||
std::set<unsigned int> get_object_idxs() const;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE_DEBUG
|
||||
#if ENABLE_MATRICES_DEBUG
|
||||
void render_debug_window() const;
|
||||
#endif // ENABLE_WORLD_COORDINATE_DEBUG
|
||||
#endif // ENABLE_MATRICES_DEBUG
|
||||
|
||||
private:
|
||||
void update_valid();
|
||||
@ -470,7 +378,6 @@ private:
|
||||
void do_remove_volume(unsigned int volume_idx);
|
||||
void do_remove_instance(unsigned int object_idx, unsigned int instance_idx);
|
||||
void do_remove_object(unsigned int object_idx);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void set_bounding_boxes_dirty() {
|
||||
m_bounding_box.reset();
|
||||
m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset();
|
||||
@ -478,15 +385,8 @@ private:
|
||||
m_full_unscaled_instance_local_bounding_box.reset();
|
||||
m_bounding_box_in_current_reference_system.reset();
|
||||
}
|
||||
#else
|
||||
void set_bounding_boxes_dirty() { m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
void render_synchronized_volumes();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void render_bounding_box(const BoundingBoxf3& box, const Transform3d& trafo, const ColorRGB& color);
|
||||
#else
|
||||
void render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
void render_selected_volumes() const;
|
||||
void render_bounding_box(const BoundingBoxf3& box, float* color) const;
|
||||
void render_sidebar_position_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix);
|
||||
@ -500,10 +400,8 @@ public:
|
||||
NONE = 0,
|
||||
// Synchronize after rotation by an axis not parallel with Z.
|
||||
GENERAL = 1,
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
// Synchronize after rotation reset.
|
||||
RESET = 2
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
};
|
||||
void synchronize_unselected_instances(SyncRotationType sync_rotation_type);
|
||||
void synchronize_unselected_volumes();
|
||||
@ -516,12 +414,10 @@ private:
|
||||
void paste_volumes_from_clipboard();
|
||||
void paste_objects_from_clipboard();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void transform_instance_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
||||
const Transform3d& transform, const Vec3d& world_pivot);
|
||||
void transform_volume_relative(GLVolume& volume, const VolumeCache& volume_data, TransformationType transformation_type,
|
||||
const Transform3d& transform, const Vec3d& world_pivot);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
};
|
||||
|
||||
ModelVolume *get_selected_volume(const Selection &selection);
|
||||
|
@ -163,13 +163,15 @@ void Tab::create_preset_tab()
|
||||
|
||||
add_scaled_button(panel, &m_btn_hide_incompatible_presets, "flag_green");
|
||||
|
||||
m_btn_compare_preset->SetToolTip(_L("Compare this preset with some another"));
|
||||
// TRN Settings Tabs: Tooltip for save button: "Settings"
|
||||
m_btn_save_preset->SetToolTip(format_wxstr(_L("Save current %s"), m_title));
|
||||
// TRN Settings Tabs: Tooltip for rename button: "Settings"
|
||||
m_btn_rename_preset->SetToolTip(format_wxstr(_L("Rename current %1%"), m_title));
|
||||
//TRN Settings Tab: tooltip for toolbar button
|
||||
m_btn_compare_preset->SetToolTip(_L("Compare preset with another"));
|
||||
//TRN Settings Tab: tooltip for toolbar button
|
||||
m_btn_save_preset ->SetToolTip(_L("Save preset"));
|
||||
//TRN Settings Tab: tooltip for toolbar button
|
||||
m_btn_rename_preset->SetToolTip(_L("Rename preset"));
|
||||
m_btn_rename_preset->Hide();
|
||||
m_btn_delete_preset->SetToolTip(_(L("Delete this preset")));
|
||||
//TRN Settings Tab: tooltip for toolbar button
|
||||
m_btn_delete_preset->SetToolTip(_(L("Delete preset")));
|
||||
m_btn_delete_preset->Hide();
|
||||
|
||||
add_scaled_button(panel, &m_question_btn, "question");
|
||||
@ -1122,10 +1124,11 @@ void Tab::update_wiping_button_visibility() {
|
||||
return; // ys_FIXME
|
||||
bool wipe_tower_enabled = dynamic_cast<ConfigOptionBool*>( (m_preset_bundle->prints.get_edited_preset().config ).option("wipe_tower"))->value;
|
||||
bool multiple_extruders = dynamic_cast<ConfigOptionFloats*>((m_preset_bundle->printers.get_edited_preset().config).option("nozzle_diameter"))->values.size() > 1;
|
||||
bool single_extruder_multi_material = dynamic_cast<ConfigOptionBool*>((m_preset_bundle->printers.get_edited_preset().config).option("single_extruder_multi_material"))->value;
|
||||
|
||||
auto wiping_dialog_button = wxGetApp().sidebar().get_wiping_dialog_button();
|
||||
if (wiping_dialog_button) {
|
||||
wiping_dialog_button->Show(wipe_tower_enabled && multiple_extruders);
|
||||
wiping_dialog_button->Show(wipe_tower_enabled && multiple_extruders && single_extruder_multi_material);
|
||||
wiping_dialog_button->GetParent()->Layout();
|
||||
}
|
||||
}
|
||||
@ -2410,8 +2413,8 @@ void TabPrinter::build_fff()
|
||||
if (!m_supports_min_feedrates && m_use_silent_mode) {
|
||||
if (!msg.IsEmpty())
|
||||
msg += "\n\n";
|
||||
msg += _L("Stealth mode for machine limits to G-code is not supported with selected G-code flavor.\n"
|
||||
"The Stealth mode was suppressed.");
|
||||
msg += _L("The selected G-code flavor does not support the machine limitation for Stealth mode.\n"
|
||||
"Stealth mode will not be applied and will be disabled.");
|
||||
|
||||
auto silent_mode = static_cast<ConfigOptionBool*>(m_config->option("silent_mode")->clone());
|
||||
silent_mode->value = false;
|
||||
|
@ -857,10 +857,10 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection* dependent_
|
||||
m_tree = new DiffViewCtrl(this, wxSize(em * (add_new_value_column ? 80 : 60), em * 30));
|
||||
m_tree->AppendToggleColumn_(L"\u2714" , DiffModel::colToggle, wxLinux ? 9 : 6);
|
||||
m_tree->AppendBmpTextColumn("" , DiffModel::colIconText, 28);
|
||||
m_tree->AppendBmpTextColumn(_L("Original Value"), DiffModel::colOldValue, 12);
|
||||
m_tree->AppendBmpTextColumn(_L("Modified Value"), DiffModel::colModValue, 12);
|
||||
m_tree->AppendBmpTextColumn(_L("Original value"), DiffModel::colOldValue, 12);
|
||||
m_tree->AppendBmpTextColumn(_L("Modified value"), DiffModel::colModValue, 12);
|
||||
if (add_new_value_column)
|
||||
m_tree->AppendBmpTextColumn(_L("New Value"), DiffModel::colNewValue, 12);
|
||||
m_tree->AppendBmpTextColumn(_L("New value"), DiffModel::colNewValue, 12);
|
||||
|
||||
// Add Buttons
|
||||
wxFont btn_font = this->GetFont().Scaled(1.4f);
|
||||
|
@ -455,6 +455,7 @@ MsgDataLegacy::MsgDataLegacy() :
|
||||
auto *text2 = new wxStaticText(this, wxID_ANY, _(L("For more information please visit our wiki page:")));
|
||||
static const wxString url("https://github.com/prusa3d/PrusaSlicer/wiki/Slic3r-PE-1.40-configuration-update");
|
||||
// The wiki page name is intentionally not localized:
|
||||
// TRN %s = PrusaSlicer
|
||||
auto *link = new wxHyperlinkCtrl(this, wxID_ANY, format_wxstr(_L("%s 1.40 configuration update"), SLIC3R_APP_NAME), CONFIG_UPDATE_WIKI_URL);
|
||||
content_sizer->Add(text2);
|
||||
content_sizer->Add(link);
|
||||
@ -491,13 +492,8 @@ MsgNoUpdates::~MsgNoUpdates() {}
|
||||
MsgNoAppUpdates::MsgNoAppUpdates() :
|
||||
MsgDialog(nullptr, _(L("App update")), _(L("No updates available")), wxICON_ERROR | wxOK)
|
||||
{
|
||||
|
||||
auto* text = new wxStaticText(this, wxID_ANY, wxString::Format(
|
||||
_(L(
|
||||
"%s has no version updates available."
|
||||
)),
|
||||
SLIC3R_APP_NAME
|
||||
));
|
||||
//TRN %1% is PrusaSlicer
|
||||
auto* text = new wxStaticText(this, wxID_ANY, format_wxstr(_L("Your %1% is up to date."),SLIC3R_APP_NAME));
|
||||
text->Wrap(CONTENT_WIDTH * wxGetApp().em_unit());
|
||||
content_sizer->Add(text);
|
||||
content_sizer->AddSpacer(VERT_SPACING);
|
||||
|
@ -553,13 +553,7 @@ void LockButton::OnButton(wxCommandEvent& event)
|
||||
if (m_disabled)
|
||||
return;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
SetLock(!m_is_pushed);
|
||||
#else
|
||||
m_is_pushed = !m_is_pushed;
|
||||
update_button_bitmaps();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
@ -221,7 +221,7 @@ boost::filesystem::path AppUpdater::priv::download_file(const DownloadAppData& d
|
||||
assert(file != NULL);
|
||||
if (file == NULL) {
|
||||
std::string line1 = GUI::format(_u8L("Download from %1% couldn't start:"), data.url);
|
||||
std::string line2 = GUI::format(_u8L("Can't create file at %1%."), tmp_path.string());
|
||||
std::string line2 = GUI::format(_u8L("Can't create file at %1%"), tmp_path.string());
|
||||
std::string message = GUI::format("%1%\n%2%", line1, line2);
|
||||
BOOST_LOG_TRIVIAL(error) << message;
|
||||
wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_APP_DOWNLOAD_FAILED);
|
||||
@ -266,7 +266,7 @@ boost::filesystem::path AppUpdater::priv::download_file(const DownloadAppData& d
|
||||
return false;
|
||||
}
|
||||
if (file == NULL) {
|
||||
error_message = GUI::format(_u8L("Can't create file at %1%."), tmp_path.string());
|
||||
error_message = GUI::format(_u8L("Can't create file at %1%"), tmp_path.string());
|
||||
return false;
|
||||
}
|
||||
try
|
||||
|
@ -234,7 +234,7 @@ void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
|
||||
if (status == AsyncStatus::Completed)
|
||||
hr = modelAsync->GetResults(model.GetAddressOf());
|
||||
else
|
||||
throw Slic3r::RuntimeError(L("Failed loading the input model."));
|
||||
throw Slic3r::RuntimeError("Failed loading the input model.");
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::Graphics::Printing3D::Printing3DMesh*>> meshes;
|
||||
hr = model->get_Meshes(meshes.GetAddressOf());
|
||||
@ -247,7 +247,7 @@ void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
|
||||
hr = model->RepairAsync(repairAsync.GetAddressOf());
|
||||
status = winrt_async_await(repairAsync, throw_on_cancel);
|
||||
if (status != AsyncStatus::Completed)
|
||||
throw Slic3r::RuntimeError(L("Mesh repair failed."));
|
||||
throw Slic3r::RuntimeError("Mesh repair failed.");
|
||||
repairAsync->GetResults();
|
||||
|
||||
on_progress(L("Loading repaired model"), 60);
|
||||
@ -262,14 +262,14 @@ void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
|
||||
hr = printing3d3mfpackage->SaveModelToPackageAsync(model.Get(), saveToPackageAsync.GetAddressOf());
|
||||
status = winrt_async_await(saveToPackageAsync, throw_on_cancel);
|
||||
if (status != AsyncStatus::Completed)
|
||||
throw Slic3r::RuntimeError(L("Saving mesh into the 3MF container failed."));
|
||||
throw Slic3r::RuntimeError("Saving mesh into the 3MF container failed.");
|
||||
hr = saveToPackageAsync->GetResults();
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IRandomAccessStream*>> generatorStreamAsync;
|
||||
hr = printing3d3mfpackage->SaveAsync(generatorStreamAsync.GetAddressOf());
|
||||
status = winrt_async_await(generatorStreamAsync, throw_on_cancel);
|
||||
if (status != AsyncStatus::Completed)
|
||||
throw Slic3r::RuntimeError(L("Saving mesh into the 3MF container failed."));
|
||||
throw Slic3r::RuntimeError("Saving mesh into the 3MF container failed.");
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream> generatorStream;
|
||||
hr = generatorStreamAsync->GetResults(generatorStream.GetAddressOf());
|
||||
|
||||
@ -300,7 +300,7 @@ void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
|
||||
hr = inputStream->ReadAsync(buffer.Get(), 65536 * 2048, ABI::Windows::Storage::Streams::InputStreamOptions_ReadAhead, asyncRead.GetAddressOf());
|
||||
status = winrt_async_await(asyncRead, throw_on_cancel);
|
||||
if (status != AsyncStatus::Completed)
|
||||
throw Slic3r::RuntimeError(L("Saving mesh into the 3MF container failed."));
|
||||
throw Slic3r::RuntimeError("Saving mesh into the 3MF container failed.");
|
||||
hr = buffer->get_Length(&length);
|
||||
if (length == 0)
|
||||
break;
|
||||
@ -375,7 +375,7 @@ bool fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx, wxPro
|
||||
mo->add_instance();
|
||||
if (!Slic3r::store_3mf(path_src.string().c_str(), &model, nullptr, false, nullptr, false)) {
|
||||
boost::filesystem::remove(path_src);
|
||||
throw Slic3r::RuntimeError(L("Export of a temporary 3mf file failed"));
|
||||
throw Slic3r::RuntimeError("Export of a temporary 3mf file failed");
|
||||
}
|
||||
model.clear_objects();
|
||||
model.clear_materials();
|
||||
@ -391,15 +391,15 @@ bool fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx, wxPro
|
||||
bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), config, config_substitutions, &model, false);
|
||||
boost::filesystem::remove(path_dst);
|
||||
if (! loaded)
|
||||
throw Slic3r::RuntimeError(L("Import of the repaired 3mf file failed"));
|
||||
throw Slic3r::RuntimeError("Import of the repaired 3mf file failed");
|
||||
if (model.objects.size() == 0)
|
||||
throw Slic3r::RuntimeError(L("Repaired 3MF file does not contain any object"));
|
||||
throw Slic3r::RuntimeError("Repaired 3MF file does not contain any object");
|
||||
if (model.objects.size() > 1)
|
||||
throw Slic3r::RuntimeError(L("Repaired 3MF file contains more than one object"));
|
||||
throw Slic3r::RuntimeError("Repaired 3MF file contains more than one object");
|
||||
if (model.objects.front()->volumes.size() == 0)
|
||||
throw Slic3r::RuntimeError(L("Repaired 3MF file does not contain any volume"));
|
||||
throw Slic3r::RuntimeError("Repaired 3MF file does not contain any volume");
|
||||
if (model.objects.front()->volumes.size() > 1)
|
||||
throw Slic3r::RuntimeError(L("Repaired 3MF file contains more than one volume"));
|
||||
throw Slic3r::RuntimeError("Repaired 3MF file contains more than one volume");
|
||||
meshes_repaired.emplace_back(std::move(model.objects.front()->volumes.front()->mesh()));
|
||||
}
|
||||
for (size_t i = 0; i < volumes.size(); ++ i) {
|
||||
|
@ -1119,12 +1119,12 @@ void PrusaConnect::set_http_post_header_args(Http& http, PrintHostPostUploadActi
|
||||
|
||||
wxString PrusaConnect::get_test_ok_msg() const
|
||||
{
|
||||
return _(L("Connection to PrusaConnect works correctly."));
|
||||
return _(L("Connection to Prusa Connect works correctly."));
|
||||
}
|
||||
|
||||
wxString PrusaConnect::get_test_failed_msg(wxString& msg) const
|
||||
{
|
||||
return GUI::format_wxstr("%s: %s", _L("Could not connect to PrusaConnect"), msg);
|
||||
return GUI::format_wxstr("%s: %s", _L("Could not connect to Prusa Connect"), msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
set(SLIC3R_APP_NAME "PrusaSlicer")
|
||||
set(SLIC3R_APP_KEY "PrusaSlicer")
|
||||
set(SLIC3R_VERSION "2.6.0-alpha5")
|
||||
set(SLIC3R_VERSION "2.6.0-alpha6")
|
||||
set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN")
|
||||
set(SLIC3R_RC_VERSION "2,6,0,0")
|
||||
set(SLIC3R_RC_VERSION_DOTS "2.6.0.0")
|
||||
|
Loading…
x
Reference in New Issue
Block a user