diff options
author | Marius Kintel <marius@kintel.net> | 2013-12-09 04:12:13 (GMT) |
---|---|---|
committer | Marius Kintel <marius@kintel.net> | 2013-12-09 04:12:13 (GMT) |
commit | 462d4d447885594629fefb8a658f9f1d079bcc44 (patch) | |
tree | 6690951e4f814b87a1a372a913b75ceda1f6cc1a /src | |
parent | 435e0c021c5018ee5de69d3218c3e31c8ab75be5 (diff) | |
parent | 33c34b6f7c43d19bbfa3bf91e7b577bcc062e5bd (diff) |
Merge branch 'master' into travis
Diffstat (limited to 'src')
-rw-r--r-- | src/AboutDialog.html | 2 | ||||
-rw-r--r-- | src/CGALEvaluator.cc | 18 | ||||
-rw-r--r-- | src/CGAL_Nef3_workaround.h | 352 | ||||
-rw-r--r-- | src/CGAL_Nef_polyhedron.cc | 19 | ||||
-rw-r--r-- | src/CocoaUtils.mm | 4 | ||||
-rw-r--r-- | src/MainWindow.h | 1 | ||||
-rw-r--r-- | src/MainWindow.ui | 7 | ||||
-rw-r--r-- | src/PlatformUtils.cc | 2 | ||||
-rw-r--r-- | src/PolySetCGALEvaluator.cc | 9 | ||||
-rw-r--r-- | src/QGLView.cc | 11 | ||||
-rw-r--r-- | src/QGLView.h | 1 | ||||
-rw-r--r-- | src/cgal.h | 8 | ||||
-rw-r--r-- | src/control.cc | 24 | ||||
-rw-r--r-- | src/dxfdata.h | 4 | ||||
-rw-r--r-- | src/editor.cc | 14 | ||||
-rw-r--r-- | src/editor.h | 2 | ||||
-rw-r--r-- | src/export.cc | 10 | ||||
-rw-r--r-- | src/expr.cc | 23 | ||||
-rw-r--r-- | src/linalg.h | 5 | ||||
-rw-r--r-- | src/mainwin.cc | 8 | ||||
-rw-r--r-- | src/modcontext.cc | 2 | ||||
-rw-r--r-- | src/openscad.cc | 9 | ||||
-rw-r--r-- | src/parser.y | 2 | ||||
-rw-r--r-- | src/stl-utils.cc | 2 | ||||
-rw-r--r-- | src/value.cc | 102 | ||||
-rw-r--r-- | src/value.h | 76 | ||||
-rw-r--r-- | src/version_check.h | 14 |
27 files changed, 655 insertions, 76 deletions
diff --git a/src/AboutDialog.html b/src/AboutDialog.html index b5a5d7c..99e7c3b 100644 --- a/src/AboutDialog.html +++ b/src/AboutDialog.html @@ -47,7 +47,7 @@ Please visit this link for a copy of the license: <a href="http://www.gnu.org/li <li><a href="http://gmplib.org/">GNU GMP</a> <li><a href="http://www.mpfr.org/">GNU MPFR</a> <li><a href="http://www.cgal.org">CGAL</a> -<li><a href="http://eigen.tuxfamily.org">Eigen2</a> +<li><a href="http://eigen.tuxfamily.org">Eigen</a> <li><a href="http://www.opencsg.org">OpenCSG</a> <li><a href="http://www.opengl.org/">OpenGL</a> <li><a href="http://glew.sourceforge.net">GLEW</a> diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc index ec01315..86118d7 100644 --- a/src/CGALEvaluator.cc +++ b/src/CGALEvaluator.cc @@ -159,9 +159,21 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node) PRINT("Hull() currently requires a valid 2-manifold. Please modify your design. See http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/STL_Import_and_Export"); } else { - chN.p3->convert_to_Polyhedron(P); - std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points3d), - boost::bind(static_cast<const CGAL_Polyhedron::Vertex::Point_3&(CGAL_Polyhedron::Vertex::*)() const>(&CGAL_Polyhedron::Vertex::point), _1)); + bool err = false; + std::string errmsg(""); + try { + err = nefworkaround::convert_to_Polyhedron<CGAL_Kernel3>( *(chN.p3), P ); + //chN.p3->convert_to_Polyhedron(P); + } catch (const CGAL::Failure_exception &e) { + err = true; + errmsg = std::string(e.what()); + } + if (err) { + PRINTB("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed. %s", errmsg); + } else { + std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points3d), + boost::bind(static_cast<const CGAL_Polyhedron::Vertex::Point_3&(CGAL_Polyhedron::Vertex::*)() const>(&CGAL_Polyhedron::Vertex::point), _1)); + } } } chnode->progress_report(); diff --git a/src/CGAL_Nef3_workaround.h b/src/CGAL_Nef3_workaround.h new file mode 100644 index 0000000..c2482ac --- /dev/null +++ b/src/CGAL_Nef3_workaround.h @@ -0,0 +1,352 @@ +// Copyright (c) 1997-2002,2005 Max-Planck-Institute Saarbruecken (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/releases/CGAL-4.0-branch/Nef_3/include/CGAL/Nef_helper_3.h $ +// $Id: Nef_helper_3.h 67117 2012-01-13 18:14:48Z lrineau $ +// +// +// Author(s) : Michael Seel <seel@mpi-sb.mpg.de> +// Miguel Granados <granados@mpi-sb.mpg.de> +// Susan Hert <hert@mpi-sb.mpg.de> +// Lutz Kettner <kettner@mpi-sb.mpg.de> +// Ralf Osbild <osbild@mpi-sb.mpg.de> +// Peter Hachenberger <hachenberger@mpi-sb.mpg.de> + +/* + modified by don bright for OpenSCAD, 2013. + +This works around issue #410, where CGAL's Nef_Polyhedron3.convert_to_Polyhedron +throws an uncatchable exception, due to an CGAL_Assertion being thrown in +Polyhedron Incremental Builder's destructor while a Triangulation exception +is still active, resulting in program termination (crashing). + +The purpose here is not to improve/change the way CGAL's Nef code works, +but instead to tweak it slightly to prevent OpenSCAD from crashing. The +behavior of the code should otherwise be exactly the same as CGAL's standard +code. + +This file was created by copying three sections +from CGAL's Nef_polyhedron3.h that were protected/private: + + Triangulation_handler2 + Build_Polyhedron + convert_to_polyhedron + +Very small code changes have been made. First, there are many template +type specifiers added to enable the movement of the code to the outside +of the Nef Polyhedron class. Second, there is a try{}catch(...){} block +added in the Builder around the Triangulation code. Third, there is an error +variable added for non-Exception communication with the caller. + +Eventually, if CGAL itself is updated and the update is widely +distributed, this file may become obsolete and can be deleted from OpenSCAD + +*/ + + +#ifndef _CGAL_NEF3_WORKAROUND_H +#define _CGAL_NEF3_WORKAROUND_H + +#include <CGAL/Polyhedron_incremental_builder_3.h> +#include <CGAL/Polyhedron_3.h> +#include <CGAL/assertions.h> + +#include <CGAL/Constrained_triangulation_2.h> +#include <CGAL/Triangulation_data_structure_2.h> +#include <CGAL/Projection_traits_xy_3.h> +#include <CGAL/Projection_traits_yz_3.h> +#include <CGAL/Projection_traits_xz_3.h> +#include <CGAL/Constrained_triangulation_face_base_2.h> + +#include "printutils.h" + +namespace nefworkaround { + +template<typename Kernel, typename Nef> +class Triangulation_handler2 { + + typedef typename CGAL::Triangulation_vertex_base_2<Kernel> Vb; + typedef typename CGAL::Constrained_triangulation_face_base_2<Kernel> Fb; + typedef typename CGAL::Triangulation_data_structure_2<Vb,Fb> TDS; + typedef typename CGAL::Constrained_triangulation_2<Kernel,TDS> CT; + + typedef typename CT::Face_handle Face_handle; + typedef typename CT::Vertex_handle CTVertex_handle; + typedef typename CT::Finite_faces_iterator Finite_face_iterator; + typedef typename CT::Edge Edge; + CT ct; + CGAL::Unique_hash_map<Face_handle, bool> visited; + CGAL::Unique_hash_map<CTVertex_handle, typename Nef::Vertex_const_handle> ctv2v; + Finite_face_iterator fi; + typename Nef::Plane_3 supporting_plane; + + public: + Triangulation_handler2(typename Nef::Halffacet_const_handle f) : + visited(false), supporting_plane(f->plane()) { + + typename Nef::Halffacet_cycle_const_iterator fci; + for(fci=f->facet_cycles_begin(); fci!=f->facet_cycles_end(); ++fci) { + if(fci.is_shalfedge()) { + typename Nef::SHalfedge_around_facet_const_circulator sfc(fci), send(sfc); + CGAL_For_all(sfc,send) { + CGAL_NEF_TRACEN(" insert point" << sfc->source()->source()->point()); + CTVertex_handle ctv = ct.insert(sfc->source()->source()->point()); + ctv2v[ctv] = sfc->source()->source(); + } + } + } + + for(fci=f->facet_cycles_begin(); fci!=f->facet_cycles_end(); ++fci) { + if(fci.is_shalfedge()) { + typename Nef::SHalfedge_around_facet_const_circulator sfc(fci), send(sfc); + CGAL_For_all(sfc,send) { + CGAL_NEF_TRACEN(" insert constraint" << sfc->source()->source()->point() + << "->" << sfc->source()->twin()->source()->point()); + ct.insert_constraint(sfc->source()->source()->point(), + sfc->source()->twin()->source()->point()); + } + } + } + CGAL_assertion(ct.is_valid()); + + CGAL_NEF_TRACEN("number of finite triangles " << ct.number_of_faces()); + + typename CT::Face_handle infinite = ct.infinite_face(); + typename CT::Vertex_handle ctv = infinite->vertex(1); + if(ct.is_infinite(ctv)) ctv = infinite->vertex(2); + CGAL_assertion(!ct.is_infinite(ctv)); + + typename CT::Face_handle opposite; + typename CT::Face_circulator vc(ctv,infinite); + do { opposite = vc++; + } while(!ct.is_constrained(typename CT::Edge(vc,vc->index(opposite)))); + typename CT::Face_handle first = vc; + + CGAL_assertion(!ct.is_infinite(first)); + traverse_triangulation(first, first->index(opposite)); + + fi = ct.finite_faces_begin(); + } + + void traverse_triangulation(Face_handle f, int parent) { + visited[f] = true; + if(!ct.is_constrained(Edge(f,ct.cw(parent))) && !visited[f->neighbor(ct.cw(parent))]) { + Face_handle child(f->neighbor(ct.cw(parent))); + traverse_triangulation(child, child->index(f)); + } + if(!ct.is_constrained(Edge(f,ct.ccw(parent))) && !visited[f->neighbor(ct.ccw(parent))]) { + Face_handle child(f->neighbor(ct.ccw(parent))); + traverse_triangulation(child, child->index(f)); + } + } + + template<typename Triangle_3> + bool get_next_triangle(Triangle_3& tr) { + while(fi != ct.finite_faces_end() && visited[fi] == false) ++fi; + if(fi == ct.finite_faces_end()) return false; + tr = Triangle_3(fi->vertex(0)->point(), fi->vertex(1)->point(), fi->vertex(2)->point()); + ++fi; + return true; + } + + bool same_orientation(typename Nef::Plane_3 p1) const { + if(p1.a() != 0) + return CGAL::sign(p1.a()) == CGAL::sign(supporting_plane.a()); + if(p1.b() != 0) + return CGAL::sign(p1.b()) == CGAL::sign(supporting_plane.b()); + return CGAL::sign(p1.c()) == CGAL::sign(supporting_plane.c()); + } + + template<typename PIB, typename Index> + void handle_triangles(PIB& pib, Index& VI) { + while(fi != ct.finite_faces_end() && visited[fi] == false) ++fi; + while(fi != ct.finite_faces_end()) { + typename Nef::Plane_3 plane(fi->vertex(0)->point(), + fi->vertex(1)->point(), + fi->vertex(2)->point()); + pib.begin_facet(); + if(same_orientation(plane)) { + pib.add_vertex_to_facet(VI[ctv2v[fi->vertex(0)]]); + pib.add_vertex_to_facet(VI[ctv2v[fi->vertex(1)]]); + pib.add_vertex_to_facet(VI[ctv2v[fi->vertex(2)]]); + } else { + pib.add_vertex_to_facet(VI[ctv2v[fi->vertex(0)]]); + pib.add_vertex_to_facet(VI[ctv2v[fi->vertex(2)]]); + pib.add_vertex_to_facet(VI[ctv2v[fi->vertex(1)]]); + } + pib.end_facet(); + do { + ++fi; + } while(fi != ct.finite_faces_end() && visited[fi] == false); + } + } +}; + + + + + + + + +template <class HDS, typename Kernel, typename Nef> +class Build_polyhedron : public CGAL::Modifier_base<HDS> { +public: + bool error; // added for OpenSCAD + class Visitor { + typedef typename CGAL::Projection_traits_xy_3<Kernel> XY; + typedef typename CGAL::Projection_traits_yz_3<Kernel> YZ; + typedef typename CGAL::Projection_traits_xz_3<Kernel> XZ; + + const CGAL::Object_index<typename Nef::Vertex_const_iterator>& VI; + CGAL::Polyhedron_incremental_builder_3<HDS>& B; + const typename Nef::SNC_const_decorator& D; + + public: + bool error;//added for OpenSCAD + Visitor(CGAL::Polyhedron_incremental_builder_3<HDS>& BB, + const typename Nef::SNC_const_decorator& sd, + CGAL::Object_index<typename Nef::Vertex_const_iterator>& vi) : VI(vi), B(BB), D(sd), error(false) {} + + void visit(typename Nef::Halffacet_const_handle opposite_facet) { + + CGAL_NEF_TRACEN("Build_polyhedron: visit facet " << opposite_facet->plane()); + + CGAL_assertion(Nef::Infi_box::is_standard(opposite_facet->plane())); + + typename Nef::SHalfedge_const_handle se; + typename Nef::Halffacet_cycle_const_iterator fc; + + typename Nef::Halffacet_const_handle f = opposite_facet->twin(); + + typename Nef::SHalfedge_around_facet_const_circulator + sfc1(f->facet_cycles_begin()), sfc2(sfc1); + + if(++f->facet_cycles_begin() != f->facet_cycles_end() || + ++(++(++sfc1)) != sfc2) { + typename Nef::Vector_3 orth = f->plane().orthogonal_vector(); + int c = CGAL::abs(orth[0]) > CGAL::abs(orth[1]) ? 0 : 1; + c = CGAL::abs(orth[2]) > CGAL::abs(orth[c]) ? 2 : c; + + try{ // added for OpenSCAD + if(c == 0) { + Triangulation_handler2<YZ,Nef> th(f); + th.handle_triangles(B, VI); + } else if(c == 1) { + Triangulation_handler2<XZ,Nef> th(f); + th.handle_triangles(B, VI); + } else if(c == 2) { + Triangulation_handler2<XY,Nef> th(f); + th.handle_triangles(B, VI); + } else + CGAL_error_msg( "wrong value"); + } catch(...) { // added for OpenSCAD + PRINT("ERROR: CGAL NefPolyhedron Triangulation failed"); // added for OpenSCAD + this->error=true; //added for OpenSCAD + } // added for OpenSCAD + } else { + + B.begin_facet(); + fc = f->facet_cycles_begin(); + se = typename Nef::SHalfedge_const_handle(fc); + CGAL_assertion(se!=0); + typename Nef::SHalfedge_around_facet_const_circulator hc_start(se); + typename Nef::SHalfedge_around_facet_const_circulator hc_end(hc_start); + CGAL_For_all(hc_start,hc_end) { + CGAL_NEF_TRACEN(" add vertex " << hc_start->source()->center_vertex()->point()); + B.add_vertex_to_facet(VI[hc_start->source()->center_vertex()]); + } + B.end_facet(); + } + } + + void visit(typename Nef::SFace_const_handle) {} + void visit(typename Nef::Halfedge_const_handle) {} + void visit(typename Nef::Vertex_const_handle) {} + void visit(typename Nef::SHalfedge_const_handle) {} + void visit(typename Nef::SHalfloop_const_handle) {} + }; + + public: + + const typename Nef::SNC_const_decorator& scd; + CGAL::Object_index<typename Nef::Vertex_const_iterator> VI; + + Build_polyhedron(const typename Nef::SNC_const_decorator& s) : error(false), + scd(s), VI(s.vertices_begin(),s.vertices_end(),'V') {} + + void operator()( HDS& hds) { + CGAL::Polyhedron_incremental_builder_3<HDS> B(hds, true); + + int skip_volumes; + if(Nef::Infi_box::extended_kernel()) { + B.begin_surface(scd.number_of_vertices()-8, + scd.number_of_facets()-6, + scd.number_of_edges()-12); + skip_volumes = 2; + } + else { + B.begin_surface(scd.number_of_vertices(), + 2*scd.number_of_vertices()-4, + 3*scd.number_of_vertices()-6); + skip_volumes = 1; + } + + int vertex_index = 0; + typename Nef::Vertex_const_iterator v; + CGAL_forall_vertices(v,scd) { + if(Nef::Infi_box::is_standard(v->point())) { + VI[v]=vertex_index++; + B.add_vertex(v->point()); + } + } + + Visitor V(B,scd,VI); + typename Nef::Volume_const_handle c; + CGAL_forall_volumes(c,scd) + if(skip_volumes-- <= 0) { + scd.visit_shell_objects(typename Nef:: SFace_const_handle(c->shells_begin()),V); + } + B.end_surface(); + this->error=B.error()||V.error; // added for OpenSCAD + if (B.error()) B.rollback(); // added for OpenSCAD + } + +}; + +template <typename Kernel> +bool convert_to_Polyhedron( const CGAL::Nef_polyhedron_3<Kernel> &N, CGAL::Polyhedron_3<Kernel> &P ) +{ + // several lines here added for OpenSCAD + typedef typename CGAL::Nef_polyhedron_3<Kernel> Nef3; + typedef typename CGAL::Polyhedron_3<Kernel> Polyhedron; + typedef typename Polyhedron::HalfedgeDS HalfedgeDS; + CGAL_precondition(N.is_simple()); + P.clear(); + Build_polyhedron<HalfedgeDS,Kernel,Nef3> bp(N); + P.delegate(bp); + return bp.error; +} + + + + + +} //namespace nefworkaround + + + + +#endif + diff --git a/src/CGAL_Nef_polyhedron.cc b/src/CGAL_Nef_polyhedron.cc index 440f4ed..49b9a53 100644 --- a/src/CGAL_Nef_polyhedron.cc +++ b/src/CGAL_Nef_polyhedron.cc @@ -96,13 +96,22 @@ PolySet *CGAL_Nef_polyhedron::convertToPolyset() } else if (this->dim == 3) { CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); + bool err = true; + std::string errmsg(""); + CGAL_Polyhedron P; try { - CGAL_Polyhedron P; - this->p3->convert_to_Polyhedron(P); - ps = createPolySetFromPolyhedron(P); + err = nefworkaround::convert_to_Polyhedron<CGAL_Kernel3>( *(this->p3), P ); + //this->p3->convert_to_Polyhedron(P); + } + catch (const CGAL::Failure_exception &e) { + err = true; + errmsg = std::string(e.what()); } - catch (const CGAL::Precondition_exception &e) { - PRINTB("CGAL error in CGAL_Nef_polyhedron::convertToPolyset(): %s", e.what()); + if (err) { + PRINT("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed."); + if (errmsg!="") PRINTB("ERROR: %s",errmsg); + } else { + ps = createPolySetFromPolyhedron(P); } CGAL::set_error_behaviour(old_behaviour); } diff --git a/src/CocoaUtils.mm b/src/CocoaUtils.mm index 92640fd..9856b3d 100644 --- a/src/CocoaUtils.mm +++ b/src/CocoaUtils.mm @@ -8,7 +8,7 @@ void CocoaUtils::endApplication() object:nil]; } -void CocoaUtils::nslog(const std::string &str, void *userdata) +void CocoaUtils::nslog(const std::string &str, void * /* userdata */) { - NSLog([NSString stringWithUTF8String: str.c_str()]); + NSLog(@"%s", str.c_str()); } diff --git a/src/MainWindow.h b/src/MainWindow.h index 4f88fbf..ac999bf 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -164,6 +164,7 @@ public slots: void viewCenter(); void viewPerspective(); void viewOrthogonal(); + void viewResetView(); void hideConsole(); void animateUpdateDocChanged(); void animateUpdate(); diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 68bc064..4cb043f 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -213,6 +213,8 @@ <addaction name="viewActionDiagonal"/> <addaction name="viewActionCenter"/> <addaction name="separator"/> + <addaction name="viewActionResetView"/> + <addaction name="separator"/> <addaction name="viewActionPerspective"/> <addaction name="viewActionOrthogonal"/> <addaction name="separator"/> @@ -697,6 +699,11 @@ <string>Show Library Folder...</string> </property> </action> + <action name="viewActionResetView"> + <property name="text"> + <string>Reset View</string> + </property> + </action> </widget> <customwidgets> <customwidget> diff --git a/src/PlatformUtils.cc b/src/PlatformUtils.cc index cfa5731..b02b822 100644 --- a/src/PlatformUtils.cc +++ b/src/PlatformUtils.cc @@ -84,7 +84,7 @@ std::string PlatformUtils::info() #ifdef QT_VERSION std::string qtVersion = qVersion(); #else - std::string qtVersion = "Qt disabled"; + std::string qtVersion = "Qt disabled - Commandline Test Version"; #endif #ifdef ENABLE_CGAL diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc index bc9206f..599fd7f 100644 --- a/src/PolySetCGALEvaluator.cc +++ b/src/PolySetCGALEvaluator.cc @@ -457,7 +457,14 @@ PolySet *PolySetCGALEvaluator::rotateDxfData(const RotateExtrudeNode &node, DxfD { double max_x = 0; for (size_t j = 0; j < dxf.paths[i].indices.size(); j++) { - max_x = fmax(max_x, dxf.points[dxf.paths[i].indices[j]][0]); + double point_x = dxf.points[dxf.paths[i].indices[j]][0]; + if (point_x < 0) { + PRINT("ERROR: all points for rotate_extrude() must have non-negative X coordinates"); + PRINTB("[Point %d on path %d has X coordinate %f]", j % i % point_x); + delete ps; + return NULL; + } + max_x = fmax(max_x, point_x); } int fragments = get_fragments_from_r(max_x, node.fn, node.fs, node.fa); diff --git a/src/QGLView.cc b/src/QGLView.cc index 5cb2e1b..6ffd586 100644 --- a/src/QGLView.cc +++ b/src/QGLView.cc @@ -64,9 +64,7 @@ static bool running_under_wine = false; void QGLView::init() { cam.type = Camera::GIMBAL; - cam.object_rot << 35, 0, -25; - cam.object_trans << 0, 0, 0; - cam.viewer_distance = 500; + resetView(); this->mouse_drag_active = false; this->statusLabel = NULL; @@ -83,6 +81,13 @@ void QGLView::init() #endif } +void QGLView::resetView() +{ + cam.object_rot << 35, 0, -25; + cam.object_trans << 0, 0, 0; + cam.viewer_distance = 500; +} + void QGLView::initializeGL() { GLenum err = glewInit(); diff --git a/src/QGLView.h b/src/QGLView.h index f3e3681..12be085 100644 --- a/src/QGLView.h +++ b/src/QGLView.h @@ -41,6 +41,7 @@ public: } std::string getRendererInfo() const; bool save(const char *filename); + void resetView(); public: QLabel *statusLabel; @@ -27,6 +27,7 @@ using boost::uintmax_t; #include <CGAL/Cartesian.h> #include <CGAL/Polyhedron_3.h> #include <CGAL/Nef_polyhedron_3.h> +#include <CGAL_Nef3_workaround.h> #include <CGAL/IO/Polyhedron_iostream.h> #include <CGAL/Exact_predicates_exact_constructions_kernel.h> #include <CGAL/Polygon_2.h> @@ -48,9 +49,10 @@ typedef CGAL::Exact_predicates_exact_constructions_kernel CGAL_ExactKernel2; typedef CGAL::Polygon_2<CGAL_ExactKernel2> CGAL_Poly2; typedef CGAL::Polygon_with_holes_2<CGAL_ExactKernel2> CGAL_Poly2h; - //typedef CGAL::Cartesian<NT> CGAL_Kernel3; -typedef CGAL::Exact_predicates_exact_constructions_kernel CGAL_Kernel3; -typedef CGAL::Exact_predicates_exact_constructions_kernel::FT NT3; +typedef CGAL::Gmpq NT3; +typedef CGAL::Cartesian<NT3> CGAL_Kernel3; +//typedef CGAL::Exact_predicates_exact_constructions_kernel::FT NT3; +//typedef CGAL::Exact_predicates_exact_constructions_kernel CGAL_Kernel3; typedef CGAL::Nef_polyhedron_3<CGAL_Kernel3> CGAL_Nef_polyhedron3; typedef CGAL_Nef_polyhedron3::Aff_transformation_3 CGAL_Aff_transformation; diff --git a/src/control.cc b/src/control.cc index 10aadf0..d5f664e 100644 --- a/src/control.cc +++ b/src/control.cc @@ -78,12 +78,14 @@ void ControlModule::for_eval(AbstractNode &node, const ModuleInstantiation &inst Context c(ctx); if (it_values.type() == Value::RANGE) { Value::RangeType range = it_values.toRange(); - range.normalize(); - if (range.nbsteps()<10000) { - for (double i = range.begin; i <= range.end; i += range.step) { - c.set_variable(it_name, Value(i)); - for_eval(node, inst, l+1, &c, evalctx); - } + uint32_t steps = range.nbsteps(); + if (steps >= 10000) { + PRINTB("WARNING: Bad range parameter in for statement: too many elements (%lu).", steps); + } else { + for (Value::RangeType::iterator it = range.begin();it != range.end();it++) { + c.set_variable(it_name, Value(*it)); + for_eval(node, inst, l+1, &c, evalctx); + } } } else if (it_values.type() == Value::VECTOR) { @@ -227,13 +229,13 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns else if (value.type() == Value::RANGE) { AbstractNode* node = new AbstractNode(inst); Value::RangeType range = value.toRange(); - range.normalize(); - if (range.nbsteps()>=10000) { - PRINTB("WARNING: Bad range parameter for children: too many elements (%d).", (int)((range.begin-range.end)/range.step)); + uint32_t steps = range.nbsteps(); + if (steps >= 10000) { + PRINTB("WARNING: Bad range parameter for children: too many elements (%lu).", steps); return NULL; } - for (double i = range.begin; i <= range.end; i += range.step) { - AbstractNode* childnode = getChild(Value(i),modulectx); // with error cases + for (Value::RangeType::iterator it = range.begin();it != range.end();it++) { + AbstractNode* childnode = getChild(Value(*it),modulectx); // with error cases if (childnode==NULL) continue; // error node->children.push_back(childnode); } diff --git a/src/dxfdata.h b/src/dxfdata.h index 64853dc..ac7260c 100644 --- a/src/dxfdata.h +++ b/src/dxfdata.h @@ -28,11 +28,7 @@ public: } }; -#ifdef __APPLE__ - std::vector<Vector2d, Eigen::aligned_allocator<Vector2d> > points; -#else std::vector<Vector2d> points; -#endif std::vector<Path> paths; std::vector<Dim> dims; diff --git a/src/editor.cc b/src/editor.cc index 08bf005..069101f 100644 --- a/src/editor.cc +++ b/src/editor.cc @@ -108,3 +108,17 @@ void Editor::wheelEvent ( QWheelEvent * event ) } } +void Editor::setPlainText(const QString &text) +{ + int y = verticalScrollBar()->sliderPosition(); + // Save current cursor position + QTextCursor cursor = textCursor(); + int n = cursor.position(); + QTextEdit::setPlainText(text); + // Restore cursor position + if (n < text.length()) { + cursor.setPosition(n); + setTextCursor(cursor); + verticalScrollBar()->setSliderPosition(y); + } +} diff --git a/src/editor.h b/src/editor.h index 09484f5..8d092a9 100644 --- a/src/editor.h +++ b/src/editor.h @@ -2,6 +2,7 @@ #include <QString> #include <QWidget> #include <QWheelEvent> +#include <QScrollBar> #include <QTextEdit> class Editor : public QTextEdit @@ -9,6 +10,7 @@ class Editor : public QTextEdit Q_OBJECT public: Editor(QWidget *parent) : QTextEdit(parent) { setAcceptRichText(false); } + void setPlainText(const QString &text); public slots: void zoomIn(); void zoomOut(); diff --git a/src/export.cc b/src/export.cc index ec6e576..cef323e 100644 --- a/src/export.cc +++ b/src/export.cc @@ -42,7 +42,12 @@ void export_stl(CGAL_Nef_polyhedron *root_N, std::ostream &output) CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); try { CGAL_Polyhedron P; - root_N->p3->convert_to_Polyhedron(P); + //root_N->p3->convert_to_Polyhedron(P); + bool err = nefworkaround::convert_to_Polyhedron<CGAL_Kernel3>( *(root_N->p3), P ); + if (err) { + PRINT("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed"); + return; + } typedef CGAL_Polyhedron::Vertex Vertex; typedef CGAL_Polyhedron::Vertex_const_iterator VCI; @@ -114,6 +119,9 @@ void export_stl(CGAL_Nef_polyhedron *root_N, std::ostream &output) catch (const CGAL::Assertion_exception &e) { PRINTB("CGAL error in CGAL_Nef_polyhedron3::convert_to_Polyhedron(): %s", e.what()); } + catch (...) { + PRINT("CGAL unknown error in CGAL_Nef_polyhedron3::convert_to_Polyhedron()"); + } CGAL::set_error_behaviour(old_behaviour); } diff --git a/src/expr.cc b/src/expr.cc index 594fccf..08615ba 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -117,11 +117,18 @@ Value Expression::evaluate(const Context *context) const if (this->type == "R") { Value v1 = this->children[0]->evaluate(context); Value v2 = this->children[1]->evaluate(context); - Value v3 = this->children[2]->evaluate(context); - if (v1.type() == Value::NUMBER && v2.type() == Value::NUMBER && v3.type() == Value::NUMBER) { - Value::RangeType range(v1.toDouble(), v2.toDouble(), v3.toDouble()); - return Value(range); - } + if (this->children.size() == 2) { + if (v1.type() == Value::NUMBER && v2.type() == Value::NUMBER) { + Value::RangeType range(v1.toDouble(), v2.toDouble()); + return Value(range); + } + } else { + Value v3 = this->children[2]->evaluate(context); + if (v1.type() == Value::NUMBER && v2.type() == Value::NUMBER && v3.type() == Value::NUMBER) { + Value::RangeType range(v1.toDouble(), v2.toDouble(), v3.toDouble()); + return Value(range); + } + } return Value(); } if (this->type == "V") { @@ -192,7 +199,11 @@ std::string Expression::toString() const stream << this->const_value; } else if (this->type == "R") { - stream << "[" << *this->children[0] << " : " << *this->children[1] << " : " << *this->children[2] << "]"; + stream << "[" << *this->children[0] << " : " << *this->children[1]; + if (this->children.size() > 2) { + stream << " : " << *this->children[2]; + } + stream << "]"; } else if (this->type == "V") { stream << "["; diff --git a/src/linalg.h b/src/linalg.h index 1f9ed30..cb82452 100644 --- a/src/linalg.h +++ b/src/linalg.h @@ -4,10 +4,13 @@ #include <Eigen/Core> #include <Eigen/Geometry> #include <Eigen/Dense> +#include<Eigen/StdVector> +EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Vector2d) using Eigen::Vector2d; +EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Vector3d) using Eigen::Vector3d; -using Eigen::Vector3f; + typedef Eigen::AlignedBox<double, 3> BoundingBox; using Eigen::Matrix3f; using Eigen::Matrix3d; diff --git a/src/mainwin.cc b/src/mainwin.cc index 65c511f..1ad8bc8 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -334,6 +334,7 @@ MainWindow::MainWindow(const QString &filename) connect(this->viewActionBack, SIGNAL(triggered()), this, SLOT(viewAngleBack())); connect(this->viewActionDiagonal, SIGNAL(triggered()), this, SLOT(viewAngleDiagonal())); connect(this->viewActionCenter, SIGNAL(triggered()), this, SLOT(viewCenter())); + connect(this->viewActionResetView, SIGNAL(triggered()), this, SLOT(viewResetView())); connect(this->viewActionPerspective, SIGNAL(triggered()), this, SLOT(viewPerspective())); connect(this->viewActionOrthogonal, SIGNAL(triggered()), this, SLOT(viewOrthogonal())); connect(this->viewActionHide, SIGNAL(triggered()), this, SLOT(hideConsole())); @@ -503,6 +504,7 @@ MainWindow::openFile(const QString &new_filename) } #endif setFileName(actual_filename); + editor->setPlainText(""); fileChangedOnDisk(); // force cached autoReloadId to update refreshDocument(); @@ -1772,6 +1774,12 @@ void MainWindow::viewOrthogonal() this->qglview->updateGL(); } +void MainWindow::viewResetView() +{ + this->qglview->resetView(); + this->qglview->updateGL(); +} + void MainWindow::hideConsole() { QSettings settings; diff --git a/src/modcontext.cc b/src/modcontext.cc index 5b48009..7941cf5 100644 --- a/src/modcontext.cc +++ b/src/modcontext.cc @@ -162,7 +162,7 @@ void ModuleContext::dump(const AbstractModule *mod, const ModuleInstantiation *i #endif FileContext::FileContext(const class FileModule &module, const Context *parent) - : usedlibs(module.usedlibs), ModuleContext(parent) + : ModuleContext(parent), usedlibs(module.usedlibs) { if (!module.modulePath().empty()) this->document_path = module.modulePath(); } diff --git a/src/openscad.cc b/src/openscad.cc index 6bbaedb..ab84235 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -453,7 +453,7 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c // Only if "fileName" is not absolute, prepend the "absoluteBase". static QString assemblePath(const fs::path& absoluteBase, const string& fileName) { - return QDir(QString::fromStdString((const string&) absoluteBase)) + return fileName.empty() ? "" : QDir(QString::fromStdString((const string&) absoluteBase)) .absoluteFilePath(QString::fromStdString(fileName)); } @@ -474,6 +474,13 @@ bool QtUseGUI() int gui(vector<string> &inputFiles, const fs::path &original_path, int argc, char ** argv) { +#ifdef Q_OS_MACX + if (QSysInfo::MacintoshVersion > QSysInfo::MV_10_8) { + // fix Mac OS X 10.9 (mavericks) font issue + // https://bugreports.qt-project.org/browse/QTBUG-32789 + QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande"); + } +#endif QApplication app(argc, argv, true); //useGUI); #ifdef Q_WS_MAC app.installEventFilter(new EventFilter(&app)); diff --git a/src/parser.y b/src/parser.y index 5645104..6446e82 100644 --- a/src/parser.y +++ b/src/parser.y @@ -325,11 +325,9 @@ expr: } | '[' expr ':' expr ']' { - Expression *e_one = new Expression(Value(1.0)); $$ = new Expression(); $$->type = "R"; $$->children.push_back($2); - $$->children.push_back(e_one); $$->children.push_back($4); } | '[' expr ':' expr ':' expr ']' diff --git a/src/stl-utils.cc b/src/stl-utils.cc index 790fd17..027339c 100644 --- a/src/stl-utils.cc +++ b/src/stl-utils.cc @@ -1,4 +1,4 @@ -#if defined(__APPLE__) && defined(__GNUC__) +#if defined(__APPLE__) && defined(__GNUC__) && !defined(__clang__) #include <iostream> diff --git a/src/value.cc b/src/value.cc index ac33a3b..5afb650 100644 --- a/src/value.cc +++ b/src/value.cc @@ -232,7 +232,7 @@ public: } std::string operator()(const Value::RangeType &v) const { - return (boost::format("[%1% : %2% : %3%]") % v.begin % v.step % v.end).str(); + return (boost::format("[%1% : %2% : %3%]") % v.begin_val % v.step_val % v.end_val).str(); } }; @@ -600,9 +600,9 @@ public: Value operator()(const Value::RangeType &range, const double &idx) const { switch(int(idx)) { - case 0: return Value(range.begin); - case 1: return Value(range.step); - case 2: return Value(range.end); + case 0: return Value(range.begin_val); + case 1: return Value(range.step_val); + case 2: return Value(range.end_val); } return Value::undefined; } @@ -617,3 +617,97 @@ Value Value::operator[](const Value &v) { return boost::apply_visitor(bracket_visitor(), this->value, v.value); } + +void Value::RangeType::normalize() { + if ((step_val>0) && (end_val < begin_val)) { + std::swap(begin_val,end_val); + PRINT("DEPRECATED: Using ranges of the form [begin:end] with begin value greater than the end value is deprecated."); + } +} + +uint32_t Value::RangeType::nbsteps() const { + if (begin_val == end_val) { + return 0; + } + + if (step_val == 0) { + return std::numeric_limits<uint32_t>::max(); + } + + double steps; + if (step_val < 0) { + if (begin_val < end_val) { + return 0; + } + steps = (begin_val - end_val) / (-step_val); + } else { + if (begin_val > end_val) { + return 0; + } + steps = (end_val - begin_val) / step_val; + } + + return steps; +} + +Value::RangeType::iterator::iterator(Value::RangeType &range, type_t type) : range(range), val(range.begin_val) +{ + this->type = type; + update_type(); +} + +void Value::RangeType::iterator::update_type() +{ + if (range.step_val == 0) { + type = RANGE_TYPE_END; + } else if (range.step_val < 0) { + if (val < range.end_val) { + type = RANGE_TYPE_END; + } + } else { + if (val > range.end_val) { + type = RANGE_TYPE_END; + } + } +} + +Value::RangeType::iterator::reference Value::RangeType::iterator::operator*() +{ + return val; +} + +Value::RangeType::iterator::pointer Value::RangeType::iterator::operator->() +{ + return &(operator*()); +} + +Value::RangeType::iterator::self_type Value::RangeType::iterator::operator++() +{ + if (type < 0) { + type = RANGE_TYPE_RUNNING; + } + val += range.step_val; + update_type(); + return *this; +} + +Value::RangeType::iterator::self_type Value::RangeType::iterator::operator++(int) +{ + self_type tmp(*this); + operator++(); + return tmp; +} + +bool Value::RangeType::iterator::operator==(const self_type &other) const +{ + if (type == RANGE_TYPE_RUNNING) { + return (type == other.type) && (val == other.val) && (range == other.range); + } else { + return (type == other.type) && (range == other.range); + } +} + +bool Value::RangeType::iterator::operator!=(const self_type &other) const +{ + return !(*this == other); +} diff --git a/src/value.h b/src/value.h index 388b721..75dff2b 100644 --- a/src/value.h +++ b/src/value.h @@ -11,6 +11,7 @@ #include <boost/variant.hpp> #include <boost/lexical_cast.hpp> #endif +#include <boost/cstdint.hpp> class QuotedString : public std::string { @@ -31,33 +32,64 @@ std::ostream &operator<<(std::ostream &stream, const Filename &filename); class Value { public: - struct RangeType { + class RangeType { + private: + double begin_val; + double step_val; + double end_val; + + /// inverse begin/end if begin is upper than end + void normalize(); + + public: + typedef enum { RANGE_TYPE_BEGIN, RANGE_TYPE_RUNNING, RANGE_TYPE_END } type_t; + + class iterator { + public: + typedef iterator self_type; + typedef double value_type; + typedef double& reference; + typedef double* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef double difference_type; + iterator(RangeType &range, type_t type); + self_type operator++(); + self_type operator++(int junk); + reference operator*(); + pointer operator->(); + bool operator==(const self_type& other) const; + bool operator!=(const self_type& other) const; + private: + RangeType ⦥ + double val; + type_t type; + + void update_type(); + }; + + RangeType(double begin, double end) + : begin_val(begin), step_val(1.0), end_val(end) + { + normalize(); + } + RangeType(double begin, double step, double end) - : begin(begin), step(step), end(end) {} + : begin_val(begin), step_val(step), end_val(end) {} bool operator==(const RangeType &other) const { - return this->begin == other.begin && - this->step == other.step && - this->end == other.end; + return this->begin_val == other.begin_val && + this->step_val == other.step_val && + this->end_val == other.end_val; } - /// inverse begin/end if begin is upper than end - void normalize() { - if ((step>0) && (end < begin)) { - std::swap(begin,end); - } - } - /// return number of steps, max int value if step is null - int nbsteps() const { - if (step<=0) { - return std::numeric_limits<int>::max(); - } - return (int)((begin-end)/step); - } - - double begin; - double step; - double end; + iterator begin() { return iterator(*this, RANGE_TYPE_BEGIN); } + iterator end() { return iterator(*this, RANGE_TYPE_END); } + + /// return number of steps, max uint32_t value if step is 0 + uint32_t nbsteps() const; + + friend class tostring_visitor; + friend class bracket_visitor; }; typedef std::vector<Value> VectorType; diff --git a/src/version_check.h b/src/version_check.h index 6e07208..be52e61 100644 --- a/src/version_check.h +++ b/src/version_check.h @@ -35,8 +35,8 @@ a time, to avoid confusion. #include <Eigen/Core> -#if not EIGEN_VERSION_AT_LEAST( 2,0,13 ) -#error eigen2 library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check +#if not EIGEN_VERSION_AT_LEAST( 3,0,0 ) +#error eigen library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check #else @@ -104,9 +104,17 @@ a time, to avoid confusion. #endif // ENABLE_CGAL #endif // Boost -#endif // Eigen2 +#endif // Eigen #endif // MPFR #endif // GMP +// see github issue #552 +#define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) +#if GCC_VERSION == 40802 +#error "OpenSCAD isnt compatible with gcc 4.8.2. Please try a different version" +#endif + #endif // OPENSCAD_SKIP_VERSION_CHECK |