Merge branch 'master' into travis
|
@ -94,7 +94,7 @@ Follow the instructions for the platform you're compiling on below.
|
|||
* [boost (1.35 - 1.53)](http://www.boost.org/)
|
||||
* [OpenCSG (1.3.2)](http://www.opencsg.org/)
|
||||
* [GLEW (1.5.4 ->)](http://glew.sourceforge.net/)
|
||||
* [Eigen (2.0.x->3.x)](http://eigen.tuxfamily.org/)
|
||||
* [Eigen (3.0 - 3.2)](http://eigen.tuxfamily.org/)
|
||||
* [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/)
|
||||
|
|
|
@ -4,4 +4,4 @@ Version=1.0
|
|||
Name=OpenSCAD
|
||||
Icon=openscad
|
||||
Exec=openscad %f
|
||||
Categories=Graphics;3DGraphics;Engineering;
|
||||
Categories=Graphics;3DGraphics;Engineering;Programming;
|
||||
|
|
|
@ -39,6 +39,7 @@ debug: DEFINES += DEBUG
|
|||
TEMPLATE = app
|
||||
|
||||
INCLUDEPATH += src
|
||||
DEPENDPATH += src
|
||||
|
||||
# Handle custom library location.
|
||||
# Used when manually installing 3rd party libraries
|
||||
|
@ -368,6 +369,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
|
|
@ -1,11 +1,41 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# build&upload script for linux & windows snapshot binaries
|
||||
# tested under linux
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# Start with a clean directory. For example:
|
||||
#
|
||||
# mkdir builder
|
||||
# cd builder
|
||||
#
|
||||
# Then run this script, or optionally the 'build only' or 'upload only' version
|
||||
#
|
||||
# /some/path/openscad/builder.sh # standard build & upload
|
||||
# /some/path/openscad/builder.sh buildonly # only do build, dont upload
|
||||
# /some/path/openscad/builder.sh uploadonly # only upload, dont build
|
||||
|
||||
# Notes:
|
||||
#
|
||||
# This script is designed to build a 'clean' version of openscad directly
|
||||
# from the openscad github master source code. It will then optionally
|
||||
# upload the build to the OpenSCAD official file repository, and modify
|
||||
# the OpenSCAD website with links to the most recently built files.
|
||||
#
|
||||
#
|
||||
# For the mingw- cross build for Windows(TM) this script does a massive
|
||||
# 'from nothing' build, including downloading and building an MXE cross
|
||||
# environment, and dependencies, into $HOME/openscad_deps. This can take
|
||||
# many many many hours and use several gigabytes of disk space.
|
||||
#
|
||||
# This script itself is designed to call other scripts that do the heavy
|
||||
# lifting. This script itself should be kept relatively simple.
|
||||
#
|
||||
|
||||
#
|
||||
# requirements -
|
||||
# see http://mxe.cc for required tools (scons, perl, yasm, etc etc etc)
|
||||
|
||||
#
|
||||
# todo - can we build 32 bit linux from within 64 bit linux?
|
||||
#
|
||||
# todo - make linux work
|
||||
|
@ -19,18 +49,24 @@ init_variables()
|
|||
{
|
||||
STARTPATH=$PWD
|
||||
export STARTPATH
|
||||
DOBUILD=1
|
||||
DOUPLOAD=1
|
||||
DRYRUN=
|
||||
if [ "`echo $* | grep uploadonly`" ]; then
|
||||
UPLOADONLY=1
|
||||
DOUPLOAD=1
|
||||
DOBUILD=
|
||||
DATECODE=`date +"%Y.%m.%d"`
|
||||
fi
|
||||
if [ "`echo $* | grep buildonly`" ]; then
|
||||
DOUPLOAD=
|
||||
DOBUILD=1
|
||||
DATECODE=`date +"%Y.%m.%d"`
|
||||
else
|
||||
UPLOADONLY=
|
||||
fi
|
||||
if [ "`echo $* | grep dry`" ]; then
|
||||
DRYRUN=1
|
||||
else
|
||||
DRYRUN=
|
||||
fi
|
||||
export UPLOADONLY
|
||||
export DOBUILD
|
||||
export DOUPLOAD
|
||||
export DRYRUN
|
||||
export DATECODE
|
||||
}
|
||||
|
@ -43,9 +79,15 @@ check_starting_path()
|
|||
fi
|
||||
}
|
||||
|
||||
get_source_code()
|
||||
get_openscad_source_code()
|
||||
{
|
||||
git clone http://github.com/openscad/openscad.git
|
||||
if [ "`echo $? | grep 0`" ]; then
|
||||
echo clone of source code is ok
|
||||
else
|
||||
echo clone of openscad source code failed. exiting
|
||||
exit 1
|
||||
fi
|
||||
cd openscad
|
||||
git submodule update --init # MCAD
|
||||
#git checkout branch ##debugging
|
||||
|
@ -80,7 +122,7 @@ build_lin32()
|
|||
export DATECODE
|
||||
}
|
||||
|
||||
upload_win_generic()
|
||||
upload_win_common()
|
||||
{
|
||||
summary="$1"
|
||||
username=$2
|
||||
|
@ -110,8 +152,8 @@ upload_win32()
|
|||
BASEDIR=./mingw32/
|
||||
WIN32_PACKAGEFILE1=OpenSCAD-$DATECODE-x86-32-Installer.exe
|
||||
WIN32_PACKAGEFILE2=OpenSCAD-$DATECODE-x86-32.zip
|
||||
upload_win_generic "$SUMMARY1" $USERNAME $BASEDIR/$WIN32_PACKAGEFILE1
|
||||
upload_win_generic "$SUMMARY2" $USERNAME $BASEDIR/$WIN32_PACKAGEFILE2
|
||||
upload_win_common "$SUMMARY1" $USERNAME $BASEDIR/$WIN32_PACKAGEFILE1
|
||||
upload_win_common "$SUMMARY2" $USERNAME $BASEDIR/$WIN32_PACKAGEFILE2
|
||||
export WIN32_PACKAGEFILE1
|
||||
export WIN32_PACKAGEFILE2
|
||||
WIN32_PACKAGEFILE1_SIZE=`ls -sh $BASEDIR/$WIN32_PACKAGEFILE1 | awk ' {print $1} ';`
|
||||
|
@ -129,8 +171,8 @@ upload_win64()
|
|||
BASEDIR=./mingw64/
|
||||
WIN64_PACKAGEFILE1=OpenSCAD-$DATECODE-x86-64-Installer.exe
|
||||
WIN64_PACKAGEFILE2=OpenSCAD-$DATECODE-x86-64.zip
|
||||
upload_win_generic "$SUMMARY1" $USERNAME $BASEDIR/$WIN64_PACKAGEFILE1
|
||||
upload_win_generic "$SUMMARY2" $USERNAME $BASEDIR/$WIN64_PACKAGEFILE2
|
||||
upload_win_common "$SUMMARY1" $USERNAME $BASEDIR/$WIN64_PACKAGEFILE1
|
||||
upload_win_common "$SUMMARY2" $USERNAME $BASEDIR/$WIN64_PACKAGEFILE2
|
||||
export WIN64_PACKAGEFILE1
|
||||
export WIN64_PACKAGEFILE2
|
||||
WIN64_PACKAGEFILE1_SIZE=`ls -sh $BASEDIR/$WIN64_PACKAGEFILE1 | awk ' {print $1} ';`
|
||||
|
@ -188,6 +230,7 @@ update_win_www_download_links()
|
|||
BASEURL='http://files.openscad.org/'
|
||||
DATECODE=`date +"%Y.%m.%d"`
|
||||
|
||||
mv win_snapshot_links.js win_snapshot_links.js.backup
|
||||
rm win_snapshot_links.js
|
||||
echo "fileinfo['WIN64_SNAPSHOT1_URL'] = '$BASEURL$WIN64_PACKAGEFILE1'" >> win_snapshot_links.js
|
||||
echo "fileinfo['WIN64_SNAPSHOT2_URL'] = '$BASEURL$WIN64_PACKAGEFILE2'" >> win_snapshot_links.js
|
||||
|
@ -229,19 +272,20 @@ check_ssh_agent()
|
|||
}
|
||||
|
||||
init_variables $*
|
||||
check_ssh_agent
|
||||
if [ $DOUPLOAD ]; then
|
||||
check_ssh_agent
|
||||
fi
|
||||
check_starting_path
|
||||
read_username_from_user
|
||||
read_password_from_user
|
||||
get_source_code
|
||||
|
||||
if [ ! $UPLOADONLY ]; then
|
||||
get_openscad_source_code
|
||||
if [ $DOBUILD ]; then
|
||||
build_win32
|
||||
build_win64
|
||||
fi
|
||||
upload_win32
|
||||
upload_win64
|
||||
update_win_www_download_links
|
||||
|
||||
|
||||
if [ $DOUPLOAD ]; then
|
||||
upload_win32
|
||||
upload_win64
|
||||
update_win_www_download_links
|
||||
fi
|
||||
|
||||
|
|
|
@ -86,21 +86,16 @@ mpfr_sysver()
|
|||
|
||||
gmp_sysver()
|
||||
{
|
||||
# on some systems you have VERSION in gmp-$arch.h not gmp.h. use gmp*.h
|
||||
if [ -e $1/include/multiarch-x86_64-linux ]; then
|
||||
subdir=include/multiarch-x86_64-linux
|
||||
else
|
||||
subdir=include
|
||||
gmppaths="`find $1 -name 'gmp.h' -o -name 'gmp-*.h'`"
|
||||
if [ ! "$gmppaths" ]; then
|
||||
debug "gmp_sysver no gmp.h beneath $1"
|
||||
return
|
||||
fi
|
||||
if [ ! -e $1/$subdir ]; then return; fi
|
||||
gmppaths=`ls $1/$subdir | grep ^gmp`
|
||||
if [ ! "$gmppaths" ]; then return; fi
|
||||
for gmpfile in $gmppaths; do
|
||||
gmppath=$1/$subdir/$gmpfile
|
||||
if [ "`grep __GNU_MP_VERSION $gmppath`" ]; then
|
||||
gmpmaj=`grep "define *__GNU_MP_VERSION *[0-9]*" $gmppath | awk '{print $3}'`
|
||||
gmpmin=`grep "define *__GNU_MP_VERSION_MINOR *[0-9]*" $gmppath | awk '{print $3}'`
|
||||
gmppat=`grep "define *__GNU_MP_VERSION_PATCHLEVEL *[0-9]*" $gmppath | awk '{print $3}'`
|
||||
if [ "`grep __GNU_MP_VERSION $gmpfile`" ]; then
|
||||
gmpmaj=`grep "define *__GNU_MP_VERSION *[0-9]*" $gmpfile | awk '{print $3}'`
|
||||
gmpmin=`grep "define *__GNU_MP_VERSION_MINOR *[0-9]*" $gmpfile | awk '{print $3}'`
|
||||
gmppat=`grep "define *__GNU_MP_VERSION_PATCHLEVEL *[0-9]*" $gmpfile | awk '{print $3}'`
|
||||
fi
|
||||
done
|
||||
gmp_sysver_result="$gmpmaj.$gmpmin.$gmppat"
|
||||
|
@ -261,32 +256,47 @@ pkg_config_search()
|
|||
|
||||
get_minversion_from_readme()
|
||||
{
|
||||
if [ -e README.md ]; then READFILE=README.md; fi
|
||||
if [ -e ../README.md ]; then READFILE=../README.md; fi
|
||||
if [ ! $READFILE ]; then
|
||||
if [ "`command -v dirname`" ]; then
|
||||
READFILE=`dirname $0`/../README.md
|
||||
fi
|
||||
fi
|
||||
if [ ! $READFILE ]; then echo "cannot find README.md"; exit 1; fi
|
||||
debug get_minversion_from_readme $*
|
||||
|
||||
# Extract dependency name
|
||||
if [ ! $1 ]; then return; fi
|
||||
depname=$1
|
||||
local grv_tmp=
|
||||
|
||||
debug $depname
|
||||
# example--> * [CGAL (3.6 - 3.9)] (www.cgal.org) becomes 3.6
|
||||
# steps: eliminate *, find left (, find -, make 'x' into 0, delete junk
|
||||
grv_tmp=`grep -i ".$depname.*([0-9]" $READFILE | sed s/"*"//`
|
||||
debug $grv_tmp
|
||||
grv_tmp=`echo $grv_tmp | awk -F"(" '{print $2}'`
|
||||
debug $grv_tmp
|
||||
grv_tmp=`echo $grv_tmp | awk -F"-" '{print $1}'`
|
||||
debug $grv_tmp
|
||||
grv_tmp=`echo $grv_tmp | sed s/"x"/"0"/g`
|
||||
debug $grv_tmp
|
||||
grv_tmp=`echo $grv_tmp | sed s/"[^0-9.]"//g`
|
||||
debug $grv_tmp
|
||||
get_minversion_from_readme_result=$grv_tmp
|
||||
local grv_tmp=
|
||||
for READFILE in README.md ../README.md "`dirname "$0"`/../README.md"
|
||||
do
|
||||
if [ ! -e "$READFILE" ]
|
||||
then
|
||||
debug "get_minversion_from_readme $READFILE not found"
|
||||
continue
|
||||
fi
|
||||
debug "get_minversion_from_readme $READFILE found"
|
||||
grep -qi ".$depname.*([0-9]" $READFILE || continue
|
||||
grv_tmp="`grep -i ".$depname.*([0-9]" $READFILE | sed s/"*"//`"
|
||||
debug $grv_tmp
|
||||
grv_tmp="`echo $grv_tmp | awk -F"(" '{print $2}'`"
|
||||
debug $grv_tmp
|
||||
grv_tmp="`echo $grv_tmp | awk -F"-" '{print $1}'`"
|
||||
debug $grv_tmp
|
||||
grv_tmp="`echo $grv_tmp | sed s/"x"/"0"/g`"
|
||||
debug $grv_tmp
|
||||
grv_tmp="`echo $grv_tmp | sed s/"[^0-9.]"//g`"
|
||||
debug $grv_tmp
|
||||
if [ "z$grv_tmp" = "z" ]
|
||||
then
|
||||
debug "get_minversion_from_readme no result for $depname from $READFILE"
|
||||
continue
|
||||
fi
|
||||
get_minversion_from_readme_result=$grv_tmp
|
||||
return 0
|
||||
done
|
||||
if [ "z$grv_tmp" = "z" ]
|
||||
then
|
||||
debug "get_minversion_from_readme no result for $depname found anywhere"
|
||||
get_minversion_from_readme_result=""
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
find_min_version()
|
||||
|
@ -462,7 +472,7 @@ check_old_local()
|
|||
{
|
||||
warnon=
|
||||
if [ "`uname | grep -i linux`" ]; then
|
||||
header_list="opencsg.h CGAL boost GL/glew.h gmp.h mpfr.h eigen2 eigen3"
|
||||
header_list="opencsg.h CGAL boost GL/glew.h gmp.h mpfr.h eigen3"
|
||||
for i in $header_list; do
|
||||
if [ -e /usr/local/include/$i ]; then
|
||||
echo "Warning: you have a copy of "$i" under /usr/local/include"
|
||||
|
@ -533,7 +543,7 @@ main()
|
|||
dep_minver=$find_min_version_result
|
||||
compare_version $dep_minver $dep_sysver
|
||||
dep_compare=$compare_version_result
|
||||
pretty_print $depname $dep_minver $dep_sysver $dep_compare
|
||||
pretty_print $depname "$dep_minver" "$dep_sysver" $dep_compare
|
||||
done
|
||||
check_old_local
|
||||
check_misc
|
||||
|
|
|
@ -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
|
||||
|
@ -220,7 +223,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
|
||||
|
@ -309,10 +312,10 @@ build_eigen()
|
|||
rm -rf eigen-$version
|
||||
|
||||
EIGENDIR="none"
|
||||
if [ $version = "2.0.17" ]; then EIGENDIR=eigen-eigen-b23437e61a07; fi
|
||||
if [ $version = "3.1.2" ]; then EIGENDIR=eigen-eigen-5097c01bcdc4;
|
||||
elif [ $version = "3.1.3" ]; then EIGENDIR=eigen-eigen-2249f9c22fe8;
|
||||
elif [ $version = "3.1.4" ]; then EIGENDIR=eigen-eigen-36bf2ceaf8f5; fi
|
||||
elif [ $version = "3.1.4" ]; then EIGENDIR=eigen-eigen-36bf2ceaf8f5;
|
||||
elif [ $version = "3.2.0" ]; then EIGENDIR=eigen-eigen-ffa86ffb5570; fi
|
||||
|
||||
if [ $EIGENDIR = "none" ]; then
|
||||
echo Unknown eigen version. Please edit script.
|
||||
|
@ -439,7 +442,7 @@ echo "Using basedir:" $BASEDIR
|
|||
mkdir -p $SRCDIR $DEPLOYDIR
|
||||
build_qt 4.8.5
|
||||
# NB! For eigen, also update the path in the function
|
||||
build_eigen 3.1.4
|
||||
build_eigen 3.2.0
|
||||
build_gmp 5.1.3
|
||||
build_mpfr 3.1.2
|
||||
build_boost 1.54.0
|
||||
|
|
|
@ -6,8 +6,13 @@
|
|||
# This script must be run from the OpenSCAD source root directory
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/mingw-x-build-dependencies.sh # 32 bit
|
||||
# ./scripts/mingw-x-build-dependencies.sh 64 # 64 bit
|
||||
# ./scripts/mingw-x-build-dependencies.sh # 32 bit
|
||||
# ./scripts/mingw-x-build-dependencies.sh 64 # 64 bit
|
||||
#
|
||||
# If you just want to download, and build later:
|
||||
#
|
||||
# ./scripts/mingw-x-build-dependencies.sh download # 32 bit download
|
||||
# ./scripts/mingw-x-build-dependencies.sh 64 download # 64 bit download
|
||||
#
|
||||
# Prerequisites:
|
||||
#
|
||||
|
@ -48,21 +53,25 @@ if [ ! -e $MXEDIR ]; then
|
|||
mkdir -p $MXEDIR
|
||||
cd $MXEDIR/..
|
||||
echo "Downloading MXE into " $PWD
|
||||
if [ "`echo $* | grep 64`" ]; then
|
||||
git clone -b multi-rebase git://github.com/tonytheodore/mxe.git $MXEDIR
|
||||
else
|
||||
git clone git://github.com/mxe/mxe.git $MXEDIR
|
||||
fi
|
||||
git clone git://github.com/mxe/mxe.git $MXEDIR
|
||||
fi
|
||||
|
||||
echo "entering" $MXEDIR
|
||||
cd $MXEDIR
|
||||
if [ "`echo $* | grep 64`" ]; then
|
||||
MXE_TARGETS='x86_64-w64-mingw32'
|
||||
MXE_TARGETS='x86_64-w64-mingw32'
|
||||
if [ "`echo $* | grep download`" ]; then
|
||||
PACKAGES='download-mpfr download-eigen download-opencsg download-cgal download-qt'
|
||||
else
|
||||
PACKAGES='mpfr eigen opencsg cgal qt'
|
||||
fi
|
||||
else
|
||||
MXE_TARGETS=
|
||||
MXE_TARGETS='i686-pc-mingw32' # fixme - does this work? test it.
|
||||
if [ "`echo $* | grep download`" ]; then
|
||||
PACKAGES='download-mpfr download-eigen download-opencsg download-cgal download-qt download-nsis'
|
||||
else
|
||||
PACKAGES='mpfr eigen opencsg cgal qt nsis'
|
||||
fi
|
||||
fi
|
||||
echo make $PACKAGES MXE_TARGETS=$MXE_TARGETS -j $NUMCPU JOBS=$NUMJOBS
|
||||
make $PACKAGES MXE_TARGETS=$MXE_TARGETS -j $NUMCPU JOBS=$NUMJOBS
|
||||
|
|
|
@ -343,7 +343,7 @@ build_cgal()
|
|||
if [ "`echo $2 | grep use-sys-libs`" ]; then
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DWITH_CGAL_Qt3=OFF -DWITH_CGAL_Qt4=OFF -DWITH_CGAL_ImageIO=OFF -DCMAKE_BUILD_TYPE=$CGAL_BUILDTYPE -DBoost_DEBUG=$DEBUGBOOSTFIND ..
|
||||
else
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DGMP_INCLUDE_DIR=$DEPLOYDIR/include -DGMP_LIBRARIES=$DEPLOYDIR/lib/libgmp.so -DGMPXX_LIBRARIES=$DEPLOYDIR/lib/libgmpxx.so -DGMPXX_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_LIBRARIES=$DEPLOYDIR/lib/libmpfr.so -DWITH_CGAL_Qt3=OFF -DWITH_CGAL_Qt4=OFF -DWITH_CGAL_ImageIO=OFF -DBOOST_LIBRARYDIR=$DEPLOYDIR/lib -DBOOST_INCLUDEDIR=$DEPLOYDIR/include -DCMAKE_BUILD_TYPE=$CGAL_BUILD_TYPE -DBoost_DEBUG=$DEBUGBOOSTFIND -DBoost_NO_SYSTEM_PATHS=1 ..
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DGMP_INCLUDE_DIR=$DEPLOYDIR/include -DGMP_LIBRARIES=$DEPLOYDIR/lib/libgmp.so -DGMPXX_LIBRARIES=$DEPLOYDIR/lib/libgmpxx.so -DGMPXX_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_LIBRARIES=$DEPLOYDIR/lib/libmpfr.so -DWITH_CGAL_Qt3=OFF -DWITH_CGAL_Qt4=OFF -DWITH_CGAL_ImageIO=OFF -DBOOST_LIBRARYDIR=$DEPLOYDIR/lib -DBOOST_INCLUDEDIR=$DEPLOYDIR/include -DCMAKE_BUILD_TYPE=$CGAL_BUILDTYPE -DBoost_DEBUG=$DEBUGBOOSTFIND -DBoost_NO_SYSTEM_PATHS=1 ..
|
||||
fi
|
||||
make -j$NUMCPU
|
||||
make install
|
||||
|
@ -476,12 +476,6 @@ build_opencsg()
|
|||
build_eigen()
|
||||
{
|
||||
version=$1
|
||||
if [ -e $DEPLOYDIR/include/eigen2 ]; then
|
||||
if [ `echo $version | grep 2....` ]; then
|
||||
echo "Eigen2 already installed. not building"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
if [ -e $DEPLOYDIR/include/eigen3 ]; then
|
||||
if [ `echo $version | grep 3....` ]; then
|
||||
echo "Eigen3 already installed. not building"
|
||||
|
@ -492,7 +486,6 @@ build_eigen()
|
|||
cd $BASEDIR/src
|
||||
rm -rf eigen-$version
|
||||
EIGENDIR="none"
|
||||
if [ $version = "2.0.17" ]; then EIGENDIR=eigen-eigen-b23437e61a07; fi
|
||||
if [ $version = "3.1.1" ]; then EIGENDIR=eigen-eigen-43d9075b23ef; fi
|
||||
if [ $EIGENDIR = "none" ]; then
|
||||
echo Unknown eigen version. Please edit script.
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
get_fedora_deps()
|
||||
{
|
||||
sudo yum install qt-devel bison flex eigen2-devel python-paramiko \
|
||||
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 \
|
||||
xorg-x11-server-Xvfb
|
||||
|
@ -20,13 +20,13 @@ get_qomo_deps()
|
|||
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 eigen2 libmpfr libgmp libgmp_cxx-devel qt4-devel libcgal-devel git-core \
|
||||
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
|
||||
}
|
||||
|
||||
get_freebsd_deps()
|
||||
{
|
||||
pkg_add -r bison boost-libs cmake git bash eigen2 flex gmake gmp mpfr \
|
||||
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
|
||||
|
@ -41,7 +41,7 @@ get_netbsd_deps()
|
|||
|
||||
get_opensuse_deps()
|
||||
{
|
||||
sudo zypper install libeigen2-devel mpfr-devel gmp-devel boost-devel \
|
||||
sudo zypper install libeigen3-devel mpfr-devel gmp-devel boost-devel \
|
||||
libqt4-devel glew-devel cmake git bison flex cgal-devel opencsg-devel curl
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ get_debian_deps()
|
|||
{
|
||||
for pkg in 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 \
|
||||
libXi-dev libmpfr-dev libboost-dev libglew-dev \
|
||||
libeigen3-dev libcgal-dev libopencsg-dev libgmp3-dev libgmp-dev \
|
||||
python-paramiko curl imagemagick; do
|
||||
sudo apt-get -y install $pkg;
|
||||
|
|
|
@ -47,7 +47,7 @@ Please visit this link for a copy of the license: <a href="http://www.gnu.org/li
|
|||
<li><a href="http://gmplib.org/">GNU GMP</a>
|
||||
<li><a href="http://www.mpfr.org/">GNU MPFR</a>
|
||||
<li><a href="http://www.cgal.org">CGAL</a>
|
||||
<li><a href="http://eigen.tuxfamily.org">Eigen2</a>
|
||||
<li><a href="http://eigen.tuxfamily.org">Eigen</a>
|
||||
<li><a href="http://www.opencsg.org">OpenCSG</a>
|
||||
<li><a href="http://www.opengl.org/">OpenGL</a>
|
||||
<li><a href="http://glew.sourceforge.net">GLEW</a>
|
||||
|
|
|
@ -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,13 +96,22 @@ PolySet *CGAL_Nef_polyhedron::convertToPolyset()
|
|||
}
|
||||
else if (this->dim == 3) {
|
||||
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||
bool err = true;
|
||||
std::string errmsg("");
|
||||
CGAL_Polyhedron P;
|
||||
try {
|
||||
CGAL_Polyhedron P;
|
||||
this->p3->convert_to_Polyhedron(P);
|
||||
ps = createPolySetFromPolyhedron(P);
|
||||
err = nefworkaround::convert_to_Polyhedron<CGAL_Kernel3>( *(this->p3), P );
|
||||
//this->p3->convert_to_Polyhedron(P);
|
||||
}
|
||||
catch (const CGAL::Precondition_exception &e) {
|
||||
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) {
|
||||
PRINT("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed.");
|
||||
if (errmsg!="") PRINTB("ERROR: %s",errmsg);
|
||||
} else {
|
||||
ps = createPolySetFromPolyhedron(P);
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
|
|
@ -164,6 +164,7 @@ public slots:
|
|||
void viewCenter();
|
||||
void viewPerspective();
|
||||
void viewOrthogonal();
|
||||
void viewResetView();
|
||||
void hideConsole();
|
||||
void animateUpdateDocChanged();
|
||||
void animateUpdate();
|
||||
|
|
|
@ -213,6 +213,8 @@
|
|||
<addaction name="viewActionDiagonal"/>
|
||||
<addaction name="viewActionCenter"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="viewActionResetView"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="viewActionPerspective"/>
|
||||
<addaction name="viewActionOrthogonal"/>
|
||||
<addaction name="separator"/>
|
||||
|
@ -697,6 +699,11 @@
|
|||
<string>Show Library Folder...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="viewActionResetView">
|
||||
<property name="text">
|
||||
<string>Reset View</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
|
|
@ -84,7 +84,7 @@ std::string PlatformUtils::info()
|
|||
#ifdef QT_VERSION
|
||||
std::string qtVersion = qVersion();
|
||||
#else
|
||||
std::string qtVersion = "Qt disabled";
|
||||
std::string qtVersion = "Qt disabled - Commandline Test Version";
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CGAL
|
||||
|
|
|
@ -457,7 +457,14 @@ PolySet *PolySetCGALEvaluator::rotateDxfData(const RotateExtrudeNode &node, DxfD
|
|||
{
|
||||
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];
|
||||
if (point_x < 0) {
|
||||
PRINT("ERROR: all points for rotate_extrude() must have non-negative X coordinates");
|
||||
PRINTB("[Point %d on path %d has X coordinate %f]", j % i % point_x);
|
||||
delete ps;
|
||||
return NULL;
|
||||
}
|
||||
max_x = fmax(max_x, point_x);
|
||||
}
|
||||
|
||||
int fragments = get_fragments_from_r(max_x, node.fn, node.fs, node.fa);
|
||||
|
|
|
@ -64,9 +64,7 @@ static bool running_under_wine = false;
|
|||
void QGLView::init()
|
||||
{
|
||||
cam.type = Camera::GIMBAL;
|
||||
cam.object_rot << 35, 0, -25;
|
||||
cam.object_trans << 0, 0, 0;
|
||||
cam.viewer_distance = 500;
|
||||
resetView();
|
||||
|
||||
this->mouse_drag_active = false;
|
||||
this->statusLabel = NULL;
|
||||
|
@ -83,6 +81,13 @@ void QGLView::init()
|
|||
#endif
|
||||
}
|
||||
|
||||
void QGLView::resetView()
|
||||
{
|
||||
cam.object_rot << 35, 0, -25;
|
||||
cam.object_trans << 0, 0, 0;
|
||||
cam.viewer_distance = 500;
|
||||
}
|
||||
|
||||
void QGLView::initializeGL()
|
||||
{
|
||||
GLenum err = glewInit();
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
}
|
||||
std::string getRendererInfo() const;
|
||||
bool save(const char *filename);
|
||||
void resetView();
|
||||
|
||||
public:
|
||||
QLabel *statusLabel;
|
||||
|
|
|
@ -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>
|
||||
|
@ -48,9 +49,10 @@ typedef CGAL::Exact_predicates_exact_constructions_kernel CGAL_ExactKernel2;
|
|||
typedef CGAL::Polygon_2<CGAL_ExactKernel2> CGAL_Poly2;
|
||||
typedef CGAL::Polygon_with_holes_2<CGAL_ExactKernel2> CGAL_Poly2h;
|
||||
|
||||
//typedef CGAL::Cartesian<NT> CGAL_Kernel3;
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel CGAL_Kernel3;
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel::FT NT3;
|
||||
typedef CGAL::Gmpq NT3;
|
||||
typedef CGAL::Cartesian<NT3> CGAL_Kernel3;
|
||||
//typedef CGAL::Exact_predicates_exact_constructions_kernel::FT NT3;
|
||||
//typedef CGAL::Exact_predicates_exact_constructions_kernel CGAL_Kernel3;
|
||||
typedef CGAL::Nef_polyhedron_3<CGAL_Kernel3> CGAL_Nef_polyhedron3;
|
||||
typedef CGAL_Nef_polyhedron3::Aff_transformation_3 CGAL_Aff_transformation;
|
||||
|
||||
|
|
|
@ -78,12 +78,14 @@ void ControlModule::for_eval(AbstractNode &node, const ModuleInstantiation &inst
|
|||
Context c(ctx);
|
||||
if (it_values.type() == Value::RANGE) {
|
||||
Value::RangeType range = it_values.toRange();
|
||||
range.normalize();
|
||||
if (range.nbsteps()<10000) {
|
||||
for (double i = range.begin; i <= range.end; i += range.step) {
|
||||
c.set_variable(it_name, Value(i));
|
||||
for_eval(node, inst, l+1, &c, evalctx);
|
||||
}
|
||||
uint32_t steps = range.nbsteps();
|
||||
if (steps >= 10000) {
|
||||
PRINTB("WARNING: Bad range parameter in for statement: too many elements (%lu).", steps);
|
||||
} else {
|
||||
for (Value::RangeType::iterator it = range.begin();it != range.end();it++) {
|
||||
c.set_variable(it_name, Value(*it));
|
||||
for_eval(node, inst, l+1, &c, evalctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (it_values.type() == Value::VECTOR) {
|
||||
|
@ -227,13 +229,13 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
|
|||
else if (value.type() == Value::RANGE) {
|
||||
AbstractNode* node = new AbstractNode(inst);
|
||||
Value::RangeType range = value.toRange();
|
||||
range.normalize();
|
||||
if (range.nbsteps()>=10000) {
|
||||
PRINTB("WARNING: Bad range parameter for children: too many elements (%d).", (int)((range.begin-range.end)/range.step));
|
||||
uint32_t steps = range.nbsteps();
|
||||
if (steps >= 10000) {
|
||||
PRINTB("WARNING: Bad range parameter for children: too many elements (%lu).", steps);
|
||||
return NULL;
|
||||
}
|
||||
for (double i = range.begin; i <= range.end; i += range.step) {
|
||||
AbstractNode* childnode = getChild(Value(i),modulectx); // with error cases
|
||||
for (Value::RangeType::iterator it = range.begin();it != range.end();it++) {
|
||||
AbstractNode* childnode = getChild(Value(*it),modulectx); // with error cases
|
||||
if (childnode==NULL) continue; // error
|
||||
node->children.push_back(childnode);
|
||||
}
|
||||
|
|
|
@ -28,11 +28,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
#ifdef __APPLE__
|
||||
std::vector<Vector2d, Eigen::aligned_allocator<Vector2d> > points;
|
||||
#else
|
||||
std::vector<Vector2d> points;
|
||||
#endif
|
||||
std::vector<Path> paths;
|
||||
std::vector<Dim> dims;
|
||||
|
||||
|
|
|
@ -108,3 +108,17 @@ void Editor::wheelEvent ( QWheelEvent * event )
|
|||
}
|
||||
}
|
||||
|
||||
void Editor::setPlainText(const QString &text)
|
||||
{
|
||||
int y = verticalScrollBar()->sliderPosition();
|
||||
// Save current cursor position
|
||||
QTextCursor cursor = textCursor();
|
||||
int n = cursor.position();
|
||||
QTextEdit::setPlainText(text);
|
||||
// Restore cursor position
|
||||
if (n < text.length()) {
|
||||
cursor.setPosition(n);
|
||||
setTextCursor(cursor);
|
||||
verticalScrollBar()->setSliderPosition(y);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <QString>
|
||||
#include <QWidget>
|
||||
#include <QWheelEvent>
|
||||
#include <QScrollBar>
|
||||
|
||||
#include <QTextEdit>
|
||||
class Editor : public QTextEdit
|
||||
|
@ -9,6 +10,7 @@ class Editor : public QTextEdit
|
|||
Q_OBJECT
|
||||
public:
|
||||
Editor(QWidget *parent) : QTextEdit(parent) { setAcceptRichText(false); }
|
||||
void setPlainText(const QString &text);
|
||||
public slots:
|
||||
void zoomIn();
|
||||
void zoomOut();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
23
src/expr.cc
|
@ -117,11 +117,18 @@ Value Expression::evaluate(const Context *context) const
|
|||
if (this->type == "R") {
|
||||
Value v1 = this->children[0]->evaluate(context);
|
||||
Value v2 = this->children[1]->evaluate(context);
|
||||
Value v3 = this->children[2]->evaluate(context);
|
||||
if (v1.type() == Value::NUMBER && v2.type() == Value::NUMBER && v3.type() == Value::NUMBER) {
|
||||
Value::RangeType range(v1.toDouble(), v2.toDouble(), v3.toDouble());
|
||||
return Value(range);
|
||||
}
|
||||
if (this->children.size() == 2) {
|
||||
if (v1.type() == Value::NUMBER && v2.type() == Value::NUMBER) {
|
||||
Value::RangeType range(v1.toDouble(), v2.toDouble());
|
||||
return Value(range);
|
||||
}
|
||||
} else {
|
||||
Value v3 = this->children[2]->evaluate(context);
|
||||
if (v1.type() == Value::NUMBER && v2.type() == Value::NUMBER && v3.type() == Value::NUMBER) {
|
||||
Value::RangeType range(v1.toDouble(), v2.toDouble(), v3.toDouble());
|
||||
return Value(range);
|
||||
}
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
if (this->type == "V") {
|
||||
|
@ -192,7 +199,11 @@ std::string Expression::toString() const
|
|||
stream << this->const_value;
|
||||
}
|
||||
else if (this->type == "R") {
|
||||
stream << "[" << *this->children[0] << " : " << *this->children[1] << " : " << *this->children[2] << "]";
|
||||
stream << "[" << *this->children[0] << " : " << *this->children[1];
|
||||
if (this->children.size() > 2) {
|
||||
stream << " : " << *this->children[2];
|
||||
}
|
||||
stream << "]";
|
||||
}
|
||||
else if (this->type == "V") {
|
||||
stream << "[";
|
||||
|
|
|
@ -4,10 +4,13 @@
|
|||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
#include <Eigen/Dense>
|
||||
#include<Eigen/StdVector>
|
||||
|
||||
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Vector2d)
|
||||
using Eigen::Vector2d;
|
||||
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Vector3d)
|
||||
using Eigen::Vector3d;
|
||||
using Eigen::Vector3f;
|
||||
|
||||
typedef Eigen::AlignedBox<double, 3> BoundingBox;
|
||||
using Eigen::Matrix3f;
|
||||
using Eigen::Matrix3d;
|
||||
|
|
|
@ -334,6 +334,7 @@ MainWindow::MainWindow(const QString &filename)
|
|||
connect(this->viewActionBack, SIGNAL(triggered()), this, SLOT(viewAngleBack()));
|
||||
connect(this->viewActionDiagonal, SIGNAL(triggered()), this, SLOT(viewAngleDiagonal()));
|
||||
connect(this->viewActionCenter, SIGNAL(triggered()), this, SLOT(viewCenter()));
|
||||
connect(this->viewActionResetView, SIGNAL(triggered()), this, SLOT(viewResetView()));
|
||||
connect(this->viewActionPerspective, SIGNAL(triggered()), this, SLOT(viewPerspective()));
|
||||
connect(this->viewActionOrthogonal, SIGNAL(triggered()), this, SLOT(viewOrthogonal()));
|
||||
connect(this->viewActionHide, SIGNAL(triggered()), this, SLOT(hideConsole()));
|
||||
|
@ -503,6 +504,7 @@ MainWindow::openFile(const QString &new_filename)
|
|||
}
|
||||
#endif
|
||||
setFileName(actual_filename);
|
||||
editor->setPlainText("");
|
||||
|
||||
fileChangedOnDisk(); // force cached autoReloadId to update
|
||||
refreshDocument();
|
||||
|
@ -1772,6 +1774,12 @@ void MainWindow::viewOrthogonal()
|
|||
this->qglview->updateGL();
|
||||
}
|
||||
|
||||
void MainWindow::viewResetView()
|
||||
{
|
||||
this->qglview->resetView();
|
||||
this->qglview->updateGL();
|
||||
}
|
||||
|
||||
void MainWindow::hideConsole()
|
||||
{
|
||||
QSettings settings;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -453,7 +453,7 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
|
|||
// Only if "fileName" is not absolute, prepend the "absoluteBase".
|
||||
static QString assemblePath(const fs::path& absoluteBase,
|
||||
const string& fileName) {
|
||||
return QDir(QString::fromStdString((const string&) absoluteBase))
|
||||
return fileName.empty() ? "" : QDir(QString::fromStdString((const string&) absoluteBase))
|
||||
.absoluteFilePath(QString::fromStdString(fileName));
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
|
|
@ -325,11 +325,9 @@ expr:
|
|||
}
|
||||
| '[' expr ':' expr ']'
|
||||
{
|
||||
Expression *e_one = new Expression(Value(1.0));
|
||||
$$ = new Expression();
|
||||
$$->type = "R";
|
||||
$$->children.push_back($2);
|
||||
$$->children.push_back(e_one);
|
||||
$$->children.push_back($4);
|
||||
}
|
||||
| '[' expr ':' expr ':' expr ']'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#if defined(__APPLE__) && defined(__GNUC__)
|
||||
#if defined(__APPLE__) && defined(__GNUC__) && !defined(__clang__)
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
|
102
src/value.cc
|
@ -232,7 +232,7 @@ public:
|
|||
}
|
||||
|
||||
std::string operator()(const Value::RangeType &v) const {
|
||||
return (boost::format("[%1% : %2% : %3%]") % v.begin % v.step % v.end).str();
|
||||
return (boost::format("[%1% : %2% : %3%]") % v.begin_val % v.step_val % v.end_val).str();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -600,9 +600,9 @@ public:
|
|||
|
||||
Value operator()(const Value::RangeType &range, const double &idx) const {
|
||||
switch(int(idx)) {
|
||||
case 0: return Value(range.begin);
|
||||
case 1: return Value(range.step);
|
||||
case 2: return Value(range.end);
|
||||
case 0: return Value(range.begin_val);
|
||||
case 1: return Value(range.step_val);
|
||||
case 2: return Value(range.end_val);
|
||||
}
|
||||
return Value::undefined;
|
||||
}
|
||||
|
@ -617,3 +617,97 @@ Value Value::operator[](const Value &v)
|
|||
{
|
||||
return boost::apply_visitor(bracket_visitor(), this->value, v.value);
|
||||
}
|
||||
|
||||
void Value::RangeType::normalize() {
|
||||
if ((step_val>0) && (end_val < begin_val)) {
|
||||
std::swap(begin_val,end_val);
|
||||
PRINT("DEPRECATED: Using ranges of the form [begin:end] with begin value greater than the end value is deprecated.");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Value::RangeType::nbsteps() const {
|
||||
if (begin_val == end_val) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (step_val == 0) {
|
||||
return std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
double steps;
|
||||
if (step_val < 0) {
|
||||
if (begin_val < end_val) {
|
||||
return 0;
|
||||
}
|
||||
steps = (begin_val - end_val) / (-step_val);
|
||||
} else {
|
||||
if (begin_val > end_val) {
|
||||
return 0;
|
||||
}
|
||||
steps = (end_val - begin_val) / step_val;
|
||||
}
|
||||
|
||||
return steps;
|
||||
}
|
||||
|
||||
Value::RangeType::iterator::iterator(Value::RangeType &range, type_t type) : range(range), val(range.begin_val)
|
||||
{
|
||||
this->type = type;
|
||||
update_type();
|
||||
}
|
||||
|
||||
void Value::RangeType::iterator::update_type()
|
||||
{
|
||||
if (range.step_val == 0) {
|
||||
type = RANGE_TYPE_END;
|
||||
} else if (range.step_val < 0) {
|
||||
if (val < range.end_val) {
|
||||
type = RANGE_TYPE_END;
|
||||
}
|
||||
} else {
|
||||
if (val > range.end_val) {
|
||||
type = RANGE_TYPE_END;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Value::RangeType::iterator::reference Value::RangeType::iterator::operator*()
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
Value::RangeType::iterator::pointer Value::RangeType::iterator::operator->()
|
||||
{
|
||||
return &(operator*());
|
||||
}
|
||||
|
||||
Value::RangeType::iterator::self_type Value::RangeType::iterator::operator++()
|
||||
{
|
||||
if (type < 0) {
|
||||
type = RANGE_TYPE_RUNNING;
|
||||
}
|
||||
val += range.step_val;
|
||||
update_type();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value::RangeType::iterator::self_type Value::RangeType::iterator::operator++(int)
|
||||
{
|
||||
self_type tmp(*this);
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool Value::RangeType::iterator::operator==(const self_type &other) const
|
||||
{
|
||||
if (type == RANGE_TYPE_RUNNING) {
|
||||
return (type == other.type) && (val == other.val) && (range == other.range);
|
||||
} else {
|
||||
return (type == other.type) && (range == other.range);
|
||||
}
|
||||
}
|
||||
|
||||
bool Value::RangeType::iterator::operator!=(const self_type &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
|
78
src/value.h
|
@ -11,6 +11,7 @@
|
|||
#include <boost/variant.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#endif
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
class QuotedString : public std::string
|
||||
{
|
||||
|
@ -31,33 +32,64 @@ std::ostream &operator<<(std::ostream &stream, const Filename &filename);
|
|||
class Value
|
||||
{
|
||||
public:
|
||||
struct RangeType {
|
||||
RangeType(double begin, double step, double end)
|
||||
: begin(begin), step(step), end(end) {}
|
||||
class RangeType {
|
||||
private:
|
||||
double begin_val;
|
||||
double step_val;
|
||||
double end_val;
|
||||
|
||||
/// inverse begin/end if begin is upper than end
|
||||
void normalize();
|
||||
|
||||
bool operator==(const RangeType &other) const {
|
||||
return this->begin == other.begin &&
|
||||
this->step == other.step &&
|
||||
this->end == other.end;
|
||||
public:
|
||||
typedef enum { RANGE_TYPE_BEGIN, RANGE_TYPE_RUNNING, RANGE_TYPE_END } type_t;
|
||||
|
||||
class iterator {
|
||||
public:
|
||||
typedef iterator self_type;
|
||||
typedef double value_type;
|
||||
typedef double& reference;
|
||||
typedef double* pointer;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef double difference_type;
|
||||
iterator(RangeType &range, type_t type);
|
||||
self_type operator++();
|
||||
self_type operator++(int junk);
|
||||
reference operator*();
|
||||
pointer operator->();
|
||||
bool operator==(const self_type& other) const;
|
||||
bool operator!=(const self_type& other) const;
|
||||
private:
|
||||
RangeType ⦥
|
||||
double val;
|
||||
type_t type;
|
||||
|
||||
void update_type();
|
||||
};
|
||||
|
||||
RangeType(double begin, double end)
|
||||
: begin_val(begin), step_val(1.0), end_val(end)
|
||||
{
|
||||
normalize();
|
||||
}
|
||||
|
||||
/// inverse begin/end if begin is upper than end
|
||||
void normalize() {
|
||||
if ((step>0) && (end < begin)) {
|
||||
std::swap(begin,end);
|
||||
}
|
||||
}
|
||||
/// return number of steps, max int value if step is null
|
||||
int nbsteps() const {
|
||||
if (step<=0) {
|
||||
return std::numeric_limits<int>::max();
|
||||
}
|
||||
return (int)((begin-end)/step);
|
||||
}
|
||||
RangeType(double begin, double step, double end)
|
||||
: begin_val(begin), step_val(step), end_val(end) {}
|
||||
|
||||
double begin;
|
||||
double step;
|
||||
double end;
|
||||
bool operator==(const RangeType &other) const {
|
||||
return this->begin_val == other.begin_val &&
|
||||
this->step_val == other.step_val &&
|
||||
this->end_val == other.end_val;
|
||||
}
|
||||
|
||||
iterator begin() { return iterator(*this, RANGE_TYPE_BEGIN); }
|
||||
iterator end() { return iterator(*this, RANGE_TYPE_END); }
|
||||
|
||||
/// return number of steps, max uint32_t value if step is 0
|
||||
uint32_t nbsteps() const;
|
||||
|
||||
friend class tostring_visitor;
|
||||
friend class bracket_visitor;
|
||||
};
|
||||
|
||||
typedef std::vector<Value> VectorType;
|
||||
|
|
|
@ -35,8 +35,8 @@ a time, to avoid confusion.
|
|||
|
||||
|
||||
#include <Eigen/Core>
|
||||
#if not EIGEN_VERSION_AT_LEAST( 2,0,13 )
|
||||
#error eigen2 library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
|
||||
#if not EIGEN_VERSION_AT_LEAST( 3,0,0 )
|
||||
#error eigen library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
|
||||
#else
|
||||
|
||||
|
||||
|
@ -104,9 +104,17 @@ a time, to avoid confusion.
|
|||
#endif // ENABLE_CGAL
|
||||
|
||||
#endif // Boost
|
||||
#endif // Eigen2
|
||||
#endif // Eigen
|
||||
#endif // MPFR
|
||||
#endif // GMP
|
||||
|
||||
// see github issue #552
|
||||
#define GCC_VERSION (__GNUC__ * 10000 \
|
||||
+ __GNUC_MINOR__ * 100 \
|
||||
+ __GNUC_PATCHLEVEL__)
|
||||
#if GCC_VERSION == 40802
|
||||
#error "OpenSCAD isnt compatible with gcc 4.8.2. Please try a different version"
|
||||
#endif
|
||||
|
||||
#endif // OPENSCAD_SKIP_VERSION_CHECK
|
||||
|
||||
|
|
|
@ -22,10 +22,10 @@ for(r=[1:2:6]) translate([r*10-30,30,0]) difference() {cylinder(r=r, center=true
|
|||
for(r=[1.5:0.2:2.5]) translate([r*10-30,30,0]) cube([1, 4*r, 2], center=true);
|
||||
|
||||
// Negative range, negative step
|
||||
for(r=[5:-1:1]) translate([r*10-60,40,0]) cylinder(r=r);
|
||||
for(r=[5:-1:1]) translate([r*10-30,50,0]) cylinder(r=r);
|
||||
|
||||
// Negative range, positive step
|
||||
for(r=[5:1:1]) translate([r*10-30,40,0]) cylinder(r=r);
|
||||
// Negative range, positive step (using backward compatible auto swap of begin and end)
|
||||
for(r=[5:1]) translate([r*10-30,40,0]) cylinder(r=r);
|
||||
|
||||
// Zero step
|
||||
|
||||
|
|
|
@ -15,4 +15,10 @@ translate([-2,0,0]) polygon(points);
|
|||
translate([-2,-2,0]) polygon(points=points, paths=[[0,1,2,3], [4,5,6,7]]);
|
||||
translate([2,-4,0]) polygon([[0,0], [1,0], [1,1], [0,0]]);
|
||||
|
||||
// With hole
|
||||
translate([-2,-4,0])
|
||||
polygon(points=[[0,0], [1,0], [1,1], [0,1], [0.2,0.2], [0.8,0.2], [0.8,0.8], [0.2,0.8]],
|
||||
paths=[[0,1,2,3],[4,5,6,7]]
|
||||
);
|
||||
|
||||
// FIXME: convexity
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
// 2D child
|
||||
projection(cut=true) { square(); }
|
||||
|
||||
projection(cut=true) translate([20,0,0]) cube(10, center=true);
|
||||
|
||||
// Boundary case: clipping the top of a cube
|
||||
translate([0,20,0]) projection(cut=true) translate([0,0,-4.999999]) cube(10, center=true);
|
||||
|
||||
// holes
|
||||
translate([0,-10,0]) projection(cut=true) {
|
||||
union() {
|
||||
difference() { cube(5,center=true); cube(4,center=true); }
|
||||
translate([2.1,2.1]) difference() { cube(5,center=true); cube(4,center=true); }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
// Linear extrude
|
||||
translate([22,0,0]) linear_extrude(height=20) projection(cut=true) translate([0,0,9]) sphere(r=10);
|
||||
translate([44,0,0]) linear_extrude(height=20) projection(cut=true) translate([0,0,7]) sphere(r=10);
|
|
@ -3,18 +3,25 @@ projection();
|
|||
// No children
|
||||
projection() { }
|
||||
// 2D child
|
||||
projection(cut=true) { square(); }
|
||||
projection() { square(); }
|
||||
|
||||
linear_extrude(height=20) projection(cut=false) sphere(r=10);
|
||||
translate([22,0,0]) linear_extrude(height=20) projection(cut=true) translate([0,0,9]) sphere(r=10);
|
||||
translate([44,0,0]) linear_extrude(height=20) projection(cut=true) translate([0,0,7]) sphere(r=10);
|
||||
// Simple
|
||||
projection(cut=false) cube(10);
|
||||
|
||||
// Boundary case: clipping the top of a cube
|
||||
translate([0,-22,0]) linear_extrude(height=5) projection(cut=true) translate([0,0,-4.999999]) cube(10, center=true);
|
||||
// Two children
|
||||
translate([-12,0]) projection(cut=false) {
|
||||
cube(10);
|
||||
difference() {
|
||||
sphere(10);
|
||||
cylinder(h=30, r=5, center=true);
|
||||
}
|
||||
}
|
||||
|
||||
// holes
|
||||
translate([0,-44,0]) linear_extrude(height=5) projection(cut=true)
|
||||
union() {
|
||||
difference() { cube(5,center=true); cube(4,center=true); }
|
||||
translate([2.1,2.1]) difference() { cube(5,center=true); cube(4,center=true); }
|
||||
}
|
||||
// Holes
|
||||
translate([6,-12]) projection(cut=false) {
|
||||
cube(10);
|
||||
difference() {
|
||||
sphere(10);
|
||||
cylinder(h=30, r=5, center=true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
render() {
|
||||
difference() {
|
||||
square(100, center=true);
|
||||
circle(r=30);
|
||||
square(10, center=true);
|
||||
circle(r=3);
|
||||
}
|
||||
}
|
||||
|
||||
translate([12,0,0]) render() {
|
||||
square(10, center=true);
|
||||
circle(r=3);
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ module test_children_range() {
|
|||
children([0:4]); // all
|
||||
children([1:2]); // child2, child3
|
||||
children([0:2:4]); // child1, child3, child5
|
||||
children([4:-1:0]); // out, out
|
||||
children([0:-1:4]); // out, out
|
||||
echo("Children range: end");
|
||||
}
|
||||
test_children_range() {
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
echo("[a01] ----- [1:4]"); for (a = [1:4]) echo ("[a01] ", a);
|
||||
echo("[a02] ----- [4:1]"); for (a = [4:1]) echo ("[a02] ", a);
|
||||
echo("[a03] ----- [0:0]"); for (a = [0:0]) echo ("[a03] ", a);
|
||||
echo("[a04] ----- [0:3]"); for (a = [0:3]) echo ("[a04] ", a);
|
||||
echo("[a05] ----- [-3:0]"); for (a = [-3:0]) echo ("[a05] ", a);
|
||||
echo("[a06] ----- [0:-3]"); for (a = [0:-3]) echo ("[a06] ", a);
|
||||
echo("[a07] ----- [-2:2]"); for (a = [-2:2]) echo ("[a07] ", a);
|
||||
echo("[a08] ----- [2:-2]"); for (a = [2:-2]) echo ("[a08] ", a);
|
||||
|
||||
echo("[b01] ----- [1:1:5]"); for (a = [1:1:5]) echo ("[b01] ", a);
|
||||
echo("[b02] ----- [1:2:5]"); for (a = [1:2:5]) echo ("[b02] ", a);
|
||||
echo("[b03] ----- [1:-1:5]"); for (a = [1:-1:5]) echo ("[b03] ", a);
|
||||
echo("[b04] ----- [5:1:1]"); for (a = [5:1:1]) echo ("[b04] ", a);
|
||||
echo("[b05] ----- [5:2:1]"); for (a = [5:2:1]) echo ("[b05] ", a);
|
||||
echo("[b06] ----- [5:-1:1]"); for (a = [5:-1:1]) echo ("[b06] ", a);
|
||||
echo("[b07] ----- [0:0:0]"); for (a = [0:0:0]) echo ("[b07] ", a);
|
||||
echo("[b08] ----- [1:0:1]"); for (a = [1:0:1]) echo ("[b08] ", a);
|
||||
echo("[b09] ----- [1:0:5]"); for (a = [1:0:5]) echo ("[b09] ", a);
|
||||
echo("[b10] ----- [0:1:0]"); for (a = [0:1:0]) echo ("[b10] ", a);
|
||||
echo("[b11] ----- [3:-.5:-3]"); for (a = [3:-.5:-3]) echo ("[b11] ", a);
|
|
@ -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")
|
||||
|
@ -212,30 +219,21 @@ if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
|||
endif()
|
||||
|
||||
# Priority
|
||||
# 3. EIGENDIR if set (EIGEN2DIR for backwards compatability)
|
||||
# 3. EIGENDIR if set
|
||||
# 1. OPENSCAD_LIBRARIES eigen3
|
||||
# 2. OPENSCAD_LIBRARIES eigen2
|
||||
# 4. system's standard include paths for eigen3
|
||||
# 5. system's standard include paths for eigen2
|
||||
|
||||
set(EIGEN2_DIR "$ENV{EIGEN2DIR}")
|
||||
set(EIGEN_DIR "$ENV{EIGENDIR}")
|
||||
set(OPENSCAD_LIBDIR "$ENV{OPENSCAD_LIBRARIES}")
|
||||
|
||||
if (EIGEN_DIR)
|
||||
set(EIGHINT ${EIGEN_DIR}/include/eigen3 ${EIGEN_DIR}/include/eigen2 ${EIGEN_DIR})
|
||||
set(EIGHINT ${EIGEN_DIR}/include/eigen3 ${EIGEN_DIR})
|
||||
find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS ${EIGHINT})
|
||||
endif()
|
||||
if (EIGEN2_DIR)
|
||||
find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS ${EIGEN2_DIR}/include/eigen2 ${EIGEN2_DIR})
|
||||
endif()
|
||||
|
||||
if (NOT EIGEN_INCLUDE_DIR)
|
||||
find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS ${OPENSCAD_LIBDIR}/include/eigen3)
|
||||
endif()
|
||||
if (NOT EIGEN_INCLUDE_DIR)
|
||||
find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS ${OPENSCAD_LIBDIR}/include/eigen2)
|
||||
endif()
|
||||
|
||||
if (NOT EIGEN_INCLUDE_DIR)
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
|
@ -249,18 +247,6 @@ if (NOT EIGEN_INCLUDE_DIR)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT EIGEN_INCLUDE_DIR)
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS /usr/local/include/eigen2)
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
|
||||
find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS /usr/pkg/include/eigen2)
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS /opt/local/include/eigen2)
|
||||
else()
|
||||
find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS /usr/include/eigen2)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT EIGEN_INCLUDE_DIR)
|
||||
message(STATUS "Eigen not found")
|
||||
else()
|
||||
|
@ -450,9 +436,11 @@ message(STATUS "OpenSCAD version: ${VERSION}")
|
|||
string(REGEX MATCHALL "^[0-9]+|[0-9]+|[0-9]+$" MYLIST "${VERSION}")
|
||||
list(GET MYLIST 0 OPENSCAD_YEAR)
|
||||
list(GET MYLIST 1 OPENSCAD_MONTH)
|
||||
math(EXPR OPENSCAD_MONTH ${OPENSCAD_MONTH}) # get rid of leading zero
|
||||
list(LENGTH MYLIST VERSIONLEN)
|
||||
if (${VERSIONLEN} EQUAL 3)
|
||||
list(GET MYLIST 2 OPENSCAD_DAY)
|
||||
math(EXPR OPENSCAD_DAY ${OPENSCAD_DAY}) # get rid of leading zero
|
||||
endif()
|
||||
|
||||
add_definitions(-DOPENSCAD_VERSION=${VERSION} -DOPENSCAD_YEAR=${OPENSCAD_YEAR} -DOPENSCAD_MONTH=${OPENSCAD_MONTH})
|
||||
|
@ -802,7 +790,8 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES}
|
|||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/lookup-tests.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/expression-shortcircuit-tests.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/parent_module-tests.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/children-tests.scad)
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/children-tests.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/range-tests.scad)
|
||||
|
||||
list(APPEND DUMPTEST_FILES ${FEATURES_FILES} ${EXAMPLE_FILES})
|
||||
list(APPEND DUMPTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test.scad
|
||||
|
@ -812,12 +801,14 @@ list(APPEND DUMPTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test
|
|||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles_dir/localfiles-compatibility-test.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/allexpressions.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/allfunctions.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/stl-cgal-convert_to_Polyhedron-crash.scad
|
||||
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/allmodules.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/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)
|
||||
|
||||
|
@ -840,6 +831,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
|
||||
|
@ -852,12 +847,8 @@ disable_tests(cgalpngtest_child-background
|
|||
# Test config handling
|
||||
|
||||
set_test_config(Heavy opencsgtest_minkowski3-tests
|
||||
opencsgtest_projection-tests
|
||||
openscad-csgpng_minkowski3-tests
|
||||
openscad-csgpng_projection-tests
|
||||
throwntogethertest_minkowski3-tests
|
||||
throwntogethertest_projection-tests
|
||||
cgalpngtest_projection-tests
|
||||
cgalpngtest_rotate_extrude-tests
|
||||
cgalpngtest_surface-tests
|
||||
cgalpngtest_sphere-tests
|
||||
|
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 4.2 KiB |
|
@ -80,7 +80,23 @@ group() {
|
|||
cube(size = [1, 9.2, 2], center = true);
|
||||
}
|
||||
}
|
||||
group();
|
||||
group() {
|
||||
multmatrix([[1, 0, 0, 20], [0, 1, 0, 50], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 5, r2 = 5, center = false);
|
||||
}
|
||||
multmatrix([[1, 0, 0, 10], [0, 1, 0, 50], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 4, r2 = 4, center = false);
|
||||
}
|
||||
multmatrix([[1, 0, 0, 0], [0, 1, 0, 50], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 3, r2 = 3, center = false);
|
||||
}
|
||||
multmatrix([[1, 0, 0, -10], [0, 1, 0, 50], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 2, r2 = 2, center = false);
|
||||
}
|
||||
multmatrix([[1, 0, 0, -20], [0, 1, 0, 50], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 1, r2 = 1, center = false);
|
||||
}
|
||||
}
|
||||
group() {
|
||||
multmatrix([[1, 0, 0, -20], [0, 1, 0, 40], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 1, r2 = 1, center = false);
|
||||
|
|
|
@ -33,4 +33,7 @@ group() {
|
|||
multmatrix([[1, 0, 0, 2], [0, 1, 0, -4], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
polygon(points = [[0, 0], [1, 0], [1, 1], [0, 0]], paths = undef, convexity = 1);
|
||||
}
|
||||
multmatrix([[1, 0, 0, -2], [0, 1, 0, -4], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
polygon(points = [[0, 0], [1, 0], [1, 1], [0, 1], [0.2, 0.2], [0.8, 0.2], [0.8, 0.8], [0.2, 0.8]], paths = [[0, 1, 2, 3], [4, 5, 6, 7]], convexity = 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
group() {
|
||||
projection(cut = true, convexity = 0) {
|
||||
square(size = [1, 1], center = false);
|
||||
}
|
||||
projection(cut = true, convexity = 0) {
|
||||
multmatrix([[1, 0, 0, 20], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
cube(size = [10, 10, 10], center = true);
|
||||
}
|
||||
}
|
||||
multmatrix([[1, 0, 0, 0], [0, 1, 0, 20], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
projection(cut = true, convexity = 0) {
|
||||
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, -4.999999], [0, 0, 0, 1]]) {
|
||||
cube(size = [10, 10, 10], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
multmatrix([[1, 0, 0, 0], [0, 1, 0, -10], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
projection(cut = true, convexity = 0) {
|
||||
union() {
|
||||
difference() {
|
||||
cube(size = [5, 5, 5], center = true);
|
||||
cube(size = [4, 4, 4], center = true);
|
||||
}
|
||||
multmatrix([[1, 0, 0, 2.1], [0, 1, 0, 2.1], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
difference() {
|
||||
cube(size = [5, 5, 5], center = true);
|
||||
cube(size = [4, 4, 4], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
group() {
|
||||
multmatrix([[1, 0, 0, 22], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
linear_extrude(height = 20, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
|
||||
projection(cut = true, convexity = 0) {
|
||||
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 9], [0, 0, 0, 1]]) {
|
||||
sphere($fn = 0, $fa = 12, $fs = 2, r = 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
multmatrix([[1, 0, 0, 44], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
linear_extrude(height = 20, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
|
||||
projection(cut = true, convexity = 0) {
|
||||
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 7], [0, 0, 0, 1]]) {
|
||||
sphere($fn = 0, $fa = 12, $fs = 2, r = 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,56 +1,27 @@
|
|||
group() {
|
||||
projection(cut = false, convexity = 0);
|
||||
projection(cut = false, convexity = 0);
|
||||
projection(cut = true, convexity = 0) {
|
||||
projection(cut = false, convexity = 0) {
|
||||
square(size = [1, 1], center = false);
|
||||
}
|
||||
linear_extrude(height = 20, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
|
||||
projection(cut = false, convexity = 0) {
|
||||
cube(size = [10, 10, 10], center = false);
|
||||
}
|
||||
multmatrix([[1, 0, 0, -12], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
projection(cut = false, convexity = 0) {
|
||||
sphere($fn = 0, $fa = 12, $fs = 2, r = 10);
|
||||
}
|
||||
}
|
||||
multmatrix([[1, 0, 0, 22], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
linear_extrude(height = 20, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
|
||||
projection(cut = true, convexity = 0) {
|
||||
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 9], [0, 0, 0, 1]]) {
|
||||
sphere($fn = 0, $fa = 12, $fs = 2, r = 10);
|
||||
}
|
||||
cube(size = [10, 10, 10], center = false);
|
||||
difference() {
|
||||
sphere($fn = 0, $fa = 12, $fs = 2, r = 10);
|
||||
cylinder($fn = 0, $fa = 12, $fs = 2, h = 30, r1 = 5, r2 = 5, center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
multmatrix([[1, 0, 0, 44], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
linear_extrude(height = 20, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
|
||||
projection(cut = true, convexity = 0) {
|
||||
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 7], [0, 0, 0, 1]]) {
|
||||
sphere($fn = 0, $fa = 12, $fs = 2, r = 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
multmatrix([[1, 0, 0, 0], [0, 1, 0, -22], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
linear_extrude(height = 5, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
|
||||
projection(cut = true, convexity = 0) {
|
||||
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, -4.999999], [0, 0, 0, 1]]) {
|
||||
cube(size = [10, 10, 10], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
multmatrix([[1, 0, 0, 0], [0, 1, 0, -44], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
linear_extrude(height = 5, center = false, convexity = 1, scale = [1, 1], $fn = 0, $fa = 12, $fs = 2) {
|
||||
projection(cut = true, convexity = 0) {
|
||||
union() {
|
||||
difference() {
|
||||
cube(size = [5, 5, 5], center = true);
|
||||
cube(size = [4, 4, 4], center = true);
|
||||
}
|
||||
multmatrix([[1, 0, 0, 2.1], [0, 1, 0, 2.1], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
difference() {
|
||||
cube(size = [5, 5, 5], center = true);
|
||||
cube(size = [4, 4, 4], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
multmatrix([[1, 0, 0, 6], [0, 1, 0, -12], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
projection(cut = false, convexity = 0) {
|
||||
cube(size = [10, 10, 10], center = false);
|
||||
difference() {
|
||||
sphere($fn = 0, $fa = 12, $fs = 2, r = 10);
|
||||
cylinder($fn = 0, $fa = 12, $fs = 2, h = 30, r1 = 5, r2 = 5, center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
group() {
|
||||
render(convexity = 1) {
|
||||
difference() {
|
||||
square(size = [100, 100], center = true);
|
||||
circle($fn = 0, $fa = 12, $fs = 2, r = 30);
|
||||
square(size = [10, 10], center = true);
|
||||
circle($fn = 0, $fa = 12, $fs = 2, r = 3);
|
||||
}
|
||||
}
|
||||
multmatrix([[1, 0, 0, 12], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
|
||||
render(convexity = 1) {
|
||||
square(size = [10, 10], center = true);
|
||||
circle($fn = 0, $fa = 12, $fs = 2, r = 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -31,5 +31,4 @@ ECHO: "child3"
|
|||
ECHO: "child1"
|
||||
ECHO: "child3"
|
||||
ECHO: "child5"
|
||||
WARNING: Bad range parameter for children: too many elements (-4).
|
||||
ECHO: "Children range: end"
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
ECHO: "[a01] ----- [1:4]"
|
||||
ECHO: "[a01] ", 1
|
||||
ECHO: "[a01] ", 2
|
||||
ECHO: "[a01] ", 3
|
||||
ECHO: "[a01] ", 4
|
||||
ECHO: "[a02] ----- [4:1]"
|
||||
DEPRECATED: Using ranges of the form [begin:end] with begin value greater than the end value is deprecated.
|
||||
ECHO: "[a02] ", 1
|
||||
ECHO: "[a02] ", 2
|
||||
ECHO: "[a02] ", 3
|
||||
ECHO: "[a02] ", 4
|
||||
ECHO: "[a03] ----- [0:0]"
|
||||
ECHO: "[a03] ", 0
|
||||
ECHO: "[a04] ----- [0:3]"
|
||||
ECHO: "[a04] ", 0
|
||||
ECHO: "[a04] ", 1
|
||||
ECHO: "[a04] ", 2
|
||||
ECHO: "[a04] ", 3
|
||||
ECHO: "[a05] ----- [-3:0]"
|
||||
ECHO: "[a05] ", -3
|
||||
ECHO: "[a05] ", -2
|
||||
ECHO: "[a05] ", -1
|
||||
ECHO: "[a05] ", 0
|
||||
ECHO: "[a06] ----- [0:-3]"
|
||||
DEPRECATED: Using ranges of the form [begin:end] with begin value greater than the end value is deprecated.
|
||||
ECHO: "[a06] ", -3
|
||||
ECHO: "[a06] ", -2
|
||||
ECHO: "[a06] ", -1
|
||||
ECHO: "[a06] ", 0
|
||||
ECHO: "[a07] ----- [-2:2]"
|
||||
ECHO: "[a07] ", -2
|
||||
ECHO: "[a07] ", -1
|
||||
ECHO: "[a07] ", 0
|
||||
ECHO: "[a07] ", 1
|
||||
ECHO: "[a07] ", 2
|
||||
ECHO: "[a08] ----- [2:-2]"
|
||||
DEPRECATED: Using ranges of the form [begin:end] with begin value greater than the end value is deprecated.
|
||||
ECHO: "[a08] ", -2
|
||||
ECHO: "[a08] ", -1
|
||||
ECHO: "[a08] ", 0
|
||||
ECHO: "[a08] ", 1
|
||||
ECHO: "[a08] ", 2
|
||||
ECHO: "[b01] ----- [1:1:5]"
|
||||
ECHO: "[b01] ", 1
|
||||
ECHO: "[b01] ", 2
|
||||
ECHO: "[b01] ", 3
|
||||
ECHO: "[b01] ", 4
|
||||
ECHO: "[b01] ", 5
|
||||
ECHO: "[b02] ----- [1:2:5]"
|
||||
ECHO: "[b02] ", 1
|
||||
ECHO: "[b02] ", 3
|
||||
ECHO: "[b02] ", 5
|
||||
ECHO: "[b03] ----- [1:-1:5]"
|
||||
ECHO: "[b04] ----- [5:1:1]"
|
||||
ECHO: "[b05] ----- [5:2:1]"
|
||||
ECHO: "[b06] ----- [5:-1:1]"
|
||||
ECHO: "[b06] ", 5
|
||||
ECHO: "[b06] ", 4
|
||||
ECHO: "[b06] ", 3
|
||||
ECHO: "[b06] ", 2
|
||||
ECHO: "[b06] ", 1
|
||||
ECHO: "[b07] ----- [0:0:0]"
|
||||
ECHO: "[b08] ----- [1:0:1]"
|
||||
ECHO: "[b09] ----- [1:0:5]"
|
||||
WARNING: Bad range parameter in for statement: too many elements (4294967295).
|
||||
ECHO: "[b10] ----- [0:1:0]"
|
||||
ECHO: "[b10] ", 0
|
||||
ECHO: "[b11] ----- [3:-.5:-3]"
|
||||
ECHO: "[b11] ", 3
|
||||
ECHO: "[b11] ", 2.5
|
||||
ECHO: "[b11] ", 2
|
||||
ECHO: "[b11] ", 1.5
|
||||
ECHO: "[b11] ", 1
|
||||
ECHO: "[b11] ", 0.5
|
||||
ECHO: "[b11] ", 0
|
||||
ECHO: "[b11] ", -0.5
|
||||
ECHO: "[b11] ", -1
|
||||
ECHO: "[b11] ", -1.5
|
||||
ECHO: "[b11] ", -2
|
||||
ECHO: "[b11] ", -2.5
|
||||
ECHO: "[b11] ", -3
|
|
@ -6,7 +6,7 @@ e = $fn;
|
|||
f1 = [1];
|
||||
f2 = [1, 2, 3];
|
||||
g = ((f2.x + f2.y) + f2.z);
|
||||
h1 = [2 : 1 : 5];
|
||||
h1 = [2 : 5];
|
||||
h2 = [1 : 2 : 10];
|
||||
i = ((h2.begin - h2.step) - h2.end);
|
||||
j = "test";
|
||||
|
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 9.3 KiB |
After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 9.4 KiB |
After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.8 KiB |
|
@ -25,544 +25,441 @@
|
|||
|
||||
# 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 __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 __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 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'
|
||||
|
||||
if bool(os.getenv("TEST_GENERATE")):
|
||||
sys.exit(0)
|
||||
|
||||
# --- Command Line Parsing ---
|
||||
|
||||
if '--debug' in ' '.join(sys.argv):
|
||||
debug_test_pp = True
|
||||
maxretry = 10
|
||||
|
||||
wikisite = 'cakebaby.wikia.com'
|
||||
wiki_api_path = '/'
|
||||
wiki_rootpath = 'OpenSCAD'
|
||||
if '--debug' in string.join(sys.argv): debug_test_pp=True
|
||||
maxretry = 10
|
||||
if '--include-passed' in sys.argv:
|
||||
include_passed = True
|
||||
|
||||
if bool(os.getenv("TEST_GENERATE")): sys.exit(0)
|
||||
dry = False
|
||||
debug('running test_pretty_print')
|
||||
if '--dryrun' in sys.argv:
|
||||
dry = True
|
||||
|
||||
include_passed = False
|
||||
if '--include-passed' in sys.argv: include_passed = True
|
||||
suffix = ezsearch('--suffix=(.*?) ', ' '.join(sys.argv) + ' ')
|
||||
builddir = ezsearch('--builddir=(.*?) ', ' '.join(sys.argv) + ' ')
|
||||
if not builddir:
|
||||
builddir = os.getcwd()
|
||||
debug('build dir set to ' + builddir)
|
||||
|
||||
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 )
|
||||
upload = False
|
||||
if '--upload' in sys.argv:
|
||||
upload = True
|
||||
debug('will upload test report')
|
||||
|
||||
# --- End Command Line Parsing ---
|
||||
|
||||
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'
|
||||
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'
|
||||
|
||||
imgs, txtpages = towiki(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, makefiles)
|
||||
|
||||
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])
|
||||
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)
|
||||
|
||||
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,'')
|
||||
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'
|
||||
|
||||
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'
|
||||
|
||||
debug( 'test_pretty_print complete' )
|
||||
debug('test_pretty_print complete')
|
||||
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
main()
|
||||
|
|