- Rename several actions, to remove all "_" in their names.

- Add several "&" in action texts.

- NEW files:
   - "Polyhedron_type.h" defines the Kernel and Polyhedron types,
   - "Polyhedron_type_fwd.h" can be used for a forward declaration of the
     type "Polyhedron".

- New functions in Scene:
    int selectionAndex();
    int selectionBindex();
  Boolean operations now use those functions to get the indices of the
  polyhedra.

- The Exact_polyhedron is now only defined in
  MainWindow_boolean_operations.cp, to reduce compilation times.

- The min/max problem is handled better, in MainWindow_pca.cpp (quote the
  macros with () instead of using #undef).

- MainWindow_simplify.cpp now works!!

- Scene.h and Scene.cpp has been splitted in several parts, to decrease
  compilation times:
    - Scene_rendering.h declares:
        void gl_render_facets(Polyhedron* poly);
        void gl_render_edges(Polyhedron *poly);
    - Scene_rendering.cpp defines those two functions by using
      <CGAL/gl_render.h>
    - Scene_polyhedron_operations.cpp contains operations that
      create/delete/load/save polyhedra.
  That way, Scene.h and Scene.cpp are CGAL-agnostic.
This commit is contained in:
Laurent Rineau 2008-07-16 11:08:06 +00:00
parent 96a229ad3c
commit c5654c95e3
18 changed files with 260 additions and 143 deletions

2
.gitignore vendored
View File

@ -237,6 +237,8 @@ Optimisation_doc/doc_ps
Polyhedron/demo/Polyhedron/*.cpp_parameters
Polyhedron/demo/Polyhedron/*.dir
Polyhedron/demo/Polyhedron/*.exe
Polyhedron/demo/Polyhedron/*.ii
Polyhedron/demo/Polyhedron/*.s
Polyhedron/demo/Polyhedron/*.sln
Polyhedron/demo/Polyhedron/*.ui
Polyhedron/demo/Polyhedron/*.vcproj

View File

@ -9,7 +9,7 @@ endif(COMMAND cmake_policy)
set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
foreach(INCDIR ./include ../../../GraphicsView/include)
foreach(INCDIR ./include ../../../GraphicsView/include ../../../Nef_3/include)
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${INCDIR})
include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/${INCDIR})
endif()
@ -52,7 +52,19 @@ add_file_dependencies( Scene_moc.cpp Scene.h )
qt4_add_resources ( RESOURCE_FILES Polyhedron_3.qrc )
add_executable ( Polyhedron_3 MainWindow_moc.cpp Scene_moc.cpp Viewer_moc.cpp main.cpp Viewer.cpp ${UI_FILES} ${RESOURCE_FILES} )
add_executable ( Polyhedron_3 MainWindow.cpp
MainWindow_boolean_operations.cpp
main.cpp
Viewer.cpp
Scene.cpp
Scene_polyhedron_operations.cpp
Scene_rendering.cpp
MainWindow_moc.cpp
Scene_moc.cpp
Viewer_moc.cpp
${UI_FILES} ${RESOURCE_FILES} )
# Link with Qt libraries
target_link_libraries( Polyhedron_3 ${QT_LIBRARIES} )

View File

@ -279,7 +279,7 @@ void MainWindow::on_actionLoadPolyhedron_triggered()
}
}
void MainWindow::on_actionSave_as_triggered()
void MainWindow::on_actionSaveAs_triggered()
{
if(!onePolygonIsSelected())
return;

View File

@ -8,7 +8,9 @@
class QDragEnterEvent;
class QDropEvent;
class Scene;
struct Polyhedron;
#include "Polyhedron_type_fwd.h"
// #include "Scene.h"
class MainWindow :
public CGAL::Qt::DemosMainWindow,
@ -18,10 +20,6 @@ class MainWindow :
public:
MainWindow(QWidget* parent = 0);
enum { BOOLEAN_UNION,
BOOLEAN_INTERSECTION,
BOOLEAN_DIFFERENCE};
public slots:
void updateViewerBBox();
void open(QString filename);
@ -43,7 +41,7 @@ protected slots:
// save
// TODO: save all, save current (do we store the current file name?)
void on_actionSave_as_triggered(); // save selected polyhedron as...
void on_actionSaveAs_triggered(); // save selected polyhedron as...
// merge (TODO)
@ -66,20 +64,23 @@ protected slots:
void on_actionIntersection_triggered();
void on_actionDifference_triggered();
// curvature estimation
// curvature estimation, in MainWindow_curvature_estimation.cpp
void on_actionEstimateCurvature_triggered();
// PCA
// PCA, in MainWindow_pca.cpp
void on_actionFitPlane_triggered();
void on_actionFitLine_triggered();
// self intersection
void on_actionSelf_intersection_triggered();
// self intersection, in MainWindow_self_intersection.cpp
void on_actionSelfIntersection_triggered();
protected:
void boolean_operation(const int operation);
enum Boolean_operation { BOOLEAN_UNION,
BOOLEAN_INTERSECTION,
BOOLEAN_DIFFERENCE };
// define in MainWindow_boolean_operations.cpp
void boolean_operation(const Boolean_operation operation);
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
void closeEvent(QCloseEvent *event);

View File

@ -16,9 +16,9 @@
<property name="geometry" >
<rect>
<x>0</x>
<y>24</y>
<y>29</y>
<width>978</width>
<height>548</height>
<height>540</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout" >
@ -37,9 +37,9 @@
<property name="geometry" >
<rect>
<x>0</x>
<y>22</y>
<y>23</y>
<width>354</width>
<height>508</height>
<height>499</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2" >
@ -122,7 +122,7 @@
<x>0</x>
<y>0</y>
<width>978</width>
<height>24</height>
<height>29</height>
</rect>
</property>
<widget class="QMenu" name="menuFile" >
@ -131,11 +131,11 @@
</property>
<addaction name="actionLoadPolyhedron" />
<addaction name="actionErasePolyhedron" />
<addaction name="actionErase_all" />
<addaction name="actionEraseAll" />
<addaction name="actionDuplicatePolyhedron" />
<addaction name="separator" />
<addaction name="actionMerge_all" />
<addaction name="actionSave_as" />
<addaction name="actionMergeAll" />
<addaction name="actionSaveAs" />
<addaction name="separator" />
<addaction name="actionQuit" />
</widget>
@ -156,7 +156,7 @@
<addaction name="actionFitPlane" />
<addaction name="actionFitLine" />
</widget>
<addaction name="actionSelf_intersection" />
<addaction name="actionSelfIntersection" />
<addaction name="menu_Principale_components_analysis" />
<addaction name="actionEstimateCurvature" />
</widget>
@ -210,9 +210,9 @@
<property name="geometry" >
<rect>
<x>0</x>
<y>572</y>
<y>569</y>
<width>978</width>
<height>22</height>
<height>25</height>
</rect>
</property>
</widget>
@ -312,7 +312,7 @@
<bool>true</bool>
</property>
<property name="text" >
<string>Antialiasing</string>
<string>&amp;Antialiasing</string>
</property>
<property name="shortcut" >
<string>Ctrl+A</string>
@ -325,72 +325,67 @@
</action>
<action name="actionConvexHull" >
<property name="text" >
<string>Convex hull</string>
<string>&amp;Convex hull</string>
</property>
</action>
<action name="actionErase_all" >
<action name="actionEraseAll" >
<property name="text" >
<string>Erase all</string>
<string>&amp;Erase all</string>
</property>
</action>
<action name="actionOptions" >
<property name="text" >
<string>Options...</string>
<string>&amp;Options...</string>
</property>
</action>
<action name="actionLoop" >
<property name="text" >
<string>Loop</string>
<string>&amp;Loop</string>
</property>
</action>
<action name="actionSave_as" >
<action name="actionSaveAs" >
<property name="text" >
<string>Save as...</string>
<string>Save &amp;as...</string>
</property>
</action>
<action name="actionSave" >
<property name="text" >
<string>Save</string>
<string>&amp;Save</string>
</property>
</action>
<action name="actionSave_all" >
<action name="actionSaveAll" >
<property name="text" >
<string>Save all</string>
<string>Save a&amp;ll</string>
</property>
</action>
<action name="actionMerge_all" >
<action name="actionMergeAll" >
<property name="text" >
<string>Merge all</string>
<string>Mer&amp;ge all</string>
</property>
</action>
<action name="actionMerge" >
<property name="text" >
<string>Merge</string>
<string>&amp;Merge</string>
</property>
</action>
<action name="actionSelf_intersection" >
<action name="actionSelfIntersection" >
<property name="text" >
<string>Self-intersection</string>
<string>Self-&amp;intersection</string>
</property>
</action>
<action name="actionSelections" >
<action name="actionSelectAll" >
<property name="text" >
<string>Selections</string>
<string>Select &amp;all</string>
</property>
</action>
<action name="actionSelect_all" >
<action name="actionSelectNone" >
<property name="text" >
<string>Select all</string>
<string>Select &amp;none</string>
</property>
</action>
<action name="actionSelect_none" >
<action name="actionSelectInvert" >
<property name="text" >
<string>Select none</string>
</property>
</action>
<action name="actionSelect_invert" >
<property name="text" >
<string>Invert selection</string>
<string>&amp;Invert selection</string>
</property>
</action>
</widget>

View File

@ -1,8 +1,17 @@
#include "MainWindow.h"
#include "Scene.h"
#include "Polyhedron_type.h"
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Nef_polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <iostream>
#include <fstream>
// Boolean operations work only with exact kernel
typedef CGAL::Exact_predicates_exact_constructions_kernel Exact_Kernel;
typedef CGAL::Polyhedron_3<Exact_Kernel> Exact_polyhedron;
// quick hacks to convert polyhedra from exact to inexact and vice-versa
@ -39,22 +48,18 @@ void MainWindow::on_actionDifference_triggered()
boolean_operation(BOOLEAN_DIFFERENCE);
}
void MainWindow::boolean_operation(const int operation)
void MainWindow::boolean_operation(const Boolean_operation operation)
{
QApplication::setOverrideCursor(Qt::WaitCursor);
// PA: to be done by LR?
//int indexA = scene->getPolygonAIndex();
//int indexB = scene->getPolygonBIndex();
// to remove
int indexA = 0;
int indexB = 1;
const int indexA = scene->selectionAindex();
const int indexB = scene->selectionBindex();
Polyhedron* polyA = scene->polyhedron(indexA);
Polyhedron* polyB = scene->polyhedron(indexB);
if(!polyA) return;
if(!polyB) return;
if(polyA == polyB) return;
typedef CGAL::Nef_polyhedron_3<Exact_Kernel> Nef_polyhedron;

View File

@ -1,7 +1,9 @@
#include "MainWindow.h"
#include "Scene.h"
#include "Polyhedron_type.h"
#include <CGAL/Monge_via_jet_fitting.h>
#include <CGAL/Make_quad_soup.h>
#include <CGAL/compute_normal.h>
void MainWindow::on_actionEstimateCurvature_triggered()
{

View File

@ -1,16 +1,12 @@
#include "MainWindow.h"
#include "Scene.h"
#include "Polyhedron_type.h"
#include <CGAL/centroid.h>
#include <CGAL/bounding_box.h>
#include <CGAL/linear_least_squares_fitting_3.h>
#include <CGAL/Make_quad_soup.h> // for plane fitting
#include <CGAL/Make_bar.h> // for line fitting
// for Visual C++ (which defines min/max macros)
#undef min
#undef max
void MainWindow::on_actionFitPlane_triggered()
{
if(onePolygonIsSelected())
@ -47,8 +43,8 @@ void MainWindow::on_actionFitPlane_triggered()
Iso_cuboid bbox = CGAL::bounding_box(pMesh->points_begin(),pMesh->points_end());
// compute scale for rendering using diagonal of bbox
Point cmin = bbox.min();
Point cmax = bbox.max();
Point cmin = (bbox.min)();
Point cmax = (bbox.max)();
FT diag = std::sqrt(CGAL::squared_distance(cmin,cmax));
Vector u1 = plane.base1();
u1 = u1 / std::sqrt(u1*u1);

View File

@ -8,7 +8,7 @@
#include <CGAL/self_intersect.h>
#include <CGAL/Make_triangle_soup.h>
void MainWindow::on_actionSelf_intersection_triggered()
void MainWindow::on_actionSelfIntersection_triggered()
{
if(onePolygonIsSelected())
{

View File

@ -17,14 +17,13 @@ void MainWindow::on_actionSimplify_triggered()
Polyhedron* pMesh = scene->polyhedron(index);
// simplify
unsigned int nb_edges = 1000; // TODO: should be an option
const unsigned int nb_edges = 1000; // TODO: should be an option
namespace SMS = CGAL::Surface_mesh_simplification;
// DOES NOT COMPILE
//SMS::Count_stop_predicate< Polyhedron > stop(nb_edges); // target # edges
//SMS::edge_collapse( *pMesh, stop,
// CGAL::vertex_index_map(boost::get(CGAL::vertex_external_index,*pMesh))
// .edge_index_map(boost::get(CGAL::edge_external_index,*pMesh)));
SMS::Count_stop_predicate< Polyhedron > stop(nb_edges); // target # edges
SMS::edge_collapse( *pMesh, stop,
CGAL::vertex_index_map(boost::get(CGAL::vertex_external_index,*pMesh))
.edge_index_map(boost::get(CGAL::edge_external_index,*pMesh)));
// update scene
scene->polyhedronChanged(index);

View File

@ -0,0 +1,29 @@
#ifndef POLYHEDRON_TYPE_H
#define POLYHEDRON_TYPE_H
// CGAL
#include <CGAL/basic.h>
// kernel
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
// surface mesh
#include <CGAL/Polyhedron_3.h>
#include "Polyhedron_type_fwd.h"
struct Kernel : public CGAL::Exact_predicates_inexact_constructions_kernel {};
typedef Kernel::FT FT;
typedef Kernel::Line_3 Line;
typedef Kernel::Point_3 Point;
typedef Kernel::Plane_3 Plane;
typedef Kernel::Sphere_3 Sphere;
typedef Kernel::Vector_3 Vector;
typedef Kernel::Triangle_3 Triangle;
typedef Kernel::Iso_cuboid_3 Iso_cuboid;
// struct Polyhedron : public CGAL::Polyhedron_3<Kernel> {};
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
#endif // POLYHEDRON_TYPE_H

View File

@ -0,0 +1,31 @@
#ifndef POLYHEDRON_TYPE_FWD_H
#define POLYHEDRON_TYPE_FWD_H
#include <memory>
struct Kernel;
namespace CGAL {
struct Polyhedron_items_3;
#ifndef CGAL_CFG_NO_TMPL_IN_TMPL_PARAM
template < class T, class I, class A>
#endif
struct HalfedgeDS_default;
template < class PolyhedronTraits_3,
class PolyhedronItems_3,
#ifndef CGAL_CFG_NO_TMPL_IN_TMPL_PARAM
template < class T, class I, class A>
#endif
class T_HDS,
class Alloc
>
class Polyhedron_3;
}
typedef CGAL::Polyhedron_3<Kernel,
CGAL::Polyhedron_items_3,
CGAL::HalfedgeDS_default,
std::allocator<int> > Polyhedron;
#endif // POLYHEDRON_TYPE_FWD_H

View File

@ -1,5 +1,4 @@
#include "Scene.h"
#include <CGAL/IO/Polyhedron_iostream.h>
#include <iostream>
#include <fstream>
@ -13,8 +12,9 @@
#include <QMouseEvent>
#include <QPainter>
#include <QColorDialog>
#include <QApplication>
#include <CGAL/gl_render.h>
#include "Scene_rendering.h"
namespace {
void CGALglcolor(QColor c)
@ -39,7 +39,7 @@ Scene::~Scene()
poly_it = polyhedra.begin(),
poly_end = polyhedra.end();
poly_it != poly_end; ++poly_it) {
delete poly_it->polyhedron_ptr;
this->destroy(poly_it->polyhedron_ptr);
}
polyhedra.clear();
}
@ -64,9 +64,9 @@ Scene::open(QString filename)
return -1;
}
// allocate new polyhedron
Polyhedron* poly = new Polyhedron;
in >> *poly;
// allocate new polyhedron
Polyhedron* poly = this->new_polyhedron();
this->load_polyhedron(poly, in);
if(!in)
{
QMessageBox::critical(qobject_cast<QWidget*>(QObject::parent()),
@ -74,14 +74,13 @@ Scene::open(QString filename)
tr("File %1 is not a valid OFF file.").arg(filename));
QApplication::restoreOverrideCursor();
cerr << QString("\n");
delete poly;
destroy(poly);
return -1;
}
addPolyhedron(poly, fileinfo.baseName());
QApplication::restoreOverrideCursor();
cerr << QString("ok (%1 vertices)\n").arg(poly->size_of_vertices());
return polyhedra.size() - 1;
}
@ -109,7 +108,7 @@ bool Scene::save(int index,
return false;
}
out << *poly;
this->save_polyhedron(poly, out);
cerr << QString("ok\n");
QApplication::restoreOverrideCursor();
@ -140,7 +139,7 @@ void Scene::addPolyhedron(Polyhedron* p,
int
Scene::erase(int polyhedron_index)
{
delete polyhedra[polyhedron_index].polyhedron_ptr;
this->destroy(polyhedra[polyhedron_index].polyhedron_ptr);
polyhedra.removeAt(polyhedron_index--);
selected_item = -1;
@ -158,7 +157,7 @@ int
Scene::duplicate(int polyhedron_index)
{
const Polyhedron_entry& entry = polyhedra[polyhedron_index];
Polyhedron* poly = new Polyhedron(*entry.polyhedron_ptr);
Polyhedron* poly = this->copy_polyhedron(entry.polyhedron_ptr);
addPolyhedron(poly,
tr("%1 (copy)").arg(entry.name),
@ -168,34 +167,6 @@ Scene::duplicate(int polyhedron_index)
return polyhedra.size() - 1;
}
CGAL::Bbox_3
Scene::bbox()
{
if(polyhedra.empty()) {
return CGAL::Bbox_3(0.0, 0.0, 0.0,
1.0, 1.0, 1.0);
}
else
{
Point p = polyhedra.begin()->polyhedron_ptr->vertices_begin()->point();
CGAL::Bbox_3 bbox(p.x(), p.y(), p.z(), p.x(), p.y(), p.z());
for(Polyhedra::iterator
poly_it = polyhedra.begin(),
poly_end = polyhedra.end();
poly_it != poly_end; ++poly_it)
{
for(Polyhedron::Vertex_iterator
v = poly_it->polyhedron_ptr->vertices_begin(),
v_end = poly_it->polyhedron_ptr->vertices_end();
v != v_end; ++v)
{
bbox = bbox + v->point().bbox();
}
}
return bbox;
}
}
void
Scene::draw()
{
@ -213,7 +184,7 @@ Scene::draw()
else
CGALglcolor(entry.color);
gl_render_facets(*poly);
gl_render_facets(poly);
}
if(index == selected_item)
@ -223,7 +194,7 @@ Scene::draw()
// superimpose edges
::glDisable(GL_LIGHTING);
gl_render_edges(*poly);
gl_render_edges(poly);
}
}
}
@ -423,6 +394,14 @@ Scene::RenderingMode Scene::polyhedronRenderingMode(int index)
return polyhedra[index].rendering_mode;
}
int Scene::selectionAindex() const {
return item_A;
}
int Scene::selectionBindex() const {
return item_B;
}
QItemSelection Scene::createSelection(int i)
{
return QItemSelection(QAbstractItemModel::createIndex(i, 0),

View File

@ -10,31 +10,10 @@
#include <QPixmap>
#include <QItemSelection>
// CGAL
#include <CGAL/basic.h>
#include "Polyhedron_type_fwd.h"
#include <CGAL/Bbox_3.h>
// kernel
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
// surface mesh
#include <CGAL/Polyhedron_3.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT;
typedef Kernel::Line_3 Line;
typedef Kernel::Point_3 Point;
typedef Kernel::Plane_3 Plane;
typedef Kernel::Sphere_3 Sphere;
typedef Kernel::Vector_3 Vector;
typedef Kernel::Triangle_3 Triangle;
typedef Kernel::Iso_cuboid_3 Iso_cuboid;
// Boolean operations work only with exact kernel
typedef CGAL::Exact_predicates_exact_constructions_kernel Exact_Kernel;
typedef CGAL::Polyhedron_3<Exact_Kernel> Exact_polyhedron;
struct Polyhedron : public CGAL::Polyhedron_3<Kernel> {};
#include <iostream>
class QEvent;
class QMouseEvent;
@ -85,12 +64,16 @@ public:
QString polyhedronName(int);
bool isPolyhedronActivated(int);
RenderingMode polyhedronRenderingMode(int);
int selectionAindex() const;
int selectionBindex() const;
// for backward compatibility
Polyhedron* getPolyhedron(int i) { return polyhedron(i); }
// draw() is called by Viewer::draw()
void draw();
// defined in Scene_polyhedron_operations.cpp
CGAL::Bbox_3 bbox();
// QAbstractItemModel functions
@ -115,6 +98,19 @@ signals:
void updated_bbox();
void updated();
private:
// functions that need to know the type Polyhedron
// defined in Scene_polyhedron_operations.cpp
Polyhedron* new_polyhedron();
Polyhedron* copy_polyhedron(Polyhedron* poly);
void destroy(Polyhedron*);
bool load_polyhedron(Polyhedron* poly, std::istream& in); // return true
// iif the
// loading is ok.
bool save_polyhedron(Polyhedron* poly, std::ostream& out); // return true
// iif the
// save is ok.
private:
static const QColor defaultColor; // defined in Scene.cpp

View File

@ -0,0 +1,57 @@
#include "Scene.h"
#include "Polyhedron_type.h"
#include <CGAL/IO/Polyhedron_iostream.h>
Polyhedron* Scene::new_polyhedron()
{
return new Polyhedron;
}
Polyhedron* Scene::copy_polyhedron(Polyhedron* poly)
{
return new Polyhedron(*poly);
}
void Scene::destroy(Polyhedron* poly)
{
delete poly;
}
bool Scene::load_polyhedron(Polyhedron* poly, std::istream& in)
{
in >> *poly;
return in;
}
bool Scene::save_polyhedron(Polyhedron* poly, std::ostream& out)
{
out << *poly;
return out;
}
CGAL::Bbox_3
Scene::bbox()
{
if(polyhedra.empty()) {
return CGAL::Bbox_3(0.0, 0.0, 0.0,
1.0, 1.0, 1.0);
}
else
{
Point p = polyhedra.begin()->polyhedron_ptr->vertices_begin()->point();
CGAL::Bbox_3 bbox(p.x(), p.y(), p.z(), p.x(), p.y(), p.z());
for(Polyhedra::iterator
poly_it = polyhedra.begin(),
poly_end = polyhedra.end();
poly_it != poly_end; ++poly_it) {
for(Polyhedron::Vertex_iterator
v = poly_it->polyhedron_ptr->vertices_begin(),
v_end = poly_it->polyhedron_ptr->vertices_end();
v != v_end; ++v)
{
bbox = bbox + v->point().bbox();
}
}
return bbox;
}
}

View File

@ -0,0 +1,12 @@
#include "Polyhedron_type.h"
#include <CGAL/gl_render.h>
void gl_render_facets(Polyhedron* poly)
{
gl_render_facets(*poly);
}
void gl_render_edges(Polyhedron *poly)
{
gl_render_edges(*poly);
}

View File

@ -0,0 +1,4 @@
#include "Polyhedron_type_fwd.h"
void gl_render_facets(Polyhedron* poly);
void gl_render_edges(Polyhedron *poly);

View File

@ -24,11 +24,8 @@ int main(int argc, char **argv)
return app.exec();
}
#include "MainWindow.cpp"
#include "Scene.cpp"
#include "MainWindow_curvature_estimation.cpp"
#include "MainWindow_subdivision_methods.cpp"
#include "MainWindow_boolean_operations.cpp"
#include "MainWindow_self_intersection.cpp"
#include "MainWindow_convex_hull.cpp"
#include "MainWindow_simplify.cpp"