Skip to content

表面细化

cgla 提供了四种细化方式,这是第一天测试结果,明天四种都测试完在更新这一块,这是其中一种细化方法

// 01frame includes
#include "cgalmethods.h"

// VTK includes
#include <vtkSTLReader.h>
#include <vtkSmartPointer.h>

// CGAL includes
#include <CGAL/Simple_cartesian.h>

// CGAL includes
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>
#include <CGAL/subdivision_method_3.h>
#include <CGAL/Timer.h>
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <fstream>
void CGALMethods::CatmullClarkSubdivision(QString off_filename) {
    typedef CGAL::Simple_cartesian<double>         Kernel;
    typedef CGAL::Surface_mesh<Kernel::Point_3>    PolygonMesh;
    using namespace std;
    using namespace CGAL;
    namespace params = CGAL::parameters;

    PolygonMesh pmesh;
    std::ifstream in(off_filename.toLocal8Bit().data());
    if (in.fail()) {
        qWarning() << "Could not open input file ";
        return ;
    }
    in >> pmesh;
    Timer t;
    t.start();
    Subdivision_method_3::CatmullClark_subdivision(
        pmesh, params::number_of_iterations(1));
    std::ofstream out(off_filename.toLocal8Bit().data());
    out << pmesh;
}

细化前结果

细化后结果


完整代码

  • Source/05 CGALThread/cgalthread.h
  • Source/05 CGALThread/cgalthread.cpp
  • Source/05 CGALThread/cgalthreadsubdivision.h
  • Source/05 CGALThread/cgalthreadsubdivision.cpp
/*
 * CGAL线程   操作基类
 * 仅有run函数在子线程,其余均在主线程
*/

#ifndef CGALTHREAD_H
#define CGALTHREAD_H

//01frame
#include "app.h"

class CGALThread : public QThread {
    Q_OBJECT
  public:
    explicit CGALThread(QObject *parent = nullptr);
    virtual ~CGALThread() override;
    bool GetThreadResult() const;//获取结果
  protected:
    virtual void run() override;//线程
    void InitialResult();//初始化
    void SetResult(const bool result);//设置结果
  protected:
    bool result_;//执行结果
};

#endif // CGALTHREAD_H
// 01frame includes
#include "cgalthread.h"

CGALThread::CGALThread(QObject *parent) : QThread(parent) {
    this->InitialResult();
}

CGALThread::~CGALThread() {

}

bool CGALThread::GetThreadResult() const {
    return this->result_;
}

void CGALThread::run() {

}

void CGALThread::InitialResult() {
    this->result_ = false;
}

void CGALThread::SetResult(const bool result) {
    result_ |= result;
}
/*
 * CGAL 表面细分算法
 * */

#ifndef CGALTHREADSUBDIVISIONMETHODS_H
#define CGALTHREADSUBDIVISIONMETHODS_H

// 01frame includes
#include "app.h"

// 05CGALThread includes
#include "cgalthread.h"

// VTK includes
#include <vtkPolyData.h>

class CGALThreadSubdivision : public CGALThread {
    Q_OBJECT
  public:
    explicit CGALThreadSubdivision(QObject *parent = nullptr);
    virtual ~CGALThreadSubdivision() override;
    void doWork();
    void SetSurface(const vtkSmartPointer<vtkPolyData> value);
    vtkSmartPointer<vtkPolyData> GetSurface();
  protected:
    virtual void run() override;
  private:
    void STL2OFF(QString off_filename);
    void OFF2STL(QString off_filename);
    void CatmullClarkSubdivision(QString off_filename);
    vtkPolyData *CustomReader(std::istream &infile);
  private:
    vtkSmartPointer<vtkPolyData> polydata_;

};

#endif // CGALSURFACESUBDIVISIONMETHODS_H
// 01frame includes
#include "cgalthreadsubdivision.h"

// C++ includes
#include <string.h>
#include <fstream>
#include <iostream>

// VTK includes
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkCellArray.h>
#include <vtkSmartPointer.h>

// CGAL includes
#include <CGAL/Timer.h>
#include <CGAL/Surface_mesh.h>
#include <boost/lexical_cast.hpp>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/subdivision_method_3.h>
#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>

CGALThreadSubdivision::CGALThreadSubdivision(QObject *parent) :
    CGALThread(parent) {
    this->polydata_ = nullptr;
}

CGALThreadSubdivision::~CGALThreadSubdivision() {

}

void CGALThreadSubdivision::doWork() {
    STL2OFF("STL2OFF.off");
    CatmullClarkSubdivision("STL2OFF.off");
    OFF2STL("STL2OFF.off");
    this->SetResult(true);
}

void CGALThreadSubdivision::SetSurface(const vtkSmartPointer<vtkPolyData> value) {
    this->polydata_ = value;
}

vtkSmartPointer<vtkPolyData> CGALThreadSubdivision::GetSurface() {
    return this->polydata_;
}

void CGALThreadSubdivision::run() {
    this->InitialResult();
    this->doWork();
}

void CGALThreadSubdivision::STL2OFF(QString off_filename) {
    qDebug();

    if (this->polydata_ == nullptr) {
        return;
    }
    if (off_filename.isEmpty()) {
        return;
    }

    double x[3];
    QFile file(off_filename);
    file.open(QIODevice::WriteOnly);
    file.close();
    if (file.open(QIODevice::ReadWrite | QIODevice::Text)) {
        QTextStream stream(&file);
        stream.seek(file.size());
        stream << "OFF" << "\n";
        stream << this->polydata_->GetNumberOfPoints() << " "
               << this->polydata_->GetNumberOfCells() << " 0\n";
        for (int ww = 0; ww < this->polydata_->GetNumberOfPoints() ; ww++) {
            this->polydata_->GetPoint(ww, x);
            stream << x[0] << " " << x[1] << " " << x[2] << "\n";
        }
        for (int ww = 0; ww < this->polydata_->GetNumberOfCells() ; ww++) {
            stream << this->polydata_->GetCell(ww)->GetNumberOfPoints() << " ";
            for (int i = 0; i <
                    this->polydata_->GetCell(ww)->GetNumberOfPoints(); i++) {
                stream << this->polydata_->GetCell(ww)->GetPointId(i) << " ";
            }
            stream << "\n";
        }
        file.close();
    }
}

void CGALThreadSubdivision::OFF2STL(QString off_filename) {
    std::string inputFilename = off_filename.toLocal8Bit().data();
    std::ifstream fin(inputFilename.c_str());
    if (this->polydata_ == nullptr) {
        return;
    }
    this->polydata_ = vtkSmartPointer<vtkPolyData>::Take(CustomReader(fin));
}

void CGALThreadSubdivision::CatmullClarkSubdivision(QString off_filename) {
    typedef CGAL::Simple_cartesian<double>         Kernel;
    typedef CGAL::Surface_mesh<Kernel::Point_3>    PolygonMesh;
    using namespace std;
    using namespace CGAL;
    namespace params = CGAL::parameters;
    PolygonMesh pmesh;
    std::ifstream in(off_filename.toLocal8Bit().data());
    if (in.fail()) {
        qWarning() << "Could not open input file ";
        return ;
    }
    in >> pmesh;

    Subdivision_method_3::CatmullClark_subdivision(
        pmesh, params::number_of_iterations(1));
    Timer t;
    t.start();
    Subdivision_method_3::CatmullClark_subdivision(
        pmesh, params::number_of_iterations(1));
    std::cerr << "Done (" << t.time() << " s)" << std::endl;
    std::ofstream out(off_filename.toLocal8Bit().data());
    out << pmesh;
}

vtkPolyData *CGALThreadSubdivision::CustomReader(istream &infile) {
    qDebug();
    char buf[1000];
    infile.getline(buf, 1000);
    if (strcmp(buf, "off") == 0 || strcmp(buf, "OFF") == 0) {
        vtkIdType number_of_points, number_of_triangles, number_of_lines;
        infile >> number_of_points >> number_of_triangles >> number_of_lines;
        vtkSmartPointer<vtkPoints> points
            = vtkSmartPointer<vtkPoints>::New();
        points->SetNumberOfPoints(number_of_points);
        for (vtkIdType i = 0; i < number_of_points; i++) {
            double x, y, z;
            infile >> x >> y >> z;
            points->SetPoint(i, x, y, z);
        }
        vtkSmartPointer<vtkCellArray> polys
            = vtkSmartPointer<vtkCellArray>::New();
        int n;
        vtkIdType type;
        for (vtkIdType i = 0; i < number_of_triangles; i++) {
            infile >> n;
            polys->InsertNextCell(n);
            for (; n > 0; n--) {
                infile >> type;
                polys->InsertCellPoint(type);
            }
        }
        vtkPolyData *polydata = vtkPolyData::New();
        polydata->SetPoints(points);
        polydata->SetPolys(polys);
        return polydata;
    }
    vtkPolyData *polydata = vtkPolyData::New();
    return polydata;
}