Merge branch 'master' of github.com:openscad/openscad into planar
Conflicts: src/CGAL_Nef_polyhedron.cc tests/CMakeLists.txtvector-concat
|
@ -1,5 +1,6 @@
|
|||
/*.scad
|
||||
*.dmg
|
||||
*~
|
||||
*.tar*
|
||||
Makefile
|
||||
objects
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
language: cpp
|
||||
cache: apt
|
||||
compiler: gcc
|
||||
|
||||
before_install:
|
||||
- echo 'yes' | sudo add-apt-repository ppa:chrysn/openscad
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq build-essential libqt4-dev libqt4-opengl-dev libxmu-dev cmake bison flex git-core libboost-all-dev libXi-dev libmpfr-dev libboost-dev libglew-dev libeigen2-dev libeigen3-dev libcgal-dev libgmp3-dev libgmp-dev python-paramiko curl imagemagick
|
||||
- sudo apt-get install -qq libopencsg-dev
|
||||
|
||||
env: OPENSCAD_UPLOAD_TESTS=yes
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
script: ./scripts/travis-ci.sh
|
|
@ -1,3 +1,5 @@
|
|||
![Travis CI](https://api.travis-ci.org/openscad/openscad.png)
|
||||
|
||||
# What is OpenSCAD?
|
||||
[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=openscad&url=http://openscad.org&title=OpenSCAD&language=&tags=github&category=software)
|
||||
|
||||
|
@ -93,6 +95,7 @@ Follow the instructions for the platform you're compiling on below.
|
|||
* [OpenCSG (1.3.2)](http://www.opencsg.org/)
|
||||
* [GLEW (1.5.4 ->)](http://glew.sourceforge.net/)
|
||||
* [Eigen (3.0 - 3.2)](http://eigen.tuxfamily.org/)
|
||||
* [glib2 (2.2.0)](https://developer.gnome.org/glib/)
|
||||
* [GCC C++ Compiler (4.2 ->)](http://gcc.gnu.org/)
|
||||
* [Bison (2.4)](http://www.gnu.org/software/bison/)
|
||||
* [Flex (2.5.35)](http://flex.sourceforge.net/)
|
||||
|
|
|
@ -11,3 +11,4 @@ include(opencsg.pri)
|
|||
include(glew.pri)
|
||||
include(eigen.pri)
|
||||
include(boost.pri)
|
||||
include(glib-2.0.pri)
|
|
@ -0,0 +1,39 @@
|
|||
# Detect glib-2.0, then use this priority list to determine
|
||||
# which library to use:
|
||||
#
|
||||
# Priority
|
||||
# 1. GLIB2_INCLUDEPATH / GLIB2_LIBPATH (qmake parameter, not checked it given on commandline)
|
||||
# 2. OPENSCAD_LIBRARIES (environment variable)
|
||||
# 3. system's standard include paths from pkg-config
|
||||
|
||||
glib-2.0 {
|
||||
# read environment variables
|
||||
OPENSCAD_LIBRARIES_DIR = $$(OPENSCAD_LIBRARIES)
|
||||
GLIB2_DIR = $$(GLIB2DIR)
|
||||
|
||||
!isEmpty(OPENSCAD_LIBRARIES_DIR) {
|
||||
isEmpty(GLIB2_INCLUDEPATH) {
|
||||
GLIB2_INCLUDEPATH = $$OPENSCAD_LIBRARIES_DIR/include/glib-2.0
|
||||
GLIB2_INCLUDEPATH_2 = $$OPENSCAD_LIBRARIES_DIR/lib/glib-2.0/include
|
||||
GLIB2_LIBPATH = $$OPENSCAD_LIBRARIES_DIR/lib
|
||||
}
|
||||
}
|
||||
|
||||
isEmpty(GLIB2_INCLUDEPATH) {
|
||||
GLIB2_CFLAGS = $$system("pkg-config --cflags glib-2.0")
|
||||
} else {
|
||||
GLIB2_CFLAGS = -I$$GLIB2_INCLUDEPATH
|
||||
GLIB2_CFLAGS += -I$$GLIB2_INCLUDEPATH_2
|
||||
}
|
||||
|
||||
isEmpty(GLIB2_LIBPATH) {
|
||||
GLIB2_LIBS = $$system("pkg-config --libs glib-2.0")
|
||||
} else {
|
||||
GLIB2_LIBS = -L$$GLIB2_LIBPATH -lglib-2.0
|
||||
}
|
||||
|
||||
QMAKE_CXXFLAGS += $$GLIB2_CFLAGS
|
||||
LIBS += $$GLIB2_LIBS
|
||||
|
||||
message("glib: $$GLIB2_CFLAGS")
|
||||
}
|
|
@ -4,4 +4,4 @@ Version=1.0
|
|||
Name=OpenSCAD
|
||||
Icon=openscad
|
||||
Exec=openscad %f
|
||||
Categories=Graphics;3DGraphics;Engineering;Programming;
|
||||
Categories=Graphics;3DGraphics;Engineering;Development;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
# OPENCSGDIR
|
||||
# OPENSCAD_LIBRARIES
|
||||
#
|
||||
# Please see the 'Buildling' sections of the OpenSCAD user manual
|
||||
# Please see the 'Building' sections of the OpenSCAD user manual
|
||||
# for updated tips & workarounds.
|
||||
#
|
||||
# http://en.wikibooks.org/wiki/OpenSCAD_User_Manual
|
||||
|
@ -39,6 +39,7 @@ debug: DEFINES += DEBUG
|
|||
TEMPLATE = app
|
||||
|
||||
INCLUDEPATH += src
|
||||
DEPENDPATH += src
|
||||
|
||||
# Handle custom library location.
|
||||
# Used when manually installing 3rd party libraries
|
||||
|
@ -155,6 +156,7 @@ CONFIG += cgal
|
|||
CONFIG += opencsg
|
||||
CONFIG += boost
|
||||
CONFIG += eigen
|
||||
CONFIG += glib-2.0
|
||||
|
||||
#Uncomment the following line to enable QCodeEdit
|
||||
#CONFIG += qcodeedit
|
||||
|
@ -368,6 +370,7 @@ HEADERS += src/cgal.h \
|
|||
src/PolySetCGALEvaluator.h \
|
||||
src/CGALRenderer.h \
|
||||
src/CGAL_Nef_polyhedron.h \
|
||||
src/CGAL_Nef3_workaround.h \
|
||||
src/cgalworker.h
|
||||
|
||||
SOURCES += src/cgalutils.cc \
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
--- src/3rdparty/libtiff/libtiff/tif_config.h
|
||||
+++ src/3rdparty/libtiff/libtiff/tif_config.h
|
||||
@@ -317,15 +317,6 @@
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
-/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
- calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
-#ifndef Q_OS_SYMBIAN
|
||||
-#ifndef __cplusplus
|
||||
-#undef inline
|
||||
-#define inline
|
||||
-#endif
|
||||
-#endif
|
||||
-
|
||||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
/* #undef off_t */
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
--- src/gui/kernel/qeventdispatcher_mac_p.h 2013-06-07 01:16:59.000000000 -0400
|
||||
+++ src/gui/kernel/qeventdispatcher_mac_p_new-8184b49c12d887928921ed5b695c8c6f04a07514.h 2013-12-08 14:31:01.000000000 -0500
|
||||
@@ -173,6 +173,7 @@
|
||||
#ifdef QT_MAC_USE_COCOA
|
||||
// The following variables help organizing modal sessions:
|
||||
static QStack<QCocoaModalSessionInfo> cocoaModalSessionStack;
|
||||
+ static QStack<QCocoaModalSessionInfo> cocoaModalSessionStackPendingEnd;
|
||||
static bool currentExecIsNSAppRun;
|
||||
static bool nsAppRunCalledByQt;
|
||||
static bool cleanupModalSessionsNeeded;
|
||||
@@ -180,6 +181,7 @@
|
||||
static NSModalSession currentModalSession();
|
||||
static void updateChildrenWorksWhenModal();
|
||||
static void temporarilyStopAllModalSessions();
|
||||
+ static void stopAllPendingEndModalSessions();
|
||||
static void beginModalSession(QWidget *widget);
|
||||
static void endModalSession(QWidget *widget);
|
||||
static void cancelWaitForMoreEvents();
|
||||
--- src/gui/kernel/qeventdispatcher_mac.mm 2013-06-07 01:16:59.000000000 -0400
|
||||
+++ src/gui/kernel/qeventdispatcher_mac_new-833e02de99494686f8dd7a567f6e19e847508f11.mm 2013-12-08 14:30:59.000000000 -0500
|
||||
@@ -603,6 +603,9 @@
|
||||
while ([NSApp runModalSession:session] == NSRunContinuesResponse && !d->interrupt)
|
||||
qt_mac_waitForMoreModalSessionEvents();
|
||||
|
||||
+ // stop all pending end modal sessions
|
||||
+ d->stopAllPendingEndModalSessions();
|
||||
+
|
||||
if (!d->interrupt && session == d->currentModalSessionCached) {
|
||||
// Someone called [NSApp stopModal:] from outside the event
|
||||
// dispatcher (e.g to stop a native dialog). But that call wrongly stopped
|
||||
@@ -678,6 +681,9 @@
|
||||
if (!d->interrupt)
|
||||
QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
|
||||
|
||||
+ // stop all pending end modal sessions
|
||||
+ d->stopAllPendingEndModalSessions();
|
||||
+
|
||||
// Since the window that holds modality might have changed while processing
|
||||
// events, we we need to interrupt when we return back the previous process
|
||||
// event recursion to ensure that we spin the correct modal session.
|
||||
@@ -781,6 +787,7 @@
|
||||
|
||||
#ifdef QT_MAC_USE_COCOA
|
||||
QStack<QCocoaModalSessionInfo> QEventDispatcherMacPrivate::cocoaModalSessionStack;
|
||||
+QStack<QCocoaModalSessionInfo> QEventDispatcherMacPrivate::cocoaModalSessionStackPendingEnd;
|
||||
bool QEventDispatcherMacPrivate::currentExecIsNSAppRun = false;
|
||||
bool QEventDispatcherMacPrivate::nsAppRunCalledByQt = false;
|
||||
bool QEventDispatcherMacPrivate::cleanupModalSessionsNeeded = false;
|
||||
@@ -828,6 +835,20 @@
|
||||
currentModalSessionCached = 0;
|
||||
}
|
||||
|
||||
+void QEventDispatcherMacPrivate::stopAllPendingEndModalSessions()
|
||||
+{
|
||||
+ // stop all modal sessions pending end
|
||||
+ int stackSize = cocoaModalSessionStackPendingEnd.size();
|
||||
+ for (int i=stackSize-1; i>=0; --i) {
|
||||
+ QCocoaModalSessionInfo &info = cocoaModalSessionStackPendingEnd[i];
|
||||
+ cocoaModalSessionStackPendingEnd.remove(i);
|
||||
+ if (info.session) {
|
||||
+ [NSApp endModalSession:info.session];
|
||||
+ [(NSWindow *)info.nswindow release];
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
NSModalSession QEventDispatcherMacPrivate::currentModalSession()
|
||||
{
|
||||
// If we have one or more modal windows, this function will create
|
||||
@@ -925,10 +946,12 @@
|
||||
}
|
||||
cocoaModalSessionStack.remove(i);
|
||||
currentModalSessionCached = 0;
|
||||
- if (info.session) {
|
||||
- [NSApp endModalSession:info.session];
|
||||
- [(NSWindow *)info.nswindow release];
|
||||
- }
|
||||
+
|
||||
+ // Cannot stop the sessions here since we might still be inside a
|
||||
+ // [NSApp runModalSession:] call. Add the session to the pending end stack and
|
||||
+ // process the stack after the call to [NSApp runModalSession:] returns.
|
||||
+ if (info.session)
|
||||
+ cocoaModalSessionStackPendingEnd.push(info);
|
||||
}
|
||||
|
||||
updateChildrenWorksWhenModal();
|
|
@ -0,0 +1,29 @@
|
|||
--- src/gui/text/qfontdatabase.cpp 2013-06-07 01:16:59.000000000 -0400
|
||||
+++ src/gui/text/qfontdatabase_new-bb2beddc3ae55c4676d190d0ac99aa32d322a6a5.cpp 2013-12-08 14:51:10.000000000 -0500
|
||||
@@ -441,6 +441,7 @@
|
||||
#endif
|
||||
#if !defined(QWS) && defined(Q_OS_MAC)
|
||||
bool fixedPitchComputed : 1;
|
||||
+ QString postscriptName;
|
||||
#endif
|
||||
#ifdef Q_WS_X11
|
||||
bool symbol_checked : 1;
|
||||
--- src/gui/text/qfontdatabase_mac.cpp 2013-06-07 01:16:59.000000000 -0400
|
||||
+++ src/gui/text/qfontdatabase_mac_new-41f29865db84152efb41c048470f713353a0a84c.cpp 2013-12-08 14:51:05.000000000 -0500
|
||||
@@ -147,6 +147,7 @@
|
||||
QCFString family_name = (CFStringRef)CTFontDescriptorCopyLocalizedAttribute(font, kCTFontFamilyNameAttribute, NULL);
|
||||
QCFString style_name = (CFStringRef)CTFontDescriptorCopyLocalizedAttribute(font, kCTFontStyleNameAttribute, NULL);
|
||||
QtFontFamily *family = db->family(family_name, true);
|
||||
+ family->postscriptName = QCFString((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontNameAttribute));
|
||||
|
||||
if (QCFType<CFArrayRef> languages = (CFArrayRef) CTFontDescriptorCopyAttribute(font, kCTFontLanguagesAttribute)) {
|
||||
CFIndex length = CFArrayGetCount(languages);
|
||||
@@ -327,7 +328,7 @@
|
||||
if (db->families[k]->name.compare(family_list.at(i), Qt::CaseInsensitive) == 0) {
|
||||
QByteArray family_name = db->families[k]->name.toUtf8();
|
||||
#if defined(QT_MAC_USE_COCOA)
|
||||
- QCFType<CTFontRef> ctFont = CTFontCreateWithName(QCFString(db->families[k]->name), 12, NULL);
|
||||
+ QCFType<CTFontRef> ctFont = CTFontCreateWithName(QCFString(db->families[k]->postscriptName), 12, NULL);
|
||||
if (ctFont) {
|
||||
fontName = CTFontCopyFullName(ctFont);
|
||||
goto found;
|
|
@ -0,0 +1,14 @@
|
|||
--- src/corelib/global/qglobal.h.orig 2013-06-07 07:16:52.000000000 +0200
|
||||
+++ src/corelib/global/qglobal.h 2013-10-27 14:05:22.000000000 +0100
|
||||
@@ -327,7 +327,10 @@
|
||||
# if !defined(MAC_OS_X_VERSION_10_8)
|
||||
# define MAC_OS_X_VERSION_10_8 MAC_OS_X_VERSION_10_7 + 1
|
||||
# endif
|
||||
-# if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_8)
|
||||
+# if !defined(MAC_OS_X_VERSION_10_9)
|
||||
+# define MAC_OS_X_VERSION_10_9 MAC_OS_X_VERSION_10_8 + 1
|
||||
+# endif
|
||||
+# if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_9)
|
||||
# warning "This version of Mac OS X is unsupported"
|
||||
# endif
|
||||
#endif
|
|
@ -66,6 +66,31 @@ cgal_sysver()
|
|||
cgal_sysver_result=`grep "define *CGAL_VERSION *[0-9.]*" $cgalpath | awk '{print $3}'`
|
||||
}
|
||||
|
||||
glib2_sysver()
|
||||
{
|
||||
#Get architecture triplet - e.g. x86_64-linux-gnu
|
||||
glib2archtriplet=`gcc -dumpmachine 2>/dev/null`
|
||||
if [ -z "$VAR" ]; then
|
||||
glib2archtriplet=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null`
|
||||
fi
|
||||
glib2path=$1/lib/$glib2archtriplet/glib-2.0/include/glibconfig.h
|
||||
if [ ! -e $glib2path ]; then
|
||||
#No glib found
|
||||
#glib can be installed in /usr/lib/i386-linux-gnu/glib-2.0/ on arch i686-linux-gnu (sometimes?)
|
||||
if [ $glib2archtriplet = "i686-linux-gnu" ]; then
|
||||
glib2archtriplet=i386-linux-gnu
|
||||
glib2path=$1/lib/$glib2archtriplet/glib-2.0/include/glibconfig.h
|
||||
if [ ! -e $glib2path ]; then return; fi
|
||||
else
|
||||
return;
|
||||
fi
|
||||
fi
|
||||
glib2major=`grep "define *GLIB_MAJOR_VERSION *[0-9.]*" $glib2path | awk '{print $3}'`
|
||||
glib2minor=`grep "define *GLIB_MINOR_VERSION *[0-9.]*" $glib2path | awk '{print $3}'`
|
||||
glib2micro=`grep "define *GLIB_MICRO_VERSION *[0-9.]*" $glib2path | awk '{print $3}'`
|
||||
glib2_sysver_result="${glib2major}.${glib2minor}.${glib2micro}"
|
||||
}
|
||||
|
||||
boost_sysver()
|
||||
{
|
||||
boostpath=$1/include/boost/version.hpp
|
||||
|
@ -530,7 +555,7 @@ checkargs()
|
|||
|
||||
main()
|
||||
{
|
||||
deps="qt4 cgal gmp mpfr boost opencsg glew eigen gcc bison flex make"
|
||||
deps="qt4 cgal gmp mpfr boost opencsg glew eigen glib2 gcc bison flex make"
|
||||
#deps="$deps curl git" # not technically necessary for build
|
||||
#deps="$deps python cmake imagemagick" # only needed for tests
|
||||
#deps="cgal"
|
||||
|
|
|
@ -24,7 +24,7 @@ BASEDIR=$PWD/../libraries
|
|||
OPENSCADDIR=$PWD
|
||||
SRCDIR=$BASEDIR/src
|
||||
DEPLOYDIR=$BASEDIR/install
|
||||
MAC_OSX_VERSION_MIN=10.6
|
||||
MAC_OSX_VERSION_MIN=10.7
|
||||
OPTION_32BIT=false
|
||||
OPTION_LLVM=false
|
||||
OPTION_CLANG=false
|
||||
|
@ -54,6 +54,9 @@ build_qt()
|
|||
fi
|
||||
tar xzf qt-everywhere-opensource-src-$version.tar.gz
|
||||
cd qt-everywhere-opensource-src-$version
|
||||
patch -p0 < $OPENSCADDIR/patches/qt4/patch-src_corelib_global_qglobal.h.diff
|
||||
patch -p0 < $OPENSCADDIR/patches/qt4/patch-libtiff.diff
|
||||
patch -p0 < $OPENSCADDIR/patches/qt4/patch-src_plugins_bearer_corewlan_qcorewlanengine.mm.diff
|
||||
if $USING_CLANG; then
|
||||
# FIX for clang
|
||||
sed -i "" -e "s/::TabletProximityRec/TabletProximityRec/g" src/gui/kernel/qt_cocoa_helpers_mac_p.h
|
||||
|
@ -80,6 +83,51 @@ build_gmp()
|
|||
fi
|
||||
tar xjf gmp-$version.tar.bz2
|
||||
cd gmp-$version
|
||||
patch -p0 gmp-h.in << EOF
|
||||
--- gmp-5.1.3/gmp-h.in.old 2013-12-02 20:16:26.000000000 -0800
|
||||
+++ gmp-5.1.3/gmp-h.in 2013-12-02 20:21:22.000000000 -0800
|
||||
@@ -27,13 +27,38 @@
|
||||
#endif
|
||||
|
||||
|
||||
-/* Instantiated by configure. */
|
||||
#if ! defined (__GMP_WITHIN_CONFIGURE)
|
||||
+/* For benefit of fat builds on MacOSX, generate a .h file that can
|
||||
+ * be used with a universal fat library
|
||||
+ */
|
||||
+#if defined(__x86_64__)
|
||||
+#define __GMP_HAVE_HOST_CPU_FAMILY_power 0
|
||||
+#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 0
|
||||
+#define GMP_LIMB_BITS 64
|
||||
+#define GMP_NAIL_BITS 0
|
||||
+#elif defined(__i386__)
|
||||
+#define __GMP_HAVE_HOST_CPU_FAMILY_power 0
|
||||
+#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 0
|
||||
+#define GMP_LIMB_BITS 32
|
||||
+#define GMP_NAIL_BITS 0
|
||||
+#elif defined(__powerpc64__)
|
||||
+#define __GMP_HAVE_HOST_CPU_FAMILY_power 0
|
||||
+#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 1
|
||||
+#define GMP_LIMB_BITS 64
|
||||
+#define GMP_NAIL_BITS 0
|
||||
+#elif defined(__ppc__)
|
||||
+#define __GMP_HAVE_HOST_CPU_FAMILY_power 0
|
||||
+#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 1
|
||||
+#define GMP_LIMB_BITS 32
|
||||
+#define GMP_NAIL_BITS 0
|
||||
+#else
|
||||
+/* For other architectures, fall back on values computed by configure */
|
||||
#define __GMP_HAVE_HOST_CPU_FAMILY_power @HAVE_HOST_CPU_FAMILY_power@
|
||||
#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc @HAVE_HOST_CPU_FAMILY_powerpc@
|
||||
#define GMP_LIMB_BITS @GMP_LIMB_BITS@
|
||||
#define GMP_NAIL_BITS @GMP_NAIL_BITS@
|
||||
#endif
|
||||
+#endif
|
||||
#define GMP_NUMB_BITS (GMP_LIMB_BITS - GMP_NAIL_BITS)
|
||||
#define GMP_NUMB_MASK ((~ __GMP_CAST (mp_limb_t, 0)) >> GMP_NAIL_BITS)
|
||||
#define GMP_NUMB_MAX GMP_NUMB_MASK
|
||||
EOF
|
||||
|
||||
if $OPTION_32BIT; then
|
||||
mkdir build-i386
|
||||
cd build-i386
|
||||
|
@ -116,42 +164,6 @@ build_gmp()
|
|||
mkdir -p include
|
||||
cp x86_64/include/gmp.h include/
|
||||
cp x86_64/include/gmpxx.h include/
|
||||
|
||||
patch -p0 include/gmp.h << EOF
|
||||
--- gmp.h.orig 2011-11-08 01:03:41.000000000 +0100
|
||||
+++ gmp.h 2011-11-08 01:06:21.000000000 +0100
|
||||
@@ -26,12 +26,28 @@
|
||||
#endif
|
||||
|
||||
|
||||
-/* Instantiated by configure. */
|
||||
-#if ! defined (__GMP_WITHIN_CONFIGURE)
|
||||
+#if defined(__i386__)
|
||||
+#define __GMP_HAVE_HOST_CPU_FAMILY_power 0
|
||||
+#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 0
|
||||
+#define GMP_LIMB_BITS 32
|
||||
+#define GMP_NAIL_BITS 0
|
||||
+#elif defined(__x86_64__)
|
||||
#define __GMP_HAVE_HOST_CPU_FAMILY_power 0
|
||||
#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 0
|
||||
#define GMP_LIMB_BITS 64
|
||||
#define GMP_NAIL_BITS 0
|
||||
+#elif defined(__ppc__)
|
||||
+#define __GMP_HAVE_HOST_CPU_FAMILY_power 0
|
||||
+#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 1
|
||||
+#define GMP_LIMB_BITS 32
|
||||
+#define GMP_NAIL_BITS 0
|
||||
+#elif defined(__powerpc64__)
|
||||
+#define __GMP_HAVE_HOST_CPU_FAMILY_power 0
|
||||
+#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 1
|
||||
+#define GMP_LIMB_BITS 64
|
||||
+#define GMP_NAIL_BITS 0
|
||||
+#else
|
||||
+#error Unsupported architecture
|
||||
#endif
|
||||
#define GMP_NUMB_BITS (GMP_LIMB_BITS - GMP_NAIL_BITS)
|
||||
#define GMP_NUMB_MASK ((~ __GMP_CAST (mp_limb_t, 0)) >> GMP_NAIL_BITS)
|
||||
EOF
|
||||
}
|
||||
|
||||
# As with gmplib, mpfr is built separately in 32-bit and 64-bit mode and then merged
|
||||
|
@ -220,7 +232,7 @@ build_boost()
|
|||
BOOST_TOOLSET="toolset=clang"
|
||||
echo "using clang ;" >> tools/build/v2/user-config.jam
|
||||
fi
|
||||
./b2 -d+2 $BOOST_TOOLSET cflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS" linkflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS -headerpad_max_install_names" install
|
||||
./b2 -j6 -d+2 $BOOST_TOOLSET cflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS" linkflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS -headerpad_max_install_names" install
|
||||
install_name_tool -id $DEPLOYDIR/lib/libboost_thread.dylib $DEPLOYDIR/lib/libboost_thread.dylib
|
||||
install_name_tool -change libboost_system.dylib $DEPLOYDIR/lib/libboost_system.dylib $DEPLOYDIR/lib/libboost_thread.dylib
|
||||
install_name_tool -change libboost_chrono.dylib $DEPLOYDIR/lib/libboost_chrono.dylib $DEPLOYDIR/lib/libboost_thread.dylib
|
||||
|
@ -282,6 +294,43 @@ build_glew()
|
|||
make GLEW_DEST=$DEPLOYDIR CC=$CC CFLAGS.EXTRA="-no-cpp-precomp -dynamic -fno-common -mmacosx-version-min=$MAC_OSX_VERSION_MIN $GLEW_EXTRA_FLAGS -arch x86_64" LDFLAGS.EXTRA="-mmacosx-version-min=$MAC_OSX_VERSION_MIN $GLEW_EXTRA_FLAGS -arch x86_64" STRIP= install
|
||||
}
|
||||
|
||||
build_gettext()
|
||||
{
|
||||
version=$1
|
||||
echo "Building gettext $version..."
|
||||
|
||||
cd "$BASEDIR"/src
|
||||
rm -rf "gettext-$version"
|
||||
if [ ! -f "glib-$version.tar.xz" ]; then
|
||||
curl --insecure -LO "http://ftpmirror.gnu.org/gettext/gettext-$version.tar.gz"
|
||||
fi
|
||||
tar xzf "gettext-$version.tar.gz"
|
||||
cd "gettext-$version"
|
||||
|
||||
./configure --prefix="$DEPLOYDIR"
|
||||
make -j4
|
||||
make install
|
||||
}
|
||||
|
||||
build_glib2()
|
||||
{
|
||||
version=$1
|
||||
echo "Building glib2 $version..."
|
||||
|
||||
cd "$BASEDIR"/src
|
||||
rm -rf "glib-$version"
|
||||
maj_min_version="${version%.*}" #Drop micro
|
||||
if [ ! -f "glib-$version.tar.xz" ]; then
|
||||
curl --insecure -LO "http://ftp.gnome.org/pub/gnome/sources/glib/$maj_min_version/glib-$version.tar.xz"
|
||||
fi
|
||||
tar xJf "glib-$version.tar.xz"
|
||||
cd "glib-$version"
|
||||
|
||||
./configure --disable-gtk-doc --disable-man --prefix="$DEPLOYDIR" CFLAGS="-I$DEPLOYDIR/include" LDFLAGS="-L$DEPLOYDIR/lib"
|
||||
make -j4
|
||||
make install
|
||||
}
|
||||
|
||||
build_opencsg()
|
||||
{
|
||||
version=$1
|
||||
|
@ -446,6 +495,12 @@ build_boost 1.54.0
|
|||
# NB! For CGAL, also update the actual download URL in the function
|
||||
build_cgal 4.3
|
||||
build_glew 1.10.0
|
||||
<<<<<<< HEAD
|
||||
build_gettext 0.18.3.1
|
||||
build_glib2 2.38.2
|
||||
=======
|
||||
build_glib2 2.38.1
|
||||
>>>>>>> d7d5bea7363703c76b9787598304bfc838e893ee
|
||||
build_opencsg 1.3.2
|
||||
if $OPTION_DEPLOY; then
|
||||
# build_sparkle andymatuschak 0ed83cf9f2eeb425d4fdd141c01a29d843970c20
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash
|
||||
|
||||
cd tests
|
||||
cmake .
|
||||
if [[ $? != 0 ]]; then
|
||||
echo "Error configuring test suite"
|
||||
exit 1
|
||||
fi
|
||||
make -j2
|
||||
if [[ $? != 0 ]]; then
|
||||
echo "Error building test suite"
|
||||
exit 1
|
||||
fi
|
||||
ctest -j8
|
||||
if [[ $? != 0 ]]; then
|
||||
echo "Test failure"
|
||||
exit 1
|
||||
fi
|
|
@ -409,6 +409,48 @@ build_glew()
|
|||
GLEW_DEST=$DEPLOYDIR $MAKER install
|
||||
}
|
||||
|
||||
build_gettext()
|
||||
{
|
||||
version=$1
|
||||
echo "Building gettext $version..."
|
||||
|
||||
cd "$BASEDIR"/src
|
||||
rm -rf "gettext-$version"
|
||||
if [ ! -f "glib-$version.tar.xz" ]; then
|
||||
curl --insecure -LO "http://ftpmirror.gnu.org/gettext/gettext-$version.tar.gz"
|
||||
fi
|
||||
tar xzf "gettext-$version.tar.gz"
|
||||
cd "gettext-$version"
|
||||
|
||||
./configure --prefix="$DEPLOYDIR"
|
||||
make -j4
|
||||
make install
|
||||
}
|
||||
|
||||
build_glib2()
|
||||
{
|
||||
version="$1"
|
||||
maj_min_version="${version%.*}" #Drop micro
|
||||
|
||||
if [ -e $DEPLOYDIR/lib/glib-2.0 ]; then
|
||||
echo "glib2 already installed. not building"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Building glib2 $version..."
|
||||
cd "$BASEDIR"/src
|
||||
rm -rf "glib-$version"
|
||||
if [ ! -f "glib-$version.tar.xz" ]; then
|
||||
curl --insecure -LO "http://ftp.gnome.org/pub/gnome/sources/glib/$maj_min_version/glib-$version.tar.xz"
|
||||
fi
|
||||
tar xJf "glib-$version.tar.xz"
|
||||
cd "glib-$version"
|
||||
|
||||
./configure --disable-gtk-doc --disable-man --prefix="$DEPLOYDIR" CFLAGS="-I$DEPLOYDIR/include" LDFLAGS="-L$DEPLOYDIR/lib"
|
||||
make -j$NUMCPU
|
||||
make install
|
||||
}
|
||||
|
||||
build_opencsg()
|
||||
{
|
||||
if [ -e $DEPLOYDIR/lib/libopencsg.so ]; then
|
||||
|
@ -603,5 +645,7 @@ build_boost 1.53.0
|
|||
build_cgal 4.0.2
|
||||
build_glew 1.9.0
|
||||
build_opencsg 1.3.2
|
||||
build_gettext 0.18.3.1
|
||||
build_glib2 2.38.2
|
||||
|
||||
echo "OpenSCAD dependencies built and installed to " $BASEDIR
|
||||
|
|
|
@ -8,7 +8,7 @@ get_fedora_deps()
|
|||
{
|
||||
sudo yum install qt-devel bison flex eigen3-devel python-paramiko \
|
||||
boost-devel mpfr-devel gmp-devel glew-devel CGAL-devel gcc gcc-c++ pkgconfig \
|
||||
opencsg-devel git libXmu-devel curl imagemagick ImageMagick make \
|
||||
opencsg-devel git libXmu-devel curl imagemagick ImageMagick glib2-devel make \
|
||||
xorg-x11-server-Xvfb
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ get_altlinux_deps()
|
|||
{
|
||||
for i in boost-devel boost-filesystem-devel gcc4.5 gcc4.5-c++ boost-program_options-devel \
|
||||
boost-thread-devel boost-system-devel boost-regex-devel eigen3 libmpfr libgmp libgmp_cxx-devel qt4-devel libcgal-devel git-core \
|
||||
libglew-devel flex bison curl imagemagick; do sudo apt-get install $i; done
|
||||
libglew-devel flex bison curl imagemagick glib2-devel; do sudo apt-get install $i; done
|
||||
}
|
||||
|
||||
get_freebsd_deps()
|
||||
|
@ -29,20 +29,21 @@ get_freebsd_deps()
|
|||
pkg_add -r bison boost-libs cmake git bash eigen3 flex gmake gmp mpfr \
|
||||
xorg libGLU libXmu libXi xorg-vfbserver glew \
|
||||
qt4-corelib qt4-gui qt4-moc qt4-opengl qt4-qmake qt4-rcc qt4-uic \
|
||||
opencsg cgal curl imagemagick
|
||||
opencsg cgal curl imagemagick glib2-devel
|
||||
}
|
||||
|
||||
get_netbsd_deps()
|
||||
{
|
||||
sudo pkgin install bison boost cmake git bash eigen flex gmake gmp mpfr \
|
||||
qt4 glew cgal opencsg modular-xorg python27 py27-paramiko curl \
|
||||
imagemagick ImageMagick
|
||||
imagemagick ImageMagick glib2-devel
|
||||
}
|
||||
|
||||
get_opensuse_deps()
|
||||
{
|
||||
sudo zypper install libeigen3-devel mpfr-devel gmp-devel boost-devel \
|
||||
libqt4-devel glew-devel cmake git bison flex cgal-devel opencsg-devel curl
|
||||
libqt4-devel glew-devel cmake git bison flex cgal-devel opencsg-devel curl \
|
||||
glib2-devel
|
||||
}
|
||||
|
||||
get_mageia_deps()
|
||||
|
@ -50,7 +51,7 @@ get_mageia_deps()
|
|||
sudo urpmi ctags
|
||||
sudo urpmi task-c-devel task-c++-devel libqt4-devel libgmp-devel \
|
||||
libmpfr-devel libboost-devel eigen3-devel libglew-devel bison flex \
|
||||
cmake imagemagick python curl git x11-server-xvfb
|
||||
cmake imagemagick glib2-devel python curl git x11-server-xvfb
|
||||
}
|
||||
|
||||
get_debian_deps()
|
||||
|
@ -59,7 +60,7 @@ get_debian_deps()
|
|||
libxmu-dev cmake bison flex git-core libboost-all-dev \
|
||||
libXi-dev libmpfr-dev libboost-dev libglew-dev \
|
||||
libeigen3-dev libcgal-dev libopencsg-dev libgmp3-dev libgmp-dev \
|
||||
python-paramiko curl imagemagick; do
|
||||
python-paramiko curl imagemagick libglib2.0-dev; do
|
||||
sudo apt-get -y install $pkg;
|
||||
done
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ Please visit this link for a copy of the license: <a href="http://www.gnu.org/li
|
|||
<li><a href="http://www.stroustrup.com/C++.html">C++</a>, <a href="http://gcc.gnu.org/">GCC</a>, <a href="http://clang.llvm.org/">clang</a>
|
||||
<li><a href="http://www.python.org">python</a>
|
||||
<li><a href="http://nsis.sourceforge.net/Main_Page">Nullsoft installer</a>
|
||||
<li><a href="https://developer.gnome.org/glib/">GLib</a>
|
||||
</lu>
|
||||
</p>
|
||||
|
||||
|
|
|
@ -159,9 +159,21 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
|
|||
PRINT("Hull() currently requires a valid 2-manifold. Please modify your design. See http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/STL_Import_and_Export");
|
||||
}
|
||||
else {
|
||||
chN.p3->convert_to_Polyhedron(P);
|
||||
std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points3d),
|
||||
boost::bind(static_cast<const CGAL_Polyhedron::Vertex::Point_3&(CGAL_Polyhedron::Vertex::*)() const>(&CGAL_Polyhedron::Vertex::point), _1));
|
||||
bool err = false;
|
||||
std::string errmsg("");
|
||||
try {
|
||||
err = nefworkaround::convert_to_Polyhedron<CGAL_Kernel3>( *(chN.p3), P );
|
||||
//chN.p3->convert_to_Polyhedron(P);
|
||||
} catch (const CGAL::Failure_exception &e) {
|
||||
err = true;
|
||||
errmsg = std::string(e.what());
|
||||
}
|
||||
if (err) {
|
||||
PRINTB("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed. %s", errmsg);
|
||||
} else {
|
||||
std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points3d),
|
||||
boost::bind(static_cast<const CGAL_Polyhedron::Vertex::Point_3&(CGAL_Polyhedron::Vertex::*)() const>(&CGAL_Polyhedron::Vertex::point), _1));
|
||||
}
|
||||
}
|
||||
}
|
||||
chnode->progress_report();
|
||||
|
|
|
@ -0,0 +1,352 @@
|
|||
// Copyright (c) 1997-2002,2005 Max-Planck-Institute Saarbruecken (Germany).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/releases/CGAL-4.0-branch/Nef_3/include/CGAL/Nef_helper_3.h $
|
||||
// $Id: Nef_helper_3.h 67117 2012-01-13 18:14:48Z lrineau $
|
||||
//
|
||||
//
|
||||
// Author(s) : Michael Seel <seel@mpi-sb.mpg.de>
|
||||
// Miguel Granados <granados@mpi-sb.mpg.de>
|
||||
// Susan Hert <hert@mpi-sb.mpg.de>
|
||||
// Lutz Kettner <kettner@mpi-sb.mpg.de>
|
||||
// Ralf Osbild <osbild@mpi-sb.mpg.de>
|
||||
// Peter Hachenberger <hachenberger@mpi-sb.mpg.de>
|
||||
|
||||
/*
|
||||
modified by don bright for OpenSCAD, 2013.
|
||||
|
||||
This works around issue #410, where CGAL's Nef_Polyhedron3.convert_to_Polyhedron
|
||||
throws an uncatchable exception, due to an CGAL_Assertion being thrown in
|
||||
Polyhedron Incremental Builder's destructor while a Triangulation exception
|
||||
is still active, resulting in program termination (crashing).
|
||||
|
||||
The purpose here is not to improve/change the way CGAL's Nef code works,
|
||||
but instead to tweak it slightly to prevent OpenSCAD from crashing. The
|
||||
behavior of the code should otherwise be exactly the same as CGAL's standard
|
||||
code.
|
||||
|
||||
This file was created by copying three sections
|
||||
from CGAL's Nef_polyhedron3.h that were protected/private:
|
||||
|
||||
Triangulation_handler2
|
||||
Build_Polyhedron
|
||||
convert_to_polyhedron
|
||||
|
||||
Very small code changes have been made. First, there are many template
|
||||
type specifiers added to enable the movement of the code to the outside
|
||||
of the Nef Polyhedron class. Second, there is a try{}catch(...){} block
|
||||
added in the Builder around the Triangulation code. Third, there is an error
|
||||
variable added for non-Exception communication with the caller.
|
||||
|
||||
Eventually, if CGAL itself is updated and the update is widely
|
||||
distributed, this file may become obsolete and can be deleted from OpenSCAD
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _CGAL_NEF3_WORKAROUND_H
|
||||
#define _CGAL_NEF3_WORKAROUND_H
|
||||
|
||||
#include <CGAL/Polyhedron_incremental_builder_3.h>
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/assertions.h>
|
||||
|
||||
#include <CGAL/Constrained_triangulation_2.h>
|
||||
#include <CGAL/Triangulation_data_structure_2.h>
|
||||
#include <CGAL/Projection_traits_xy_3.h>
|
||||
#include <CGAL/Projection_traits_yz_3.h>
|
||||
#include <CGAL/Projection_traits_xz_3.h>
|
||||
#include <CGAL/Constrained_triangulation_face_base_2.h>
|
||||
|
||||
#include "printutils.h"
|
||||
|
||||
namespace nefworkaround {
|
||||
|
||||
template<typename Kernel, typename Nef>
|
||||
class Triangulation_handler2 {
|
||||
|
||||
typedef typename CGAL::Triangulation_vertex_base_2<Kernel> Vb;
|
||||
typedef typename CGAL::Constrained_triangulation_face_base_2<Kernel> Fb;
|
||||
typedef typename CGAL::Triangulation_data_structure_2<Vb,Fb> TDS;
|
||||
typedef typename CGAL::Constrained_triangulation_2<Kernel,TDS> CT;
|
||||
|
||||
typedef typename CT::Face_handle Face_handle;
|
||||
typedef typename CT::Vertex_handle CTVertex_handle;
|
||||
typedef typename CT::Finite_faces_iterator Finite_face_iterator;
|
||||
typedef typename CT::Edge Edge;
|
||||
CT ct;
|
||||
CGAL::Unique_hash_map<Face_handle, bool> visited;
|
||||
CGAL::Unique_hash_map<CTVertex_handle, typename Nef::Vertex_const_handle> ctv2v;
|
||||
Finite_face_iterator fi;
|
||||
typename Nef::Plane_3 supporting_plane;
|
||||
|
||||
public:
|
||||
Triangulation_handler2(typename Nef::Halffacet_const_handle f) :
|
||||
visited(false), supporting_plane(f->plane()) {
|
||||
|
||||
typename Nef::Halffacet_cycle_const_iterator fci;
|
||||
for(fci=f->facet_cycles_begin(); fci!=f->facet_cycles_end(); ++fci) {
|
||||
if(fci.is_shalfedge()) {
|
||||
typename Nef::SHalfedge_around_facet_const_circulator sfc(fci), send(sfc);
|
||||
CGAL_For_all(sfc,send) {
|
||||
CGAL_NEF_TRACEN(" insert point" << sfc->source()->source()->point());
|
||||
CTVertex_handle ctv = ct.insert(sfc->source()->source()->point());
|
||||
ctv2v[ctv] = sfc->source()->source();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(fci=f->facet_cycles_begin(); fci!=f->facet_cycles_end(); ++fci) {
|
||||
if(fci.is_shalfedge()) {
|
||||
typename Nef::SHalfedge_around_facet_const_circulator sfc(fci), send(sfc);
|
||||
CGAL_For_all(sfc,send) {
|
||||
CGAL_NEF_TRACEN(" insert constraint" << sfc->source()->source()->point()
|
||||
<< "->" << sfc->source()->twin()->source()->point());
|
||||
ct.insert_constraint(sfc->source()->source()->point(),
|
||||
sfc->source()->twin()->source()->point());
|
||||
}
|
||||
}
|
||||
}
|
||||
CGAL_assertion(ct.is_valid());
|
||||
|
||||
CGAL_NEF_TRACEN("number of finite triangles " << ct.number_of_faces());
|
||||
|
||||
typename CT::Face_handle infinite = ct.infinite_face();
|
||||
typename CT::Vertex_handle ctv = infinite->vertex(1);
|
||||
if(ct.is_infinite(ctv)) ctv = infinite->vertex(2);
|
||||
CGAL_assertion(!ct.is_infinite(ctv));
|
||||
|
||||
typename CT::Face_handle opposite;
|
||||
typename CT::Face_circulator vc(ctv,infinite);
|
||||
do { opposite = vc++;
|
||||
} while(!ct.is_constrained(typename CT::Edge(vc,vc->index(opposite))));
|
||||
typename CT::Face_handle first = vc;
|
||||
|
||||
CGAL_assertion(!ct.is_infinite(first));
|
||||
traverse_triangulation(first, first->index(opposite));
|
||||
|
||||
fi = ct.finite_faces_begin();
|
||||
}
|
||||
|
||||
void traverse_triangulation(Face_handle f, int parent) {
|
||||
visited[f] = true;
|
||||
if(!ct.is_constrained(Edge(f,ct.cw(parent))) && !visited[f->neighbor(ct.cw(parent))]) {
|
||||
Face_handle child(f->neighbor(ct.cw(parent)));
|
||||
traverse_triangulation(child, child->index(f));
|
||||
}
|
||||
if(!ct.is_constrained(Edge(f,ct.ccw(parent))) && !visited[f->neighbor(ct.ccw(parent))]) {
|
||||
Face_handle child(f->neighbor(ct.ccw(parent)));
|
||||
traverse_triangulation(child, child->index(f));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Triangle_3>
|
||||
bool get_next_triangle(Triangle_3& tr) {
|
||||
while(fi != ct.finite_faces_end() && visited[fi] == false) ++fi;
|
||||
if(fi == ct.finite_faces_end()) return false;
|
||||
tr = Triangle_3(fi->vertex(0)->point(), fi->vertex(1)->point(), fi->vertex(2)->point());
|
||||
++fi;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool same_orientation(typename Nef::Plane_3 p1) const {
|
||||
if(p1.a() != 0)
|
||||
return CGAL::sign(p1.a()) == CGAL::sign(supporting_plane.a());
|
||||
if(p1.b() != 0)
|
||||
return CGAL::sign(p1.b()) == CGAL::sign(supporting_plane.b());
|
||||
return CGAL::sign(p1.c()) == CGAL::sign(supporting_plane.c());
|
||||
}
|
||||
|
||||
template<typename PIB, typename Index>
|
||||
void handle_triangles(PIB& pib, Index& VI) {
|
||||
while(fi != ct.finite_faces_end() && visited[fi] == false) ++fi;
|
||||
while(fi != ct.finite_faces_end()) {
|
||||
typename Nef::Plane_3 plane(fi->vertex(0)->point(),
|
||||
fi->vertex(1)->point(),
|
||||
fi->vertex(2)->point());
|
||||
pib.begin_facet();
|
||||
if(same_orientation(plane)) {
|
||||
pib.add_vertex_to_facet(VI[ctv2v[fi->vertex(0)]]);
|
||||
pib.add_vertex_to_facet(VI[ctv2v[fi->vertex(1)]]);
|
||||
pib.add_vertex_to_facet(VI[ctv2v[fi->vertex(2)]]);
|
||||
} else {
|
||||
pib.add_vertex_to_facet(VI[ctv2v[fi->vertex(0)]]);
|
||||
pib.add_vertex_to_facet(VI[ctv2v[fi->vertex(2)]]);
|
||||
pib.add_vertex_to_facet(VI[ctv2v[fi->vertex(1)]]);
|
||||
}
|
||||
pib.end_facet();
|
||||
do {
|
||||
++fi;
|
||||
} while(fi != ct.finite_faces_end() && visited[fi] == false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <class HDS, typename Kernel, typename Nef>
|
||||
class Build_polyhedron : public CGAL::Modifier_base<HDS> {
|
||||
public:
|
||||
bool error; // added for OpenSCAD
|
||||
class Visitor {
|
||||
typedef typename CGAL::Projection_traits_xy_3<Kernel> XY;
|
||||
typedef typename CGAL::Projection_traits_yz_3<Kernel> YZ;
|
||||
typedef typename CGAL::Projection_traits_xz_3<Kernel> XZ;
|
||||
|
||||
const CGAL::Object_index<typename Nef::Vertex_const_iterator>& VI;
|
||||
CGAL::Polyhedron_incremental_builder_3<HDS>& B;
|
||||
const typename Nef::SNC_const_decorator& D;
|
||||
|
||||
public:
|
||||
bool error;//added for OpenSCAD
|
||||
Visitor(CGAL::Polyhedron_incremental_builder_3<HDS>& BB,
|
||||
const typename Nef::SNC_const_decorator& sd,
|
||||
CGAL::Object_index<typename Nef::Vertex_const_iterator>& vi) : VI(vi), B(BB), D(sd), error(false) {}
|
||||
|
||||
void visit(typename Nef::Halffacet_const_handle opposite_facet) {
|
||||
|
||||
CGAL_NEF_TRACEN("Build_polyhedron: visit facet " << opposite_facet->plane());
|
||||
|
||||
CGAL_assertion(Nef::Infi_box::is_standard(opposite_facet->plane()));
|
||||
|
||||
typename Nef::SHalfedge_const_handle se;
|
||||
typename Nef::Halffacet_cycle_const_iterator fc;
|
||||
|
||||
typename Nef::Halffacet_const_handle f = opposite_facet->twin();
|
||||
|
||||
typename Nef::SHalfedge_around_facet_const_circulator
|
||||
sfc1(f->facet_cycles_begin()), sfc2(sfc1);
|
||||
|
||||
if(++f->facet_cycles_begin() != f->facet_cycles_end() ||
|
||||
++(++(++sfc1)) != sfc2) {
|
||||
typename Nef::Vector_3 orth = f->plane().orthogonal_vector();
|
||||
int c = CGAL::abs(orth[0]) > CGAL::abs(orth[1]) ? 0 : 1;
|
||||
c = CGAL::abs(orth[2]) > CGAL::abs(orth[c]) ? 2 : c;
|
||||
|
||||
try{ // added for OpenSCAD
|
||||
if(c == 0) {
|
||||
Triangulation_handler2<YZ,Nef> th(f);
|
||||
th.handle_triangles(B, VI);
|
||||
} else if(c == 1) {
|
||||
Triangulation_handler2<XZ,Nef> th(f);
|
||||
th.handle_triangles(B, VI);
|
||||
} else if(c == 2) {
|
||||
Triangulation_handler2<XY,Nef> th(f);
|
||||
th.handle_triangles(B, VI);
|
||||
} else
|
||||
CGAL_error_msg( "wrong value");
|
||||
} catch(...) { // added for OpenSCAD
|
||||
PRINT("ERROR: CGAL NefPolyhedron Triangulation failed"); // added for OpenSCAD
|
||||
this->error=true; //added for OpenSCAD
|
||||
} // added for OpenSCAD
|
||||
} else {
|
||||
|
||||
B.begin_facet();
|
||||
fc = f->facet_cycles_begin();
|
||||
se = typename Nef::SHalfedge_const_handle(fc);
|
||||
CGAL_assertion(se!=0);
|
||||
typename Nef::SHalfedge_around_facet_const_circulator hc_start(se);
|
||||
typename Nef::SHalfedge_around_facet_const_circulator hc_end(hc_start);
|
||||
CGAL_For_all(hc_start,hc_end) {
|
||||
CGAL_NEF_TRACEN(" add vertex " << hc_start->source()->center_vertex()->point());
|
||||
B.add_vertex_to_facet(VI[hc_start->source()->center_vertex()]);
|
||||
}
|
||||
B.end_facet();
|
||||
}
|
||||
}
|
||||
|
||||
void visit(typename Nef::SFace_const_handle) {}
|
||||
void visit(typename Nef::Halfedge_const_handle) {}
|
||||
void visit(typename Nef::Vertex_const_handle) {}
|
||||
void visit(typename Nef::SHalfedge_const_handle) {}
|
||||
void visit(typename Nef::SHalfloop_const_handle) {}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
const typename Nef::SNC_const_decorator& scd;
|
||||
CGAL::Object_index<typename Nef::Vertex_const_iterator> VI;
|
||||
|
||||
Build_polyhedron(const typename Nef::SNC_const_decorator& s) : error(false),
|
||||
scd(s), VI(s.vertices_begin(),s.vertices_end(),'V') {}
|
||||
|
||||
void operator()( HDS& hds) {
|
||||
CGAL::Polyhedron_incremental_builder_3<HDS> B(hds, true);
|
||||
|
||||
int skip_volumes;
|
||||
if(Nef::Infi_box::extended_kernel()) {
|
||||
B.begin_surface(scd.number_of_vertices()-8,
|
||||
scd.number_of_facets()-6,
|
||||
scd.number_of_edges()-12);
|
||||
skip_volumes = 2;
|
||||
}
|
||||
else {
|
||||
B.begin_surface(scd.number_of_vertices(),
|
||||
2*scd.number_of_vertices()-4,
|
||||
3*scd.number_of_vertices()-6);
|
||||
skip_volumes = 1;
|
||||
}
|
||||
|
||||
int vertex_index = 0;
|
||||
typename Nef::Vertex_const_iterator v;
|
||||
CGAL_forall_vertices(v,scd) {
|
||||
if(Nef::Infi_box::is_standard(v->point())) {
|
||||
VI[v]=vertex_index++;
|
||||
B.add_vertex(v->point());
|
||||
}
|
||||
}
|
||||
|
||||
Visitor V(B,scd,VI);
|
||||
typename Nef::Volume_const_handle c;
|
||||
CGAL_forall_volumes(c,scd)
|
||||
if(skip_volumes-- <= 0) {
|
||||
scd.visit_shell_objects(typename Nef:: SFace_const_handle(c->shells_begin()),V);
|
||||
}
|
||||
B.end_surface();
|
||||
this->error=B.error()||V.error; // added for OpenSCAD
|
||||
if (B.error()) B.rollback(); // added for OpenSCAD
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename Kernel>
|
||||
bool convert_to_Polyhedron( const CGAL::Nef_polyhedron_3<Kernel> &N, CGAL::Polyhedron_3<Kernel> &P )
|
||||
{
|
||||
// several lines here added for OpenSCAD
|
||||
typedef typename CGAL::Nef_polyhedron_3<Kernel> Nef3;
|
||||
typedef typename CGAL::Polyhedron_3<Kernel> Polyhedron;
|
||||
typedef typename Polyhedron::HalfedgeDS HalfedgeDS;
|
||||
CGAL_precondition(N.is_simple());
|
||||
P.clear();
|
||||
Build_polyhedron<HalfedgeDS,Kernel,Nef3> bp(N);
|
||||
P.delegate(bp);
|
||||
return bp.error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} //namespace nefworkaround
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -96,16 +96,23 @@ PolySet *CGAL_Nef_polyhedron::convertToPolyset()
|
|||
}
|
||||
else if (this->dim == 3) {
|
||||
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||
ps = new PolySet();
|
||||
bool err = true;
|
||||
std::string errmsg("");
|
||||
CGAL_Polyhedron P;
|
||||
try {
|
||||
ps = new PolySet();
|
||||
CGAL_Polyhedron P;
|
||||
this->p3->convert_to_Polyhedron(P);
|
||||
bool err = createPolySetFromPolyhedron(P, *ps);
|
||||
if (err) delete ps;
|
||||
err = nefworkaround::convert_to_Polyhedron<CGAL_Kernel3>( *(this->p3), P );
|
||||
//this->p3->convert_to_Polyhedron(P);
|
||||
}
|
||||
catch (const CGAL::Precondition_exception &e) {
|
||||
delete ps;
|
||||
PRINTB("CGAL error in CGAL_Nef_polyhedron::convertToPolyset(): %s", e.what());
|
||||
catch (const CGAL::Failure_exception &e) {
|
||||
err = true;
|
||||
errmsg = std::string(e.what());
|
||||
}
|
||||
if (!err) err = createPolySetFromPolyhedron(P, *ps);
|
||||
if (err) {
|
||||
PRINT("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed.");
|
||||
if (errmsg!="") PRINTB("ERROR: %s",errmsg);
|
||||
delete ps; ps = NULL;
|
||||
}
|
||||
CGAL::set_error_behaviour(old_behaviour);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ void CocoaUtils::endApplication()
|
|||
object:nil];
|
||||
}
|
||||
|
||||
void CocoaUtils::nslog(const std::string &str, void *userdata)
|
||||
void CocoaUtils::nslog(const std::string &str, void * /* userdata */)
|
||||
{
|
||||
NSLog([NSString stringWithUTF8String: str.c_str()]);
|
||||
NSLog(@"%s", str.c_str());
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include "PlatformUtils.h"
|
||||
#include "boosty.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
bool PlatformUtils::createLibraryPath()
|
||||
{
|
||||
std::string path = PlatformUtils::libraryPath();
|
||||
|
@ -114,6 +116,7 @@ std::string PlatformUtils::info()
|
|||
<< "\nOpenCSG version: " << OPENCSG_VERSION_STRING
|
||||
<< "\nQt version: " << qtVersion
|
||||
<< "\nMingW build: " << mingwstatus
|
||||
<< "\nGLib version: " << GLIB_MAJOR_VERSION << "." << GLIB_MINOR_VERSION << "." << GLIB_MICRO_VERSION
|
||||
<< "\nOPENSCADPATH: " << getenv("OPENSCADPATH") << "\n"
|
||||
;
|
||||
return s.str();
|
||||
|
|
|
@ -455,12 +455,21 @@ PolySet *PolySetCGALEvaluator::rotateDxfData(const RotateExtrudeNode &node, DxfD
|
|||
|
||||
for (size_t i = 0; i < dxf.paths.size(); i++)
|
||||
{
|
||||
double min_x = 0;
|
||||
double max_x = 0;
|
||||
for (size_t j = 0; j < dxf.paths[i].indices.size(); j++) {
|
||||
max_x = fmax(max_x, dxf.points[dxf.paths[i].indices[j]][0]);
|
||||
double point_x = dxf.points[dxf.paths[i].indices[j]][0];
|
||||
min_x = fmin(min_x, point_x);
|
||||
max_x = fmax(max_x, point_x);
|
||||
|
||||
if ((max_x - min_x) > max_x && (max_x - min_x) > fabs(min_x)) {
|
||||
PRINTB("ERROR: all points for rotate_extrude() must have the same X coordinate sign (range is %.2f -> %.2f)", min_x % max_x);
|
||||
delete ps;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int fragments = get_fragments_from_r(max_x, node.fn, node.fs, node.fa);
|
||||
int fragments = get_fragments_from_r(max_x-min_x, node.fn, node.fs, node.fa);
|
||||
|
||||
double ***points;
|
||||
points = new double**[fragments];
|
||||
|
|
|
@ -27,6 +27,7 @@ using boost::uintmax_t;
|
|||
#include <CGAL/Cartesian.h>
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/Nef_polyhedron_3.h>
|
||||
#include <CGAL_Nef3_workaround.h>
|
||||
#include <CGAL/IO/Polyhedron_iostream.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Polygon_2.h>
|
||||
|
|
|
@ -42,7 +42,12 @@ void export_stl(CGAL_Nef_polyhedron *root_N, std::ostream &output)
|
|||
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||
try {
|
||||
CGAL_Polyhedron P;
|
||||
root_N->p3->convert_to_Polyhedron(P);
|
||||
//root_N->p3->convert_to_Polyhedron(P);
|
||||
bool err = nefworkaround::convert_to_Polyhedron<CGAL_Kernel3>( *(root_N->p3), P );
|
||||
if (err) {
|
||||
PRINT("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed");
|
||||
return;
|
||||
}
|
||||
|
||||
typedef CGAL_Polyhedron::Vertex Vertex;
|
||||
typedef CGAL_Polyhedron::Vertex_const_iterator VCI;
|
||||
|
@ -114,6 +119,9 @@ void export_stl(CGAL_Nef_polyhedron *root_N, std::ostream &output)
|
|||
catch (const CGAL::Assertion_exception &e) {
|
||||
PRINTB("CGAL error in CGAL_Nef_polyhedron3::convert_to_Polyhedron(): %s", e.what());
|
||||
}
|
||||
catch (...) {
|
||||
PRINT("CGAL unknown error in CGAL_Nef_polyhedron3::convert_to_Polyhedron()");
|
||||
}
|
||||
CGAL::set_error_behaviour(old_behaviour);
|
||||
}
|
||||
|
||||
|
|
49
src/func.cc
|
@ -45,6 +45,8 @@
|
|||
|
||||
#include <boost/random/mersenne_twister.hpp>
|
||||
#include <boost/random/uniform_real.hpp>
|
||||
/*Unicode support for string lengths and array accesses*/
|
||||
#include <glib.h>
|
||||
|
||||
#ifdef __WIN32__
|
||||
#include <process.h>
|
||||
|
@ -306,7 +308,11 @@ Value builtin_length(const Context *, const EvalContext *evalctx)
|
|||
{
|
||||
if (evalctx->numArgs() == 1) {
|
||||
if (evalctx->getArgValue(0).type() == Value::VECTOR) return Value(int(evalctx->getArgValue(0).toVector().size()));
|
||||
if (evalctx->getArgValue(0).type() == Value::STRING) return Value(int(evalctx->getArgValue(0).toString().size()));
|
||||
if (evalctx->getArgValue(0).type() == Value::STRING) {
|
||||
//Unicode glyph count for the length -- rather than the string (num. of bytes) length.
|
||||
std::string text = evalctx->getArgValue(0).toString();
|
||||
return Value(int( g_utf8_strlen( text.c_str(), text.size() ) ));
|
||||
}
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
|
@ -380,10 +386,17 @@ Value builtin_lookup(const Context *, const EvalContext *evalctx)
|
|||
num_returns_per_match : int;
|
||||
index_col_num : int;
|
||||
|
||||
The search string and searched strings can be unicode strings.
|
||||
Examples:
|
||||
Index values return as list:
|
||||
search("a","abcdabcd");
|
||||
- returns [0,4]
|
||||
- returns [0]
|
||||
search("Л","Л"); //A unicode string
|
||||
- returns [0]
|
||||
search("🂡aЛ","a🂡Л🂡a🂡Л🂡a",0);
|
||||
- returns [[1,3,5,7],[0,4,8],[2,6]]
|
||||
search("a","abcdabcd",0); //Search up to all matches
|
||||
- returns [[0,4]]
|
||||
search("a","abcdabcd",1);
|
||||
- returns [0]
|
||||
search("e","abcdabcd",1);
|
||||
|
@ -433,16 +446,25 @@ Value builtin_search(const Context *, const EvalContext *evalctx)
|
|||
}
|
||||
} else if (findThis.type() == Value::STRING) {
|
||||
unsigned int searchTableSize;
|
||||
if (searchTable.type() == Value::STRING) searchTableSize = searchTable.toString().size();
|
||||
else searchTableSize = searchTable.toVector().size();
|
||||
for (size_t i = 0; i < findThis.toString().size(); i++) {
|
||||
//Unicode glyph count for the length
|
||||
unsigned int findThisSize = g_utf8_strlen( findThis.toString().c_str(), findThis.toString().size() );
|
||||
if (searchTable.type() == Value::STRING) {
|
||||
searchTableSize = g_utf8_strlen( searchTable.toString().c_str(), searchTable.toString().size() );
|
||||
} else {
|
||||
searchTableSize = searchTable.toVector().size();
|
||||
}
|
||||
for (size_t i = 0; i < findThisSize; i++) {
|
||||
unsigned int matchCount = 0;
|
||||
Value::VectorType resultvec;
|
||||
for (size_t j = 0; j < searchTableSize; j++) {
|
||||
if ((searchTable.type() == Value::VECTOR &&
|
||||
findThis.toString()[i] == searchTable.toVector()[j].toVector()[index_col_num].toString()[0]) ||
|
||||
(searchTable.type() == Value::STRING &&
|
||||
findThis.toString()[i] == searchTable.toString()[j])) {
|
||||
gchar* ptr_ft = g_utf8_offset_to_pointer(findThis.toString().c_str(), i);
|
||||
gchar* ptr_st = NULL;
|
||||
if(searchTable.type() == Value::VECTOR) {
|
||||
ptr_st = g_utf8_offset_to_pointer(searchTable.toVector()[j].toVector()[index_col_num].toString().c_str(), 0);
|
||||
} else if(searchTable.type() == Value::STRING){
|
||||
ptr_st = g_utf8_offset_to_pointer(searchTable.toString().c_str(), j);
|
||||
}
|
||||
if( (ptr_ft) && (ptr_st) && (g_utf8_get_char(ptr_ft) == g_utf8_get_char(ptr_st)) ) {
|
||||
Value resultValue((double(j)));
|
||||
matchCount++;
|
||||
if (num_returns_per_match == 1) {
|
||||
|
@ -454,7 +476,14 @@ Value builtin_search(const Context *, const EvalContext *evalctx)
|
|||
if (num_returns_per_match > 1 && matchCount >= num_returns_per_match) break;
|
||||
}
|
||||
}
|
||||
if (matchCount == 0) PRINTB(" WARNING: search term not found: \"%s\"", findThis.toString()[i]);
|
||||
if (matchCount == 0) {
|
||||
gchar* ptr_ft = g_utf8_offset_to_pointer(findThis.toString().c_str(), i);
|
||||
gchar utf8_of_cp[6] = ""; //A buffer for a single unicode character to be copied into
|
||||
if(ptr_ft) {
|
||||
g_utf8_strncpy( utf8_of_cp, ptr_ft, 1 );
|
||||
}
|
||||
PRINTB(" WARNING: search term not found: \"%s\"", utf8_of_cp );
|
||||
}
|
||||
if (num_returns_per_match == 0 || num_returns_per_match > 1) {
|
||||
returnvec.push_back(Value(resultvec));
|
||||
}
|
||||
|
|
|
@ -162,7 +162,7 @@ void ModuleContext::dump(const AbstractModule *mod, const ModuleInstantiation *i
|
|||
#endif
|
||||
|
||||
FileContext::FileContext(const class FileModule &module, const Context *parent)
|
||||
: usedlibs(module.usedlibs), ModuleContext(parent)
|
||||
: ModuleContext(parent), usedlibs(module.usedlibs)
|
||||
{
|
||||
if (!module.modulePath().empty()) this->document_path = module.modulePath();
|
||||
}
|
||||
|
|
|
@ -474,6 +474,13 @@ bool QtUseGUI()
|
|||
|
||||
int gui(vector<string> &inputFiles, const fs::path &original_path, int argc, char ** argv)
|
||||
{
|
||||
#ifdef Q_OS_MACX
|
||||
if (QSysInfo::MacintoshVersion > QSysInfo::MV_10_8) {
|
||||
// fix Mac OS X 10.9 (mavericks) font issue
|
||||
// https://bugreports.qt-project.org/browse/QTBUG-32789
|
||||
QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande");
|
||||
}
|
||||
#endif
|
||||
QApplication app(argc, argv, true); //useGUI);
|
||||
#ifdef Q_WS_MAC
|
||||
app.installEventFilter(new EventFilter(&app));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#if defined(__APPLE__) && defined(__GNUC__)
|
||||
#if defined(__APPLE__) && defined(__GNUC__) && !defined(__clang__)
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
|
18
src/value.cc
|
@ -36,6 +36,8 @@
|
|||
#include <boost/format.hpp>
|
||||
#include "boost-utils.h"
|
||||
#include "boosty.h"
|
||||
/*Unicode support for string lengths and array accesses*/
|
||||
#include <glib.h>
|
||||
|
||||
std::ostream &operator<<(std::ostream &stream, const Filename &filename)
|
||||
{
|
||||
|
@ -579,14 +581,28 @@ Value Value::operator-() const
|
|||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* bracket operation [] detecting multi-byte unicode.
|
||||
* If the string is multi-byte unicode then the index will offset to the character (2 or 4 byte) and not to the byte.
|
||||
* A 'normal' string with byte chars are a subset of unicode and still work.
|
||||
*/
|
||||
class bracket_visitor : public boost::static_visitor<Value>
|
||||
{
|
||||
public:
|
||||
Value operator()(const std::string &str, const double &idx) const {
|
||||
int i = int(idx);
|
||||
Value v;
|
||||
//Check that the index is positive and less than the size in bytes
|
||||
if ((i >= 0) && (i < (int)str.size())) {
|
||||
v = Value(str[int(idx)]);
|
||||
//Ensure character (not byte) index is inside the character/glyph array
|
||||
if( (unsigned) i < g_utf8_strlen( str.c_str(), str.size() ) ) {
|
||||
gchar utf8_of_cp[6] = ""; //A buffer for a single unicode character to be copied into
|
||||
gchar* ptr = g_utf8_offset_to_pointer(str.c_str(), i);
|
||||
if(ptr) {
|
||||
g_utf8_strncpy(utf8_of_cp, ptr, 1);
|
||||
}
|
||||
v = std::string(utf8_of_cp);
|
||||
}
|
||||
// std::cout << "bracket_visitor: " << v << "\n";
|
||||
}
|
||||
return v;
|
||||
|
|
|
@ -113,7 +113,7 @@ a time, to avoid confusion.
|
|||
+ __GNUC_MINOR__ * 100 \
|
||||
+ __GNUC_PATCHLEVEL__)
|
||||
#if GCC_VERSION == 40802
|
||||
#error OpenSCAD isn't compatible with gcc 4.8.2. Please try a different version
|
||||
#warning "gcc 4.8.2 contains a bug causing a crash in CGAL."
|
||||
#endif
|
||||
|
||||
#endif // OPENSCAD_SKIP_VERSION_CHECK
|
||||
|
|
|
@ -11,10 +11,35 @@ module polyhedrons() {
|
|||
translate([4,0,0])
|
||||
polyhedron(points = [[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]],
|
||||
triangles = [[0,2,4],[0,5,2],[0,4,3],[0,3,5],[1,4,2],[1,2,5],[1,3,4], [1,5,3]]);
|
||||
|
||||
// Containing concave polygons
|
||||
translate([6,0,0])
|
||||
polyhedron(points=[
|
||||
[-0.8,-0.8,-0.8],
|
||||
[0,0,-0.8],
|
||||
[0.8,-0.8,-0.8],
|
||||
[0.8,0.8,-0.8],
|
||||
[-0.8,0.8,-0.8],
|
||||
[-0.8,-0.8,0.8],
|
||||
[0,0,0.8],
|
||||
[0.8,-0.8,0.8],
|
||||
[0.8,0.8,0.8],
|
||||
[-0.8,0.8,0.8],
|
||||
],
|
||||
triangles=[
|
||||
[0,1,2,3,4],
|
||||
[5,6,1,0],
|
||||
[6,7,2,1],
|
||||
[7,8,3,2],
|
||||
[8,9,4,3],
|
||||
[9,5,0,4],
|
||||
[9,8,7,6,5],
|
||||
], convexity=2);
|
||||
}
|
||||
|
||||
polyhedrons();
|
||||
translate([0,2,0]) difference() {
|
||||
polyhedrons();
|
||||
translate([2,0,2]) cube([8,3,3], center=true);
|
||||
translate([3,0,2]) cube([8,3,3], center=true);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,3 +32,6 @@ translate([50,50,0]) {
|
|||
// Minimal $fn
|
||||
translate([0,-60,0]) rotate_extrude($fn=1) translate([20,0,0]) circle(r=10,$fn=1);
|
||||
|
||||
// Object in negative X
|
||||
translate([0,60,0]) rotate_extrude() translate([-20,0]) square(10);
|
||||
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
//Test search with unicode strings
|
||||
|
||||
//Helper function that pretty prints our search test
|
||||
//Expected result is checked against execution of a search() invocation and OK/FAIL is indicated
|
||||
module test_search_and_echo( exp_res, search_to_find, search_to_search, search_up_to_num_matches = undef)
|
||||
{
|
||||
if(undef != search_up_to_num_matches)
|
||||
{
|
||||
assign( test_res = search(search_to_find, search_to_search, search_up_to_num_matches) )
|
||||
echo(str("Expect ", exp_res, " for search(", search_to_find, ", ", search_to_search, ", ", search_up_to_num_matches, ")=", test_res, ". ", (exp_res == test_res)?"OK":"FAIL" ));
|
||||
}
|
||||
else
|
||||
{
|
||||
assign( test_res = search(search_to_find, search_to_search) )
|
||||
echo(str("Expect ", exp_res, " for search(", search_to_find, ", ", search_to_search, ")=", test_res, ". ", (exp_res == test_res)?"OK":"FAIL" ));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//"Normal" text for comparison
|
||||
echo ("----- Lookup of 1 byte into 1 byte");
|
||||
//Hits - up_to_count 1
|
||||
test_search_and_echo( [0], "a","aaaa" );
|
||||
test_search_and_echo( [0], "a","aaaa",1 );
|
||||
test_search_and_echo( [0,0], "aa","aaaa" );
|
||||
test_search_and_echo( [0,0], "aa","aaaa",1 );
|
||||
|
||||
|
||||
//Hits - up to count 1+ (incl 0 == all)
|
||||
test_search_and_echo( [[0,1,2,3]] , "a","aaaa",0 );
|
||||
test_search_and_echo( [[0,1]], "a","aaaa",2 );
|
||||
test_search_and_echo( [[0,1,2]], "a","aaaa",3 );
|
||||
test_search_and_echo( [[0,1,2,3]] , "a","aaaa",4 );
|
||||
test_search_and_echo( [[0,1,2,3],[0,1,2,3]] , "aa","aaaa",0 );
|
||||
//Misses
|
||||
test_search_and_echo( [], "b","aaaa" );
|
||||
test_search_and_echo( [], "b","aaaa",1 );
|
||||
test_search_and_echo( [[]], "b","aaaa",0 );
|
||||
test_search_and_echo( [[]], "b","aaaa",2 );
|
||||
|
||||
test_search_and_echo( [], "bb","aaaa" );
|
||||
test_search_and_echo( [], "bb","aaaa",1 );
|
||||
test_search_and_echo( [[],[]], "bb","aaaa",0 );
|
||||
test_search_and_echo( [[],[]], "bb","aaaa",2 );
|
||||
//Miss - empties
|
||||
test_search_and_echo( [], "","aaaa" );
|
||||
test_search_and_echo( [], "","" );
|
||||
test_search_and_echo( [], "a","" );
|
||||
|
||||
|
||||
//Unicode tests
|
||||
echo ("----- Lookup of multi-byte into 1 byte");
|
||||
test_search_and_echo( [], "Л","aaaa" );
|
||||
test_search_and_echo( [], "🂡","aaaa" );
|
||||
test_search_and_echo( [[]], "Л","aaaa",0 );
|
||||
test_search_and_echo( [[]], "🂡","aaaa",0 );
|
||||
|
||||
test_search_and_echo( [], "ЛЛ","aaaa" );
|
||||
test_search_and_echo( [], "🂡🂡","aaaa" );
|
||||
test_search_and_echo( [[],[]], "ЛЛ","aaaa",0 );
|
||||
test_search_and_echo( [[],[]], "🂡🂡","aaaa",0 );
|
||||
|
||||
echo ("----- Lookup of 1-byte into multi-byte");
|
||||
test_search_and_echo( [] , "a","ЛЛЛЛ" );
|
||||
test_search_and_echo( [] , "a","🂡🂡🂡🂡" );
|
||||
test_search_and_echo( [] , "a","ЛЛЛЛ",1 );
|
||||
|
||||
test_search_and_echo( [[]] , "a","🂡🂡🂡🂡",0 );
|
||||
test_search_and_echo( [[]] , "a","🂡🂡🂡🂡",2 );
|
||||
|
||||
echo ("----- Lookup of 1-byte into mixed multi-byte");
|
||||
test_search_and_echo( [0], "a","aЛaЛaЛaЛa" );
|
||||
test_search_and_echo( [0], "a","a🂡a🂡a🂡a🂡a" );
|
||||
test_search_and_echo( [0], "a","a🂡Л🂡a🂡Л🂡a" );
|
||||
|
||||
test_search_and_echo( [[0,2,4,6,8]], "a","aЛaЛaЛaЛa",0 );
|
||||
test_search_and_echo( [[0,2,4,6,8]], "a","a🂡a🂡a🂡a🂡a", 0 );
|
||||
test_search_and_echo( [[0,4,8]] , "a","a🂡Л🂡a🂡Л🂡a", 0 );
|
||||
|
||||
echo ("----- Lookup of 2-byte into 2-byte");
|
||||
test_search_and_echo( [0] , "Л","ЛЛЛЛ" );
|
||||
test_search_and_echo( [[0,1,2,3]] , "Л","ЛЛЛЛ",0 );
|
||||
|
||||
echo ("----- Lookup of 2-byte into 4-byte");
|
||||
test_search_and_echo( [] , "Л","🂡🂡🂡🂡" );
|
||||
|
||||
echo ("----- Lookup of 4-byte into 4-byte");
|
||||
test_search_and_echo( [0] , "🂡","🂡🂡🂡🂡" );
|
||||
test_search_and_echo( [[0,1,2,3]], "🂡","🂡🂡🂡🂡",0 );
|
||||
|
||||
echo ("----- Lookup of 4-byte into 2-byte");
|
||||
test_search_and_echo( [] , "🂡","ЛЛЛЛ" );
|
||||
|
||||
echo ("----- Lookup of 2-byte into mixed multi-byte");
|
||||
test_search_and_echo( [1] , "Л","aЛaЛaЛaЛa",1 );
|
||||
test_search_and_echo( [] , "Л","a🂡a🂡a🂡a🂡a", 1 );
|
||||
test_search_and_echo( [2] , "Л","a🂡Л🂡a🂡Л🂡a", 1 );
|
||||
|
||||
test_search_and_echo( [[1,3,5,7]] , "Л","aЛaЛaЛaЛa",0 );
|
||||
test_search_and_echo( [[]] , "Л","a🂡a🂡a🂡a🂡a", 0 );
|
||||
test_search_and_echo( [[2,6]] , "Л","a🂡Л🂡a🂡Л🂡a", 0 );
|
||||
|
||||
echo ("----- Lookup of 4-byte into mixed multi-byte");
|
||||
test_search_and_echo( [] , "🂡","aЛaЛaЛaЛa",1 );
|
||||
test_search_and_echo( [1] , "🂡","a🂡a🂡a🂡a🂡a", 1 );
|
||||
|
||||
test_search_and_echo( [[]] , "🂡","aЛaЛaЛaЛa",0 );
|
||||
test_search_and_echo( [[1,3,5,7]] , "🂡","a🂡a🂡a🂡a🂡a", 0 );
|
||||
test_search_and_echo( [[1,3,5,7]] , "🂡","a🂡Л🂡a🂡Л🂡a", 0 );
|
||||
|
||||
echo ("----- Lookup of mixed multi-byte into mixed multi-byte");
|
||||
test_search_and_echo( [[0,2,4,6,8],[1,3,5,7],[]], "aЛ🂡","aЛaЛaЛaЛa",0 );
|
||||
test_search_and_echo( [[0,2,4,6,8],[],[1,3,5,7]], "aЛ🂡","a🂡a🂡a🂡a🂡a", 0 );
|
||||
test_search_and_echo( [[0,4,8],[2,6],[1,3,5,7]] , "aЛ🂡","a🂡Л🂡a🂡Л🂡a", 0 );
|
||||
test_search_and_echo( [[1,3,5,7],[0,4,8],[2,6]] , "🂡aЛ","a🂡Л🂡a🂡Л🂡a", 0 );
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
//Test length reporting
|
||||
text_1bytes_len = "1234";
|
||||
text_2bytes_len = "ЛЛЛЛ";
|
||||
text_4bytes_len = "🂡🂱🃁🃑";
|
||||
|
||||
echo( "text_1bytes_len = ", text_1bytes_len, " len = ", len(text_1bytes_len) );
|
||||
echo( "text_2bytes_len = ", text_2bytes_len, " len = ", len(text_2bytes_len) );
|
||||
echo( "text_4bytes_len = ", text_4bytes_len, " len = ", len(text_4bytes_len) );
|
||||
|
||||
//Test how well arrays of unicode string are accessed.
|
||||
|
||||
texts_array = [
|
||||
"DEADBEEF",
|
||||
"Ленивый рыжий кот",
|
||||
"كسول الزنجبيل القط",
|
||||
"懶惰的姜貓",
|
||||
"äöü ÄÖÜ ß",
|
||||
"😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏😐",
|
||||
"⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏",
|
||||
"🂡🂱🃁🃑",
|
||||
];
|
||||
|
||||
text_2bytes = "Ленивый рыжий кот";
|
||||
text_4bytes = "🂡🂱🃁🃑";
|
||||
|
||||
|
||||
//Test all the normal accesses
|
||||
for (text_array_idx = [0:(len(texts_array)-1)])
|
||||
{
|
||||
echo( "[", text_array_idx, "] = ", texts_array[text_array_idx], " of len=", len(texts_array[text_array_idx]), ":" );
|
||||
for (text_idx = [0:(len(texts_array[text_array_idx])-1)])
|
||||
{
|
||||
echo( " [", text_idx, ,"]=", texts_array[text_array_idx][text_idx] );
|
||||
}
|
||||
}
|
||||
|
||||
//Test one past the last element of (x-byte unicode). This will be one past the length but inside the char length of the string
|
||||
echo( "Past end of unicode only 2-byte ", text_2bytes[len(text_2bytes)] );
|
||||
echo( "Past end of unicode only 4-byte ", text_4bytes[len(text_4bytes)] );
|
||||
|
||||
//Test past the last element of (x-byte unicode). Outside both lengths.
|
||||
echo( "Past end of both 2-byte ", text_2bytes[ len(text_2bytes) * 2 ] );
|
||||
echo( "Past end of both 4-byte ", text_4bytes[ len(text_4bytes) * 4 ] );
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# instructions - see ../doc/testing.txt
|
||||
|
||||
# set(DEBUG_OSCD 1) # print debug info during cmake
|
||||
#set(DEBUG_OSCD 1) # print debug info during cmake
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3)
|
||||
|
@ -15,8 +15,15 @@ include(CMakeParseArguments.cmake)
|
|||
# Detect Lion and force gcc
|
||||
IF (APPLE)
|
||||
EXECUTE_PROCESS(COMMAND sw_vers -productVersion OUTPUT_VARIABLE MACOSX_VERSION)
|
||||
IF (NOT ${MACOSX_VERSION} VERSION_LESS "10.8.0")
|
||||
message("Detected Mountain Lion (10.8) or later")
|
||||
IF (NOT ${MACOSX_VERSION} VERSION_LESS "10.9.0")
|
||||
message("Detected Maverick (10.9) or later")
|
||||
set(CMAKE_C_COMPILER "clang")
|
||||
set(CMAKE_CXX_COMPILER "clang++")
|
||||
# Somehow, since we build dependencies for 10.7, we need to also build executables
|
||||
# for 10.7. This used to not be necessary, but since 10.9 it apparently is..
|
||||
SET(CMAKE_OSX_DEPLOYMENT_TARGET 10.7 CACHE STRING "Deployment target")
|
||||
ELSEIF (NOT ${MACOSX_VERSION} VERSION_LESS "10.8.0")
|
||||
message("Detected Mountain Lion (10.8)")
|
||||
set(CMAKE_C_COMPILER "clang")
|
||||
set(CMAKE_CXX_COMPILER "clang++")
|
||||
ELSEIF (NOT ${MACOSX_VERSION} VERSION_LESS "10.7.0")
|
||||
|
@ -359,10 +366,10 @@ if (NOT $ENV{CGALDIR} STREQUAL "")
|
|||
elseif (NOT $ENV{OPENSCAD_LIBRARIES} STREQUAL "")
|
||||
if (EXISTS "$ENV{OPENSCAD_LIBRARIES}/lib/CGAL")
|
||||
set(CGAL_DIR "$ENV{OPENSCAD_LIBRARIES}/lib/CGAL")
|
||||
set(CMAKE_MODULE_PATH "${CGAL_DIR}")
|
||||
set(CMAKE_MODULE_PATH "${CGAL_DIR}" ${CMAKE_MODULE_PATH})
|
||||
elseif (EXISTS "$ENV{OPENSCAD_LIBRARIES}/include/CGAL")
|
||||
set(CGAL_DIR "$ENV{OPENSCAD_LIBRARIES}")
|
||||
set(CMAKE_MODULE_PATH "${CGAL_DIR}")
|
||||
set(CMAKE_MODULE_PATH "${CGAL_DIR}" ${CMAKE_MODULE_PATH})
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "CGAL_DIR: " ${CGAL_DIR})
|
||||
|
@ -376,12 +383,40 @@ if("${CGAL_MAJOR_VERSION}.${CGAL_MINOR_VERSION}" VERSION_LESS 3.6)
|
|||
message(FATAL_ERROR "CGAL >= 3.6 required")
|
||||
endif()
|
||||
inclusion(CGAL_DIR CGAL_INCLUDE_DIRS)
|
||||
#Remove bad BOOST libraries from CGAL 3rd party dependencies when they don't exist (such as on 64-bit Ubuntu 13.10).
|
||||
#Libs of concern are /usr/lib/libboost_thread.so;/usr/lib/libboost_system.so;
|
||||
#Confirmed bug in CGAL @ https://bugs.launchpad.net/ubuntu/+source/cgal/+bug/1242111
|
||||
string(FIND "${CGAL_3RD_PARTY_LIBRARIES}" "/usr/lib/libboost_system.so" FIND_POSITION )
|
||||
if(NOT "-1" STREQUAL ${FIND_POSITION} )
|
||||
if(NOT EXISTS "/usr/lib/libboost_system.so")
|
||||
MESSAGE( STATUS "CGAL_3RD_PARTY_LIBRARIES:Removing non-existent /usr/lib/libboost_system.so" )
|
||||
string(REPLACE "/usr/lib/libboost_system.so" "" CGAL_3RD_PARTY_LIBRARIES ${CGAL_3RD_PARTY_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
string(FIND "${CGAL_3RD_PARTY_LIBRARIES}" "/usr/lib/libboost_thread.so" FIND_POSITION )
|
||||
if(NOT "-1" STREQUAL ${FIND_POSITION} )
|
||||
if(NOT EXISTS "/usr/lib/libboost_thread.so")
|
||||
MESSAGE( STATUS "CGAL_3RD_PARTY_LIBRARIES:Removing non-existent /usr/lib/libboost_thread.so" )
|
||||
string(REPLACE "/usr/lib/libboost_thread.so" "" CGAL_3RD_PARTY_LIBRARIES ${CGAL_3RD_PARTY_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(${CMAKE_CXX_COMPILER} MATCHES ".*clang.*" AND NOT ${CGAL_CXX_FLAGS_INIT} STREQUAL "" )
|
||||
string(REPLACE "-frounding-math" "" CGAL_CXX_FLAGS_INIT ${CGAL_CXX_FLAGS_INIT})
|
||||
string(REPLACE "--param=ssp-buffer-size=4" "" CGAL_CXX_FLAGS_INIT ${CGAL_CXX_FLAGS_INIT})
|
||||
endif()
|
||||
|
||||
if (NOT $ENV{OPENSCAD_LIBRARIES} STREQUAL "")
|
||||
# Force pkg-config to look _only_ in the local library folder
|
||||
# in case OPENSCAD_LIBRARIES is set.
|
||||
set(ENV{PKG_CONFIG_PATH} "$ENV{OPENSCAD_LIBRARIES}/lib/pkgconfig")
|
||||
set(ENV{PKG_CONFIG_LIBDIR} "$ENV{OPENSCAD_LIBRARIES}/lib/pkgconfig")
|
||||
endif()
|
||||
|
||||
find_package(GLIB2 2.2.0 REQUIRED)
|
||||
add_definitions(${GLIB2_DEFINITIONS})
|
||||
inclusion(GLIB2_DIR GLIB2_INCLUDE_DIRS)
|
||||
|
||||
# Imagemagick
|
||||
|
||||
if (SKIP_IMAGEMAGICK)
|
||||
|
@ -553,8 +588,8 @@ set(OFFSCREEN_SOURCES
|
|||
../src/OpenCSGRenderer.cc)
|
||||
|
||||
add_library(tests-core STATIC ${CORE_SOURCES})
|
||||
target_link_libraries(tests-core ${OPENGL_LIBRARIES})
|
||||
set(TESTS-CORE-LIBRARIES ${OPENGL_LIBRARIES} ${Boost_LIBRARIES})
|
||||
target_link_libraries(tests-core ${OPENGL_LIBRARIES} ${GLIB2_LIBRARIES} )
|
||||
set(TESTS-CORE-LIBRARIES ${OPENGL_LIBRARIES} ${GLIB2_LIBRARIES} ${Boost_LIBRARIES} )
|
||||
|
||||
add_library(tests-common STATIC ${COMMON_SOURCES})
|
||||
target_link_libraries(tests-common tests-core)
|
||||
|
@ -574,7 +609,7 @@ set(TESTS-NOCGAL-LIBRARIES ${TESTS-CORE-LIBRARIES})
|
|||
# modulecachetest
|
||||
#
|
||||
add_executable(modulecachetest modulecachetest.cc)
|
||||
target_link_libraries(modulecachetest tests-nocgal ${TESTS-NOCGAL-LIBRARIES} ${Boost_LIBRARIES})
|
||||
target_link_libraries(modulecachetest tests-nocgal ${TESTS-NOCGAL-LIBRARIES})
|
||||
|
||||
#
|
||||
# csgtexttest
|
||||
|
@ -594,7 +629,7 @@ target_link_libraries(cgalcachetest tests-cgal ${TESTS-CGAL-LIBRARIES} ${GLEW_LI
|
|||
#
|
||||
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}")
|
||||
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} )
|
||||
target_link_libraries(openscad_nogui tests-offscreen tests-cgal tests-nocgal ${TESTS-CORE-LIBRARIES} ${TESTS-CGAL-LIBRARIES} ${GLEW_LIBRARY} ${OPENCSG_LIBRARY} ${COCOA_LIBRARY} )
|
||||
|
||||
#
|
||||
# GUI binary tests
|
||||
|
@ -774,8 +809,10 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES}
|
|||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/dim-all.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/string-test.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/string-indexing.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/string-unicode.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/vector-values.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/search-tests.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/search-tests-unicode.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/recursion-tests.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests2.scad
|
||||
|
@ -795,13 +832,15 @@ list(APPEND DUMPTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test
|
|||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/allexpressions.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/allfunctions.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/allmodules.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/nonplanar_polyhedron.scad)
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/nonplanar_polyhedron.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/stl-cgal-convert_to_Polyhedron-crash.scad)
|
||||
|
||||
list(APPEND CGALPNGTEST_FILES ${FEATURES_FILES} ${SCAD_DXF_FILES} ${EXAMPLE_FILES})
|
||||
list(APPEND CGALPNGTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/include-tests.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/transform-nan-inf-tests.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/nonplanar_polyhedron.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/stl-cgal-convert_to_Polyhedron-crash.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles-test.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles_dir/localfiles-compatibility-test.scad)
|
||||
|
||||
|
@ -824,6 +863,10 @@ disable_tests(openscad-csgpng_child-background)
|
|||
disable_tests(opencsgtest_example006 cgalpngtest_example006)
|
||||
disable_tests(openscad-csgpng_example006 openscad-cgalpng_example006)
|
||||
|
||||
# NefPolyhedron->Polyhedron conversion failures. No images for OpenCSG/Thrown
|
||||
disable_tests(opencsgtest_stl-cgal-convert_to_Polyhedron-crash)
|
||||
disable_tests(throwntogethertest_stl-cgal-convert_to_Polyhedron-crash)
|
||||
|
||||
# These tests only makes sense in OpenCSG mode
|
||||
disable_tests(cgalpngtest_child-background
|
||||
cgalpngtest_highlight-and-background-modifier
|
||||
|
@ -893,6 +936,14 @@ string(REPLACE __header__ "Generated by cmake from ${CMAKE_CURRENT_SOURCE_DIR}/C
|
|||
string(REPLACE __cmake_system_name__ ${CMAKE_SYSTEM_NAME} TMP ${TMP})
|
||||
string(REPLACE __openscad_binpath__ ${OPENSCAD_BINPATH} TMP ${TMP})
|
||||
|
||||
set(OPENSCAD_UPLOAD_TESTS $ENV{OPENSCAD_UPLOAD_TESTS})
|
||||
if (OPENSCAD_UPLOAD_TESTS)
|
||||
set(UPLOADARG "--upload")
|
||||
endif()
|
||||
if (UPLOADARG)
|
||||
string(REPLACE __openscad_upload_tests__ ${UPLOADARG} TMP ${TMP})
|
||||
endif()
|
||||
|
||||
if (MINGW_CROSS_ENV_DIR)
|
||||
string(REPLACE __wine__ wine TMP ${TMP})
|
||||
else()
|
||||
|
|
|
@ -63,7 +63,12 @@ endif()
|
|||
|
||||
message("running '__openscad_binpath__ --info' to generate sysinfo.txt")
|
||||
execute_process(COMMAND __wine__ __openscad_binpath__ --info OUTPUT_FILE sysinfo.txt)
|
||||
set(CTEST_CUSTOM_POST_TEST ${CTEST_CUSTOM_POST_TEST} "__cmake_current_binary_dir__/test_pretty_print")
|
||||
|
||||
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_LESS 2.8.12)
|
||||
set(CTEST_CUSTOM_POST_TEST ${CTEST_CUSTOM_POST_TEST} "__cmake_current_binary_dir__/test_pretty_print")
|
||||
else()
|
||||
set(CTEST_CUSTOM_POST_TEST ${CTEST_CUSTOM_POST_TEST} "__python__ __cmake_current_source_dir__/test_pretty_print.py --builddir=__cmake_current_binary_dir__ __openscad_upload_tests__")
|
||||
endif()
|
||||
|
||||
if ( ${debug_openscad_template} )
|
||||
foreach(post_test ${CTEST_CUSTOM_POST_TEST} )
|
||||
|
|
|
@ -0,0 +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}")
|
||||
|
||||
set(GLIB2_DEFINITIONS ${GLIB2_CFLAGS_OTHER})
|
||||
#message("GLIB2_DEFINITIONS ${GLIB2_DEFINITIONS}")
|
||||
|
||||
set(GLIB2_LIBRARY_NAMES ${GLIB2_LIBRARIES})
|
||||
set(GLIB2_LIBRARIES "")
|
||||
foreach(GLIB2_LIB ${GLIB2_LIBRARY_NAMES})
|
||||
# message("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}")
|
||||
list(APPEND GLIB2_LIBRARIES "${TMP}")
|
||||
endforeach()
|
||||
message("GLIB2_LIBRARIES: ${GLIB2_LIBRARIES}")
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 4.2 KiB |
|
@ -7,6 +7,9 @@ group() {
|
|||
multmatrix([[1, 0, 0, 4], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], faces = [[0, 2, 4], [0, 5, 2], [0, 4, 3], [0, 3, 5], [1, 4, 2], [1, 2, 5], [1, 3, 4], [1, 5, 3]], convexity = 1);
|
||||
}
|
||||
multmatrix([[1, 0, 0, 6], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
polyhedron(points = [[-0.8, -0.8, -0.8], [0, 0, -0.8], [0.8, -0.8, -0.8], [0.8, 0.8, -0.8], [-0.8, 0.8, -0.8], [-0.8, -0.8, 0.8], [0, 0, 0.8], [0.8, -0.8, 0.8], [0.8, 0.8, 0.8], [-0.8, 0.8, 0.8]], triangles = [[0, 1, 2, 3, 4], [5, 6, 1, 0], [6, 7, 2, 1], [7, 8, 3, 2], [8, 9, 4, 3], [9, 5, 0, 4], [9, 8, 7, 6, 5]], convexity = 2);
|
||||
}
|
||||
}
|
||||
multmatrix([[1, 0, 0, 0], [0, 1, 0, 2], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
difference() {
|
||||
|
@ -18,8 +21,11 @@ group() {
|
|||
multmatrix([[1, 0, 0, 4], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], faces = [[0, 2, 4], [0, 5, 2], [0, 4, 3], [0, 3, 5], [1, 4, 2], [1, 2, 5], [1, 3, 4], [1, 5, 3]], convexity = 1);
|
||||
}
|
||||
multmatrix([[1, 0, 0, 6], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
polyhedron(points = [[-0.8, -0.8, -0.8], [0, 0, -0.8], [0.8, -0.8, -0.8], [0.8, 0.8, -0.8], [-0.8, 0.8, -0.8], [-0.8, -0.8, 0.8], [0, 0, 0.8], [0.8, -0.8, 0.8], [0.8, 0.8, 0.8], [-0.8, 0.8, 0.8]], triangles = [[0, 1, 2, 3, 4], [5, 6, 1, 0], [6, 7, 2, 1], [7, 8, 3, 2], [8, 9, 4, 3], [9, 5, 0, 4], [9, 8, 7, 6, 5]], convexity = 2);
|
||||
}
|
||||
}
|
||||
multmatrix([[1, 0, 0, 2], [0, 1, 0, 0], [0, 0, 1, 2], [0, 0, 0, 1]]) {
|
||||
multmatrix([[1, 0, 0, 3], [0, 1, 0, 0], [0, 0, 1, 2], [0, 0, 0, 1]]) {
|
||||
cube(size = [8, 3, 3], center = true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,4 +50,11 @@ group() {
|
|||
}
|
||||
}
|
||||
}
|
||||
multmatrix([[1, 0, 0, 0], [0, 1, 0, 60], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
rotate_extrude(convexity = 1, $fn = 0, $fa = 12, $fs = 2) {
|
||||
multmatrix([[1, 0, 0, -20], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
square(size = [10, 10], center = false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
group() {
|
||||
render(convexity = 1) {
|
||||
import(file = "stl-cgal-convert_to_Polyhedron-crash.stl", layer = "", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
ECHO: "----- Lookup of 1 byte into 1 byte"
|
||||
ECHO: "Expect [0] for search(a, aaaa)=[0]. OK"
|
||||
ECHO: "Expect [0] for search(a, aaaa, 1)=[0]. OK"
|
||||
ECHO: "Expect [0, 0] for search(aa, aaaa)=[0, 0]. OK"
|
||||
ECHO: "Expect [0, 0] for search(aa, aaaa, 1)=[0, 0]. OK"
|
||||
ECHO: "Expect [[0, 1, 2, 3]] for search(a, aaaa, 0)=[[0, 1, 2, 3]]. OK"
|
||||
ECHO: "Expect [[0, 1]] for search(a, aaaa, 2)=[[0, 1]]. OK"
|
||||
ECHO: "Expect [[0, 1, 2]] for search(a, aaaa, 3)=[[0, 1, 2]]. OK"
|
||||
ECHO: "Expect [[0, 1, 2, 3]] for search(a, aaaa, 4)=[[0, 1, 2, 3]]. OK"
|
||||
ECHO: "Expect [[0, 1, 2, 3], [0, 1, 2, 3]] for search(aa, aaaa, 0)=[[0, 1, 2, 3], [0, 1, 2, 3]]. OK"
|
||||
WARNING: search term not found: "b"
|
||||
ECHO: "Expect [] for search(b, aaaa)=[]. OK"
|
||||
WARNING: search term not found: "b"
|
||||
ECHO: "Expect [] for search(b, aaaa, 1)=[]. OK"
|
||||
WARNING: search term not found: "b"
|
||||
ECHO: "Expect [[]] for search(b, aaaa, 0)=[[]]. OK"
|
||||
WARNING: search term not found: "b"
|
||||
ECHO: "Expect [[]] for search(b, aaaa, 2)=[[]]. OK"
|
||||
WARNING: search term not found: "b"
|
||||
WARNING: search term not found: "b"
|
||||
ECHO: "Expect [] for search(bb, aaaa)=[]. OK"
|
||||
WARNING: search term not found: "b"
|
||||
WARNING: search term not found: "b"
|
||||
ECHO: "Expect [] for search(bb, aaaa, 1)=[]. OK"
|
||||
WARNING: search term not found: "b"
|
||||
WARNING: search term not found: "b"
|
||||
ECHO: "Expect [[], []] for search(bb, aaaa, 0)=[[], []]. OK"
|
||||
WARNING: search term not found: "b"
|
||||
WARNING: search term not found: "b"
|
||||
ECHO: "Expect [[], []] for search(bb, aaaa, 2)=[[], []]. OK"
|
||||
ECHO: "Expect [] for search(, aaaa)=[]. OK"
|
||||
ECHO: "Expect [] for search(, )=[]. OK"
|
||||
WARNING: search term not found: "a"
|
||||
ECHO: "Expect [] for search(a, )=[]. OK"
|
||||
ECHO: "----- Lookup of multi-byte into 1 byte"
|
||||
WARNING: search term not found: "Л"
|
||||
ECHO: "Expect [] for search(Л, aaaa)=[]. OK"
|
||||
WARNING: search term not found: "🂡"
|
||||
ECHO: "Expect [] for search(🂡, aaaa)=[]. OK"
|
||||
WARNING: search term not found: "Л"
|
||||
ECHO: "Expect [[]] for search(Л, aaaa, 0)=[[]]. OK"
|
||||
WARNING: search term not found: "🂡"
|
||||
ECHO: "Expect [[]] for search(🂡, aaaa, 0)=[[]]. OK"
|
||||
WARNING: search term not found: "Л"
|
||||
WARNING: search term not found: "Л"
|
||||
ECHO: "Expect [] for search(ЛЛ, aaaa)=[]. OK"
|
||||
WARNING: search term not found: "🂡"
|
||||
WARNING: search term not found: "🂡"
|
||||
ECHO: "Expect [] for search(🂡🂡, aaaa)=[]. OK"
|
||||
WARNING: search term not found: "Л"
|
||||
WARNING: search term not found: "Л"
|
||||
ECHO: "Expect [[], []] for search(ЛЛ, aaaa, 0)=[[], []]. OK"
|
||||
WARNING: search term not found: "🂡"
|
||||
WARNING: search term not found: "🂡"
|
||||
ECHO: "Expect [[], []] for search(🂡🂡, aaaa, 0)=[[], []]. OK"
|
||||
ECHO: "----- Lookup of 1-byte into multi-byte"
|
||||
WARNING: search term not found: "a"
|
||||
ECHO: "Expect [] for search(a, ЛЛЛЛ)=[]. OK"
|
||||
WARNING: search term not found: "a"
|
||||
ECHO: "Expect [] for search(a, 🂡🂡🂡🂡)=[]. OK"
|
||||
WARNING: search term not found: "a"
|
||||
ECHO: "Expect [] for search(a, ЛЛЛЛ, 1)=[]. OK"
|
||||
WARNING: search term not found: "a"
|
||||
ECHO: "Expect [[]] for search(a, 🂡🂡🂡🂡, 0)=[[]]. OK"
|
||||
WARNING: search term not found: "a"
|
||||
ECHO: "Expect [[]] for search(a, 🂡🂡🂡🂡, 2)=[[]]. OK"
|
||||
ECHO: "----- Lookup of 1-byte into mixed multi-byte"
|
||||
ECHO: "Expect [0] for search(a, aЛaЛaЛaЛa)=[0]. OK"
|
||||
ECHO: "Expect [0] for search(a, a🂡a🂡a🂡a🂡a)=[0]. OK"
|
||||
ECHO: "Expect [0] for search(a, a🂡Л🂡a🂡Л🂡a)=[0]. OK"
|
||||
ECHO: "Expect [[0, 2, 4, 6, 8]] for search(a, aЛaЛaЛaЛa, 0)=[[0, 2, 4, 6, 8]]. OK"
|
||||
ECHO: "Expect [[0, 2, 4, 6, 8]] for search(a, a🂡a🂡a🂡a🂡a, 0)=[[0, 2, 4, 6, 8]]. OK"
|
||||
ECHO: "Expect [[0, 4, 8]] for search(a, a🂡Л🂡a🂡Л🂡a, 0)=[[0, 4, 8]]. OK"
|
||||
ECHO: "----- Lookup of 2-byte into 2-byte"
|
||||
ECHO: "Expect [0] for search(Л, ЛЛЛЛ)=[0]. OK"
|
||||
ECHO: "Expect [[0, 1, 2, 3]] for search(Л, ЛЛЛЛ, 0)=[[0, 1, 2, 3]]. OK"
|
||||
ECHO: "----- Lookup of 2-byte into 4-byte"
|
||||
WARNING: search term not found: "Л"
|
||||
ECHO: "Expect [] for search(Л, 🂡🂡🂡🂡)=[]. OK"
|
||||
ECHO: "----- Lookup of 4-byte into 4-byte"
|
||||
ECHO: "Expect [0] for search(🂡, 🂡🂡🂡🂡)=[0]. OK"
|
||||
ECHO: "Expect [[0, 1, 2, 3]] for search(🂡, 🂡🂡🂡🂡, 0)=[[0, 1, 2, 3]]. OK"
|
||||
ECHO: "----- Lookup of 4-byte into 2-byte"
|
||||
WARNING: search term not found: "🂡"
|
||||
ECHO: "Expect [] for search(🂡, ЛЛЛЛ)=[]. OK"
|
||||
ECHO: "----- Lookup of 2-byte into mixed multi-byte"
|
||||
ECHO: "Expect [1] for search(Л, aЛaЛaЛaЛa, 1)=[1]. OK"
|
||||
WARNING: search term not found: "Л"
|
||||
ECHO: "Expect [] for search(Л, a🂡a🂡a🂡a🂡a, 1)=[]. OK"
|
||||
ECHO: "Expect [2] for search(Л, a🂡Л🂡a🂡Л🂡a, 1)=[2]. OK"
|
||||
ECHO: "Expect [[1, 3, 5, 7]] for search(Л, aЛaЛaЛaЛa, 0)=[[1, 3, 5, 7]]. OK"
|
||||
WARNING: search term not found: "Л"
|
||||
ECHO: "Expect [[]] for search(Л, a🂡a🂡a🂡a🂡a, 0)=[[]]. OK"
|
||||
ECHO: "Expect [[2, 6]] for search(Л, a🂡Л🂡a🂡Л🂡a, 0)=[[2, 6]]. OK"
|
||||
ECHO: "----- Lookup of 4-byte into mixed multi-byte"
|
||||
WARNING: search term not found: "🂡"
|
||||
ECHO: "Expect [] for search(🂡, aЛaЛaЛaЛa, 1)=[]. OK"
|
||||
ECHO: "Expect [1] for search(🂡, a🂡a🂡a🂡a🂡a, 1)=[1]. OK"
|
||||
WARNING: search term not found: "🂡"
|
||||
ECHO: "Expect [[]] for search(🂡, aЛaЛaЛaЛa, 0)=[[]]. OK"
|
||||
ECHO: "Expect [[1, 3, 5, 7]] for search(🂡, a🂡a🂡a🂡a🂡a, 0)=[[1, 3, 5, 7]]. OK"
|
||||
ECHO: "Expect [[1, 3, 5, 7]] for search(🂡, a🂡Л🂡a🂡Л🂡a, 0)=[[1, 3, 5, 7]]. OK"
|
||||
ECHO: "----- Lookup of mixed multi-byte into mixed multi-byte"
|
||||
WARNING: search term not found: "🂡"
|
||||
ECHO: "Expect [[0, 2, 4, 6, 8], [1, 3, 5, 7], []] for search(aЛ🂡, aЛaЛaЛaЛa, 0)=[[0, 2, 4, 6, 8], [1, 3, 5, 7], []]. OK"
|
||||
WARNING: search term not found: "Л"
|
||||
ECHO: "Expect [[0, 2, 4, 6, 8], [], [1, 3, 5, 7]] for search(aЛ🂡, a🂡a🂡a🂡a🂡a, 0)=[[0, 2, 4, 6, 8], [], [1, 3, 5, 7]]. OK"
|
||||
ECHO: "Expect [[0, 4, 8], [2, 6], [1, 3, 5, 7]] for search(aЛ🂡, a🂡Л🂡a🂡Л🂡a, 0)=[[0, 4, 8], [2, 6], [1, 3, 5, 7]]. OK"
|
||||
ECHO: "Expect [[1, 3, 5, 7], [0, 4, 8], [2, 6]] for search(🂡aЛ, a🂡Л🂡a🂡Л🂡a, 0)=[[1, 3, 5, 7], [0, 4, 8], [2, 6]]. OK"
|
|
@ -0,0 +1,107 @@
|
|||
ECHO: "text_1bytes_len = ", "1234", " len = ", 4
|
||||
ECHO: "text_2bytes_len = ", "ЛЛЛЛ", " len = ", 4
|
||||
ECHO: "text_4bytes_len = ", "🂡🂱🃁🃑", " len = ", 4
|
||||
ECHO: "[", 0, "] = ", "DEADBEEF", " of len=", 8, ":"
|
||||
ECHO: " [", 0, "]=", "D"
|
||||
ECHO: " [", 1, "]=", "E"
|
||||
ECHO: " [", 2, "]=", "A"
|
||||
ECHO: " [", 3, "]=", "D"
|
||||
ECHO: " [", 4, "]=", "B"
|
||||
ECHO: " [", 5, "]=", "E"
|
||||
ECHO: " [", 6, "]=", "E"
|
||||
ECHO: " [", 7, "]=", "F"
|
||||
ECHO: "[", 1, "] = ", "Ленивый рыжий кот", " of len=", 17, ":"
|
||||
ECHO: " [", 0, "]=", "Л"
|
||||
ECHO: " [", 1, "]=", "е"
|
||||
ECHO: " [", 2, "]=", "н"
|
||||
ECHO: " [", 3, "]=", "и"
|
||||
ECHO: " [", 4, "]=", "в"
|
||||
ECHO: " [", 5, "]=", "ы"
|
||||
ECHO: " [", 6, "]=", "й"
|
||||
ECHO: " [", 7, "]=", " "
|
||||
ECHO: " [", 8, "]=", "р"
|
||||
ECHO: " [", 9, "]=", "ы"
|
||||
ECHO: " [", 10, "]=", "ж"
|
||||
ECHO: " [", 11, "]=", "и"
|
||||
ECHO: " [", 12, "]=", "й"
|
||||
ECHO: " [", 13, "]=", " "
|
||||
ECHO: " [", 14, "]=", "к"
|
||||
ECHO: " [", 15, "]=", "о"
|
||||
ECHO: " [", 16, "]=", "т"
|
||||
ECHO: "[", 2, "] = ", "كسول الزنجبيل القط", " of len=", 18, ":"
|
||||
ECHO: " [", 0, "]=", "ك"
|
||||
ECHO: " [", 1, "]=", "س"
|
||||
ECHO: " [", 2, "]=", "و"
|
||||
ECHO: " [", 3, "]=", "ل"
|
||||
ECHO: " [", 4, "]=", " "
|
||||
ECHO: " [", 5, "]=", "ا"
|
||||
ECHO: " [", 6, "]=", "ل"
|
||||
ECHO: " [", 7, "]=", "ز"
|
||||
ECHO: " [", 8, "]=", "ن"
|
||||
ECHO: " [", 9, "]=", "ج"
|
||||
ECHO: " [", 10, "]=", "ب"
|
||||
ECHO: " [", 11, "]=", "ي"
|
||||
ECHO: " [", 12, "]=", "ل"
|
||||
ECHO: " [", 13, "]=", " "
|
||||
ECHO: " [", 14, "]=", "ا"
|
||||
ECHO: " [", 15, "]=", "ل"
|
||||
ECHO: " [", 16, "]=", "ق"
|
||||
ECHO: " [", 17, "]=", "ط"
|
||||
ECHO: "[", 3, "] = ", "懶惰的姜貓", " of len=", 5, ":"
|
||||
ECHO: " [", 0, "]=", "懶"
|
||||
ECHO: " [", 1, "]=", "惰"
|
||||
ECHO: " [", 2, "]=", "的"
|
||||
ECHO: " [", 3, "]=", "姜"
|
||||
ECHO: " [", 4, "]=", "貓"
|
||||
ECHO: "[", 4, "] = ", "äöü ÄÖÜ ß", " of len=", 9, ":"
|
||||
ECHO: " [", 0, "]=", "ä"
|
||||
ECHO: " [", 1, "]=", "ö"
|
||||
ECHO: " [", 2, "]=", "ü"
|
||||
ECHO: " [", 3, "]=", " "
|
||||
ECHO: " [", 4, "]=", "Ä"
|
||||
ECHO: " [", 5, "]=", "Ö"
|
||||
ECHO: " [", 6, "]=", "Ü"
|
||||
ECHO: " [", 7, "]=", " "
|
||||
ECHO: " [", 8, "]=", "ß"
|
||||
ECHO: "[", 5, "] = ", "😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏😐", " of len=", 16, ":"
|
||||
ECHO: " [", 0, "]=", "😁"
|
||||
ECHO: " [", 1, "]=", "😂"
|
||||
ECHO: " [", 2, "]=", "😃"
|
||||
ECHO: " [", 3, "]=", "😄"
|
||||
ECHO: " [", 4, "]=", "😅"
|
||||
ECHO: " [", 5, "]=", "😆"
|
||||
ECHO: " [", 6, "]=", "😇"
|
||||
ECHO: " [", 7, "]=", "😈"
|
||||
ECHO: " [", 8, "]=", "😉"
|
||||
ECHO: " [", 9, "]=", "😊"
|
||||
ECHO: " [", 10, "]=", "😋"
|
||||
ECHO: " [", 11, "]=", "😌"
|
||||
ECHO: " [", 12, "]=", "😍"
|
||||
ECHO: " [", 13, "]=", "😎"
|
||||
ECHO: " [", 14, "]=", "😏"
|
||||
ECHO: " [", 15, "]=", "😐"
|
||||
ECHO: "[", 6, "] = ", "⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏", " of len=", 15, ":"
|
||||
ECHO: " [", 0, "]=", "⠁"
|
||||
ECHO: " [", 1, "]=", "⠂"
|
||||
ECHO: " [", 2, "]=", "⠃"
|
||||
ECHO: " [", 3, "]=", "⠄"
|
||||
ECHO: " [", 4, "]=", "⠅"
|
||||
ECHO: " [", 5, "]=", "⠆"
|
||||
ECHO: " [", 6, "]=", "⠇"
|
||||
ECHO: " [", 7, "]=", "⠈"
|
||||
ECHO: " [", 8, "]=", "⠉"
|
||||
ECHO: " [", 9, "]=", "⠊"
|
||||
ECHO: " [", 10, "]=", "⠋"
|
||||
ECHO: " [", 11, "]=", "⠌"
|
||||
ECHO: " [", 12, "]=", "⠍"
|
||||
ECHO: " [", 13, "]=", "⠎"
|
||||
ECHO: " [", 14, "]=", "⠏"
|
||||
ECHO: "[", 7, "] = ", "🂡🂱🃁🃑", " of len=", 4, ":"
|
||||
ECHO: " [", 0, "]=", "🂡"
|
||||
ECHO: " [", 1, "]=", "🂱"
|
||||
ECHO: " [", 2, "]=", "🃁"
|
||||
ECHO: " [", 3, "]=", "🃑"
|
||||
ECHO: "Past end of unicode only 2-byte ", undef
|
||||
ECHO: "Past end of unicode only 4-byte ", undef
|
||||
ECHO: "Past end of both 2-byte ", undef
|
||||
ECHO: "Past end of both 4-byte ", undef
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 7.9 KiB |
|
@ -25,544 +25,447 @@
|
|||
|
||||
# todo
|
||||
#
|
||||
# 1. Note: Wiki code is deprecated. All future development should move to
|
||||
# create html output (or even xml output). Wiki design was based on the
|
||||
# wrong assumption of easily accessible public wiki servers with
|
||||
# auto-upload scripts available. wiki code should be removed and code
|
||||
# simplified.
|
||||
#
|
||||
# to still use wiki, use args '--wiki' and/or '--wiki-upload'
|
||||
#
|
||||
# 2. why is hash differing
|
||||
# 1. why is hash differing
|
||||
|
||||
import string,sys,re,os,hashlib,subprocess,textwrap,time,platform
|
||||
import string
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
import hashlib
|
||||
import subprocess
|
||||
import time
|
||||
import platform
|
||||
try:
|
||||
from urllib.request import urlopen
|
||||
from urllib.parse import urlencode
|
||||
except:
|
||||
from urllib2 import urlopen
|
||||
from urllib import urlencode
|
||||
|
||||
def tryread(filename):
|
||||
data = None
|
||||
try:
|
||||
f = open(filename,'rb')
|
||||
data = f.read()
|
||||
f.close()
|
||||
except Exception, e:
|
||||
print 'couldn\'t open ',filename
|
||||
print type(e), e
|
||||
return data
|
||||
data = None
|
||||
try:
|
||||
f = open(filename,'rb')
|
||||
data = f.read()
|
||||
f.close()
|
||||
except Exception as e:
|
||||
print 'couldn\'t open ',filename
|
||||
print type(e), e
|
||||
return data
|
||||
|
||||
def trysave(filename,data):
|
||||
dir = os.path.dirname(filename)
|
||||
try:
|
||||
if not os.path.isdir(dir):
|
||||
if not dir == '':
|
||||
debug( 'creating' + dir)
|
||||
os.mkdir(dir)
|
||||
f=open(filename,'wb')
|
||||
f.write(data)
|
||||
f.close()
|
||||
except Exception, e:
|
||||
print 'problem writing to',filename
|
||||
print type(e), e
|
||||
return None
|
||||
return True
|
||||
def trysave(filename, data):
|
||||
dir = os.path.dirname(filename)
|
||||
try:
|
||||
if not os.path.isdir(dir):
|
||||
if not dir == '':
|
||||
debug( 'creating' + dir)
|
||||
os.mkdir(dir)
|
||||
f=open(filename,'wb')
|
||||
f.write(data)
|
||||
f.close()
|
||||
except Exception as e:
|
||||
print 'problem writing to',filename
|
||||
print type(e), e
|
||||
return None
|
||||
return True
|
||||
|
||||
def ezsearch(pattern,str):
|
||||
x = re.search(pattern,str,re.DOTALL|re.MULTILINE)
|
||||
if x and len(x.groups())>0: return x.group(1).strip()
|
||||
return ''
|
||||
def ezsearch(pattern, str):
|
||||
x = re.search(pattern,str,re.DOTALL|re.MULTILINE)
|
||||
if x and len(x.groups())>0: return x.group(1).strip()
|
||||
return ''
|
||||
|
||||
def read_gitinfo():
|
||||
# won't work if run from outside of branch.
|
||||
try:
|
||||
data = subprocess.Popen(['git','remote','-v'],stdout=subprocess.PIPE).stdout.read()
|
||||
origin = ezsearch('^origin *?(.*?)\(fetch.*?$',data)
|
||||
upstream = ezsearch('^upstream *?(.*?)\(fetch.*?$',data)
|
||||
data = subprocess.Popen(['git','branch'],stdout=subprocess.PIPE).stdout.read()
|
||||
branch = ezsearch('^\*(.*?)$',data)
|
||||
out = 'Git branch: ' + branch + ' from origin ' + origin + '\n'
|
||||
out += 'Git upstream: ' + upstream + '\n'
|
||||
except:
|
||||
out = 'Problem running git'
|
||||
return out
|
||||
# won't work if run from outside of branch.
|
||||
try:
|
||||
data = subprocess.Popen(['git', 'remote', '-v'], stdout=subprocess.PIPE).stdout.read()
|
||||
origin = ezsearch('^origin *?(.*?)\(fetch.*?$', data)
|
||||
upstream = ezsearch('^upstream *?(.*?)\(fetch.*?$', data)
|
||||
data = subprocess.Popen(['git', 'branch'], stdout=subprocess.PIPE).stdout.read()
|
||||
branch = ezsearch('^\*(.*?)$', data)
|
||||
out = 'Git branch: ' + branch + ' from origin ' + origin + '\n'
|
||||
out += 'Git upstream: ' + upstream + '\n'
|
||||
except:
|
||||
out = 'Problem running git'
|
||||
return out
|
||||
|
||||
def read_sysinfo(filename):
|
||||
data = tryread(filename)
|
||||
if not data:
|
||||
sinfo = platform.sys.platform
|
||||
sinfo += '\nsystem cannot create offscreen GL framebuffer object'
|
||||
sinfo += '\nsystem cannot create GL based images'
|
||||
sysid = platform.sys.platform+'_no_GL_renderer'
|
||||
return sinfo, sysid
|
||||
data = tryread(filename)
|
||||
if not data:
|
||||
sinfo = platform.sys.platform
|
||||
sinfo += '\nsystem cannot create offscreen GL framebuffer object'
|
||||
sinfo += '\nsystem cannot create GL based images'
|
||||
sysid = platform.sys.platform+'_no_GL_renderer'
|
||||
return sinfo, sysid
|
||||
|
||||
machine = ezsearch('Machine:(.*?)\n',data)
|
||||
machine = machine.replace(' ','-').replace('/','-')
|
||||
machine = ezsearch('Machine:(.*?)\n',data)
|
||||
machine = machine.replace(' ','-').replace('/','-')
|
||||
|
||||
osinfo = ezsearch('OS info:(.*?)\n',data)
|
||||
osplain = osinfo.split(' ')[0].strip().replace('/','-')
|
||||
if 'windows' in osinfo.lower(): osplain = 'win'
|
||||
osinfo = ezsearch('OS info:(.*?)\n',data)
|
||||
osplain = osinfo.split(' ')[0].strip().replace('/','-')
|
||||
if 'windows' in osinfo.lower():
|
||||
osplain = 'win'
|
||||
|
||||
renderer = ezsearch('GL Renderer:(.*?)\n',data)
|
||||
tmp = renderer.split(' ')
|
||||
tmp = string.join(tmp[0:3],'-')
|
||||
tmp = tmp.split('/')[0]
|
||||
renderer = tmp
|
||||
renderer = ezsearch('GL Renderer:(.*?)\n',data)
|
||||
tmp = renderer.split(' ')
|
||||
tmp = string.join(tmp[0:3],'-')
|
||||
tmp = tmp.split('/')[0]
|
||||
renderer = tmp
|
||||
|
||||
data += read_gitinfo()
|
||||
data += read_gitinfo()
|
||||
|
||||
data += 'Image comparison: ImageMagick'
|
||||
data += 'Image comparison: ImageMagick'
|
||||
|
||||
data = data.strip()
|
||||
data = data.strip()
|
||||
|
||||
# create 4 letter hash and stick on end of sysid
|
||||
nondate_data = re.sub("\n.*?ompile date.*?\n","\n",data).strip()
|
||||
hexhash = hashlib.md5()
|
||||
hexhash.update(nondate_data)
|
||||
hexhash = hexhash.hexdigest()[-4:].upper()
|
||||
hash = ''
|
||||
for c in hexhash: hash += chr(ord(c)+97-48)
|
||||
# create 4 letter hash and stick on end of sysid
|
||||
nondate_data = re.sub("\n.*?ompile date.*?\n", "\n", data).strip()
|
||||
hexhash = hashlib.md5(nondate_data).hexdigest()[-4:].upper()
|
||||
hash_ = ''.join(chr(ord(c) + 97 - 48) for c in hexhash)
|
||||
|
||||
sysid = osplain + '_' + machine + '_' + renderer + '_' + hash
|
||||
sysid = sysid.replace('(','_').replace(')','_')
|
||||
sysid = sysid.lower()
|
||||
sysid = '_'.join([osplain, machine, renderer, hash_])
|
||||
sysid = sysid.replace('(', '_').replace(')', '_')
|
||||
sysid = sysid.lower()
|
||||
|
||||
return data, sysid
|
||||
return data, sysid
|
||||
|
||||
class Test:
|
||||
def __init__(self,fullname,time,passed,output,type,actualfile,expectedfile,scadfile,log):
|
||||
self.fullname,self.time,self.passed,self.output = \
|
||||
fullname, time, passed, output
|
||||
self.type, self.actualfile, self.expectedfile, self.scadfile = \
|
||||
type, actualfile, expectedfile, scadfile
|
||||
self.fulltestlog = log
|
||||
def __init__(self, fullname, subpr, passed, output, type, actualfile,
|
||||
expectedfile, scadfile, log):
|
||||
self.fullname, self.time = fullname, time
|
||||
self.passed, self.output = passed, output
|
||||
self.type, self.actualfile = type, actualfile
|
||||
self.expectedfile, self.scadfile = expectedfile, scadfile
|
||||
self.fulltestlog = log
|
||||
|
||||
def __str__(self):
|
||||
x = 'fullname: ' + self.fullname
|
||||
x+= '\nactualfile: ' + self.actualfile
|
||||
x+= '\nexpectedfile: ' + self.expectedfile
|
||||
x+= '\ntesttime: ' + self.time
|
||||
x+= '\ntesttype: ' + self.type
|
||||
x+= '\npassed: ' + str(self.passed)
|
||||
x+= '\nscadfile: ' + self.scadfile
|
||||
x+= '\noutput bytes: ' + str(len(self.output))
|
||||
x+= '\ntestlog bytes: ' + str(len(self.fulltestlog))
|
||||
x+= '\n'
|
||||
return x
|
||||
def __str__(self):
|
||||
x = 'fullname: ' + self.fullname
|
||||
x+= '\nactualfile: ' + self.actualfile
|
||||
x+= '\nexpectedfile: ' + self.expectedfile
|
||||
x+= '\ntesttime: ' + self.time
|
||||
x+= '\ntesttype: ' + self.type
|
||||
x+= '\npassed: ' + str(self.passed)
|
||||
x+= '\nscadfile: ' + self.scadfile
|
||||
x+= '\noutput bytes: ' + str(len(self.output))
|
||||
x+= '\ntestlog bytes: ' + str(len(self.fulltestlog))
|
||||
x+= '\n'
|
||||
return x
|
||||
|
||||
def parsetest(teststring):
|
||||
patterns = ["Test:(.*?)\n", # fullname
|
||||
"Test time =(.*?) sec\n",
|
||||
"Test time.*?Test (Passed)", # pass/fail
|
||||
"Output:(.*?)<end of output>",
|
||||
'Command:.*?-s" "(.*?)"', # type
|
||||
"^ actual .*?:(.*?)\n",
|
||||
"^ expected .*?:(.*?)\n",
|
||||
'Command:.*?(testdata.*?)"' # scadfile
|
||||
]
|
||||
hits = map( lambda pattern: ezsearch(pattern,teststring), patterns )
|
||||
test = Test(hits[0],hits[1],hits[2]=='Passed',hits[3],hits[4],hits[5],hits[6],hits[7],teststring)
|
||||
if len(test.actualfile) > 0: test.actualfile_data = tryread(test.actualfile)
|
||||
if len(test.expectedfile) > 0: test.expectedfile_data = tryread(test.expectedfile)
|
||||
return test
|
||||
patterns = ["Test:(.*?)\n", # fullname
|
||||
"Test time =(.*?) sec\n",
|
||||
"Test time.*?Test (Passed)", # pass/fail
|
||||
"Output:(.*?)<end of output>",
|
||||
'Command:.*?-s" "(.*?)"', # type
|
||||
"^ actual .*?:(.*?)\n",
|
||||
"^ expected .*?:(.*?)\n",
|
||||
'Command:.*?(testdata.*?)"' # scadfile
|
||||
]
|
||||
hits = map( lambda pattern: ezsearch(pattern, teststring), patterns)
|
||||
test = Test(hits[0], hits[1], hits[2]=='Passed', hits[3], hits[4], hits[5],
|
||||
hits[6], hits[7], teststring)
|
||||
if len(test.actualfile) > 0:
|
||||
test.actualfile_data = tryread(test.actualfile)
|
||||
if len(test.expectedfile) > 0:
|
||||
test.expectedfile_data = tryread(test.expectedfile)
|
||||
return test
|
||||
|
||||
def parselog(data):
|
||||
startdate = ezsearch('Start testing: (.*?)\n',data)
|
||||
enddate = ezsearch('End testing: (.*?)\n',data)
|
||||
pattern = '([0-9]*/[0-9]* Testing:.*?time elapsed.*?\n)'
|
||||
test_chunks = re.findall(pattern,data,re.S)
|
||||
tests = map( parsetest, test_chunks )
|
||||
tests = sorted(tests, key = lambda t:t.passed)
|
||||
return startdate, tests, enddate
|
||||
startdate = ezsearch('Start testing: (.*?)\n', data)
|
||||
enddate = ezsearch('End testing: (.*?)\n', data)
|
||||
pattern = '([0-9]*/[0-9]* Testing:.*?time elapsed.*?\n)'
|
||||
test_chunks = re.findall(pattern,data, re.S)
|
||||
tests = map( parsetest, test_chunks )
|
||||
tests = sorted(tests, key = lambda t: t.passed)
|
||||
return startdate, tests, enddate
|
||||
|
||||
def load_makefiles(builddir):
|
||||
filelist = []
|
||||
for root, dirs, files in os.walk(builddir):
|
||||
for fname in files: filelist += [ os.path.join(root, fname) ]
|
||||
files = filter(lambda x: 'build.make' in os.path.basename(x), filelist)
|
||||
files += filter(lambda x: 'flags.make' in os.path.basename(x), filelist)
|
||||
files = filter(lambda x: 'esting' not in x and 'emporary' not in x, files)
|
||||
result = {}
|
||||
for fname in files:
|
||||
result[fname.replace(builddir,'')] = open(fname,'rb').read()
|
||||
return result
|
||||
|
||||
def wikify_filename(fname, wiki_rootpath, sysid):
|
||||
wikifname = fname.replace('/','_').replace('\\','_').strip('.')
|
||||
return wiki_rootpath + '_' + sysid + '_' + wikifname
|
||||
|
||||
def towiki(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, makefiles):
|
||||
|
||||
wiki_template = """
|
||||
<h3>[[WIKI_ROOTPATH]] test run report</h3>
|
||||
|
||||
'''Sysid''': SYSID
|
||||
|
||||
'''Result summary''': NUMPASSED / NUMTESTS tests passed ( PERCENTPASSED % ) <br>
|
||||
|
||||
'''System info''':
|
||||
<pre>
|
||||
SYSINFO
|
||||
</pre>
|
||||
|
||||
start time: STARTDATE <br>
|
||||
end time : ENDDATE <br>
|
||||
|
||||
'''Image tests'''
|
||||
|
||||
<REPEAT1>
|
||||
{| border=1 cellspacing=0 cellpadding=1
|
||||
|-
|
||||
| colspan=2 | FTESTNAME
|
||||
|-
|
||||
| Expected image || Actual image
|
||||
|-
|
||||
| [[File:EXPECTEDFILE|250px]] || ACTUALFILE_WIKI
|
||||
|}
|
||||
|
||||
<pre>
|
||||
TESTLOG
|
||||
</pre>
|
||||
filelist = []
|
||||
for root, dirs, files in os.walk(builddir):
|
||||
for fname in files: filelist += [ os.path.join(root, fname) ]
|
||||
files = [file for file in filelist if 'build.make' in os.path.basename(file)
|
||||
or 'flags.make' in os.path.basename(file)]
|
||||
files = [file for file in files if 'esting' not in file and 'emporary' not in file]
|
||||
result = {}
|
||||
for fname in files:
|
||||
result[fname.replace(builddir, '')] = tryread(fname)
|
||||
return result
|
||||
|
||||
|
||||
def png_encode64(fname, width=250, data=None):
|
||||
# en.wikipedia.org/wiki/Data_URI_scheme
|
||||
data = data or tryread(fname) or ''
|
||||
data_uri = data.encode('base64').replace('\n', '')
|
||||
tag = '''<img src="data:image/png;base64,%s" width="%s" %s/>'''
|
||||
if data == '':
|
||||
alt = 'alt="error: no image generated" '
|
||||
else:
|
||||
alt = 'alt="openscad_test_image" '
|
||||
tag %= (data_uri, width, alt)
|
||||
return tag
|
||||
|
||||
</REPEAT1>
|
||||
|
||||
|
||||
'''Text tests'''
|
||||
|
||||
<REPEAT2>
|
||||
{|border=1 cellspacing=0 cellpadding=1
|
||||
|-
|
||||
| FTESTNAME
|
||||
|}
|
||||
|
||||
<pre>
|
||||
TESTLOG
|
||||
</pre>
|
||||
|
||||
|
||||
</REPEAT2>
|
||||
|
||||
'''build.make and flags.make'''
|
||||
<REPEAT3>
|
||||
*[[MAKEFILE_NAME]]
|
||||
</REPEAT3>
|
||||
"""
|
||||
txtpages = {}
|
||||
imgs = {}
|
||||
passed_tests = filter(lambda x: x.passed, tests)
|
||||
failed_tests = filter(lambda x: not x.passed, tests)
|
||||
|
||||
tests_to_report = failed_tests
|
||||
if include_passed: tests_to_report = tests
|
||||
|
||||
try: percent = str(int(100.0*len(passed_tests) / len(tests)))
|
||||
except ZeroDivisionError: percent = 'n/a'
|
||||
s = wiki_template
|
||||
repeat1 = ezsearch('(<REPEAT1>.*?</REPEAT1>)',s)
|
||||
repeat2 = ezsearch('(<REPEAT2>.*?</REPEAT2>)',s)
|
||||
repeat3 = ezsearch('(<REPEAT3>.*?</REPEAT3>)',s)
|
||||
dic = { 'STARTDATE': startdate, 'ENDDATE': enddate, 'WIKI_ROOTPATH': wiki_rootpath,
|
||||
'SYSINFO': sysinfo, 'SYSID':sysid,
|
||||
'NUMTESTS':len(tests), 'NUMPASSED':len(passed_tests), 'PERCENTPASSED':percent }
|
||||
for key in dic.keys():
|
||||
s = s.replace(key,str(dic[key]))
|
||||
|
||||
for t in tests_to_report:
|
||||
if t.type in ('txt', 'ast', 'csg', 'term', 'echo'):
|
||||
newchunk = re.sub('FTESTNAME',t.fullname,repeat2)
|
||||
newchunk = newchunk.replace('TESTLOG',t.fulltestlog)
|
||||
s = s.replace(repeat2, newchunk+repeat2)
|
||||
elif t.type=='png':
|
||||
tmp = t.actualfile.replace(builddir,'')
|
||||
wikiname_a = wikify_filename(tmp,wiki_rootpath,sysid)
|
||||
tmp = t.expectedfile.replace(os.path.dirname(builddir),'')
|
||||
wikiname_e = wikify_filename(tmp,wiki_rootpath,sysid)
|
||||
if hasattr(t, 'expectedfile_data'):
|
||||
imgs[wikiname_e] = t.expectedfile_data
|
||||
if t.actualfile:
|
||||
actualfile_wiki = '[[File:'+wikiname_a+'|250px]]'
|
||||
if hasattr(t, 'actualfile_data'):
|
||||
imgs[wikiname_a] = t.actualfile_data
|
||||
else:
|
||||
actualfile_wiki = 'No image generated.'
|
||||
newchunk = re.sub('FTESTNAME',t.fullname,repeat1)
|
||||
newchunk = newchunk.replace('ACTUALFILE_WIKI',actualfile_wiki)
|
||||
newchunk = newchunk.replace('EXPECTEDFILE',wikiname_e)
|
||||
newchunk = newchunk.replace('TESTLOG',t.fulltestlog)
|
||||
s = s.replace(repeat1, newchunk+repeat1)
|
||||
else:
|
||||
raise Exception("Unknown test type %r"%t.type)
|
||||
|
||||
makefiles_wikinames = {}
|
||||
for mf in sorted(makefiles.keys()):
|
||||
tmp = mf.replace('CMakeFiles','').replace('.dir','')
|
||||
wikiname = wikify_filename(tmp,wiki_rootpath,sysid)
|
||||
newchunk = re.sub('MAKEFILE_NAME',wikiname,repeat3)
|
||||
s = s.replace(repeat3, newchunk+repeat3)
|
||||
makefiles_wikinames[mf] = wikiname
|
||||
|
||||
s = s.replace(repeat1,'')
|
||||
s = s.replace(repeat2,'')
|
||||
s = s.replace(repeat3,'')
|
||||
s = re.sub('<REPEAT.*?>\n','',s)
|
||||
s = re.sub('</REPEAT.*?>','',s)
|
||||
|
||||
mainpage_wikiname = wiki_rootpath + '_' + sysid + '_test_report'
|
||||
txtpages[ mainpage_wikiname ] = s
|
||||
for mf in sorted(makefiles.keys()):
|
||||
txtpages[ makefiles_wikinames[ mf ] ] = '\n*Subreport from [['+mainpage_wikiname+']]\n\n\n<pre>\n'+makefiles[mf]+'\n</pre>'
|
||||
|
||||
return imgs, txtpages
|
||||
|
||||
def png_encode64( fname, width=250 ):
|
||||
# en.wikipedia.org/wiki/Data_URI_scheme
|
||||
try:
|
||||
f = open( fname, "rb" )
|
||||
data = f.read()
|
||||
except:
|
||||
data = ''
|
||||
data_uri = data.encode("base64").replace("\n","")
|
||||
tag = '<img'
|
||||
tag += ' style="border:1px solid gray"'
|
||||
tag += ' src="data:image/png;base64,'
|
||||
tag += data_uri + '"'
|
||||
tag += ' width="'+str(width)+'"'
|
||||
if data =='':
|
||||
tag += ' alt="error: no image generated"'
|
||||
else:
|
||||
tag += ' alt="openscad_test_image"'
|
||||
tag += ' />\n'
|
||||
return tag
|
||||
|
||||
def tohtml(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, makefiles):
|
||||
# kludge. assume wiki stuff has alreayd run and dumped files properly
|
||||
head = '<html><head><title>'+wiki_rootpath+' test run for '+sysid +'</title></head><body>'
|
||||
tail = '</body></html>'
|
||||
|
||||
passed_tests = filter(lambda x: x.passed, tests)
|
||||
failed_tests = filter(lambda x: not x.passed, tests)
|
||||
try: percent = str(int(100.0*len(passed_tests) / len(tests)))
|
||||
except ZeroDivisionError: percent = 'n/a'
|
||||
|
||||
tests_to_report = failed_tests
|
||||
if include_passed: tests_to_report = tests
|
||||
|
||||
s=''
|
||||
|
||||
s+= '\n<h3>'
|
||||
s+= '\nSystem info\n'
|
||||
s+= '\n</h3><p>'
|
||||
s+= '<pre>'+sysinfo+'</pre>\n'
|
||||
|
||||
s+= '\n<pre>'
|
||||
s+= '\nSTARTDATE: '+ startdate
|
||||
s+= '\nENDDATE: '+ enddate
|
||||
s+= '\nWIKI_ROOTPATH: '+ wiki_rootpath
|
||||
s+= '\nSYSID: '+sysid
|
||||
s+= '\nNUMTESTS: '+str(len(tests))
|
||||
s+= '\nNUMPASSED: '+str(len(passed_tests))
|
||||
s+= '\nPERCENTPASSED: '+ percent
|
||||
s+= '\n</pre>'
|
||||
|
||||
if not include_passed:
|
||||
s+= '<h3>Failed tests:</h3>\n'
|
||||
|
||||
if len(tests_to_report)==0:
|
||||
s+= '<p>none</p>'
|
||||
|
||||
for t in tests_to_report:
|
||||
if t.type in ('txt', 'ast', 'csg', 'term', 'echo'):
|
||||
s+='\n<pre>'+t.fullname+'</pre>\n'
|
||||
s+='<p><pre>'+t.fulltestlog+'</pre>\n\n'
|
||||
elif t.type=='png':
|
||||
tmp = t.actualfile.replace(builddir,'')
|
||||
wikiname_a = wikify_filename(tmp,wiki_rootpath,sysid)
|
||||
tmp = t.expectedfile.replace(os.path.dirname(builddir),'')
|
||||
wikiname_e = wikify_filename(tmp,wiki_rootpath,sysid)
|
||||
# imgtag_e = <img src='+wikiname_e+' width=250/>'
|
||||
# imatag_a = <img src='+wikiname_a+' width=250/>'
|
||||
imgtag_e = png_encode64( t.expectedfile, 250 )
|
||||
imgtag_a = png_encode64( t.actualfile, 250 )
|
||||
s+='<table>'
|
||||
s+='\n<tr><td colspan=2>'+t.fullname
|
||||
s+='\n<tr><td>Expected<td>Actual'
|
||||
s+='\n<tr><td>' + imgtag_e + '</td>'
|
||||
s+='\n <td>' + imgtag_a + '</td>'
|
||||
s+='\n</table>'
|
||||
s+='\n<pre>'
|
||||
s+=t.fulltestlog
|
||||
s+='\n</pre>'
|
||||
else:
|
||||
raise Exception("Unknown test type %r"%t.type)
|
||||
|
||||
s+='\n\n<p>\n\n'
|
||||
|
||||
s+= '<h3> CMake .build files </h3>\n'
|
||||
s+= '\n<pre>'
|
||||
makefiles_wikinames = {}
|
||||
for mf in sorted(makefiles.keys()):
|
||||
mfname = mf.strip().lstrip(os.path.sep)
|
||||
text = open(os.path.join(builddir,mfname)).read()
|
||||
s+= '</pre><h4>'+mfname+'</h4><pre>'
|
||||
s+= text
|
||||
tmp = mf.replace('CMakeFiles','').replace('.dir','')
|
||||
wikiname = wikify_filename(tmp,wiki_rootpath,sysid)
|
||||
# s += '\n<a href='+wikiname+'>'+wikiname+'</a><br>'
|
||||
s+= '\n</pre>'
|
||||
s+='\n'
|
||||
|
||||
return head + s + tail
|
||||
|
||||
def wiki_login(wikiurl,api_php_path,botname,botpass):
|
||||
site = mwclient.Site(wikiurl,api_php_path)
|
||||
site.login(botname,botpass)
|
||||
return site
|
||||
|
||||
def wiki_upload(wikiurl,api_php_path,botname,botpass,filedata,wikipgname):
|
||||
counter = 0
|
||||
done = False
|
||||
descrip = 'test'
|
||||
time.sleep(1)
|
||||
while not done:
|
||||
try:
|
||||
print 'login',botname,'to',wikiurl
|
||||
site = wiki_login(wikiurl,api_php_path,botname,botpass)
|
||||
print 'uploading...',
|
||||
if wikipgname.endswith('png'):
|
||||
site.upload(filedata,wikipgname,descrip,ignore=True)
|
||||
else:
|
||||
page = site.Pages[wikipgname]
|
||||
text = page.edit()
|
||||
page.save(filedata)
|
||||
done = True
|
||||
print 'transfer ok'
|
||||
except Exception, e:
|
||||
print 'Error:', type(e),e
|
||||
counter += 1
|
||||
if counter>maxretry:
|
||||
print 'giving up. please try a different wiki site'
|
||||
done = True
|
||||
else:
|
||||
print 'wiki',wikiurl,'down. retrying in 15 seconds'
|
||||
time.sleep(15)
|
||||
|
||||
def upload(wikiurl,api_php_path='/',wiki_rootpath='test', sysid='null', botname='cakebaby',botpass='anniew',wikidir='.',dryrun=True):
|
||||
wetrun = not dryrun
|
||||
if dryrun: print 'dry run'
|
||||
try:
|
||||
global mwclient
|
||||
import mwclient
|
||||
except:
|
||||
print 'please download mwclient 0.6.5 and unpack here:', os.getcwd()
|
||||
sys.exit()
|
||||
|
||||
if wetrun: site = wiki_login(wikiurl,api_php_path,botname,botpass)
|
||||
|
||||
wikifiles = os.listdir(wikidir)
|
||||
testreport_page = filter( lambda x: 'test_report' in x, wikifiles )
|
||||
if (len(testreport_page)>1):
|
||||
print 'multiple test reports found, please clean dir',wikidir
|
||||
sys.exit()
|
||||
|
||||
rootpage = testreport_page[0]
|
||||
print 'add',rootpage,' to main report page ',wiki_rootpath
|
||||
if wetrun:
|
||||
page = site.Pages[wiki_rootpath]
|
||||
text = page.edit()
|
||||
if not '[['+rootpage+']]' in text:
|
||||
page.save(text +'\n*[['+rootpage+']]\n')
|
||||
|
||||
wikifiles = os.listdir(wikidir)
|
||||
wikifiles = filter(lambda x: not x.endswith('html'), wikifiles)
|
||||
|
||||
print 'upload wiki pages:'
|
||||
for wikiname in wikifiles:
|
||||
filename = os.path.join(wikidir,wikiname)
|
||||
filedata = tryread(filename)
|
||||
print 'upload',len(filedata),'bytes from',wikiname
|
||||
if wetrun and len(filedata)>0:
|
||||
wiki_upload(wikiurl,api_php_path,botname,botpass,filedata,wikiname)
|
||||
if len(filedata)==0:
|
||||
print 'cancelling empty upload'
|
||||
|
||||
def findlogfile(builddir):
|
||||
logpath = os.path.join(builddir,'Testing','Temporary')
|
||||
logfilename = os.path.join(logpath,'LastTest.log.tmp')
|
||||
if not os.path.isfile(logfilename):
|
||||
logfilename = os.path.join(logpath,'LastTest.log')
|
||||
if not os.path.isfile(logfilename):
|
||||
print 'cant find and/or open logfile',logfilename
|
||||
sys.exit()
|
||||
return logpath, logfilename
|
||||
logpath = os.path.join(builddir, 'Testing', 'Temporary')
|
||||
logfilename = os.path.join(logpath, 'LastTest.log.tmp')
|
||||
if not os.path.isfile(logfilename):
|
||||
logfilename = os.path.join(logpath, 'LastTest.log')
|
||||
if not os.path.isfile(logfilename):
|
||||
print 'can\'t find and/or open logfile', logfilename
|
||||
sys.exit()
|
||||
return logfilename
|
||||
|
||||
# --- Templating ---
|
||||
|
||||
class Templates(object):
|
||||
html_template = '''<html>
|
||||
<head><title>Test run for {sysid}</title>
|
||||
{style}
|
||||
</head>
|
||||
<body>
|
||||
<h1>{project_name} test run report</h1>
|
||||
<p>
|
||||
<b>Sysid</b>: {sysid}
|
||||
</p>
|
||||
<p>
|
||||
<b>Result summary</b>: {numpassed} / {numtests} tests passed ({percent}%)
|
||||
</p>
|
||||
|
||||
<h2>System info</h2>
|
||||
<pre>{sysinfo}</pre>
|
||||
|
||||
<p>start time: {startdate}</p>
|
||||
<p>end time: {enddate}</p>
|
||||
|
||||
<h2>Image tests</h2>
|
||||
{image_tests}
|
||||
|
||||
<h2>Text tests</h2>
|
||||
{text_tests}
|
||||
|
||||
<h2>build.make and flags.make</h2>
|
||||
{makefiles}
|
||||
</body></html>'''
|
||||
|
||||
style = '''
|
||||
<style>
|
||||
body {
|
||||
color: black;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table td, th {
|
||||
border: 2px solid gray;
|
||||
}
|
||||
|
||||
.text-name {
|
||||
border: 2px solid black;
|
||||
padding: 0.14em;
|
||||
}
|
||||
</style>'''
|
||||
|
||||
image_template = '''<table>
|
||||
<tbody>
|
||||
<tr><td colspan="2">{test_name}</td></tr>
|
||||
<tr><td> Expected image </td><td> Actual image </td></tr>
|
||||
<tr><td> {expected} </td><td> {actual} </td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<pre>
|
||||
{test_log}
|
||||
</pre>
|
||||
'''
|
||||
|
||||
text_template = '''
|
||||
<span class="text-name">{test_name}</span>
|
||||
|
||||
<pre>
|
||||
{test_log}
|
||||
</pre>
|
||||
'''
|
||||
|
||||
makefile_template = '''
|
||||
<h4>{name}</h4>
|
||||
<pre>
|
||||
{text}
|
||||
</pre>
|
||||
'''
|
||||
|
||||
def __init__(self, **defaults):
|
||||
self.filled = {}
|
||||
self.defaults = defaults
|
||||
|
||||
def fill(self, template, *args, **kwargs):
|
||||
kwds = self.defaults.copy()
|
||||
kwds.update(kwargs)
|
||||
return getattr(self, template).format(*args, **kwds)
|
||||
|
||||
def add(self, template, var, *args, **kwargs):
|
||||
self.filled[var] = self.filled.get(var, '') + self.fill(template, *args, **kwargs)
|
||||
return self.filled[var]
|
||||
|
||||
def get(self, var):
|
||||
return self.filled.get(var, '')
|
||||
|
||||
|
||||
def to_html(project_name, startdate, tests, enddate, sysinfo, sysid, makefiles):
|
||||
passed_tests = [test for test in tests if test.passed]
|
||||
failed_tests = [test for test in tests if not test.passed]
|
||||
|
||||
report_tests = failed_tests
|
||||
if include_passed:
|
||||
report_tests = tests
|
||||
|
||||
percent = '%.0f' % (100.0 * len(passed_tests) / len(tests)) if tests else 'n/a'
|
||||
|
||||
templates = Templates()
|
||||
for test in report_tests:
|
||||
if test.type in ('txt', 'ast', 'csg', 'term', 'echo'):
|
||||
templates.add('text_template', 'text_tests',
|
||||
test_name=test.fullname,
|
||||
test_log=test.fulltestlog)
|
||||
elif test.type == 'png':
|
||||
actual_img = png_encode64(test.actualfile,
|
||||
data=vars(test).get('actualfile_data'))
|
||||
expected_img = png_encode64(test.expectedfile,
|
||||
data=vars(test).get('expectedfile_data'))
|
||||
templates.add('image_template', 'image_tests',
|
||||
test_name=test.fullname,
|
||||
test_log=test.fulltestlog,
|
||||
actual=actual_img,
|
||||
expected=expected_img)
|
||||
else:
|
||||
raise TypeError('Unknown test type %r' % test.type)
|
||||
|
||||
for mf in sorted(makefiles.keys()):
|
||||
mfname = mf.strip().lstrip(os.path.sep)
|
||||
text = open(os.path.join(builddir, mfname)).read()
|
||||
templates.add('makefile_template', 'makefiles', name=mfname, text=text)
|
||||
|
||||
text_tests = templates.get('text_tests')
|
||||
image_tests = templates.get('image_tests')
|
||||
makefiles_str = templates.get('makefiles')
|
||||
|
||||
return templates.fill('html_template', style=Templates.style,
|
||||
sysid=sysid, sysinfo=sysinfo,
|
||||
startdate=startdate, enddate=enddate,
|
||||
project_name=project_name,
|
||||
numtests=len(tests),
|
||||
numpassed=len(passed_tests),
|
||||
percent=percent, image_tests=image_tests,
|
||||
text_tests=text_tests, makefiles=makefiles_str)
|
||||
|
||||
# --- End Templating ---
|
||||
|
||||
# --- Web Upload ---
|
||||
|
||||
def postify(data):
|
||||
return urlencode(data).encode()
|
||||
|
||||
def create_page():
|
||||
data = {
|
||||
'action': 'create',
|
||||
'type': 'html'
|
||||
}
|
||||
try:
|
||||
response = urlopen('http://www.dinkypage.com', data=postify(data))
|
||||
except:
|
||||
return None
|
||||
return response.geturl()
|
||||
|
||||
def upload_html(page_url, title, html):
|
||||
data = {
|
||||
'mode': 'editor',
|
||||
'title': title,
|
||||
'html': html,
|
||||
'ajax': '1'
|
||||
}
|
||||
try:
|
||||
response = urlopen(page_url, data=postify(data))
|
||||
except:
|
||||
return False
|
||||
return 'success' in response.read().decode()
|
||||
|
||||
# --- End Web Upload ---
|
||||
|
||||
def debug(x):
|
||||
if debug_test_pp: print 'test_pretty_print: '+x
|
||||
if debug_test_pp:
|
||||
print 'test_pretty_print: ' + x
|
||||
|
||||
debug_test_pp=False
|
||||
builddir=os.getcwd()
|
||||
debug_test_pp = False
|
||||
include_passed = False
|
||||
builddir = os.getcwd()
|
||||
|
||||
def main():
|
||||
#wikisite = 'cakebaby.referata.com'
|
||||
#wiki_api_path = ''
|
||||
global wikisite, wiki_api_path, wiki_rootpath, builddir, debug_test_pp
|
||||
global maxretry, dry, include_passed
|
||||
global builddir, debug_test_pp
|
||||
global maxretry, dry, include_passed
|
||||
project_name = 'OpenSCAD'
|
||||
|
||||
wikisite = 'cakebaby.wikia.com'
|
||||
wiki_api_path = '/'
|
||||
wiki_rootpath = 'OpenSCAD'
|
||||
if '--debug' in string.join(sys.argv): debug_test_pp=True
|
||||
maxretry = 10
|
||||
if bool(os.getenv("TEST_GENERATE")):
|
||||
sys.exit(0)
|
||||
|
||||
if bool(os.getenv("TEST_GENERATE")): sys.exit(0)
|
||||
# --- Command Line Parsing ---
|
||||
|
||||
include_passed = False
|
||||
if '--include-passed' in sys.argv: include_passed = True
|
||||
if '--debug' in ' '.join(sys.argv):
|
||||
debug_test_pp = True
|
||||
maxretry = 10
|
||||
|
||||
dry = False
|
||||
debug( 'running test_pretty_print' )
|
||||
if '--dryrun' in sys.argv: dry=True
|
||||
suffix = ezsearch('--suffix=(.*?) ',string.join(sys.argv)+' ')
|
||||
builddir = ezsearch('--builddir=(.*?) ',string.join(sys.argv)+' ')
|
||||
if builddir=='': builddir=os.getcwd()
|
||||
debug( 'build dir set to ' + builddir )
|
||||
if '--include-passed' in sys.argv:
|
||||
include_passed = True
|
||||
|
||||
sysinfo, sysid = read_sysinfo(os.path.join(builddir,'sysinfo.txt'))
|
||||
makefiles = load_makefiles(builddir)
|
||||
logpath, logfilename = findlogfile(builddir)
|
||||
testlog = tryread(logfilename)
|
||||
startdate, tests, enddate = parselog(testlog)
|
||||
if debug_test_pp:
|
||||
print 'found sysinfo.txt,',
|
||||
print 'found', len(makefiles),'makefiles,',
|
||||
print 'found', len(tests),'test results'
|
||||
dry = False
|
||||
debug('running test_pretty_print')
|
||||
if '--dryrun' in sys.argv:
|
||||
dry = True
|
||||
|
||||
imgs, txtpages = towiki(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, makefiles)
|
||||
suffix = ezsearch('--suffix=(.*?) ', ' '.join(sys.argv) + ' ')
|
||||
builddir = ezsearch('--builddir=(.*?) ', ' '.join(sys.argv) + ' ')
|
||||
if not builddir:
|
||||
builddir = os.getcwd()
|
||||
debug('build dir set to ' + builddir)
|
||||
|
||||
wikidir = os.path.join(logpath,sysid+'_report')
|
||||
debug( 'erasing files in ' + wikidir )
|
||||
try: map(lambda x:os.remove(os.path.join(wikidir,x)), os.listdir(wikidir))
|
||||
except: pass
|
||||
debug( 'output dir:\n' + wikidir.replace(os.getcwd(),'') )
|
||||
debug( 'writing ' + str(len(imgs)) + ' images' )
|
||||
debug( 'writing ' + str(len(txtpages)-1) + ' text pages' )
|
||||
debug( 'writing index.html ' )
|
||||
if '--wiki' in string.join(sys.argv):
|
||||
print "wiki output is deprecated"
|
||||
for pgname in sorted(imgs): trysave( os.path.join(wikidir,pgname), imgs[pgname])
|
||||
for pgname in sorted(txtpages): trysave( os.path.join(wikidir,pgname), txtpages[pgname])
|
||||
upload = False
|
||||
if '--upload' in sys.argv:
|
||||
upload = True
|
||||
debug('will upload test report')
|
||||
|
||||
htmldata = tohtml(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, makefiles)
|
||||
html_basename = sysid+'_report.html'
|
||||
html_filename = os.path.join(builddir,'Testing','Temporary',html_basename)
|
||||
debug('saving ' +html_filename + ' ' + str(len(htmldata)) + ' bytes')
|
||||
trysave( html_filename, htmldata )
|
||||
print "report saved:", html_filename.replace(os.getcwd()+os.path.sep,'')
|
||||
# Workaround for old cmake's not being able to pass parameters
|
||||
# to CTEST_CUSTOM_POST_TEST
|
||||
if bool(os.getenv("OPENSCAD_UPLOAD_TESTS")):
|
||||
upload = True
|
||||
|
||||
if '--wiki-upload' in sys.argv:
|
||||
print "wiki upload is deprecated."
|
||||
upload(wikisite,wiki_api_path,wiki_rootpath,sysid,'openscadbot',
|
||||
'tobdacsnepo',wikidir,dryrun=dry)
|
||||
print 'upload attempt complete'
|
||||
# --- End Command Line Parsing ---
|
||||
|
||||
debug( 'test_pretty_print complete' )
|
||||
sysinfo, sysid = read_sysinfo(os.path.join(builddir, 'sysinfo.txt'))
|
||||
makefiles = load_makefiles(builddir)
|
||||
logfilename = findlogfile(builddir)
|
||||
testlog = tryread(logfilename)
|
||||
startdate, tests, enddate = parselog(testlog)
|
||||
if debug_test_pp:
|
||||
print 'found sysinfo.txt,',
|
||||
print 'found', len(makefiles),'makefiles,',
|
||||
print 'found', len(tests),'test results'
|
||||
|
||||
|
||||
html = to_html(project_name, startdate, tests, enddate, sysinfo, sysid, makefiles)
|
||||
html_basename = sysid + '_report.html'
|
||||
html_filename = os.path.join(builddir, 'Testing', 'Temporary', html_basename)
|
||||
debug('saving ' + html_filename + ' ' + str(len(html)) + ' bytes')
|
||||
trysave(html_filename, html)
|
||||
print "report saved:\n", html_filename.replace(os.getcwd()+os.path.sep,'')
|
||||
|
||||
if upload:
|
||||
page_url = create_page()
|
||||
if upload_html(page_url, title='OpenSCAD test results', html=html):
|
||||
share_url = page_url.partition('?')[0]
|
||||
print 'html report uploaded at', share_url
|
||||
else:
|
||||
print 'could not upload html report'
|
||||
|
||||
debug('test_pretty_print complete')
|
||||
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
main()
|
||||
|
|