Arquivos
CuraEngine/support.cpp
T

188 linhas
6.8 KiB
C++

/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "support.h"
template<typename T> inline void swap(T& p0, T& p1)
{
T tmp = p0;
p0 = p1;
p1 = tmp;
}
int cmp_SupportPoint(const void* a, const void* b)
{
return ((SupportPoint*)a)->z - ((SupportPoint*)b)->z;
}
void generateSupportGrid(SupportStorage& storage, OptimizedModel* om, int supportAngle, bool supportEverywhere, int supportXYDistance, int supportZDistance)
{
storage.generated = false;
if (supportAngle < 0)
return;
storage.generated = true;
storage.gridOffset.X = om->vMin.x;
storage.gridOffset.Y = om->vMin.y;
storage.gridScale = 200;
storage.gridWidth = (om->modelSize.x / storage.gridScale) + 1;
storage.gridHeight = (om->modelSize.y / storage.gridScale) + 1;
storage.grid = new vector<SupportPoint>[storage.gridWidth * storage.gridHeight];
storage.angle = supportAngle;
storage.everywhere = supportEverywhere;
storage.XYDistance = supportXYDistance;
storage.ZDistance = supportZDistance;
for(unsigned int volumeIdx = 0; volumeIdx < om->volumes.size(); volumeIdx++)
{
OptimizedVolume* vol = &om->volumes[volumeIdx];
for(unsigned int faceIdx = 0; faceIdx < vol->faces.size(); faceIdx++)
{
OptimizedFace* face = &vol->faces[faceIdx];
Point3 v0 = vol->points[face->index[0]].p;
Point3 v1 = vol->points[face->index[1]].p;
Point3 v2 = vol->points[face->index[2]].p;
Point3 normal = (v1 - v0).cross(v2 - v0);
int32_t normalSize = normal.vSize();
double cosAngle = fabs(double(normal.z) / double(normalSize));
v0.x = (v0.x - storage.gridOffset.X) / storage.gridScale;
v0.y = (v0.y - storage.gridOffset.Y) / storage.gridScale;
v1.x = (v1.x - storage.gridOffset.X) / storage.gridScale;
v1.y = (v1.y - storage.gridOffset.Y) / storage.gridScale;
v2.x = (v2.x - storage.gridOffset.X) / storage.gridScale;
v2.y = (v2.y - storage.gridOffset.Y) / storage.gridScale;
if (v0.x > v1.x) swap(v0, v1);
if (v1.x > v2.x) swap(v1, v2);
if (v0.x > v1.x) swap(v0, v1);
for(int64_t x=v0.x; x<v1.x; x++)
{
int64_t y0 = v0.y + (v1.y - v0.y) * (x - v0.x) / (v1.x - v0.x);
int64_t y1 = v0.y + (v2.y - v0.y) * (x - v0.x) / (v2.x - v0.x);
int64_t z0 = v0.z + (v1.z - v0.z) * (x - v0.x) / (v1.x - v0.x);
int64_t z1 = v0.z + (v2.z - v0.z) * (x - v0.x) / (v2.x - v0.x);
if (y0 > y1) { swap(y0, y1); swap(z0, z1); }
for(int64_t y=y0; y<y1; y++)
storage.grid[x+y*storage.gridWidth].push_back(SupportPoint(z0 + (z1 - z0) * (y-y0) / (y1-y0), cosAngle));
}
for(int64_t x=v1.x; x<v2.x; x++)
{
int64_t y0 = v1.y + (v2.y - v1.y) * (x - v1.x) / (v2.x - v1.x);
int64_t y1 = v0.y + (v2.y - v0.y) * (x - v0.x) / (v2.x - v0.x);
int64_t z0 = v1.z + (v2.z - v1.z) * (x - v1.x) / (v2.x - v1.x);
int64_t z1 = v0.z + (v2.z - v0.z) * (x - v0.x) / (v2.x - v0.x);
if (y0 > y1) { swap(y0, y1); swap(z0, z1); }
for(int64_t y=y0; y<y1; y++)
storage.grid[x+y*storage.gridWidth].push_back(SupportPoint(z0 + (z1 - z0) * (y-y0) / (y1-y0), cosAngle));
}
}
}
for(int32_t x=0; x<storage.gridWidth; x++)
{
for(int32_t y=0; y<storage.gridHeight; y++)
{
unsigned int n = x+y*storage.gridWidth;
qsort(storage.grid[n].data(), storage.grid[n].size(), sizeof(SupportPoint), cmp_SupportPoint);
}
}
storage.gridOffset.X += storage.gridScale / 2;
storage.gridOffset.Y += storage.gridScale / 2;
}
bool SupportPolyGenerator::needSupportAt(Point p)
{
if (p.X < 1) return false;
if (p.Y < 1) return false;
if (p.X >= storage.gridWidth - 1) return false;
if (p.Y >= storage.gridHeight - 1) return false;
if (done[p.X + p.Y * storage.gridWidth]) return false;
unsigned int n = p.X+p.Y*storage.gridWidth;
if (everywhere)
{
bool ok = false;
for(unsigned int i=0; i<storage.grid[n].size(); i+=2)
{
if (storage.grid[n][i].cosAngle >= cosAngle && storage.grid[n][i].z - supportZDistance >= z && (i == 0 || storage.grid[n][i-1].z + supportZDistance < z))
{
ok = true;
break;
}
}
if (!ok) return false;
}else{
if (storage.grid[n].size() < 1) return false;
if (storage.grid[n][0].cosAngle < cosAngle) return false;
if (storage.grid[n][0].z - supportZDistance < z) return false;
}
return true;
}
void SupportPolyGenerator::lazyFill(Point startPoint)
{
static int nr = 0;
nr++;
ClipperLib::Polygon poly;
ClipperLib::Polygon tmpPoly;
while(1)
{
Point p = startPoint;
done[p.X + p.Y * storage.gridWidth] = nr;
while(needSupportAt(p + Point(1, 0)))
{
p.X ++;
done[p.X + p.Y * storage.gridWidth] = nr;
}
tmpPoly.push_back(startPoint * storage.gridScale + storage.gridOffset - Point(storage.gridScale/2, 0));
poly.push_back(p * storage.gridScale + storage.gridOffset);
startPoint.Y++;
while(!needSupportAt(startPoint) && startPoint.X <= p.X)
startPoint.X ++;
if (startPoint.X > p.X)
{
for(unsigned int n=0;n<tmpPoly.size();n++)
{
poly.push_back(tmpPoly[tmpPoly.size()-n-1]);
}
polygons.add(poly);
return;
}
while(needSupportAt(startPoint - Point(1, 0)) && startPoint.X > 1)
startPoint.X --;
}
}
SupportPolyGenerator::SupportPolyGenerator(SupportStorage& storage, int32_t z)
: storage(storage), z(z), everywhere(storage.everywhere)
{
if (!storage.generated)
return;
cosAngle = cos(double(90 - storage.angle) / 180.0 * M_PI) - 0.01;
this->supportZDistance = storage.ZDistance;
done = new int[storage.gridWidth*storage.gridHeight];
memset(done, 0, sizeof(int) * storage.gridWidth*storage.gridHeight);
for(int32_t y=1; y<storage.gridHeight; y++)
{
for(int32_t x=1; x<storage.gridWidth; x++)
{
if (!needSupportAt(Point(x, y)) || done[x + y * storage.gridWidth]) continue;
lazyFill(Point(x, y));
}
}
delete done;
polygons = polygons.offset(storage.XYDistance);
}