240 lines
No EOL
7.3 KiB
C++
240 lines
No EOL
7.3 KiB
C++
#include "NonplanarSurface.hpp"
|
|
|
|
namespace Slic3r {
|
|
|
|
NonplanarSurface::NonplanarSurface(std::map<int, NonplanarFacet> &_mesh)
|
|
{
|
|
this->mesh = _mesh;
|
|
this->calculate_stats();
|
|
}
|
|
|
|
bool
|
|
NonplanarSurface::operator==(const NonplanarSurface& other) const {
|
|
return (stats.min.x == other.stats.min.x &&
|
|
stats.min.y == other.stats.min.y &&
|
|
stats.min.z == other.stats.min.z &&
|
|
stats.max.x == other.stats.max.x &&
|
|
stats.max.y == other.stats.max.y &&
|
|
stats.max.z == other.stats.max.z);
|
|
}
|
|
|
|
void
|
|
NonplanarSurface::calculate_stats()
|
|
{
|
|
//calculate min and max values
|
|
this->stats.min.x = 10000000;
|
|
this->stats.min.y = 10000000;
|
|
this->stats.min.z = 10000000;
|
|
this->stats.max.x = -10000000;
|
|
this->stats.max.y = -10000000;
|
|
this->stats.max.z = -10000000;
|
|
for(auto& facet : this->mesh) {
|
|
this->stats.min.x = std::min(this->stats.min.x, facet.second.stats.min.x);
|
|
this->stats.min.y = std::min(this->stats.min.y, facet.second.stats.min.y);
|
|
this->stats.min.z = std::min(this->stats.min.z, facet.second.stats.min.z);
|
|
this->stats.max.x = std::max(this->stats.max.x, facet.second.stats.max.x);
|
|
this->stats.max.y = std::max(this->stats.max.y, facet.second.stats.max.y);
|
|
this->stats.max.z = std::max(this->stats.max.z, facet.second.stats.max.z);
|
|
}
|
|
}
|
|
|
|
void
|
|
NonplanarSurface::translate(float x, float y, float z)
|
|
{
|
|
//translate all facets
|
|
for(auto& facet : this->mesh) {
|
|
facet.second.translate(x, y, z);
|
|
}
|
|
|
|
//translate min and max values
|
|
this->stats.min.x += x;
|
|
this->stats.min.y += y;
|
|
this->stats.min.z += z;
|
|
this->stats.max.x += x;
|
|
this->stats.max.y += y;
|
|
this->stats.max.z += z;
|
|
}
|
|
|
|
void
|
|
NonplanarSurface::scale(float factor)
|
|
{
|
|
float versor[3];
|
|
versor[0] = factor;
|
|
versor[1] = factor;
|
|
versor[2] = factor;
|
|
this->scale(versor);
|
|
}
|
|
|
|
void
|
|
NonplanarSurface::scale(float versor[3])
|
|
{
|
|
//scale all facets
|
|
for(auto& facet : this->mesh) {
|
|
facet.second.scale(versor);
|
|
}
|
|
|
|
//scale min and max values
|
|
this->stats.min.x *= versor[0];
|
|
this->stats.min.y *= versor[1];
|
|
this->stats.min.z *= versor[2];
|
|
this->stats.max.x *= versor[0];
|
|
this->stats.max.y *= versor[1];
|
|
this->stats.max.z *= versor[2];
|
|
}
|
|
|
|
void
|
|
NonplanarSurface::rotate_z(float angle) {
|
|
double radian_angle = (angle / 180.0) * 3.1415927;
|
|
double c = cos(radian_angle);
|
|
double s = sin(radian_angle);
|
|
|
|
for(auto& facet : this->mesh) {
|
|
for(int j = 0; j < 3; j++) {
|
|
double xold = facet.second.vertex[j].x;
|
|
double yold = facet.second.vertex[j].y;
|
|
facet.second.vertex[j].x = c * xold - s * yold;
|
|
facet.second.vertex[j].y = s * xold + c * yold;
|
|
}
|
|
facet.second.calculate_stats();
|
|
}
|
|
|
|
this->calculate_stats();
|
|
}
|
|
|
|
void
|
|
NonplanarSurface::debug_output()
|
|
{
|
|
std::cout << "Facets(" << this->mesh.size() << "): (min:X:" << this->stats.min.x << " Y:" << this->stats.min.y << " Z:" << this->stats.min.z <<
|
|
" max:X:" << this->stats.max.x << " Y:" << this->stats.max.y << " Z:" << this->stats.max.z << ")" <<
|
|
"Height " << this->stats.max.z - this->stats.min.z << std::endl;
|
|
for(auto& facet : this->mesh) {
|
|
std::cout << "triangle: (" << facet.first << ")(" << facet.second.marked << ") ";
|
|
std::cout << " (" << (180*std::acos(facet.second.normal.z))/3.14159265 << "°)";
|
|
|
|
std::cout << " | V0:";
|
|
std::cout << " X:"<< facet.second.vertex[0].x;
|
|
std::cout << " Y:"<< facet.second.vertex[0].y;
|
|
std::cout << " Z:"<< facet.second.vertex[0].z;
|
|
|
|
std::cout << " | V1:";
|
|
std::cout << " X:"<< facet.second.vertex[1].x;
|
|
std::cout << " Y:"<< facet.second.vertex[1].y;
|
|
std::cout << " Z:"<< facet.second.vertex[1].z;
|
|
|
|
std::cout << " | V2:";
|
|
std::cout << " X:"<< facet.second.vertex[2].x;
|
|
std::cout << " Y:"<< facet.second.vertex[2].y;
|
|
std::cout << " Z:"<< facet.second.vertex[2].z;
|
|
|
|
std::cout << " | Normal:";
|
|
std::cout << " X:"<< facet.second.normal.x;
|
|
std::cout << " Y:"<< facet.second.normal.y;
|
|
std::cout << " Z:"<< facet.second.normal.z;
|
|
|
|
//TODO check if neighbors exist
|
|
// stl_neighbors* neighbors = mesh.stl.neighbors_start + facet.first;
|
|
std::cout << " | Neighbors:";
|
|
std::cout << " 0:"<< facet.second.neighbor[0];
|
|
std::cout << " 1:"<< facet.second.neighbor[1];
|
|
std::cout << " 2:"<< facet.second.neighbor[2];
|
|
std::cout << std::endl;
|
|
}
|
|
}
|
|
|
|
NonplanarSurfaces
|
|
NonplanarSurface::group_surfaces()
|
|
{
|
|
std::pair<int, NonplanarFacet> begin = *this->mesh.begin();
|
|
this->mark_neighbor_surfaces(begin.first);
|
|
NonplanarSurface newSurface;
|
|
for (std::map<int, NonplanarFacet>::iterator it=this->mesh.begin(); it!=this->mesh.end();) {
|
|
if((*it).second.marked == false) {
|
|
newSurface.mesh[(*it).first] = (*it).second;
|
|
it = this->mesh.erase(it);
|
|
}
|
|
else {
|
|
++it;
|
|
}
|
|
}
|
|
this->calculate_stats();
|
|
if (newSurface.mesh.size() == 0) {
|
|
//return only this
|
|
NonplanarSurfaces nonplanar_surfaces;
|
|
nonplanar_surfaces.push_back(*this);
|
|
return nonplanar_surfaces;
|
|
}
|
|
else {
|
|
//return union of this and recursion
|
|
NonplanarSurfaces nonplanar_surfaces = newSurface.group_surfaces();
|
|
nonplanar_surfaces.push_back(*this);
|
|
return nonplanar_surfaces;
|
|
}
|
|
}
|
|
|
|
void
|
|
NonplanarSurface::mark_neighbor_surfaces(int id)
|
|
{
|
|
//if already marked return
|
|
if(this->mesh.find(id) == this->mesh.end() || this->mesh[id].marked == true) return;
|
|
//mark this facet
|
|
this->mesh[id].marked = true;
|
|
//mark all neighbors
|
|
for(int j = 0; j < 3; j++) {
|
|
this->mark_neighbor_surfaces(this->mesh[id].neighbor[j]);
|
|
}
|
|
}
|
|
|
|
bool
|
|
NonplanarSurface::check_max_printing_height(float height)
|
|
{
|
|
if ((this->stats.max.z - this->stats.min.z) > height ) {
|
|
std::cout << "Surface removed: printheight too heigh (" << (this->stats.max.z - this->stats.min.z) << " mm)" << '\n';
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool
|
|
NonplanarSurface::check_surface_area()
|
|
{
|
|
//calculate surface area of nonplanar surface.
|
|
float area = 0.0f;
|
|
for(auto& facet : this->mesh) {
|
|
area += facet.second.calculate_surface_area();
|
|
}
|
|
if (area < 20.0f) {
|
|
std::cout << "Surface removed: area too small (" << area << " mm²)" << '\n';
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void
|
|
NonplanarSurface::check_printable_surfaces(float max_angle)
|
|
{
|
|
//TODO do something
|
|
}
|
|
|
|
/* this will return scaled ExPolygons */
|
|
ExPolygons
|
|
NonplanarSurface::horizontal_projection() const
|
|
{
|
|
Polygons pp;
|
|
pp.reserve(this->mesh.size());
|
|
for(auto& facet : this->mesh) {
|
|
Polygon p;
|
|
p.points.resize(3);
|
|
p.points[0] = Point(scale_(facet.second.vertex[0].x), scale_(facet.second.vertex[0].y));
|
|
p.points[1] = Point(scale_(facet.second.vertex[1].x), scale_(facet.second.vertex[1].y));
|
|
p.points[2] = Point(scale_(facet.second.vertex[2].x), scale_(facet.second.vertex[2].y));
|
|
p.make_counter_clockwise(); // do this after scaling, as winding order might change while doing that
|
|
pp.push_back(p);
|
|
}
|
|
|
|
// the offset factor was tuned using groovemount.stl
|
|
return union_ex(offset(pp, scale_(0.01)));
|
|
}
|
|
|
|
} |