mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-24 09:11:23 -06:00
Merge remote-tracking branch 'origin/master' into ys_msw_dpi
This commit is contained in:
commit
df7ada0199
104 changed files with 2162 additions and 410 deletions
|
|
@ -189,7 +189,6 @@ target_link_libraries(libslic3r
|
|||
clipper
|
||||
nowide
|
||||
${EXPAT_LIBRARIES}
|
||||
${GLEW_LIBRARIES}
|
||||
glu-libtess
|
||||
polypartition
|
||||
poly2tri
|
||||
|
|
|
|||
|
|
@ -593,6 +593,8 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
|
|||
this->origin_translation = rhs.origin_translation;
|
||||
m_bounding_box = rhs.m_bounding_box;
|
||||
m_bounding_box_valid = rhs.m_bounding_box_valid;
|
||||
m_raw_bounding_box = rhs.m_raw_bounding_box;
|
||||
m_raw_bounding_box_valid = rhs.m_raw_bounding_box_valid;
|
||||
m_raw_mesh_bounding_box = rhs.m_raw_mesh_bounding_box;
|
||||
m_raw_mesh_bounding_box_valid = rhs.m_raw_mesh_bounding_box_valid;
|
||||
|
||||
|
|
@ -627,6 +629,8 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
|
|||
this->origin_translation = std::move(rhs.origin_translation);
|
||||
m_bounding_box = std::move(rhs.m_bounding_box);
|
||||
m_bounding_box_valid = std::move(rhs.m_bounding_box_valid);
|
||||
m_raw_bounding_box = rhs.m_raw_bounding_box;
|
||||
m_raw_bounding_box_valid = rhs.m_raw_bounding_box_valid;
|
||||
m_raw_mesh_bounding_box = rhs.m_raw_mesh_bounding_box;
|
||||
m_raw_mesh_bounding_box_valid = rhs.m_raw_mesh_bounding_box_valid;
|
||||
|
||||
|
|
@ -859,7 +863,7 @@ TriangleMesh ModelObject::full_raw_mesh() const
|
|||
return mesh;
|
||||
}
|
||||
|
||||
BoundingBoxf3 ModelObject::raw_mesh_bounding_box() const
|
||||
const BoundingBoxf3& ModelObject::raw_mesh_bounding_box() const
|
||||
{
|
||||
if (! m_raw_mesh_bounding_box_valid) {
|
||||
m_raw_mesh_bounding_box_valid = true;
|
||||
|
|
@ -880,33 +884,36 @@ BoundingBoxf3 ModelObject::full_raw_mesh_bounding_box() const
|
|||
}
|
||||
|
||||
// A transformed snug bounding box around the non-modifier object volumes, without the translation applied.
|
||||
// This bounding box is only used for the actual slicing.
|
||||
BoundingBoxf3 ModelObject::raw_bounding_box() const
|
||||
// This bounding box is only used for the actual slicing and for layer editing UI to calculate the layers.
|
||||
const BoundingBoxf3& ModelObject::raw_bounding_box() const
|
||||
{
|
||||
BoundingBoxf3 bb;
|
||||
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
if (this->instances.empty())
|
||||
throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
|
||||
if (! m_raw_bounding_box_valid) {
|
||||
m_raw_bounding_box_valid = true;
|
||||
m_raw_bounding_box.reset();
|
||||
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
if (this->instances.empty())
|
||||
throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
|
||||
|
||||
const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true);
|
||||
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
for (const ModelVolume *v : this->volumes)
|
||||
if (v->is_model_part()) {
|
||||
#if !ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
if (this->instances.empty())
|
||||
throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
|
||||
#endif // !ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true);
|
||||
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
for (const ModelVolume *v : this->volumes)
|
||||
if (v->is_model_part()) {
|
||||
#if !ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
if (this->instances.empty())
|
||||
throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
|
||||
#endif // !ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
|
||||
TriangleMesh vol_mesh(v->mesh);
|
||||
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
vol_mesh.transform(inst_matrix * v->get_matrix());
|
||||
bb.merge(vol_mesh.bounding_box());
|
||||
#else
|
||||
vol_mesh.transform(v->get_matrix());
|
||||
bb.merge(this->instances.front()->transform_mesh_bounding_box(vol_mesh, true));
|
||||
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
}
|
||||
return bb;
|
||||
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
m_raw_bounding_box.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix()));
|
||||
#else
|
||||
// unmaintaned
|
||||
assert(false);
|
||||
// vol_mesh.transform(v->get_matrix());
|
||||
// m_raw_bounding_box_valid.merge(this->instances.front()->transform_mesh_bounding_box(vol_mesh, true));
|
||||
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
}
|
||||
}
|
||||
return m_raw_bounding_box;
|
||||
}
|
||||
|
||||
// This returns an accurate snug bounding box of the transformed object instance, without the translation applied.
|
||||
|
|
@ -920,13 +927,13 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_
|
|||
{
|
||||
if (v->is_model_part())
|
||||
{
|
||||
TriangleMesh mesh(v->mesh);
|
||||
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
mesh.transform(inst_matrix * v->get_matrix());
|
||||
bb.merge(mesh.bounding_box());
|
||||
bb.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix()));
|
||||
#else
|
||||
mesh.transform(v->get_matrix());
|
||||
bb.merge(this->instances[instance_idx]->transform_mesh_bounding_box(mesh, dont_translate));
|
||||
// not maintained
|
||||
assert(false);
|
||||
//mesh.transform(v->get_matrix());
|
||||
//bb.merge(this->instances[instance_idx]->transform_mesh_bounding_box(mesh, dont_translate));
|
||||
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ public:
|
|||
// This bounding box is approximate and not snug.
|
||||
// This bounding box is being cached.
|
||||
const BoundingBoxf3& bounding_box() const;
|
||||
void invalidate_bounding_box() { m_bounding_box_valid = false; m_raw_mesh_bounding_box_valid = false; }
|
||||
void invalidate_bounding_box() { m_bounding_box_valid = false; m_raw_bounding_box_valid = false; m_raw_mesh_bounding_box_valid = false; }
|
||||
|
||||
// A mesh containing all transformed instances of this object.
|
||||
TriangleMesh mesh() const;
|
||||
|
|
@ -223,11 +223,11 @@ public:
|
|||
TriangleMesh full_raw_mesh() const;
|
||||
// A transformed snug bounding box around the non-modifier object volumes, without the translation applied.
|
||||
// This bounding box is only used for the actual slicing.
|
||||
BoundingBoxf3 raw_bounding_box() const;
|
||||
const BoundingBoxf3& raw_bounding_box() const;
|
||||
// A snug bounding box around the transformed non-modifier object volumes.
|
||||
BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate = false) const;
|
||||
// A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
|
||||
BoundingBoxf3 raw_mesh_bounding_box() const;
|
||||
const BoundingBoxf3& raw_mesh_bounding_box() const;
|
||||
// A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.
|
||||
BoundingBoxf3 full_raw_mesh_bounding_box() const;
|
||||
|
||||
|
|
@ -285,7 +285,7 @@ protected:
|
|||
|
||||
private:
|
||||
ModelObject(Model *model) : m_model(model), origin_translation(Vec3d::Zero()),
|
||||
m_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) {}
|
||||
m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) {}
|
||||
~ModelObject();
|
||||
|
||||
/* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */
|
||||
|
|
@ -304,6 +304,8 @@ private:
|
|||
// Bounding box, cached.
|
||||
mutable BoundingBoxf3 m_bounding_box;
|
||||
mutable bool m_bounding_box_valid;
|
||||
mutable BoundingBoxf3 m_raw_bounding_box;
|
||||
mutable bool m_raw_bounding_box_valid;
|
||||
mutable BoundingBoxf3 m_raw_mesh_bounding_box;
|
||||
mutable bool m_raw_mesh_bounding_box_valid;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ public:
|
|||
// The slicing parameters are dependent on various configuration values
|
||||
// (layer height, first layer height, raft settings, print nozzle diameter etc).
|
||||
const SlicingParameters& slicing_parameters() const { return m_slicing_params; }
|
||||
static SlicingParameters slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object);
|
||||
static SlicingParameters slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object, float object_max_z);
|
||||
|
||||
// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
|
||||
std::vector<unsigned int> object_extruders() const;
|
||||
|
|
|
|||
|
|
@ -2528,14 +2528,17 @@ void PrintConfigDef::init_sla_params()
|
|||
|
||||
def = this->add("pad_wall_height", coFloat);
|
||||
def->label = L("Pad wall height");
|
||||
def->tooltip = L("Defines the cavity depth. Set to zero to disable the cavity.");
|
||||
def->tooltip = L("Defines the pad cavity depth. Set to zero to disable the cavity. "
|
||||
"Be careful when enabling this feature, as some resins may "
|
||||
"produce an extreme suction effect inside the cavity, "
|
||||
"which makes pealing the print off the vat foil difficult.");
|
||||
def->category = L("Pad");
|
||||
// def->tooltip = L("");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->max = 30;
|
||||
def->mode = comSimple;
|
||||
def->default_value = new ConfigOptionFloat(5.0);
|
||||
def->mode = comExpert;
|
||||
def->default_value = new ConfigOptionFloat(0.);
|
||||
|
||||
def = this->add("pad_max_merge_distance", coFloat);
|
||||
def->label = L("Max merge distance");
|
||||
|
|
@ -3114,6 +3117,13 @@ CLIMiscConfigDef::CLIMiscConfigDef()
|
|||
def->label = L("Logging level");
|
||||
def->tooltip = L("Messages with severity lower or eqal to the loglevel will be printed out. 0:trace, 1:debug, 2:info, 3:warning, 4:error, 5:fatal");
|
||||
def->min = 0;
|
||||
|
||||
#if defined(_MSC_VER) && defined(SLIC3R_GUI)
|
||||
def = this->add("sw_renderer", coBool);
|
||||
def->label = L("Render with a software renderer");
|
||||
def->tooltip = L("Render with a software renderer. The bundled MESA software renderer is loaded instead of the default OpenGL driver.");
|
||||
def->min = 0;
|
||||
#endif /* _MSC_VER */
|
||||
}
|
||||
|
||||
const CLIActionsConfigDef cli_actions_config_def;
|
||||
|
|
|
|||
|
|
@ -1370,7 +1370,7 @@ void PrintObject::update_slicing_parameters()
|
|||
this->print()->config(), m_config, unscale<double>(this->size(2)), this->object_extruders());
|
||||
}
|
||||
|
||||
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object)
|
||||
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object, float object_max_z)
|
||||
{
|
||||
PrintConfig print_config;
|
||||
PrintObjectConfig object_config;
|
||||
|
|
@ -1390,7 +1390,9 @@ SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full
|
|||
object_extruders);
|
||||
sort_remove_duplicates(object_extruders);
|
||||
|
||||
return SlicingParameters::create_from_config(print_config, object_config, model_object.bounding_box().max.z(), object_extruders);
|
||||
if (object_max_z <= 0.f)
|
||||
object_max_z = model_object.raw_bounding_box().size().z();
|
||||
return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders);
|
||||
}
|
||||
|
||||
// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
|
||||
|
|
|
|||
|
|
@ -1572,10 +1572,8 @@ public:
|
|||
auto hit = bridge_mesh_intersect(headjp, n, r);
|
||||
|
||||
if(std::isinf(hit.distance())) ground_head_indices.emplace_back(i);
|
||||
else {
|
||||
if(m_cfg.ground_facing_only) head.invalidate();
|
||||
m_iheads_onmodel.emplace_back(std::make_pair(i, hit));
|
||||
}
|
||||
else if(m_cfg.ground_facing_only) head.invalidate();
|
||||
else m_iheads_onmodel.emplace_back(std::make_pair(i, hit));
|
||||
}
|
||||
|
||||
// We want to search for clusters of points that are far enough
|
||||
|
|
@ -1872,7 +1870,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void cascade_pillars() {
|
||||
void interconnect_pillars() {
|
||||
// Now comes the algorithm that connects pillars with each other.
|
||||
// Ideally every pillar should be connected with at least one of its
|
||||
// neighbors if that neighbor is within max_pillar_link_distance
|
||||
|
|
@ -2121,7 +2119,7 @@ bool SLASupportTree::generate(const std::vector<SupportPoint> &support_points,
|
|||
|
||||
std::bind(&Algorithm::routing_to_model, &alg),
|
||||
|
||||
std::bind(&Algorithm::cascade_pillars, &alg),
|
||||
std::bind(&Algorithm::interconnect_pillars, &alg),
|
||||
|
||||
std::bind(&Algorithm::routing_headless, &alg),
|
||||
|
||||
|
|
@ -2150,16 +2148,16 @@ bool SLASupportTree::generate(const std::vector<SupportPoint> &support_points,
|
|||
// Let's define a simple automaton that will run our program.
|
||||
auto progress = [&ctl, &pc] () {
|
||||
static const std::array<std::string, NUM_STEPS> stepstr {
|
||||
L("Starting"),
|
||||
L("Filtering"),
|
||||
L("Generate pinheads"),
|
||||
L("Classification"),
|
||||
L("Routing to ground"),
|
||||
L("Routing supports to model surface"),
|
||||
L("Cascading pillars"),
|
||||
L("Processing small holes"),
|
||||
L("Done"),
|
||||
L("Abort")
|
||||
"Starting",
|
||||
"Filtering",
|
||||
"Generate pinheads",
|
||||
"Classification",
|
||||
"Routing to ground",
|
||||
"Routing supports to model surface",
|
||||
"Interconnecting pillars",
|
||||
"Processing small holes",
|
||||
"Done",
|
||||
"Abort"
|
||||
};
|
||||
|
||||
static const std::array<unsigned, NUM_STEPS> stepstate {
|
||||
|
|
|
|||
|
|
@ -693,6 +693,16 @@ void TriangleMeshSlicer::init(TriangleMesh *_mesh, throw_on_cancel_callback_type
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TriangleMeshSlicer::set_up_direction(const Vec3f& up)
|
||||
{
|
||||
m_quaternion.setFromTwoVectors(up, Vec3f::UnitZ());
|
||||
m_use_quaternion = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::slice";
|
||||
|
|
@ -795,7 +805,7 @@ void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons
|
|||
void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLines>* lines, boost::mutex* lines_mutex,
|
||||
const std::vector<float> &z) const
|
||||
{
|
||||
const stl_facet &facet = this->mesh->stl.facet_start[facet_idx];
|
||||
const stl_facet &facet = m_use_quaternion ? this->mesh->stl.facet_start[facet_idx].rotated(m_quaternion) : this->mesh->stl.facet_start[facet_idx];
|
||||
|
||||
// find facet extents
|
||||
const float min_z = fminf(facet.vertex[0](2), fminf(facet.vertex[1](2), facet.vertex[2](2)));
|
||||
|
|
@ -860,26 +870,43 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet(
|
|||
IntersectionPoint points[3];
|
||||
size_t num_points = 0;
|
||||
size_t point_on_layer = size_t(-1);
|
||||
|
||||
|
||||
// Reorder vertices so that the first one is the one with lowest Z.
|
||||
// This is needed to get all intersection lines in a consistent order
|
||||
// (external on the right of the line)
|
||||
const int *vertices = this->mesh->stl.v_indices[facet_idx].vertex;
|
||||
int i = (facet.vertex[1].z() == min_z) ? 1 : ((facet.vertex[2].z() == min_z) ? 2 : 0);
|
||||
|
||||
// These are used only if the cut plane is tilted:
|
||||
stl_vertex rotated_a;
|
||||
stl_vertex rotated_b;
|
||||
|
||||
for (int j = i; j - i < 3; ++j) { // loop through facet edges
|
||||
int edge_id = this->facets_edges[facet_idx * 3 + (j % 3)];
|
||||
int a_id = vertices[j % 3];
|
||||
int b_id = vertices[(j+1) % 3];
|
||||
const stl_vertex *a = &this->v_scaled_shared[a_id];
|
||||
const stl_vertex *b = &this->v_scaled_shared[b_id];
|
||||
|
||||
const stl_vertex *a;
|
||||
const stl_vertex *b;
|
||||
if (m_use_quaternion) {
|
||||
rotated_a = m_quaternion * this->v_scaled_shared[a_id];
|
||||
rotated_b = m_quaternion * this->v_scaled_shared[b_id];
|
||||
a = &rotated_a;
|
||||
b = &rotated_b;
|
||||
}
|
||||
else {
|
||||
a = &this->v_scaled_shared[a_id];
|
||||
b = &this->v_scaled_shared[b_id];
|
||||
}
|
||||
|
||||
// Is edge or face aligned with the cutting plane?
|
||||
if (a->z() == slice_z && b->z() == slice_z) {
|
||||
// Edge is horizontal and belongs to the current layer.
|
||||
const stl_vertex &v0 = this->v_scaled_shared[vertices[0]];
|
||||
const stl_vertex &v1 = this->v_scaled_shared[vertices[1]];
|
||||
const stl_vertex &v2 = this->v_scaled_shared[vertices[2]];
|
||||
const stl_normal &normal = this->mesh->stl.facet_start[facet_idx].normal;
|
||||
// The following rotation of the three vertices may not be efficient, but this branch happens rarely.
|
||||
const stl_vertex &v0 = m_use_quaternion ? stl_vertex(m_quaternion * this->v_scaled_shared[vertices[0]]) : this->v_scaled_shared[vertices[0]];
|
||||
const stl_vertex &v1 = m_use_quaternion ? stl_vertex(m_quaternion * this->v_scaled_shared[vertices[1]]) : this->v_scaled_shared[vertices[1]];
|
||||
const stl_vertex &v2 = m_use_quaternion ? stl_vertex(m_quaternion * this->v_scaled_shared[vertices[2]]) : this->v_scaled_shared[vertices[2]];
|
||||
const stl_normal &normal = facet.normal;
|
||||
// We may ignore this edge for slicing purposes, but we may still use it for object cutting.
|
||||
FacetSliceType result = Slicing;
|
||||
if (min_z == max_z) {
|
||||
|
|
@ -995,7 +1022,9 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet(
|
|||
if (i == line_out->a_id || i == line_out->b_id)
|
||||
i = vertices[2];
|
||||
assert(i != line_out->a_id && i != line_out->b_id);
|
||||
line_out->edge_type = (this->v_scaled_shared[i].z() < slice_z) ? feTop : feBottom;
|
||||
line_out->edge_type = ((m_use_quaternion ?
|
||||
(m_quaternion * this->v_scaled_shared[i]).z()
|
||||
: this->v_scaled_shared[i].z()) < slice_z) ? feTop : feBottom;
|
||||
}
|
||||
#endif
|
||||
return Slicing;
|
||||
|
|
|
|||
|
|
@ -25,9 +25,10 @@ public:
|
|||
TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd> &facets);
|
||||
TriangleMesh(const TriangleMesh &other) : repaired(false) { stl_initialize(&this->stl); *this = other; }
|
||||
TriangleMesh(TriangleMesh &&other) : repaired(false) { stl_initialize(&this->stl); this->swap(other); }
|
||||
~TriangleMesh() { stl_close(&this->stl); }
|
||||
~TriangleMesh() { clear(); }
|
||||
TriangleMesh& operator=(const TriangleMesh &other);
|
||||
TriangleMesh& operator=(TriangleMesh &&other) { this->swap(other); return *this; }
|
||||
void clear() { stl_close(&this->stl); this->repaired = false; }
|
||||
void swap(TriangleMesh &other) { std::swap(this->stl, other.stl); std::swap(this->repaired, other.repaired); }
|
||||
void ReadSTLFile(const char* input_file) { stl_open(&stl, input_file); }
|
||||
void write_ascii(const char* output_file) { stl_write_ascii(&this->stl, output_file, ""); }
|
||||
|
|
@ -171,6 +172,7 @@ public:
|
|||
FacetSliceType slice_facet(float slice_z, const stl_facet &facet, const int facet_idx,
|
||||
const float min_z, const float max_z, IntersectionLine *line_out) const;
|
||||
void cut(float z, TriangleMesh* upper, TriangleMesh* lower) const;
|
||||
void set_up_direction(const Vec3f& up);
|
||||
|
||||
private:
|
||||
const TriangleMesh *mesh;
|
||||
|
|
@ -178,6 +180,10 @@ private:
|
|||
std::vector<int> facets_edges;
|
||||
// Scaled copy of this->mesh->stl.v_shared
|
||||
std::vector<stl_vertex> v_scaled_shared;
|
||||
// Quaternion that will be used to rotate every facet before the slicing
|
||||
Eigen::Quaternion<float, Eigen::DontAlign> m_quaternion;
|
||||
// Whether or not the above quaterion should be used
|
||||
bool m_use_quaternion = false;
|
||||
|
||||
void _slice_do(size_t facet_idx, std::vector<IntersectionLines>* lines, boost::mutex* lines_mutex, const std::vector<float> &z) const;
|
||||
void make_loops(std::vector<IntersectionLine> &lines, Polygons* loops) const;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue