Merge branch 'et_gcode_viewer' of https://github.com/prusa3d/PrusaSlicer into et_gcode_viewer
This commit is contained in:
commit
32178dd06d
20 changed files with 571 additions and 89 deletions
|
@ -57,6 +57,14 @@ using namespace Slic3r;
|
|||
|
||||
int CLI::run(int argc, char **argv)
|
||||
{
|
||||
|
||||
#ifdef __WXGTK__
|
||||
// On Linux, wxGTK has no support for Wayland, and the app crashes on
|
||||
// startup if gtk3 is used. This env var has to be set explicitly to
|
||||
// instruct the window manager to fall back to X server mode.
|
||||
::setenv("GDK_BACKEND", "x11", /* replace */ true);
|
||||
#endif
|
||||
|
||||
// Switch boost::filesystem to utf8.
|
||||
try {
|
||||
boost::nowide::nowide_filesystem();
|
||||
|
|
|
@ -591,6 +591,7 @@ void GCodeProcessor::store_move_vertex(EMoveType type)
|
|||
vertex.fan_speed = m_fan_speed;
|
||||
vertex.extruder_id = m_extruder_id;
|
||||
vertex.cp_color_id = m_cp_color.current;
|
||||
vertex.time = static_cast<float>(m_result.moves.size());
|
||||
m_result.moves.emplace_back(vertex);
|
||||
}
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ namespace Slic3r {
|
|||
float height{ 0.0f }; // mm
|
||||
float mm3_per_mm{ 0.0f };
|
||||
float fan_speed{ 0.0f }; // percentage
|
||||
float time{ 0.0f }; // s
|
||||
|
||||
float volumetric_rate() const { return feedrate * mm3_per_mm; }
|
||||
|
||||
|
|
|
@ -1040,6 +1040,8 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
|||
for (ModelVolume *volume : volumes) {
|
||||
const auto volume_matrix = volume->get_matrix();
|
||||
|
||||
volume->m_supported_facets.clear();
|
||||
|
||||
if (! volume->is_model_part()) {
|
||||
// Modifiers are not cut, but we still need to add the instance transformation
|
||||
// to the modifier volume transformation to preserve their shape properly.
|
||||
|
@ -1739,6 +1741,41 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::vector<int> FacetsAnnotation::get_facets(FacetSupportType type) const
|
||||
{
|
||||
std::vector<int> out;
|
||||
for (auto& [facet_idx, this_type] : m_data)
|
||||
if (this_type == type)
|
||||
out.push_back(facet_idx);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FacetsAnnotation::set_facet(int idx, FacetSupportType type)
|
||||
{
|
||||
bool changed = true;
|
||||
|
||||
if (type == FacetSupportType::NONE)
|
||||
changed = m_data.erase(idx) != 0;
|
||||
else
|
||||
m_data[idx] = type;
|
||||
|
||||
if (changed)
|
||||
update_timestamp();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FacetsAnnotation::clear()
|
||||
{
|
||||
m_data.clear();
|
||||
update_timestamp();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Test whether the two models contain the same number of ModelObjects with the same set of IDs
|
||||
// ordered in the same order. In that case it is not necessary to kill the background processing.
|
||||
bool model_object_list_equal(const Model &model_old, const Model &model_new)
|
||||
|
@ -1802,6 +1839,16 @@ bool model_volume_list_changed(const ModelObject &model_object_old, const ModelO
|
|||
return false;
|
||||
}
|
||||
|
||||
bool model_custom_supports_data_changed(const ModelObject& mo, const ModelObject& mo_new) {
|
||||
assert(! model_volume_list_changed(mo, mo_new, ModelVolumeType::MODEL_PART));
|
||||
assert(mo.volumes.size() == mo_new.volumes.size());
|
||||
for (size_t i=0; i<mo.volumes.size(); ++i) {
|
||||
if (! mo_new.volumes[i]->m_supported_facets.is_same_as(mo.volumes[i]->m_supported_facets))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
extern bool model_has_multi_part_objects(const Model &model)
|
||||
{
|
||||
for (const ModelObject *model_object : model.objects)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
namespace cereal {
|
||||
class BinaryInputArchive;
|
||||
|
@ -214,8 +215,8 @@ public:
|
|||
when user expects that. */
|
||||
Vec3d origin_translation;
|
||||
|
||||
Model* get_model() { return m_model; };
|
||||
const Model* get_model() const { return m_model; };
|
||||
Model* get_model() { return m_model; }
|
||||
const Model* get_model() const { return m_model; }
|
||||
|
||||
ModelVolume* add_volume(const TriangleMesh &mesh);
|
||||
ModelVolume* add_volume(TriangleMesh &&mesh);
|
||||
|
@ -391,6 +392,34 @@ enum class ModelVolumeType : int {
|
|||
SUPPORT_BLOCKER,
|
||||
};
|
||||
|
||||
enum class FacetSupportType : int8_t {
|
||||
NONE = 0,
|
||||
ENFORCER = 1,
|
||||
BLOCKER = 2
|
||||
};
|
||||
|
||||
class FacetsAnnotation {
|
||||
public:
|
||||
using ClockType = std::chrono::steady_clock;
|
||||
|
||||
std::vector<int> get_facets(FacetSupportType type) const;
|
||||
void set_facet(int idx, FacetSupportType type);
|
||||
void clear();
|
||||
|
||||
ClockType::time_point get_timestamp() const { return timestamp; }
|
||||
bool is_same_as(const FacetsAnnotation& other) const {
|
||||
return timestamp == other.get_timestamp();
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<int, FacetSupportType> m_data;
|
||||
|
||||
ClockType::time_point timestamp;
|
||||
void update_timestamp() {
|
||||
timestamp = ClockType::now();
|
||||
}
|
||||
};
|
||||
|
||||
// An object STL, or a modifier volume, over which a different set of parameters shall be applied.
|
||||
// ModelVolume instances are owned by a ModelObject.
|
||||
class ModelVolume final : public ObjectBase
|
||||
|
@ -421,8 +450,11 @@ public:
|
|||
// overriding the global Slic3r settings and the ModelObject settings.
|
||||
ModelConfig config;
|
||||
|
||||
// List of mesh facets to be supported/unsupported.
|
||||
FacetsAnnotation m_supported_facets;
|
||||
|
||||
// A parent object owning this modifier volume.
|
||||
ModelObject* get_object() const { return this->object; };
|
||||
ModelObject* get_object() const { return this->object; }
|
||||
ModelVolumeType type() const { return m_type; }
|
||||
void set_type(const ModelVolumeType t) { m_type = t; }
|
||||
bool is_model_part() const { return m_type == ModelVolumeType::MODEL_PART; }
|
||||
|
@ -548,7 +580,9 @@ private:
|
|||
// Copying an existing volume, therefore this volume will get a copy of the ID assigned.
|
||||
ModelVolume(ModelObject *object, const ModelVolume &other) :
|
||||
ObjectBase(other),
|
||||
name(other.name), source(other.source), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation)
|
||||
name(other.name), source(other.source), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull),
|
||||
config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation),
|
||||
m_supported_facets(other.m_supported_facets)
|
||||
{
|
||||
assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id());
|
||||
assert(this->id() == other.id() && this->config.id() == other.config.id());
|
||||
|
@ -565,6 +599,8 @@ private:
|
|||
if (mesh.stl.stats.number_of_facets > 1)
|
||||
calculate_convex_hull();
|
||||
assert(this->config.id().valid()); assert(this->config.id() != other.config.id()); assert(this->id() != this->config.id());
|
||||
|
||||
m_supported_facets.clear();
|
||||
}
|
||||
|
||||
ModelVolume& operator=(ModelVolume &rhs) = delete;
|
||||
|
@ -820,8 +856,7 @@ public:
|
|||
std::string propose_export_file_name_and_path(const std::string &new_extension) const;
|
||||
|
||||
private:
|
||||
|
||||
explicit Model(int) : ObjectBase(-1) { assert(this->id().invalid()); };
|
||||
explicit Model(int) : ObjectBase(-1) { assert(this->id().invalid()); }
|
||||
void assign_new_unique_ids_recursive();
|
||||
void update_links_bottom_up_recursive();
|
||||
|
||||
|
@ -848,6 +883,10 @@ extern bool model_object_list_extended(const Model &model_old, const Model &mode
|
|||
// than the old ModelObject.
|
||||
extern bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolumeType type);
|
||||
|
||||
// Test whether the now ModelObject has newer custom supports data than the old one.
|
||||
// The function assumes that volumes list is synchronized.
|
||||
extern bool model_custom_supports_data_changed(const ModelObject& mo, const ModelObject& mo_new);
|
||||
|
||||
// If the model has multi-part objects, then it is currently not supported by the SLA mode.
|
||||
// Either the model cannot be loaded, or a SLA printer has to be activated.
|
||||
extern bool model_has_multi_part_objects(const Model &model);
|
||||
|
|
|
@ -114,6 +114,7 @@ public:
|
|||
Point& operator+=(const Point& rhs) { (*this)(0) += rhs(0); (*this)(1) += rhs(1); return *this; }
|
||||
Point& operator-=(const Point& rhs) { (*this)(0) -= rhs(0); (*this)(1) -= rhs(1); return *this; }
|
||||
Point& operator*=(const double &rhs) { (*this)(0) = coord_t((*this)(0) * rhs); (*this)(1) = coord_t((*this)(1) * rhs); return *this; }
|
||||
Point operator*(const double &rhs) { return Point((*this)(0) * rhs, (*this)(1) * rhs); }
|
||||
|
||||
void rotate(double angle);
|
||||
void rotate(double angle, const Point ¢er);
|
||||
|
|
|
@ -404,6 +404,7 @@ static inline void model_volume_list_copy_configs(ModelObject &model_object_dst,
|
|||
// Copy the ModelVolume data.
|
||||
mv_dst.name = mv_src.name;
|
||||
static_cast<DynamicPrintConfig&>(mv_dst.config) = static_cast<const DynamicPrintConfig&>(mv_src.config);
|
||||
mv_dst.m_supported_facets = mv_src.m_supported_facets;
|
||||
//FIXME what to do with the materials?
|
||||
// mv_dst.m_material_id = mv_src.m_material_id;
|
||||
++ i_src;
|
||||
|
@ -854,7 +855,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||
}
|
||||
// Copy content of the ModelObject including its ID, do not change the parent.
|
||||
model_object.assign_copy(model_object_new);
|
||||
} else if (support_blockers_differ || support_enforcers_differ) {
|
||||
} else if (support_blockers_differ || support_enforcers_differ || model_custom_supports_data_changed(model_object, model_object_new)) {
|
||||
// First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list.
|
||||
this->call_cancel_callback();
|
||||
update_apply_status(false);
|
||||
|
@ -862,8 +863,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
||||
for (auto it = range.first; it != range.second; ++ it)
|
||||
update_apply_status(it->print_object->invalidate_step(posSupportMaterial));
|
||||
// Copy just the support volumes.
|
||||
model_volume_list_update_supports(model_object, model_object_new);
|
||||
if (support_enforcers_differ || support_blockers_differ) {
|
||||
// Copy just the support volumes.
|
||||
model_volume_list_update_supports(model_object, model_object_new);
|
||||
}
|
||||
}
|
||||
if (! model_parts_differ && ! modifiers_differ) {
|
||||
// Synchronize Object's config.
|
||||
|
@ -881,7 +884,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||
}
|
||||
}
|
||||
}
|
||||
// Synchronize (just copy) the remaining data of ModelVolumes (name, config).
|
||||
// Synchronize (just copy) the remaining data of ModelVolumes (name, config, custom supports data).
|
||||
//FIXME What to do with m_material_id?
|
||||
model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::MODEL_PART);
|
||||
model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::PARAMETER_MODIFIER);
|
||||
|
|
|
@ -195,6 +195,11 @@ public:
|
|||
std::vector<ExPolygons> slice_support_blockers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_BLOCKER); }
|
||||
std::vector<ExPolygons> slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); }
|
||||
|
||||
// Helpers to project custom supports on slices
|
||||
void project_and_append_custom_supports(FacetSupportType type, std::vector<ExPolygons>& expolys) const;
|
||||
void project_and_append_custom_enforcers(std::vector<ExPolygons>& enforcers) const { project_and_append_custom_supports(FacetSupportType::ENFORCER, enforcers); }
|
||||
void project_and_append_custom_blockers(std::vector<ExPolygons>& blockers) const { project_and_append_custom_supports(FacetSupportType::BLOCKER, blockers); }
|
||||
|
||||
private:
|
||||
// to be called from Print only.
|
||||
friend class Print;
|
||||
|
|
|
@ -2645,4 +2645,168 @@ void PrintObject::_generate_support_material()
|
|||
support_material.generate(*this);
|
||||
}
|
||||
|
||||
|
||||
void PrintObject::project_and_append_custom_supports(
|
||||
FacetSupportType type, std::vector<ExPolygons>& expolys) const
|
||||
{
|
||||
for (const ModelVolume* mv : this->model_object()->volumes) {
|
||||
const std::vector<int> custom_facets = mv->m_supported_facets.get_facets(type);
|
||||
if (custom_facets.empty())
|
||||
continue;
|
||||
|
||||
const TriangleMesh& mesh = mv->mesh();
|
||||
const Transform3f& tr1 = mv->get_matrix().cast<float>();
|
||||
const Transform3f& tr2 = this->trafo().cast<float>();
|
||||
const Transform3f tr = tr2 * tr1;
|
||||
|
||||
|
||||
// The projection will be at most a pentagon. Let's minimize heap
|
||||
// reallocations by saving in in the following struct.
|
||||
// Points are used so that scaling can be done in parallel
|
||||
// and they can be moved from to create an ExPolygon later.
|
||||
struct LightPolygon {
|
||||
LightPolygon() { pts.reserve(5); }
|
||||
Points pts;
|
||||
|
||||
void add(const Vec2f& pt) {
|
||||
pts.emplace_back(scale_(pt.x()), scale_(pt.y()));
|
||||
assert(pts.size() <= 5);
|
||||
}
|
||||
};
|
||||
|
||||
// Structure to collect projected polygons. One element for each triangle.
|
||||
// Saves vector of polygons and layer_id of the first one.
|
||||
struct TriangleProjections {
|
||||
size_t first_layer_id;
|
||||
std::vector<LightPolygon> polygons;
|
||||
};
|
||||
|
||||
// Vector to collect resulting projections from each triangle.
|
||||
std::vector<TriangleProjections> projections_of_triangles(custom_facets.size());
|
||||
|
||||
// Iterate over all triangles.
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<size_t>(0, custom_facets.size()),
|
||||
[&](const tbb::blocked_range<size_t>& range) {
|
||||
for (size_t idx = range.begin(); idx < range.end(); ++ idx) {
|
||||
|
||||
std::array<Vec3f, 3> facet;
|
||||
|
||||
// Transform the triangle into worlds coords.
|
||||
for (int i=0; i<3; ++i)
|
||||
facet[i] = tr * mesh.its.vertices[mesh.its.indices[custom_facets[idx]](i)];
|
||||
|
||||
// Ignore triangles with upward-pointing normal.
|
||||
if ((facet[1]-facet[0]).cross(facet[2]-facet[0]).z() > 0.)
|
||||
continue;
|
||||
|
||||
// Sort the three vertices according to z-coordinate.
|
||||
std::sort(facet.begin(), facet.end(),
|
||||
[](const Vec3f& pt1, const Vec3f&pt2) {
|
||||
return pt1.z() < pt2.z();
|
||||
});
|
||||
|
||||
std::array<Vec2f, 3> trianglef;
|
||||
for (int i=0; i<3; ++i) {
|
||||
trianglef[i] = Vec2f(facet[i].x(), facet[i].y());
|
||||
trianglef[i] += Vec2f(unscale<float>(this->center_offset().x()),
|
||||
unscale<float>(this->center_offset().y()));
|
||||
}
|
||||
|
||||
// Find lowest slice not below the triangle.
|
||||
auto it = std::lower_bound(layers().begin(), layers().end(), facet[0].z()+EPSILON,
|
||||
[](const Layer* l1, float z) {
|
||||
return l1->slice_z < z;
|
||||
});
|
||||
|
||||
// Count how many projections will be generated for this triangle
|
||||
// and allocate respective amount in projections_of_triangles.
|
||||
projections_of_triangles[idx].first_layer_id = it-layers().begin();
|
||||
size_t last_layer_id = projections_of_triangles[idx].first_layer_id;
|
||||
// The cast in the condition below is important. The comparison must
|
||||
// be an exact opposite of the one lower in the code where
|
||||
// the polygons are appended. And that one is on floats.
|
||||
while (last_layer_id + 1 < layers().size()
|
||||
&& float(layers()[last_layer_id]->slice_z) <= facet[2].z())
|
||||
++last_layer_id;
|
||||
projections_of_triangles[idx].polygons.resize(
|
||||
last_layer_id - projections_of_triangles[idx].first_layer_id + 1);
|
||||
|
||||
// Calculate how to move points on triangle sides per unit z increment.
|
||||
Vec2f ta(trianglef[1] - trianglef[0]);
|
||||
Vec2f tb(trianglef[2] - trianglef[0]);
|
||||
ta *= 1./(facet[1].z() - facet[0].z());
|
||||
tb *= 1./(facet[2].z() - facet[0].z());
|
||||
|
||||
// Projection on current slice will be build directly in place.
|
||||
LightPolygon* proj = &projections_of_triangles[idx].polygons[0];
|
||||
proj->add(trianglef[0]);
|
||||
|
||||
bool passed_first = false;
|
||||
bool stop = false;
|
||||
|
||||
// Project a sub-polygon on all slices intersecting the triangle.
|
||||
while (it != layers().end()) {
|
||||
const float z = (*it)->slice_z;
|
||||
|
||||
// Projections of triangle sides intersections with slices.
|
||||
// a moves along one side, b tracks the other.
|
||||
Vec2f a;
|
||||
Vec2f b;
|
||||
|
||||
// If the middle vertex was already passed, append the vertex
|
||||
// and use ta for tracking the remaining side.
|
||||
if (z > facet[1].z() && ! passed_first) {
|
||||
proj->add(trianglef[1]);
|
||||
ta = trianglef[2]-trianglef[1];
|
||||
ta *= 1./(facet[2].z() - facet[1].z());
|
||||
passed_first = true;
|
||||
}
|
||||
|
||||
// This slice is above the triangle already.
|
||||
if (z > facet[2].z() || it+1 == layers().end()) {
|
||||
proj->add(trianglef[2]);
|
||||
stop = true;
|
||||
}
|
||||
else {
|
||||
// Move a, b along the side it currently tracks to get
|
||||
// projected intersection with current slice.
|
||||
a = passed_first ? (trianglef[1]+ta*(z-facet[1].z()))
|
||||
: (trianglef[0]+ta*(z-facet[0].z()));
|
||||
b = trianglef[0]+tb*(z-facet[0].z());
|
||||
proj->add(a);
|
||||
proj->add(b);
|
||||
}
|
||||
|
||||
if (stop)
|
||||
break;
|
||||
|
||||
// Advance to the next layer.
|
||||
++it;
|
||||
++proj;
|
||||
assert(proj <= &projections_of_triangles[idx].polygons.back() );
|
||||
|
||||
// a, b are first two points of the polygon for the next layer.
|
||||
proj->add(b);
|
||||
proj->add(a);
|
||||
}
|
||||
}
|
||||
}); // end of parallel_for
|
||||
|
||||
// Make sure that the output vector can be used.
|
||||
expolys.resize(layers().size());
|
||||
|
||||
// Now append the collected polygons to respective layers.
|
||||
for (auto& trg : projections_of_triangles) {
|
||||
int layer_id = trg.first_layer_id;
|
||||
|
||||
for (const LightPolygon& poly : trg.polygons) {
|
||||
expolys[layer_id].emplace_back(std::move(poly.pts));
|
||||
++layer_id;
|
||||
}
|
||||
}
|
||||
|
||||
} // loop over ModelVolumes
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -971,6 +971,10 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
|||
std::vector<ExPolygons> enforcers = object.slice_support_enforcers();
|
||||
std::vector<ExPolygons> blockers = object.slice_support_blockers();
|
||||
|
||||
// Append custom supports.
|
||||
object.project_and_append_custom_enforcers(enforcers);
|
||||
object.project_and_append_custom_blockers(blockers);
|
||||
|
||||
// Output layers, sorted by top Z.
|
||||
MyLayersPtr contact_out;
|
||||
|
||||
|
@ -1097,10 +1101,10 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
|||
if (! enforcers.empty()) {
|
||||
// Apply the "support enforcers".
|
||||
//FIXME add the "enforcers" to the sparse support regions only.
|
||||
const ExPolygons &enforcer = enforcers[layer_id - 1];
|
||||
const ExPolygons &enforcer = enforcers[layer_id];
|
||||
if (! enforcer.empty()) {
|
||||
// Enforce supports (as if with 90 degrees of slope) for the regions covered by the enforcer meshes.
|
||||
Polygons new_contacts = diff(intersection(layerm_polygons, to_polygons(enforcer)),
|
||||
Polygons new_contacts = diff(intersection(layerm_polygons, to_polygons(std::move(enforcer))),
|
||||
offset(lower_layer_polygons, 0.05f * fw, SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
||||
if (! new_contacts.empty()) {
|
||||
if (diff_polygons.empty())
|
||||
|
@ -1111,19 +1115,26 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
|||
}
|
||||
}
|
||||
}
|
||||
// Apply the "support blockers".
|
||||
if (! diff_polygons.empty() && ! blockers.empty() && ! blockers[layer_id].empty()) {
|
||||
// Enforce supports (as if with 90 degrees of slope) for the regions covered by the enforcer meshes.
|
||||
diff_polygons = diff(diff_polygons, to_polygons(blockers[layer_id]));
|
||||
}
|
||||
|
||||
if (diff_polygons.empty())
|
||||
continue;
|
||||
|
||||
// Apply the "support blockers".
|
||||
if (! blockers.empty() && ! blockers[layer_id].empty()) {
|
||||
// Expand the blocker a bit. Custom blockers produce strips
|
||||
// spanning just the projection between the two slices.
|
||||
// Subtracting them as they are may leave unwanted narrow
|
||||
// residues of diff_polygons that would then be supported.
|
||||
diff_polygons = diff(diff_polygons,
|
||||
offset(union_(to_polygons(std::move(blockers[layer_id]))),
|
||||
1000.*SCALED_EPSILON));
|
||||
}
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
{
|
||||
::Slic3r::SVG svg(debug_out_path("support-top-contacts-raw-run%d-layer%d-region%d.svg",
|
||||
iRun, layer_id,
|
||||
std::find_if(layer.regions.begin(), layer.regions.end(), [layerm](const LayerRegion* other){return other == layerm;}) - layer.regions.begin()),
|
||||
std::find_if(layer.regions.begin(), layer.regions.end(), [layerm](const LayerRegion* other){return other == layerm;}) - layer.regions.begin()),
|
||||
get_extents(diff_polygons));
|
||||
Slic3r::ExPolygons expolys = union_ex(diff_polygons, false);
|
||||
svg.draw(expolys);
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
// Enable G-Code viewer
|
||||
#define ENABLE_GCODE_VIEWER (1 && ENABLE_2_3_0_ALPHA1)
|
||||
#define ENABLE_GCODE_VIEWER_DEBUG_OUTPUT (0 && ENABLE_GCODE_VIEWER)
|
||||
#define ENABLE_GCODE_VIEWER_GL_OPTIMIZATION (1 && ENABLE_GCODE_VIEWER)
|
||||
#define ENABLE_GCODE_VIEWER_STATISTICS (0 && ENABLE_GCODE_VIEWER)
|
||||
|
||||
|
||||
|
|
|
@ -259,7 +259,8 @@ Point Bed3D::point_projection(const Point& point) const
|
|||
return m_polygon.point_projection(point);
|
||||
}
|
||||
|
||||
void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes) const
|
||||
void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor,
|
||||
bool show_axes, bool show_texture) const
|
||||
{
|
||||
m_scale_factor = scale_factor;
|
||||
|
||||
|
@ -270,9 +271,9 @@ void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool sho
|
|||
|
||||
switch (m_type)
|
||||
{
|
||||
case System: { render_system(canvas, bottom); break; }
|
||||
case System: { render_system(canvas, bottom, show_texture); break; }
|
||||
default:
|
||||
case Custom: { render_custom(canvas, bottom); break; }
|
||||
case Custom: { render_custom(canvas, bottom, show_texture); break; }
|
||||
}
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
|
@ -384,12 +385,13 @@ void Bed3D::render_axes() const
|
|||
m_axes.render();
|
||||
}
|
||||
|
||||
void Bed3D::render_system(GLCanvas3D& canvas, bool bottom) const
|
||||
void Bed3D::render_system(GLCanvas3D& canvas, bool bottom, bool show_texture) const
|
||||
{
|
||||
if (!bottom)
|
||||
render_model();
|
||||
|
||||
render_texture(bottom, canvas);
|
||||
if (show_texture)
|
||||
render_texture(bottom, canvas);
|
||||
}
|
||||
|
||||
void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
|
||||
|
@ -564,7 +566,7 @@ void Bed3D::render_model() const
|
|||
}
|
||||
}
|
||||
|
||||
void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom) const
|
||||
void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture) const
|
||||
{
|
||||
if (m_texture_filename.empty() && m_model_filename.empty())
|
||||
{
|
||||
|
@ -575,7 +577,8 @@ void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom) const
|
|||
if (!bottom)
|
||||
render_model();
|
||||
|
||||
render_texture(bottom, canvas);
|
||||
if (show_texture)
|
||||
render_texture(bottom, canvas);
|
||||
}
|
||||
|
||||
void Bed3D::render_default(bool bottom) const
|
||||
|
|
|
@ -103,11 +103,15 @@ public:
|
|||
// Return true if the bed shape changed, so the calee will update the UI.
|
||||
bool set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model);
|
||||
|
||||
const BoundingBoxf3& get_bounding_box(bool extended) const { return extended ? m_extended_bounding_box : m_bounding_box; }
|
||||
const BoundingBoxf3& get_bounding_box(bool extended) const {
|
||||
return extended ? m_extended_bounding_box : m_bounding_box;
|
||||
}
|
||||
|
||||
bool contains(const Point& point) const;
|
||||
Point point_projection(const Point& point) const;
|
||||
|
||||
void render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes) const;
|
||||
void render(GLCanvas3D& canvas, bool bottom, float scale_factor,
|
||||
bool show_axes, bool show_texture) const;
|
||||
|
||||
private:
|
||||
void calc_bounding_boxes() const;
|
||||
|
@ -115,10 +119,10 @@ private:
|
|||
void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox);
|
||||
std::tuple<EType, std::string, std::string> detect_type(const Pointfs& shape) const;
|
||||
void render_axes() const;
|
||||
void render_system(GLCanvas3D& canvas, bool bottom) const;
|
||||
void render_system(GLCanvas3D& canvas, bool bottom, bool show_texture) const;
|
||||
void render_texture(bool bottom, GLCanvas3D& canvas) const;
|
||||
void render_model() const;
|
||||
void render_custom(GLCanvas3D& canvas, bool bottom) const;
|
||||
void render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture) const;
|
||||
void render_default(bool bottom) const;
|
||||
void reset();
|
||||
};
|
||||
|
|
|
@ -92,9 +92,8 @@ bool GCodeViewer::IBuffer::init_shader(const std::string& vertex_shader_src, con
|
|||
|
||||
void GCodeViewer::IBuffer::add_path(const GCodeProcessor::MoveVertex& move)
|
||||
{
|
||||
unsigned int id = static_cast<unsigned int>(data.size());
|
||||
double z = static_cast<double>(move.position[2]);
|
||||
paths.push_back({ move.type, move.extrusion_role, id, id, z, z, move.delta_extruder, move.height, move.width, move.feedrate, move.fan_speed, move.volumetric_rate(), move.extruder_id, move.cp_color_id });
|
||||
Path::Endpoint endpoint = { static_cast<unsigned int>(data.size()), static_cast<double>(move.position[2]) };
|
||||
paths.push_back({ move.type, move.extrusion_role, endpoint, endpoint, move.delta_extruder, move.height, move.width, move.feedrate, move.fan_speed, move.volumetric_rate(), move.extruder_id, move.cp_color_id });
|
||||
}
|
||||
|
||||
std::array<float, 3> GCodeViewer::Extrusions::Range::get_color_at(float value) const
|
||||
|
@ -215,6 +214,11 @@ void GCodeViewer::refresh(const GCodeProcessor::Result& gcode_result, const std:
|
|||
}
|
||||
}
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
// update buffers' render paths
|
||||
refresh_render_paths();
|
||||
#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
m_statistics.refresh_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start_time).count();
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
@ -346,6 +350,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
{
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
m_statistics.results_size = SLIC3R_STDVEC_MEMSIZE(gcode_result.moves, GCodeProcessor::MoveVertex);
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
||||
// vertex data
|
||||
|
@ -363,7 +368,8 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
}
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
m_statistics.vertices_size = vertices_data.size() * sizeof(float);
|
||||
m_statistics.vertices_size = SLIC3R_STDVEC_MEMSIZE(vertices_data, float);
|
||||
m_statistics.vertices_gpu_size = vertices_data.size() * sizeof(float);
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
||||
// vertex data -> send to gpu
|
||||
|
@ -408,13 +414,13 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
buffer.data.push_back(static_cast<unsigned int>(i - 1));
|
||||
}
|
||||
|
||||
buffer.paths.back().last = static_cast<unsigned int>(buffer.data.size());
|
||||
buffer.paths.back().last.id = static_cast<unsigned int>(buffer.data.size());
|
||||
buffer.data.push_back(static_cast<unsigned int>(i));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -424,7 +430,8 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
|
|||
{
|
||||
buffer.data_size = buffer.data.size();
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
m_statistics.indices_size += buffer.data_size * sizeof(unsigned int);
|
||||
m_statistics.indices_size += SLIC3R_STDVEC_MEMSIZE(buffer.data, unsigned int);
|
||||
m_statistics.indices_gpu_size += buffer.data_size * sizeof(unsigned int);
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
||||
if (buffer.data_size > 0) {
|
||||
|
@ -526,7 +533,8 @@ void GCodeViewer::load_shells(const Print& print, bool initialized)
|
|||
}
|
||||
}
|
||||
|
||||
void GCodeViewer::render_toolpaths() const
|
||||
#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
void GCodeViewer::refresh_render_paths() const
|
||||
{
|
||||
auto extrusion_color = [this](const Path& path) {
|
||||
std::array<float, 3> color;
|
||||
|
@ -551,6 +559,65 @@ void GCodeViewer::render_toolpaths() const
|
|||
Travel_Colors[0] /* Move */);
|
||||
};
|
||||
|
||||
|
||||
for (IBuffer& buffer : m_buffers) {
|
||||
buffer.render_paths = std::vector<RenderPath>();
|
||||
for (const Path& path : buffer.paths)
|
||||
{
|
||||
if (!is_in_z_range(path))
|
||||
continue;
|
||||
|
||||
if (path.type == GCodeProcessor::EMoveType::Extrude && !is_visible(path))
|
||||
continue;
|
||||
|
||||
std::array<float, 3> color = { 0.0f, 0.0f, 0.0f };
|
||||
switch (path.type)
|
||||
{
|
||||
case GCodeProcessor::EMoveType::Extrude: { color = extrusion_color(path); break; }
|
||||
case GCodeProcessor::EMoveType::Travel: { color = (m_view_type == EViewType::Feedrate || m_view_type == EViewType::Tool || m_view_type == EViewType::ColorPrint) ? extrusion_color(path) : travel_color(path); break; }
|
||||
}
|
||||
|
||||
auto it = std::find_if(buffer.render_paths.begin(), buffer.render_paths.end(), [color](const RenderPath& path) { return path.color == color; });
|
||||
if (it == buffer.render_paths.end())
|
||||
{
|
||||
it = buffer.render_paths.insert(buffer.render_paths.end(), RenderPath());
|
||||
it->color = color;
|
||||
}
|
||||
|
||||
it->sizes.push_back(path.last.id - path.first.id + 1);
|
||||
it->offsets.push_back(static_cast<size_t>(path.first.id * sizeof(unsigned int)));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
|
||||
void GCodeViewer::render_toolpaths() const
|
||||
{
|
||||
#if !ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
auto extrusion_color = [this](const Path& path) {
|
||||
std::array<float, 3> color;
|
||||
switch (m_view_type)
|
||||
{
|
||||
case EViewType::FeatureType: { color = Extrusion_Role_Colors[static_cast<unsigned int>(path.role)]; break; }
|
||||
case EViewType::Height: { color = m_extrusions.ranges.height.get_color_at(path.height); break; }
|
||||
case EViewType::Width: { color = m_extrusions.ranges.width.get_color_at(path.width); break; }
|
||||
case EViewType::Feedrate: { color = m_extrusions.ranges.feedrate.get_color_at(path.feedrate); break; }
|
||||
case EViewType::FanSpeed: { color = m_extrusions.ranges.fan_speed.get_color_at(path.fan_speed); break; }
|
||||
case EViewType::VolumetricRate: { color = m_extrusions.ranges.volumetric_rate.get_color_at(path.volumetric_rate); break; }
|
||||
case EViewType::Tool: { color = m_tool_colors[path.extruder_id]; break; }
|
||||
case EViewType::ColorPrint: { color = m_tool_colors[path.cp_color_id]; break; }
|
||||
default: { color = { 1.0f, 1.0f, 1.0f }; break; }
|
||||
}
|
||||
return color;
|
||||
};
|
||||
|
||||
auto travel_color = [this](const Path& path) {
|
||||
return (path.delta_extruder < 0.0f) ? Travel_Colors[2] /* Retract */ :
|
||||
((path.delta_extruder > 0.0f) ? Travel_Colors[1] /* Extrude */ :
|
||||
Travel_Colors[0] /* Move */);
|
||||
};
|
||||
#endif // !ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
|
||||
auto set_color = [](GLint current_program_id, const std::array<float, 3>& color) {
|
||||
if (current_program_id > 0) {
|
||||
GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1;
|
||||
|
@ -601,7 +668,7 @@ void GCodeViewer::render_toolpaths() const
|
|||
continue;
|
||||
|
||||
glsafe(::glEnable(GL_PROGRAM_POINT_SIZE));
|
||||
glsafe(::glDrawElements(GL_POINTS, GLsizei(path.last - path.first + 1), GL_UNSIGNED_INT, (const void*)(path.first * sizeof(GLuint))));
|
||||
glsafe(::glDrawElements(GL_POINTS, GLsizei(path.last.id - path.first.id + 1), GL_UNSIGNED_INT, (const void*)(path.first.id * sizeof(GLuint))));
|
||||
glsafe(::glDisable(GL_PROGRAM_POINT_SIZE));
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
@ -619,7 +686,7 @@ void GCodeViewer::render_toolpaths() const
|
|||
continue;
|
||||
|
||||
glsafe(::glEnable(GL_PROGRAM_POINT_SIZE));
|
||||
glsafe(::glDrawElements(GL_POINTS, GLsizei(path.last - path.first + 1), GL_UNSIGNED_INT, (const void*)(path.first * sizeof(GLuint))));
|
||||
glsafe(::glDrawElements(GL_POINTS, GLsizei(path.last.id - path.first.id + 1), GL_UNSIGNED_INT, (const void*)(path.first.id * sizeof(GLuint))));
|
||||
glsafe(::glDisable(GL_PROGRAM_POINT_SIZE));
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
@ -637,7 +704,7 @@ void GCodeViewer::render_toolpaths() const
|
|||
continue;
|
||||
|
||||
glsafe(::glEnable(GL_PROGRAM_POINT_SIZE));
|
||||
glsafe(::glDrawElements(GL_POINTS, GLsizei(path.last - path.first + 1), GL_UNSIGNED_INT, (const void*)(path.first * sizeof(GLuint))));
|
||||
glsafe(::glDrawElements(GL_POINTS, GLsizei(path.last.id - path.first.id + 1), GL_UNSIGNED_INT, (const void*)(path.first.id * sizeof(GLuint))));
|
||||
glsafe(::glDisable(GL_PROGRAM_POINT_SIZE));
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
@ -655,7 +722,7 @@ void GCodeViewer::render_toolpaths() const
|
|||
continue;
|
||||
|
||||
glsafe(::glEnable(GL_PROGRAM_POINT_SIZE));
|
||||
glsafe(::glDrawElements(GL_POINTS, GLsizei(path.last - path.first + 1), GL_UNSIGNED_INT, (const void*)(path.first * sizeof(GLuint))));
|
||||
glsafe(::glDrawElements(GL_POINTS, GLsizei(path.last.id - path.first.id + 1), GL_UNSIGNED_INT, (const void*)(path.first.id * sizeof(GLuint))));
|
||||
glsafe(::glDisable(GL_PROGRAM_POINT_SIZE));
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
@ -673,7 +740,7 @@ void GCodeViewer::render_toolpaths() const
|
|||
continue;
|
||||
|
||||
glsafe(::glEnable(GL_PROGRAM_POINT_SIZE));
|
||||
glsafe(::glDrawElements(GL_POINTS, GLsizei(path.last - path.first + 1), GL_UNSIGNED_INT, (const void*)(path.first * sizeof(GLuint))));
|
||||
glsafe(::glDrawElements(GL_POINTS, GLsizei(path.last.id - path.first.id + 1), GL_UNSIGNED_INT, (const void*)(path.first.id * sizeof(GLuint))));
|
||||
glsafe(::glDisable(GL_PROGRAM_POINT_SIZE));
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
@ -691,7 +758,7 @@ void GCodeViewer::render_toolpaths() const
|
|||
continue;
|
||||
|
||||
glsafe(::glEnable(GL_PROGRAM_POINT_SIZE));
|
||||
glsafe(::glDrawElements(GL_POINTS, GLsizei(path.last - path.first + 1), GL_UNSIGNED_INT, (const void*)(path.first * sizeof(GLuint))));
|
||||
glsafe(::glDrawElements(GL_POINTS, GLsizei(path.last.id - path.first.id + 1), GL_UNSIGNED_INT, (const void*)(path.first.id * sizeof(GLuint))));
|
||||
glsafe(::glDisable(GL_PROGRAM_POINT_SIZE));
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
@ -702,32 +769,56 @@ void GCodeViewer::render_toolpaths() const
|
|||
}
|
||||
case GCodeProcessor::EMoveType::Extrude:
|
||||
{
|
||||
#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
for (const RenderPath& path : buffer.render_paths)
|
||||
{
|
||||
set_color(current_program_id, path.color);
|
||||
glsafe(::glMultiDrawElements(GL_LINE_STRIP, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_INT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
++m_statistics.gl_multi_line_strip_calls_count;
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
||||
}
|
||||
#else
|
||||
for (const Path& path : buffer.paths) {
|
||||
if (!is_visible(path) || !is_in_z_range(path))
|
||||
continue;
|
||||
|
||||
set_color(current_program_id, extrusion_color(path));
|
||||
glsafe(::glDrawElements(GL_LINE_STRIP, GLsizei(path.last - path.first + 1), GL_UNSIGNED_INT, (const void*)(path.first * sizeof(GLuint))));
|
||||
glsafe(::glDrawElements(GL_LINE_STRIP, GLsizei(path.last.id - path.first.id + 1), GL_UNSIGNED_INT, (const void*)(path.first.id * sizeof(GLuint))));
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
++m_statistics.gl_line_strip_calls_count;
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
break;
|
||||
}
|
||||
case GCodeProcessor::EMoveType::Travel:
|
||||
{
|
||||
#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
for (const RenderPath& path : buffer.render_paths)
|
||||
{
|
||||
set_color(current_program_id, path.color);
|
||||
glsafe(::glMultiDrawElements(GL_LINE_STRIP, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_INT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
++m_statistics.gl_multi_line_strip_calls_count;
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
||||
}
|
||||
#else
|
||||
for (const Path& path : buffer.paths) {
|
||||
if (!is_in_z_range(path))
|
||||
continue;
|
||||
|
||||
set_color(current_program_id, (m_view_type == EViewType::Feedrate || m_view_type == EViewType::Tool || m_view_type == EViewType::ColorPrint) ? extrusion_color(path) : travel_color(path));
|
||||
glsafe(::glDrawElements(GL_LINE_STRIP, GLsizei(path.last - path.first + 1), GL_UNSIGNED_INT, (const void*)(path.first * sizeof(GLuint))));
|
||||
glsafe(::glDrawElements(GL_LINE_STRIP, GLsizei(path.last.id - path.first.id + 1), GL_UNSIGNED_INT, (const void*)(path.first.id * sizeof(GLuint))));
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
++m_statistics.gl_line_strip_calls_count;
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -840,6 +931,10 @@ void GCodeViewer::render_legend() const
|
|||
if (role < erCount)
|
||||
{
|
||||
m_extrusions.role_visibility_flags = is_visible(role) ? m_extrusions.role_visibility_flags & ~(1 << role) : m_extrusions.role_visibility_flags | (1 << role);
|
||||
#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
// update buffers' render paths
|
||||
refresh_render_paths();
|
||||
#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
wxGetApp().plater()->get_current_canvas3D()->set_as_dirty();
|
||||
wxGetApp().plater()->update_preview_bottom_toolbar();
|
||||
}
|
||||
|
@ -986,7 +1081,7 @@ void GCodeViewer::render_statistics() const
|
|||
static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f);
|
||||
static const float offset = 250.0f;
|
||||
|
||||
if (!m_legend_enabled || m_roles.empty())
|
||||
if (m_roles.empty())
|
||||
return;
|
||||
|
||||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||
|
@ -1020,20 +1115,52 @@ void GCodeViewer::render_statistics() const
|
|||
ImGui::SameLine(offset);
|
||||
imgui.text(std::to_string(m_statistics.gl_line_strip_calls_count));
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
|
||||
imgui.text(std::string("Multi GL_POINTS calls:"));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine(offset);
|
||||
imgui.text(std::to_string(m_statistics.gl_multi_points_calls_count));
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
|
||||
imgui.text(std::string("Multi GL_LINE_STRIP calls:"));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine(offset);
|
||||
imgui.text(std::to_string(m_statistics.gl_multi_line_strip_calls_count));
|
||||
#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
|
||||
imgui.text(std::string("Vertices:"));
|
||||
imgui.text(std::string("Results:"));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine(offset);
|
||||
imgui.text(std::to_string(m_statistics.results_size) + " bytes");
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
|
||||
imgui.text(std::string("Vertices CPU:"));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine(offset);
|
||||
imgui.text(std::to_string(m_statistics.vertices_size) + " bytes");
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
|
||||
imgui.text(std::string("Indices:"));
|
||||
imgui.text(std::string("Vertices GPU:"));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine(offset);
|
||||
imgui.text(std::to_string(m_statistics.vertices_gpu_size) + " bytes");
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
|
||||
imgui.text(std::string("Indices CPU:"));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine(offset);
|
||||
imgui.text(std::to_string(m_statistics.indices_size) + " bytes");
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
|
||||
imgui.text(std::string("Indices GPU:"));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine(offset);
|
||||
imgui.text(std::to_string(m_statistics.indices_gpu_size) + " bytes");
|
||||
|
||||
imgui.end();
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
|
|
@ -35,12 +35,16 @@ class GCodeViewer
|
|||
// Used to identify different toolpath sub-types inside a IBuffer
|
||||
struct Path
|
||||
{
|
||||
struct Endpoint
|
||||
{
|
||||
unsigned int id{ 0u };
|
||||
double z{ 0.0 };
|
||||
};
|
||||
|
||||
GCodeProcessor::EMoveType type{ GCodeProcessor::EMoveType::Noop };
|
||||
ExtrusionRole role{ erNone };
|
||||
unsigned int first{ 0 };
|
||||
unsigned int last{ 0 };
|
||||
double first_z{ 0.0f };
|
||||
double last_z{ 0.0f };
|
||||
Endpoint first;
|
||||
Endpoint last;
|
||||
float delta_extruder{ 0.0f };
|
||||
float height{ 0.0f };
|
||||
float width{ 0.0f };
|
||||
|
@ -57,6 +61,16 @@ class GCodeViewer
|
|||
}
|
||||
};
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
// Used to batch the indices needed to render paths
|
||||
struct RenderPath
|
||||
{
|
||||
std::array<float, 3> color;
|
||||
std::vector<unsigned int> sizes;
|
||||
std::vector<size_t> offsets; // use size_t because we need the pointer's size (used in the call glMultiDrawElements())
|
||||
};
|
||||
#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
|
||||
// buffer containing indices data and shader for a specific toolpath type
|
||||
struct IBuffer
|
||||
{
|
||||
|
@ -65,6 +79,9 @@ class GCodeViewer
|
|||
std::vector<unsigned int> data;
|
||||
size_t data_size{ 0 };
|
||||
std::vector<Path> paths;
|
||||
#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
std::vector<RenderPath> render_paths;
|
||||
#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
bool visible{ false };
|
||||
|
||||
void reset();
|
||||
|
@ -139,8 +156,15 @@ class GCodeViewer
|
|||
long long refresh_time{ 0 };
|
||||
long long gl_points_calls_count{ 0 };
|
||||
long long gl_line_strip_calls_count{ 0 };
|
||||
#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
long long gl_multi_points_calls_count{ 0 };
|
||||
long long gl_multi_line_strip_calls_count{ 0 };
|
||||
#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
long long results_size{ 0 };
|
||||
long long vertices_size{ 0 };
|
||||
long long vertices_gpu_size{ 0 };
|
||||
long long indices_size{ 0 };
|
||||
long long indices_gpu_size{ 0 };
|
||||
|
||||
void reset_all() {
|
||||
reset_times();
|
||||
|
@ -156,11 +180,18 @@ class GCodeViewer
|
|||
void reset_opengl() {
|
||||
gl_points_calls_count = 0;
|
||||
gl_line_strip_calls_count = 0;
|
||||
#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
gl_multi_points_calls_count = 0;
|
||||
gl_multi_line_strip_calls_count = 0;
|
||||
#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
}
|
||||
|
||||
void reset_sizes() {
|
||||
results_size = 0;
|
||||
vertices_size = 0;
|
||||
vertices_gpu_size = 0;
|
||||
indices_size = 0;
|
||||
indices_gpu_size = 0;
|
||||
}
|
||||
};
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
@ -240,6 +271,9 @@ private:
|
|||
bool init_shaders();
|
||||
void load_toolpaths(const GCodeProcessor::Result& gcode_result);
|
||||
void load_shells(const Print& print, bool initialized);
|
||||
#if ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
void refresh_render_paths() const;
|
||||
#endif // ENABLE_GCODE_VIEWER_GL_OPTIMIZATION
|
||||
void render_toolpaths() const;
|
||||
void render_shells() const;
|
||||
void render_legend() const;
|
||||
|
@ -255,7 +289,7 @@ private:
|
|||
return z > m_layers_z_range[0] - EPSILON && z < m_layers_z_range[1] + EPSILON;
|
||||
};
|
||||
|
||||
return in_z_range(path.first_z) || in_z_range(path.last_z);
|
||||
return in_z_range(path.first.z) || in_z_range(path.last.z);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -5459,14 +5459,19 @@ void GLCanvas3D::_render_background() const
|
|||
glsafe(::glPopMatrix());
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_bed(float theta, bool show_axes) const
|
||||
void GLCanvas3D::_render_bed(bool bottom, bool show_axes) const
|
||||
{
|
||||
float scale_factor = 1.0;
|
||||
#if ENABLE_RETINA_GL
|
||||
scale_factor = m_retina_helper->get_scale_factor();
|
||||
#endif // ENABLE_RETINA_GL
|
||||
|
||||
bool show_texture = ! bottom ||
|
||||
(m_gizmos.get_current_type() != GLGizmosManager::FdmSupports
|
||||
&& m_gizmos.get_current_type() != GLGizmosManager::SlaSupports);
|
||||
|
||||
#if ENABLE_NON_STATIC_CANVAS_MANAGER
|
||||
wxGetApp().plater()->get_bed().render(const_cast<GLCanvas3D&>(*this), theta, scale_factor, show_axes);
|
||||
wxGetApp().plater()->get_bed().render(const_cast<GLCanvas3D&>(*this), bottom, scale_factor, show_axes, show_texture);
|
||||
#else
|
||||
m_bed.render(const_cast<GLCanvas3D&>(*this), theta, scale_factor, show_axes);
|
||||
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
|
||||
|
|
|
@ -795,7 +795,7 @@ private:
|
|||
void _picking_pass() const;
|
||||
void _rectangular_selection_picking_pass() const;
|
||||
void _render_background() const;
|
||||
void _render_bed(float theta, bool show_axes) const;
|
||||
void _render_bed(bool bottom, bool show_axes) const;
|
||||
void _render_objects() const;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
void _render_gcode() const;
|
||||
|
|
|
@ -314,7 +314,7 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
|
|||
m_label_show = new wxStaticText(this, wxID_ANY, _(L("Show")));
|
||||
|
||||
m_combochecklist_features = new wxComboCtrl();
|
||||
m_combochecklist_features->Create(this, wxID_ANY, _(L("Feature types")), wxDefaultPosition, wxSize(15 * wxGetApp().em_unit(), -1), wxCB_READONLY);
|
||||
m_combochecklist_features->Create(this, wxID_ANY, _(L("Feature types")), wxDefaultPosition, wxDefaultSize, wxCB_READONLY);
|
||||
std::string feature_items = GUI::into_u8(
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
_L("Unknown") + "|1|" +
|
||||
|
@ -337,7 +337,7 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
|
|||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_combochecklist_options = new wxComboCtrl();
|
||||
m_combochecklist_options->Create(this, wxID_ANY, _(L("Others")), wxDefaultPosition, wxSize(15 * wxGetApp().em_unit(), -1), wxCB_READONLY);
|
||||
m_combochecklist_options->Create(this, wxID_ANY, _(L("Options")), wxDefaultPosition, wxDefaultSize, wxCB_READONLY);
|
||||
std::string options_items = GUI::into_u8(
|
||||
_(L("Travel")) + "|0|" +
|
||||
_(L("Retractions")) + "|0|" +
|
||||
|
@ -349,7 +349,7 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
|
|||
_(L("Shells")) + "|0|" +
|
||||
_(L("Legend")) + "|1"
|
||||
);
|
||||
Slic3r::GUI::create_combochecklist(m_combochecklist_options, GUI::into_u8(_(L("Others"))), options_items);
|
||||
Slic3r::GUI::create_combochecklist(m_combochecklist_options, GUI::into_u8(_(L("Options"))), options_items);
|
||||
#else
|
||||
m_checkbox_travel = new wxCheckBox(this, wxID_ANY, _(L("Travel")));
|
||||
m_checkbox_retractions = new wxCheckBox(this, wxID_ANY, _(L("Retractions")));
|
||||
|
@ -605,15 +605,11 @@ void Preview::show_hide_ui_elements(const std::string& what)
|
|||
bool enable = (what == "full");
|
||||
m_label_show->Enable(enable);
|
||||
m_combochecklist_features->Enable(enable);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_combochecklist_options->Enable(enable);
|
||||
#else
|
||||
m_checkbox_travel->Enable(enable);
|
||||
m_checkbox_retractions->Enable(enable);
|
||||
m_checkbox_unretractions->Enable(enable);
|
||||
m_checkbox_shells->Enable(enable);
|
||||
m_checkbox_legend->Enable(enable);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
enable = (what != "none");
|
||||
m_label_view_type->Enable(enable);
|
||||
|
@ -622,15 +618,11 @@ void Preview::show_hide_ui_elements(const std::string& what)
|
|||
bool visible = (what != "none");
|
||||
m_label_show->Show(visible);
|
||||
m_combochecklist_features->Show(visible);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_combochecklist_options->Show(visible);
|
||||
#else
|
||||
m_checkbox_travel->Show(visible);
|
||||
m_checkbox_retractions->Show(visible);
|
||||
m_checkbox_unretractions->Show(visible);
|
||||
m_checkbox_shells->Show(visible);
|
||||
m_checkbox_legend->Show(visible);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
m_label_view_type->Show(visible);
|
||||
m_choice_view_type->Show(visible);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/PresetBundle.hpp"
|
||||
#include "slic3r/GUI/Camera.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
|
||||
|
||||
|
@ -45,6 +46,7 @@ bool GLGizmoFdmSupports::on_init()
|
|||
m_desc["block"] = _L("Block supports");
|
||||
m_desc["remove_caption"] = _L("Shift + Left mouse button") + ": ";
|
||||
m_desc["remove"] = _L("Remove selection");
|
||||
m_desc["remove_all"] = _L("Remove all");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -191,7 +193,16 @@ void GLGizmoFdmSupports::update_mesh()
|
|||
// This mesh does not account for the possible Z up SLA offset.
|
||||
const TriangleMesh* mesh = &mv->mesh();
|
||||
|
||||
m_selected_facets[volume_id].assign(mesh->its.indices.size(), SelType::NONE);
|
||||
m_selected_facets[volume_id].assign(mesh->its.indices.size(), FacetSupportType::NONE);
|
||||
|
||||
// Load current state from ModelVolume.
|
||||
for (FacetSupportType type : {FacetSupportType::ENFORCER, FacetSupportType::BLOCKER}) {
|
||||
const std::vector<int>& list = mv->m_supported_facets.get_facets(type);
|
||||
for (int i : list)
|
||||
m_selected_facets[volume_id][i] = type;
|
||||
}
|
||||
update_vertex_buffers(mv, volume_id, true, true);
|
||||
|
||||
m_neighbors[volume_id].resize(3 * mesh->its.indices.size());
|
||||
|
||||
// Prepare vector of vertex_index - facet_index pairs to quickly find adjacent facets
|
||||
|
@ -247,16 +258,16 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
|| action == SLAGizmoEventType::RightDown
|
||||
|| (action == SLAGizmoEventType::Dragging && m_button_down != Button::None)) {
|
||||
|
||||
SelType new_state = SelType::NONE;
|
||||
FacetSupportType new_state = FacetSupportType::NONE;
|
||||
if (! shift_down) {
|
||||
if (action == SLAGizmoEventType::Dragging)
|
||||
new_state = m_button_down == Button::Left
|
||||
? SelType::ENFORCER
|
||||
: SelType::BLOCKER;
|
||||
? FacetSupportType::ENFORCER
|
||||
: FacetSupportType::BLOCKER;
|
||||
else
|
||||
new_state = action == SLAGizmoEventType::LeftDown
|
||||
? SelType::ENFORCER
|
||||
: SelType::BLOCKER;
|
||||
? FacetSupportType::ENFORCER
|
||||
: FacetSupportType::BLOCKER;
|
||||
}
|
||||
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
|
@ -383,9 +394,9 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
|
||||
// Now just select all facets that passed.
|
||||
for (size_t next_facet : facets_to_select) {
|
||||
SelType& facet = m_selected_facets[mesh_id][next_facet];
|
||||
FacetSupportType& facet = m_selected_facets[mesh_id][next_facet];
|
||||
|
||||
if (facet != new_state && facet != SelType::NONE) {
|
||||
if (facet != new_state && facet != FacetSupportType::NONE) {
|
||||
// this triangle is currently in the other VBA.
|
||||
// Both VBAs need to be refreshed.
|
||||
update_both = true;
|
||||
|
@ -395,8 +406,8 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
}
|
||||
|
||||
update_vertex_buffers(mv, mesh_id,
|
||||
new_state == SelType::ENFORCER || update_both,
|
||||
new_state == SelType::BLOCKER || update_both
|
||||
new_state == FacetSupportType::ENFORCER || update_both,
|
||||
new_state == FacetSupportType::BLOCKER || update_both
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -420,6 +431,18 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::RightUp)
|
||||
&& m_button_down != Button::None) {
|
||||
m_button_down = Button::None;
|
||||
|
||||
// Synchronize gizmo with ModelVolume data.
|
||||
ModelObject* mo = m_c->selection_info()->model_object();
|
||||
int idx = -1;
|
||||
for (ModelVolume* mv : mo->volumes) {
|
||||
++idx;
|
||||
if (! mv->is_model_part())
|
||||
continue;
|
||||
for (int i=0; i<int(m_selected_facets[idx].size()); ++i)
|
||||
mv->m_supported_facets.set_facet(i, m_selected_facets[idx][i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -434,16 +457,16 @@ void GLGizmoFdmSupports::update_vertex_buffers(const ModelVolume* mv,
|
|||
{
|
||||
const TriangleMesh* mesh = &mv->mesh();
|
||||
|
||||
for (SelType type : {SelType::ENFORCER, SelType::BLOCKER}) {
|
||||
if ((type == SelType::ENFORCER && ! update_enforcers)
|
||||
|| (type == SelType::BLOCKER && ! update_blockers))
|
||||
for (FacetSupportType type : {FacetSupportType::ENFORCER, FacetSupportType::BLOCKER}) {
|
||||
if ((type == FacetSupportType::ENFORCER && ! update_enforcers)
|
||||
|| (type == FacetSupportType::BLOCKER && ! update_blockers))
|
||||
continue;
|
||||
|
||||
GLIndexedVertexArray& iva = m_ivas[mesh_id][type==SelType::ENFORCER ? 0 : 1];
|
||||
GLIndexedVertexArray& iva = m_ivas[mesh_id][type==FacetSupportType::ENFORCER ? 0 : 1];
|
||||
iva.release_geometry();
|
||||
size_t triangle_cnt=0;
|
||||
for (size_t facet_idx=0; facet_idx<m_selected_facets[mesh_id].size(); ++facet_idx) {
|
||||
SelType status = m_selected_facets[mesh_id][facet_idx];
|
||||
FacetSupportType status = m_selected_facets[mesh_id][facet_idx];
|
||||
if (status != type)
|
||||
continue;
|
||||
for (int i=0; i<3; ++i)
|
||||
|
@ -471,6 +494,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
|||
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
|
||||
const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f);
|
||||
const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f);
|
||||
const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f);
|
||||
const float minimal_slider_width = m_imgui->scaled(4.f);
|
||||
|
||||
float caption_max = 0.f;
|
||||
|
@ -484,6 +508,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
|||
|
||||
float window_width = minimal_slider_width + std::max(cursor_slider_left, clipping_slider_left);
|
||||
window_width = std::max(window_width, total_text_max);
|
||||
window_width = std::max(window_width, button_width);
|
||||
|
||||
auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) {
|
||||
static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f);
|
||||
|
@ -499,6 +524,20 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
|||
|
||||
m_imgui->text("");
|
||||
|
||||
if (m_imgui->button(m_desc.at("remove_all"))) {
|
||||
ModelObject* mo = m_c->selection_info()->model_object();
|
||||
int idx = -1;
|
||||
for (ModelVolume* mv : mo->volumes) {
|
||||
++idx;
|
||||
if (mv->is_model_part()) {
|
||||
m_selected_facets[idx].assign(m_selected_facets[idx].size(), FacetSupportType::NONE);
|
||||
mv->m_supported_facets.clear();
|
||||
update_vertex_buffers(mv, idx, true, true);
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
|
||||
|
||||
m_imgui->text(m_desc.at("cursor_size"));
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
enum class FacetSupportType : int8_t;
|
||||
|
||||
namespace GUI {
|
||||
|
||||
enum class SLAGizmoEventType : unsigned char;
|
||||
|
@ -26,15 +29,9 @@ private:
|
|||
static constexpr float CursorRadiusMax = 8.f;
|
||||
static constexpr float CursorRadiusStep = 0.2f;
|
||||
|
||||
enum class SelType : int8_t {
|
||||
NONE,
|
||||
ENFORCER,
|
||||
BLOCKER
|
||||
};
|
||||
|
||||
// For each model-part volume, store a list of statuses of
|
||||
// individual facets (one of the enum values above).
|
||||
std::vector<std::vector<SelType>> m_selected_facets;
|
||||
std::vector<std::vector<FacetSupportType>> m_selected_facets;
|
||||
|
||||
// Store two vertex buffer arrays (for enforcers/blockers)
|
||||
// for each model-part volume.
|
||||
|
|
Loading…
Reference in a new issue