diff --git a/fonts/05-osx-fonts.conf b/fonts-osx/conf.d/05-osx-fonts.conf similarity index 100% rename from fonts/05-osx-fonts.conf rename to fonts-osx/conf.d/05-osx-fonts.conf diff --git a/openscad.pro b/openscad.pro index 5fdcab29..d745c708 100644 --- a/openscad.pro +++ b/openscad.pro @@ -12,6 +12,10 @@ # # PREFIX defines the base installation folder # +# SUFFIX defines an optional suffix for the binary and the +# resource folder. E.g. using SUFFIX=-nightly will name the +# resulting binary openscad-nightly. +# # Please see the 'Building' sections of the OpenSCAD user manual # for updated tips & workarounds. # @@ -78,8 +82,10 @@ macx { TARGET = OpenSCAD } else { - TARGET = openscad + TARGET = openscad$${SUFFIX} } +FULLNAME = openscad$${SUFFIX} +!isEmpty(SUFFIX): DEFINES += INSTALL_SUFFIX="\"\\\"$${SUFFIX}\\\"\"" macx { ICON = icons/OpenSCAD.icns @@ -110,7 +116,6 @@ macx { win* { RC_FILE = openscad_win32.rc - QTPLUGIN += qtaccessiblewidgets } CONFIG += qt @@ -124,8 +129,6 @@ unix:!macx { QMAKE_LIBS_OPENGL *= -lX11 } -#QTPLUGIN += qtaccessiblewidgets - netbsd* { QMAKE_LFLAGS += -L/usr/X11R7/lib QMAKE_LFLAGS += -Wl,-R/usr/X11R7/lib @@ -491,54 +494,57 @@ QMAKE_POST_LINK += $$PWD/scripts/translation-make.sh # Create install targets for the languages defined in LINGUAS LINGUAS = $$cat(locale/LINGUAS) -LOCALE_PREFIX = $$PREFIX/share/openscad/locale +LOCALE_PREFIX = "$$PREFIX/share/$${FULLNAME}/locale" for(language, LINGUAS) { - catalog = locale/$$language/LC_MESSAGES/openscad.mo - exists($$catalog) { + catalogdir = locale/$$language/LC_MESSAGES + exists(locale/$${language}.po) { + # Use .extra and copy manually as the source path might not exist, + # e.g. on a clean checkout. In that case qmake would not create + # the needed targets in the generated Makefile. translation_path = translation_$${language}.path - translation_files = translation_$${language}.files + translation_extra = translation_$${language}.extra translation_depends = translation_$${language}.depends $$translation_path = $$LOCALE_PREFIX/$$language/LC_MESSAGES/ - $$translation_files = $$catalog + $$translation_extra = cp -f $${catalogdir}/openscad.mo \"\$(INSTALL_ROOT)$$LOCALE_PREFIX/$$language/LC_MESSAGES/openscad.mo\" $$translation_depends = locale/$${language}.po INSTALLS += translation_$$language } } -examples.path = $$PREFIX/share/openscad/examples/ +examples.path = "$$PREFIX/share/$${FULLNAME}/examples/" examples.files = examples/* INSTALLS += examples -libraries.path = $$PREFIX/share/openscad/libraries/ +libraries.path = "$$PREFIX/share/$${FULLNAME}/libraries/" libraries.files = libraries/* INSTALLS += libraries -fonts.path = $$PREFIX/share/openscad/fonts/ +fonts.path = "$$PREFIX/share/$${FULLNAME}/fonts/" fonts.files = fonts/* INSTALLS += fonts -colorschemes.path = $$PREFIX/share/openscad/color-schemes/ +colorschemes.path = "$$PREFIX/share/$${FULLNAME}/color-schemes/" colorschemes.files = color-schemes/* INSTALLS += colorschemes applications.path = $$PREFIX/share/applications -applications.files = icons/openscad.desktop +applications.extra = cat icons/openscad.desktop | sed -e \"'s/^Icon=openscad/Icon=$${FULLNAME}/; s/^Exec=openscad/Exec=$${FULLNAME}/'\" > \"\$(INSTALL_ROOT)$${applications.path}/$${FULLNAME}.desktop\" INSTALLS += applications mimexml.path = $$PREFIX/share/mime/packages -mimexml.files = icons/openscad.xml +mimexml.extra = cp -f icons/openscad.xml \"\$(INSTALL_ROOT)$${mimexml.path}/$${FULLNAME}.xml\" INSTALLS += mimexml appdata.path = $$PREFIX/share/appdata -appdata.files = openscad.appdata.xml +appdata.extra = cp -f openscad.appdata.xml \"\$(INSTALL_ROOT)$${appdata.path}/$${FULLNAME}.appdata.xml\" INSTALLS += appdata icons.path = $$PREFIX/share/pixmaps -icons.files = icons/openscad.png +icons.extra = cp -f icons/openscad.png \"\$(INSTALL_ROOT)$${icons.path}/$${FULLNAME}.png\" INSTALLS += icons man.path = $$PREFIX/share/man/man1 -man.files = doc/openscad.1 +man.extra = cp -f doc/openscad.1 \"\$(INSTALL_ROOT)$${man.path}/$${FULLNAME}.1\" INSTALLS += man CONFIG(winconsole) { diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh index e91123cc..86bb3c7b 100755 --- a/scripts/macosx-build-dependencies.sh +++ b/scripts/macosx-build-dependencies.sh @@ -515,7 +515,7 @@ build_freetype() cd "$BASEDIR"/src rm -rf "freetype-$version" if [ ! -f "freetype-$version.tar.gz" ]; then - curl --insecure -LO "http://download.savannah.gnu.org/releases/freetype/freetype-$version.tar.gz" + curl --insecure -LO "http://downloads.sourceforge.net/project/freetype/freetype2/$version/freetype-$version.tar.gz" fi tar xzf "freetype-$version.tar.gz" cd "freetype-$version" @@ -655,7 +655,7 @@ build_ragel() cd "$BASEDIR"/src rm -rf "ragel-$version" if [ ! -f "ragel-$version.tar.gz" ]; then - curl --insecure -LO "http://www.colm.net/wp-content/uploads/2014/10/ragel-$version.tar.gz" + curl --insecure -LO "http://www.colm.net/files/ragel/ragel-$version.tar.gz" fi tar xzf "ragel-$version.tar.gz" cd "ragel-$version" @@ -770,7 +770,7 @@ fi echo "Using basedir:" $BASEDIR mkdir -p $SRCDIR $DEPLOYDIR -build_qt5 5.3.1 +build_qt5 5.3.2 build_qscintilla 2.8.4 # NB! For eigen, also update the path in the function build_eigen 3.2.1 @@ -784,7 +784,7 @@ build_gettext 0.18.3.2 build_libffi 3.1 build_glib2 2.40.0 build_opencsg 1.4.0 -build_freetype 2.5.3 --without-png +build_freetype 2.5.4 --without-png build_ragel 6.9 build_harfbuzz 0.9.35 "--with-coretext=auto --with-glib=no" export FREETYPE_CFLAGS="-I$DEPLOYDIR/include -I$DEPLOYDIR/include/freetype2" diff --git a/src/CGAL_Nef_polyhedron.cc b/src/CGAL_Nef_polyhedron.cc index dfe16536..d49521e0 100644 --- a/src/CGAL_Nef_polyhedron.cc +++ b/src/CGAL_Nef_polyhedron.cc @@ -48,6 +48,11 @@ size_t CGAL_Nef_polyhedron::memsize() const return memsize; } +bool CGAL_Nef_polyhedron::isEmpty() const +{ + return !this->p3 || this->p3->is_empty(); +} + /*! Creates a new PolySet and initializes it with the data from this polyhedron diff --git a/src/CGAL_Nef_polyhedron.h b/src/CGAL_Nef_polyhedron.h index f3585469..2d7b37d6 100644 --- a/src/CGAL_Nef_polyhedron.h +++ b/src/CGAL_Nef_polyhedron.h @@ -19,7 +19,7 @@ public: virtual std::string dump() const; virtual unsigned int getDimension() const { return 3; } // Empty means it is a geometric node which has zero area/volume - virtual bool isEmpty() const { return !p3; } + virtual bool isEmpty() const; virtual Geometry *copy() const { return new CGAL_Nef_polyhedron(*this); } void reset() { p3.reset(); } diff --git a/src/CsgInfo.h b/src/CsgInfo.h index c50ab4d4..8a3512c8 100644 --- a/src/CsgInfo.h +++ b/src/CsgInfo.h @@ -12,13 +12,8 @@ class CsgInfo { public: - CsgInfo() + CsgInfo() : glview(NULL), root_chain(NULL), highlights_chain(NULL), background_chain(NULL), progress_function(NULL) { - root_chain = NULL; - highlights_chain = NULL; - background_chain = NULL; - glview = NULL; - progress_function = NULL; normalizelimit = RenderSettings::inst()->openCSGTermLimit; } OffscreenView *glview; @@ -43,12 +38,6 @@ public: CSGTermEvaluator evaluator(tree, &geomevaluator); boost::shared_ptr root_raw_term = evaluator.evaluateCSGTerm( *root_node, this->highlight_terms, this->background_terms ); - if (!root_raw_term && this->background_terms.empty()) { - PRINT("Error: CSG generation failed! (no objects found)"); - call_progress_function(); - return false; - } - PRINT("Compiling design (CSG Products normalization)..."); call_progress_function(); CSGTermNormalizer normalizer( normalizelimit ); diff --git a/src/GeometryEvaluator.cc b/src/GeometryEvaluator.cc index 71b52a81..24118c1f 100644 --- a/src/GeometryEvaluator.cc +++ b/src/GeometryEvaluator.cc @@ -63,10 +63,12 @@ shared_ptr GeometryEvaluator::evaluateGeometry(const AbstractNod PolySet *ps = new PolySet(3); ps->setConvexity(N->getConvexity()); this->root.reset(ps); - bool err = CGALUtils::createPolySetFromNefPolyhedron3(*N->p3, *ps); - if (err) { - PRINT("ERROR: Nef->PolySet failed"); - } + if (!N->isEmpty()) { + bool err = CGALUtils::createPolySetFromNefPolyhedron3(*N->p3, *ps); + if (err) { + PRINT("ERROR: Nef->PolySet failed"); + } + } smartCacheInsert(node, this->root); } @@ -123,8 +125,9 @@ GeometryEvaluator::ResultObject GeometryEvaluator::applyToChildren3D(const Abstr if (op == OPENSCAD_MINKOWSKI) return ResultObject(CGALUtils::applyMinkowski(children)); - CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron; - CGALUtils::applyOperator(children, *N, op); + CGAL_Nef_polyhedron *N = CGALUtils::applyOperator(children, op); + // FIXME: Clarify when we can return NULL and what that means + if (!N) N = new CGAL_Nef_polyhedron; return ResultObject(N); } @@ -354,6 +357,7 @@ void GeometryEvaluator::addToParent(const State &state, // Root node, insert into cache smartCacheInsert(node, geom); this->root = geom; + assert(this->visitedchildren.empty()); } } @@ -547,7 +551,12 @@ Response GeometryEvaluator::visit(State &state, const TransformNode &node) node.matrix(1,0), node.matrix(1,1), node.matrix(1,3), node.matrix(3,0), node.matrix(3,1), node.matrix(3,3); newpoly->transform(mat2); - geom = newpoly; + // A 2D transformation may flip the winding order of a polygon. + // If that happens with a sanitized polygon, we need to reverse + // the winding order for it to be correct. + if (newpoly->isSanitized() && mat2.matrix().determinant() <= 0) { + geom.reset(ClipperUtils::sanitize(*newpoly)); + } } else if (geom->getDimension() == 3) { shared_ptr ps = dynamic_pointer_cast(geom); diff --git a/src/LibraryInfo.cc b/src/LibraryInfo.cc index 83f3875c..52facbb1 100644 --- a/src/LibraryInfo.cc +++ b/src/LibraryInfo.cc @@ -29,12 +29,20 @@ std::string LibraryInfo::info() { std::stringstream s; +#if defined(__x86_64__) || defined(_M_X64) + std::string bits(" 64bit"); +#elif defined(__i386) || defined(_M_IX86) + std::string bits(" 32bit"); +#else + std::string bits(""); +#endif + #if defined(__GNUG__) && !defined(__clang__) - std::string compiler_info( "GCC " + std::string(TOSTRING(__VERSION__)) ); + std::string compiler_info( "GCC " + std::string(TOSTRING(__VERSION__)) + bits); #elif defined(_MSC_VER) - std::string compiler_info( "MSVC " + std::string(TOSTRING(_MSC_FULL_VER)) ); + std::string compiler_info( "MSVC " + std::string(TOSTRING(_MSC_FULL_VER)) + bits); #elif defined(__clang__) - std::string compiler_info( "Clang " + std::string(TOSTRING(__clang_version__)) ); + std::string compiler_info( "Clang " + std::string(TOSTRING(__clang_version__)) + bits); #else std::string compiler_info( "unknown compiler" ); #endif @@ -80,6 +88,7 @@ std::string LibraryInfo::info() const char *env_font_path = getenv("OPENSCAD_FONT_PATH"); s << "OpenSCAD Version: " << TOSTRING(OPENSCAD_VERSION) + << "\nSystem information: " << PlatformUtils::sysinfo() << "\nCompiler, build date: " << compiler_info << ", " << __DATE__ << "\nBoost version: " << BOOST_LIB_VERSION << "\nEigen version: " << EIGEN_WORLD_VERSION << "." << EIGEN_MAJOR_VERSION << "." << EIGEN_MINOR_VERSION diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 81f6c34b..74365644 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -543,6 +543,9 @@ Ctrl+Q + + QAction::QuitRole + @@ -955,6 +958,9 @@ About + + QAction::AboutRole + @@ -983,6 +989,9 @@ Preferences + + QAction::PreferencesRole + diff --git a/src/PlatformUtils-mac.mm b/src/PlatformUtils-mac.mm index cb93e522..768d9c09 100644 --- a/src/PlatformUtils-mac.mm +++ b/src/PlatformUtils-mac.mm @@ -1,4 +1,8 @@ #include "PlatformUtils.h" +#include +#include +#include + #import std::string PlatformUtils::pathSeparatorChar() @@ -35,5 +39,33 @@ unsigned long PlatformUtils::stackLimit() return STACK_LIMIT_DEFAULT; } +std::string PlatformUtils::sysinfo() +{ + std::string result; + + result += "Mac OS X "; + result += [[[NSProcessInfo processInfo] operatingSystemVersionString] UTF8String]; + + int mib[2]; + int64_t physical_memory; + int32_t numcpu; + size_t length64 = sizeof(int64_t); + size_t length32 = sizeof(int32_t);; + + sysctlbyname("hw.memsize", &physical_memory, &length64, NULL, 0); + sysctlbyname("hw.physicalcpu", &numcpu, &length32, NULL, 0); + + result += " "; + result += boost::lexical_cast(numcpu); + result += " CPU"; + if (numcpu > 1) result += "s"; + + result += " "; + result += PlatformUtils::toMemorySizeString(physical_memory, 2); + result += " RAM"; + + return result; +} + void PlatformUtils::ensureStdIO(void) {} diff --git a/src/PlatformUtils-posix.cc b/src/PlatformUtils-posix.cc index 3854a5e7..c3767fa7 100644 --- a/src/PlatformUtils-posix.cc +++ b/src/PlatformUtils-posix.cc @@ -1,4 +1,13 @@ +#include +#include +#include +#include #include +#include + +#include +#include +#include #include "PlatformUtils.h" #include "boosty.h" @@ -60,5 +69,109 @@ unsigned long PlatformUtils::stackLimit() return STACK_LIMIT_DEFAULT; } +static std::string readText(const std::string &path) +{ + std::ifstream s(path.c_str()); + s.seekg(0, std::ios::end); + if (s.fail() || s.tellg() > 4096) { + return ""; + } + s.seekg(0, std::ios::beg); + + std::string text((std::istreambuf_iterator(s)), std::istreambuf_iterator()); + return text; +} + +/** + * Check /etc/os-release as defined by systemd. + * @see http://0pointer.de/blog/projects/os-release.html + * @see http://www.freedesktop.org/software/systemd/man/os-release.html + * @return the PRETTY_NAME from the os-release file or an empty string. + */ +static std::string checkOsRelease() +{ + std::string os_release(readText("/etc/os-release")); + + boost::smatch results; + boost::regex pretty_name("^PRETTY_NAME=\"([^\"]+)\""); + if (boost::regex_search(os_release, results, pretty_name)) { + return results[1]; + } + + return ""; +} + +static std::string checkEtcIssue() +{ + std::string issue(readText("/etc/issue")); + + boost::regex nl("\n.*$"); + issue = boost::regex_replace(issue, nl, ""); + boost::regex esc("\\\\."); + issue = boost::regex_replace(issue, esc, ""); + boost::algorithm::trim(issue); + + return issue; +} + +static std::string detectDistribution() +{ + std::string osrelease = checkOsRelease(); + if (!osrelease.empty()) { + return osrelease; + } + + std::string etcissue = checkEtcIssue(); + if (!etcissue.empty()) { + return etcissue; + } + + return ""; +} + +std::string PlatformUtils::sysinfo() +{ + std::string result; + + struct utsname osinfo; + if (uname(&osinfo) == 0) { + result += osinfo.sysname; + result += " "; + result += osinfo.release; + result += " "; + result += osinfo.version; + result += " "; + result += osinfo.machine; + } else { + result += "Unknown Linux"; + } + + long numcpu = sysconf(_SC_NPROCESSORS_ONLN); + if (numcpu > 0) { + result += " "; + result += boost::lexical_cast(numcpu); + result += " CPU"; + if (numcpu > 1) { + result += "s"; + } + } + + long pages = sysconf(_SC_PHYS_PAGES); + long pagesize = sysconf(_SC_PAGE_SIZE); + if ((pages > 0) && (pagesize > 0)) { + result += " "; + result += PlatformUtils::toMemorySizeString(pages * pagesize, 2); + result += " RAM"; + } + + std::string distribution = detectDistribution(); + if (!distribution.empty()) { + result += " "; + result += distribution; + } + + return result; +} + void PlatformUtils::ensureStdIO(void) {} diff --git a/src/PlatformUtils-win.cc b/src/PlatformUtils-win.cc index c83855d0..1f07b683 100644 --- a/src/PlatformUtils-win.cc +++ b/src/PlatformUtils-win.cc @@ -98,6 +98,96 @@ unsigned long PlatformUtils::stackLimit() return STACK_LIMIT_DEFAULT; } +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); + +// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms684139%28v=vs.85%29.aspx +static BOOL IsWow64() +{ + BOOL bIsWow64 = FALSE; + + //IsWow64Process is not available on all supported versions of Windows. + //Use GetModuleHandle to get a handle to the DLL that contains the function + //and GetProcAddress to get a pointer to the function if available. + LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process"); + + if (NULL != fnIsWow64Process) { + if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) + { + return false; + } + } + return bIsWow64; +} + +std::string PlatformUtils::sysinfo() +{ + std::string result; + + OSVERSIONINFOEX osinfo; + osinfo.dwOSVersionInfoSize = sizeof(osinfo); + if (GetVersionEx((OSVERSIONINFO*)&osinfo) == 0) { + result += "Unknown Windows"; + } else { + unsigned int version = osinfo.dwMajorVersion * 1000 + osinfo.dwMinorVersion; + if (osinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { + switch (version) { + case 5000: + result += "Windows 2000"; + break; + case 5001: + result += "Windows XP"; + break; + case 5002: + result += "Windows Server 2003"; + break; + case 6000: + result += (osinfo.wProductType == VER_NT_WORKSTATION ? "Windows Vista" : "Windows Server 2008"); + break; + case 6001: + result += (osinfo.wProductType == VER_NT_WORKSTATION ? "Windows 7" : "Windows Server 2008 R2"); + break; + case 6002: + result += (osinfo.wProductType == VER_NT_WORKSTATION ? "Windows 8" : "Windows Server 2012"); + break; + case 6003: + // For applications that have been manifested for Windows 8.1. + result += (osinfo.wProductType == VER_NT_WORKSTATION ? "Windows 8.1" : "Windows Server 2012 R2"); + break; + } + boost::format fmt(" (v%d.%d)"); + fmt % osinfo.dwMajorVersion % osinfo.dwMinorVersion; + result += fmt.str(); + } else { + boost::format fmt("Unknown Windows (dwPlatformId = %d, dwMajorVersion = %d, dwMinorVersion = %d"); + fmt % osinfo.dwPlatformId % osinfo.dwMajorVersion % osinfo.dwMinorVersion; + result += fmt.str(); + } + } + + SYSTEM_INFO systeminfo; + bool isWow64 = IsWow64(); + if (isWow64) { + GetNativeSystemInfo(&systeminfo); + } else { + GetSystemInfo(&systeminfo); + } + + int numcpu = systeminfo.dwNumberOfProcessors; + boost::format fmt(" %d CPU%s%s"); + fmt % numcpu % (numcpu > 1 ? "s" : "") % (isWow64 ? " WOW64" : ""); + result += fmt.str(); + + MEMORYSTATUSEX memoryinfo; + memoryinfo.dwLength = sizeof(memoryinfo); + if (GlobalMemoryStatusEx(&memoryinfo) != 0) { + result += " "; + result += PlatformUtils::toMemorySizeString(memoryinfo.ullTotalPhys, 2); + result += " RAM"; + } + + return result; +} + #include #include #include diff --git a/src/PlatformUtils.cc b/src/PlatformUtils.cc index 2dc524ea..a15a0a3c 100644 --- a/src/PlatformUtils.cc +++ b/src/PlatformUtils.cc @@ -1,7 +1,14 @@ #include +#include #include "PlatformUtils.h" +#ifdef INSTALL_SUFFIX +#define RESOURCE_FOLDER(path) path INSTALL_SUFFIX +#else +#define RESOURCE_FOLDER(path) path +#endif + extern std::vector librarypath; extern std::vector fontpath; @@ -28,8 +35,8 @@ static std::string lookupResourcesPath() }; #else const char *searchpath[] = { - "../share/openscad", - "../../share/openscad", + RESOURCE_FOLDER("../share/openscad"), + RESOURCE_FOLDER("../../share/openscad"), ".", "..", "../..", @@ -184,3 +191,25 @@ int PlatformUtils::setenv(const char *name, const char *value, int overwrite) return ::setenv(name, value, overwrite); #endif } + +std::string PlatformUtils::toMemorySizeString(unsigned long bytes, int digits) +{ + static const char *units[] = { "B", "kB", "MB", "GB", "TB", NULL }; + + int idx = 0; + double val = bytes; + while (true) { + if (val < 1024.0) { + break; + } + if (units[idx + 1] == NULL) { + break; + } + idx++; + val /= 1024.0; + } + + boost::format fmt("%f %s"); + fmt % boost::io::group(std::setprecision(digits), val) % units[idx]; + return fmt.str(); +} diff --git a/src/PlatformUtils.h b/src/PlatformUtils.h index a5c2ec91..5210dc85 100644 --- a/src/PlatformUtils.h +++ b/src/PlatformUtils.h @@ -34,6 +34,20 @@ namespace PlatformUtils { std::string backupPath(); bool createBackupPath(); + /** + * Return a human readable text describing the operating system + * the application is currently running on. This is mainly intended + * to provide information for bug reports (e.g. to be included in + * the LibraryInfoDialog). + * + * If there is some error to retrieve the details, at least the + * OS type is reported based on what platform the application was + * built for. + * + * @return system information. + */ + std::string sysinfo(); + /** * Platform abstraction to set environment variables. Windows/MinGW * does not support setenv(), but needs _putenv(). @@ -65,4 +79,10 @@ namespace PlatformUtils { * Currently limited to MS Windows GUI application console only. */ void ensureStdIO(void); + + /** + * Convert the number of bytes to a human readable string with + * a given number of digits. + */ + std::string toMemorySizeString(unsigned long bytes, int digits); } diff --git a/src/Polygon2d.cc b/src/Polygon2d.cc index 8152c7f9..aeb22b22 100644 --- a/src/Polygon2d.cc +++ b/src/Polygon2d.cc @@ -11,8 +11,10 @@ We can store sanitized vs. unsanitized polygons. Sanitized polygons will have opposite winding order for holes and is guaranteed to not - have intersecting geometry. Sanitization is typically done by ClipperUtils, but - if you create geometry which you know is sanitized, the flag can be set manually. + have intersecting geometry. The winding order will be counter-clockwise + for positive outlines and clockwise for holes. Sanitization is typically + done by ClipperUtils, but if you create geometry which you know is sanitized, + the flag can be set manually. */ size_t Polygon2d::memsize() const diff --git a/src/cgalutils.cc b/src/cgalutils.cc index 5693ed60..cc8d870f 100644 --- a/src/cgalutils.cc +++ b/src/cgalutils.cc @@ -273,7 +273,11 @@ static CGAL_Nef_polyhedron *createNefPolyhedronFromPolySet(const PolySet &ps) if (ps.isEmpty()) return new CGAL_Nef_polyhedron(); assert(ps.getDimension() == 3); - if (ps.is_convex()) { + // Since is_convex doesn't work well with non-planar faces, + // we tessellate the polyset before checking. + PolySet ps_tri(3); + PolysetUtils::tessellate_faces(ps, ps_tri); + if (ps_tri.is_convex()) { typedef CGAL::Exact_predicates_inexact_constructions_kernel K; // Collect point cloud std::set points; @@ -316,10 +320,8 @@ static CGAL_Nef_polyhedron *createNefPolyhedronFromPolySet(const PolySet &ps) } } if (plane_error) try { - PolySet ps2(3); CGAL_Polyhedron P; - PolysetUtils::tessellate_faces(ps, ps2); - bool err = CGALUtils::createPolyhedronFromPolySet(ps2,P); + bool err = CGALUtils::createPolyhedronFromPolySet(ps_tri, P); if (!err) N = new CGAL_Nef_polyhedron3(P); } catch (const CGAL::Assertion_exception &e) { @@ -603,14 +605,13 @@ namespace CGALUtils { fake_children.push_back(std::make_pair((const AbstractNode*)NULL, shared_ptr(createNefPolyhedronFromGeometry(ps)))); } - CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron; - CGALUtils::applyOperator(fake_children, *N, OPENSCAD_UNION); + CGAL_Nef_polyhedron *N = CGALUtils::applyOperator(fake_children, OPENSCAD_UNION); t.stop(); PRINTDB("Minkowski: Union done: %f s",t.time()); t.reset(); operands[0] = N; } else { - return NULL; + operands[0] = new CGAL_Nef_polyhedron(); } } @@ -623,17 +624,16 @@ namespace CGALUtils { // If anything throws we simply fall back to Nef Minkowski PRINTD("Minkowski: Falling back to Nef Minkowski"); - CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron; - applyOperator(children, *N, OPENSCAD_MINKOWSKI); + CGAL_Nef_polyhedron *N = applyOperator(children, OPENSCAD_MINKOWSKI); return N; } } /*! - Applies op to all children and stores the result in dest. + Applies op to all children and returns the result. The child list should be guaranteed to contain non-NULL 3D or empty Geometry objects */ - void applyOperator(const Geometry::ChildList &children, CGAL_Nef_polyhedron &dest, OpenSCADOperator op) + CGAL_Nef_polyhedron *applyOperator(const Geometry::ChildList &children, OpenSCADOperator op) { // Speeds up n-ary union operations significantly CGAL::Nef_nary_union_3 nary_union; @@ -720,13 +720,15 @@ namespace CGALUtils { } CGAL::set_error_behaviour(old_behaviour); } - if (N) dest = *N; + return N; } /*! Modifies target by applying op to target and src: target = target [op] src */ +//FIXME: Old, can be removed: +#if 0 void applyBinaryOperator(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op) { if (target.getDimension() != 2 && target.getDimension() != 3) { @@ -772,6 +774,7 @@ namespace CGALUtils { } CGAL::set_error_behaviour(old_behaviour); } +#endif static void add_outline_to_poly(CGAL_Nef_polyhedron2::Explorer &explorer, CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator circ, @@ -932,6 +935,13 @@ namespace CGALUtils { }; + /*! + Check if all faces of a polyset is within 0.1 degree of being convex. + + NB! This function can give false positives if the polyset contains + non-planar faces. To be on the safe side, consider passing a tessellated polyset. + See issue #1061. + */ bool is_approximately_convex(const PolySet &ps) { const double angle_threshold = cos(.1/180*M_PI); // .1° diff --git a/src/cgalutils.h b/src/cgalutils.h index 225e93f1..364ff80e 100644 --- a/src/cgalutils.h +++ b/src/cgalutils.h @@ -13,8 +13,9 @@ typedef std::vector PolyholeK; namespace CGALUtils { bool applyHull(const Geometry::ChildList &children, PolySet &P); - void applyOperator(const Geometry::ChildList &children, CGAL_Nef_polyhedron &dest, OpenSCADOperator op); - void applyBinaryOperator(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op); + CGAL_Nef_polyhedron *applyOperator(const Geometry::ChildList &children, OpenSCADOperator op); + //FIXME: Old, can be removed: + //void applyBinaryOperator(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op); Polygon2d *project(const CGAL_Nef_polyhedron &N, bool cut); CGAL_Iso_cuboid_3 boundingBox(const CGAL_Nef_polyhedron3 &N); bool is_approximately_convex(const PolySet &ps); diff --git a/src/export_png.cc b/src/export_png.cc index 69770547..80dda0ca 100644 --- a/src/export_png.cc +++ b/src/export_png.cc @@ -53,10 +53,7 @@ void export_png_preview_common(Tree &tree, Camera &cam, std::ostream &output, Pr { PRINTD("export_png_preview_common"); CsgInfo csgInfo = CsgInfo(); - if (!csgInfo.compile_chains(tree)) { - fprintf(stderr,"Couldn't initialize CSG chains\n"); - return; - } + csgInfo.compile_chains(tree); try { csgInfo.glview = new OffscreenView(cam.pixel_width, cam.pixel_height); diff --git a/src/func.cc b/src/func.cc index c7e26193..e6830099 100644 --- a/src/func.cc +++ b/src/func.cc @@ -36,6 +36,7 @@ #include "stl-utils.h" #include "printutils.h" #include "stackcheck.h" +#include "exceptions.h" #include #include @@ -150,9 +151,12 @@ ValuePtr FunctionTailRecursion::evaluate(const Context *ctx, const EvalContext * EvalContext ec(&c, call->call_arguments); Context tmp(&c); + unsigned int counter = 0; while (invert ^ expr->first->evaluate(&c)) { tmp.setVariables(definition_arguments, &ec); c.apply_variables(tmp); + + if (counter++ == 1000000) throw RecursionException("function", this->name); } ValuePtr result = endexpr->evaluate(&c); diff --git a/src/mainwin.cc b/src/mainwin.cc index 92d64a16..a4601f59 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -1051,9 +1051,6 @@ void MainWindow::compileCSG(bool procevents) CSGTermEvaluator csgrenderer(this->tree, &geomevaluator); if (procevents) QApplication::processEvents(); this->root_raw_term = csgrenderer.evaluateCSGTerm(*root_node, highlight_terms, background_terms); - if (!root_raw_term && background_terms.empty()) { - PRINT("ERROR: CSG generation failed! (no objects found)"); - } GeometryCache::instance()->print(); #ifdef ENABLE_CGAL CGALCache::instance()->print(); @@ -1768,8 +1765,8 @@ void MainWindow::actionRenderDone(shared_ptr root_geom) int s = this->progresswidget->elapsedTime() / 1000; PRINTB("Total rendering time: %d hours, %d minutes, %d seconds", (s / (60*60)) % ((s / 60) % 60) % (s % 60)); - if (const CGAL_Nef_polyhedron *N = dynamic_cast(root_geom.get())) { - if (!N->isEmpty()) { + if (root_geom && !root_geom->isEmpty()) { + if (const CGAL_Nef_polyhedron *N = dynamic_cast(root_geom.get())) { if (N->getDimension() == 3) { PRINT(" Top level object is a 3D object:"); PRINTB(" Simple: %6s", (N->p3->is_simple() ? "yes" : "no")); @@ -1781,16 +1778,16 @@ void MainWindow::actionRenderDone(shared_ptr root_geom) PRINTB(" Volumes: %6d", N->p3->number_of_volumes()); } } - } - else if (const PolySet *ps = dynamic_cast(root_geom.get())) { - assert(ps->getDimension() == 3); - PRINT(" Top level object is a 3D object:"); - PRINTB(" Facets: %6d", ps->numPolygons()); - } else if (const Polygon2d *poly = dynamic_cast(root_geom.get())) { - PRINT(" Top level object is a 2D object:"); - PRINTB(" Contours: %6d", poly->outlines().size()); - } else { - assert(false && "Unknown geometry type"); + else if (const PolySet *ps = dynamic_cast(root_geom.get())) { + assert(ps->getDimension() == 3); + PRINT(" Top level object is a 3D object:"); + PRINTB(" Facets: %6d", ps->numPolygons()); + } else if (const Polygon2d *poly = dynamic_cast(root_geom.get())) { + PRINT(" Top level object is a 2D object:"); + PRINTB(" Contours: %6d", poly->outlines().size()); + } else { + assert(false && "Unknown geometry type"); + } } PRINT("Rendering finished."); diff --git a/src/openscad.cc b/src/openscad.cc index 54f8a9b3..41ee8242 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -626,14 +626,20 @@ int gui(vector &inputFiles, const fs::path &original_path, int argc, cha updater->init(); #endif + QGLFormat fmt; #if 0 /*** disabled by clifford wolf: adds rendering artefacts with OpenCSG ***/ // turn on anti-aliasing - QGLFormat f; - f.setSampleBuffers(true); - f.setSamples(4); - QGLFormat::setDefaultFormat(f); + fmt.setSampleBuffers(true); + fmt.setSamples(4); #endif - + // The default SwapInterval causes very bad interactive behavior as + // waiting for the buffer swap seems to block mouse events. So the + // effect is that we can process mouse events at the frequency of + // the screen retrace interval causing them to queue up. + // (see https://bugreports.qt-project.org/browse/QTBUG-39370 + fmt.setSwapInterval(0); + QGLFormat::setDefaultFormat(fmt); + set_render_color_scheme(arg_colorscheme, false); bool noInputFiles = false; diff --git a/src/polyset-utils.cc b/src/polyset-utils.cc index 5587be6e..b3bba6d7 100644 --- a/src/polyset-utils.cc +++ b/src/polyset-utils.cc @@ -2,7 +2,9 @@ #include "polyset.h" #include "Polygon2d.h" #include "printutils.h" +#ifdef ENABLE_CGAL #include "cgalutils.h" +#endif #include @@ -45,6 +47,7 @@ namespace PolysetUtils { The tessellation will be robust wrt. degenerate and self-intersecting */ void tessellate_faces(const PolySet &inps, PolySet &outps) { +#ifdef ENABLE_CGAL int degeneratePolygons = 0; for (size_t i = 0; i < inps.polygons.size(); i++) { const Polygon pgon = inps.polygons[i]; @@ -76,5 +79,17 @@ namespace PolysetUtils { } } if (degeneratePolygons > 0) PRINT("WARNING: PolySet has degenerate polygons"); +#else + assert(false); +#endif } + + bool is_approximately_convex(const PolySet &ps) { +#ifdef ENABLE_CGAL + return CGALUtils::is_approximately_convex(ps); +#else + return false; +#endif + } + } diff --git a/src/polyset-utils.h b/src/polyset-utils.h index 2bdaca03..41364f07 100644 --- a/src/polyset-utils.h +++ b/src/polyset-utils.h @@ -7,5 +7,6 @@ namespace PolysetUtils { Polygon2d *project(const PolySet &ps); void tessellate_faces(const PolySet &inps, PolySet &outps); + bool is_approximately_convex(const PolySet &ps); }; diff --git a/src/polyset.cc b/src/polyset.cc index 0dfc2ba8..ad6b6e59 100644 --- a/src/polyset.cc +++ b/src/polyset.cc @@ -25,6 +25,7 @@ */ #include "polyset.h" +#include "polyset-utils.h" #include "linalg.h" #include "printutils.h" #include @@ -140,20 +141,10 @@ void PolySet::transform(const Transform3d &mat) } } -namespace CGALUtils { - extern bool is_approximately_convex(const PolySet &ps); -} - bool PolySet::is_convex() const { - if (convex) return true; + if (convex || this->isEmpty()) return true; if (!convex) return false; - -#ifdef ENABLE_CGAL - convex = CGALUtils::is_approximately_convex(*this); - return convex; -#else - return false; -#endif + return PolysetUtils::is_approximately_convex(*this); } void PolySet::resize(Vector3d newsize, const Eigen::Matrix &autosize) diff --git a/src/printutils.cc b/src/printutils.cc index 5004c745..4e400ccb 100644 --- a/src/printutils.cc +++ b/src/printutils.cc @@ -2,12 +2,16 @@ #include #include #include +#include +#include std::list print_messages_stack; OutputHandlerFunc *outputhandler = NULL; void *outputhandler_data = NULL; std::string OpenSCAD::debug(""); +boost::circular_buffer lastmessages(5); + void set_output_handler(OutputHandlerFunc *newhandler, void *userdata) { outputhandler = newhandler; @@ -46,6 +50,16 @@ void PRINT(const std::string &msg) void PRINT_NOCACHE(const std::string &msg) { if (msg.empty()) return; + + if (boost::starts_with(msg, "WARNING") || boost::starts_with(msg, "ERROR")) { + int i; + for (i=0;i=(const ValuePtr &v) const; bool operator>(const ValuePtr &v) const; ValuePtr operator-() const; + ValuePtr operator!() const; ValuePtr operator[](const ValuePtr &v) const; ValuePtr operator+(const ValuePtr &v) const; ValuePtr operator-(const ValuePtr &v) const; diff --git a/testdata/scad/2D/features/scale2D-tests.scad b/testdata/scad/2D/features/scale2D-tests.scad index 87b22784..385809c7 100644 --- a/testdata/scad/2D/features/scale2D-tests.scad +++ b/testdata/scad/2D/features/scale2D-tests.scad @@ -6,5 +6,5 @@ translate([5,0,0]) scale([2,4/3]) obj2D(); translate([10,0,0]) scale(2) obj2D(); // Scale by zero; 2D object -linear_extrude() scale([0,0]) obj2D(); -linear_extrude() scale([0,1]) obj2D(); +translate([-5,0,0]) linear_extrude() scale([0,0]) obj2D(); +translate([-5,0,0]) linear_extrude() scale([0,1]) obj2D(); diff --git a/testdata/scad/3D/features/nullspace-difference.scad b/testdata/scad/3D/features/nullspace-difference.scad new file mode 100644 index 00000000..7db36eae --- /dev/null +++ b/testdata/scad/3D/features/nullspace-difference.scad @@ -0,0 +1,4 @@ +difference() { + cube(1, center=true); + cube(2, center=true); +} diff --git a/testdata/scad/3D/features/nullspace-intersection.scad b/testdata/scad/3D/features/nullspace-intersection.scad new file mode 100644 index 00000000..b58b3e0e --- /dev/null +++ b/testdata/scad/3D/features/nullspace-intersection.scad @@ -0,0 +1,4 @@ +intersection() { + translate([-2,0,0]) cube(1); + translate([2,0,0]) cube(1); +} diff --git a/testdata/scad/3D/features/nullspace-minkowski-intersection.scad b/testdata/scad/3D/features/nullspace-minkowski-intersection.scad new file mode 100644 index 00000000..617eae82 --- /dev/null +++ b/testdata/scad/3D/features/nullspace-minkowski-intersection.scad @@ -0,0 +1,10 @@ +intersection() { + minkowski() { + intersection() { + translate([-2,0,0]) cube(1); + translate([2,0,0]) cube(1); + } + cube(); + } + cube(); +} diff --git a/testdata/scad/3D/features/nullspace-minkowski.scad b/testdata/scad/3D/features/nullspace-minkowski.scad new file mode 100644 index 00000000..c1cb6b50 --- /dev/null +++ b/testdata/scad/3D/features/nullspace-minkowski.scad @@ -0,0 +1,7 @@ +minkowski() { + intersection() { + translate([-2,0,0]) cube(1); + translate([2,0,0]) cube(1); + } + cube(); +} diff --git a/testdata/scad/3D/features/scale-mirror2D-3D-tests.scad b/testdata/scad/3D/features/scale-mirror2D-3D-tests.scad new file mode 100644 index 00000000..bca2450f --- /dev/null +++ b/testdata/scad/3D/features/scale-mirror2D-3D-tests.scad @@ -0,0 +1,7 @@ +module obj2D() polygon([[-0.5,-0.5], [1,-0.5], [1,1], [-0.5, 0.5]]) +square([2,3], center=true); + +linear_extrude(1) scale([1, -1]) obj2D(); +translate([3,0,0]) linear_extrude(1) scale([-1, -0.5]) obj2D(); +translate([0,3,0]) linear_extrude(1) mirror() obj2D(); +translate([2,3,0]) linear_extrude(1) mirror([0,1]) obj2D(); diff --git a/testdata/scad/3D/features/transform-tests.scad b/testdata/scad/3D/features/transform-tests.scad index e2dd71e1..0c922c78 100644 --- a/testdata/scad/3D/features/transform-tests.scad +++ b/testdata/scad/3D/features/transform-tests.scad @@ -15,5 +15,3 @@ multmatrix([[1,0.4,0.1,-25], [0.4,0.8,0,-25], [0.2,0.2,0.5,0], [0,0,0,1]]) mycyl(); - -//FIXME: mirror() and scale() \ No newline at end of file diff --git a/testdata/scad/bugs/issue1061.scad b/testdata/scad/bugs/issue1061.scad new file mode 100644 index 00000000..70cc35cc --- /dev/null +++ b/testdata/scad/bugs/issue1061.scad @@ -0,0 +1 @@ +polyhedron(points = [[-5, -5, 0], [-5, 5, 0], [5, 5, 0], [5, -5, 0], [-1.87866, -4.21311, 3], [-4.21311, 5.51058, 3], [5.51058, 7.84504, 3], [7.84504, -1.87866, 3], [1.05099, -3.48892, 6], [-3.48892, 5.42115, 6], [5.42115, 9.96105, 6], [9.96105, 1.05099, 6], [3.39596, -3.09852, 9], [-3.09852, 4.50554, 9], [4.50554, 11, 9], [11, 3.39596, 9], [4.91038, -3.17979, 12], [-3.17979, 2.69807, 12], [2.69807, 10.7882, 12], [10.7882, 4.91038, 12], [5.53441, -3.70439, 15], [-3.70439, 0.122447, 15], [0.122447, 9.36124, 15], [9.36124, 5.53441, 15], [5.39234, -4.48455, 18], [-4.48455, -2.9202, 18], [-2.9202, 6.95668, 18], [6.95668, 5.39234, 18]], faces = [[0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7], [4, 5, 9, 8], [5, 6, 10, 9], [6, 7, 11, 10], [7, 4, 8, 11], [8, 9, 13, 12], [9, 10, 14, 13], [10, 11, 15, 14], [11, 8, 12, 15], [12, 13, 17, 16], [13, 14, 18, 17], [14, 15, 19, 18], [15, 12, 16, 19], [16, 17, 21, 20], [17, 18, 22, 21], [18, 19, 23, 22], [19, 16, 20, 23], [20, 21, 25, 24], [21, 22, 26, 25], [22, 23, 27, 26], [23, 20, 24, 27], [3, 2, 1, 0], [24, 25, 26, 27]]); diff --git a/testdata/scad/misc/expression-evaluation-tests.scad b/testdata/scad/misc/expression-evaluation-tests.scad new file mode 100644 index 00000000..0dd5ff37 --- /dev/null +++ b/testdata/scad/misc/expression-evaluation-tests.scad @@ -0,0 +1,41 @@ +values = [ + undef, // special undefined value + 1/0, // infinity + -1/0, // -infinity + 0/0, // not a number + 0, -4.2, -2, 3, 42.42, 242, // number + true, false, // boolean + "", "text", // string + [], [ 0 ], [ 1 ], // vector + [ 0 : 0 ], [ 1 : 2 ] // range +]; + +array = [ "a", "b", "c", "d" ]; + +for (v = values) { + echo(v = v, op = "not v", result = !v); + echo(v = v, op = "-v", result = -v); + echo(v = v, op = "v *", result = v * 3); + echo(v = v, op = "* v", result = 2 * v); + echo(v = v, op = "v /", result = v / 3); + echo(v = v, op = "/ v", result = 2 / v); + echo(v = v, op = "v %", result = v % 3); + echo(v = v, op = "% v", result = 2 % v); + echo(v = v, op = "v +", result = v + 3); + echo(v = v, op = "+ v", result = 2 + v); + echo(v = v, op = "v -", result = v - 3); + echo(v = v, op = "- v", result = 2 - v); + echo(v = v, op = "v and true", result = v && true); + echo(v = v, op = "v and false", result = v && false); + echo(v = v, op = "v or true", result = v || true); + echo(v = v, op = "v or false", result = v || false); +// echo(v = v, op = "<", result = v < 3); +// echo(v = v, op = "<=", result = v <= 3); +// echo(v = v, op = "==", result = v == 3); +// echo(v = v, op = "!=", result = v != 3); +// echo(v = v, op = ">=", result = v >= 3); +// echo(v = v, op = ">", result = v > 3); + echo(v = v, op = "[v]", result = array[v]); + echo(v = v, op = "v[0]", result = v[0]); + echo(v = v, op = "v[4]", result = v[4]); +} diff --git a/testdata/scad/misc/nonmanifold-polyhedron.scad b/testdata/scad/misc/nonmanifold-polyhedron.scad new file mode 100644 index 00000000..a1b56654 --- /dev/null +++ b/testdata/scad/misc/nonmanifold-polyhedron.scad @@ -0,0 +1,16 @@ +polyhedron(points=[ +[0,0,0], +[10,0,0], +[10,10,0], +[0,10,0], +[0,-20,20], +[10,-20,20], +[10,-20,30], +[0,-20,30] +], +faces = [[0,1,2,3],[4,5,6,7], +[1,2,5,4], +[2,3,6,5], +[3,0,6,5], +[0,1,4,7] +]); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index be237330..9c9f84c1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -632,7 +632,6 @@ set(CORE_SOURCES ../src/csgtermnormalizer.cc ../src/Geometry.cc ../src/Polygon2d.cc - ../src/polyset.cc ../src/csgops.cc ../src/transform.cc ../src/color.cc @@ -666,7 +665,10 @@ set(NOCGAL_SOURCES ../src/builtin.cc ../src/import.cc ../src/export.cc - ../src/LibraryInfo.cc) + ../src/LibraryInfo.cc + ../src/polyset.cc + ../src/polyset-utils.cc) + set(CGAL_SOURCES ${NOCGAL_SOURCES} @@ -678,7 +680,6 @@ set(CGAL_SOURCES ../src/CGALCache.cc ../src/CGAL_Nef_polyhedron_DxfData.cc ../src/Polygon2d-CGAL.cc - ../src/polyset-utils.cc ../src/svg.cc ../src/GeometryEvaluator.cc) @@ -749,20 +750,20 @@ set_target_properties(tests-offscreen PROPERTIES COMPILE_FLAGS "${ENABLE_OPENCSG # modulecachetest # add_executable(modulecachetest modulecachetest.cc) -target_link_libraries(modulecachetest tests-nocgal) +target_link_libraries(modulecachetest tests-nocgal ${GLEW_LIBRARY} ${OPENCSG_LIBRARY} ${APP_SERVICES_LIBRARY}) # # csgtexttest # add_executable(csgtexttest csgtexttest.cc CSGTextRenderer.cc CSGTextCache.cc) -target_link_libraries(csgtexttest tests-nocgal) +target_link_libraries(csgtexttest tests-nocgal ${GLEW_LIBRARY} ${OPENCSG_LIBRARY} ${APP_SERVICES_LIBRARY}) # # cgalcachetest # add_executable(cgalcachetest cgalcachetest.cc) set_target_properties(cgalcachetest PROPERTIES COMPILE_FLAGS "-DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}") -target_link_libraries(cgalcachetest tests-cgal) +target_link_libraries(cgalcachetest tests-cgal ${GLEW_LIBRARY} ${OPENCSG_LIBRARY} ${APP_SERVICES_LIBRARY}) # # openscad no-qt @@ -1025,6 +1026,7 @@ list(APPEND EXAMPLE_FILES ${EXAMPLE_3D_FILES} ${EXAMPLE_2D_FILES}) list(APPEND ECHO_FILES ${FUNCTION_FILES} ${CMAKE_SOURCE_DIR}/../testdata/scad/3D/features/for-tests.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/expression-evaluation-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/echo-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/parser-tests.scad @@ -1114,6 +1116,9 @@ list(APPEND EXPORT3D_TEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/3D/features ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/bad-stl-wing.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/rotate_extrude-hole.scad) +list(APPEND EXPORTCSG_TEST_FILES + ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/nonmanifold-polyhedron.scad) + disable_tests( # These don't output anything dxfpngtest_text-empty-tests @@ -1123,6 +1128,7 @@ disable_tests( # Not useful throwntogethertest_internal-cavity throwntogethertest_internal-cavity-polyhedron + throwntogethertest_nullspace-difference # these take too long, for little relative gain in testing stlpngtest_iteration @@ -1211,9 +1217,16 @@ list(APPEND BUGS_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue584.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue964b.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue990.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue1004.scad - ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue1005.scad) + ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue1005.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue1061.scad) list(APPEND EXPORT3D_TEST_FILES ${BUGS_FILES}) -list(REMOVE_ITEM EXPORT3D_TEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue899.scad) +list(REMOVE_ITEM EXPORT3D_TEST_FILES + ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue899.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue964.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue964b.scad) +list(APPEND EXPORTCSG_TEST_FILES + ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue964.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue964b.scad) list(APPEND ALL_2D_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/issue899.scad) list(APPEND OPENCSGTEST_FILES ${BUGS_FILES}) @@ -1231,6 +1244,8 @@ foreach(FILE ${BUGS_FILES}) set_test_config(Bugs ${TEST_FULLNAME}) get_test_fullname(stlpngtest ${FILE} TEST_FULLNAME) set_test_config(Bugs ${TEST_FULLNAME}) + get_test_fullname(stlcsgpngtest ${FILE} TEST_FULLNAME) + set_test_config(Bugs ${TEST_FULLNAME}) endforeach() # Examples @@ -1309,6 +1324,7 @@ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake ${TMP}) # o stlpngtest: Export to STL, Re-import and render to PNG (--render=cgal) # o offpngtest: Export to OFF, Re-import and render to PNG (--render=cgal) # o dxfpngtest: Export to DXF, Re-import and render to PNG (--render=cgal) +# o stlcsgpngtest: Export to STL, Re-import and render to PNG (--render) # add_cmdline_test(moduledumptest EXE ${OPENSCAD_BINPATH} ARGS -o SUFFIX ast FILES @@ -1352,6 +1368,7 @@ add_cmdline_test(monotonepngtest EXE ${OPENSCAD_BINPATH} ARGS --colorscheme=Mono add_cmdline_test(stlpngtest EXE ${PYTHON_EXECUTABLE} SCRIPT ${CMAKE_SOURCE_DIR}/export_import_pngtest.py ARGS --openscad=${OPENSCAD_BINPATH} --format=STL --render=cgal EXPECTEDDIR monotonepngtest SUFFIX png FILES ${EXPORT3D_TEST_FILES}) add_cmdline_test(offpngtest EXE ${PYTHON_EXECUTABLE} SCRIPT ${CMAKE_SOURCE_DIR}/export_import_pngtest.py ARGS --openscad=${OPENSCAD_BINPATH} --format=OFF --render=cgal EXPECTEDDIR monotonepngtest SUFFIX png FILES ${EXPORT3D_TEST_FILES}) add_cmdline_test(dxfpngtest EXE ${PYTHON_EXECUTABLE} SCRIPT ${CMAKE_SOURCE_DIR}/export_import_pngtest.py ARGS --openscad=${OPENSCAD_BINPATH} --format=DXF --render=cgal EXPECTEDDIR cgalpngtest SUFFIX png FILES ${FILES_2D}) +add_cmdline_test(stlcsgpngtest EXE ${PYTHON_EXECUTABLE} SCRIPT ${CMAKE_SOURCE_DIR}/export_import_pngtest.py ARGS --openscad=${OPENSCAD_BINPATH} --format=STL --render EXPECTEDDIR monotonepngtest SUFFIX png FILES ${EXPORTCSG_TEST_FILES}) # diff --git a/tests/regression/cgalpngtest/issue1061-expected.png b/tests/regression/cgalpngtest/issue1061-expected.png new file mode 100644 index 00000000..78bd8525 Binary files /dev/null and b/tests/regression/cgalpngtest/issue1061-expected.png differ diff --git a/tests/regression/cgalpngtest/nullspace-difference-expected.png b/tests/regression/cgalpngtest/nullspace-difference-expected.png new file mode 100644 index 00000000..08ee92b2 Binary files /dev/null and b/tests/regression/cgalpngtest/nullspace-difference-expected.png differ diff --git a/tests/regression/cgalpngtest/nullspace-intersection-expected.png b/tests/regression/cgalpngtest/nullspace-intersection-expected.png new file mode 100644 index 00000000..08ee92b2 Binary files /dev/null and b/tests/regression/cgalpngtest/nullspace-intersection-expected.png differ diff --git a/tests/regression/cgalpngtest/nullspace-minkowski-expected.png b/tests/regression/cgalpngtest/nullspace-minkowski-expected.png new file mode 100644 index 00000000..08ee92b2 Binary files /dev/null and b/tests/regression/cgalpngtest/nullspace-minkowski-expected.png differ diff --git a/tests/regression/cgalpngtest/nullspace-minkowski-intersection-expected.png b/tests/regression/cgalpngtest/nullspace-minkowski-intersection-expected.png new file mode 100644 index 00000000..08ee92b2 Binary files /dev/null and b/tests/regression/cgalpngtest/nullspace-minkowski-intersection-expected.png differ diff --git a/tests/regression/cgalpngtest/scale-mirror2D-3D-tests-expected.png b/tests/regression/cgalpngtest/scale-mirror2D-3D-tests-expected.png new file mode 100644 index 00000000..5d85630a Binary files /dev/null and b/tests/regression/cgalpngtest/scale-mirror2D-3D-tests-expected.png differ diff --git a/tests/regression/dumptest/nullspace-difference-expected.csg b/tests/regression/dumptest/nullspace-difference-expected.csg new file mode 100644 index 00000000..a8d054c6 --- /dev/null +++ b/tests/regression/dumptest/nullspace-difference-expected.csg @@ -0,0 +1,6 @@ +group() { + difference() { + cube(size = [1, 1, 1], center = true); + cube(size = [2, 2, 2], center = true); + } +} diff --git a/tests/regression/dumptest/nullspace-intersection-expected.csg b/tests/regression/dumptest/nullspace-intersection-expected.csg new file mode 100644 index 00000000..f4e4f89e --- /dev/null +++ b/tests/regression/dumptest/nullspace-intersection-expected.csg @@ -0,0 +1,10 @@ +group() { + intersection() { + multmatrix([[1, 0, 0, -2], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cube(size = [1, 1, 1], center = false); + } + multmatrix([[1, 0, 0, 2], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cube(size = [1, 1, 1], center = false); + } + } +} diff --git a/tests/regression/dumptest/nullspace-minkowski-expected.csg b/tests/regression/dumptest/nullspace-minkowski-expected.csg new file mode 100644 index 00000000..e387596e --- /dev/null +++ b/tests/regression/dumptest/nullspace-minkowski-expected.csg @@ -0,0 +1,13 @@ +group() { + minkowski(convexity = 0) { + intersection() { + multmatrix([[1, 0, 0, -2], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cube(size = [1, 1, 1], center = false); + } + multmatrix([[1, 0, 0, 2], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cube(size = [1, 1, 1], center = false); + } + } + cube(size = [1, 1, 1], center = false); + } +} diff --git a/tests/regression/dumptest/nullspace-minkowski-intersection-expected.csg b/tests/regression/dumptest/nullspace-minkowski-intersection-expected.csg new file mode 100644 index 00000000..0620307c --- /dev/null +++ b/tests/regression/dumptest/nullspace-minkowski-intersection-expected.csg @@ -0,0 +1,16 @@ +group() { + intersection() { + minkowski(convexity = 0) { + intersection() { + multmatrix([[1, 0, 0, -2], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cube(size = [1, 1, 1], center = false); + } + multmatrix([[1, 0, 0, 2], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cube(size = [1, 1, 1], center = false); + } + } + cube(size = [1, 1, 1], center = false); + } + cube(size = [1, 1, 1], center = false); + } +} diff --git a/tests/regression/dumptest/scale-mirror2D-3D-tests-expected.csg b/tests/regression/dumptest/scale-mirror2D-3D-tests-expected.csg new file mode 100644 index 00000000..2293a339 --- /dev/null +++ b/tests/regression/dumptest/scale-mirror2D-3D-tests-expected.csg @@ -0,0 +1,36 @@ +group() { + linear_extrude(height = 1, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) { + multmatrix([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + polygon(points = [[-0.5, -0.5], [1, -0.5], [1, 1], [-0.5, 0.5]], paths = undef, convexity = 1); + } + } + } + multmatrix([[1, 0, 0, 3], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + linear_extrude(height = 1, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) { + multmatrix([[-1, 0, 0, 0], [0, -0.5, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + polygon(points = [[-0.5, -0.5], [1, -0.5], [1, 1], [-0.5, 0.5]], paths = undef, convexity = 1); + } + } + } + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 3], [0, 0, 1, 0], [0, 0, 0, 1]]) { + linear_extrude(height = 1, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) { + multmatrix([[-1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + polygon(points = [[-0.5, -0.5], [1, -0.5], [1, 1], [-0.5, 0.5]], paths = undef, convexity = 1); + } + } + } + } + multmatrix([[1, 0, 0, 2], [0, 1, 0, 3], [0, 0, 1, 0], [0, 0, 0, 1]]) { + linear_extrude(height = 1, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) { + multmatrix([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + polygon(points = [[-0.5, -0.5], [1, -0.5], [1, 1], [-0.5, 0.5]], paths = undef, convexity = 1); + } + } + } + } +} diff --git a/tests/regression/dumptest/scale2D-tests-expected.csg b/tests/regression/dumptest/scale2D-tests-expected.csg index b20a9757..5d0b7866 100644 --- a/tests/regression/dumptest/scale2D-tests-expected.csg +++ b/tests/regression/dumptest/scale2D-tests-expected.csg @@ -18,17 +18,21 @@ group() { } } } - linear_extrude(height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) { - multmatrix([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { - group() { - square(size = [2, 3], center = true); + multmatrix([[1, 0, 0, -5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + linear_extrude(height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) { + multmatrix([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + square(size = [2, 3], center = true); + } } } } - linear_extrude(height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) { - multmatrix([[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { - group() { - square(size = [2, 3], center = true); + multmatrix([[1, 0, 0, -5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + linear_extrude(height = 100, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) { + multmatrix([[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + square(size = [2, 3], center = true); + } } } } diff --git a/tests/regression/echotest/dim-all-expected.echo b/tests/regression/echotest/dim-all-expected.echo index a16c5801..adba64d1 100644 --- a/tests/regression/echotest/dim-all-expected.echo +++ b/tests/regression/echotest/dim-all-expected.echo @@ -8,9 +8,6 @@ WARNING: Unsupported DXF Entity 'LEADER' (1) in "dim-all.dxf". ECHO: ordinateX = -49.17542445724 WARNING: Unsupported DXF Entity 'LEADER' (1) in "dim-all.dxf". ECHO: ordinateY = 30.86974532565 -WARNING: Unsupported DXF Entity 'LEADER' (1) in "dim-all.dxf". ECHO: radius = 60 -WARNING: Unsupported DXF Entity 'LEADER' (1) in "dim-all.dxf". ECHO: diameter = 120 -WARNING: Unsupported DXF Entity 'LEADER' (1) in "dim-all.dxf". ECHO: arc = 59.03624346792 diff --git a/tests/regression/echotest/expression-evaluation-tests-expected.echo b/tests/regression/echotest/expression-evaluation-tests-expected.echo new file mode 100644 index 00000000..49f91f0d --- /dev/null +++ b/tests/regression/echotest/expression-evaluation-tests-expected.echo @@ -0,0 +1,361 @@ +ECHO: v = undef, op = "not v", result = true +ECHO: v = undef, op = "-v", result = undef +ECHO: v = undef, op = "v *", result = undef +ECHO: v = undef, op = "* v", result = undef +ECHO: v = undef, op = "v /", result = undef +ECHO: v = undef, op = "/ v", result = undef +ECHO: v = undef, op = "v %", result = undef +ECHO: v = undef, op = "% v", result = undef +ECHO: v = undef, op = "v +", result = undef +ECHO: v = undef, op = "+ v", result = undef +ECHO: v = undef, op = "v -", result = undef +ECHO: v = undef, op = "- v", result = undef +ECHO: v = undef, op = "v and true", result = false +ECHO: v = undef, op = "v and false", result = false +ECHO: v = undef, op = "v or true", result = true +ECHO: v = undef, op = "v or false", result = false +ECHO: v = undef, op = "[v]", result = undef +ECHO: v = undef, op = "v[0]", result = undef +ECHO: v = undef, op = "v[4]", result = undef +ECHO: v = inf, op = "not v", result = false +ECHO: v = inf, op = "-v", result = -inf +ECHO: v = inf, op = "v *", result = inf +ECHO: v = inf, op = "* v", result = inf +ECHO: v = inf, op = "v /", result = inf +ECHO: v = inf, op = "/ v", result = 0 +ECHO: v = inf, op = "v %", result = nan +ECHO: v = inf, op = "% v", result = 2 +ECHO: v = inf, op = "v +", result = inf +ECHO: v = inf, op = "+ v", result = inf +ECHO: v = inf, op = "v -", result = inf +ECHO: v = inf, op = "- v", result = -inf +ECHO: v = inf, op = "v and true", result = true +ECHO: v = inf, op = "v and false", result = false +ECHO: v = inf, op = "v or true", result = true +ECHO: v = inf, op = "v or false", result = true +ECHO: v = inf, op = "[v]", result = undef +ECHO: v = inf, op = "v[0]", result = undef +ECHO: v = inf, op = "v[4]", result = undef +ECHO: v = -inf, op = "not v", result = false +ECHO: v = -inf, op = "-v", result = inf +ECHO: v = -inf, op = "v *", result = -inf +ECHO: v = -inf, op = "* v", result = -inf +ECHO: v = -inf, op = "v /", result = -inf +ECHO: v = -inf, op = "/ v", result = 0 +ECHO: v = -inf, op = "v %", result = nan +ECHO: v = -inf, op = "% v", result = 2 +ECHO: v = -inf, op = "v +", result = -inf +ECHO: v = -inf, op = "+ v", result = -inf +ECHO: v = -inf, op = "v -", result = -inf +ECHO: v = -inf, op = "- v", result = inf +ECHO: v = -inf, op = "v and true", result = true +ECHO: v = -inf, op = "v and false", result = false +ECHO: v = -inf, op = "v or true", result = true +ECHO: v = -inf, op = "v or false", result = true +ECHO: v = -inf, op = "[v]", result = undef +ECHO: v = -inf, op = "v[0]", result = undef +ECHO: v = -inf, op = "v[4]", result = undef +ECHO: v = nan, op = "not v", result = false +ECHO: v = nan, op = "-v", result = nan +ECHO: v = nan, op = "v *", result = nan +ECHO: v = nan, op = "* v", result = nan +ECHO: v = nan, op = "v /", result = nan +ECHO: v = nan, op = "/ v", result = nan +ECHO: v = nan, op = "v %", result = nan +ECHO: v = nan, op = "% v", result = nan +ECHO: v = nan, op = "v +", result = nan +ECHO: v = nan, op = "+ v", result = nan +ECHO: v = nan, op = "v -", result = nan +ECHO: v = nan, op = "- v", result = nan +ECHO: v = nan, op = "v and true", result = true +ECHO: v = nan, op = "v and false", result = false +ECHO: v = nan, op = "v or true", result = true +ECHO: v = nan, op = "v or false", result = true +ECHO: v = nan, op = "[v]", result = undef +ECHO: v = nan, op = "v[0]", result = undef +ECHO: v = nan, op = "v[4]", result = undef +ECHO: v = 0, op = "not v", result = true +ECHO: v = 0, op = "-v", result = 0 +ECHO: v = 0, op = "v *", result = 0 +ECHO: v = 0, op = "* v", result = 0 +ECHO: v = 0, op = "v /", result = 0 +ECHO: v = 0, op = "/ v", result = inf +ECHO: v = 0, op = "v %", result = 0 +ECHO: v = 0, op = "% v", result = nan +ECHO: v = 0, op = "v +", result = 3 +ECHO: v = 0, op = "+ v", result = 2 +ECHO: v = 0, op = "v -", result = -3 +ECHO: v = 0, op = "- v", result = 2 +ECHO: v = 0, op = "v and true", result = false +ECHO: v = 0, op = "v and false", result = false +ECHO: v = 0, op = "v or true", result = true +ECHO: v = 0, op = "v or false", result = false +ECHO: v = 0, op = "[v]", result = "a" +ECHO: v = 0, op = "v[0]", result = undef +ECHO: v = 0, op = "v[4]", result = undef +ECHO: v = -4.2, op = "not v", result = false +ECHO: v = -4.2, op = "-v", result = 4.2 +ECHO: v = -4.2, op = "v *", result = -12.6 +ECHO: v = -4.2, op = "* v", result = -8.4 +ECHO: v = -4.2, op = "v /", result = -1.4 +ECHO: v = -4.2, op = "/ v", result = -0.47619047619 +ECHO: v = -4.2, op = "v %", result = -1.2 +ECHO: v = -4.2, op = "% v", result = 2 +ECHO: v = -4.2, op = "v +", result = -1.2 +ECHO: v = -4.2, op = "+ v", result = -2.2 +ECHO: v = -4.2, op = "v -", result = -7.2 +ECHO: v = -4.2, op = "- v", result = 6.2 +ECHO: v = -4.2, op = "v and true", result = true +ECHO: v = -4.2, op = "v and false", result = false +ECHO: v = -4.2, op = "v or true", result = true +ECHO: v = -4.2, op = "v or false", result = true +ECHO: v = -4.2, op = "[v]", result = undef +ECHO: v = -4.2, op = "v[0]", result = undef +ECHO: v = -4.2, op = "v[4]", result = undef +ECHO: v = -2, op = "not v", result = false +ECHO: v = -2, op = "-v", result = 2 +ECHO: v = -2, op = "v *", result = -6 +ECHO: v = -2, op = "* v", result = -4 +ECHO: v = -2, op = "v /", result = -0.66666666666 +ECHO: v = -2, op = "/ v", result = -1 +ECHO: v = -2, op = "v %", result = -2 +ECHO: v = -2, op = "% v", result = 0 +ECHO: v = -2, op = "v +", result = 1 +ECHO: v = -2, op = "+ v", result = 0 +ECHO: v = -2, op = "v -", result = -5 +ECHO: v = -2, op = "- v", result = 4 +ECHO: v = -2, op = "v and true", result = true +ECHO: v = -2, op = "v and false", result = false +ECHO: v = -2, op = "v or true", result = true +ECHO: v = -2, op = "v or false", result = true +ECHO: v = -2, op = "[v]", result = undef +ECHO: v = -2, op = "v[0]", result = undef +ECHO: v = -2, op = "v[4]", result = undef +ECHO: v = 3, op = "not v", result = false +ECHO: v = 3, op = "-v", result = -3 +ECHO: v = 3, op = "v *", result = 9 +ECHO: v = 3, op = "* v", result = 6 +ECHO: v = 3, op = "v /", result = 1 +ECHO: v = 3, op = "/ v", result = 0.66666666666 +ECHO: v = 3, op = "v %", result = 0 +ECHO: v = 3, op = "% v", result = 2 +ECHO: v = 3, op = "v +", result = 6 +ECHO: v = 3, op = "+ v", result = 5 +ECHO: v = 3, op = "v -", result = 0 +ECHO: v = 3, op = "- v", result = -1 +ECHO: v = 3, op = "v and true", result = true +ECHO: v = 3, op = "v and false", result = false +ECHO: v = 3, op = "v or true", result = true +ECHO: v = 3, op = "v or false", result = true +ECHO: v = 3, op = "[v]", result = "d" +ECHO: v = 3, op = "v[0]", result = undef +ECHO: v = 3, op = "v[4]", result = undef +ECHO: v = 42.42, op = "not v", result = false +ECHO: v = 42.42, op = "-v", result = -42.42 +ECHO: v = 42.42, op = "v *", result = 127.26 +ECHO: v = 42.42, op = "* v", result = 84.84 +ECHO: v = 42.42, op = "v /", result = 14.14 +ECHO: v = 42.42, op = "/ v", result = 0.0471475719 +ECHO: v = 42.42, op = "v %", result = 0.42 +ECHO: v = 42.42, op = "% v", result = 2 +ECHO: v = 42.42, op = "v +", result = 45.42 +ECHO: v = 42.42, op = "+ v", result = 44.42 +ECHO: v = 42.42, op = "v -", result = 39.42 +ECHO: v = 42.42, op = "- v", result = -40.42 +ECHO: v = 42.42, op = "v and true", result = true +ECHO: v = 42.42, op = "v and false", result = false +ECHO: v = 42.42, op = "v or true", result = true +ECHO: v = 42.42, op = "v or false", result = true +ECHO: v = 42.42, op = "[v]", result = undef +ECHO: v = 42.42, op = "v[0]", result = undef +ECHO: v = 42.42, op = "v[4]", result = undef +ECHO: v = 242, op = "not v", result = false +ECHO: v = 242, op = "-v", result = -242 +ECHO: v = 242, op = "v *", result = 726 +ECHO: v = 242, op = "* v", result = 484 +ECHO: v = 242, op = "v /", result = 80.66666666666 +ECHO: v = 242, op = "/ v", result = 0.00826446281 +ECHO: v = 242, op = "v %", result = 2 +ECHO: v = 242, op = "% v", result = 2 +ECHO: v = 242, op = "v +", result = 245 +ECHO: v = 242, op = "+ v", result = 244 +ECHO: v = 242, op = "v -", result = 239 +ECHO: v = 242, op = "- v", result = -240 +ECHO: v = 242, op = "v and true", result = true +ECHO: v = 242, op = "v and false", result = false +ECHO: v = 242, op = "v or true", result = true +ECHO: v = 242, op = "v or false", result = true +ECHO: v = 242, op = "[v]", result = undef +ECHO: v = 242, op = "v[0]", result = undef +ECHO: v = 242, op = "v[4]", result = undef +ECHO: v = true, op = "not v", result = false +ECHO: v = true, op = "-v", result = undef +ECHO: v = true, op = "v *", result = undef +ECHO: v = true, op = "* v", result = undef +ECHO: v = true, op = "v /", result = undef +ECHO: v = true, op = "/ v", result = undef +ECHO: v = true, op = "v %", result = undef +ECHO: v = true, op = "% v", result = undef +ECHO: v = true, op = "v +", result = undef +ECHO: v = true, op = "+ v", result = undef +ECHO: v = true, op = "v -", result = undef +ECHO: v = true, op = "- v", result = undef +ECHO: v = true, op = "v and true", result = true +ECHO: v = true, op = "v and false", result = false +ECHO: v = true, op = "v or true", result = true +ECHO: v = true, op = "v or false", result = true +ECHO: v = true, op = "[v]", result = undef +ECHO: v = true, op = "v[0]", result = undef +ECHO: v = true, op = "v[4]", result = undef +ECHO: v = false, op = "not v", result = true +ECHO: v = false, op = "-v", result = undef +ECHO: v = false, op = "v *", result = undef +ECHO: v = false, op = "* v", result = undef +ECHO: v = false, op = "v /", result = undef +ECHO: v = false, op = "/ v", result = undef +ECHO: v = false, op = "v %", result = undef +ECHO: v = false, op = "% v", result = undef +ECHO: v = false, op = "v +", result = undef +ECHO: v = false, op = "+ v", result = undef +ECHO: v = false, op = "v -", result = undef +ECHO: v = false, op = "- v", result = undef +ECHO: v = false, op = "v and true", result = false +ECHO: v = false, op = "v and false", result = false +ECHO: v = false, op = "v or true", result = true +ECHO: v = false, op = "v or false", result = false +ECHO: v = false, op = "[v]", result = undef +ECHO: v = false, op = "v[0]", result = undef +ECHO: v = false, op = "v[4]", result = undef +ECHO: v = "", op = "not v", result = true +ECHO: v = "", op = "-v", result = undef +ECHO: v = "", op = "v *", result = undef +ECHO: v = "", op = "* v", result = undef +ECHO: v = "", op = "v /", result = undef +ECHO: v = "", op = "/ v", result = undef +ECHO: v = "", op = "v %", result = undef +ECHO: v = "", op = "% v", result = undef +ECHO: v = "", op = "v +", result = undef +ECHO: v = "", op = "+ v", result = undef +ECHO: v = "", op = "v -", result = undef +ECHO: v = "", op = "- v", result = undef +ECHO: v = "", op = "v and true", result = false +ECHO: v = "", op = "v and false", result = false +ECHO: v = "", op = "v or true", result = true +ECHO: v = "", op = "v or false", result = false +ECHO: v = "", op = "[v]", result = undef +ECHO: v = "", op = "v[0]", result = undef +ECHO: v = "", op = "v[4]", result = undef +ECHO: v = "text", op = "not v", result = false +ECHO: v = "text", op = "-v", result = undef +ECHO: v = "text", op = "v *", result = undef +ECHO: v = "text", op = "* v", result = undef +ECHO: v = "text", op = "v /", result = undef +ECHO: v = "text", op = "/ v", result = undef +ECHO: v = "text", op = "v %", result = undef +ECHO: v = "text", op = "% v", result = undef +ECHO: v = "text", op = "v +", result = undef +ECHO: v = "text", op = "+ v", result = undef +ECHO: v = "text", op = "v -", result = undef +ECHO: v = "text", op = "- v", result = undef +ECHO: v = "text", op = "v and true", result = true +ECHO: v = "text", op = "v and false", result = false +ECHO: v = "text", op = "v or true", result = true +ECHO: v = "text", op = "v or false", result = true +ECHO: v = "text", op = "[v]", result = undef +ECHO: v = "text", op = "v[0]", result = "t" +ECHO: v = "text", op = "v[4]", result = undef +ECHO: v = [], op = "not v", result = true +ECHO: v = [], op = "-v", result = [] +ECHO: v = [], op = "v *", result = [] +ECHO: v = [], op = "* v", result = [] +ECHO: v = [], op = "v /", result = [] +ECHO: v = [], op = "/ v", result = [] +ECHO: v = [], op = "v %", result = undef +ECHO: v = [], op = "% v", result = undef +ECHO: v = [], op = "v +", result = undef +ECHO: v = [], op = "+ v", result = undef +ECHO: v = [], op = "v -", result = undef +ECHO: v = [], op = "- v", result = undef +ECHO: v = [], op = "v and true", result = false +ECHO: v = [], op = "v and false", result = false +ECHO: v = [], op = "v or true", result = true +ECHO: v = [], op = "v or false", result = false +ECHO: v = [], op = "[v]", result = undef +ECHO: v = [], op = "v[0]", result = undef +ECHO: v = [], op = "v[4]", result = undef +ECHO: v = [0], op = "not v", result = false +ECHO: v = [0], op = "-v", result = [0] +ECHO: v = [0], op = "v *", result = [0] +ECHO: v = [0], op = "* v", result = [0] +ECHO: v = [0], op = "v /", result = [0] +ECHO: v = [0], op = "/ v", result = [inf] +ECHO: v = [0], op = "v %", result = undef +ECHO: v = [0], op = "% v", result = undef +ECHO: v = [0], op = "v +", result = undef +ECHO: v = [0], op = "+ v", result = undef +ECHO: v = [0], op = "v -", result = undef +ECHO: v = [0], op = "- v", result = undef +ECHO: v = [0], op = "v and true", result = true +ECHO: v = [0], op = "v and false", result = false +ECHO: v = [0], op = "v or true", result = true +ECHO: v = [0], op = "v or false", result = true +ECHO: v = [0], op = "[v]", result = undef +ECHO: v = [0], op = "v[0]", result = 0 +ECHO: v = [0], op = "v[4]", result = undef +ECHO: v = [1], op = "not v", result = false +ECHO: v = [1], op = "-v", result = [-1] +ECHO: v = [1], op = "v *", result = [3] +ECHO: v = [1], op = "* v", result = [2] +ECHO: v = [1], op = "v /", result = [0.33333333333] +ECHO: v = [1], op = "/ v", result = [2] +ECHO: v = [1], op = "v %", result = undef +ECHO: v = [1], op = "% v", result = undef +ECHO: v = [1], op = "v +", result = undef +ECHO: v = [1], op = "+ v", result = undef +ECHO: v = [1], op = "v -", result = undef +ECHO: v = [1], op = "- v", result = undef +ECHO: v = [1], op = "v and true", result = true +ECHO: v = [1], op = "v and false", result = false +ECHO: v = [1], op = "v or true", result = true +ECHO: v = [1], op = "v or false", result = true +ECHO: v = [1], op = "[v]", result = undef +ECHO: v = [1], op = "v[0]", result = 1 +ECHO: v = [1], op = "v[4]", result = undef +ECHO: v = [0 : 1 : 0], op = "not v", result = false +ECHO: v = [0 : 1 : 0], op = "-v", result = undef +ECHO: v = [0 : 1 : 0], op = "v *", result = undef +ECHO: v = [0 : 1 : 0], op = "* v", result = undef +ECHO: v = [0 : 1 : 0], op = "v /", result = undef +ECHO: v = [0 : 1 : 0], op = "/ v", result = undef +ECHO: v = [0 : 1 : 0], op = "v %", result = undef +ECHO: v = [0 : 1 : 0], op = "% v", result = undef +ECHO: v = [0 : 1 : 0], op = "v +", result = undef +ECHO: v = [0 : 1 : 0], op = "+ v", result = undef +ECHO: v = [0 : 1 : 0], op = "v -", result = undef +ECHO: v = [0 : 1 : 0], op = "- v", result = undef +ECHO: v = [0 : 1 : 0], op = "v and true", result = true +ECHO: v = [0 : 1 : 0], op = "v and false", result = false +ECHO: v = [0 : 1 : 0], op = "v or true", result = true +ECHO: v = [0 : 1 : 0], op = "v or false", result = true +ECHO: v = [0 : 1 : 0], op = "[v]", result = undef +ECHO: v = [0 : 1 : 0], op = "v[0]", result = 0 +ECHO: v = [0 : 1 : 0], op = "v[4]", result = undef +ECHO: v = [1 : 1 : 2], op = "not v", result = false +ECHO: v = [1 : 1 : 2], op = "-v", result = undef +ECHO: v = [1 : 1 : 2], op = "v *", result = undef +ECHO: v = [1 : 1 : 2], op = "* v", result = undef +ECHO: v = [1 : 1 : 2], op = "v /", result = undef +ECHO: v = [1 : 1 : 2], op = "/ v", result = undef +ECHO: v = [1 : 1 : 2], op = "v %", result = undef +ECHO: v = [1 : 1 : 2], op = "% v", result = undef +ECHO: v = [1 : 1 : 2], op = "v +", result = undef +ECHO: v = [1 : 1 : 2], op = "+ v", result = undef +ECHO: v = [1 : 1 : 2], op = "v -", result = undef +ECHO: v = [1 : 1 : 2], op = "- v", result = undef +ECHO: v = [1 : 1 : 2], op = "v and true", result = true +ECHO: v = [1 : 1 : 2], op = "v and false", result = false +ECHO: v = [1 : 1 : 2], op = "v or true", result = true +ECHO: v = [1 : 1 : 2], op = "v or false", result = true +ECHO: v = [1 : 1 : 2], op = "[v]", result = undef +ECHO: v = [1 : 1 : 2], op = "v[0]", result = 1 +ECHO: v = [1 : 1 : 2], op = "v[4]", result = undef diff --git a/tests/regression/echotest/for-tests-expected.echo b/tests/regression/echotest/for-tests-expected.echo index 39a8d584..d66cebf8 100644 --- a/tests/regression/echotest/for-tests-expected.echo +++ b/tests/regression/echotest/for-tests-expected.echo @@ -11,14 +11,3 @@ ECHO: "INF", 0 WARNING: Bad range parameter in for statement: too many elements (4294967295). ECHO: "-INF", 1 WARNING: Bad range parameter in for statement: too many elements (4294967295). -WARNING: Bad range parameter in for statement: too many elements (4294967295). -WARNING: Bad range parameter in for statement: too many elements (4294967295). -WARNING: Bad range parameter in for statement: too many elements (4294967295). -WARNING: Bad range parameter in for statement: too many elements (4294967295). -WARNING: Bad range parameter in for statement: too many elements (4294967295). -WARNING: Bad range parameter in for statement: too many elements (4294967295). -WARNING: Bad range parameter in for statement: too many elements (4294967295). -WARNING: Bad range parameter in for statement: too many elements (4294967295). -WARNING: Bad range parameter in for statement: too many elements (4294967295). -WARNING: Bad range parameter in for statement: too many elements (4294967295). -WARNING: Bad range parameter in for statement: too many elements (4294967295). diff --git a/tests/regression/monotonepngtest/issue1061-expected.png b/tests/regression/monotonepngtest/issue1061-expected.png new file mode 100644 index 00000000..78bd8525 Binary files /dev/null and b/tests/regression/monotonepngtest/issue1061-expected.png differ diff --git a/tests/regression/monotonepngtest/nonmanifold-polyhedron-expected.png b/tests/regression/monotonepngtest/nonmanifold-polyhedron-expected.png new file mode 100644 index 00000000..27adff5c Binary files /dev/null and b/tests/regression/monotonepngtest/nonmanifold-polyhedron-expected.png differ diff --git a/tests/regression/opencsgtest/issue1061-expected.png b/tests/regression/opencsgtest/issue1061-expected.png new file mode 100644 index 00000000..fc626374 Binary files /dev/null and b/tests/regression/opencsgtest/issue1061-expected.png differ diff --git a/tests/regression/opencsgtest/nullspace-difference-expected.png b/tests/regression/opencsgtest/nullspace-difference-expected.png new file mode 100644 index 00000000..08ee92b2 Binary files /dev/null and b/tests/regression/opencsgtest/nullspace-difference-expected.png differ diff --git a/tests/regression/opencsgtest/nullspace-intersection-expected.png b/tests/regression/opencsgtest/nullspace-intersection-expected.png new file mode 100644 index 00000000..08ee92b2 Binary files /dev/null and b/tests/regression/opencsgtest/nullspace-intersection-expected.png differ diff --git a/tests/regression/opencsgtest/nullspace-minkowski-expected.png b/tests/regression/opencsgtest/nullspace-minkowski-expected.png new file mode 100644 index 00000000..08ee92b2 Binary files /dev/null and b/tests/regression/opencsgtest/nullspace-minkowski-expected.png differ diff --git a/tests/regression/opencsgtest/nullspace-minkowski-intersection-expected.png b/tests/regression/opencsgtest/nullspace-minkowski-intersection-expected.png new file mode 100644 index 00000000..08ee92b2 Binary files /dev/null and b/tests/regression/opencsgtest/nullspace-minkowski-intersection-expected.png differ diff --git a/tests/regression/opencsgtest/scale-mirror2D-3D-tests-expected.png b/tests/regression/opencsgtest/scale-mirror2D-3D-tests-expected.png new file mode 100644 index 00000000..6521e4af Binary files /dev/null and b/tests/regression/opencsgtest/scale-mirror2D-3D-tests-expected.png differ diff --git a/tests/regression/throwntogethertest/nullspace-difference-expected.png b/tests/regression/throwntogethertest/nullspace-difference-expected.png new file mode 100644 index 00000000..08ee92b2 Binary files /dev/null and b/tests/regression/throwntogethertest/nullspace-difference-expected.png differ diff --git a/tests/regression/throwntogethertest/nullspace-intersection-expected.png b/tests/regression/throwntogethertest/nullspace-intersection-expected.png new file mode 100644 index 00000000..08ee92b2 Binary files /dev/null and b/tests/regression/throwntogethertest/nullspace-intersection-expected.png differ diff --git a/tests/regression/throwntogethertest/nullspace-minkowski-expected.png b/tests/regression/throwntogethertest/nullspace-minkowski-expected.png new file mode 100644 index 00000000..08ee92b2 Binary files /dev/null and b/tests/regression/throwntogethertest/nullspace-minkowski-expected.png differ diff --git a/tests/regression/throwntogethertest/nullspace-minkowski-intersection-expected.png b/tests/regression/throwntogethertest/nullspace-minkowski-intersection-expected.png new file mode 100644 index 00000000..08ee92b2 Binary files /dev/null and b/tests/regression/throwntogethertest/nullspace-minkowski-intersection-expected.png differ diff --git a/tests/regression/throwntogethertest/scale-mirror2D-3D-tests-expected.png b/tests/regression/throwntogethertest/scale-mirror2D-3D-tests-expected.png new file mode 100644 index 00000000..471748a7 Binary files /dev/null and b/tests/regression/throwntogethertest/scale-mirror2D-3D-tests-expected.png differ