From b05eb736a06a77eef2ae6c1298a11778386424a2 Mon Sep 17 00:00:00 2001 From: Oskar Linde Date: Mon, 27 Jan 2014 16:21:18 +0100 Subject: [PATCH 01/10] Regression test for 2D intersection() operation --- .../scad/features/intersection2-tests.scad | 40 ++++++++++++++++++ .../intersection2-tests-expected.png | Bin 0 -> 7195 bytes 2 files changed, 40 insertions(+) create mode 100644 testdata/scad/features/intersection2-tests.scad create mode 100644 tests/regression/cgalpngtest/intersection2-tests-expected.png diff --git a/testdata/scad/features/intersection2-tests.scad b/testdata/scad/features/intersection2-tests.scad new file mode 100644 index 00000000..ac787c0c --- /dev/null +++ b/testdata/scad/features/intersection2-tests.scad @@ -0,0 +1,40 @@ +translate([0,-20]) intersection() { + circle(r=5); + square(8,center=true); +} + +// Intersecting something with nothing +translate([-10,0]) intersection() { + circle(r=5); + square(0,center=true); +} + +// Non-geometry (echo) statement as first child should be ignored +translate([0,20]) intersection() { + echo("difference-tests"); + circle(r=5); + square(8,center=true); +} + +// intersection with 1 operand +translate([20,-20]) intersection() { + translate([10,0]) circle(r=15); +} + +// intersection with 2 operands +translate([20,0]) intersection() { + translate([10,0]) circle(r=15); + rotate(120) translate([10,0]) circle(r=15); +} + +// intersection with 3 operands +translate([20,20]) intersection() { + translate([10,0]) circle(r=15); + rotate(120) translate([10,0]) circle(r=15); + rotate(240) translate([10,0]) circle(r=15); +} + +// intersection_for +translate([0,0]) intersection_for (a = [0:60:359.99]) { + translate([cos(a),sin(a)]*10) circle(r=15); +} diff --git a/tests/regression/cgalpngtest/intersection2-tests-expected.png b/tests/regression/cgalpngtest/intersection2-tests-expected.png new file mode 100644 index 0000000000000000000000000000000000000000..5cd53ebc2782955ccddbc5d2106ada4b9d28d2e9 GIT binary patch literal 7195 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 BBH91| literal 0 HcmV?d00001 From c25ead11ff97fbca0505cfd01bb004e6c857f395 Mon Sep 17 00:00:00 2001 From: Oskar Linde Date: Mon, 27 Jan 2014 15:07:30 +0100 Subject: [PATCH 02/10] Regression fix: n-ary 2d intersection() with n != 2 --- src/GeometryEvaluator.cc | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/GeometryEvaluator.cc b/src/GeometryEvaluator.cc index 6b5a8c89..7f1a8cc9 100644 --- a/src/GeometryEvaluator.cc +++ b/src/GeometryEvaluator.cc @@ -342,6 +342,14 @@ Polygon2d *GeometryEvaluator::applyToChildren2D(const AbstractNode &node, OpenSC std::vector children = collectChildren2D(node); + if (children.empty()) { + return NULL; + } + + if (children.size() == 1) { + return new Polygon2d(*children[0]); // Copy + } + ClipperLib::ClipType clipType; switch (op) { case OPENSCAD_UNION: @@ -359,7 +367,26 @@ Polygon2d *GeometryEvaluator::applyToChildren2D(const AbstractNode &node, OpenSC break; } - return ClipperUtils::apply(children, clipType); + if (clipType == ClipperLib::ctIntersection && !children.empty()) { + // intersection operations must be split into a sequence of binary operations + + std::vector operands(2); + operands[0] = children[0]; + + for (int i = 1; i < children.size(); i++) { + operands[1] = children[i]; + Polygon2d * result = ClipperUtils::apply(operands, clipType); + if (operands[0] != children[0]) delete operands[0]; + operands[0] = result; + } + + assert(children.size() >= 2); + // We know that this is ok + return const_cast(operands[0]); + } + else { + return ClipperUtils::apply(children, clipType); + } } /*! From 0600d800468cd7225cc0bbd2a21e3f6224d365af Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Mon, 27 Jan 2014 23:25:33 -0500 Subject: [PATCH 03/10] Moved special handling of intersection to ClipperUtils --- src/GeometryEvaluator.cc | 21 +---- src/clipper-utils.cc | 25 +++++- .../dumptest/intersection2-tests-expected.csg | 79 ++++++++++++++++++ .../intersection2-tests-expected.png | Bin 0 -> 7431 bytes .../intersection2-tests-expected.png | Bin 0 -> 7025 bytes 5 files changed, 104 insertions(+), 21 deletions(-) create mode 100644 tests/regression/dumptest/intersection2-tests-expected.csg create mode 100644 tests/regression/opencsgtest/intersection2-tests-expected.png create mode 100644 tests/regression/throwntogethertest/intersection2-tests-expected.png diff --git a/src/GeometryEvaluator.cc b/src/GeometryEvaluator.cc index 7f1a8cc9..a6a95f2d 100644 --- a/src/GeometryEvaluator.cc +++ b/src/GeometryEvaluator.cc @@ -367,26 +367,7 @@ Polygon2d *GeometryEvaluator::applyToChildren2D(const AbstractNode &node, OpenSC break; } - if (clipType == ClipperLib::ctIntersection && !children.empty()) { - // intersection operations must be split into a sequence of binary operations - - std::vector operands(2); - operands[0] = children[0]; - - for (int i = 1; i < children.size(); i++) { - operands[1] = children[i]; - Polygon2d * result = ClipperUtils::apply(operands, clipType); - if (operands[0] != children[0]) delete operands[0]; - operands[0] = result; - } - - assert(children.size() >= 2); - // We know that this is ok - return const_cast(operands[0]); - } - else { - return ClipperUtils::apply(children, clipType); - } + return ClipperUtils::apply(children, clipType); } /*! diff --git a/src/clipper-utils.cc b/src/clipper-utils.cc index 1bc1183a..9b9f2802 100644 --- a/src/clipper-utils.cc +++ b/src/clipper-utils.cc @@ -34,7 +34,13 @@ namespace ClipperUtils { clipper.Execute(ClipperLib::ctUnion, result, ClipperLib::pftEvenOdd); return result; } - + + /*! + We want to use a PolyTree to convert to Polygon2d, since only PolyTrees + have an explicit notion of holes. + We could use a Paths structure, but we'd have to check the orientation of each + path before adding it to the Polygon2d. + */ Polygon2d *toPolygon2d(const ClipperLib::PolyTree &poly) { Polygon2d *result = new Polygon2d; const ClipperLib::PolyNode *node = poly.GetFirst(); @@ -71,6 +77,23 @@ namespace ClipperUtils { ClipperLib::ClipType clipType) { ClipperLib::Clipper clipper; + + if (clipType == ClipperLib::ctIntersection && pathsvector.size() > 2) { + // intersection operations must be split into a sequence of binary operations + ClipperLib::Paths source = pathsvector[0]; + ClipperLib::PolyTree result; + for (int i = 1; i < pathsvector.size(); i++) { + clipper.AddPaths(source, ClipperLib::ptSubject, true); + clipper.AddPaths(pathsvector[i], ClipperLib::ptClip, true); + clipper.Execute(clipType, result, ClipperLib::pftNonZero, ClipperLib::pftNonZero); + if (i != pathsvector.size()-1) { + ClipperLib::PolyTreeToPaths(result, source); + clipper.Clear(); + } + } + return ClipperUtils::toPolygon2d(result); + } + bool first = true; BOOST_FOREACH(const ClipperLib::Paths &paths, pathsvector) { clipper.AddPaths(paths, first ? ClipperLib::ptSubject : ClipperLib::ptClip, true); diff --git a/tests/regression/dumptest/intersection2-tests-expected.csg b/tests/regression/dumptest/intersection2-tests-expected.csg new file mode 100644 index 00000000..78ea41ce --- /dev/null +++ b/tests/regression/dumptest/intersection2-tests-expected.csg @@ -0,0 +1,79 @@ +group() { + multmatrix([[1, 0, 0, 0], [0, 1, 0, -20], [0, 0, 1, 0], [0, 0, 0, 1]]) { + intersection() { + circle($fn = 0, $fa = 12, $fs = 2, r = 5); + square(size = [8, 8], center = true); + } + } + multmatrix([[1, 0, 0, -10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + intersection() { + circle($fn = 0, $fa = 12, $fs = 2, r = 5); + square(size = [0, 0], center = true); + } + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 20], [0, 0, 1, 0], [0, 0, 0, 1]]) { + intersection() { + group(); + circle($fn = 0, $fa = 12, $fs = 2, r = 5); + square(size = [8, 8], center = true); + } + } + multmatrix([[1, 0, 0, 20], [0, 1, 0, -20], [0, 0, 1, 0], [0, 0, 0, 1]]) { + intersection() { + multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 0, $fa = 12, $fs = 2, r = 15); + } + } + } + multmatrix([[1, 0, 0, 20], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + intersection() { + multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 0, $fa = 12, $fs = 2, r = 15); + } + multmatrix([[-0.5, -0.86602540378, 0, 0], [0.86602540378, -0.5, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 0, $fa = 12, $fs = 2, r = 15); + } + } + } + } + multmatrix([[1, 0, 0, 20], [0, 1, 0, 20], [0, 0, 1, 0], [0, 0, 0, 1]]) { + intersection() { + multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 0, $fa = 12, $fs = 2, r = 15); + } + multmatrix([[-0.5, -0.86602540378, 0, 0], [0.86602540378, -0.5, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 0, $fa = 12, $fs = 2, r = 15); + } + } + multmatrix([[-0.5, 0.86602540378, 0, 0], [-0.86602540378, -0.5, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 0, $fa = 12, $fs = 2, r = 15); + } + } + } + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + intersection() { + multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 0, $fa = 12, $fs = 2, r = 15); + } + multmatrix([[1, 0, 0, 5], [0, 1, 0, 8.66025403784], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 0, $fa = 12, $fs = 2, r = 15); + } + multmatrix([[1, 0, 0, -5], [0, 1, 0, 8.66025403784], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 0, $fa = 12, $fs = 2, r = 15); + } + multmatrix([[1, 0, 0, -10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 0, $fa = 12, $fs = 2, r = 15); + } + multmatrix([[1, 0, 0, -5], [0, 1, 0, -8.66025403784], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 0, $fa = 12, $fs = 2, r = 15); + } + multmatrix([[1, 0, 0, 5], [0, 1, 0, -8.66025403784], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 0, $fa = 12, $fs = 2, r = 15); + } + } + } +} diff --git a/tests/regression/opencsgtest/intersection2-tests-expected.png b/tests/regression/opencsgtest/intersection2-tests-expected.png new file mode 100644 index 0000000000000000000000000000000000000000..243cf40fe840f0d181f6c953da5637d5d793f73c GIT binary patch literal 7431 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 MQM)50f8ekF2MuG~BLDyZ literal 0 HcmV?d00001 diff --git a/tests/regression/throwntogethertest/intersection2-tests-expected.png b/tests/regression/throwntogethertest/intersection2-tests-expected.png new file mode 100644 index 0000000000000000000000000000000000000000..e84c642b49df65d15b4d482df249b12961a92c99 GIT binary patch literal 7025 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 MA3OB&C*qa=18wb$wEzGB literal 0 HcmV?d00001 From fbcb807463142d2ec48dba828634bd900f078015 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Tue, 28 Jan 2014 01:16:02 -0500 Subject: [PATCH 04/10] Short-circuit zero scaled 2D objects --- src/Polygon2d.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Polygon2d.cc b/src/Polygon2d.cc index 3c72b6f2..271a68a0 100644 --- a/src/Polygon2d.cc +++ b/src/Polygon2d.cc @@ -1,4 +1,5 @@ #include "Polygon2d.h" +#include "printutils.h" #include /*! @@ -54,6 +55,11 @@ bool Polygon2d::isEmpty() const void Polygon2d::transform(const Transform2d &mat) { + if (mat.matrix().determinant() == 0) { + PRINT("Warning: Scaling a 2D object with 0 - removing object"); + this->theoutlines.clear(); + return; + } BOOST_FOREACH(Outline2d &o, this->theoutlines) { BOOST_FOREACH(Vector2d &v, o.vertices) { v = mat * v; From 2e3729ab2268f29ee4ff5898f629c4a10c2d6587 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Tue, 28 Jan 2014 23:08:04 -0600 Subject: [PATCH 05/10] redo assemblePath for Win. redo openscad.com to handle spaces in filenames --- src/openscad.cc | 10 +++++++--- src/winconsole.c | 10 +++++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/openscad.cc b/src/openscad.cc index d9dd1580..09165ada 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -443,15 +443,19 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c #include #include #include +#include #include Q_DECLARE_METATYPE(shared_ptr); // Only if "fileName" is not absolute, prepend the "absoluteBase". -static QString assemblePath(const fs::path& absoluteBase, +static QString assemblePath(const fs::path& absoluteBaseDir, const string& fileName) { - return fileName.empty() ? "" : QDir(QString::fromStdString((const string&) absoluteBase)) - .absoluteFilePath(QString::fromStdString(fileName)); + if (fileName.empty()) return ""; + QString qsDir( boosty::stringy( absoluteBaseDir ).c_str() ); + QString qsFile( fileName.c_str() ); + QFileInfo info( qsDir, qsFile ); // if qsfile is absolute, dir is ignored. + return info.absoluteFilePath(); } bool QtUseGUI() diff --git a/src/winconsole.c b/src/winconsole.c index de8e6825..11a03090 100644 --- a/src/winconsole.c +++ b/src/winconsole.c @@ -40,16 +40,24 @@ int main( int argc, char * argv[] ) int eof = 0; int pclose_result; int i; + const char * argchar; int result = 0; + int quotify_arg = 0; strcat( cmd, "\0" ); strcat( cmd, "openscad.exe" ); for ( i = 1 ; i < argc ; ++i ) { + quotify_arg = 0; + for ( argchar = argv[i]; *argchar!=0; argchar++ ) { + if ((char)(*argchar)==' ') quotify_arg = 1; + } strcat( cmd, " " ); + if (quotify_arg) strcat( cmd, "\""); strcat( cmd, argv[i] ); + if (quotify_arg) strcat( cmd, "\""); } - strcat( cmd, " "); strcat( cmd, " 2>&1"); // capture stderr and stdout + printf("openscad.com: running command: %s\n", cmd ); cmd_stdout = _popen( cmd, "rt" ); if ( cmd_stdout == NULL ) { From 0308a2c896a13ae9d8cc032df1d08e13d3623f50 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Thu, 30 Jan 2014 18:21:32 -0600 Subject: [PATCH 06/10] build on system without OpenGL. do cmake .. -DNULLGL=1 --- doc/testing.txt | 67 +++++++++++++-------- src/CGAL_renderer.h | 22 +++++++ src/GLView.h | 1 + src/OffscreenView.cc | 1 - src/export.h | 2 +- src/export_png.cc | 2 + src/polyset.cc | 133 ++++++++++++++++++++++-------------------- src/system-gl.h | 10 +++- tests/CMakeLists.txt | 101 +++++++++++++++++++------------- tests/FindGLIB2.cmake | 24 ++++---- 10 files changed, 222 insertions(+), 141 deletions(-) diff --git a/doc/testing.txt b/doc/testing.txt index 311f0b8b..17281e4b 100644 --- a/doc/testing.txt +++ b/doc/testing.txt @@ -3,8 +3,10 @@ Running regression tests: Prerequisites: cmake, python, ImageMagick 6.5.9.3 or newer -First, get a working qmake GUI build of the main openscad binary and install MCAD. -See the main README. +First, install MCAD. + +$ cd openscad +$ git submodule update --init A) Building test environment @@ -13,7 +15,10 @@ $ cd tests $ cmake . $ make -Windows + MSVC: +Windows + MSVC: + +The MSVC build hasn't been tested in years. See the README for pointers. +First, gett the main GUI to build. Then, to build the tests: From the QT command prompt: @@ -23,9 +28,10 @@ From the QT command prompt: > cmake . > nmake -f Makefile -Cross compiling Linux->Win32: +Cross compiling Linux->Win32 and testing under Wine: -Please see openscad/tests/CMingw-cross-env.cmake for instructions. +Experimental. Please see openscad/tests/CMingw-cross-env.cmake for instructions +on attempting to get it to work. B) Running tests @@ -65,23 +71,6 @@ This is almost the same as adding a new regression test: 4) run the test normally and verify that it passes: $ ctest -C Examples -R exampleNNN -Migration away from dedicated regression tests: ------------------------------------------------ - -This test still needs an intermediate script that mangles away timestamps and -near-zero floating point numbers: - -* cgalstlsanitytest - -Some tests are yet to be converted: - -* csgtexttest -- verify whether this is not redundant with dumptest - -These look like tests, but are not actually in use: - -* modulecachetest -* cgalcachetest - Troubleshooting: ------------------------------ @@ -147,10 +136,42 @@ Is a boost/libstdc++ bug. Fix like so: $ export LC_MESSAGES= -6. Other issues +6. I want to build without OpenGL + + There is an unsupported way to do this, by defining NULLGL to Cmake: + + mkdir nullglbin + cd nullglbin && cmake .. -DNULLGL=1 && make + + The resulting openscad_nogui binary will fail most tests, but may be + useful for debugging and outputting 3d-formats like STL on systems without GL. + This option may break in the future and require tweaking to get working again. + +7. Other issues The OpenSCAD User Manual has a section on buildling. Please check there for updates: http://en.wikibooks.org/wiki/OpenSCAD_User_Manual + + +Migration away from dedicated regression tests: +----------------------------------------------- + +In 2013 the test programs underwent a major change. These notes are leftover. + +This test still needs an intermediate script that mangles away timestamps and +near-zero floating point numbers: + +* cgalstlsanitytest + +Some tests are yet to be converted: + +* csgtexttest -- verify whether this is not redundant with dumptest + +These look like tests, but are not actually in use: + +* modulecachetest +* cgalcachetest + diff --git a/src/CGAL_renderer.h b/src/CGAL_renderer.h index acc902ff..27ee59a6 100644 --- a/src/CGAL_renderer.h +++ b/src/CGAL_renderer.h @@ -27,6 +27,8 @@ #ifndef CGAL_RENDERER_H #define CGAL_RENDERER_H +#ifndef NULLGL + #include "OGL_helper.h" #undef CGAL_NEF3_MARKED_VERTEX_COLOR #undef CGAL_NEF3_MARKED_EDGE_COLOR @@ -101,4 +103,24 @@ private: }; // Polyhedron + + + +#else // NULLGL + +#include + +class Polyhedron +{ +public: + Polyhedron() {} + void draw(bool showedges) const {} + CGAL::Bbox_3 bbox() const { return CGAL::Bbox_3(-1,-1,-1,1,1,1); } +}; + +#endif // NULLGL + + + + #endif // CGAL_RENDERER_H diff --git a/src/GLView.h b/src/GLView.h index 165c6348..0b6d8046 100644 --- a/src/GLView.h +++ b/src/GLView.h @@ -7,6 +7,7 @@ This class is inherited by: *QGLview - for Qt GUI *OffscreenView - for offscreen rendering, in tests and from command-line +(This class is also overridden by NULLGL.cc for special experiments) The view assumes either a Gimbal Camera (rotation,translation,distance) or Vector Camera (eye,center/target) is being used. See Camera.h. The diff --git a/src/OffscreenView.cc b/src/OffscreenView.cc index 2186eb10..53aa6d0c 100644 --- a/src/OffscreenView.cc +++ b/src/OffscreenView.cc @@ -1,4 +1,3 @@ -#include #include "OffscreenView.h" #include "system-gl.h" #include diff --git a/src/export.h b/src/export.h index 7c137683..87dd3844 100644 --- a/src/export.h +++ b/src/export.h @@ -25,7 +25,7 @@ void export_png(const CGAL_Nef_polyhedron *root_N, Camera &c, std::ostream &outp void export_png_with_opencsg(Tree &tree, Camera &c, std::ostream &output); void export_png_with_throwntogether(Tree &tree, Camera &c, std::ostream &output); -#endif +#endif // ENABLE_CGAL #ifdef DEBUG void export_stl(const class PolySet &ps, std::ostream &output); diff --git a/src/export_png.cc b/src/export_png.cc index df76c4fa..ea060f9d 100644 --- a/src/export_png.cc +++ b/src/export_png.cc @@ -91,9 +91,11 @@ void export_png_preview_common( Tree &tree, Camera &cam, std::ostream &output, P } csgInfo.glview->setCamera( cam ); +#ifdef ENABLE_OPENCSG if ( previewer == OPENCSG ) csgInfo.glview->setRenderer( &openCSGRenderer ); else +#endif csgInfo.glview->setRenderer( &thrownTogetherRenderer ); #ifdef ENABLE_OPENCSG OpenCSG::setContext( 0 ); diff --git a/src/polyset.cc b/src/polyset.cc index 1adf92b2..689232c4 100644 --- a/src/polyset.cc +++ b/src/polyset.cc @@ -104,6 +104,71 @@ void PolySet::insert_vertex(Vector3d v) polygons.back().insert(polygons.back().begin(), v); } +BoundingBox PolySet::getBoundingBox() const +{ + BoundingBox bbox; + for (size_t i = 0; i < polygons.size(); i++) { + const Polygon &poly = polygons[i]; + for (size_t j = 0; j < poly.size(); j++) { + const Vector3d &p = poly[j]; + bbox.extend(p); + } + } + return bbox; +} + +size_t PolySet::memsize() const +{ + size_t mem = 0; + BOOST_FOREACH(const Polygon &p, this->polygons) mem += p.size() * sizeof(Vector3d); + mem += this->polygon.memsize() - sizeof(this->polygon); + mem += sizeof(PolySet); + return mem; +} + +void PolySet::append(const PolySet &ps) +{ + this->polygons.insert(this->polygons.end(), ps.polygons.begin(), ps.polygons.end()); +} + +void PolySet::transform(const Transform3d &mat) +{ + BOOST_FOREACH(Polygon &p, this->polygons) { + BOOST_FOREACH(Vector3d &v, p) { + v = mat * v; + } + } +} + +void PolySet::resize(Vector3d newsize, const Eigen::Matrix &autosize) +{ + BoundingBox bbox = this->getBoundingBox(); + + // Find largest dimension + int maxdim = 0; + for (int i=1;i<3;i++) if (newsize[i] > newsize[maxdim]) maxdim = i; + + // Default scale (scale with 1 if the new size is 0) + Vector3d scale(1,1,1); + for (int i=0;i<3;i++) if (newsize[i] > 0) scale[i] = newsize[i] / bbox.sizes()[i]; + + // Autoscale where applicable + double autoscale = scale[maxdim]; + Vector3d newscale; + for (int i=0;i<3;i++) newscale[i] = !autosize[i] || (newsize[i] > 0) ? scale[i] : autoscale; + + Transform3d t; + t.matrix() << + newscale[0], 0, 0, 0, + 0, newscale[1], 0, 0, + 0, 0, newscale[2], 0, + 0, 0, 0, 1; + + this->transform(t); +} + +// all GL functions grouped together here +#ifndef NULLGL static void gl_draw_triangle(GLint *shaderinfo, const Vector3d &p0, const Vector3d &p1, const Vector3d &p2, bool e0, bool e1, bool e2, double z, bool mirrored) { double ax = p1[0] - p0[0], bx = p1[0] - p2[0]; @@ -333,66 +398,8 @@ void PolySet::render_edges(Renderer::csgmode_e csgmode) const glEnable(GL_LIGHTING); } -BoundingBox PolySet::getBoundingBox() const -{ - BoundingBox bbox; - for (size_t i = 0; i < polygons.size(); i++) { - const Polygon &poly = polygons[i]; - for (size_t j = 0; j < poly.size(); j++) { - const Vector3d &p = poly[j]; - bbox.extend(p); - } - } - return bbox; -} - -size_t PolySet::memsize() const -{ - size_t mem = 0; - BOOST_FOREACH(const Polygon &p, this->polygons) mem += p.size() * sizeof(Vector3d); - mem += this->polygon.memsize() - sizeof(this->polygon); - mem += sizeof(PolySet); - return mem; -} - -void PolySet::append(const PolySet &ps) -{ - this->polygons.insert(this->polygons.end(), ps.polygons.begin(), ps.polygons.end()); -} - -void PolySet::transform(const Transform3d &mat) -{ - BOOST_FOREACH(Polygon &p, this->polygons) { - BOOST_FOREACH(Vector3d &v, p) { - v = mat * v; - } - } -} - -void PolySet::resize(Vector3d newsize, const Eigen::Matrix &autosize) -{ - BoundingBox bbox = this->getBoundingBox(); - - // Find largest dimension - int maxdim = 0; - for (int i=1;i<3;i++) if (newsize[i] > newsize[maxdim]) maxdim = i; - - // Default scale (scale with 1 if the new size is 0) - Vector3d scale(1,1,1); - for (int i=0;i<3;i++) if (newsize[i] > 0) scale[i] = newsize[i] / bbox.sizes()[i]; - - // Autoscale where applicable - double autoscale = scale[maxdim]; - Vector3d newscale; - for (int i=0;i<3;i++) newscale[i] = !autosize[i] || (newsize[i] > 0) ? scale[i] : autoscale; - - Transform3d t; - t.matrix() << - newscale[0], 0, 0, 0, - 0, newscale[1], 0, 0, - 0, 0, newscale[2], 0, - 0, 0, 0, 1; - - this->transform(t); -} - +#else //NULLGL +static void gl_draw_triangle(GLint *shaderinfo, const Vector3d &p0, const Vector3d &p1, const Vector3d &p2, bool e0, bool e1, bool e2, double z, bool mirrored) {} +void PolySet::render_surface(Renderer::csgmode_e csgmode, const Transform3d &m, GLint *shaderinfo) const {} +void PolySet::render_edges(Renderer::csgmode_e csgmode) const {} +#endif //NULLGL diff --git a/src/system-gl.h b/src/system-gl.h index 4a9474fe..50eeb21b 100644 --- a/src/system-gl.h +++ b/src/system-gl.h @@ -1,6 +1,8 @@ #ifndef SYSTEMGL_H_ #define SYSTEMGL_H_ +#ifndef NULLGL + #include #ifdef __APPLE__ @@ -13,10 +15,16 @@ #endif #endif +#else // NULLGL +#define GLint int +#define GLuint unsigned int +inline void glColor4fv( float *c ) {} +#endif // NULLGL + #include std::string glew_dump(); std::string glew_extensions_dump(); bool report_glerror(const char * function); -#endif +#endif // SYSTEMGL_H_ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6461bd85..e0868e8f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -73,6 +73,17 @@ if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../libraries/MCAD/__init__.py) message(FATAL_ERROR "MCAD not found. You can install from the OpenSCAD root as follows: \n git submodule update --init") endif() +# NULLGL - Allow us to buidl without OpenGL(TM). run 'cmake .. -DNULLGL=1' +# Most tests will fail, but it can be used for testing/experiments + +if(NULLGL) + set(ENABLE_OPENCSG_FLAG "") # OpenCSG is entirely an OpenGL software + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNULLGL") + set(SKIP_IMAGEMAGICK "1") # we dont generate png, so nothing to compare +else() + set(ENABLE_OPENCSG_FLAG "-DENABLE_OPENCSG") +endif() + # # Windows # @@ -255,6 +266,10 @@ else() inclusion(EIGEN_DIR EIGEN_INCLUDE_DIR) endif() +###### NULLGL wraps all OpenGL(TM) items (GL, Glew, OpenCSG) +###### Several pages of code fall under this 'if( NOT NULLGL )' +if (NOT NULLGL) + # OpenGL find_package(OpenGL REQUIRED) if (NOT OPENGL_GLU_FOUND) @@ -327,6 +342,8 @@ message(STATUS "GLEW library: " ${GLEW_LIBRARY}) inclusion(GLEW_DIR GLEW_INCLUDE_DIR) +endif() ########## NULLGL ENDIF + # Flex/Bison find_package(BISON REQUIRED) @@ -431,19 +448,19 @@ else() else() message(FATAL_ERROR "Couldn't find imagemagick 'convert' program") endif() -endif() -if ( "${ImageMagick_VERSION_STRING}" VERSION_LESS "6.5.9.4" ) - message(STATUS "ImageMagick version less than 6.5.9.4, cannot use -morphology comparison") - message(STATUS "ImageMagick Using older image comparison method") - set(COMPARATOR "old") -endif() + if ( "${ImageMagick_VERSION_STRING}" VERSION_LESS "6.5.9.4" ) + message(STATUS "ImageMagick version less than 6.5.9.4, cannot use -morphology comparison") + message(STATUS "ImageMagick Using older image comparison method") + set(COMPARATOR "old") + endif() -execute_process(COMMAND ${ImageMagick_convert_EXECUTABLE} --version OUTPUT_VARIABLE IM_OUT ) -if ( ${IM_OUT} MATCHES "OpenMP" ) - # http://www.daniloaz.com/en/617/systems/high-cpu-load-when-converting-images-with-imagemagick - message(STATUS "ImageMagick: OpenMP bug workaround - setting MAGICK_THREAD_LIMIT=1") - set(CTEST_ENVIRONMENT "${CTEST_ENVIRONMENT};MAGICK_THREAD_LIMIT=1") + execute_process(COMMAND ${ImageMagick_convert_EXECUTABLE} --version OUTPUT_VARIABLE IM_OUT ) + if ( ${IM_OUT} MATCHES "OpenMP" ) + # http://www.daniloaz.com/en/617/systems/high-cpu-load-when-converting-images-with-imagemagick + message(STATUS "ImageMagick: OpenMP bug workaround - setting MAGICK_THREAD_LIMIT=1") + set(CTEST_ENVIRONMENT "${CTEST_ENVIRONMENT};MAGICK_THREAD_LIMIT=1") + endif() endif() # Internal includes @@ -592,6 +609,21 @@ set(OFFSCREEN_SOURCES ../src/${PLATFORMUTILS_SOURCE} ../src/OpenCSGRenderer.cc) +if(NULLGL) + message(STATUS "NULLGL is set. Overriding previous OpenGL(TM) settings") + set(OFFSCREEN_SOURCES + ../src/NULLGL.cc # contains several 'nullified' versions of above .cc files + ../src/OffscreenView.cc + ../src/OffscreenContextNULL.cc + ../src/export_png.cc + ../src/${OFFSCREEN_IMGUTILS_SOURCE} + ../src/imageutils.cc + ../src/renderer.cc + ../src/render.cc + ../src/PlatformUtils.cc + ../src/${PLATFORMUTILS_SOURCE} ) +endif() + add_library(tests-core STATIC ${CORE_SOURCES}) target_link_libraries(tests-core ${OPENGL_LIBRARIES} ${GLIB2_LIBRARIES} ) set(TESTS-CORE-LIBRARIES ${OPENGL_LIBRARIES} ${GLIB2_LIBRARIES} ${Boost_LIBRARIES} ) @@ -604,11 +636,24 @@ set_target_properties(tests-cgal PROPERTIES COMPILE_FLAGS "-DENABLE_CGAL ${CGAL_ target_link_libraries(tests-cgal tests-common) set(TESTS-CGAL-LIBRARIES ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${GMP_LIBRARIES} ${MPFR_LIBRARIES} ${TESTS-CORE-LIBRARIES}) -add_library(tests-nocgal STATIC ${NOCGAL_SOURCES}) -target_link_libraries(tests-nocgal tests-common) +# +# Create non-CGAL tests +# +if (NOT NULLGL) + add_library(tests-nocgal STATIC ${NOCGAL_SOURCES}) + target_link_libraries(tests-nocgal tests-common) + set(TESTS-NOCGAL-LIBRARIES ${TESTS-CORE-LIBRARIES}) +else() + message(STATUS "NULLGL: cannot use GL/GLU tessellator. see dxftess.cc") + message(STATUS "NULLGL: non-CGAL tests will use CGAL's tessellator") + add_library(tests-nocgal STATIC ${CGAL_SOURCES}) + set_target_properties(tests-nocgal PROPERTIES COMPILE_FLAGS "-DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}") + target_link_libraries(tests-nocgal tests-common) + set(TESTS-NOCGAL-LIBRARIES ${TESTS-CGAL-LIBRARIES}) +endif() + add_library(tests-offscreen STATIC ${OFFSCREEN_SOURCES}) -set_target_properties(tests-offscreen PROPERTIES COMPILE_FLAGS "-DENABLE_OPENCSG -DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}") -set(TESTS-NOCGAL-LIBRARIES ${TESTS-CORE-LIBRARIES}) +set_target_properties(tests-offscreen PROPERTIES COMPILE_FLAGS "${ENABLE_OPENCSG_FLAG} -DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}") # # modulecachetest @@ -633,33 +678,9 @@ target_link_libraries(cgalcachetest tests-cgal ${TESTS-CGAL-LIBRARIES} ${CLIPPER # openscad no-qt # add_executable(openscad_nogui ../src/openscad.cc) -set_target_properties(openscad_nogui PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing -DEIGEN_DONT_ALIGN -DENABLE_CGAL -DENABLE_OPENCSG ${CGAL_CXX_FLAGS_INIT}") +set_target_properties(openscad_nogui PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing -DEIGEN_DONT_ALIGN -DENABLE_CGAL ${ENABLE_OPENCSG_FLAG} ${CGAL_CXX_FLAGS_INIT}") target_link_libraries(openscad_nogui tests-offscreen tests-cgal tests-nocgal ${TESTS-CORE-LIBRARIES} ${TESTS-CGAL-LIBRARIES} ${GLEW_LIBRARY} ${Boost_LIBRARIES} ${OPENCSG_LIBRARY} ${COCOA_LIBRARY} ${APP_SERVICES_LIBRARY}) -# -# GUI binary tests -# -#if(APPLE) -# set(OPENSCAD_BINPATH "${CMAKE_CURRENT_SOURCE_DIR}/../OpenSCAD.app/Contents/MacOS/OpenSCAD") -#elseif (MINGW_CROSS_ENV_DIR) -# set(OPENSCAD_BINPATH "${CMAKE_CURRENT_SOURCE_DIR}/../mingw32/release/openscad.exe") -#elseif(WIN32) -# set(OPENSCAD_BINPATH "${CMAKE_CURRENT_SOURCE_DIR}/../Release/openscad.exe") -#else() -# set(OPENSCAD_BINPATH "${CMAKE_CURRENT_SOURCE_DIR}/../openscad") -#endif() - -#if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/openscad") -# set(OPENSCAD_BINPATH "${CMAKE_CURRENT_BINARY_DIR}/openscad") -#endif() - -#if(EXISTS "${OPENSCAD_BINPATH}") -# message(STATUS "Found OpenSCAD binary: ${OPENSCAD_BINPATH}") -#else() -# message(STATUS "Couldn't find the OpenSCAD binary: ${OPENSCAD_BINPATH}") -# message(FATAL_ERROR "Please build the OpenSCAD binary and place it here: ${OPENSCAD_BINPATH}" ) -#endif() - if(WIN32) set(OPENSCAD_BINPATH "${CMAKE_CURRENT_BINARY_DIR}/openscad_nogui.exe") else() diff --git a/tests/FindGLIB2.cmake b/tests/FindGLIB2.cmake index 9164c391..407f4696 100644 --- a/tests/FindGLIB2.cmake +++ b/tests/FindGLIB2.cmake @@ -1,28 +1,28 @@ find_package(PkgConfig REQUIRED) pkg_search_module(GLIB2 REQUIRED glib-2.0) -#message("GLIB2_LIBRARIES ${GLIB2_LIBRARIES}") -message("GLIB2_LIBRARY_DIRS ${GLIB2_LIBRARY_DIRS}") -#message("GLIB2_LDFLAGS ${GLIB2_LDFLAGS}") -#message("GLIB2_LDFLAGS_OTHER ${GLIB2_LDFLAGS_OTHER}") -message("GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS}") -#message("GLIB2_CFLAGS ${GLIB2_CFLAGS}") -#message("GLIB2_CFLAGS_OTHER ${GLIB2_CFLAGS_OTHER}") -message("GLIB2_LIBDIR ${GLIB2_LIBDIR}") +#message(STATUS "GLIB2_LIBRARIES ${GLIB2_LIBRARIES}") +message(STATUS "GLIB2_LIBRARY_DIRS ${GLIB2_LIBRARY_DIRS}") +#message(STATUS "GLIB2_LDFLAGS ${GLIB2_LDFLAGS}") +#message(STATUS "GLIB2_LDFLAGS_OTHER ${GLIB2_LDFLAGS_OTHER}") +message(STATUS "GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS}") +#message(STATUS "GLIB2_CFLAGS ${GLIB2_CFLAGS}") +#message(STATUS "GLIB2_CFLAGS_OTHER ${GLIB2_CFLAGS_OTHER}") +message(STATUS "GLIB2_LIBDIR ${GLIB2_LIBDIR}") set(GLIB2_DEFINITIONS ${GLIB2_CFLAGS_OTHER}) -#message("GLIB2_DEFINITIONS ${GLIB2_DEFINITIONS}") +#message(STATUS "GLIB2_DEFINITIONS ${GLIB2_DEFINITIONS}") set(GLIB2_LIBRARY_NAMES ${GLIB2_LIBRARIES}) set(GLIB2_LIBRARIES "") foreach(GLIB2_LIB ${GLIB2_LIBRARY_NAMES}) -# message("lib: ${GLIB2_LIB}") +# message(STATUS "lib: ${GLIB2_LIB}") set(TMP TMP-NOTFOUND) find_library(TMP NAMES ${GLIB2_LIB} PATHS ${GLIB2_LIBRARY_DIRS} PATHS ${GLIB2_LIBDIR} NO_DEFAULT_PATH) -# message("TMP: ${TMP}") +# message(STATUS "TMP: ${TMP}") list(APPEND GLIB2_LIBRARIES "${TMP}") endforeach() -message("GLIB2_LIBRARIES: ${GLIB2_LIBRARIES}") +message(STATUS "GLIB2_LIBRARIES: ${GLIB2_LIBRARIES}") From 1b77d945bec70d5f9b250ed4b36e3b00146c4ce5 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Fri, 31 Jan 2014 00:59:59 -0500 Subject: [PATCH 07/10] bugfix: When trying to copy Nef polyhderons, we were just copying pointers, defeating the const --- src/GeometryEvaluator.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/GeometryEvaluator.cc b/src/GeometryEvaluator.cc index a6a95f2d..c95bd279 100644 --- a/src/GeometryEvaluator.cc +++ b/src/GeometryEvaluator.cc @@ -436,7 +436,7 @@ Response GeometryEvaluator::visit(State &state, const RenderNode &node) else if (shared_ptr N = dynamic_pointer_cast(geom)) { // If we got a const object, make a copy shared_ptr newN; - if (res.isConst()) newN.reset(new CGAL_Nef_polyhedron(*N)); + if (res.isConst()) newN.reset(N->copy()); else newN = dynamic_pointer_cast(res.ptr()); newN->setConvexity(node.convexity); geom = newN; @@ -552,7 +552,7 @@ Response GeometryEvaluator::visit(State &state, const TransformNode &node) assert(N); // If we got a const object, make a copy shared_ptr newN; - if (res.isConst()) newN.reset(new CGAL_Nef_polyhedron(*N)); + if (res.isConst()) newN.reset(N->copy()); else newN = dynamic_pointer_cast(res.ptr()); newN->transform(node.matrix); geom = newN; @@ -969,7 +969,7 @@ Response GeometryEvaluator::visit(State &state, const CgaladvNode &node) if (N) { // If we got a const object, make a copy shared_ptr newN; - if (res.isConst()) newN.reset(new CGAL_Nef_polyhedron(*N)); + if (res.isConst()) newN.reset(N->copy()); else newN = dynamic_pointer_cast(res.ptr()); applyResize3D(*newN, node.newsize, node.autosize); geom = newN; From 88ff8ee6d468e26b20c56d3d17b9f077db6f0ab1 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Fri, 31 Jan 2014 06:34:46 -0600 Subject: [PATCH 08/10] add missing file --- src/NULLGL.cc | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/NULLGL.cc diff --git a/src/NULLGL.cc b/src/NULLGL.cc new file mode 100644 index 00000000..496810c2 --- /dev/null +++ b/src/NULLGL.cc @@ -0,0 +1,39 @@ +#include "GLView.h" + +GLView::GLView() {} +void GLView::setRenderer(Renderer* r) {} +void GLView::initializeGL() {} +void GLView::resizeGL(int w, int h) {} +void GLView::setupGimbalCamPerspective() {} +void GLView::setupGimbalCamOrtho(double distance, bool offset) {} +void GLView::setupVectorCamPerspective() {} +void GLView::setupVectorCamOrtho(bool offset) {} +void GLView::setCamera( Camera &cam ) {} +void GLView::paintGL() {} +void GLView::vectorCamPaintGL() {} +void GLView::gimbalCamPaintGL() {} +void GLView::showSmallaxes() {} +void GLView::showAxes() {} +void GLView::showCrosshairs() {} + +#include "ThrownTogetherRenderer.h" + +ThrownTogetherRenderer::ThrownTogetherRenderer(CSGChain *root_chain, + CSGChain *highlights_chain, CSGChain *background_chain) {} +void ThrownTogetherRenderer::draw(bool /*showfaces*/, bool showedges) const {} +void ThrownTogetherRenderer::renderCSGChain(CSGChain *chain, bool + highlight, bool background, bool showedges, bool fberror) const {} + +#include "CGALRenderer.h" + +CGALRenderer::CGALRenderer(shared_ptr geom) {} +CGALRenderer::~CGALRenderer() {} +void CGALRenderer::draw(bool showfaces, bool showedges) const {} + +#include "system-gl.h" + +double gl_version() { return -1; } +std::string glew_dump() { return std::string("NULLGL Glew"); } +std::string glew_extensions_dump() { return std::string("NULLGL Glew Extensions"); } +bool report_glerror(const char * function) { return false; } + From 54742747ad0384e16ceb3d072334261b4e63b1dd Mon Sep 17 00:00:00 2001 From: Don Bright Date: Fri, 31 Jan 2014 06:41:57 -0600 Subject: [PATCH 09/10] adding missing file --- src/OffscreenContextNULL.cc | 66 +++++++++++++++++++++++++++++++++++++ src/grid.h | 10 ++++-- 2 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 src/OffscreenContextNULL.cc diff --git a/src/OffscreenContextNULL.cc b/src/OffscreenContextNULL.cc new file mode 100644 index 00000000..bcf9ff66 --- /dev/null +++ b/src/OffscreenContextNULL.cc @@ -0,0 +1,66 @@ +/* + +Create an NULL OpenGL context that doesnt actually use any OpenGL code, +and can be compiled on a system without OpenGL. + +*/ + +#include + +#include "OffscreenContext.h" +#include "printutils.h" +#include "imageutils.h" + +#include +#include +#include + +using namespace std; + +struct OffscreenContext +{ + int width; + int height; +}; + +void offscreen_context_init(OffscreenContext &ctx, int width, int height) +{ + ctx.width = width; + ctx.height = height; +} + +string offscreen_context_getinfo(OffscreenContext *ctx) +{ + return string("NULLGL"); +} + +OffscreenContext *create_offscreen_context(int w, int h) +{ + OffscreenContext *ctx = new OffscreenContext; + offscreen_context_init( *ctx, w, h ); +} + +bool teardown_offscreen_context(OffscreenContext *ctx) +{ + return true; +} + +bool save_framebuffer(OffscreenContext *ctx, char const * filename) +{ + std::ofstream fstream(filename,std::ios::out|std::ios::binary); + if (!fstream.is_open()) { + std::cerr << "Can't open file " << filename << " for writing"; + return false; + } else { + save_framebuffer(ctx, fstream); + fstream.close(); + } + return true; +} + +bool save_framebuffer(OffscreenContext *ctx, std::ostream &output) +{ + output << "NULLGL framebuffer"; + return true; +} + diff --git a/src/grid.h b/src/grid.h index c6cc7d25..913623c7 100644 --- a/src/grid.h +++ b/src/grid.h @@ -11,8 +11,14 @@ typedef __int64 int64_t; #include #include -const double GRID_COARSE = 0.001; -const double GRID_FINE = 0.000001; +//const double GRID_COARSE = 0.001; +//const double GRID_FINE = 0.000001; +/* Using decimals that are exactly convertible to binary floating point +(and then converted exactly to GMPQ Rational in CGAL's engine) provides +at least a 5% speedup for ctest -R CGAL. We choose 1/1024 and 1/(1024*1024) +In python: print '%.64f' % float(fractions.Fraction(1,1024)) */ +const double GRID_COARSE = 0.0009765625; +const double GRID_FINE = 0.00000095367431640625; template class Grid2d From 11c24e312030e8be9a5bcb953d8f26c94a9246a1 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Fri, 31 Jan 2014 06:42:13 -0600 Subject: [PATCH 10/10] undo my changes --- src/grid.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/grid.h b/src/grid.h index 913623c7..c6cc7d25 100644 --- a/src/grid.h +++ b/src/grid.h @@ -11,14 +11,8 @@ typedef __int64 int64_t; #include #include -//const double GRID_COARSE = 0.001; -//const double GRID_FINE = 0.000001; -/* Using decimals that are exactly convertible to binary floating point -(and then converted exactly to GMPQ Rational in CGAL's engine) provides -at least a 5% speedup for ctest -R CGAL. We choose 1/1024 and 1/(1024*1024) -In python: print '%.64f' % float(fractions.Fraction(1,1024)) */ -const double GRID_COARSE = 0.0009765625; -const double GRID_FINE = 0.00000095367431640625; +const double GRID_COARSE = 0.001; +const double GRID_FINE = 0.000001; template class Grid2d