mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Use of bounding box of rotated 3D convex hull for out of print volume detection
This commit is contained in:
		
							parent
							
								
									211790f8c3
								
							
						
					
					
						commit
						4d98d32199
					
				
					 12 changed files with 276 additions and 141 deletions
				
			
		| 
						 | 
				
			
			@ -1491,6 +1491,7 @@ namespace Slic3r {
 | 
			
		|||
 | 
			
		||||
            stl_get_size(&stl);
 | 
			
		||||
            volume->mesh.repair();
 | 
			
		||||
            volume->calculate_convex_hull();
 | 
			
		||||
 | 
			
		||||
            // apply volume's name and config data
 | 
			
		||||
            for (const Metadata& metadata : volume_data.metadata)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -406,6 +406,7 @@ void AMFParserContext::endElement(const char * /* name */)
 | 
			
		|||
        }
 | 
			
		||||
        stl_get_size(&stl);
 | 
			
		||||
        m_volume->mesh.repair();
 | 
			
		||||
        m_volume->calculate_convex_hull();
 | 
			
		||||
        m_volume_facets.clear();
 | 
			
		||||
        m_volume = nullptr;
 | 
			
		||||
        break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,6 +17,11 @@
 | 
			
		|||
#include "SVG.hpp"
 | 
			
		||||
#include <Eigen/Dense>
 | 
			
		||||
 | 
			
		||||
static const float UNIT_MATRIX[] = { 1.0f, 0.0f, 0.0f, 0.0f,
 | 
			
		||||
                                     0.0f, 1.0f, 0.0f, 0.0f,
 | 
			
		||||
                                     0.0f, 0.0f, 1.0f, 0.0f,
 | 
			
		||||
                                     0.0f, 0.0f, 0.0f, 1.0f };
 | 
			
		||||
 | 
			
		||||
namespace Slic3r {
 | 
			
		||||
 | 
			
		||||
    unsigned int Model::s_auto_extruder_id = 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -235,14 +240,6 @@ BoundingBoxf3 Model::bounding_box() const
 | 
			
		|||
    return bb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundingBoxf3 Model::transformed_bounding_box() const
 | 
			
		||||
{
 | 
			
		||||
    BoundingBoxf3 bb;
 | 
			
		||||
    for (const ModelObject* obj : this->objects)
 | 
			
		||||
        bb.merge(obj->tight_bounding_box(false));
 | 
			
		||||
    return bb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Model::center_instances_around_point(const Pointf &point)
 | 
			
		||||
{
 | 
			
		||||
//    BoundingBoxf3 bb = this->bounding_box();
 | 
			
		||||
| 
						 | 
				
			
			@ -623,54 +620,6 @@ const BoundingBoxf3& ModelObject::bounding_box() const
 | 
			
		|||
    return m_bounding_box;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundingBoxf3 ModelObject::tight_bounding_box(bool include_modifiers) const
 | 
			
		||||
{
 | 
			
		||||
    BoundingBoxf3 bb;
 | 
			
		||||
 | 
			
		||||
    for (const ModelVolume* vol : this->volumes)
 | 
			
		||||
    {
 | 
			
		||||
        if (include_modifiers || !vol->modifier)
 | 
			
		||||
        {
 | 
			
		||||
            for (const ModelInstance* inst : this->instances)
 | 
			
		||||
            {
 | 
			
		||||
                double c = cos(inst->rotation);
 | 
			
		||||
                double s = sin(inst->rotation);
 | 
			
		||||
 | 
			
		||||
                for (int f = 0; f < vol->mesh.stl.stats.number_of_facets; ++f)
 | 
			
		||||
                {
 | 
			
		||||
                    const stl_facet& facet = vol->mesh.stl.facet_start[f];
 | 
			
		||||
 | 
			
		||||
                    for (int i = 0; i < 3; ++i)
 | 
			
		||||
                    {
 | 
			
		||||
                        // original point
 | 
			
		||||
                        const stl_vertex& v = facet.vertex[i];
 | 
			
		||||
                        Pointf3 p((double)v.x, (double)v.y, (double)v.z);
 | 
			
		||||
 | 
			
		||||
                        // scale
 | 
			
		||||
                        p.x *= inst->scaling_factor;
 | 
			
		||||
                        p.y *= inst->scaling_factor;
 | 
			
		||||
                        p.z *= inst->scaling_factor;
 | 
			
		||||
 | 
			
		||||
                        // rotate Z
 | 
			
		||||
                        double x = p.x;
 | 
			
		||||
                        double y = p.y;
 | 
			
		||||
                        p.x = c * x - s * y;
 | 
			
		||||
                        p.y = s * x + c * y;
 | 
			
		||||
 | 
			
		||||
                        // translate
 | 
			
		||||
                        p.x += inst->offset.x;
 | 
			
		||||
                        p.y += inst->offset.y;
 | 
			
		||||
 | 
			
		||||
                        bb.merge(p);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return bb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A mesh containing all transformed instances of this object.
 | 
			
		||||
TriangleMesh ModelObject::mesh() const
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -755,15 +704,22 @@ void ModelObject::center_around_origin()
 | 
			
		|||
void ModelObject::translate(coordf_t x, coordf_t y, coordf_t z)
 | 
			
		||||
{
 | 
			
		||||
    for (ModelVolume *v : this->volumes)
 | 
			
		||||
    {
 | 
			
		||||
        v->mesh.translate(float(x), float(y), float(z));
 | 
			
		||||
    if (m_bounding_box_valid) 
 | 
			
		||||
        v->m_convex_hull.translate(float(x), float(y), float(z));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (m_bounding_box_valid)
 | 
			
		||||
        m_bounding_box.translate(x, y, z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ModelObject::scale(const Pointf3 &versor)
 | 
			
		||||
{
 | 
			
		||||
    for (ModelVolume *v : this->volumes)
 | 
			
		||||
    {
 | 
			
		||||
        v->mesh.scale(versor);
 | 
			
		||||
        v->m_convex_hull.scale(versor);
 | 
			
		||||
    }
 | 
			
		||||
    // reset origin translation since it doesn't make sense anymore
 | 
			
		||||
    this->origin_translation = Pointf3(0,0,0);
 | 
			
		||||
    this->invalidate_bounding_box();
 | 
			
		||||
| 
						 | 
				
			
			@ -774,6 +730,7 @@ void ModelObject::rotate(float angle, const Axis &axis)
 | 
			
		|||
    for (ModelVolume *v : this->volumes)
 | 
			
		||||
    {
 | 
			
		||||
        v->mesh.rotate(angle, axis);
 | 
			
		||||
        v->m_convex_hull.rotate(angle, axis);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    center_around_origin();
 | 
			
		||||
| 
						 | 
				
			
			@ -790,6 +747,7 @@ void ModelObject::transform(const float* matrix3x4)
 | 
			
		|||
    for (ModelVolume* v : volumes)
 | 
			
		||||
    {
 | 
			
		||||
        v->mesh.transform(matrix3x4);
 | 
			
		||||
        v->m_convex_hull.transform(matrix3x4);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    origin_translation = Pointf3(0.0, 0.0, 0.0);
 | 
			
		||||
| 
						 | 
				
			
			@ -799,8 +757,12 @@ void ModelObject::transform(const float* matrix3x4)
 | 
			
		|||
void ModelObject::mirror(const Axis &axis)
 | 
			
		||||
{
 | 
			
		||||
    for (ModelVolume *v : this->volumes)
 | 
			
		||||
    {
 | 
			
		||||
        v->mesh.mirror(axis);
 | 
			
		||||
    this->origin_translation = Pointf3(0,0,0);
 | 
			
		||||
        v->m_convex_hull.mirror(axis);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this->origin_translation = Pointf3(0, 0, 0);
 | 
			
		||||
    this->invalidate_bounding_box();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -904,45 +866,20 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
 | 
			
		|||
 | 
			
		||||
void ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume)
 | 
			
		||||
{
 | 
			
		||||
    for (ModelVolume* vol : this->volumes)
 | 
			
		||||
    for (const ModelVolume* vol : this->volumes)
 | 
			
		||||
    {
 | 
			
		||||
        if (!vol->modifier)
 | 
			
		||||
        {
 | 
			
		||||
            for (ModelInstance* inst : this->instances)
 | 
			
		||||
            {
 | 
			
		||||
                BoundingBoxf3 bb;
 | 
			
		||||
                std::vector<float> world_mat(UNIT_MATRIX, std::end(UNIT_MATRIX));
 | 
			
		||||
                Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
 | 
			
		||||
                m.translate(Eigen::Vector3f((float)inst->offset.x, (float)inst->offset.y, 0.0f));
 | 
			
		||||
                m.rotate(Eigen::AngleAxisf(inst->rotation, Eigen::Vector3f::UnitZ()));
 | 
			
		||||
                m.scale(inst->scaling_factor);
 | 
			
		||||
                ::memcpy((void*)world_mat.data(), (const void*)m.data(), 16 * sizeof(float));
 | 
			
		||||
 | 
			
		||||
                double c = cos(inst->rotation);
 | 
			
		||||
                double s = sin(inst->rotation);
 | 
			
		||||
 | 
			
		||||
                for (int f = 0; f < vol->mesh.stl.stats.number_of_facets; ++f)
 | 
			
		||||
                {
 | 
			
		||||
                    const stl_facet& facet = vol->mesh.stl.facet_start[f];
 | 
			
		||||
 | 
			
		||||
                    for (int i = 0; i < 3; ++i)
 | 
			
		||||
                    {
 | 
			
		||||
                        // original point
 | 
			
		||||
                        const stl_vertex& v = facet.vertex[i];
 | 
			
		||||
                        Pointf3 p((double)v.x, (double)v.y, (double)v.z);
 | 
			
		||||
 | 
			
		||||
                        // scale
 | 
			
		||||
                        p.x *= inst->scaling_factor;
 | 
			
		||||
                        p.y *= inst->scaling_factor;
 | 
			
		||||
                        p.z *= inst->scaling_factor;
 | 
			
		||||
 | 
			
		||||
                        // rotate Z
 | 
			
		||||
                        double x = p.x;
 | 
			
		||||
                        double y = p.y;
 | 
			
		||||
                        p.x = c * x - s * y;
 | 
			
		||||
                        p.y = s * x + c * y;
 | 
			
		||||
 | 
			
		||||
                        // translate
 | 
			
		||||
                        p.x += inst->offset.x;
 | 
			
		||||
                        p.y += inst->offset.y;
 | 
			
		||||
 | 
			
		||||
                        bb.merge(p);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(world_mat);
 | 
			
		||||
 | 
			
		||||
                if (print_volume.contains(bb))
 | 
			
		||||
                    inst->print_volume_state = ModelInstance::PVS_Inside;
 | 
			
		||||
| 
						 | 
				
			
			@ -1025,6 +962,16 @@ ModelMaterial* ModelVolume::assign_unique_material()
 | 
			
		|||
    return model->add_material(this->_material_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ModelVolume::calculate_convex_hull()
 | 
			
		||||
{
 | 
			
		||||
    m_convex_hull = mesh.convex_hull_3d();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const TriangleMesh& ModelVolume::get_convex_hull() const
 | 
			
		||||
{
 | 
			
		||||
    return m_convex_hull;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Split this volume, append the result to the object owning this volume.
 | 
			
		||||
// Return the number of volumes created from this one.
 | 
			
		||||
// This is useful to assign different materials to different volumes of an object.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -105,9 +105,6 @@ public:
 | 
			
		|||
    // This bounding box is being cached.
 | 
			
		||||
    const BoundingBoxf3& bounding_box() const;
 | 
			
		||||
    void invalidate_bounding_box() { m_bounding_box_valid = false; }
 | 
			
		||||
    // Returns a snug bounding box of the transformed instances.
 | 
			
		||||
    // This bounding box is not being cached.
 | 
			
		||||
    BoundingBoxf3 tight_bounding_box(bool include_modifiers) const;
 | 
			
		||||
 | 
			
		||||
    // A mesh containing all transformed instances of this object.
 | 
			
		||||
    TriangleMesh mesh() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -157,6 +154,10 @@ private:
 | 
			
		|||
class ModelVolume
 | 
			
		||||
{
 | 
			
		||||
    friend class ModelObject;
 | 
			
		||||
 | 
			
		||||
    // The convex hull of this model's mesh.
 | 
			
		||||
    TriangleMesh m_convex_hull;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    std::string name;
 | 
			
		||||
    // The triangular model.
 | 
			
		||||
| 
						 | 
				
			
			@ -180,19 +181,32 @@ public:
 | 
			
		|||
 | 
			
		||||
    ModelMaterial* assign_unique_material();
 | 
			
		||||
    
 | 
			
		||||
    void calculate_convex_hull();
 | 
			
		||||
    const TriangleMesh& get_convex_hull() const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    // Parent object owning this ModelVolume.
 | 
			
		||||
    ModelObject* object;
 | 
			
		||||
    t_model_material_id _material_id;
 | 
			
		||||
    
 | 
			
		||||
    ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), modifier(false), object(object) {}
 | 
			
		||||
    ModelVolume(ModelObject *object, TriangleMesh &&mesh) : mesh(std::move(mesh)), modifier(false), object(object) {}
 | 
			
		||||
    ModelVolume(ModelObject *object, const ModelVolume &other) : 
 | 
			
		||||
        name(other.name), mesh(other.mesh), config(other.config), modifier(other.modifier), object(object)
 | 
			
		||||
        { this->material_id(other.material_id()); }
 | 
			
		||||
    ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) : 
 | 
			
		||||
    ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), modifier(false), object(object)
 | 
			
		||||
    {
 | 
			
		||||
        if (mesh.stl.stats.number_of_facets > 1)
 | 
			
		||||
            calculate_convex_hull();
 | 
			
		||||
    }
 | 
			
		||||
    ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) : mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), modifier(false), object(object) {}
 | 
			
		||||
    ModelVolume(ModelObject *object, const ModelVolume &other) :
 | 
			
		||||
        name(other.name), mesh(other.mesh), m_convex_hull(other.m_convex_hull), config(other.config), modifier(other.modifier), object(object)
 | 
			
		||||
    {
 | 
			
		||||
        this->material_id(other.material_id());
 | 
			
		||||
    }
 | 
			
		||||
    ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) :
 | 
			
		||||
        name(other.name), mesh(std::move(mesh)), config(other.config), modifier(other.modifier), object(object)
 | 
			
		||||
        { this->material_id(other.material_id()); }
 | 
			
		||||
    {
 | 
			
		||||
        this->material_id(other.material_id());
 | 
			
		||||
        if (mesh.stl.stats.number_of_facets > 1)
 | 
			
		||||
            calculate_convex_hull();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// A single instance of a ModelObject.
 | 
			
		||||
| 
						 | 
				
			
			@ -285,8 +299,6 @@ public:
 | 
			
		|||
    bool add_default_instances();
 | 
			
		||||
    // Returns approximate axis aligned bounding box of this model
 | 
			
		||||
    BoundingBoxf3 bounding_box() const;
 | 
			
		||||
    // Returns tight axis aligned bounding box of this model
 | 
			
		||||
    BoundingBoxf3 transformed_bounding_box() const;
 | 
			
		||||
    void center_instances_around_point(const Pointf &point);
 | 
			
		||||
    void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); }
 | 
			
		||||
    TriangleMesh mesh() const;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,9 @@
 | 
			
		|||
#include "TriangleMesh.hpp"
 | 
			
		||||
#include "ClipperUtils.hpp"
 | 
			
		||||
#include "Geometry.hpp"
 | 
			
		||||
#include "qhull/src/libqhullcpp/Qhull.h"
 | 
			
		||||
#include "qhull/src/libqhullcpp/QhullFacetList.h"
 | 
			
		||||
#include "qhull/src/libqhullcpp/QhullVertexSet.h"
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <deque>
 | 
			
		||||
#include <queue>
 | 
			
		||||
| 
						 | 
				
			
			@ -15,6 +18,8 @@
 | 
			
		|||
 | 
			
		||||
#include <tbb/parallel_for.h>
 | 
			
		||||
 | 
			
		||||
#include <Eigen/Dense>
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
    #define DEBUG
 | 
			
		||||
    #define _DEBUG
 | 
			
		||||
| 
						 | 
				
			
			@ -597,6 +602,134 @@ TriangleMesh::bounding_box() const
 | 
			
		|||
    return bb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundingBoxf3 TriangleMesh::transformed_bounding_box(const std::vector<float>& matrix) const
 | 
			
		||||
{
 | 
			
		||||
    bool has_shared = (stl.v_shared != nullptr);
 | 
			
		||||
    if (!has_shared)
 | 
			
		||||
        stl_generate_shared_vertices(&stl);
 | 
			
		||||
 | 
			
		||||
    unsigned int vertices_count = (stl.stats.shared_vertices > 0) ? (unsigned int)stl.stats.shared_vertices : 3 * (unsigned int)stl.stats.number_of_facets;
 | 
			
		||||
 | 
			
		||||
    if (vertices_count == 0)
 | 
			
		||||
        return BoundingBoxf3();
 | 
			
		||||
 | 
			
		||||
    Eigen::MatrixXf src_vertices(3, vertices_count);
 | 
			
		||||
 | 
			
		||||
    if (stl.stats.shared_vertices > 0)
 | 
			
		||||
    {
 | 
			
		||||
        stl_vertex* vertex_ptr = stl.v_shared;
 | 
			
		||||
        for (int i = 0; i < stl.stats.shared_vertices; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            src_vertices(0, i) = vertex_ptr->x;
 | 
			
		||||
            src_vertices(1, i) = vertex_ptr->y;
 | 
			
		||||
            src_vertices(2, i) = vertex_ptr->z;
 | 
			
		||||
            vertex_ptr += 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        stl_facet* facet_ptr = stl.facet_start;
 | 
			
		||||
        unsigned int v_id = 0;
 | 
			
		||||
        while (facet_ptr < stl.facet_start + stl.stats.number_of_facets)
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < 3; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                src_vertices(0, v_id) = facet_ptr->vertex[i].x;
 | 
			
		||||
                src_vertices(1, v_id) = facet_ptr->vertex[i].y;
 | 
			
		||||
                src_vertices(2, v_id) = facet_ptr->vertex[i].z;
 | 
			
		||||
            }
 | 
			
		||||
            facet_ptr += 1;
 | 
			
		||||
            ++v_id;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!has_shared && (stl.stats.shared_vertices > 0))
 | 
			
		||||
        stl_invalidate_shared_vertices(&stl);
 | 
			
		||||
 | 
			
		||||
    Eigen::Transform<float, 3, Eigen::Affine> m;
 | 
			
		||||
    ::memcpy((void*)m.data(), (const void*)matrix.data(), 16 * sizeof(float));
 | 
			
		||||
 | 
			
		||||
    Eigen::MatrixXf dst_vertices(3, vertices_count);
 | 
			
		||||
    dst_vertices = m * src_vertices.colwise().homogeneous();
 | 
			
		||||
 | 
			
		||||
    float min_x = dst_vertices(0, 0);
 | 
			
		||||
    float max_x = dst_vertices(0, 0);
 | 
			
		||||
    float min_y = dst_vertices(1, 0);
 | 
			
		||||
    float max_y = dst_vertices(1, 0);
 | 
			
		||||
    float min_z = dst_vertices(2, 0);
 | 
			
		||||
    float max_z = dst_vertices(2, 0);
 | 
			
		||||
 | 
			
		||||
    for (int i = 1; i < vertices_count; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        min_x = std::min(min_x, dst_vertices(0, i));
 | 
			
		||||
        max_x = std::max(max_x, dst_vertices(0, i));
 | 
			
		||||
        min_y = std::min(min_y, dst_vertices(1, i));
 | 
			
		||||
        max_y = std::max(max_y, dst_vertices(1, i));
 | 
			
		||||
        min_z = std::min(min_z, dst_vertices(2, i));
 | 
			
		||||
        max_z = std::max(max_z, dst_vertices(2, i));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return BoundingBoxf3(Pointf3((coordf_t)min_x, (coordf_t)min_y, (coordf_t)min_z), Pointf3((coordf_t)max_x, (coordf_t)max_y, (coordf_t)max_z));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TriangleMesh TriangleMesh::convex_hull_3d() const
 | 
			
		||||
{
 | 
			
		||||
    // Helper struct for qhull:
 | 
			
		||||
    struct PointForQHull{
 | 
			
		||||
        PointForQHull(float x_p, float y_p, float z_p) : x((realT)x_p), y((realT)y_p), z((realT)z_p) {}
 | 
			
		||||
        realT x, y, z;
 | 
			
		||||
    };
 | 
			
		||||
    std::vector<PointForQHull> src_vertices;
 | 
			
		||||
 | 
			
		||||
    // We will now fill the vector with input points for computation:
 | 
			
		||||
    stl_facet* facet_ptr = stl.facet_start;
 | 
			
		||||
    while (facet_ptr < stl.facet_start + stl.stats.number_of_facets)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < 3; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            const stl_vertex& v = facet_ptr->vertex[i];
 | 
			
		||||
            src_vertices.emplace_back(v.x, v.y, v.z);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        facet_ptr += 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The qhull call:
 | 
			
		||||
    orgQhull::Qhull qhull;
 | 
			
		||||
    qhull.disableOutputStream(); // we want qhull to be quiet
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        qhull.runQhull("", 3, (int)src_vertices.size(), (const realT*)(src_vertices.data()), "Qt");
 | 
			
		||||
    }
 | 
			
		||||
    catch (...)
 | 
			
		||||
    {
 | 
			
		||||
        std::cout << "Unable to create convex hull" << std::endl;
 | 
			
		||||
        return TriangleMesh();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Let's collect results:
 | 
			
		||||
    Pointf3s det_vertices;
 | 
			
		||||
    std::vector<Point3> facets;
 | 
			
		||||
    auto facet_list = qhull.facetList().toStdVector();
 | 
			
		||||
    for (const orgQhull::QhullFacet& facet : facet_list)
 | 
			
		||||
    {   // iterate through facets
 | 
			
		||||
        orgQhull::QhullVertexSet vertices = facet.vertices();
 | 
			
		||||
        for (int i = 0; i < 3; ++i)
 | 
			
		||||
        {   // iterate through facet's vertices
 | 
			
		||||
 | 
			
		||||
            orgQhull::QhullPoint p = vertices[i].point();
 | 
			
		||||
            const float* coords = p.coordinates();
 | 
			
		||||
            det_vertices.emplace_back(coords[0], coords[1], coords[2]);
 | 
			
		||||
        }
 | 
			
		||||
        unsigned int size = (unsigned int)det_vertices.size();
 | 
			
		||||
        facets.emplace_back(size - 3, size - 2, size - 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    TriangleMesh output_mesh(det_vertices, facets);
 | 
			
		||||
    output_mesh.repair();
 | 
			
		||||
    return output_mesh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
TriangleMesh::require_shared_vertices()
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,6 +55,10 @@ public:
 | 
			
		|||
    ExPolygons horizontal_projection() const;
 | 
			
		||||
    Polygon convex_hull();
 | 
			
		||||
    BoundingBoxf3 bounding_box() const;
 | 
			
		||||
    // Returns the bbox of this TriangleMesh transformed by the given matrix
 | 
			
		||||
    BoundingBoxf3 transformed_bounding_box(const std::vector<float>& matrix) const;
 | 
			
		||||
    // Returns the convex hull of this TriangleMesh
 | 
			
		||||
    TriangleMesh convex_hull_3d() const;
 | 
			
		||||
    void reset_repair_stats();
 | 
			
		||||
    bool needed_repair() const;
 | 
			
		||||
    size_t facets_count() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -66,7 +70,7 @@ public:
 | 
			
		|||
    // Count disconnected triangle patches.
 | 
			
		||||
    size_t number_of_patches() const;
 | 
			
		||||
 | 
			
		||||
    stl_file stl;
 | 
			
		||||
    mutable stl_file stl;
 | 
			
		||||
    bool repaired;
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -202,7 +202,8 @@ const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
 | 
			
		|||
GLVolume::GLVolume(float r, float g, float b, float a)
 | 
			
		||||
    : m_angle_z(0.0f)
 | 
			
		||||
    , m_scale_factor(1.0f)
 | 
			
		||||
    , m_dirty(true)
 | 
			
		||||
    , m_transformed_bounding_box_dirty(true)
 | 
			
		||||
    , m_transformed_convex_hull_bounding_box_dirty(true)
 | 
			
		||||
    , composite_id(-1)
 | 
			
		||||
    , select_group_id(-1)
 | 
			
		||||
    , drag_group_id(-1)
 | 
			
		||||
| 
						 | 
				
			
			@ -219,8 +220,6 @@ GLVolume::GLVolume(float r, float g, float b, float a)
 | 
			
		|||
    , tverts_range(0, size_t(-1))
 | 
			
		||||
    , qverts_range(0, size_t(-1))
 | 
			
		||||
{
 | 
			
		||||
    m_world_mat = std::vector<float>(UNIT_MATRIX, std::end(UNIT_MATRIX));
 | 
			
		||||
 | 
			
		||||
    color[0] = r;
 | 
			
		||||
    color[1] = g;
 | 
			
		||||
    color[2] = b;
 | 
			
		||||
| 
						 | 
				
			
			@ -264,45 +263,76 @@ const Pointf3& GLVolume::get_origin() const
 | 
			
		|||
 | 
			
		||||
void GLVolume::set_origin(const Pointf3& origin)
 | 
			
		||||
{
 | 
			
		||||
    m_origin = origin;
 | 
			
		||||
    m_dirty = true;
 | 
			
		||||
    if (m_origin != origin)
 | 
			
		||||
    {
 | 
			
		||||
        m_origin = origin;
 | 
			
		||||
        m_transformed_bounding_box_dirty = true;
 | 
			
		||||
        m_transformed_convex_hull_bounding_box_dirty = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLVolume::set_angle_z(float angle_z)
 | 
			
		||||
{
 | 
			
		||||
    m_angle_z = angle_z;
 | 
			
		||||
    m_dirty = true;
 | 
			
		||||
    if (m_angle_z != angle_z)
 | 
			
		||||
    {
 | 
			
		||||
        m_angle_z = angle_z;
 | 
			
		||||
        m_transformed_bounding_box_dirty = true;
 | 
			
		||||
        m_transformed_convex_hull_bounding_box_dirty = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLVolume::set_scale_factor(float scale_factor)
 | 
			
		||||
{
 | 
			
		||||
    m_scale_factor = scale_factor;
 | 
			
		||||
    m_dirty = true;
 | 
			
		||||
    if (m_scale_factor != scale_factor)
 | 
			
		||||
    {
 | 
			
		||||
        m_scale_factor = scale_factor;
 | 
			
		||||
        m_transformed_bounding_box_dirty = true;
 | 
			
		||||
        m_transformed_convex_hull_bounding_box_dirty = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const std::vector<float>& GLVolume::world_matrix() const
 | 
			
		||||
void GLVolume::set_convex_hull(const TriangleMesh& convex_hull)
 | 
			
		||||
{
 | 
			
		||||
    if (m_dirty)
 | 
			
		||||
    {
 | 
			
		||||
        Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
 | 
			
		||||
        m.translate(Eigen::Vector3f((float)m_origin.x, (float)m_origin.y, (float)m_origin.z));
 | 
			
		||||
        m.rotate(Eigen::AngleAxisf(m_angle_z, Eigen::Vector3f::UnitZ()));
 | 
			
		||||
        m.scale(m_scale_factor);
 | 
			
		||||
        ::memcpy((void*)m_world_mat.data(), (const void*)m.data(), 16 * sizeof(float));
 | 
			
		||||
        m_dirty = false;
 | 
			
		||||
    }
 | 
			
		||||
    m_convex_hull = convex_hull;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    return m_world_mat;
 | 
			
		||||
std::vector<float> GLVolume::world_matrix() const
 | 
			
		||||
{
 | 
			
		||||
    std::vector<float> world_mat(UNIT_MATRIX, std::end(UNIT_MATRIX));
 | 
			
		||||
    Eigen::Transform<float, 3, Eigen::Affine> m = Eigen::Transform<float, 3, Eigen::Affine>::Identity();
 | 
			
		||||
    m.translate(Eigen::Vector3f((float)m_origin.x, (float)m_origin.y, (float)m_origin.z));
 | 
			
		||||
    m.rotate(Eigen::AngleAxisf(m_angle_z, Eigen::Vector3f::UnitZ()));
 | 
			
		||||
    m.scale(m_scale_factor);
 | 
			
		||||
    ::memcpy((void*)world_mat.data(), (const void*)m.data(), 16 * sizeof(float));
 | 
			
		||||
    return world_mat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundingBoxf3 GLVolume::transformed_bounding_box() const
 | 
			
		||||
{
 | 
			
		||||
    if (m_dirty)
 | 
			
		||||
    if (m_transformed_bounding_box_dirty)
 | 
			
		||||
    {
 | 
			
		||||
        m_transformed_bounding_box = bounding_box.transformed(world_matrix());
 | 
			
		||||
        m_transformed_bounding_box_dirty = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return m_transformed_bounding_box;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoundingBoxf3 GLVolume::transformed_convex_hull_bounding_box() const
 | 
			
		||||
{
 | 
			
		||||
    if (m_transformed_convex_hull_bounding_box_dirty)
 | 
			
		||||
    {
 | 
			
		||||
        if (m_convex_hull.stl.stats.number_of_facets > 0)
 | 
			
		||||
            m_transformed_convex_hull_bounding_box = m_convex_hull.transformed_bounding_box(world_matrix());
 | 
			
		||||
        else
 | 
			
		||||
            m_transformed_convex_hull_bounding_box = bounding_box.transformed(world_matrix());
 | 
			
		||||
 | 
			
		||||
        m_transformed_convex_hull_bounding_box_dirty = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return m_transformed_convex_hull_bounding_box;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLVolume::set_range(double min_z, double max_z)
 | 
			
		||||
{
 | 
			
		||||
    this->qverts_range.first  = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -629,6 +659,7 @@ std::vector<int> GLVolumeCollection::load_object(
 | 
			
		|||
 | 
			
		||||
            if (!model_volume->modifier)
 | 
			
		||||
            {
 | 
			
		||||
                v.set_convex_hull(model_volume->get_convex_hull());
 | 
			
		||||
                v.layer_height_texture = layer_height_texture;
 | 
			
		||||
                if (extruder_id != -1)
 | 
			
		||||
                    v.extruder_id = extruder_id;
 | 
			
		||||
| 
						 | 
				
			
			@ -716,6 +747,7 @@ int GLVolumeCollection::load_wipe_tower_preview(
 | 
			
		|||
    v.drag_group_id = obj_idx * 1000;
 | 
			
		||||
    v.is_wipe_tower = true;
 | 
			
		||||
    v.shader_outside_printer_detection_enabled = ! size_unknown;
 | 
			
		||||
    v.set_convex_hull(mesh.convex_hull_3d());
 | 
			
		||||
    return int(this->volumes.size() - 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -803,7 +835,7 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
 | 
			
		|||
    {
 | 
			
		||||
        if ((volume != nullptr) && !volume->is_modifier)
 | 
			
		||||
        {
 | 
			
		||||
            const BoundingBoxf3& bb = volume->transformed_bounding_box();
 | 
			
		||||
            const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box();
 | 
			
		||||
            bool contained = print_volume.contains(bb);
 | 
			
		||||
            all_contained &= contained;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -260,12 +260,16 @@ private:
 | 
			
		|||
    float                 m_angle_z;
 | 
			
		||||
    // Scale factor of the volume to be rendered.
 | 
			
		||||
    float                 m_scale_factor;
 | 
			
		||||
    // World matrix of the volume to be rendered.
 | 
			
		||||
    std::vector<float>    m_world_mat;
 | 
			
		||||
    // Bounding box of this volume, in unscaled coordinates.
 | 
			
		||||
    mutable BoundingBoxf3 m_transformed_bounding_box;
 | 
			
		||||
    // Whether or not is needed to recalculate the world matrix.
 | 
			
		||||
    mutable bool          m_dirty;
 | 
			
		||||
    // Whether or not is needed to recalculate the transformed bounding box.
 | 
			
		||||
    mutable bool          m_transformed_bounding_box_dirty;
 | 
			
		||||
    // Convex hull of the original mesh, if any.
 | 
			
		||||
    TriangleMesh          m_convex_hull;
 | 
			
		||||
    // Bounding box of this volume, in unscaled coordinates.
 | 
			
		||||
    mutable BoundingBoxf3 m_transformed_convex_hull_bounding_box;
 | 
			
		||||
    // Whether or not is needed to recalculate the transformed convex hull bounding box.
 | 
			
		||||
    mutable bool          m_transformed_convex_hull_bounding_box_dirty;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -323,13 +327,15 @@ public:
 | 
			
		|||
    void set_origin(const Pointf3& origin);
 | 
			
		||||
    void set_angle_z(float angle_z);
 | 
			
		||||
    void set_scale_factor(float scale_factor);
 | 
			
		||||
    void set_convex_hull(const TriangleMesh& convex_hull);
 | 
			
		||||
 | 
			
		||||
    int                 object_idx() const { return this->composite_id / 1000000; }
 | 
			
		||||
    int                 volume_idx() const { return (this->composite_id / 1000) % 1000; }
 | 
			
		||||
    int                 instance_idx() const { return this->composite_id % 1000; }
 | 
			
		||||
 | 
			
		||||
    const std::vector<float>& world_matrix() const;
 | 
			
		||||
    std::vector<float> world_matrix() const;
 | 
			
		||||
    BoundingBoxf3       transformed_bounding_box() const;
 | 
			
		||||
    BoundingBoxf3       transformed_convex_hull_bounding_box() const;
 | 
			
		||||
 | 
			
		||||
    bool                empty() const { return this->indexed_vertex_array.empty(); }
 | 
			
		||||
    bool                indexed() const { return this->indexed_vertex_array.indexed(); }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3243,7 +3243,7 @@ BoundingBoxf3 GLCanvas3D::_selected_volumes_bounding_box() const
 | 
			
		|||
    {
 | 
			
		||||
        for (const GLVolume* volume : selected_volumes)
 | 
			
		||||
        {
 | 
			
		||||
            bb.merge(volume->transformed_bounding_box());
 | 
			
		||||
            bb.merge(volume->transformed_convex_hull_bounding_box());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -189,7 +189,7 @@ GLGizmoRotate::GLGizmoRotate()
 | 
			
		|||
    , m_angle_z(0.0f)
 | 
			
		||||
    , m_center(Pointf(0.0, 0.0))
 | 
			
		||||
    , m_radius(0.0f)
 | 
			
		||||
    , m_keep_radius(false)
 | 
			
		||||
    , m_keep_initial_values(false)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -229,7 +229,7 @@ bool GLGizmoRotate::on_init()
 | 
			
		|||
 | 
			
		||||
void GLGizmoRotate::on_set_state()
 | 
			
		||||
{
 | 
			
		||||
    m_keep_radius = (m_state == On) ? false : true;
 | 
			
		||||
    m_keep_initial_values = (m_state == On) ? false : true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLGizmoRotate::on_update(const Pointf& mouse_pos)
 | 
			
		||||
| 
						 | 
				
			
			@ -255,19 +255,19 @@ void GLGizmoRotate::on_update(const Pointf& mouse_pos)
 | 
			
		|||
 | 
			
		||||
void GLGizmoRotate::on_refresh()
 | 
			
		||||
{
 | 
			
		||||
    m_keep_radius = false;
 | 
			
		||||
    m_keep_initial_values = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLGizmoRotate::on_render(const BoundingBoxf3& box) const
 | 
			
		||||
{
 | 
			
		||||
    ::glDisable(GL_DEPTH_TEST);
 | 
			
		||||
 | 
			
		||||
    const Pointf3& size = box.size();
 | 
			
		||||
    m_center = box.center();
 | 
			
		||||
    if (!m_keep_radius)
 | 
			
		||||
    if (!m_keep_initial_values)
 | 
			
		||||
    {
 | 
			
		||||
        const Pointf3& size = box.size();
 | 
			
		||||
        m_center = box.center();
 | 
			
		||||
        m_radius = Offset + ::sqrt(sqr(0.5f * size.x) + sqr(0.5f * size.y));
 | 
			
		||||
        m_keep_radius = true;
 | 
			
		||||
        m_keep_initial_values = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ::glLineWidth(2.0f);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -101,7 +101,7 @@ class GLGizmoRotate : public GLGizmoBase
 | 
			
		|||
 | 
			
		||||
    mutable Pointf m_center;
 | 
			
		||||
    mutable float m_radius;
 | 
			
		||||
    mutable bool m_keep_radius;
 | 
			
		||||
    mutable bool m_keep_initial_values;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    GLGizmoRotate();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -65,7 +65,6 @@
 | 
			
		|||
             %};
 | 
			
		||||
    Clone<BoundingBoxf3> bounding_box() const
 | 
			
		||||
        %code%{ RETVAL = THIS->bounding_box; %};
 | 
			
		||||
    Clone<BoundingBoxf3> transformed_bounding_box() const;
 | 
			
		||||
 | 
			
		||||
    bool                empty() const;
 | 
			
		||||
    bool                indexed() const;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue