Merge branch 'master' of https://github.com/Prusa-Development/PrusaSlicerPrivate into et_picking_parts_fix

This commit is contained in:
enricoturri1966 2023-04-04 11:40:10 +02:00
commit a0f1b0313a
93 changed files with 48927 additions and 50928 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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()) ?

View File

@ -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;

View File

@ -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)

View File

@ -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
{

View File

@ -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];

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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); }

View File

@ -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();

View File

@ -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>>(

View File

@ -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 });

View File

@ -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

View File

@ -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);

View File

@ -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);
}
}
});

View File

@ -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;

View File

@ -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());

View File

@ -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_

View File

@ -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();
}

View File

@ -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)

View File

@ -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 };

View File

@ -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();

View File

@ -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(); }

View File

@ -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).

View 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);

View File

@ -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

View File

@ -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_

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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(); }

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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
};
}}

View File

@ -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
{

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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();

View File

@ -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)

View File

@ -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());

View File

@ -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"); }

View File

@ -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, &center](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

View File

@ -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
};

View File

@ -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.

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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();
};

View File

@ -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)

View File

@ -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());

View File

@ -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

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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)

View File

@ -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());

View File

@ -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;
}

View File

@ -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"));

View File

@ -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());
}

View File

@ -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)));

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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();
}

View File

@ -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

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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")