From c7b9a49c15f10ee76258f735ff66c1ed32e64c51 Mon Sep 17 00:00:00 2001 From: kintel Date: Tue, 9 Feb 2010 13:48:09 +0000 Subject: [PATCH] Cleaned up progress handling, implemented cancel function. Needs more testing git-svn-id: http://svn.clifford.at/openscad/trunk@420 b57f626f-c46c-0410-a088-ec61d464b74c --- openscad.pro | 6 +- src/MainWindow.h | 1 + src/dxflinextrude.cc | 37 +---- src/dxfrotextrude.cc | 36 +---- src/mainwin.cc | 364 +++++++++++++++++++++++++------------------ src/node.cc | 65 ++++++-- src/node.h | 8 +- src/openscad.cc | 2 +- src/polyset.cc | 52 ------- src/progress.cc | 28 ++++ src/progress.h | 16 ++ src/projection.cc | 37 +---- src/render.cc | 22 +-- 13 files changed, 320 insertions(+), 354 deletions(-) create mode 100644 src/progress.cc create mode 100644 src/progress.h diff --git a/openscad.pro b/openscad.pro index d2050c3f..8ab9b31e 100644 --- a/openscad.pro +++ b/openscad.pro @@ -86,7 +86,8 @@ HEADERS += src/CGAL_renderer.h \ src/openscad.h \ src/polyset.h \ src/printutils.h \ - src/value.h + src/value.h \ + src/progress.h SOURCES += src/openscad.cc \ src/mainwin.cc \ @@ -118,7 +119,8 @@ SOURCES += src/openscad.cc \ src/highlighter.cc \ src/printutils.cc \ src/nef2dxf.cc \ - src/Preferences.cc + src/Preferences.cc \ + src/progress.cc macx { HEADERS += src/AppleEvents.h \ diff --git a/src/MainWindow.h b/src/MainWindow.h index de738cad..216b7e25 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -68,6 +68,7 @@ private: void load(); AbstractNode *find_root_tag(AbstractNode *n); void compile(bool procevents); + void compileCSG(bool procevents); bool maybeSave(); private slots: diff --git a/src/dxflinextrude.cc b/src/dxflinextrude.cc index f1aaf8cc..ff270dad 100644 --- a/src/dxflinextrude.cc +++ b/src/dxflinextrude.cc @@ -31,6 +31,7 @@ #include "dxfdata.h" #include "dxftess.h" #include "polyset.h" +#include "progress.h" #include "openscad.h" // get_fragments_from_r() #include @@ -209,17 +210,6 @@ static void add_slice(PolySet *ps, DxfData::Path *pt, double rot1, double rot2, } } -static void report_func(const class AbstractNode*, void *vp, int mark) -{ - QProgressDialog *pd = (QProgressDialog*)vp; - int v = (int)((mark*100.0) / progress_report_count); - pd->setValue(v < 100 ? v : 99); - QString label; - label.sprintf("Rendering Polygon Mesh using CGAL (%d/%d)", mark, progress_report_count); - pd->setLabelText(label); - QApplication::processEvents(); -} - PolySet *DxfLinearExtrudeNode::render_polyset(render_mode_e rm) const { QString key = mk_cache_id(); @@ -234,26 +224,9 @@ PolySet *DxfLinearExtrudeNode::render_polyset(render_mode_e rm) const if (filename.isEmpty()) { #ifdef ENABLE_CGAL - QTime t; - QProgressDialog *pd = NULL; - - if (rm == RENDER_OPENCSG) - { - PRINT_NOCACHE("Processing uncached linear_extrude outline..."); - QApplication::processEvents(); - - t.start(); - pd = new QProgressDialog("Rendering Polygon Mesh using CGAL...", QString(), 0, 100); - pd->setValue(0); - pd->setAutoClose(false); - pd->show(); - QApplication::processEvents(); - - progress_report_prep((AbstractNode*)this, report_func, pd); - } // Before extruding, union all (2D) children nodes - // to a single DxfData, then tessealte this into a PolySet + // to a single DxfData, then tesselate this into a PolySet CGAL_Nef_polyhedron N; N.dim = 2; foreach(AbstractNode * v, children) { @@ -263,12 +236,6 @@ PolySet *DxfLinearExtrudeNode::render_polyset(render_mode_e rm) const } dxf = new DxfData(N); - if (rm == RENDER_OPENCSG) { - progress_report_fin(); - int s = t.elapsed() / 1000; - PRINTF_NOCACHE("..rendering time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60); - delete pd; - } #else // ENABLE_CGAL PRINT("WARNING: Found linear_extrude() statement without dxf file but compiled without CGAL support!"); dxf = new DxfData(); diff --git a/src/dxfrotextrude.cc b/src/dxfrotextrude.cc index 21718ac2..ba0d4201 100644 --- a/src/dxfrotextrude.cc +++ b/src/dxfrotextrude.cc @@ -30,6 +30,7 @@ #include "builtin.h" #include "polyset.h" #include "dxfdata.h" +#include "progress.h" #include "openscad.h" // get_fragments_from_r() #include @@ -112,17 +113,6 @@ void register_builtin_dxf_rotate_extrude() builtin_modules["rotate_extrude"] = new DxfRotateExtrudeModule(); } -static void report_func(const class AbstractNode*, void *vp, int mark) -{ - QProgressDialog *pd = (QProgressDialog*)vp; - int v = (int)((mark*100.0) / progress_report_count); - pd->setValue(v < 100 ? v : 99); - QString label; - label.sprintf("Rendering Polygon Mesh using CGAL (%d/%d)", mark, progress_report_count); - pd->setLabelText(label); - QApplication::processEvents(); -} - PolySet *DxfRotateExtrudeNode::render_polyset(render_mode_e rm) const { QString key = mk_cache_id(); @@ -137,24 +127,6 @@ PolySet *DxfRotateExtrudeNode::render_polyset(render_mode_e rm) const if (filename.isEmpty()) { #ifdef ENABLE_CGAL - QTime t; - QProgressDialog *pd; - - if (rm == RENDER_OPENCSG) - { - PRINT_NOCACHE("Processing uncached rotate_extrude outline..."); - QApplication::processEvents(); - - t.start(); - pd = new QProgressDialog("Rendering Polygon Mesh using CGAL...", QString(), 0, 100); - pd->setValue(0); - pd->setAutoClose(false); - pd->show(); - QApplication::processEvents(); - - progress_report_prep((AbstractNode*)this, report_func, pd); - } - CGAL_Nef_polyhedron N; N.dim = 2; foreach(AbstractNode * v, children) { @@ -164,12 +136,6 @@ PolySet *DxfRotateExtrudeNode::render_polyset(render_mode_e rm) const } dxf = new DxfData(N); - if (rm == RENDER_OPENCSG) { - progress_report_fin(); - int s = t.elapsed() / 1000; - PRINTF_NOCACHE("..rendering time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60); - delete pd; - } #else // ENABLE_CGAL PRINT("WARNING: Found rotate_extrude() statement without dxf file but compiled without CGAL support!"); dxf = new DxfData(); diff --git a/src/mainwin.cc b/src/mainwin.cc index e9bbdaae..02ea4454 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -37,6 +37,7 @@ #include "export.h" #include "builtin.h" #include "dxftess.h" +#include "progress.h" #include #include @@ -45,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -336,6 +338,20 @@ MainWindow::~MainWindow() #endif } +typedef QPair ProgressData; + +static void report_func(const class AbstractNode*, void *vp, int mark) +{ + ProgressData *progpair = static_cast(vp); + int v = (int)((mark*100.0) / progress_report_count); + progpair->first->setValue(v < 100 ? v : 99); + QString label; + label.sprintf("Rendering Polygon Mesh (%d/%d)", mark, progress_report_count); + progpair->second->setLabelText(label); + QApplication::processEvents(); + if (progpair->second->wasCanceled()) throw ProgressCancelException(); +} + /*! Requests to open a file from an external event, e.g. by double-clicking a filename. */ @@ -458,6 +474,9 @@ AbstractNode *MainWindow::find_root_tag(AbstractNode *n) return NULL; } +/*! + Parse and evaluate the design -> this->root_node +*/ void MainWindow::compile(bool procevents) { PRINT("Parsing design (AST generation)..."); @@ -554,7 +573,7 @@ void MainWindow::compile(bool procevents) if (procevents) QApplication::processEvents(); - AbstractNode::idx_counter = 1; + AbstractNode::resetIndexCounter(); root_inst = ModuleInstantiation(); absolute_root_node = root_module->evaluate(&root_ctx, &root_inst); @@ -567,89 +586,6 @@ void MainWindow::compile(bool procevents) } root_node->dump(""); - PRINT("Compiling design (CSG Products generation)..."); - if (procevents) - QApplication::processEvents(); - - double m[20]; - - for (int i = 0; i < 16; i++) - m[i] = i % 5 == 0 ? 1.0 : 0.0; - for (int i = 16; i < 20; i++) - m[i] = -1; - - // Main CSG evaluation - root_raw_term = root_node->render_csg_term(m, &highlight_terms, &background_terms); - - if (!root_raw_term) - goto fail; - - PRINT("Compiling design (CSG Products normalization)..."); - if (procevents) - QApplication::processEvents(); - - root_norm_term = root_raw_term->link(); - - // CSG normalization - while (1) { - CSGTerm *n = root_norm_term->normalize(); - root_norm_term->unlink(); - if (root_norm_term == n) - break; - root_norm_term = n; - } - - if (!root_norm_term) - goto fail; - - root_chain = new CSGChain(); - root_chain->import(root_norm_term); - - if (root_chain->polysets.size() > 1000) { - PRINTF("WARNING: Normalized tree has %d elements!", root_chain->polysets.size()); - PRINTF("WARNING: OpenCSG rendering has been disabled."); - } else { - enableOpenCSG = true; - } - - if (highlight_terms.size() > 0) - { - PRINTF("Compiling highlights (%d CSG Trees)...", highlight_terms.size()); - if (procevents) - QApplication::processEvents(); - - highlights_chain = new CSGChain(); - for (int i = 0; i < highlight_terms.size(); i++) { - while (1) { - CSGTerm *n = highlight_terms[i]->normalize(); - highlight_terms[i]->unlink(); - if (highlight_terms[i] == n) - break; - highlight_terms[i] = n; - } - highlights_chain->import(highlight_terms[i]); - } - } - - if (background_terms.size() > 0) - { - PRINTF("Compiling background (%d CSG Trees)...", background_terms.size()); - if (procevents) - QApplication::processEvents(); - - background_chain = new CSGChain(); - for (int i = 0; i < background_terms.size(); i++) { - while (1) { - CSGTerm *n = background_terms[i]->normalize(); - background_terms[i]->unlink(); - if (background_terms[i] == n) - break; - background_terms[i] = n; - } - background_chain->import(background_terms[i]); - } - } - if (1) { PRINT("Compilation finished."); if (procevents) @@ -677,6 +613,126 @@ fail: } } +/*! + Generates CSG tree for OpenCSG evaluation. + Assumes that the design has been parsed and evaluated +*/ +void MainWindow::compileCSG(bool procevents) +{ + assert(this->root_node); + PRINT("Compiling design (CSG Products generation)..."); + if (procevents) + QApplication::processEvents(); + + double m[20]; + + for (int i = 0; i < 16; i++) + m[i] = i % 5 == 0 ? 1.0 : 0.0; + for (int i = 16; i < 20; i++) + m[i] = -1; + + // Main CSG evaluation + QTime t; + t.start(); + + QProgressDialog *pd = new QProgressDialog("Rendering CSG products...", "Cancel", 0, 100); + QProgressBar *bar = new QProgressBar(pd); + bar->setRange(0, 100); + bar->setValue(0); + pd->setBar(bar); + pd->setAutoClose(false); + pd->show(); + ProgressData progpair(bar, pd); + QApplication::processEvents(); + + progress_report_prep(root_node, report_func, &progpair); + try { + root_raw_term = root_node->render_csg_term(m, &highlight_terms, &background_terms); + if (!root_raw_term) { + PRINT("ERROR: CSG generation failed! (no top level object found)"); + if (procevents) + QApplication::processEvents(); + } + } + catch (ProgressCancelException e) { + } + progress_report_fin(); + delete pd; + + if (root_raw_term) { + PRINT("Compiling design (CSG Products normalization)..."); + if (procevents) + QApplication::processEvents(); + + root_norm_term = root_raw_term->link(); + + // CSG normalization + while (1) { + CSGTerm *n = root_norm_term->normalize(); + root_norm_term->unlink(); + if (root_norm_term == n) + break; + root_norm_term = n; + } + + assert(root_norm_term); + + root_chain = new CSGChain(); + root_chain->import(root_norm_term); + + if (root_chain->polysets.size() > 1000) { + PRINTF("WARNING: Normalized tree has %d elements!", root_chain->polysets.size()); + PRINTF("WARNING: OpenCSG rendering has been disabled."); + } else { + enableOpenCSG = true; + } + + if (highlight_terms.size() > 0) + { + PRINTF("Compiling highlights (%d CSG Trees)...", highlight_terms.size()); + if (procevents) + QApplication::processEvents(); + + highlights_chain = new CSGChain(); + for (int i = 0; i < highlight_terms.size(); i++) { + while (1) { + CSGTerm *n = highlight_terms[i]->normalize(); + highlight_terms[i]->unlink(); + if (highlight_terms[i] == n) + break; + highlight_terms[i] = n; + } + highlights_chain->import(highlight_terms[i]); + } + } + + if (background_terms.size() > 0) + { + PRINTF("Compiling background (%d CSG Trees)...", background_terms.size()); + if (procevents) + QApplication::processEvents(); + + background_chain = new CSGChain(); + for (int i = 0; i < background_terms.size(); i++) { + while (1) { + CSGTerm *n = background_terms[i]->normalize(); + background_terms[i]->unlink(); + if (background_terms[i] == n) + break; + background_terms[i] = n; + } + background_chain->import(background_terms[i]); + } + } + + PRINT("CSG generation finished."); + int s = t.elapsed() / 1000; + PRINTF("Total rendering time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60); + if (procevents) + QApplication::processEvents(); + } +} + void MainWindow::actionNew() { #ifdef ENABLE_MDI @@ -909,6 +965,7 @@ void MainWindow::actionReloadCompile() current_win = this; compile(true); + if (this->root_node) compileCSG(true); #ifdef ENABLE_OPENCSG if (!(viewActionOpenCSG->isVisible() && viewActionOpenCSG->isChecked()) && @@ -929,6 +986,7 @@ void MainWindow::actionCompile() console->clear(); compile(!viewActionAnimate->isChecked()); + if (this->root_node) compileCSG(!viewActionAnimate->isChecked()); // Go to non-CGAL view mode if (!viewActionOpenCSG->isChecked() && !viewActionThrownTogether->isChecked()) { @@ -952,17 +1010,6 @@ void MainWindow::actionCompile() #ifdef ENABLE_CGAL -static void report_func(const class AbstractNode*, void *vp, int mark) -{ - QProgressDialog *pd = (QProgressDialog*)vp; - int v = (int)((mark*100.0) / progress_report_count); - pd->setValue(v < 100 ? v : 99); - QString label; - label.sprintf("Rendering Polygon Mesh using CGAL (%d/%d)", mark, progress_report_count); - pd->setLabelText(label); - QApplication::processEvents(); -} - void MainWindow::actionRenderCGAL() { current_win = this; @@ -985,72 +1032,85 @@ void MainWindow::actionRenderCGAL() QTime t; t.start(); - QProgressDialog *pd = new QProgressDialog("Rendering Polygon Mesh using CGAL...", QString(), 0, 100); - pd->setValue(0); + QProgressDialog *pd = new QProgressDialog("Rendering Polygon Mesh using CGAL...", "Cancel", 0, 100); + QProgressBar *bar = new QProgressBar(pd); + bar->setRange(0, 100); + bar->setValue(0); + pd->setBar(bar); pd->setAutoClose(false); pd->show(); +// this->statusBar()->addPermanentWidget(bar); + ProgressData progpair(bar, pd); QApplication::processEvents(); - progress_report_prep(root_node, report_func, pd); - this->root_N = new CGAL_Nef_polyhedron(root_node->render_cgal_nef_polyhedron()); + progress_report_prep(root_node, report_func, &progpair); + try { + this->root_N = new CGAL_Nef_polyhedron(root_node->render_cgal_nef_polyhedron()); + } + catch (ProgressCancelException e) { + } progress_report_fin(); +// this->statusBar()->removeWidget(bar); - PRINTF("Number of vertices currently in CGAL cache: %d", AbstractNode::cgal_nef_cache.totalCost()); - PRINTF("Number of objects currently in CGAL cache: %d", AbstractNode::cgal_nef_cache.size()); - QApplication::processEvents(); + if (this->root_N) + { + PRINTF("Number of vertices currently in CGAL cache: %d", AbstractNode::cgal_nef_cache.totalCost()); + PRINTF("Number of objects currently in CGAL cache: %d", AbstractNode::cgal_nef_cache.size()); + QApplication::processEvents(); - if (this->root_N->dim == 2) { - PRINTF(" Top level object is a 2D object:"); - QApplication::processEvents(); - PRINTF(" Empty: %6s", this->root_N->p2.is_empty() ? "yes" : "no"); - QApplication::processEvents(); - PRINTF(" Plane: %6s", this->root_N->p2.is_plane() ? "yes" : "no"); - QApplication::processEvents(); - PRINTF(" Vertices: %6d", (int)this->root_N->p2.explorer().number_of_vertices()); - QApplication::processEvents(); - PRINTF(" Halfedges: %6d", (int)this->root_N->p2.explorer().number_of_halfedges()); - QApplication::processEvents(); - PRINTF(" Edges: %6d", (int)this->root_N->p2.explorer().number_of_edges()); - QApplication::processEvents(); - PRINTF(" Faces: %6d", (int)this->root_N->p2.explorer().number_of_faces()); - QApplication::processEvents(); - PRINTF(" FaceCycles: %6d", (int)this->root_N->p2.explorer().number_of_face_cycles()); - QApplication::processEvents(); - PRINTF(" ConnComp: %6d", (int)this->root_N->p2.explorer().number_of_connected_components()); - QApplication::processEvents(); + if (this->root_N->dim == 2) { + PRINTF(" Top level object is a 2D object:"); + QApplication::processEvents(); + PRINTF(" Empty: %6s", this->root_N->p2.is_empty() ? "yes" : "no"); + QApplication::processEvents(); + PRINTF(" Plane: %6s", this->root_N->p2.is_plane() ? "yes" : "no"); + QApplication::processEvents(); + PRINTF(" Vertices: %6d", (int)this->root_N->p2.explorer().number_of_vertices()); + QApplication::processEvents(); + PRINTF(" Halfedges: %6d", (int)this->root_N->p2.explorer().number_of_halfedges()); + QApplication::processEvents(); + PRINTF(" Edges: %6d", (int)this->root_N->p2.explorer().number_of_edges()); + QApplication::processEvents(); + PRINTF(" Faces: %6d", (int)this->root_N->p2.explorer().number_of_faces()); + QApplication::processEvents(); + PRINTF(" FaceCycles: %6d", (int)this->root_N->p2.explorer().number_of_face_cycles()); + QApplication::processEvents(); + PRINTF(" ConnComp: %6d", (int)this->root_N->p2.explorer().number_of_connected_components()); + QApplication::processEvents(); + } + + if (this->root_N->dim == 3) { + PRINTF(" Top level object is a 3D object:"); + PRINTF(" Simple: %6s", this->root_N->p3.is_simple() ? "yes" : "no"); + QApplication::processEvents(); + PRINTF(" Valid: %6s", this->root_N->p3.is_valid() ? "yes" : "no"); + QApplication::processEvents(); + PRINTF(" Vertices: %6d", (int)this->root_N->p3.number_of_vertices()); + QApplication::processEvents(); + PRINTF(" Halfedges: %6d", (int)this->root_N->p3.number_of_halfedges()); + QApplication::processEvents(); + PRINTF(" Edges: %6d", (int)this->root_N->p3.number_of_edges()); + QApplication::processEvents(); + PRINTF(" Halffacets: %6d", (int)this->root_N->p3.number_of_halffacets()); + QApplication::processEvents(); + PRINTF(" Facets: %6d", (int)this->root_N->p3.number_of_facets()); + QApplication::processEvents(); + PRINTF(" Volumes: %6d", (int)this->root_N->p3.number_of_volumes()); + QApplication::processEvents(); + } + + int s = t.elapsed() / 1000; + PRINTF("Total rendering time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60); + + if (!viewActionCGALSurfaces->isChecked() && !viewActionCGALGrid->isChecked()) { + viewModeCGALSurface(); + } else { + screen->updateGL(); + } + + PRINT("Rendering finished."); } - if (this->root_N->dim == 3) { - PRINTF(" Top level object is a 3D object:"); - PRINTF(" Simple: %6s", this->root_N->p3.is_simple() ? "yes" : "no"); - QApplication::processEvents(); - PRINTF(" Valid: %6s", this->root_N->p3.is_valid() ? "yes" : "no"); - QApplication::processEvents(); - PRINTF(" Vertices: %6d", (int)this->root_N->p3.number_of_vertices()); - QApplication::processEvents(); - PRINTF(" Halfedges: %6d", (int)this->root_N->p3.number_of_halfedges()); - QApplication::processEvents(); - PRINTF(" Edges: %6d", (int)this->root_N->p3.number_of_edges()); - QApplication::processEvents(); - PRINTF(" Halffacets: %6d", (int)this->root_N->p3.number_of_halffacets()); - QApplication::processEvents(); - PRINTF(" Facets: %6d", (int)this->root_N->p3.number_of_facets()); - QApplication::processEvents(); - PRINTF(" Volumes: %6d", (int)this->root_N->p3.number_of_volumes()); - QApplication::processEvents(); - } - - int s = t.elapsed() / 1000; - PRINTF("Total rendering time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60); - - if (!viewActionCGALSurfaces->isChecked() && !viewActionCGALGrid->isChecked()) { - viewModeCGALSurface(); - } else { - screen->updateGL(); - } - - PRINT("Rendering finished."); - delete pd; current_win = NULL; } diff --git a/src/node.cc b/src/node.cc index e4d14778..31215492 100644 --- a/src/node.cc +++ b/src/node.cc @@ -27,6 +27,8 @@ #include "node.h" #include "module.h" #include "csgterm.h" +#include "progress.h" +#include "polyset.h" #include int AbstractNode::idx_counter; @@ -55,7 +57,7 @@ QString AbstractNode::mk_cache_id() const #ifdef ENABLE_CGAL -AbstractNode::cgal_nef_cache_entry::cgal_nef_cache_entry(CGAL_Nef_polyhedron N) : +AbstractNode::cgal_nef_cache_entry::cgal_nef_cache_entry(const CGAL_Nef_polyhedron &N) : N(N), msg(print_messages_stack.last()) { }; QCache AbstractNode::cgal_nef_cache(100000); @@ -167,35 +169,64 @@ QString AbstractIntersectionNode::dump(QString indent) const return dump_cache; } -int progress_report_count; -void (*progress_report_f)(const class AbstractNode*, void*, int); -void *progress_report_vp; - void AbstractNode::progress_prepare() { foreach (AbstractNode *v, children) v->progress_prepare(); - progress_mark = ++progress_report_count; + this->progress_mark = ++progress_report_count; } void AbstractNode::progress_report() const { - if (progress_report_f) - progress_report_f(this, progress_report_vp, progress_mark); + progress_update(this, this->progress_mark); } -void progress_report_prep(AbstractNode *root, void (*f)(const class AbstractNode *node, void *vp, int mark), void *vp) +#ifdef ENABLE_CGAL + +CGAL_Nef_polyhedron AbstractPolyNode::render_cgal_nef_polyhedron() const { - progress_report_count = 0; - progress_report_f = f; - progress_report_vp = vp; - root->progress_prepare(); + QString cache_id = mk_cache_id(); + if (cgal_nef_cache.contains(cache_id)) { + progress_report(); + PRINT(cgal_nef_cache[cache_id]->msg); + return cgal_nef_cache[cache_id]->N; + } + + print_messages_push(); + + PolySet *ps = render_polyset(RENDER_CGAL); + try { + CGAL_Nef_polyhedron N = ps->render_cgal_nef_polyhedron(); + cgal_nef_cache.insert(cache_id, new cgal_nef_cache_entry(N), N.weight()); + print_messages_pop(); + progress_report(); + + ps->unlink(); + return N; + } + catch (...) { // Don't leak the PolySet on ProgressCancelException + ps->unlink(); + throw; + } } -void progress_report_fin() +#endif /* ENABLE_CGAL */ + +CSGTerm *AbstractPolyNode::render_csg_term(double m[20], QVector *highlights, QVector *background) const { - progress_report_count = 0; - progress_report_f = NULL; - progress_report_vp = NULL; + PolySet *ps = render_polyset(RENDER_OPENCSG); + return render_csg_term_from_ps(m, highlights, background, ps, modinst, idx); +} + +CSGTerm *AbstractPolyNode::render_csg_term_from_ps(double m[20], QVector *highlights, QVector *background, PolySet *ps, const ModuleInstantiation *modinst, int idx) +{ + CSGTerm *t = new CSGTerm(ps, m, QString("n%1").arg(idx)); + if (modinst->tag_highlight && highlights) + highlights->append(t->link()); + if (modinst->tag_background && background) { + background->append(t); + return NULL; + } + return t; } diff --git a/src/node.h b/src/node.h index 9121a3b7..969c80ee 100644 --- a/src/node.h +++ b/src/node.h @@ -17,7 +17,10 @@ void progress_report_fin(); class AbstractNode { + static int idx_counter; // Node instantiation index public: + static void resetIndexCounter() { idx_counter = 1; } + QVector children; const class ModuleInstantiation *modinst; @@ -26,7 +29,6 @@ public: void progress_report() const; int idx; - static int idx_counter; QString dump_cache; AbstractNode(const ModuleInstantiation *mi); @@ -36,7 +38,7 @@ public: struct cgal_nef_cache_entry { CGAL_Nef_polyhedron N; QString msg; - cgal_nef_cache_entry(CGAL_Nef_polyhedron N); + cgal_nef_cache_entry(const CGAL_Nef_polyhedron &N); }; static QCache cgal_nef_cache; virtual CGAL_Nef_polyhedron render_cgal_nef_polyhedron() const; @@ -64,7 +66,7 @@ public: RENDER_OPENCSG }; AbstractPolyNode(const ModuleInstantiation *mi) : AbstractNode(mi) { }; - virtual class PolySet *render_polyset(render_mode_e mode) const; + virtual class PolySet *render_polyset(render_mode_e mode) const = 0; #ifdef ENABLE_CGAL virtual CGAL_Nef_polyhedron render_cgal_nef_polyhedron() const; #endif diff --git a/src/openscad.cc b/src/openscad.cc index 44c4e3c4..f2e1afc3 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -227,7 +227,7 @@ int main(int argc, char **argv) QString original_path = QDir::currentPath(); QDir::setCurrent(fileInfo.absolutePath()); - AbstractNode::idx_counter = 1; + AbstractNode::resetIndexCounter(); root_node = root_module->evaluate(&root_ctx, &root_inst); CGAL_Nef_polyhedron *root_N; diff --git a/src/polyset.cc b/src/polyset.cc index 0285b95e..8eccf37c 100644 --- a/src/polyset.cc +++ b/src/polyset.cc @@ -24,9 +24,6 @@ */ #include "polyset.h" -#include "node.h" -#include "module.h" -#include "csgterm.h" #include "printutils.h" #include "Preferences.h" @@ -666,52 +663,3 @@ CGAL_Nef_polyhedron PolySet::render_cgal_nef_polyhedron() const #endif /* ENABLE_CGAL */ -PolySet *AbstractPolyNode::render_polyset(render_mode_e) const -{ - return NULL; -} - -#ifdef ENABLE_CGAL - -CGAL_Nef_polyhedron AbstractPolyNode::render_cgal_nef_polyhedron() const -{ - QString cache_id = mk_cache_id(); - if (cgal_nef_cache.contains(cache_id)) { - progress_report(); - PRINT(cgal_nef_cache[cache_id]->msg); - return cgal_nef_cache[cache_id]->N; - } - - print_messages_push(); - - PolySet *ps = render_polyset(RENDER_CGAL); - CGAL_Nef_polyhedron N = ps->render_cgal_nef_polyhedron(); - - cgal_nef_cache.insert(cache_id, new cgal_nef_cache_entry(N), N.weight()); - print_messages_pop(); - progress_report(); - - ps->unlink(); - return N; -} - -#endif /* ENABLE_CGAL */ - -CSGTerm *AbstractPolyNode::render_csg_term(double m[20], QVector *highlights, QVector *background) const -{ - PolySet *ps = render_polyset(RENDER_OPENCSG); - return render_csg_term_from_ps(m, highlights, background, ps, modinst, idx); -} - -CSGTerm *AbstractPolyNode::render_csg_term_from_ps(double m[20], QVector *highlights, QVector *background, PolySet *ps, const ModuleInstantiation *modinst, int idx) -{ - CSGTerm *t = new CSGTerm(ps, m, QString("n%1").arg(idx)); - if (modinst->tag_highlight && highlights) - highlights->append(t->link()); - if (modinst->tag_background && background) { - background->append(t); - return NULL; - } - return t; -} - diff --git a/src/progress.cc b/src/progress.cc new file mode 100644 index 00000000..300147d0 --- /dev/null +++ b/src/progress.cc @@ -0,0 +1,28 @@ +#include "progress.h" +#include "node.h" + +int progress_report_count; +void (*progress_report_f)(const class AbstractNode*, void*, int); +void *progress_report_userdata; + +void progress_report_prep(AbstractNode *root, void (*f)(const class AbstractNode *node, void *userdata, int mark), void *userdata) +{ + progress_report_count = 0; + progress_report_f = f; + progress_report_userdata = userdata; + root->progress_prepare(); +} + +void progress_report_fin() +{ + progress_report_count = 0; + progress_report_f = NULL; + progress_report_userdata = NULL; +} + +void progress_update(const AbstractNode *node, int mark) +{ + if (progress_report_f) + progress_report_f(node, progress_report_userdata, mark); +} + diff --git a/src/progress.h b/src/progress.h new file mode 100644 index 00000000..33c340cf --- /dev/null +++ b/src/progress.h @@ -0,0 +1,16 @@ +#ifndef PROGRESS_H_ +#define PROGRESS_H_ + +// Reset to 0 in _prep() and increased for each Node instance in progress_prepare() +extern int progress_report_count; + +extern void (*progress_report_f)(const class AbstractNode*, void*, int); +extern void *progress_report_userdata; + +void progress_report_prep(AbstractNode *root, void (*f)(const class AbstractNode *node, void *userdata, int mark), void *userdata); +void progress_report_fin(); +void progress_update(const AbstractNode *node, int mark); + +class ProgressCancelException { }; + +#endif diff --git a/src/projection.cc b/src/projection.cc index 75aaf44c..fa45ff35 100644 --- a/src/projection.cc +++ b/src/projection.cc @@ -32,6 +32,7 @@ #include "dxftess.h" #include "polyset.h" #include "export.h" +#include "progress.h" #include #include @@ -95,17 +96,6 @@ void register_builtin_projection() #ifdef ENABLE_CGAL -static void report_func(const class AbstractNode*, void *vp, int mark) -{ - QProgressDialog *pd = (QProgressDialog*)vp; - int v = (int)((mark*100.0) / progress_report_count); - pd->setValue(v < 100 ? v : 99); - QString label; - label.sprintf("Rendering Polygon Mesh using CGAL (%d/%d)", mark, progress_report_count); - pd->setLabelText(label); - QApplication::processEvents(); -} - PolySet *ProjectionNode::render_polyset(render_mode_e rm) const { QString key = mk_cache_id(); @@ -116,24 +106,6 @@ PolySet *ProjectionNode::render_polyset(render_mode_e rm) const print_messages_push(); - QTime t; - QProgressDialog *pd = NULL; - - if (rm == RENDER_OPENCSG) - { - PRINT_NOCACHE("Processing uncached projection body..."); - QApplication::processEvents(); - - t.start(); - pd = new QProgressDialog("Rendering Polygon Mesh using CGAL...", QString(), 0, 100); - pd->setValue(0); - pd->setAutoClose(false); - pd->show(); - QApplication::processEvents(); - - progress_report_prep((AbstractNode*)this, report_func, pd); - } - CGAL_Nef_polyhedron N; N.dim = 3; foreach(AbstractNode *v, this->children) { @@ -142,13 +114,6 @@ PolySet *ProjectionNode::render_polyset(render_mode_e rm) const N.p3 += v->render_cgal_nef_polyhedron().p3; } - if (rm == RENDER_OPENCSG) { - progress_report_fin(); - int s = t.elapsed() / 1000; - PRINTF_NOCACHE("..rendering time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60); - delete pd; - } - PolySet *ps = new PolySet(); ps->convexity = this->convexity; ps->is2d = true; diff --git a/src/render.cc b/src/render.cc index 27a9aa51..1081f5bf 100644 --- a/src/render.cc +++ b/src/render.cc @@ -32,6 +32,7 @@ #include "csgterm.h" #include "builtin.h" #include "printutils.h" +#include "progress.h" #ifdef ENABLE_CGAL # include "cgal.h" #endif @@ -124,17 +125,6 @@ CGAL_Nef_polyhedron RenderNode::render_cgal_nef_polyhedron() const return N; } -static void report_func(const class AbstractNode*, void *vp, int mark) -{ - QProgressDialog *pd = (QProgressDialog*)vp; - int v = (int)((mark*100.0) / progress_report_count); - pd->setValue(v < 100 ? v : 99); - QString label; - label.sprintf("Rendering Polygon Mesh using CGAL (%d/%d)", mark, progress_report_count); - pd->setLabelText(label); - QApplication::processEvents(); -} - CSGTerm *RenderNode::render_csg_term(double m[20], QVector *highlights, QVector *background) const { QString key = mk_cache_id(); @@ -162,20 +152,10 @@ CSGTerm *RenderNode::render_csg_term(double m[20], QVector *highlights QTime t; t.start(); - QProgressDialog *pd = new QProgressDialog("Rendering Polygon Mesh using CGAL...", QString(), 0, 100); - pd->setValue(0); - pd->setAutoClose(false); - pd->show(); - QApplication::processEvents(); - - progress_report_prep((AbstractNode*)this, report_func, pd); N = this->render_cgal_nef_polyhedron(); - progress_report_fin(); int s = t.elapsed() / 1000; PRINTF_NOCACHE("..rendering time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60); - - delete pd; } PolySet *ps = NULL;