diff options
author | Don Bright <hugh.m.bright@gmail.com> | 2013-12-15 21:32:06 (GMT) |
---|---|---|
committer | Don Bright <hugh.m.bright@gmail.com> | 2013-12-15 21:32:06 (GMT) |
commit | 3b3ef44f6636affef8138f4c8b7dec1333f50377 (patch) | |
tree | 977698cc6d2d56775f140967792ad637db03490f /src | |
parent | 5271b345bc755f37e98d7f497f6686d34990fa5c (diff) | |
parent | c7cea0082e427f3c53985845f05e8737873c8a25 (diff) |
Merge branch 'master' of github.com:openscad/openscad into planar
Conflicts:
src/CGAL_Nef_polyhedron.cc
tests/CMakeLists.txt
Diffstat (limited to 'src')
-rw-r--r-- | src/AboutDialog.html | 1 | ||||
-rw-r--r-- | src/CGALEvaluator.cc | 18 | ||||
-rw-r--r-- | src/CGAL_Nef3_workaround.h | 352 | ||||
-rw-r--r-- | src/CGAL_Nef_polyhedron.cc | 23 | ||||
-rw-r--r-- | src/CocoaUtils.mm | 4 | ||||
-rw-r--r-- | src/PlatformUtils.cc | 3 | ||||
-rw-r--r-- | src/PolySetCGALEvaluator.cc | 13 | ||||
-rw-r--r-- | src/cgal.h | 1 | ||||
-rw-r--r-- | src/export.cc | 10 | ||||
-rw-r--r-- | src/func.cc | 49 | ||||
-rw-r--r-- | src/modcontext.cc | 2 | ||||
-rw-r--r-- | src/openscad.cc | 7 | ||||
-rw-r--r-- | src/stl-utils.cc | 2 | ||||
-rw-r--r-- | src/value.cc | 18 | ||||
-rw-r--r-- | src/version_check.h | 2 |
15 files changed, 475 insertions, 30 deletions
diff --git a/src/AboutDialog.html b/src/AboutDialog.html index 99e7c3b..65a54d7 100644 --- a/src/AboutDialog.html +++ b/src/AboutDialog.html @@ -64,6 +64,7 @@ Please visit this link for a copy of the license: <a href="http://www.gnu.org/li <li><a href="http://www.stroustrup.com/C++.html">C++</a>, <a href="http://gcc.gnu.org/">GCC</a>, <a href="http://clang.llvm.org/">clang</a> <li><a href="http://www.python.org">python</a> <li><a href="http://nsis.sourceforge.net/Main_Page">Nullsoft installer</a> +<li><a href="https://developer.gnome.org/glib/">GLib</a> </lu> </p> diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc index 3a05b2b..20c5d5e 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 8b54eba..ea9accd 100644 --- a/src/CGAL_Nef_polyhedron.cc +++ b/src/CGAL_Nef_polyhedron.cc @@ -96,16 +96,23 @@ PolySet *CGAL_Nef_polyhedron::convertToPolyset() } else if (this->dim == 3) { CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); + ps = new PolySet(); + bool err = true; + std::string errmsg(""); + CGAL_Polyhedron P; try { - ps = new PolySet(); - CGAL_Polyhedron P; - this->p3->convert_to_Polyhedron(P); - bool err = createPolySetFromPolyhedron(P, *ps); - if (err) delete ps; + 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) { - delete ps; - PRINTB("CGAL error in CGAL_Nef_polyhedron::convertToPolyset(): %s", e.what()); + if (!err) err = createPolySetFromPolyhedron(P, *ps); + if (err) { + PRINT("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed."); + if (errmsg!="") PRINTB("ERROR: %s",errmsg); + delete ps; ps = NULL; } 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/PlatformUtils.cc b/src/PlatformUtils.cc index b02b822..8b39f6d 100644 --- a/src/PlatformUtils.cc +++ b/src/PlatformUtils.cc @@ -1,6 +1,8 @@ #include "PlatformUtils.h" #include "boosty.h" +#include <glib.h> + bool PlatformUtils::createLibraryPath() { std::string path = PlatformUtils::libraryPath(); @@ -114,6 +116,7 @@ std::string PlatformUtils::info() << "\nOpenCSG version: " << OPENCSG_VERSION_STRING << "\nQt version: " << qtVersion << "\nMingW build: " << mingwstatus + << "\nGLib version: " << GLIB_MAJOR_VERSION << "." << GLIB_MINOR_VERSION << "." << GLIB_MICRO_VERSION << "\nOPENSCADPATH: " << getenv("OPENSCADPATH") << "\n" ; return s.str(); diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc index bc9206f..a2d896d 100644 --- a/src/PolySetCGALEvaluator.cc +++ b/src/PolySetCGALEvaluator.cc @@ -455,12 +455,21 @@ PolySet *PolySetCGALEvaluator::rotateDxfData(const RotateExtrudeNode &node, DxfD for (size_t i = 0; i < dxf.paths.size(); i++) { + double min_x = 0; 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]; + min_x = fmin(min_x, point_x); + max_x = fmax(max_x, point_x); + + if ((max_x - min_x) > max_x && (max_x - min_x) > fabs(min_x)) { + PRINTB("ERROR: all points for rotate_extrude() must have the same X coordinate sign (range is %.2f -> %.2f)", min_x % max_x); + delete ps; + return NULL; + } } - int fragments = get_fragments_from_r(max_x, node.fn, node.fs, node.fa); + int fragments = get_fragments_from_r(max_x-min_x, node.fn, node.fs, node.fa); double ***points; points = new double**[fragments]; @@ -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> 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/func.cc b/src/func.cc index 865a2b4..4587f72 100644 --- a/src/func.cc +++ b/src/func.cc @@ -45,6 +45,8 @@ #include <boost/random/mersenne_twister.hpp> #include <boost/random/uniform_real.hpp> +/*Unicode support for string lengths and array accesses*/ +#include <glib.h> #ifdef __WIN32__ #include <process.h> @@ -306,7 +308,11 @@ Value builtin_length(const Context *, const EvalContext *evalctx) { if (evalctx->numArgs() == 1) { if (evalctx->getArgValue(0).type() == Value::VECTOR) return Value(int(evalctx->getArgValue(0).toVector().size())); - if (evalctx->getArgValue(0).type() == Value::STRING) return Value(int(evalctx->getArgValue(0).toString().size())); + if (evalctx->getArgValue(0).type() == Value::STRING) { + //Unicode glyph count for the length -- rather than the string (num. of bytes) length. + std::string text = evalctx->getArgValue(0).toString(); + return Value(int( g_utf8_strlen( text.c_str(), text.size() ) )); + } } return Value(); } @@ -380,10 +386,17 @@ Value builtin_lookup(const Context *, const EvalContext *evalctx) num_returns_per_match : int; index_col_num : int; + The search string and searched strings can be unicode strings. Examples: Index values return as list: search("a","abcdabcd"); - - returns [0,4] + - returns [0] + search("Л","Л"); //A unicode string + - returns [0] + search("🂡aЛ","a🂡Л🂡a🂡Л🂡a",0); + - returns [[1,3,5,7],[0,4,8],[2,6]] + search("a","abcdabcd",0); //Search up to all matches + - returns [[0,4]] search("a","abcdabcd",1); - returns [0] search("e","abcdabcd",1); @@ -433,16 +446,25 @@ Value builtin_search(const Context *, const EvalContext *evalctx) } } else if (findThis.type() == Value::STRING) { unsigned int searchTableSize; - if (searchTable.type() == Value::STRING) searchTableSize = searchTable.toString().size(); - else searchTableSize = searchTable.toVector().size(); - for (size_t i = 0; i < findThis.toString().size(); i++) { + //Unicode glyph count for the length + unsigned int findThisSize = g_utf8_strlen( findThis.toString().c_str(), findThis.toString().size() ); + if (searchTable.type() == Value::STRING) { + searchTableSize = g_utf8_strlen( searchTable.toString().c_str(), searchTable.toString().size() ); + } else { + searchTableSize = searchTable.toVector().size(); + } + for (size_t i = 0; i < findThisSize; i++) { unsigned int matchCount = 0; Value::VectorType resultvec; for (size_t j = 0; j < searchTableSize; j++) { - if ((searchTable.type() == Value::VECTOR && - findThis.toString()[i] == searchTable.toVector()[j].toVector()[index_col_num].toString()[0]) || - (searchTable.type() == Value::STRING && - findThis.toString()[i] == searchTable.toString()[j])) { + gchar* ptr_ft = g_utf8_offset_to_pointer(findThis.toString().c_str(), i); + gchar* ptr_st = NULL; + if(searchTable.type() == Value::VECTOR) { + ptr_st = g_utf8_offset_to_pointer(searchTable.toVector()[j].toVector()[index_col_num].toString().c_str(), 0); + } else if(searchTable.type() == Value::STRING){ + ptr_st = g_utf8_offset_to_pointer(searchTable.toString().c_str(), j); + } + if( (ptr_ft) && (ptr_st) && (g_utf8_get_char(ptr_ft) == g_utf8_get_char(ptr_st)) ) { Value resultValue((double(j))); matchCount++; if (num_returns_per_match == 1) { @@ -454,7 +476,14 @@ Value builtin_search(const Context *, const EvalContext *evalctx) if (num_returns_per_match > 1 && matchCount >= num_returns_per_match) break; } } - if (matchCount == 0) PRINTB(" WARNING: search term not found: \"%s\"", findThis.toString()[i]); + if (matchCount == 0) { + gchar* ptr_ft = g_utf8_offset_to_pointer(findThis.toString().c_str(), i); + gchar utf8_of_cp[6] = ""; //A buffer for a single unicode character to be copied into + if(ptr_ft) { + g_utf8_strncpy( utf8_of_cp, ptr_ft, 1 ); + } + PRINTB(" WARNING: search term not found: \"%s\"", utf8_of_cp ); + } if (num_returns_per_match == 0 || num_returns_per_match > 1) { returnvec.push_back(Value(resultvec)); } 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 ece6818..ab84235 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -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/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 5afb650..c8a88c6 100644 --- a/src/value.cc +++ b/src/value.cc @@ -36,6 +36,8 @@ #include <boost/format.hpp> #include "boost-utils.h" #include "boosty.h" +/*Unicode support for string lengths and array accesses*/ +#include <glib.h> std::ostream &operator<<(std::ostream &stream, const Filename &filename) { @@ -579,14 +581,28 @@ Value Value::operator-() const } */ +/* + * bracket operation [] detecting multi-byte unicode. + * If the string is multi-byte unicode then the index will offset to the character (2 or 4 byte) and not to the byte. + * A 'normal' string with byte chars are a subset of unicode and still work. + */ class bracket_visitor : public boost::static_visitor<Value> { public: Value operator()(const std::string &str, const double &idx) const { int i = int(idx); Value v; + //Check that the index is positive and less than the size in bytes if ((i >= 0) && (i < (int)str.size())) { - v = Value(str[int(idx)]); + //Ensure character (not byte) index is inside the character/glyph array + if( (unsigned) i < g_utf8_strlen( str.c_str(), str.size() ) ) { + gchar utf8_of_cp[6] = ""; //A buffer for a single unicode character to be copied into + gchar* ptr = g_utf8_offset_to_pointer(str.c_str(), i); + if(ptr) { + g_utf8_strncpy(utf8_of_cp, ptr, 1); + } + v = std::string(utf8_of_cp); + } // std::cout << "bracket_visitor: " << v << "\n"; } return v; diff --git a/src/version_check.h b/src/version_check.h index fbea077..2688f2a 100644 --- a/src/version_check.h +++ b/src/version_check.h @@ -113,7 +113,7 @@ a time, to avoid confusion. + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) #if GCC_VERSION == 40802 -#error OpenSCAD isn't compatible with gcc 4.8.2. Please try a different version +#warning "gcc 4.8.2 contains a bug causing a crash in CGAL." #endif #endif // OPENSCAD_SKIP_VERSION_CHECK |