1. 程式人生 > 其它 >.STL模型進行3D列印路徑設計

.STL模型進行3D列印路徑設計

技術標籤:VTKc++pyclipper

首先這篇部落格只留做備份使用:

如果有需要,麻煩下面給我留言:

需要用到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;
}


這個僅用作備份參考,如果有問題,麻煩給我留言。