Merge branch 'master' into fs_undoredo

This commit is contained in:
Filip Sykala - NTB T15p 2023-04-03 11:15:07 +02:00
commit 482b56f108
54 changed files with 1044 additions and 2710 deletions

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

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

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

@ -4935,18 +4935,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

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

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

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

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

@ -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;
@ -1816,7 +1817,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();
@ -1827,9 +1827,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();
}
@ -2140,8 +2138,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;
@ -2152,6 +2148,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(
@ -2724,13 +2724,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;
}
);
@ -3337,14 +3333,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();
@ -3612,17 +3604,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();
@ -3693,13 +3677,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)
@ -3716,22 +3696,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();
}
}
@ -3795,23 +3763,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();
}
@ -3873,18 +3829,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();
}
}
@ -3907,7 +3854,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)
@ -3969,7 +3915,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()
{
@ -4148,7 +4093,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()),
@ -4156,14 +4100,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());
@ -5750,9 +5686,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()
@ -6168,18 +6104,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());
@ -7330,11 +7259,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

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

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

@ -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
@ -1425,7 +1426,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())
@ -1434,15 +1435,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)
@ -2058,7 +2059,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());
@ -2072,14 +2073,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)
@ -2286,7 +2288,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());
}
}
@ -2302,32 +2304,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 exising 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,\nthat you want permanently and unrecoverable \nremove \"%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()) {
@ -2338,25 +2355,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
@ -2403,7 +2401,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
@ -2412,7 +2410,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())) {
@ -2945,17 +2943,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() ||
@ -3017,7 +3015,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) {

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

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

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

@ -1700,6 +1700,10 @@ void ImGuiWrapper::init_font(bool compress)
assert(rect->Width == icon_sz);
assert(rect->Height == icon_sz);
std::vector<unsigned char> raw_data = load_svg(icon.second, icon_sz, icon_sz);
if (raw_data.empty()) {
rect_id++;
continue;
}
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);

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

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

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

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

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

@ -1122,10 +1122,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();
}
}

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

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