.STL模型進行3D列印路徑設計
阿新 • • 發佈:2020-12-26
首先這篇部落格只留做備份使用:
如果有需要,麻煩下面給我留言:
需要用到VTK庫和Clipper庫
.h標頭檔案:
#ifndef STLCONVERTOR_H
#define STLCONVERTOR_H
#include "vtkAppendPolyData.h"
#include "vtkAxesActor.h"
#include "vtkCamera.h"
#include "vtkCell.h"
#include "vtkCellArray.h"
#include "vtkCleanPolyData.h"
#include "vtkClipPolyData.h"
#include "vtkCutter.h"
#include "vtkGenericRenderWindowInteractor.h"
#include "vtkInteractorStyleJoystickCamera.h"
#include "vtkInteractorStyleTrackballCamera.h"
#include "vtkLODActor.h"
#include "vtkLight.h"
#include "vtkLine.h"
#include "vtkOutputWindow.h"
#include "vtkPlane.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkPolyDataNormals.h"
#include "vtkPolyLine.h"
#include "vtkPropPicker.h"
#include "vtkProperty.h"
#include "vtkRenderWindow.h"
#include "vtkRenderer.h"
#include "vtkSTLReader.h"
#include "vtkShrinkPolyData.h"
#include "vtkStripper.h"
#include "vtkTextActor.h"
#include "vtkTransform.h"
#include "vtkTransformPolyDataFilter.h"
#include "vtkTriangleFilter.h"
#include <QString>
#include <algorithm>
#include <vtkSmartPointer.h>
#include <vtkTriangle.h>
#include "clipper.h"
#include <list>
#include <string>
#include <vector>
#define PI 3.1415926
using namespace std;
using namespace ClipperLib;
class StlConvertor {
public:
StlConvertor() {};
enum FillType {
FullFill,
NoFill
};
static void convert(QString file_name, double scale, double layer_height, double line_width, double angle, double cut_threshold, int wall_thick, double fill_rate, bool fill_type);
static double getRate();
private:
static vtkSmartPointer<vtkTriangleFilter> getcutObj(vtkSmartPointer<vtkPolyData>& src, int normal[], double* center);
static Paths getLayerPoint(vtkSmartPointer<vtkPolyData>& src);
static void cutX(vtkSmartPointer<vtkPolyData>& src, vector<vtkSmartPointer<vtkPolyData>>& object_list, double cut_threshold);
static void cutY(vtkSmartPointer<vtkPolyData>& src, vector<vtkSmartPointer<vtkPolyData>>& object_list, double cut_threshold);
static vector<vtkSmartPointer<vtkPolyData>> cutObject(vtkSmartPointer<vtkPolyData>& src, double cut_threshold);
static vector<vtkSmartPointer<vtkPolyData>> getObjectLayer(vtkSmartPointer<vtkPolyData>& src, double layer_height);
static Paths getContract(Paths paths, double line_width);
static Paths getWallThickness(vtkSmartPointer<vtkPolyData>& src, Paths& final_in, double line_width, int wall_thick);
static Paths fillBound(list<Paths>& target, int n);
//static vector<Paths> getBotTop(vector<vtkSmartPointer<vtkPolyData>>& src, int n);
static Paths getFillSquare(vector<vtkSmartPointer<vtkPolyData>>& src, Paths final_in, double line_width, int n, int wall_thick);
static Paths getFinalFillPath(Paths& target, Paths& grille, int line_width);
static Paths getFillPath(vtkSmartPointer<vtkPolyData>& src, Paths& grille, double line_width, int n, int fill);
static Paths getGrille(double length, double line_width, double angle);
static bool compare(const Path& p1, const Path& p2);
static bool comparePoints(const IntPoint& p1, const IntPoint& p2);
std::string filename;
static double rate;
static double sort_angle;
// static list<Paths> layer_compare_paths;
};
#endif // STLCONVERTOR_H
.cpp檔案:
#include "stlconvertor.h"
double StlConvertor::rate = 0;
double StlConvertor::sort_angle = 0;
void StlConvertor::convert(QString file_name, double scale, double layer_height, double line_width, double angle, double cut_threshold, int wall_thick, double fill_rate, bool fill_type)
{
// 控制不彈出vtk錯誤提示框
vtkOutputWindow::SetGlobalWarningDisplay(0);
sort_angle = angle;
rate = 0;
// 讀取檔案,獲取整個stl的大小
/*std::string file = file_name.toStdString();*/
vtkSmartPointer<vtkSTLReader> reader = vtkSmartPointer<vtkSTLReader>::New();
reader->SetFileName(file_name.toLocal8Bit().toStdString().c_str());
reader->Update();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::New();
mapper->SetInputConnection(reader->GetOutputPort());
vtkSmartPointer<vtkPolyData> src = vtkSmartPointer<vtkPolyData>::New();
src = reader->GetOutput();
// 根據scale引數縮放整個stl
auto transformer = vtkSmartPointer<vtkTransform>::New();
transformer->Scale(scale, scale, scale);
auto transformFilter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
transformFilter->SetInputConnection(reader->GetOutputPort());
transformFilter->SetTransform(transformer);
transformFilter->Update();
// 求最長邊
double longest = 100;
double xmin, ymin, zmin, xmax, ymax, zmax, distance_x, distance_y, distance_z;
vtkPolyData* show_stl1 = transformFilter->GetOutput();
xmin = show_stl1->GetBounds()[0];
xmax = show_stl1->GetBounds()[1];
ymin = show_stl1->GetBounds()[2];
ymax = show_stl1->GetBounds()[3];
zmin = show_stl1->GetBounds()[4];
zmax = show_stl1->GetBounds()[5];
//distance_x = xmax - xmin;
//distance_y = ymax - ymin;
//distance_z = zmax - zmin;
//根據將stl的角點,移動到(0,0,0)
vtkSmartPointer<vtkTransform> distance_move = vtkSmartPointer<vtkTransform>::New();
distance_move->Translate(-xmin, -ymin, -zmin);
auto transformMoveFilter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
transformMoveFilter->SetInputConnection(transformFilter->GetOutputPort());
transformMoveFilter->SetTransform(distance_move);
transformMoveFilter->Update();
auto show_stl = vtkSmartPointer<vtkPolyData>::New();
show_stl = transformMoveFilter->GetOutput();
xmin = show_stl->GetBounds()[0];
xmax = show_stl->GetBounds()[1];
ymin = show_stl->GetBounds()[2];
ymax = show_stl->GetBounds()[3];
zmin = show_stl->GetBounds()[4];
zmax = show_stl->GetBounds()[5];
distance_x = xmax - xmin;
distance_y = ymax - ymin;
//distance_z = zmax - zmin;
//longest = (distance_x > distance_y) ? distance_x > distance_z ? distance_x : distance_z : distance_y > distance_z ? distance_y : distance_z;
longest = (distance_x > distance_y) ? distance_x : distance_y;
//根據縮放之後的stl物件計算填充的格柵
Paths max_grilles = getGrille(longest * 1.5, line_width / fill_rate, angle);
//縮小相交網格的大小,為了提升填充速度
Paths paths1;
Path path1;
path1.push_back(IntPoint(xmin * 1000, ymin * 1000));
path1.push_back(IntPoint(xmin * 1000, ymax * 1000));
path1.push_back(IntPoint(xmax * 1000, ymax * 1000));
path1.push_back(IntPoint(xmax * 1000, ymin * 1000));
paths1.push_back(path1);
Paths grilles = getFinalFillPath(paths1, max_grilles, line_width * 1000);
//根據切塊的閾值得到切塊兒之後的資料
vector<vtkSmartPointer<vtkPolyData>> object_list = cutObject(show_stl, cut_threshold);
rate = 10;
//遍歷每一個分塊
for (unsigned int i = 0; i < object_list.size(); i++) {
vector<vtkSmartPointer<vtkPolyData>> layer_list = getObjectLayer(object_list[i], layer_height);
fstream file;
file.open(file_name.toLocal8Bit().toStdString() + '.' + to_string(i) + ".gwl", ios::out);
//遍歷所有層
for (unsigned int j = 0; j < layer_list.size(); j++) {
Paths result;
//全填充
if (fill_type) {
//將應該填充的區域填充並返回填充資料,並排序
Paths final_in;
result = getWallThickness(layer_list[j], final_in, line_width, wall_thick);
Paths fill_result = getFinalFillPath(final_in, grilles, line_width * 1000);
result.insert(result.end(), fill_result.begin(), fill_result.end());
//複製第一個點的位置,構成閉環
for (unsigned int i = 0; i < result.size(); i++) {
result[i].push_back(result[i][0]);
}
} else {
Paths fill_result, final_in;
result = getWallThickness(layer_list[j], final_in, line_width, wall_thick);
//sort(result.begin(), result.end(), compare);
// 根據上下層獲取需要填充的區域,並填充
Paths target = getFillSquare(layer_list, final_in, line_width, j, wall_thick);
fill_result = getFinalFillPath(target, grilles, line_width * 1000);
//合併多層壁厚與層差
result.insert(result.end(), fill_result.begin(), fill_result.end());
//複製第一個點的位置,構成閉環
for (unsigned int i = 0; i < result.size(); i++) {
result[i].push_back(result[i][0]);
}
}
if (!file) {
std::cerr << "Open File" + to_string(i) + "Fail !" << endl;
}
for (unsigned int m = 0; m < result.size(); m++) {
for (unsigned int n = 0; n < result[m].size(); n++) {
file << double(result[m][n].X / 1000.0) << " " << double(result[m][n].Y / 1000.0) << " " << double(layer_list[j]->GetCenter()[2]) << " " << 100.0 << endl;
}
file << -999 << " " << -999 << " " << -999 << " " << -999 << endl;
}
//將輪廓和填充迴圈輸出到檔案 XXX_i.gwl。
rate = 10 + i * 90.0 / object_list.size() + (0.9 / object_list.size()) * (j * 100.0 / layer_list.size());
}
file << -999 << " " << -999 << " " << -999 << " " << -999 << endl;
file.close();
}
}
/*
* 切塊X方向
*/
void StlConvertor::cutX(vtkSmartPointer<vtkPolyData>& src, vector<vtkSmartPointer<vtkPolyData>>& object_list, double cut_threshold)
{
if (src->GetBounds()[1] - src->GetBounds()[0] < cut_threshold) {
object_list.push_back(src);
return;
} else {
double* center = src->GetCenter();
auto plane1 = vtkSmartPointer<vtkPlane>::New();
plane1->SetOrigin(center[0], center[1], center[2]);
plane1->SetNormal(1, 0, 0);
auto clipper1 = vtkSmartPointer<vtkClipPolyData>::New();
clipper1->SetInputData(src);
clipper1->SetClipFunction(plane1);
clipper1->Update();
int x[3] = { 1, 0, 0 };
auto polydata_x1 = getcutObj(src, x, center);
auto appendFilter_x1 = vtkSmartPointer<vtkAppendPolyData>::New();
appendFilter_x1->AddInputConnection(clipper1->GetOutputPort());
appendFilter_x1->AddInputConnection(polydata_x1->GetOutputPort());
appendFilter_x1->Update();
auto cleanFileter_x1 = vtkSmartPointer<vtkCleanPolyData>::New();
cleanFileter_x1->SetInputData(appendFilter_x1->GetOutput());
cleanFileter_x1->SetInputConnection(appendFilter_x1->GetOutputPort());
cleanFileter_x1->Update();
vtkSmartPointer<vtkPolyData> c_x1(cleanFileter_x1->GetOutput());
cutX(c_x1, object_list, cut_threshold);
auto plane2 = vtkSmartPointer<vtkPlane>::New();
plane2->SetOrigin(center[0], center[1], center[2]);
plane2->SetNormal(-1, 0, 0);
auto clipper2 = vtkSmartPointer<vtkClipPolyData>::New();
clipper2->SetInputData(src);
clipper2->SetClipFunction(plane2);
clipper2->Update();
int x2[3] = { -1, 0, 0 };
auto polydata_x2 = getcutObj(src, x2, center);
auto appendFilter_x2 = vtkSmartPointer<vtkAppendPolyData>::New();
appendFilter_x2->AddInputConnection(clipper2->GetOutputPort());
//appendFilter_x2->SetInputData(polydata_x2);
appendFilter_x2->AddInputConnection(polydata_x2->GetOutputPort());
appendFilter_x2->Update();
auto cleanFileter_x2 = vtkSmartPointer<vtkCleanPolyData>::New();
cleanFileter_x2->SetInputData(appendFilter_x2->GetOutput());
cleanFileter_x2->SetInputConnection(appendFilter_x2->GetOutputPort());
cleanFileter_x2->Update();
vtkSmartPointer<vtkPolyData> c_x2(cleanFileter_x2->GetOutput());
cutX(c_x2, object_list, cut_threshold);
}
}
/*
*切塊Y方向
*/
void StlConvertor::cutY(vtkSmartPointer<vtkPolyData>& src, vector<vtkSmartPointer<vtkPolyData>>& object_list, double cut_threshold)
{
if (src->GetBounds()[3] - src->GetBounds()[2] < cut_threshold) {
object_list.push_back(src);
return;
} else {
double* center = src->GetCenter();
auto plane1 = vtkSmartPointer<vtkPlane>::New();
plane1->SetOrigin(center[0], center[1], center[2]);
plane1->SetNormal(0, 1, 0);
auto clipper1 = vtkSmartPointer<vtkClipPolyData>::New();
clipper1->SetInputData(src);
clipper1->SetClipFunction(plane1);
clipper1->Update();
int y[3] = { 0, 1, 0 };
auto polydata_y1 = getcutObj(src, y, center);
auto appendFilter_y1 = vtkSmartPointer<vtkAppendPolyData>::New();
appendFilter_y1->AddInputConnection(clipper1->GetOutputPort());
//appendFilter_y1->AddInputData(polydata_y1);
appendFilter_y1->AddInputConnection(polydata_y1->GetOutputPort());
appendFilter_y1->Update();
auto cleanFileter_y1 = vtkSmartPointer<vtkCleanPolyData>::New();
cleanFileter_y1->SetInputData(appendFilter_y1->GetOutput());
cleanFileter_y1->SetInputConnection(appendFilter_y1->GetOutputPort());
cleanFileter_y1->Update();
vtkSmartPointer<vtkPolyData> c_y1(cleanFileter_y1->GetOutput());
cutY(c_y1, object_list, cut_threshold);
auto plane2 = vtkSmartPointer<vtkPlane>::New();
plane2->SetOrigin(center[0], center[1], center[2]);
plane2->SetNormal(0, -1, 0);
auto clipper2 = vtkSmartPointer<vtkClipPolyData>::New();
clipper2->SetInputData(src);
clipper2->SetClipFunction(plane2);
clipper2->Update();
int y2[3] = { 0, -1, 0 };
auto polydata_y2 = getcutObj(src, y2, center);
auto appendFilter_y2 = vtkSmartPointer<vtkAppendPolyData>::New();
appendFilter_y2->AddInputConnection(clipper2->GetOutputPort());
appendFilter_y2->AddInputConnection(polydata_y2->GetOutputPort());
appendFilter_y2->Update();
auto cleanFileter_y2 = vtkSmartPointer<vtkCleanPolyData>::New();
cleanFileter_y2->SetInputData(appendFilter_y2->GetOutput());
cleanFileter_y2->SetInputConnection(appendFilter_y2->GetOutputPort());
cleanFileter_y2->Update();
vtkSmartPointer<vtkPolyData> c_y2(cleanFileter_y2->GetOutput());
cutY(c_y2, object_list, cut_threshold);
}
}
/*
* 傳入整個STL物件,根據切塊的閾值得到塊的列表,並返回列表。如果stl不需要切塊兒,也返回列表,元素數量為1.
*/
vector<vtkSmartPointer<vtkPolyData>> StlConvertor::cutObject(vtkSmartPointer<vtkPolyData>& src, double cut_threshold)
{
vector<vtkSmartPointer<vtkPolyData>> object_list;
double xmin, ymin, zmin, xmax, ymax, zmax, distance_x, distance_y, distance_z;
xmin = src->GetBounds()[0];
xmax = src->GetBounds()[1];
ymin = src->GetBounds()[2];
ymax = src->GetBounds()[3];
distance_x = xmax - xmin;
distance_y = ymax - ymin;
// 開始進行切塊
if (distance_x > cut_threshold || distance_y > cut_threshold) {
vector<vtkSmartPointer<vtkPolyData>> object_list1;
cutX(src, object_list1, cut_threshold);
for (unsigned int i = 0; i < object_list1.size(); i++) {
cutY(object_list1[i], object_list, cut_threshold);
}
} else
object_list.push_back(src);
return object_list;
}
/*
* 獲取stl中所有層的二維路徑,為下一步填充做準備。
*/
vector<vtkSmartPointer<vtkPolyData>> StlConvertor::getObjectLayer(vtkSmartPointer<vtkPolyData>& src, double layer_height)
{
vector<vtkSmartPointer<vtkPolyData>> layer_list;
//獲取其中一層
int layer_num = (src->GetBounds()[5] - src->GetBounds()[4]) / layer_height;
vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
vtkSmartPointer<vtkPolyDataNormals> normalGenerator = vtkSmartPointer<vtkPolyDataNormals>::New();
polydata->DeepCopy(src);
normalGenerator->SetInputData(polydata);
normalGenerator->ComputePointNormalsOn();
normalGenerator->ComputeCellNormalsOff();
normalGenerator->Update();
for (int i = 0; i < layer_num; i++) {
vtkSmartPointer<vtkPlane> plane = vtkSmartPointer<vtkPlane>::New();
plane->SetNormal(0, 0, 1);
plane->Push(i * layer_height);
vtkSmartPointer<vtkCutter> cutter = vtkSmartPointer<vtkCutter>::New();
cutter->SetInputData(normalGenerator->GetOutput());
cutter->SetCutFunction(plane);
cutter->GenerateCutScalarsOn();
// cutter->SetValue(0, 0.1);
cutter->Update();
vtkSmartPointer<vtkStripper> stripper = vtkSmartPointer<vtkStripper>::New();
stripper->SetInputConnection(cutter->GetOutputPort());
stripper->Update();
vtkSmartPointer<vtkPolyData> layerpoly = stripper->GetOutput();
layer_list.push_back(layerpoly);
}
return layer_list;
}
Paths StlConvertor::getContract(Paths paths, double line_width)
{
Paths result;
ClipperOffset c;
c.MiterLimit = 10000;
//CleanPolygons(paths, 0);
//這段解決的是有些重合的區域,將重合的區域分開。
Paths simp_polygons;
SimplifyPolygons(paths, simp_polygons, pftEvenOdd);
c.AddPaths(simp_polygons, jtRound, etClosedPolygon);
c.Execute(result, -(int)(line_width));
return result;
}
// 返回已排序的多層輪廓,其中final_in返回最內層輪廓
Paths StlConvertor::getWallThickness(vtkSmartPointer<vtkPolyData>& src, Paths& final_in, double line_width, int wall_thick)
{
Paths result;
Paths layer, pre_path, p;
layer = getLayerPoint(src);
for (int k = 0; k < wall_thick; k++) {
//獲得去重的路徑
p = getContract(layer, k * line_width * 1000.0);
if (p.size() != 0) {
for (unsigned int m = 0; m < p.size(); m++) {
result.push_back(p[m]);
}
pre_path = p;
}
}
Paths sort_result;
for (auto path : result) {
Path::iterator max = max_element(path.begin(), path.end(), comparePoints);
Path tmp;
tmp.insert(tmp.end(), max, path.end());
tmp.insert(tmp.end(), path.begin(), max);
sort_result.push_back(tmp);
}
final_in.clear();
final_in.insert(final_in.end(), pre_path.begin(), pre_path.end());
return sort_result;
}
/*
* 獲取當前層的比例,這個值是乘100後的,後面直接跟%就可以了
*/
double StlConvertor::getRate()
{
return rate;
}
/*
* 返回切片後的結構
*/
vtkSmartPointer<vtkTriangleFilter> StlConvertor::getcutObj(vtkSmartPointer<vtkPolyData>& src, int normal[], double* center)
{
auto polydataNormals = vtkSmartPointer<vtkPolyDataNormals>::New();
polydataNormals->SetInputData(src);
auto plane = vtkSmartPointer<vtkPlane>::New();
plane->SetOrigin(center[0], center[1], center[2]);
plane->SetNormal(normal[0], normal[2], normal[2]);
auto cutEdges = vtkSmartPointer<vtkCutter>::New();
cutEdges->SetInputConnection(polydataNormals->GetOutputPort());
cutEdges->SetCutFunction(plane);
cutEdges->GenerateCutScalarsOn();
cutEdges->SetValue(0, 0);
cutEdges->Update();
auto cutStrips = vtkSmartPointer<vtkStripper>::New();
cutStrips->SetInputConnection(cutEdges->GetOutputPort());
cutStrips->Update();
auto cutPolyData = vtkSmartPointer<vtkPolyData>::New();
cutPolyData->SetPoints(cutStrips->GetOutput()->GetPoints());
cutPolyData->SetPolys(cutStrips->GetOutput()->GetLines());
auto cutTriangles = vtkSmartPointer<vtkTriangleFilter>::New();
cutTriangles->SetInputData(cutPolyData);
//這裡返回的是一個Filter型別的,但是接受的是vtkPolydata型別的。
return vtkSmartPointer<vtkTriangleFilter>(cutTriangles);
}
/*
* 獲取層上的輪廓點
*/
Paths StlConvertor::getLayerPoint(vtkSmartPointer<vtkPolyData>& src)
{
Paths target;
int cellnums = src->GetNumberOfCells();
try {
for (int i = 0; i < cellnums; i++) {
vtkSmartPointer<vtkIdList> pointIdList = vtkSmartPointer<vtkIdList>::New();
src->GetCellPoints(i, pointIdList);
int cellpointsnums = pointIdList->GetNumberOfIds();
Path path;
for (int j = 0; j < cellpointsnums; j++) {
double* p = src->GetPoint(pointIdList->GetId(j));
path.push_back(IntPoint(p[0] * 1000, p[1] * 1000));
}
target.push_back(path);
}
} catch (std::exception e) {
//spdlog::error("GetLayerPointError{0}", e.what());
}
return target;
}
/*
* 給出一層路徑得到這層的填充路徑
*/
Paths StlConvertor::getFillPath(vtkSmartPointer<vtkPolyData>& src, Paths& grille, double line_width, int wall_thick, int fill)
{
//將polyData轉換為Paths格式。
Paths result, in_result;
Paths final_in;
result = getWallThickness(src, final_in, line_width, wall_thick);
//呼叫另一個函式進行填充
return result;
}
/*
* 返回輪廓的已排序填充路徑
*/
Paths StlConvertor::getFinalFillPath(Paths& target, Paths& grille, int line_width)
{
Paths result, temp;
temp = getContract(target, line_width);
Clipper c;
c.AddPaths(grille, ptSubject, true);
c.AddPaths(temp, ptClip, true);
c.Execute(ctIntersection, result, pftEvenOdd, pftEvenOdd);
sort(result.begin(), result.end(), compare);
return result;
}
/*
*填充上下層之間差的部分
*/
Paths StlConvertor::fillBound(list<Paths>& target, int n)
{
Paths result;
auto ele_n = target.begin();
advance(ele_n, n - 1);
for (Paths tp : target) {
Paths tp_result;
Clipper c;
c.AddPaths(*ele_n, ptSubject, true);
c.AddPaths(tp, ptClip, true);
c.Execute(ctDifference, tp_result, pftEvenOdd, pftEvenOdd);
result.insert(result.end(), tp_result.begin(), tp_result.end());
}
// for (unsigned int i = 0; i < target.size(); i++) {
// Paths paths;
// Clipper c;
// if (i < n) {
// c.AddPaths(target., ptSubject, true);
// c.AddPaths(target[i], ptClip, true);
// } else {
// c.AddPaths(target[n], ptSubject, true);
// c.AddPaths(target[i], ptClip, true);
// }
// for (unsigned int j = 0; j < paths.size(); j++) {
// result.push_back(paths[j]);
// }
// }
return result;
}
/*
* 檢視前後一層的影象,返回需要填充的部分。
*/
Paths StlConvertor::getFillSquare(vector<vtkSmartPointer<vtkPolyData>>& src, Paths final_in, double line_width, int n, int wall_thick)
{
Paths result;
list<Paths> layer_compare_paths, add_paths;
Paths ps, grilles, no_use, last_in;
Path path;
if (n <= wall_thick || n >= src.size() - wall_thick) {
result = final_in;
} else {
//前N層
for (int i = n - wall_thick; i < n; i++) {
Paths layer = getLayerPoint(src[i]);
Paths p = getContract(layer, n * line_width * 1000.0);
layer_compare_paths.push_back(p);
}
//當前層
layer_compare_paths.push_back(final_in);
//後N層
for (unsigned int i = n + 1; i < n + wall_thick; i++) {
Paths layer = getLayerPoint(src[i]);
Paths p = getContract(layer, n * line_width * 1000.0);
layer_compare_paths.push_back(p);
}
result = fillBound(layer_compare_paths, wall_thick);
}
return result;
}
/*
* 獲取填充網格
*
* 根據線寬角度生成一個邊長為length的方形填充區域。可以參考圖片填充區域的生成演算法。
*/
Paths StlConvertor::getGrille(double length, double line_width, double angle)
{
// 100就是個例子,需要根據實際情況計算。
float cos_p = cos(PI / 180 * angle) * 1000;
float sin_p = sin(PI / 180 * angle) * 1000;
Paths subj;
Path path;
for (float i = -length; i < length; i = i + line_width * 2) {
path.push_back(IntPoint(length * cos_p - i * sin_p, length * sin_p + cos_p * i));
path.push_back(IntPoint(-length * cos_p - i * sin_p, -length * sin_p + cos_p * i));
path.push_back(IntPoint(-length * cos_p - (i + line_width) * sin_p, -length * sin_p + cos_p * (i + line_width)));
path.push_back(IntPoint(length * cos_p - (i + line_width) * sin_p, length * sin_p + cos_p * (i + line_width)));
path.push_back(IntPoint(length * cos_p - i * sin_p, length * sin_p + cos_p * i));
subj.push_back(path);
path.clear();
}
return subj;
}
bool StlConvertor::compare(const Path& p1, const Path& p2)
{
int y1 = -p1[0].Y * sin(PI / 180 * sort_angle) + p1[0].X * cos(PI / 180 * sort_angle);
int y2 = -p2[0].Y * sin(PI / 180 * sort_angle) + p2[0].X * cos(PI / 180 * sort_angle);
return y1 < y2;
}
bool StlConvertor::comparePoints(const IntPoint& p1, const IntPoint& p2)
{
return p1.X < p2.X || p1.Y < p2.Y;
}
main.cpp主函式:
#include <QtCore/QCoreApplication>
//
//int main(int argc, char *argv[])
//{
// QCoreApplication a(argc, argv);
//
// return a.exec();
//}
#include <iostream>
#include <vtkAutoInit.h>
#include "vtkCamera.h"
#include "vtkGenericRenderWindowInteractor.h"
#include "vtkInteractorStyleJoystickCamera.h"
#include "vtkInteractorStyleTrackballCamera.h"
#include "vtkLODActor.h"
#include "vtkLight.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkPropPicker.h"
#include "vtkProperty.h"
#include "vtkRenderWindow.h"
#include "vtkRenderer.h"
#include "vtkSTLReader.h"
#include "vtkShrinkPolyData.h"
#include <vtkAxesActor.h>
#include <vtkTransform.h>
#include <vtkOutputWindow.h>
#include "clipper.h"
#include "stlconvertor.h"
using namespace ClipperLib;
#include <string.h>
using namespace std;
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
int main(int argc, char *argv[]) {
StlConvertor stl;
//引數:STL檔案路徑、縮放比例、層高、填充線寬、填充線角度、分塊閾值、壁厚、填充率、填充型別(填充和不填充)
//stl.convert("c:/users/34933/desktop/yjbgb.stl",1, 0.075, 0.25, 45, 80,5,1, stl.FullFill);
stl.convert("c:/users/34933/desktop/yuan.stl",1, 1.0, 0.8, 45, 100000,1,1, stl.NoFill);
建立繪製器物件
//vtkOutputWindow::SetGlobalWarningDisplay(0);
//string filename = "c:/users/hp/desktop/8.stl";
//vtkSmartPointer<vtkSTLReader> reader = vtkSmartPointer<vtkSTLReader>::New();
//reader->SetFileName(filename.c_str());
//reader->Update();
//vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::New();
//mapper->SetInputConnection(reader->GetOutputPort());
//double xmin, ymin, zmin, xmax, ymax, zmax;
//vtkPolyData *data1 = reader->GetOutput();
//xmin = data1->GetBounds()[0];
//xmax = data1->GetBounds()[1];
//ymin = data1->GetBounds()[2];
//ymax = data1->GetBounds()[3];
//zmin = data1->GetBounds()[4];
//zmax = data1->GetBounds()[5];
//vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
//actor->SetMapper(mapper);
//vtkSmartPointer<vtkTransform> transfil = vtkSmartPointer<vtkTransform>::New();
//vtkSmartPointer<vtkTransform> trans_axes = vtkSmartPointer<vtkTransform>::New();
//transfil->Translate(-(xmax + xmin) / 2.0, -(ymax + ymin) / 2.0, -(zmax + zmin) / 2.0);
//trans_axes->Translate(-(xmax - xmin) / 2.0, -(ymax - ymin) / 2.0, -(zmax - zmin) / 2.0);
//vtkSmartPointer<vtkAxesActor> axes = vtkSmartPointer<vtkAxesActor>::New();
//axes->SetXAxisLabelText("");
//axes->SetYAxisLabelText("");
//axes->SetZAxisLabelText("");
//axes->SetTotalLength(xmax - xmin + 20, ymax - ymin + 20, zmax - zmin + 20);
//axes->SetNormalizedTipLength(0.0, 0.0, 0.0);
//vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
//renderer->SetBackground(1, 1, 1);
//actor->SetUserTransform(transfil);
//renderer->AddActor(actor);
//axes->SetUserTransform(trans_axes);
//renderer->AddActor(axes);
//vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
//renderWindow->SetSize(600, 600);
//renderWindow->AddRenderer(renderer);
//renderWindow->Render();
//vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
//renderWindowInteractor->SetRenderWindow(renderWindow);
//vtkSmartPointer<vtkInteractorStyleTrackballCamera> style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
//renderWindowInteractor->SetInteractorStyle(style);
//renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
這個僅用作備份參考,如果有問題,麻煩給我留言。