Merge branch 'master' into fix-assertions
This commit is contained in:
commit
1ed7895f61
@ -34,6 +34,8 @@ option(SLIC3R_PERL_XS "Compile XS Perl module and enable Perl unit and
|
|||||||
option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
|
option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
|
||||||
option(SLIC3R_SYNTAXONLY "Only perform source code correctness checking, no binary output (UNIX only)" 0)
|
option(SLIC3R_SYNTAXONLY "Only perform source code correctness checking, no binary output (UNIX only)" 0)
|
||||||
|
|
||||||
|
set(SLIC3R_GTK "2" CACHE STRING "GTK version to use with wxWidgets on Linux")
|
||||||
|
|
||||||
# Proposal for C++ unit tests and sandboxes
|
# Proposal for C++ unit tests and sandboxes
|
||||||
option(SLIC3R_BUILD_SANDBOXES "Build development sandboxes" OFF)
|
option(SLIC3R_BUILD_SANDBOXES "Build development sandboxes" OFF)
|
||||||
option(SLIC3R_BUILD_TESTS "Build unit tests" OFF)
|
option(SLIC3R_BUILD_TESTS "Build unit tests" OFF)
|
||||||
|
@ -91,6 +91,10 @@ You can also use the Visual Studio GUI or other generators as mentioned above.
|
|||||||
The `DESTDIR` option is the location where the bundle will be installed.
|
The `DESTDIR` option is the location where the bundle will be installed.
|
||||||
This may be customized. If you leave it empty, the `DESTDIR` will be places inside the same `build` directory.
|
This may be customized. If you leave it empty, the `DESTDIR` will be places inside the same `build` directory.
|
||||||
|
|
||||||
|
Warning: If the `build` directory is nested too deep inside other folders, various file paths during the build
|
||||||
|
become too long and the build might fail due to file writing errors. For this reason, it is recommended to
|
||||||
|
place the `build` directory relatively close to the drive root.
|
||||||
|
|
||||||
Note that the build variant that you may choose using Visual Studio (i.e. _Release_ or _Debug_ etc.) when building the dependency package is **not relevant**.
|
Note that the build variant that you may choose using Visual Studio (i.e. _Release_ or _Debug_ etc.) when building the dependency package is **not relevant**.
|
||||||
The dependency build will by default build _both_ the _Release_ and _Debug_ variants regardless of what you choose in Visual Studio.
|
The dependency build will by default build _both_ the _Release_ and _Debug_ variants regardless of what you choose in Visual Studio.
|
||||||
You can disable building of the debug variant by passing the `-DDEP_DEBUG=OFF` option to CMake, this will only produce a _Release_ build.
|
You can disable building of the debug variant by passing the `-DDEP_DEBUG=OFF` option to CMake, this will only produce a _Release_ build.
|
||||||
|
@ -60,6 +60,7 @@ if (SLIC3R_GUI)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
set (wxWidgets_CONFIG_OPTIONS "--toolkit=gtk${SLIC3R_GTK}")
|
||||||
if (SLIC3R_WX_STABLE)
|
if (SLIC3R_WX_STABLE)
|
||||||
find_package(wxWidgets 3.0 REQUIRED COMPONENTS base core adv html gl)
|
find_package(wxWidgets 3.0 REQUIRED COMPONENTS base core adv html gl)
|
||||||
else ()
|
else ()
|
||||||
|
@ -175,6 +175,11 @@ struct AMFParserContext
|
|||||||
bool mirrory_set;
|
bool mirrory_set;
|
||||||
float mirrorz;
|
float mirrorz;
|
||||||
bool mirrorz_set;
|
bool mirrorz_set;
|
||||||
|
|
||||||
|
bool anything_set() const { return deltax_set || deltay_set || deltaz_set ||
|
||||||
|
rx_set || ry_set || rz_set ||
|
||||||
|
scalex_set || scaley_set || scalez_set ||
|
||||||
|
mirrorx_set || mirrory_set || mirrorz_set; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Object {
|
struct Object {
|
||||||
@ -644,11 +649,7 @@ void AMFParserContext::endDocument()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (const Instance &instance : object.second.instances)
|
for (const Instance &instance : object.second.instances)
|
||||||
#if ENABLE_VOLUMES_CENTERING_FIXES
|
if (instance.anything_set()) {
|
||||||
{
|
|
||||||
#else
|
|
||||||
if (instance.deltax_set && instance.deltay_set) {
|
|
||||||
#endif // ENABLE_VOLUMES_CENTERING_FIXES
|
|
||||||
ModelInstance *mi = m_model.objects[object.second.idx]->add_instance();
|
ModelInstance *mi = m_model.objects[object.second.idx]->add_instance();
|
||||||
mi->set_offset(Vec3d(instance.deltax_set ? (double)instance.deltax : 0.0, instance.deltay_set ? (double)instance.deltay : 0.0, instance.deltaz_set ? (double)instance.deltaz : 0.0));
|
mi->set_offset(Vec3d(instance.deltax_set ? (double)instance.deltax : 0.0, instance.deltay_set ? (double)instance.deltay : 0.0, instance.deltaz_set ? (double)instance.deltaz : 0.0));
|
||||||
mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0));
|
mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0));
|
||||||
|
@ -56,6 +56,113 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class Vector,
|
||||||
|
class Value = typename Vector::value_type>
|
||||||
|
class IndexBasedIterator {
|
||||||
|
static const size_t NONE = size_t(-1);
|
||||||
|
|
||||||
|
std::reference_wrapper<Vector> m_index_ref;
|
||||||
|
size_t m_idx = NONE;
|
||||||
|
public:
|
||||||
|
|
||||||
|
using value_type = Value;
|
||||||
|
using pointer = Value *;
|
||||||
|
using reference = Value &;
|
||||||
|
using difference_type = long;
|
||||||
|
using iterator_category = std::random_access_iterator_tag;
|
||||||
|
|
||||||
|
inline explicit
|
||||||
|
IndexBasedIterator(Vector& index, size_t idx):
|
||||||
|
m_index_ref(index), m_idx(idx) {}
|
||||||
|
|
||||||
|
// Post increment
|
||||||
|
inline IndexBasedIterator operator++(int) {
|
||||||
|
IndexBasedIterator cpy(*this); ++m_idx; return cpy;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IndexBasedIterator operator--(int) {
|
||||||
|
IndexBasedIterator cpy(*this); --m_idx; return cpy;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IndexBasedIterator& operator++() {
|
||||||
|
++m_idx; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IndexBasedIterator& operator--() {
|
||||||
|
--m_idx; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IndexBasedIterator& operator+=(difference_type l) {
|
||||||
|
m_idx += size_t(l); return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IndexBasedIterator operator+(difference_type l) {
|
||||||
|
auto cpy = *this; cpy += l; return cpy;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IndexBasedIterator& operator-=(difference_type l) {
|
||||||
|
m_idx -= size_t(l); return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IndexBasedIterator operator-(difference_type l) {
|
||||||
|
auto cpy = *this; cpy -= l; return cpy;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator difference_type() { return difference_type(m_idx); }
|
||||||
|
|
||||||
|
inline bool is_end() const { return m_idx >= m_index_ref.get().size();}
|
||||||
|
|
||||||
|
inline Value & operator*() const {
|
||||||
|
assert(m_idx < m_index_ref.get().size());
|
||||||
|
return m_index_ref.get().operator[](m_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Value * operator->() const {
|
||||||
|
assert(m_idx < m_index_ref.get().size());
|
||||||
|
return &m_index_ref.get().operator[](m_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator ==(const IndexBasedIterator& other) {
|
||||||
|
size_t e = m_index_ref.get().size();
|
||||||
|
return m_idx == other.m_idx || (m_idx >= e && other.m_idx >= e);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator !=(const IndexBasedIterator& other) {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator <=(const IndexBasedIterator& other) {
|
||||||
|
return (m_idx < other.m_idx) || (*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator <(const IndexBasedIterator& other) {
|
||||||
|
return m_idx < other.m_idx && (*this != other);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator >=(const IndexBasedIterator& other) {
|
||||||
|
return m_idx > other.m_idx || *this == other;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator >(const IndexBasedIterator& other) {
|
||||||
|
return m_idx > other.m_idx && *this != other;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class It> class Range {
|
||||||
|
It from, to;
|
||||||
|
public:
|
||||||
|
It begin() const { return from; }
|
||||||
|
It end() const { return to; }
|
||||||
|
using Type = It;
|
||||||
|
|
||||||
|
Range() = default;
|
||||||
|
Range(It &&b, It &&e):
|
||||||
|
from(std::forward<It>(b)), to(std::forward<It>(e)) {}
|
||||||
|
|
||||||
|
inline size_t size() const { return end() - begin(); }
|
||||||
|
inline bool empty() const { return size() == 0; }
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // MTUTILS_HPP
|
#endif // MTUTILS_HPP
|
||||||
|
@ -2240,6 +2240,18 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SlicedSupports SLASupportTree::slice(const std::vector<float> &heights,
|
||||||
|
float cr) const
|
||||||
|
{
|
||||||
|
TriangleMesh fullmesh = m_impl->merged_mesh();
|
||||||
|
fullmesh.merge(get_pad());
|
||||||
|
TriangleMeshSlicer slicer(&fullmesh);
|
||||||
|
SlicedSupports ret;
|
||||||
|
slicer.slice(heights, cr, &ret, get().ctl().cancelfn);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
const TriangleMesh &SLASupportTree::add_pad(const SliceLayer& baseplate,
|
const TriangleMesh &SLASupportTree::add_pad(const SliceLayer& baseplate,
|
||||||
const PoolConfig& pcfg) const
|
const PoolConfig& pcfg) const
|
||||||
{
|
{
|
||||||
|
@ -181,6 +181,8 @@ public:
|
|||||||
/// Get the sliced 2d layers of the support geometry.
|
/// Get the sliced 2d layers of the support geometry.
|
||||||
SlicedSupports slice(float layerh, float init_layerh = -1.0) const;
|
SlicedSupports slice(float layerh, float init_layerh = -1.0) const;
|
||||||
|
|
||||||
|
SlicedSupports slice(const std::vector<float>&, float closing_radius) const;
|
||||||
|
|
||||||
/// Adding the "pad" (base pool) under the supports
|
/// Adding the "pad" (base pool) under the supports
|
||||||
const TriangleMesh& add_pad(const SliceLayer& baseplate,
|
const TriangleMesh& add_pad(const SliceLayer& baseplate,
|
||||||
const PoolConfig& pcfg) const;
|
const PoolConfig& pcfg) const;
|
||||||
|
@ -30,7 +30,6 @@ public:
|
|||||||
std::vector<sla::SupportPoint> support_points; // all the support points (manual/auto)
|
std::vector<sla::SupportPoint> support_points; // all the support points (manual/auto)
|
||||||
SupportTreePtr support_tree_ptr; // the supports
|
SupportTreePtr support_tree_ptr; // the supports
|
||||||
SlicedSupports support_slices; // sliced supports
|
SlicedSupports support_slices; // sliced supports
|
||||||
std::vector<LevelID> level_ids;
|
|
||||||
|
|
||||||
inline SupportData(const TriangleMesh& trmesh): emesh(trmesh) {}
|
inline SupportData(const TriangleMesh& trmesh): emesh(trmesh) {}
|
||||||
};
|
};
|
||||||
@ -567,6 +566,18 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) {
|
|||||||
return scfg;
|
return scfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sla::PoolConfig make_pool_config(const SLAPrintObjectConfig& c) {
|
||||||
|
sla::PoolConfig pcfg;
|
||||||
|
|
||||||
|
pcfg.min_wall_thickness_mm = c.pad_wall_thickness.getFloat();
|
||||||
|
pcfg.wall_slope = c.pad_wall_slope.getFloat();
|
||||||
|
pcfg.edge_radius_mm = c.pad_edge_radius.getFloat();
|
||||||
|
pcfg.max_merge_distance_mm = c.pad_max_merge_distance.getFloat();
|
||||||
|
pcfg.min_wall_height_mm = c.pad_wall_height.getFloat();
|
||||||
|
|
||||||
|
return pcfg;
|
||||||
|
}
|
||||||
|
|
||||||
void swapXY(ExPolygon& expoly) {
|
void swapXY(ExPolygon& expoly) {
|
||||||
for(auto& p : expoly.contour.points) std::swap(p(X), p(Y));
|
for(auto& p : expoly.contour.points) std::swap(p(X), p(Y));
|
||||||
for(auto& h : expoly.holes) for(auto& p : h.points) std::swap(p(X), p(Y));
|
for(auto& h : expoly.holes) for(auto& p : h.points) std::swap(p(X), p(Y));
|
||||||
@ -591,25 +602,9 @@ std::string SLAPrint::validate() const
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<float> SLAPrint::calculate_heights(const BoundingBoxf3& bb3d,
|
|
||||||
float elevation,
|
|
||||||
float initial_layer_height,
|
|
||||||
float layer_height) const
|
|
||||||
{
|
|
||||||
std::vector<float> heights;
|
|
||||||
float minZ = float(bb3d.min(Z)) - float(elevation);
|
|
||||||
float maxZ = float(bb3d.max(Z));
|
|
||||||
auto flh = float(layer_height);
|
|
||||||
auto gnd = float(bb3d.min(Z));
|
|
||||||
|
|
||||||
for(float h = minZ + initial_layer_height; h < maxZ; h += flh)
|
|
||||||
if(h >= gnd) heights.emplace_back(h);
|
|
||||||
|
|
||||||
return heights;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class...Args>
|
template<class...Args>
|
||||||
void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args) {
|
void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args)
|
||||||
|
{
|
||||||
BOOST_LOG_TRIVIAL(info) << st << "% " << msg;
|
BOOST_LOG_TRIVIAL(info) << st << "% " << msg;
|
||||||
p.set_status(st, msg, std::forward<Args>(args)...);
|
p.set_status(st, msg, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
@ -620,12 +615,19 @@ void SLAPrint::process()
|
|||||||
using namespace sla;
|
using namespace sla;
|
||||||
using ExPolygon = Slic3r::ExPolygon;
|
using ExPolygon = Slic3r::ExPolygon;
|
||||||
|
|
||||||
|
if(m_objects.empty()) return;
|
||||||
|
|
||||||
// Assumption: at this point the print objects should be populated only with
|
// Assumption: at this point the print objects should be populated only with
|
||||||
// the model objects we have to process and the instances are also filtered
|
// the model objects we have to process and the instances are also filtered
|
||||||
|
|
||||||
// shortcut to initial layer height
|
// shortcut to initial layer height
|
||||||
double ilhd = m_material_config.initial_layer_height.getFloat();
|
double ilhd = m_material_config.initial_layer_height.getFloat();
|
||||||
auto ilh = float(ilhd);
|
auto ilh = float(ilhd);
|
||||||
|
double lhd = m_objects.front()->m_config.layer_height.getFloat();
|
||||||
|
float lh = float(lhd);
|
||||||
|
|
||||||
|
auto ilhs = LevelID(ilhd / SCALING_FACTOR);
|
||||||
|
auto lhs = LevelID(lhd / SCALING_FACTOR);
|
||||||
const size_t objcount = m_objects.size();
|
const size_t objcount = m_objects.size();
|
||||||
|
|
||||||
const unsigned min_objstatus = 0; // where the per object operations start
|
const unsigned min_objstatus = 0; // where the per object operations start
|
||||||
@ -646,24 +648,59 @@ void SLAPrint::process()
|
|||||||
|
|
||||||
// Slicing the model object. This method is oversimplified and needs to
|
// Slicing the model object. This method is oversimplified and needs to
|
||||||
// be compared with the fff slicing algorithm for verification
|
// be compared with the fff slicing algorithm for verification
|
||||||
auto slice_model = [this, ilh](SLAPrintObject& po) {
|
auto slice_model = [this, ilhs, lhs, ilh, lh](SLAPrintObject& po) {
|
||||||
double lh = po.m_config.layer_height.getFloat();
|
|
||||||
|
|
||||||
TriangleMesh mesh = po.transformed_mesh();
|
TriangleMesh mesh = po.transformed_mesh();
|
||||||
|
|
||||||
|
// We need to prepare the slice index...
|
||||||
|
|
||||||
|
auto&& bb3d = mesh.bounding_box();
|
||||||
|
double minZ = bb3d.min(Z) - po.get_elevation();
|
||||||
|
double maxZ = bb3d.max(Z);
|
||||||
|
|
||||||
|
auto minZs = LevelID(minZ / SCALING_FACTOR);
|
||||||
|
auto maxZs = LevelID(maxZ / SCALING_FACTOR);
|
||||||
|
|
||||||
|
po.m_slice_index.clear();
|
||||||
|
po.m_slice_index.reserve(size_t(maxZs - (minZs + ilhs) / lhs) + 1);
|
||||||
|
po.m_slice_index.emplace_back(minZs + ilhs, float(minZ) + ilh / 2.f, ilh);
|
||||||
|
|
||||||
|
for(LevelID h = minZs + ilhs + lhs; h <= maxZs; h += lhs) {
|
||||||
|
po.m_slice_index.emplace_back(h, float(h*SCALING_FACTOR) - lh / 2.f, lh);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto slindex_it = po.search_slice_index(float(bb3d.min(Z)));
|
||||||
|
|
||||||
|
if(slindex_it == po.m_slice_index.end())
|
||||||
|
throw std::runtime_error(L("Slicing had to be stopped "
|
||||||
|
"due to an internal error."));
|
||||||
|
|
||||||
|
po.m_model_height_levels.clear();
|
||||||
|
po.m_model_height_levels.reserve(po.m_slice_index.size());
|
||||||
|
for(auto it = slindex_it; it != po.m_slice_index.end(); ++it)
|
||||||
|
{
|
||||||
|
po.m_model_height_levels.emplace_back(it->slice_level());
|
||||||
|
}
|
||||||
|
|
||||||
TriangleMeshSlicer slicer(&mesh);
|
TriangleMeshSlicer slicer(&mesh);
|
||||||
|
|
||||||
// The 1D grid heights
|
po.m_model_slices.clear();
|
||||||
std::vector<float> heights = calculate_heights(mesh.bounding_box(),
|
slicer.slice(po.m_model_height_levels,
|
||||||
float(po.get_elevation()),
|
float(po.config().slice_closing_radius.value),
|
||||||
ilh, float(lh));
|
&po.m_model_slices,
|
||||||
|
[this](){ throw_if_canceled(); });
|
||||||
|
|
||||||
auto& layers = po.m_model_slices; layers.clear();
|
auto mit = slindex_it;
|
||||||
slicer.slice(heights, float(po.config().slice_closing_radius.value), &layers, [this](){ throw_if_canceled(); });
|
for(size_t id = 0;
|
||||||
|
id < po.m_model_slices.size() && mit != po.m_slice_index.end();
|
||||||
|
id++)
|
||||||
|
{
|
||||||
|
mit->set_model_slice_idx(id); ++mit;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// In this step we check the slices, identify island and cover them with
|
// In this step we check the slices, identify island and cover them with
|
||||||
// support points. Then we sprinkle the rest of the mesh.
|
// support points. Then we sprinkle the rest of the mesh.
|
||||||
auto support_points = [this, ilh](SLAPrintObject& po) {
|
auto support_points = [this](SLAPrintObject& po) {
|
||||||
const ModelObject& mo = *po.m_model_object;
|
const ModelObject& mo = *po.m_model_object;
|
||||||
po.m_supportdata.reset(
|
po.m_supportdata.reset(
|
||||||
new SLAPrintObject::SupportData(po.transformed_mesh()) );
|
new SLAPrintObject::SupportData(po.transformed_mesh()) );
|
||||||
@ -680,12 +717,7 @@ void SLAPrint::process()
|
|||||||
if (mo.sla_points_status != sla::PointsStatus::UserModified) {
|
if (mo.sla_points_status != sla::PointsStatus::UserModified) {
|
||||||
|
|
||||||
// calculate heights of slices (slices are calculated already)
|
// calculate heights of slices (slices are calculated already)
|
||||||
double lh = po.m_config.layer_height.getFloat();
|
const std::vector<float>& heights = po.m_model_height_levels;
|
||||||
|
|
||||||
std::vector<float> heights =
|
|
||||||
calculate_heights(po.transformed_mesh().bounding_box(),
|
|
||||||
float(po.get_elevation()),
|
|
||||||
ilh, float(lh));
|
|
||||||
|
|
||||||
this->throw_if_canceled();
|
this->throw_if_canceled();
|
||||||
SLAAutoSupports::Config config;
|
SLAAutoSupports::Config config;
|
||||||
@ -831,86 +863,34 @@ void SLAPrint::process()
|
|||||||
// Slicing the support geometries similarly to the model slicing procedure.
|
// Slicing the support geometries similarly to the model slicing procedure.
|
||||||
// If the pad had been added previously (see step "base_pool" than it will
|
// If the pad had been added previously (see step "base_pool" than it will
|
||||||
// be part of the slices)
|
// be part of the slices)
|
||||||
auto slice_supports = [ilh](SLAPrintObject& po) {
|
auto slice_supports = [](SLAPrintObject& po) {
|
||||||
auto& sd = po.m_supportdata;
|
auto& sd = po.m_supportdata;
|
||||||
|
|
||||||
|
if(sd) sd->support_slices.clear();
|
||||||
|
|
||||||
if(sd && sd->support_tree_ptr) {
|
if(sd && sd->support_tree_ptr) {
|
||||||
auto lh = float(po.m_config.layer_height.getFloat());
|
|
||||||
sd->support_slices = sd->support_tree_ptr->slice(lh, ilh);
|
std::vector<float> heights; heights.reserve(po.m_slice_index.size());
|
||||||
|
|
||||||
|
for(auto& rec : po.m_slice_index) {
|
||||||
|
heights.emplace_back(rec.slice_level());
|
||||||
|
}
|
||||||
|
|
||||||
|
sd->support_slices = sd->support_tree_ptr->slice(
|
||||||
|
heights, float(po.config().slice_closing_radius.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i = 0;
|
||||||
|
i < sd->support_slices.size() && i < po.m_slice_index.size();
|
||||||
|
++i)
|
||||||
|
{
|
||||||
|
po.m_slice_index[i].set_support_slice_idx(i);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// We have the layer polygon collection but we need to unite them into
|
// We have the layer polygon collection but we need to unite them into
|
||||||
// an index where the key is the height level in discrete levels (clipper)
|
// an index where the key is the height level in discrete levels (clipper)
|
||||||
auto index_slices = [this, ilhd](SLAPrintObject& po) {
|
auto index_slices = [this/*, ilhd*/](SLAPrintObject& /*po*/) {
|
||||||
po.m_slice_index.clear();
|
|
||||||
auto sih = LevelID(scale_(ilhd));
|
|
||||||
|
|
||||||
// Establish the slice grid boundaries
|
|
||||||
auto bb = po.transformed_mesh().bounding_box();
|
|
||||||
double modelgnd = bb.min(Z);
|
|
||||||
double elevation = po.get_elevation();
|
|
||||||
double lh = po.m_config.layer_height.getFloat();
|
|
||||||
double minZ = modelgnd - elevation;
|
|
||||||
|
|
||||||
// scaled values:
|
|
||||||
auto sminZ = LevelID(scale_(minZ));
|
|
||||||
auto smaxZ = LevelID(scale_(bb.max(Z)));
|
|
||||||
auto smodelgnd = LevelID(scale_(modelgnd));
|
|
||||||
auto slh = LevelID(scale_(lh));
|
|
||||||
|
|
||||||
// It is important that the next levels match the levels in
|
|
||||||
// model_slice method. Only difference is that here it works with
|
|
||||||
// scaled coordinates
|
|
||||||
po.m_level_ids.clear();
|
|
||||||
for(LevelID h = sminZ + sih; h < smaxZ; h += slh)
|
|
||||||
if(h >= smodelgnd) po.m_level_ids.emplace_back(h);
|
|
||||||
|
|
||||||
std::vector<ExPolygons>& oslices = po.m_model_slices;
|
|
||||||
|
|
||||||
// If everything went well this code should not run at all, but
|
|
||||||
// let's be robust...
|
|
||||||
// assert(levelids.size() == oslices.size());
|
|
||||||
if(po.m_level_ids.size() < oslices.size()) { // extend the levels until...
|
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(warning)
|
|
||||||
<< "Height level mismatch at rasterization!\n";
|
|
||||||
|
|
||||||
LevelID lastlvl = po.m_level_ids.back();
|
|
||||||
while(po.m_level_ids.size() < oslices.size()) {
|
|
||||||
lastlvl += slh;
|
|
||||||
po.m_level_ids.emplace_back(lastlvl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(size_t i = 0; i < oslices.size(); ++i) {
|
|
||||||
LevelID h = po.m_level_ids[i];
|
|
||||||
|
|
||||||
float fh = float(double(h) * SCALING_FACTOR);
|
|
||||||
|
|
||||||
// now for the public slice index:
|
|
||||||
SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh];
|
|
||||||
// There should be only one slice layer for each print object
|
|
||||||
assert(sr.model_slices_idx == SLAPrintObject::SliceRecord::NONE);
|
|
||||||
sr.model_slices_idx = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(po.m_supportdata) { // deal with the support slices if present
|
|
||||||
std::vector<ExPolygons>& sslices = po.m_supportdata->support_slices;
|
|
||||||
po.m_supportdata->level_ids.clear();
|
|
||||||
po.m_supportdata->level_ids.reserve(sslices.size());
|
|
||||||
|
|
||||||
for(int i = 0; i < int(sslices.size()); ++i) {
|
|
||||||
LevelID h = sminZ + sih + i * slh;
|
|
||||||
po.m_supportdata->level_ids.emplace_back(h);
|
|
||||||
|
|
||||||
float fh = float(double(h) * SCALING_FACTOR);
|
|
||||||
|
|
||||||
SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh];
|
|
||||||
assert(sr.support_slices_idx == SLAPrintObject::SliceRecord::NONE);
|
|
||||||
sr.support_slices_idx = SLAPrintObject::SliceRecord::Idx(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update status to the 3D preview to load the SLA slices.
|
// Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update status to the 3D preview to load the SLA slices.
|
||||||
report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
|
report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
|
||||||
};
|
};
|
||||||
@ -923,30 +903,18 @@ void SLAPrint::process()
|
|||||||
m_printer_input.clear();
|
m_printer_input.clear();
|
||||||
|
|
||||||
for(SLAPrintObject * o : m_objects) {
|
for(SLAPrintObject * o : m_objects) {
|
||||||
auto& po = *o;
|
LevelID gndlvl = o->get_slice_index().front().key();
|
||||||
std::vector<ExPolygons>& oslices = po.m_model_slices;
|
for(auto& slicerecord : o->get_slice_index()) {
|
||||||
|
auto& lyrs = m_printer_input[slicerecord.key() - gndlvl];
|
||||||
|
|
||||||
// We need to adjust the min Z level of the slices to be zero
|
const ExPolygons& objslices = o->get_slices_from_record(slicerecord, soModel);
|
||||||
LevelID smfirst =
|
const ExPolygons& supslices = o->get_slices_from_record(slicerecord, soSupport);
|
||||||
po.m_supportdata && !po.m_supportdata->level_ids.empty() ?
|
|
||||||
po.m_supportdata->level_ids.front() : 0;
|
|
||||||
LevelID mfirst = po.m_level_ids.empty()? 0 : po.m_level_ids.front();
|
|
||||||
LevelID gndlvl = -(std::min(smfirst, mfirst));
|
|
||||||
|
|
||||||
// now merge this object's support and object slices with the rest
|
if(!objslices.empty())
|
||||||
// of the print object slices
|
lyrs.emplace_back(objslices, o->instances());
|
||||||
|
|
||||||
for(size_t i = 0; i < oslices.size(); ++i) {
|
if(!supslices.empty())
|
||||||
auto& lyrs = m_printer_input[gndlvl + po.m_level_ids[i]];
|
lyrs.emplace_back(supslices, o->instances());
|
||||||
lyrs.emplace_back(oslices[i], po.m_instances);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!po.m_supportdata) continue;
|
|
||||||
std::vector<ExPolygons>& sslices = po.m_supportdata->support_slices;
|
|
||||||
for(size_t i = 0; i < sslices.size(); ++i) {
|
|
||||||
LayerRefs& lyrs =
|
|
||||||
m_printer_input[gndlvl + po.m_supportdata->level_ids[i]];
|
|
||||||
lyrs.emplace_back(sslices[i], po.m_instances);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1249,13 +1217,13 @@ void SLAPrint::fill_statistics()
|
|||||||
|
|
||||||
// find highest object
|
// find highest object
|
||||||
// Which is a better bet? To compare by max_z or by number of layers in the index?
|
// Which is a better bet? To compare by max_z or by number of layers in the index?
|
||||||
double max_z = 0.;
|
float max_z = 0.;
|
||||||
size_t max_layers_cnt = 0;
|
size_t max_layers_cnt = 0;
|
||||||
size_t highest_obj_idx = 0;
|
size_t highest_obj_idx = 0;
|
||||||
for (SLAPrintObject *&po : m_objects) {
|
for (SLAPrintObject *&po : m_objects) {
|
||||||
const SLAPrintObject::SliceIndex& slice_index = po->get_slice_index();
|
const SLAPrintObject::SliceIndex& slice_index = po->get_slice_index();
|
||||||
if (! slice_index.empty()) {
|
if (! slice_index.empty()) {
|
||||||
double z = (-- slice_index.end())->first;
|
float z = (-- slice_index.end())->slice_level();
|
||||||
size_t cnt = slice_index.size();
|
size_t cnt = slice_index.size();
|
||||||
//if (z > max_z) {
|
//if (z > max_z) {
|
||||||
if (cnt > max_layers_cnt) {
|
if (cnt > max_layers_cnt) {
|
||||||
@ -1275,7 +1243,7 @@ void SLAPrint::fill_statistics()
|
|||||||
int sliced_layer_cnt = 0;
|
int sliced_layer_cnt = 0;
|
||||||
for (const auto& layer : highest_obj_slice_index)
|
for (const auto& layer : highest_obj_slice_index)
|
||||||
{
|
{
|
||||||
const double l_height = (layer.first == highest_obj_slice_index.begin()->first) ? init_layer_height : layer_height;
|
const double l_height = (layer.key() == highest_obj_slice_index.begin()->key()) ? init_layer_height : layer_height;
|
||||||
|
|
||||||
// Calculation of the consumed material
|
// Calculation of the consumed material
|
||||||
|
|
||||||
@ -1284,21 +1252,22 @@ void SLAPrint::fill_statistics()
|
|||||||
|
|
||||||
for (SLAPrintObject * po : m_objects)
|
for (SLAPrintObject * po : m_objects)
|
||||||
{
|
{
|
||||||
const SLAPrintObject::SliceRecord *record = nullptr;
|
const SLAPrintObject::_SliceRecord *record = nullptr;
|
||||||
{
|
{
|
||||||
const SLAPrintObject::SliceIndex& index = po->get_slice_index();
|
const SLAPrintObject::SliceIndex& index = po->get_slice_index();
|
||||||
auto key = layer.first;
|
auto it = po->search_slice_index(layer.slice_level() - float(EPSILON));
|
||||||
const SLAPrintObject::SliceIndex::const_iterator it_key = index.lower_bound(key - float(EPSILON));
|
if (it == index.end() || it->slice_level() > layer.slice_level() + float(EPSILON))
|
||||||
if (it_key == index.end() || it_key->first > key + EPSILON)
|
|
||||||
continue;
|
continue;
|
||||||
record = &it_key->second;
|
record = &(*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (record->model_slices_idx != SLAPrintObject::SliceRecord::NONE)
|
const ExPolygons &modelslices = po->get_slices_from_record(*record, soModel);
|
||||||
append(model_polygons, get_all_polygons(po->get_model_slices()[record->model_slices_idx], po->instances()));
|
if (!modelslices.empty())
|
||||||
|
append(model_polygons, get_all_polygons(modelslices, po->instances()));
|
||||||
if (record->support_slices_idx != SLAPrintObject::SliceRecord::NONE)
|
|
||||||
append(supports_polygons, get_all_polygons(po->get_support_slices()[record->support_slices_idx], po->instances()));
|
const ExPolygons &supportslices = po->get_slices_from_record(*record, soSupport);
|
||||||
|
if (!supportslices.empty())
|
||||||
|
append(supports_polygons, get_all_polygons(supportslices, po->instances()));
|
||||||
}
|
}
|
||||||
|
|
||||||
model_polygons = union_(model_polygons);
|
model_polygons = union_(model_polygons);
|
||||||
@ -1394,11 +1363,15 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
|
|||||||
for (const t_config_option_key &opt_key : opt_keys) {
|
for (const t_config_option_key &opt_key : opt_keys) {
|
||||||
if ( opt_key == "layer_height"
|
if ( opt_key == "layer_height"
|
||||||
|| opt_key == "faded_layers"
|
|| opt_key == "faded_layers"
|
||||||
|
|| opt_key == "pad_enable"
|
||||||
|
|| opt_key == "pad_wall_thickness"
|
||||||
|
|| opt_key == "supports_enable"
|
||||||
|
|| opt_key == "support_object_elevation"
|
||||||
|| opt_key == "slice_closing_radius") {
|
|| opt_key == "slice_closing_radius") {
|
||||||
steps.emplace_back(slaposObjectSlice);
|
steps.emplace_back(slaposObjectSlice);
|
||||||
} else if (
|
} else if (
|
||||||
opt_key == "supports_enable"
|
|
||||||
|| opt_key == "support_points_density_relative"
|
opt_key == "support_points_density_relative"
|
||||||
|| opt_key == "support_points_minimal_distance") {
|
|| opt_key == "support_points_minimal_distance") {
|
||||||
steps.emplace_back(slaposSupportPoints);
|
steps.emplace_back(slaposSupportPoints);
|
||||||
} else if (
|
} else if (
|
||||||
@ -1413,12 +1386,10 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
|
|||||||
|| opt_key == "support_critical_angle"
|
|| opt_key == "support_critical_angle"
|
||||||
|| opt_key == "support_max_bridge_length"
|
|| opt_key == "support_max_bridge_length"
|
||||||
|| opt_key == "support_max_pillar_link_distance"
|
|| opt_key == "support_max_pillar_link_distance"
|
||||||
|| opt_key == "support_object_elevation") {
|
) {
|
||||||
steps.emplace_back(slaposSupportTree);
|
steps.emplace_back(slaposSupportTree);
|
||||||
} else if (
|
} else if (
|
||||||
opt_key == "pad_enable"
|
opt_key == "pad_wall_height"
|
||||||
|| opt_key == "pad_wall_thickness"
|
|
||||||
|| opt_key == "pad_wall_height"
|
|
||||||
|| opt_key == "pad_max_merge_distance"
|
|| opt_key == "pad_max_merge_distance"
|
||||||
|| opt_key == "pad_wall_slope"
|
|| opt_key == "pad_wall_slope"
|
||||||
|| opt_key == "pad_edge_radius") {
|
|| opt_key == "pad_edge_radius") {
|
||||||
@ -1474,11 +1445,7 @@ double SLAPrintObject::get_elevation() const {
|
|||||||
// its walls but currently it is half of its thickness. Whatever it
|
// its walls but currently it is half of its thickness. Whatever it
|
||||||
// will be in the future, we provide the config to the get_pad_elevation
|
// will be in the future, we provide the config to the get_pad_elevation
|
||||||
// method and we will have the correct value
|
// method and we will have the correct value
|
||||||
sla::PoolConfig pcfg;
|
sla::PoolConfig pcfg = make_pool_config(m_config);
|
||||||
pcfg.min_wall_height_mm = m_config.pad_wall_height.getFloat();
|
|
||||||
pcfg.min_wall_thickness_mm = m_config.pad_wall_thickness.getFloat();
|
|
||||||
pcfg.edge_radius_mm = m_config.pad_edge_radius.getFloat();
|
|
||||||
pcfg.max_merge_distance_mm = m_config.pad_max_merge_distance.getFloat();
|
|
||||||
ret += sla::get_pad_elevation(pcfg);
|
ret += sla::get_pad_elevation(pcfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1502,6 +1469,7 @@ double SLAPrintObject::get_current_elevation() const
|
|||||||
namespace { // dummy empty static containers for return values in some methods
|
namespace { // dummy empty static containers for return values in some methods
|
||||||
const std::vector<ExPolygons> EMPTY_SLICES;
|
const std::vector<ExPolygons> EMPTY_SLICES;
|
||||||
const TriangleMesh EMPTY_MESH;
|
const TriangleMesh EMPTY_MESH;
|
||||||
|
const ExPolygons EMPTY_SLICE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<sla::SupportPoint>& SLAPrintObject::get_support_points() const
|
const std::vector<sla::SupportPoint>& SLAPrintObject::get_support_points() const
|
||||||
@ -1509,6 +1477,72 @@ const std::vector<sla::SupportPoint>& SLAPrintObject::get_support_points() const
|
|||||||
return m_supportdata->support_points;
|
return m_supportdata->support_points;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SLAPrintObject::SliceIndex::iterator
|
||||||
|
SLAPrintObject::search_slice_index(float slice_level)
|
||||||
|
{
|
||||||
|
_SliceRecord query(0, slice_level, 0);
|
||||||
|
auto it = std::lower_bound(m_slice_index.begin(), m_slice_index.end(),
|
||||||
|
query,
|
||||||
|
[](const _SliceRecord& r1, const _SliceRecord& r2)
|
||||||
|
{
|
||||||
|
return r1.slice_level() < r2.slice_level();
|
||||||
|
});
|
||||||
|
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
SLAPrintObject::SliceIndex::const_iterator
|
||||||
|
SLAPrintObject::search_slice_index(float slice_level) const
|
||||||
|
{
|
||||||
|
_SliceRecord query(0, slice_level, 0);
|
||||||
|
auto it = std::lower_bound(m_slice_index.cbegin(), m_slice_index.cend(),
|
||||||
|
query,
|
||||||
|
[](const _SliceRecord& r1, const _SliceRecord& r2)
|
||||||
|
{
|
||||||
|
return r1.slice_level() < r2.slice_level();
|
||||||
|
});
|
||||||
|
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
SLAPrintObject::SliceIndex::iterator
|
||||||
|
SLAPrintObject::search_slice_index(SLAPrintObject::_SliceRecord::Key key,
|
||||||
|
bool exact)
|
||||||
|
{
|
||||||
|
_SliceRecord query(key, 0.f, 0.f);
|
||||||
|
auto it = std::lower_bound(m_slice_index.begin(), m_slice_index.end(),
|
||||||
|
query,
|
||||||
|
[](const _SliceRecord& r1, const _SliceRecord& r2)
|
||||||
|
{
|
||||||
|
return r1.key() < r2.key();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Return valid iterator only if the keys really match
|
||||||
|
if(exact && it != m_slice_index.end() && it->key() != key)
|
||||||
|
it = m_slice_index.end();
|
||||||
|
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
SLAPrintObject::SliceIndex::const_iterator
|
||||||
|
SLAPrintObject::search_slice_index(SLAPrintObject::_SliceRecord::Key key,
|
||||||
|
bool exact) const
|
||||||
|
{
|
||||||
|
_SliceRecord query(key, 0.f, 0.f);
|
||||||
|
auto it = std::lower_bound(m_slice_index.cbegin(), m_slice_index.cend(),
|
||||||
|
query,
|
||||||
|
[](const _SliceRecord& r1, const _SliceRecord& r2)
|
||||||
|
{
|
||||||
|
return r1.key() < r2.key();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Return valid iterator only if the keys really match
|
||||||
|
if(exact && it != m_slice_index.end() && it->key() != key)
|
||||||
|
it = m_slice_index.end();
|
||||||
|
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
|
const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
|
||||||
{
|
{
|
||||||
// assert(is_step_done(slaposSliceSupports));
|
// assert(is_step_done(slaposSliceSupports));
|
||||||
@ -1516,7 +1550,30 @@ const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
|
|||||||
return m_supportdata->support_slices;
|
return m_supportdata->support_slices;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SLAPrintObject::SliceIndex &SLAPrintObject::get_slice_index() const
|
const ExPolygons &SLAPrintObject::get_slices_from_record(
|
||||||
|
const _SliceRecord &rec,
|
||||||
|
SliceOrigin o) const
|
||||||
|
{
|
||||||
|
size_t idx = o == soModel ? rec.get_model_slice_idx() :
|
||||||
|
rec.get_support_slice_idx();
|
||||||
|
|
||||||
|
const std::vector<ExPolygons>& v = o == soModel? get_model_slices() :
|
||||||
|
get_support_slices();
|
||||||
|
|
||||||
|
if(idx >= v.size()) return EMPTY_SLICE;
|
||||||
|
|
||||||
|
return idx >= v.size() ? EMPTY_SLICE : v[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
const ExPolygons &SLAPrintObject::get_slices_from_record(
|
||||||
|
SLAPrintObject::SliceRecordConstIterator it, SliceOrigin o) const
|
||||||
|
{
|
||||||
|
if(it.is_end()) return EMPTY_SLICE;
|
||||||
|
return get_slices_from_record(*it, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<SLAPrintObject::_SliceRecord>&
|
||||||
|
SLAPrintObject::get_slice_index() const
|
||||||
{
|
{
|
||||||
// assert(is_step_done(slaposIndexSlices));
|
// assert(is_step_done(slaposIndexSlices));
|
||||||
return m_slice_index;
|
return m_slice_index;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "PrintExport.hpp"
|
#include "PrintExport.hpp"
|
||||||
#include "Point.hpp"
|
#include "Point.hpp"
|
||||||
#include "MTUtils.hpp"
|
#include "MTUtils.hpp"
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
@ -35,12 +36,19 @@ using _SLAPrintObjectBase =
|
|||||||
// the printer (rasterizer) in the SLAPrint class.
|
// the printer (rasterizer) in the SLAPrint class.
|
||||||
using LevelID = long long;
|
using LevelID = long long;
|
||||||
|
|
||||||
|
enum SliceOrigin { soSupport, soModel };
|
||||||
|
|
||||||
class SLAPrintObject : public _SLAPrintObjectBase
|
class SLAPrintObject : public _SLAPrintObjectBase
|
||||||
{
|
{
|
||||||
private: // Prevents erroneous use by other classes.
|
private: // Prevents erroneous use by other classes.
|
||||||
using Inherited = _SLAPrintObjectBase;
|
using Inherited = _SLAPrintObjectBase;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
// I refuse to grantee copying (Tamas)
|
||||||
|
SLAPrintObject(const SLAPrintObject&) = delete;
|
||||||
|
SLAPrintObject& operator=(const SLAPrintObject&) = delete;
|
||||||
|
|
||||||
const SLAPrintObjectConfig& config() const { return m_config; }
|
const SLAPrintObjectConfig& config() const { return m_config; }
|
||||||
const Transform3d& trafo() const { return m_trafo; }
|
const Transform3d& trafo() const { return m_trafo; }
|
||||||
|
|
||||||
@ -82,40 +90,146 @@ public:
|
|||||||
// pad is not, then without the pad, otherwise the full value is returned.
|
// pad is not, then without the pad, otherwise the full value is returned.
|
||||||
double get_current_elevation() const;
|
double get_current_elevation() const;
|
||||||
|
|
||||||
// These two methods should be callable on the client side (e.g. UI thread)
|
|
||||||
// when the appropriate steps slaposObjectSlice and slaposSliceSupports
|
|
||||||
// are ready. All the print objects are processed before slapsRasterize so
|
|
||||||
// it is safe to call them during and/or after slapsRasterize.
|
|
||||||
const std::vector<ExPolygons>& get_model_slices() const;
|
|
||||||
const std::vector<ExPolygons>& get_support_slices() const;
|
|
||||||
|
|
||||||
// This method returns the support points of this SLAPrintObject.
|
// This method returns the support points of this SLAPrintObject.
|
||||||
const std::vector<sla::SupportPoint>& get_support_points() const;
|
const std::vector<sla::SupportPoint>& get_support_points() const;
|
||||||
|
|
||||||
|
// The public Slice record structure. It corresponds to one printable layer.
|
||||||
|
// To get the sliced polygons, use SLAPrintObject::get_slices_from_record
|
||||||
|
class SliceRecord {
|
||||||
|
public:
|
||||||
|
using Key = LevelID;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Key m_print_z = 0; // Top of the layer
|
||||||
|
float m_slice_z = 0.f; // Exact level of the slice
|
||||||
|
float m_height = 0.f; // Height of the sliced layer
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SliceRecord(Key key, float slicez, float height):
|
||||||
|
m_print_z(key), m_slice_z(slicez), m_height(height) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// The key will be the integer height level of the top of the layer.
|
||||||
|
inline Key key() const { return m_print_z; }
|
||||||
|
|
||||||
|
// Returns the exact floating point Z coordinate of the slice
|
||||||
|
inline float slice_level() const { return m_slice_z; }
|
||||||
|
|
||||||
|
// Returns the current layer height
|
||||||
|
inline float layer_height() const { return m_height; }
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
// An index record referencing the slices
|
// An index record referencing the slices
|
||||||
// (get_model_slices(), get_support_slices()) where the keys are the height
|
// (get_model_slices(), get_support_slices()) where the keys are the height
|
||||||
// levels of the model in scaled-clipper coordinates. The levels correspond
|
// levels of the model in scaled-clipper coordinates. The levels correspond
|
||||||
// to the z coordinate of the object coordinate system.
|
// to the z coordinate of the object coordinate system.
|
||||||
struct SliceRecord {
|
class _SliceRecord: public SliceRecord {
|
||||||
using Key = float;
|
public:
|
||||||
|
static const size_t NONE = size_t(-1); // this will be the max limit of size_t
|
||||||
|
private:
|
||||||
|
size_t m_model_slices_idx = NONE;
|
||||||
|
size_t m_support_slices_idx = NONE;
|
||||||
|
|
||||||
using Idx = size_t;
|
public:
|
||||||
static const Idx NONE = Idx(-1); // this will be the max limit of size_t
|
_SliceRecord(Key key, float slicez, float height):
|
||||||
|
SliceRecord(key, slicez, height) {}
|
||||||
|
|
||||||
Idx model_slices_idx = NONE;
|
// Methods for setting the indices into the slice vectors.
|
||||||
Idx support_slices_idx = NONE;
|
void set_model_slice_idx(size_t id) { m_model_slices_idx = id; }
|
||||||
|
void set_support_slice_idx(size_t id) { m_support_slices_idx = id; }
|
||||||
|
|
||||||
|
inline size_t get_model_slice_idx() const { return m_model_slices_idx; }
|
||||||
|
inline size_t get_support_slice_idx() const { return m_support_slices_idx; }
|
||||||
};
|
};
|
||||||
|
|
||||||
using SliceIndex = std::map<SliceRecord::Key, SliceRecord>;
|
// Slice index will be a plain vector sorted by the integer height levels
|
||||||
|
using SliceIndex = std::vector<_SliceRecord>;
|
||||||
|
|
||||||
// Retrieve the slice index which is readable only after slaposIndexSlices
|
// Retrieve the slice index which is readable only after slaposIndexSlices
|
||||||
// is done.
|
// is done.
|
||||||
const SliceIndex& get_slice_index() const;
|
const SliceIndex& get_slice_index() const;
|
||||||
|
|
||||||
// I refuse to grantee copying (Tamas)
|
// Search slice index for the closest slice to the given level
|
||||||
SLAPrintObject(const SLAPrintObject&) = delete;
|
SliceIndex::iterator search_slice_index(float slice_level);
|
||||||
SLAPrintObject& operator=(const SLAPrintObject&) = delete;
|
SliceIndex::const_iterator search_slice_index(float slice_level) const;
|
||||||
|
|
||||||
|
// Search the slice index for a particular level in integer coordinates.
|
||||||
|
// If no such layer is present, it will return m_slice_index.end()
|
||||||
|
// This behavior can be suppressed by the second parameter. If it is true
|
||||||
|
// the method will return the closest (non-equal) record
|
||||||
|
SliceIndex::iterator search_slice_index(_SliceRecord::Key key, bool exact = false);
|
||||||
|
SliceIndex::const_iterator search_slice_index(_SliceRecord::Key key, bool = false) const;
|
||||||
|
|
||||||
|
const std::vector<ExPolygons>& get_model_slices() const;
|
||||||
|
const std::vector<ExPolygons>& get_support_slices() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Should work as a polymorphic bidirectional iterator to the slice records
|
||||||
|
using SliceRecordConstIterator =
|
||||||
|
IndexBasedIterator<const SliceIndex, const _SliceRecord>;
|
||||||
|
|
||||||
|
// /////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// These two methods should be callable on the client side (e.g. UI thread)
|
||||||
|
// when the appropriate steps slaposObjectSlice and slaposSliceSupports
|
||||||
|
// are ready. All the print objects are processed before slapsRasterize so
|
||||||
|
// it is safe to call them during and/or after slapsRasterize.
|
||||||
|
//
|
||||||
|
// /////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Get the slice records from a range of slice levels (inclusive). Floating
|
||||||
|
// point keys are the levels where the model was sliced with the mesh
|
||||||
|
// slicer. Integral keys are the keys of the slice records, which
|
||||||
|
// correspond to the top of each layer.. The end() method of the returned
|
||||||
|
// range points *after* the last valid element. This is for being
|
||||||
|
// consistent with std and makeing range based for loops work. use
|
||||||
|
// std::prev(range.end()) or --range.end() to get the last element.
|
||||||
|
template<class Key> Range<SliceRecordConstIterator>
|
||||||
|
get_slice_records(Key from, Key to = std::numeric_limits<Key>::max()) const
|
||||||
|
{
|
||||||
|
SliceIndex::const_iterator it_from, it_to;
|
||||||
|
if(std::is_integral<Key>::value) {
|
||||||
|
it_from = search_slice_index(SliceRecord::Key(from));
|
||||||
|
it_to = search_slice_index(SliceRecord::Key(to));
|
||||||
|
} else if(std::is_floating_point<Key>::value) {
|
||||||
|
it_from = search_slice_index(float(from));
|
||||||
|
it_to = search_slice_index(float(to));
|
||||||
|
} else return {
|
||||||
|
SliceRecordConstIterator(m_slice_index, _SliceRecord::NONE ),
|
||||||
|
SliceRecordConstIterator(m_slice_index, _SliceRecord::NONE ),
|
||||||
|
};
|
||||||
|
|
||||||
|
auto start = m_slice_index.begin();
|
||||||
|
|
||||||
|
size_t bidx = it_from == m_slice_index.end() ? _SliceRecord::NONE :
|
||||||
|
size_t(it_from - start);
|
||||||
|
|
||||||
|
size_t eidx = it_to == m_slice_index.end() ? _SliceRecord::NONE :
|
||||||
|
size_t(it_to - start) + 1;
|
||||||
|
|
||||||
|
return {
|
||||||
|
SliceRecordConstIterator(m_slice_index, bidx),
|
||||||
|
SliceRecordConstIterator(m_slice_index, eidx),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all the slice records as a range.
|
||||||
|
inline Range<SliceRecordConstIterator> get_slice_records() const {
|
||||||
|
return {
|
||||||
|
SliceRecordConstIterator(m_slice_index, 0),
|
||||||
|
SliceRecordConstIterator(m_slice_index, m_slice_index.size())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const ExPolygons& get_slices_from_record(SliceRecordConstIterator it,
|
||||||
|
SliceOrigin o) const;
|
||||||
|
|
||||||
|
const ExPolygons& get_slices_from_record(const _SliceRecord& rec,
|
||||||
|
SliceOrigin o) const;
|
||||||
protected:
|
protected:
|
||||||
// to be called from SLAPrint only.
|
// to be called from SLAPrint only.
|
||||||
friend class SLAPrint;
|
friend class SLAPrint;
|
||||||
@ -145,8 +259,10 @@ protected:
|
|||||||
private:
|
private:
|
||||||
// Object specific configuration, pulled from the configuration layer.
|
// Object specific configuration, pulled from the configuration layer.
|
||||||
SLAPrintObjectConfig m_config;
|
SLAPrintObjectConfig m_config;
|
||||||
|
|
||||||
// Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
|
// Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
|
||||||
Transform3d m_trafo = Transform3d::Identity();
|
Transform3d m_trafo = Transform3d::Identity();
|
||||||
|
|
||||||
std::vector<Instance> m_instances;
|
std::vector<Instance> m_instances;
|
||||||
|
|
||||||
// Individual 2d slice polygons from lower z to higher z levels
|
// Individual 2d slice polygons from lower z to higher z levels
|
||||||
@ -154,11 +270,9 @@ private:
|
|||||||
|
|
||||||
// Exact (float) height levels mapped to the slices. Each record contains
|
// Exact (float) height levels mapped to the slices. Each record contains
|
||||||
// the index to the model and the support slice vectors.
|
// the index to the model and the support slice vectors.
|
||||||
SliceIndex m_slice_index;
|
std::vector<_SliceRecord> m_slice_index;
|
||||||
|
|
||||||
// The height levels corrected and scaled up in integer values. This will
|
std::vector<float> m_model_height_levels;
|
||||||
// be used at rasterization.
|
|
||||||
std::vector<LevelID> m_level_ids;
|
|
||||||
|
|
||||||
// Caching the transformed (m_trafo) raw mesh of the object
|
// Caching the transformed (m_trafo) raw mesh of the object
|
||||||
mutable CachedObject<TriangleMesh> m_transformed_rmesh;
|
mutable CachedObject<TriangleMesh> m_transformed_rmesh;
|
||||||
@ -236,6 +350,11 @@ public:
|
|||||||
}
|
}
|
||||||
const PrintObjects& objects() const { return m_objects; }
|
const PrintObjects& objects() const { return m_objects; }
|
||||||
|
|
||||||
|
const SLAPrintConfig& print_config() const { return m_print_config; }
|
||||||
|
const SLAPrinterConfig& printer_config() const { return m_printer_config; }
|
||||||
|
const SLAMaterialConfig& material_config() const { return m_material_config; }
|
||||||
|
|
||||||
|
|
||||||
std::string output_filename() const override;
|
std::string output_filename() const override;
|
||||||
|
|
||||||
const SLAPrintStatistics& print_statistics() const { return m_print_statistics; }
|
const SLAPrintStatistics& print_statistics() const { return m_print_statistics; }
|
||||||
@ -249,11 +368,6 @@ private:
|
|||||||
// Invalidate steps based on a set of parameters changed.
|
// Invalidate steps based on a set of parameters changed.
|
||||||
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
||||||
|
|
||||||
std::vector<float> calculate_heights(const BoundingBoxf3& bb,
|
|
||||||
float elevation,
|
|
||||||
float initial_layer_height,
|
|
||||||
float layer_height) const;
|
|
||||||
|
|
||||||
void fill_statistics();
|
void fill_statistics();
|
||||||
|
|
||||||
SLAPrintConfig m_print_config;
|
SLAPrintConfig m_print_config;
|
||||||
|
@ -540,7 +540,10 @@ void Choice::BUILD() {
|
|||||||
else{
|
else{
|
||||||
for (auto el : m_opt.enum_labels.empty() ? m_opt.enum_values : m_opt.enum_labels) {
|
for (auto el : m_opt.enum_labels.empty() ? m_opt.enum_values : m_opt.enum_labels) {
|
||||||
const wxString& str = _(el);//m_opt_id == "support" ? _(el) : el;
|
const wxString& str = _(el);//m_opt_id == "support" ? _(el) : el;
|
||||||
temp->Append(str, create_scaled_bitmap("empty_icon.png"));
|
//FIXME Vojtech: Why is the single column empty icon necessary? It is a workaround of some kind, but what for?
|
||||||
|
// Please document such workarounds by comments!
|
||||||
|
// temp->Append(str, create_scaled_bitmap("empty_icon.png"));
|
||||||
|
temp->Append(str, wxNullBitmap);
|
||||||
}
|
}
|
||||||
set_selection();
|
set_selection();
|
||||||
}
|
}
|
||||||
|
@ -2293,11 +2293,13 @@ int GLCanvas3D::check_volumes_outside_state() const
|
|||||||
return (int)state;
|
return (int)state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible)
|
void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo, int instance_idx)
|
||||||
{
|
{
|
||||||
for (GLVolume* vol : m_volumes.volumes) {
|
for (GLVolume* vol : m_volumes.volumes) {
|
||||||
if (vol->composite_id.volume_id < 0)
|
if ((mo == nullptr || m_model->objects[vol->composite_id.object_id] == mo)
|
||||||
vol->is_active = visible;
|
&& (instance_idx == -1 || vol->composite_id.instance_id == instance_idx)
|
||||||
|
&& vol->composite_id.volume_id < 0)
|
||||||
|
vol->is_active = visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_render_sla_auxiliaries = visible;
|
m_render_sla_auxiliaries = visible;
|
||||||
@ -2313,7 +2315,7 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (visible && !mo)
|
if (visible && !mo)
|
||||||
toggle_sla_auxiliaries_visibility(true);
|
toggle_sla_auxiliaries_visibility(true, mo, instance_idx);
|
||||||
|
|
||||||
if (!mo && !visible && !m_model->objects.empty() && (m_model->objects.size() > 1 || m_model->objects.front()->instances.size() > 1))
|
if (!mo && !visible && !m_model->objects.empty() && (m_model->objects.size() > 1 || m_model->objects.front()->instances.size() > 1))
|
||||||
_set_warning_texture(WarningTexture::SomethingNotShown, true);
|
_set_warning_texture(WarningTexture::SomethingNotShown, true);
|
||||||
@ -4971,24 +4973,20 @@ void GLCanvas3D::_render_sla_slices() const
|
|||||||
{
|
{
|
||||||
const SLAPrintObject* obj = print_objects[i];
|
const SLAPrintObject* obj = print_objects[i];
|
||||||
|
|
||||||
double shift_z = obj->get_current_elevation();
|
|
||||||
double min_z = clip_min_z - shift_z;
|
|
||||||
double max_z = clip_max_z - shift_z;
|
|
||||||
|
|
||||||
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i);
|
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i);
|
||||||
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i);
|
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i);
|
||||||
{
|
{
|
||||||
if (it_caps_bottom == m_sla_caps[0].triangles.end())
|
if (it_caps_bottom == m_sla_caps[0].triangles.end())
|
||||||
it_caps_bottom = m_sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first;
|
it_caps_bottom = m_sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first;
|
||||||
if (! m_sla_caps[0].matches(min_z)) {
|
if (! m_sla_caps[0].matches(clip_min_z)) {
|
||||||
m_sla_caps[0].z = min_z;
|
m_sla_caps[0].z = clip_min_z;
|
||||||
it_caps_bottom->second.object.clear();
|
it_caps_bottom->second.object.clear();
|
||||||
it_caps_bottom->second.supports.clear();
|
it_caps_bottom->second.supports.clear();
|
||||||
}
|
}
|
||||||
if (it_caps_top == m_sla_caps[1].triangles.end())
|
if (it_caps_top == m_sla_caps[1].triangles.end())
|
||||||
it_caps_top = m_sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first;
|
it_caps_top = m_sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first;
|
||||||
if (! m_sla_caps[1].matches(max_z)) {
|
if (! m_sla_caps[1].matches(clip_max_z)) {
|
||||||
m_sla_caps[1].z = max_z;
|
m_sla_caps[1].z = clip_max_z;
|
||||||
it_caps_top->second.object.clear();
|
it_caps_top->second.object.clear();
|
||||||
it_caps_top->second.supports.clear();
|
it_caps_top->second.supports.clear();
|
||||||
}
|
}
|
||||||
@ -5008,36 +5006,39 @@ void GLCanvas3D::_render_sla_slices() const
|
|||||||
std::vector<InstanceTransform> instance_transforms;
|
std::vector<InstanceTransform> instance_transforms;
|
||||||
for (const SLAPrintObject::Instance& inst : instances)
|
for (const SLAPrintObject::Instance& inst : instances)
|
||||||
{
|
{
|
||||||
instance_transforms.push_back({ to_3d(unscale(inst.shift), shift_z), Geometry::rad2deg(inst.rotation) });
|
instance_transforms.push_back({ to_3d(unscale(inst.shift), 0.), Geometry::rad2deg(inst.rotation) });
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && obj->is_step_done(slaposIndexSlices))
|
if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && obj->is_step_done(slaposIndexSlices))
|
||||||
{
|
{
|
||||||
const std::vector<ExPolygons>& model_slices = obj->get_model_slices();
|
double initial_layer_height = print->material_config().initial_layer_height.value;
|
||||||
const std::vector<ExPolygons>& support_slices = obj->get_support_slices();
|
LevelID key_zero = obj->get_slice_records().begin()->key();
|
||||||
|
LevelID key_low = LevelID((clip_min_z - initial_layer_height) / SCALING_FACTOR) + key_zero;
|
||||||
const SLAPrintObject::SliceIndex& index = obj->get_slice_index();
|
LevelID key_high = LevelID((clip_max_z - initial_layer_height) / SCALING_FACTOR) + key_zero;
|
||||||
SLAPrintObject::SliceIndex::const_iterator it_min_z = std::find_if(index.begin(), index.end(), [min_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(min_z - id.first) < EPSILON; });
|
auto slice_range = obj->get_slice_records(key_low - LevelID(SCALED_EPSILON), key_high - LevelID(SCALED_EPSILON));
|
||||||
SLAPrintObject::SliceIndex::const_iterator it_max_z = std::find_if(index.begin(), index.end(), [max_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(max_z - id.first) < EPSILON; });
|
auto it_low = slice_range.begin();
|
||||||
|
auto it_high = std::prev(slice_range.end());
|
||||||
if (it_min_z != index.end())
|
|
||||||
{
|
if (! it_low.is_end() && it_low->key() < key_low + LevelID(SCALED_EPSILON)) {
|
||||||
|
const ExPolygons& obj_bottom = obj->get_slices_from_record(it_low, soModel);
|
||||||
|
const ExPolygons& sup_bottom = obj->get_slices_from_record(it_low, soSupport);
|
||||||
// calculate model bottom cap
|
// calculate model bottom cap
|
||||||
if (bottom_obj_triangles.empty() && (it_min_z->second.model_slices_idx < model_slices.size()))
|
if (bottom_obj_triangles.empty() && !obj_bottom.empty())
|
||||||
bottom_obj_triangles = triangulate_expolygons_3d(model_slices[it_min_z->second.model_slices_idx], min_z, true);
|
bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z, true);
|
||||||
// calculate support bottom cap
|
// calculate support bottom cap
|
||||||
if (bottom_sup_triangles.empty() && (it_min_z->second.support_slices_idx < support_slices.size()))
|
if (bottom_sup_triangles.empty() && !sup_bottom.empty())
|
||||||
bottom_sup_triangles = triangulate_expolygons_3d(support_slices[it_min_z->second.support_slices_idx], min_z, true);
|
bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it_max_z != index.end())
|
if (! it_high.is_end() && it_high->key() < key_high + LevelID(SCALED_EPSILON)) {
|
||||||
{
|
const ExPolygons& obj_top = obj->get_slices_from_record(it_high, soModel);
|
||||||
|
const ExPolygons& sup_top = obj->get_slices_from_record(it_high, soSupport);
|
||||||
// calculate model top cap
|
// calculate model top cap
|
||||||
if (top_obj_triangles.empty() && (it_max_z->second.model_slices_idx < model_slices.size()))
|
if (top_obj_triangles.empty() && !obj_top.empty())
|
||||||
top_obj_triangles = triangulate_expolygons_3d(model_slices[it_max_z->second.model_slices_idx], max_z, false);
|
top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z, false);
|
||||||
// calculate support top cap
|
// calculate support top cap
|
||||||
if (top_sup_triangles.empty() && (it_max_z->second.support_slices_idx < support_slices.size()))
|
if (top_sup_triangles.empty() && !sup_top.empty())
|
||||||
top_sup_triangles = triangulate_expolygons_3d(support_slices[it_max_z->second.support_slices_idx], max_z, false);
|
top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,6 +584,9 @@ private:
|
|||||||
bool m_regenerate_volumes;
|
bool m_regenerate_volumes;
|
||||||
bool m_moving;
|
bool m_moving;
|
||||||
bool m_tab_down;
|
bool m_tab_down;
|
||||||
|
|
||||||
|
// Following variable is obsolete and it should be safe to remove it.
|
||||||
|
// I just don't want to do it now before a release (Lukas Matena 24.3.2019)
|
||||||
bool m_render_sla_auxiliaries;
|
bool m_render_sla_auxiliaries;
|
||||||
|
|
||||||
std::string m_color_by;
|
std::string m_color_by;
|
||||||
@ -610,7 +613,7 @@ public:
|
|||||||
void reset_volumes();
|
void reset_volumes();
|
||||||
int check_volumes_outside_state() const;
|
int check_volumes_outside_state() const;
|
||||||
|
|
||||||
void toggle_sla_auxiliaries_visibility(bool visible);
|
void toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
|
||||||
void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
|
void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
|
||||||
|
|
||||||
void set_config(const DynamicPrintConfig* config);
|
void set_config(const DynamicPrintConfig* config);
|
||||||
|
@ -157,7 +157,6 @@ GLToolbar::GLToolbar(GLToolbar::EType type)
|
|||||||
#if ENABLE_SVG_ICONS
|
#if ENABLE_SVG_ICONS
|
||||||
, m_icons_texture_dirty(true)
|
, m_icons_texture_dirty(true)
|
||||||
#endif // ENABLE_SVG_ICONS
|
#endif // ENABLE_SVG_ICONS
|
||||||
, m_mouse_capture({ false, false, false, nullptr })
|
|
||||||
, m_tooltip("")
|
, m_tooltip("")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -410,6 +409,16 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
|
|||||||
bool processed = false;
|
bool processed = false;
|
||||||
|
|
||||||
// mouse anywhere
|
// mouse anywhere
|
||||||
|
if (!evt.Dragging() && !evt.Leaving() && !evt.Entering() && (m_mouse_capture.parent != nullptr))
|
||||||
|
{
|
||||||
|
if (m_mouse_capture.any() && (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()))
|
||||||
|
// prevents loosing selection into the scene if mouse down was done inside the toolbar and mouse up was down outside it,
|
||||||
|
// as when switching between views
|
||||||
|
processed = true;
|
||||||
|
|
||||||
|
m_mouse_capture.reset();
|
||||||
|
}
|
||||||
|
|
||||||
if (evt.Moving())
|
if (evt.Moving())
|
||||||
m_tooltip = update_hover_state(mouse_pos, parent);
|
m_tooltip = update_hover_state(mouse_pos, parent);
|
||||||
else if (evt.LeftUp())
|
else if (evt.LeftUp())
|
||||||
@ -418,17 +427,9 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
|
|||||||
m_mouse_capture.middle = false;
|
m_mouse_capture.middle = false;
|
||||||
else if (evt.RightUp())
|
else if (evt.RightUp())
|
||||||
m_mouse_capture.right = false;
|
m_mouse_capture.right = false;
|
||||||
else if (m_mouse_capture.any())
|
else if (evt.Dragging() && m_mouse_capture.any())
|
||||||
{
|
// if the button down was done on this toolbar, prevent from dragging into the scene
|
||||||
if (evt.Dragging())
|
processed = true;
|
||||||
processed = true;
|
|
||||||
else if (evt.Entering() && (m_mouse_capture.parent == &parent))
|
|
||||||
// Resets the mouse capture state to avoid setting the dragging event as processed when, for example,
|
|
||||||
// the item action opens a modal dialog
|
|
||||||
// Keeps the mouse capture state if the entering event happens on different parent from the one
|
|
||||||
// who received the button down event, to prevent, for example, dragging when switching between scene views
|
|
||||||
m_mouse_capture.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
int item_id = contains_mouse(mouse_pos, parent);
|
int item_id = contains_mouse(mouse_pos, parent);
|
||||||
if (item_id == -1)
|
if (item_id == -1)
|
||||||
|
@ -238,6 +238,8 @@ private:
|
|||||||
bool right;
|
bool right;
|
||||||
GLCanvas3D* parent;
|
GLCanvas3D* parent;
|
||||||
|
|
||||||
|
MouseCapture() { reset(); }
|
||||||
|
|
||||||
bool any() const { return left || middle || right; }
|
bool any() const { return left || middle || right; }
|
||||||
void reset() { left = middle = right = false; parent = nullptr; }
|
void reset() { left = middle = right = false; parent = nullptr; }
|
||||||
};
|
};
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
|
|
||||||
|
#include <wx/wupdlock.h>
|
||||||
|
|
||||||
namespace Slic3r
|
namespace Slic3r
|
||||||
{
|
{
|
||||||
namespace GUI
|
namespace GUI
|
||||||
@ -40,7 +42,7 @@ void OG_Settings::Hide()
|
|||||||
void OG_Settings::UpdateAndShow(const bool show)
|
void OG_Settings::UpdateAndShow(const bool show)
|
||||||
{
|
{
|
||||||
Show(show);
|
Show(show);
|
||||||
// m_parent->Layout();
|
// m_parent->Layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxSizer* OG_Settings::get_sizer()
|
wxSizer* OG_Settings::get_sizer()
|
||||||
@ -84,6 +86,7 @@ void ObjectSettings::update_settings_list()
|
|||||||
btn->Bind(wxEVT_BUTTON, [opt_key, config, this](wxEvent &event) {
|
btn->Bind(wxEVT_BUTTON, [opt_key, config, this](wxEvent &event) {
|
||||||
config->erase(opt_key);
|
config->erase(opt_key);
|
||||||
wxTheApp->CallAfter([this]() {
|
wxTheApp->CallAfter([this]() {
|
||||||
|
wxWindowUpdateLocker noUpdates(m_parent);
|
||||||
update_settings_list();
|
update_settings_list();
|
||||||
m_parent->Layout();
|
m_parent->Layout();
|
||||||
});
|
});
|
||||||
@ -119,7 +122,7 @@ void ObjectSettings::update_settings_list()
|
|||||||
if (cat.second.size() == 1 && cat.second[0] == "extruder")
|
if (cat.second.size() == 1 && cat.second[0] == "extruder")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto optgroup = std::make_shared<ConfigOptionsGroup>(m_parent, cat.first, config, false, extra_column);
|
auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), cat.first, config, false, extra_column);
|
||||||
optgroup->label_width = 15 * wxGetApp().em_unit();//150;
|
optgroup->label_width = 15 * wxGetApp().em_unit();//150;
|
||||||
optgroup->sidetext_width = 7 * wxGetApp().em_unit();//70;
|
optgroup->sidetext_width = 7 * wxGetApp().em_unit();//70;
|
||||||
|
|
||||||
|
@ -769,19 +769,17 @@ void Preview::load_print_as_sla()
|
|||||||
unsigned int n_layers = 0;
|
unsigned int n_layers = 0;
|
||||||
const SLAPrint* print = m_process->sla_print();
|
const SLAPrint* print = m_process->sla_print();
|
||||||
|
|
||||||
std::set<double> zs;
|
std::vector<double> zs;
|
||||||
|
double initial_layer_height = print->material_config().initial_layer_height.value;
|
||||||
for (const SLAPrintObject* obj : print->objects())
|
for (const SLAPrintObject* obj : print->objects())
|
||||||
{
|
|
||||||
double shift_z = obj->get_current_elevation();
|
|
||||||
if (obj->is_step_done(slaposIndexSlices))
|
if (obj->is_step_done(slaposIndexSlices))
|
||||||
{
|
{
|
||||||
const SLAPrintObject::SliceIndex& index = obj->get_slice_index();
|
auto slicerecords = obj->get_slice_records();
|
||||||
for (const SLAPrintObject::SliceIndex::value_type& id : index)
|
auto low_coord = slicerecords.begin()->key();
|
||||||
{
|
for (auto& rec : slicerecords)
|
||||||
zs.insert(shift_z + id.first);
|
zs.emplace_back(initial_layer_height + (rec.key() - low_coord) * SCALING_FACTOR);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
sort_remove_duplicates(zs);
|
||||||
|
|
||||||
n_layers = (unsigned int)zs.size();
|
n_layers = (unsigned int)zs.size();
|
||||||
if (n_layers == 0)
|
if (n_layers == 0)
|
||||||
@ -796,11 +794,7 @@ void Preview::load_print_as_sla()
|
|||||||
show_hide_ui_elements("none");
|
show_hide_ui_elements("none");
|
||||||
|
|
||||||
if (n_layers > 0)
|
if (n_layers > 0)
|
||||||
{
|
update_sliders(zs);
|
||||||
std::vector<double> layer_zs;
|
|
||||||
std::copy(zs.begin(), zs.end(), std::back_inserter(layer_zs));
|
|
||||||
update_sliders(layer_zs);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_loaded = true;
|
m_loaded = true;
|
||||||
}
|
}
|
||||||
|
@ -666,7 +666,7 @@ RENDER_AGAIN:
|
|||||||
m_imgui->end();
|
m_imgui->end();
|
||||||
|
|
||||||
if (m_editing_mode != m_old_editing_state) { // user toggled between editing/non-editing mode
|
if (m_editing_mode != m_old_editing_state) { // user toggled between editing/non-editing mode
|
||||||
m_parent.toggle_sla_auxiliaries_visibility(!m_editing_mode);
|
m_parent.toggle_sla_auxiliaries_visibility(!m_editing_mode, m_model_object, m_active_instance);
|
||||||
force_refresh = true;
|
force_refresh = true;
|
||||||
}
|
}
|
||||||
m_old_editing_state = m_editing_mode;
|
m_old_editing_state = m_editing_mode;
|
||||||
|
@ -327,8 +327,7 @@ void PresetComboBox::set_label_marker(int item, LabelItemType label_item_type)
|
|||||||
|
|
||||||
void PresetComboBox::check_selection()
|
void PresetComboBox::check_selection()
|
||||||
{
|
{
|
||||||
if (this->last_selected != GetSelection())
|
this->last_selected = GetSelection();
|
||||||
this->last_selected = GetSelection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Frequently changed parameters
|
// Frequently changed parameters
|
||||||
@ -829,10 +828,7 @@ void Sidebar::update_presets(Preset::Type preset_type)
|
|||||||
preset_bundle.sla_materials.update_platter_ui(p->combo_sla_material);
|
preset_bundle.sla_materials.update_platter_ui(p->combo_sla_material);
|
||||||
}
|
}
|
||||||
// Update the printer choosers, update the dirty flags.
|
// Update the printer choosers, update the dirty flags.
|
||||||
auto prev_selection = p->combo_printer->GetSelection();
|
|
||||||
preset_bundle.printers.update_platter_ui(p->combo_printer);
|
preset_bundle.printers.update_platter_ui(p->combo_printer);
|
||||||
if (prev_selection != p->combo_printer->GetSelection())
|
|
||||||
p->combo_printer->check_selection();
|
|
||||||
// Update the filament choosers to only contain the compatible presets, update the color preview,
|
// Update the filament choosers to only contain the compatible presets, update the color preview,
|
||||||
// update the dirty flags.
|
// update the dirty flags.
|
||||||
if (print_tech == ptFFF) {
|
if (print_tech == ptFFF) {
|
||||||
@ -1717,8 +1713,8 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
|
|||||||
object->center_around_origin();
|
object->center_around_origin();
|
||||||
new_instances.emplace_back(object->add_instance());
|
new_instances.emplace_back(object->add_instance());
|
||||||
#else /* AUTOPLACEMENT_ON_LOAD */
|
#else /* AUTOPLACEMENT_ON_LOAD */
|
||||||
// if object has no defined position(s) we need to rearrange everything after loading object->center_around_origin();
|
// if object has no defined position(s) we need to rearrange everything after loading
|
||||||
need_arrange = true;
|
need_arrange = true;
|
||||||
// add a default instance and center object around origin
|
// add a default instance and center object around origin
|
||||||
object->center_around_origin(); // also aligns object to Z = 0
|
object->center_around_origin(); // also aligns object to Z = 0
|
||||||
ModelInstance* instance = object->add_instance();
|
ModelInstance* instance = object->add_instance();
|
||||||
|
@ -988,6 +988,7 @@ void PresetCollection::update_platter_ui(GUI::PresetComboBox *ui)
|
|||||||
|
|
||||||
ui->SetSelection(selected_preset_item);
|
ui->SetSelection(selected_preset_item);
|
||||||
ui->SetToolTip(ui->GetString(selected_preset_item));
|
ui->SetToolTip(ui->GetString(selected_preset_item));
|
||||||
|
ui->check_selection();
|
||||||
ui->Thaw();
|
ui->Thaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,9 +11,10 @@
|
|||||||
#include "slic3r/Utils/Semver.hpp"
|
#include "slic3r/Utils/Semver.hpp"
|
||||||
|
|
||||||
class wxBitmap;
|
class wxBitmap;
|
||||||
class wxChoice;
|
|
||||||
class wxBitmapComboBox;
|
class wxBitmapComboBox;
|
||||||
|
class wxChoice;
|
||||||
class wxItemContainer;
|
class wxItemContainer;
|
||||||
|
class wxString;
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
@ -1529,6 +1529,7 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::Pr
|
|||||||
}
|
}
|
||||||
ui->SetSelection(selected_preset_item);
|
ui->SetSelection(selected_preset_item);
|
||||||
ui->SetToolTip(ui->GetString(selected_preset_item));
|
ui->SetToolTip(ui->GetString(selected_preset_item));
|
||||||
|
ui->check_selection();
|
||||||
ui->Thaw();
|
ui->Thaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user