2013-06-24 17:35:49 +00:00
|
|
|
#include "TriangleMesh.hpp"
|
2013-09-07 12:06:09 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <math.h>
|
2013-06-24 17:35:49 +00:00
|
|
|
|
2013-07-07 20:36:14 +00:00
|
|
|
namespace Slic3r {
|
|
|
|
|
2013-06-24 17:35:49 +00:00
|
|
|
TriangleMesh::TriangleMesh() {}
|
|
|
|
TriangleMesh::~TriangleMesh() {
|
|
|
|
stl_close(&stl);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TriangleMesh::ReadSTLFile(char* input_file) {
|
|
|
|
stl_open(&stl, input_file);
|
|
|
|
}
|
|
|
|
|
2013-07-03 09:38:01 +00:00
|
|
|
void TriangleMesh::ReadFromPerl(SV* vertices, SV* facets)
|
|
|
|
{
|
|
|
|
stl_initialize(&stl);
|
|
|
|
stl.stats.type = inmemory;
|
|
|
|
|
|
|
|
// count facets and allocate memory
|
|
|
|
AV* facets_av = (AV*)SvRV(facets);
|
|
|
|
stl.stats.number_of_facets = av_len(facets_av)+1;
|
|
|
|
stl.stats.original_num_facets = stl.stats.number_of_facets;
|
|
|
|
stl_allocate(&stl);
|
|
|
|
|
|
|
|
// read geometry
|
|
|
|
AV* vertices_av = (AV*)SvRV(vertices);
|
|
|
|
for (unsigned int i = 0; i < stl.stats.number_of_facets; i++) {
|
|
|
|
AV* facet_av = (AV*)SvRV(*av_fetch(facets_av, i, 0));
|
|
|
|
stl_facet facet;
|
2013-07-26 15:08:08 +00:00
|
|
|
facet.normal.x = 0;
|
|
|
|
facet.normal.y = 0;
|
|
|
|
facet.normal.z = 0;
|
2013-07-03 09:38:01 +00:00
|
|
|
for (unsigned int v = 0; v <= 2; v++) {
|
|
|
|
AV* vertex_av = (AV*)SvRV(*av_fetch(vertices_av, SvIV(*av_fetch(facet_av, v, 0)), 0));
|
|
|
|
facet.vertex[v].x = SvNV(*av_fetch(vertex_av, 0, 0));
|
|
|
|
facet.vertex[v].y = SvNV(*av_fetch(vertex_av, 1, 0));
|
|
|
|
facet.vertex[v].z = SvNV(*av_fetch(vertex_av, 2, 0));
|
|
|
|
}
|
2013-07-26 15:08:08 +00:00
|
|
|
facet.extra[0] = 0;
|
|
|
|
facet.extra[1] = 0;
|
2013-07-03 09:38:01 +00:00
|
|
|
|
|
|
|
stl.facet_start[i] = facet;
|
|
|
|
}
|
2013-08-05 17:39:10 +00:00
|
|
|
|
|
|
|
stl_get_size(&(this->stl));
|
2013-07-03 09:38:01 +00:00
|
|
|
}
|
|
|
|
|
2013-06-24 17:35:49 +00:00
|
|
|
void
|
|
|
|
TriangleMesh::Repair() {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// checking exact
|
|
|
|
stl_check_facets_exact(&stl);
|
|
|
|
stl.stats.facets_w_1_bad_edge = (stl.stats.connected_facets_2_edge - stl.stats.connected_facets_3_edge);
|
|
|
|
stl.stats.facets_w_2_bad_edge = (stl.stats.connected_facets_1_edge - stl.stats.connected_facets_2_edge);
|
|
|
|
stl.stats.facets_w_3_bad_edge = (stl.stats.number_of_facets - stl.stats.connected_facets_1_edge);
|
|
|
|
|
|
|
|
// checking nearby
|
|
|
|
int last_edges_fixed = 0;
|
|
|
|
float tolerance = stl.stats.shortest_edge;
|
|
|
|
float increment = stl.stats.bounding_diameter / 10000.0;
|
|
|
|
int iterations = 2;
|
|
|
|
if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) {
|
|
|
|
for (i = 0; i < iterations; i++) {
|
|
|
|
if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) {
|
2013-06-24 18:36:51 +00:00
|
|
|
//printf("Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance, i + 1, iterations);
|
2013-06-24 17:35:49 +00:00
|
|
|
stl_check_facets_nearby(&stl, tolerance);
|
2013-06-24 18:36:51 +00:00
|
|
|
//printf(" Fixed %d edges.\n", stl.stats.edges_fixed - last_edges_fixed);
|
2013-06-24 17:35:49 +00:00
|
|
|
last_edges_fixed = stl.stats.edges_fixed;
|
|
|
|
tolerance += increment;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove_unconnected
|
|
|
|
if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) {
|
|
|
|
stl_remove_unconnected_facets(&stl);
|
2013-06-24 18:36:51 +00:00
|
|
|
}
|
2013-06-24 17:35:49 +00:00
|
|
|
|
|
|
|
// fill_holes
|
|
|
|
if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) {
|
|
|
|
stl_fill_holes(&stl);
|
2013-06-24 18:36:51 +00:00
|
|
|
}
|
2013-06-24 17:35:49 +00:00
|
|
|
|
|
|
|
// normal_directions
|
|
|
|
stl_fix_normal_directions(&stl);
|
|
|
|
|
|
|
|
// normal_values
|
|
|
|
stl_fix_normal_values(&stl);
|
2013-07-13 17:00:38 +00:00
|
|
|
|
|
|
|
// always calculate the volume and reverse all normals if volume is negative
|
|
|
|
stl_calculate_volume(&stl);
|
|
|
|
|
|
|
|
// neighbors
|
|
|
|
stl_verify_neighbors(&stl);
|
2013-06-24 17:35:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TriangleMesh::WriteOBJFile(char* output_file) {
|
|
|
|
stl_generate_shared_vertices(&stl);
|
|
|
|
stl_write_obj(&stl, output_file);
|
|
|
|
}
|
2013-06-24 18:11:56 +00:00
|
|
|
|
2013-08-04 19:34:26 +00:00
|
|
|
void TriangleMesh::scale(float factor)
|
|
|
|
{
|
|
|
|
stl_scale(&(this->stl), factor);
|
|
|
|
}
|
|
|
|
|
2013-08-05 08:48:38 +00:00
|
|
|
void TriangleMesh::translate(float x, float y, float z)
|
|
|
|
{
|
|
|
|
stl_translate(&(this->stl), x, y, z);
|
|
|
|
}
|
|
|
|
|
2013-08-05 17:22:33 +00:00
|
|
|
void TriangleMesh::align_to_origin()
|
|
|
|
{
|
|
|
|
this->translate(
|
|
|
|
-(this->stl.stats.min.x),
|
|
|
|
-(this->stl.stats.min.y),
|
|
|
|
-(this->stl.stats.min.z)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2013-08-05 17:52:37 +00:00
|
|
|
void TriangleMesh::rotate(double angle, Point* center)
|
|
|
|
{
|
|
|
|
this->translate(-center->x, -center->y, 0);
|
|
|
|
stl_rotate_z(&(this->stl), (float)angle);
|
|
|
|
this->translate(+center->x, +center->y, 0);
|
|
|
|
}
|
|
|
|
|
2013-09-07 12:06:09 +00:00
|
|
|
std::vector<Polygons>*
|
|
|
|
TriangleMesh::slice(const std::vector<double> &z)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
This method gets called with a list of Z coordinates and outputs
|
|
|
|
a vector pointer having the same number of items as the original list.
|
|
|
|
Each item is a vector of polygons created by slicing our mesh at the
|
|
|
|
given heights.
|
|
|
|
|
|
|
|
This method should basically combine the behavior of the existing
|
|
|
|
Perl methods defined in lib/Slic3r/TriangleMesh.pm:
|
|
|
|
|
|
|
|
- analyze(): this creates the 'facets_edges' and the 'edges_facets'
|
|
|
|
tables (we don't need the 'edges' table)
|
|
|
|
|
|
|
|
- slice_facet(): this has to be done for each facet. It generates
|
|
|
|
intersection lines with each plane identified by the Z list.
|
|
|
|
The get_layer_range() binary search used to identify the Z range
|
|
|
|
of the facet is already ported to C++ (see Object.xsp)
|
|
|
|
|
|
|
|
- make_loops(): this has to be done for each layer. It creates polygons
|
|
|
|
from the lines generated by the previous step.
|
|
|
|
|
|
|
|
At the end, we free the tables generated by analyze() as we don't
|
|
|
|
need them anymore.
|
|
|
|
FUTURE: parallelize slice_facet() and make_loops()
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (int facet_idx = 0; facet_idx < this->stl.stats.number_of_facets; facet_idx++) {
|
|
|
|
stl_facet facet = this->stl.facet_start[facet_idx]; // this is a copy
|
|
|
|
|
|
|
|
/* 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) */
|
|
|
|
float min_z;
|
|
|
|
if (facet.vertex[1].z < facet.vertex[0].z && facet.vertex[1].z < facet.vertex[2].z) {
|
|
|
|
// vertex 1 has lowest Z
|
|
|
|
min_z = facet.vertex[1].z;
|
|
|
|
stl_vertex v0 = facet.vertex[0];
|
|
|
|
facet.vertex[0] = facet.vertex[1];
|
|
|
|
facet.vertex[1] = facet.vertex[2];
|
|
|
|
facet.vertex[2] = v0;
|
|
|
|
} else if (facet.vertex[2].z < facet.vertex[0].z && facet.vertex[2].z < facet.vertex[1].z) {
|
|
|
|
// vertex 2 has lowest Z
|
|
|
|
min_z = facet.vertex[2].z;
|
|
|
|
stl_vertex v0 = facet.vertex[0];
|
|
|
|
facet.vertex[0] = facet.vertex[2];
|
|
|
|
facet.vertex[2] = facet.vertex[1];
|
|
|
|
facet.vertex[1] = v0;
|
|
|
|
} else {
|
|
|
|
min_z = facet.vertex[0].z;
|
|
|
|
}
|
|
|
|
float max_z = fmaxf(facet.vertex[0].z, fmaxf(facet.vertex[1].z, facet.vertex[2].z));
|
|
|
|
|
|
|
|
#ifdef SLIC3R_DEBUG
|
|
|
|
printf("\n==> FACET %d (%f,%f,%f - %f,%f,%f - %f,%f,%f):\n", facet_idx,
|
|
|
|
facet.vertex[0].x, facet.vertex[0].y, facet.vertex[0].z,
|
|
|
|
facet.vertex[1].x, facet.vertex[1].y, facet.vertex[1].z,
|
|
|
|
facet.vertex[2].x, facet.vertex[2].y, facet.vertex[2].z);
|
|
|
|
printf("z: min = %.2f, max = %.2f\n", min_z, max_z);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (min_z == max_z) {
|
|
|
|
#ifdef SLIC3R_DEBUG
|
|
|
|
printf("Facet is horizontal; ignoring\n");
|
|
|
|
#endif
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<double>::const_iterator min_layer, max_layer;
|
|
|
|
min_layer = std::lower_bound(z.begin(), z.end(), min_z); // first layer whose slice_z is >= min_z
|
|
|
|
max_layer = std::upper_bound(z.begin() + (min_layer - z.begin()), z.end(), max_z) - 1; // last layer whose slice_z is <= max_z
|
|
|
|
#ifdef SLIC3R_DEBUG
|
|
|
|
printf("layers: min = %d, max = %d\n", (int)(min_layer - z.begin()), (int)(max_layer - z.begin()));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (std::vector<double>::const_iterator it = z.begin(); it != z.end(); ++it) {
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<Polygons>* layers = new std::vector<Polygons>(z.size());
|
|
|
|
|
|
|
|
// ...
|
|
|
|
// add a Polygon p to layer n:
|
|
|
|
// (*layers)[n].push_back(p);
|
|
|
|
|
|
|
|
return layers;
|
|
|
|
}
|
|
|
|
|
2013-07-07 20:36:14 +00:00
|
|
|
}
|