void ModelObject::center_around_origin() { // calculate the displacements needed to // center this object around the origin BoundingBoxf3 bb; { TriangleMesh mesh; this->raw_mesh(&mesh); mesh.bounding_box(&bb); } // first align to origin on XYZ Vectorf3 vector(-bb.min.x, -bb.min.y, -bb.min.z); // then center it on XY Sizef3 size = bb.size(); vector.x -= size.x/2; vector.y -= size.y/2; this->translate(vector); this->origin_translation.translate(vector); if (!this->instances.empty()) { for (ModelInstancePtrs::const_iterator i = this->instances.begin(); i != this->instances.end(); ++i) { (*i)->offset.translate(-vector.x, -vector.y); } this->update_bounding_box(); } }
void ModelObject::center_around_origin() { // calculate the displacements needed to // center this object around the origin BoundingBoxf3 bb; for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) if (! (*v)->modifier) bb.merge((*v)->mesh.bounding_box()); // first align to origin on XYZ Vectorf3 vector(-bb.min.x, -bb.min.y, -bb.min.z); // then center it on XY Sizef3 size = bb.size(); vector.x -= size.x/2; vector.y -= size.y/2; this->translate(vector); this->origin_translation.translate(vector); if (!this->instances.empty()) { for (ModelInstancePtrs::const_iterator i = this->instances.begin(); i != this->instances.end(); ++i) { // apply rotation and scaling to vector as well before translating instance, // in order to leave final position unaltered Vectorf3 v = vector.negative(); v.rotate((*i)->rotation, (*i)->offset); v.scale((*i)->scaling_factor); (*i)->offset.translate(v.x, v.y); } this->invalidate_bounding_box(); } }
PrintObject::PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox) : _print(print), _model_object(model_object), typed_slices(false) { region_volumes.resize(this->_print->regions.size()); // Compute the translation to be applied to our meshes so that we work with smaller coordinates { // Translate meshes so that our toolpath generation algorithms work with smaller // XY coordinates; this translation is an optimization and not strictly required. // A cloned mesh will be aligned to 0 before slicing in _slice_region() since we // don't assume it's already aligned and we don't alter the original position in model. // We store the XY translation so that we can place copies correctly in the output G-code // (copies are expressed in G-code coordinates and this translation is not publicly exposed). this->_copies_shift = Point( scale_(modobj_bbox.min.x), scale_(modobj_bbox.min.y)); // Scale the object size and store it Pointf3 size = modobj_bbox.size(); this->size = Point3(scale_(size.x), scale_(size.y), scale_(size.z)); } this->reload_model_instances(); this->layer_height_ranges = model_object->layer_height_ranges; }
void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool picking) const { if (m_quadric == nullptr) return; float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size(mean_size) : (double)m_grabbers[0].get_half_size(mean_size); float color[3]; ::memcpy((void*)color, (const void*)m_grabbers[0].color, 3 * sizeof(float)); if (!picking && (m_hover_id != -1)) { color[0] = 1.0f - color[0]; color[1] = 1.0f - color[1]; color[2] = 1.0f - color[2]; } if (!picking) glsafe(::glEnable(GL_LIGHTING)); glsafe(::glColor3fv(color)); glsafe(::glPushMatrix()); glsafe(::glTranslated(m_grabbers[0].center(0), m_grabbers[0].center(1), m_grabbers[0].center(2))); glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0)); glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); glsafe(::glTranslated(0.0, 0.0, 2.0 * size)); ::gluQuadricOrientation(m_quadric, GLU_OUTSIDE); ::gluCylinder(m_quadric, 0.75 * size, 0.0, 3.0 * size, 36, 1); ::gluQuadricOrientation(m_quadric, GLU_INSIDE); ::gluDisk(m_quadric, 0.0, 0.75 * size, 36, 1); glsafe(::glPopMatrix()); glsafe(::glPushMatrix()); glsafe(::glTranslated(m_grabbers[0].center(0), m_grabbers[0].center(1), m_grabbers[0].center(2))); glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0)); glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); glsafe(::glTranslated(0.0, 0.0, 2.0 * size)); ::gluQuadricOrientation(m_quadric, GLU_OUTSIDE); ::gluCylinder(m_quadric, 0.75 * size, 0.0, 3.0 * size, 36, 1); ::gluQuadricOrientation(m_quadric, GLU_INSIDE); ::gluDisk(m_quadric, 0.0, 0.75 * size, 36, 1); glsafe(::glPopMatrix()); if (!picking) glsafe(::glDisable(GL_LIGHTING)); }
void Model::align_instances_to_origin() { BoundingBoxf3 bb = this->bounding_box(); Pointf new_center = (Pointf)bb.size(); new_center.translate(-new_center.x/2, -new_center.y/2); this->center_instances_around_point(new_center); }
void Model::center_instances_around_point(const Pointf &point) { BoundingBoxf3 bb = this->bounding_box(); Sizef3 size = bb.size(); coordf_t shift_x = -bb.min.x + point.x - size.x/2; coordf_t shift_y = -bb.min.y + point.y - size.y/2; for (ModelObjectPtrs::const_iterator o = this->objects.begin(); o != this->objects.end(); ++o) { for (ModelInstancePtrs::const_iterator i = (*o)->instances.begin(); i != (*o)->instances.end(); ++i) { (*i)->offset.translate(shift_x, shift_y); } (*o)->invalidate_bounding_box(); } }
void ModelObject::print_info() const { using namespace std; cout << fixed; cout << "[" << boost::filesystem::path(this->input_file).filename().string() << "]" << endl; TriangleMesh mesh = this->raw_mesh(); mesh.check_topology(); BoundingBoxf3 bb = mesh.bounding_box(); Sizef3 size = bb.size(); cout << "size_x = " << size.x << endl; cout << "size_y = " << size.y << endl; cout << "size_z = " << size.z << endl; cout << "min_x = " << bb.min.x << endl; cout << "min_y = " << bb.min.y << endl; cout << "min_z = " << bb.min.z << endl; cout << "max_x = " << bb.max.x << endl; cout << "max_y = " << bb.max.y << endl; cout << "max_z = " << bb.max.z << endl; cout << "number_of_facets = " << mesh.stl.stats.number_of_facets << endl; cout << "manifold = " << (mesh.is_manifold() ? "yes" : "no") << endl; mesh.repair(); // this calculates number_of_parts if (mesh.needed_repair()) { mesh.repair(); if (mesh.stl.stats.degenerate_facets > 0) cout << "degenerate_facets = " << mesh.stl.stats.degenerate_facets << endl; if (mesh.stl.stats.edges_fixed > 0) cout << "edges_fixed = " << mesh.stl.stats.edges_fixed << endl; if (mesh.stl.stats.facets_removed > 0) cout << "facets_removed = " << mesh.stl.stats.facets_removed << endl; if (mesh.stl.stats.facets_added > 0) cout << "facets_added = " << mesh.stl.stats.facets_added << endl; if (mesh.stl.stats.facets_reversed > 0) cout << "facets_reversed = " << mesh.stl.stats.facets_reversed << endl; if (mesh.stl.stats.backwards_edges > 0) cout << "backwards_edges = " << mesh.stl.stats.backwards_edges << endl; } cout << "number_of_parts = " << mesh.stl.stats.number_of_parts << endl; cout << "volume = " << mesh.volume() << endl; }
void SVGExport::writeSVG(const std::string &outputfile) { // align to origin taking raft into account BoundingBoxf3 bb = this->mesh.bounding_box(); if (this->config.raft_layers > 0) { bb.min.x -= this->config.raft_offset.value; bb.min.y -= this->config.raft_offset.value; bb.max.x += this->config.raft_offset.value; bb.max.y += this->config.raft_offset.value; } this->mesh.translate(-bb.min.x, -bb.min.y, -bb.min.z); // align to origin bb.translate(-bb.min.x, -bb.min.y, -bb.min.z); // align to origin const Sizef3 size = bb.size(); // if we are generating a raft, first_layer_height will not affect mesh slicing const float lh = this->config.layer_height.value; const float first_lh = this->config.first_layer_height.value; // generate the list of Z coordinates for mesh slicing // (we slice each layer at half of its thickness) std::vector<float> slice_z, layer_z; { const float first_slice_lh = (this->config.raft_layers > 0) ? lh : first_lh; slice_z.push_back(first_slice_lh/2); layer_z.push_back(first_slice_lh); } while (layer_z.back() + lh/2 <= this->mesh.stl.stats.max.z) { slice_z.push_back(layer_z.back() + lh/2); layer_z.push_back(layer_z.back() + lh); } // perform the slicing std::vector<ExPolygons> layers; TriangleMeshSlicer(&this->mesh).slice(slice_z, &layers); // generate a solid raft if requested if (this->config.raft_layers > 0) { ExPolygons raft = offset_ex(layers.front(), scale_(this->config.raft_offset)); for (int i = this->config.raft_layers; i >= 1; --i) { layer_z.insert(layer_z.begin(), first_lh + lh * (i-1)); layers.insert(layers.begin(), raft); } // prepend total raft height to all sliced layers for (int i = this->config.raft_layers; i < layer_z.size(); ++i) layer_z[i] += first_lh + lh * (this->config.raft_layers-1); } // generate support material std::vector<Points> support_material(layers.size()); if (this->config.support_material) { // generate a grid of points according to the configured spacing, // covering the entire object bounding box Points support_material_points; for (coordf_t x = bb.min.x; x <= bb.max.x; x += this->config.support_material_spacing) { for (coordf_t y = bb.min.y; y <= bb.max.y; y += this->config.support_material_spacing) { support_material_points.push_back(Point(scale_(x), scale_(y))); } } // check overhangs, starting from the upper layer, and detect which points apply // to each layer ExPolygons overhangs; for (int i = layer_z.size()-1; i >= 0; --i) { overhangs = diff_ex(union_(overhangs, layers[i+1]), layers[i]); for (Points::const_iterator it = support_material_points.begin(); it != support_material_points.end(); ++it) { for (ExPolygons::const_iterator e = overhangs.begin(); e != overhangs.end(); ++e) { if (e->contains(*it)) { support_material[i].push_back(*it); break; } } } } } double support_material_radius = this->config.support_material_extrusion_width.get_abs_value(this->config.layer_height)/2; FILE* f = fopen(outputfile.c_str(), "w"); fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n" "<svg width=\"%f\" height=\"%f\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:slic3r=\"http://slic3r.org/namespaces/slic3r\" viewport-fill=\"black\">\n" "<!-- Generated using Slic3r %s http://slic3r.org/ -->\n" , size.x, size.y, SLIC3R_VERSION); for (size_t i = 0; i < layer_z.size(); ++i) { fprintf(f, "\t<g id=\"layer%zu\" slic3r:z=\"%0.4f\">\n", i, layer_z[i]); for (ExPolygons::const_iterator it = layers[i].begin(); it != layers[i].end(); ++it) { std::string pd; Polygons pp = *it; for (Polygons::const_iterator mp = pp.begin(); mp != pp.end(); ++mp) { std::ostringstream d; d << "M "; for (Points::const_iterator p = mp->points.begin(); p != mp->points.end(); ++p) { d << unscale(p->x) << " "; d << unscale(p->y) << " "; } d << "z"; pd += d.str() + " "; } fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:area=\"%0.4f\" />\n", pd.c_str(), "white", "black", "0", unscale(unscale(it->area())) ); } for (Points::const_iterator it = support_material[i].begin(); it != support_material[i].end(); ++it) { fprintf(f,"\t\t<circle cx=\"%f\" cy=\"%f\" r=\"%f\" stroke-width=\"0\" fill=\"white\" slic3r:type=\"support\" />\n", unscale(it->x), unscale(it->y), support_material_radius ); } fprintf(f,"\t</g>\n"); } fprintf(f,"</svg>\n"); }