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/GeometryEvaluator.cc b/src/GeometryEvaluator.cc index 6b5a8c89..c95bd279 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: @@ -428,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; @@ -544,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; @@ -961,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; 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; } + 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/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/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; 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/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/openscad.cc b/src/openscad.cc index 158763ab..b63a364d 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/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/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 ) { 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/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}") diff --git a/tests/regression/cgalpngtest/intersection2-tests-expected.png b/tests/regression/cgalpngtest/intersection2-tests-expected.png new file mode 100644 index 00000000..5cd53ebc Binary files /dev/null and b/tests/regression/cgalpngtest/intersection2-tests-expected.png differ 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 00000000..243cf40f Binary files /dev/null and b/tests/regression/opencsgtest/intersection2-tests-expected.png differ diff --git a/tests/regression/throwntogethertest/intersection2-tests-expected.png b/tests/regression/throwntogethertest/intersection2-tests-expected.png new file mode 100644 index 00000000..e84c642b Binary files /dev/null and b/tests/regression/throwntogethertest/intersection2-tests-expected.png differ