diff options
30 files changed, 293 insertions, 130 deletions
diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 7807e77..ff39b18 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,4 +1,32 @@ -o Additional output formats: AST, TERM, null +OpenSCAD YYYY.MM +================ + +Language Features: +o Added diameter argument: circle(d), cylinder(d, d1, d2) and sphere(d) +o Added parent_module() and $parent_modules +o Added children() as a replacement for child() + +Program Features: +o Added --info parameter to the cmd-line for system/library info + +Bugfixes: +o Automatic reloads of large designs are more robust +o Boolean logic in if() statements are now correctly short-circuited +o rands() with zero range caused an infinite loop +o resize(, auto=true) didn't work when shrinking objects +o The $children variable sometimes misbehaved due to dynamic scoping +o The --camera cmd-line option behaved differently then the corresponding GUI function +o PNG export now doesn't leak transparency settings into the target image +o Improved performance of OpenCSG (F5) compilation in some cases + +Deprecations: +o child() is no longer supported. Use children() instead. + +Misc: +o We now use CGAL's EPEC kernel +o Additional output formats: .ast, .term, null (these are most useful for testing) +o Test framework now shares more code with the GUI app +o Better compatibility with BSD systems OpenSCAD 2013.06 ================ diff --git a/appcast-snapshots.xml.in b/appcast-snapshots.xml.in index f46c814..acd10aa 100644 --- a/appcast-snapshots.xml.in +++ b/appcast-snapshots.xml.in @@ -3,12 +3,12 @@ <channel> <title>OpenSCAD Development Snapshots</title> <link>http://openscad.org/appcast-snapshots.xml</link> - <language>en</language> + <language>en</language> <item> <title>OpenSCAD @VERSION@</title> <pubDate>@VERSIONDATE@</pubDate> <sparkle:releaseNotesLink>https://raw.github.com/openscad/openscad/master/RELEASE_NOTES</sparkle:releaseNotesLink> - <enclosure url="https://openscad.googlecode.com/files/OpenSCAD-@VERSION@.dmg" + <enclosure url="http://files.openscad.org/OpenSCAD-@VERSION@.dmg" sparkle:version="@VERSIONDATE@" sparkle:shortVersionString="@VERSION@" sparkle:dsaSignature="@DSASIGNATURE@" diff --git a/appcast.xml.in b/appcast.xml.in index f61710c..8961a57 100644 --- a/appcast.xml.in +++ b/appcast.xml.in @@ -8,7 +8,7 @@ <title>OpenSCAD @VERSION@</title> <pubDate>@VERSIONDATE@</pubDate> <sparkle:releaseNotesLink>https://raw.github.com/openscad/openscad/openscad-@VERSION@/RELEASE_NOTES</sparkle:releaseNotesLink> - <enclosure url="https://openscad.googlecode.com/files/OpenSCAD-@VERSION@.dmg" + <enclosure url="http://files.openscad.org/OpenSCAD-@VERSION@.dmg" sparkle:version="@VERSIONDATE@" sparkle:shortVersionString="@VERSION@" sparkle:dsaSignature="@DSASIGNATURE@" diff --git a/scripts/check-dependencies.sh b/scripts/check-dependencies.sh index c4f2893..120aed9 100755 --- a/scripts/check-dependencies.sh +++ b/scripts/check-dependencies.sh @@ -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() @@ -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 diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh index a257201..d1c5985 100755 --- a/scripts/macosx-build-dependencies.sh +++ b/scripts/macosx-build-dependencies.sh @@ -8,7 +8,6 @@ # # Usage: macosx-build-dependencies.sh [-6lcd] # -6 Build only 64-bit binaries -# -c Force use of LLVM compiler # -l Force use of LLVM compiler # -c Force use of clang compiler # -d Build for deployment (if not specified, e.g. Sparkle won't be built) @@ -221,7 +220,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" install + ./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 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 @@ -241,8 +240,9 @@ build_cgal() cd $BASEDIR/src rm -rf CGAL-$version if [ ! -f CGAL-$version.tar.gz ]; then - # 4.2 - curl -O https://gforge.inria.fr/frs/download.php/32359/CGAL-$version.tar.gz + # 4.3 + curl -O https://gforge.inria.fr/frs/download.php/32994/CGAL-$version.tar.gz + # 4.2 curl -O https://gforge.inria.fr/frs/download.php/32359/CGAL-$version.tar.gz # 4.1 curl -O https://gforge.inria.fr/frs/download.php/31641/CGAL-$version.tar.gz # 4.1-beta1 curl -O https://gforge.inria.fr/frs/download.php/31348/CGAL-$version.tar.gz # 4.0.2 curl -O https://gforge.inria.fr/frs/download.php/31175/CGAL-$version.tar.gz @@ -311,7 +311,9 @@ build_eigen() 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; fi + elif [ $version = "3.1.3" ]; then EIGENDIR=eigen-eigen-2249f9c22fe8; + 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. @@ -341,12 +343,13 @@ build_sparkle() # Let Sparkle use the default compiler unset CC unset CXX - version=$1 + github=$1 + version=$2 echo "Building Sparkle" $version "..." cd $BASEDIR/src rm -rf Sparkle-$version if [ ! -f Sparkle-$version.zip ]; then - curl -o Sparkle-$version.zip https://nodeload.github.com/andymatuschak/Sparkle/zip/$version + curl -o Sparkle-$version.zip https://nodeload.github.com/$github/Sparkle/zip/$version fi unzip -q Sparkle-$version.zip cd Sparkle-$version @@ -389,7 +392,7 @@ USING_LLVM=false USING_GCC=false USING_CLANG=false if $OPTION_LLVM; then - USING_LLCM=true + USING_LLVM=true elif $OPTION_GCC; then USING_GCC=true elif $OPTION_CLANG; then @@ -437,14 +440,15 @@ 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.3 -build_gmp 5.1.2 +build_eigen 3.2.0 +build_gmp 5.1.3 build_mpfr 3.1.2 -build_boost 1.53.0 +build_boost 1.54.0 # NB! For CGAL, also update the actual download URL in the function -build_cgal 4.2 -build_glew 1.9.0 +build_cgal 4.3 +build_glew 1.10.0 build_opencsg 1.3.2 if $OPTION_DEPLOY; then - build_sparkle 0ed83cf9f2eeb425d4fdd141c01a29d843970c20 +# build_sparkle andymatuschak 0ed83cf9f2eeb425d4fdd141c01a29d843970c20 + build_sparkle Cocoanetics 1e7dcb1a48b96d1a8c62100b5864bd50211cbae1 fi diff --git a/scripts/publish-macosx.sh b/scripts/publish-macosx.sh index 3617570..738f7db 100755 --- a/scripts/publish-macosx.sh +++ b/scripts/publish-macosx.sh @@ -21,7 +21,7 @@ update_www_download_links() filesize=$(human_filesize $filesize) webdir=../openscad.github.com incfile=inc/mac_snapshot_links.js - BASEURL='https://openscad.googlecode.com/files/' + BASEURL='http://files.openscad.org/' DATECODE=`date +"%Y.%m.%d"` if [ -f $webdir/$incfile ]; then @@ -83,13 +83,6 @@ if [[ $VERSION == $VERSIONDATE ]]; then fi echo "Uploading..." -LABELS=OpSys-OSX,Type-Executable -if ! $SNAPSHOT; then LABELS=$LABELS,Featured; fi -`dirname $0`/googlecode_upload.py -s 'Mac OS X Snapshot' -p openscad OpenSCAD-$VERSION.dmg -l $LABELS -if [[ $? != 0 ]]; then - exit 1 -fi - scp OpenSCAD-$VERSION.dmg openscad@files.openscad.org:www if [[ $? != 0 ]]; then exit 1 diff --git a/scripts/uni-build-dependencies.sh b/scripts/uni-build-dependencies.sh index 48f162a..620c705 100755 --- a/scripts/uni-build-dependencies.sh +++ b/scripts/uni-build-dependencies.sh @@ -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 diff --git a/src/CocoaUtils.h b/src/CocoaUtils.h index 8543d84..35e8c28 100644 --- a/src/CocoaUtils.h +++ b/src/CocoaUtils.h @@ -1,10 +1,13 @@ #ifndef COCOAUTILS_H_ #define COCOAUTILS_H_ +#include <string> + class CocoaUtils { public: static void endApplication(); + static void nslog(const std::string &str, void *userdata); }; #endif diff --git a/src/CocoaUtils.mm b/src/CocoaUtils.mm index b72583c..92640fd 100644 --- a/src/CocoaUtils.mm +++ b/src/CocoaUtils.mm @@ -8,3 +8,7 @@ void CocoaUtils::endApplication() object:nil]; } +void CocoaUtils::nslog(const std::string &str, void *userdata) +{ + NSLog([NSString stringWithUTF8String: str.c_str()]); +} diff --git a/src/PlatformUtils.cc b/src/PlatformUtils.cc index 5059b78..cfa5731 100644 --- a/src/PlatformUtils.cc +++ b/src/PlatformUtils.cc @@ -114,7 +114,7 @@ std::string PlatformUtils::info() << "\nOpenCSG version: " << OPENCSG_VERSION_STRING << "\nQt version: " << qtVersion << "\nMingW build: " << mingwstatus - << "\nOPENSCADPATH: " << getenv("OPENSCADPATH") + << "\nOPENSCADPATH: " << getenv("OPENSCADPATH") << "\n" ; return s.str(); } diff --git a/src/QGLView.cc b/src/QGLView.cc index 25ed323..6ffd586 100644 --- a/src/QGLView.cc +++ b/src/QGLView.cc @@ -172,15 +172,20 @@ void QGLView::paintGL() void QGLView::keyPressEvent(QKeyEvent *event) { - if (event->key() == Qt::Key_Plus) { + switch (event->key()) { + case Qt::Key_Plus: // On many keyboards, this requires to press Shift-equals + case Qt::Key_Equal: // ...so simplify this a bit. cam.viewer_distance *= 0.9; updateGL(); - return; - } - if (event->key() == Qt::Key_Minus) { + break; + case Qt::Key_Minus: cam.viewer_distance /= 0.9; updateGL(); - return; + break; + case Qt::Key_C: // 'center' + cam.object_trans << 0, 0, 0; + updateGL(); + break; } } @@ -192,6 +197,7 @@ void QGLView::wheelEvent(QWheelEvent *event) void QGLView::mousePressEvent(QMouseEvent *event) { + setFocus(); mouse_drag_active = true; last_mouse = event->globalPos(); } diff --git a/src/dxfdata.h b/src/dxfdata.h index 64853dc..ac7260c 100644 --- a/src/dxfdata.h +++ b/src/dxfdata.h @@ -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; diff --git a/src/linalg.h b/src/linalg.h index 1f9ed30..cb82452 100644 --- a/src/linalg.h +++ b/src/linalg.h @@ -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; diff --git a/src/openscad.cc b/src/openscad.cc index e5eb69f..6bbaedb 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -37,6 +37,7 @@ #include "rendersettings.h" #include "PlatformUtils.h" #include "nodedumper.h" +#include "CocoaUtils.h" #include <string> #include <vector> @@ -99,15 +100,19 @@ public: static void help(const char *progname) { - int tab = int(strlen(progname))+8; - fprintf(stderr,"Usage: %s [ -o output_file [ -d deps_file ] ]\\\n" - "%*s[ -m make_command ] [ -D var=val [..] ] \\\n" - "%*s[ --camera=translatex,y,z,rotx,y,z,dist | \\\n" - "%*s --camera=eyex,y,z,centerx,y,z ] \\\n" - "%*s[ --imgsize=width,height ] [ --projection=(o)rtho|(p)ersp] \\\n" - "%*s[ --render | --preview[=throwntogether] ] \\\n" - "%*sfilename\n", - progname, tab, "", tab, "", tab, "", tab, "", tab, "", tab, ""); + int tablen = strlen(progname)+8; + char tabstr[tablen+1]; + for (int i=0;i<tablen;i++) tabstr[i] = ' '; + tabstr[tablen] = '\0'; + + PRINTB("Usage: %1% [ -o output_file [ -d deps_file ] ]\\\n" + "%2%[ -m make_command ] [ -D var=val [..] ] \\\n" + "%2%[ --camera=translatex,y,z,rotx,y,z,dist | \\\n" + "%2% --camera=eyex,y,z,centerx,y,z ] \\\n" + "%2%[ --imgsize=width,height ] [ --projection=(o)rtho|(p)ersp] \\\n" + "%2%[ --render | --preview[=throwntogether] ] \\\n" + "%2%filename\n", + progname % (const char *)tabstr); exit(1); } @@ -115,7 +120,7 @@ static void help(const char *progname) #define TOSTRING(x) STRINGIFY(x) static void version() { - printf("OpenSCAD version %s\n", TOSTRING(OPENSCAD_VERSION)); + PRINTB("OpenSCAD version %s\n", TOSTRING(OPENSCAD_VERSION)); exit(1); } @@ -127,7 +132,7 @@ static void info() try { csgInfo.glview = new OffscreenView(512,512); } catch (int error) { - fprintf(stderr,"Can't create OpenGL OffscreenView. Code: %i. Exiting.\n", error); + PRINTB("Can't create OpenGL OffscreenView. Code: %i. Exiting.\n", error); exit(1); } @@ -149,8 +154,8 @@ Camera get_camera( po::variables_map vm ) cam_parameters.push_back(lexical_cast<double>(s)); camera.setup( cam_parameters ); } else { - fprintf(stderr,"Camera setup requires either 7 numbers for Gimbal Camera\n"); - fprintf(stderr,"or 6 numbers for Vector Camera\n"); + PRINT("Camera setup requires either 7 numbers for Gimbal Camera\n"); + PRINT("or 6 numbers for Vector Camera\n"); exit(1); } } @@ -166,7 +171,7 @@ Camera get_camera( po::variables_map vm ) else if (proj=="p" || proj=="perspective") camera.projection = Camera::PERSPECTIVE; else { - fprintf(stderr,"projection needs to be 'o' or 'p' for ortho or perspective\n"); + PRINT("projection needs to be 'o' or 'p' for ortho or perspective\n"); exit(1); } } @@ -177,7 +182,7 @@ Camera get_camera( po::variables_map vm ) vector<string> strs; split(strs, vm["imgsize"].as<string>(), is_any_of(",")); if ( strs.size() != 2 ) { - fprintf(stderr,"Need 2 numbers for imgsize\n"); + PRINT("Need 2 numbers for imgsize\n"); exit(1); } else { w = lexical_cast<int>( strs[0] ); @@ -190,8 +195,14 @@ Camera get_camera( po::variables_map vm ) return camera; } -int cmdline(const std::string &application_path, const char *deps_output_file, const std::string &filename, Camera &camera, const char *output_file, const fs::path &original_path, Render::type renderer, char ** argv ) +int cmdline(const char *deps_output_file, const std::string &filename, Camera &camera, const char *output_file, const fs::path &original_path, Render::type renderer, int argc, char ** argv ) { +#ifdef OPENSCAD_QTGUI + QCoreApplication app(argc, argv); + const std::string application_path = QApplication::instance()->applicationDirPath().toLocal8Bit().constData(); +#else + const std::string application_path = boosty::stringy(boosty::absolute(boost::filesystem::path(argv[0]).parent_path())); +#endif parser_init(application_path, false); Tree tree; #ifdef ENABLE_CGAL @@ -219,7 +230,7 @@ int cmdline(const std::string &application_path, const char *deps_output_file, c else if (suffix == ".term") term_output_file = output_file; else if (suffix == ".echo") echo_output_file = output_file; else { - fprintf(stderr, "Unknown suffix for output file %s\n", output_file); + PRINTB("Unknown suffix for output file %s\n", output_file); return 1; } @@ -243,7 +254,7 @@ int cmdline(const std::string &application_path, const char *deps_output_file, c std::ifstream ifs(filename.c_str()); if (!ifs.is_open()) { - fprintf(stderr, "Can't open input file '%s'!\n", filename.c_str()); + PRINTB("Can't open input file '%s'!\n", filename.c_str()); return 1; } std::string text((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>()); @@ -252,7 +263,7 @@ int cmdline(const std::string &application_path, const char *deps_output_file, c std::string parentpath = boosty::stringy(abspath.parent_path()); root_module = parse(text.c_str(), parentpath.c_str(), false); if (!root_module) { - fprintf(stderr, "Can't parse file '%s'!\n", filename.c_str()); + PRINTB("Can't parse file '%s'!\n", filename.c_str()); return 1; } root_module->handleDependencies(); @@ -347,11 +358,11 @@ int cmdline(const std::string &application_path, const char *deps_output_file, c if (stl_output_file) { if (root_N.dim != 3) { - fprintf(stderr, "Current top level object is not a 3D object.\n"); + PRINT("Current top level object is not a 3D object.\n"); return 1; } if (!root_N.p3->is_simple()) { - fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n"); + PRINT("Object isn't a valid 2-manifold! Modify your design.\n"); return 1; } std::ofstream fstream(stl_output_file); @@ -366,11 +377,11 @@ int cmdline(const std::string &application_path, const char *deps_output_file, c if (off_output_file) { if (root_N.dim != 3) { - fprintf(stderr, "Current top level object is not a 3D object.\n"); + PRINT("Current top level object is not a 3D object.\n"); return 1; } if (!root_N.p3->is_simple()) { - fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n"); + PRINT("Object isn't a valid 2-manifold! Modify your design.\n"); return 1; } std::ofstream fstream(off_output_file); @@ -385,7 +396,7 @@ int cmdline(const std::string &application_path, const char *deps_output_file, c if (dxf_output_file) { if (root_N.dim != 2) { - fprintf(stderr, "Current top level object is not a 2D object.\n"); + PRINT("Current top level object is not a 2D object.\n"); return 1; } std::ofstream fstream(dxf_output_file); @@ -415,7 +426,7 @@ int cmdline(const std::string &application_path, const char *deps_output_file, c } } #else - fprintf(stderr, "OpenSCAD has been compiled without CGAL support!\n"); + PRINT("OpenSCAD has been compiled without CGAL support!\n"); return 1; #endif } @@ -439,6 +450,13 @@ int cmdline(const std::string &application_path, const char *deps_output_file, c #include <QString> #include <QDir> +// 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)) + .absoluteFilePath(QString::fromStdString(fileName)); +} + bool QtUseGUI() { #ifdef Q_WS_X11 @@ -454,7 +472,7 @@ bool QtUseGUI() return useGUI; } -int gui(const std::string &application_path, vector<string> &inputFiles, const fs::path &original_path, int argc, char ** argv) +int gui(vector<string> &inputFiles, const fs::path &original_path, int argc, char ** argv) { QApplication app(argc, argv, true); //useGUI); #ifdef Q_WS_MAC @@ -466,7 +484,9 @@ int gui(const std::string &application_path, vector<string> &inputFiles, const f QCoreApplication::setApplicationName("OpenSCAD"); QCoreApplication::setApplicationVersion(TOSTRING(OPENSCAD_VERSION)); - QDir exdir(QApplication::instance()->applicationDirPath()); + const QString &app_path = app.applicationDirPath(); + + QDir exdir(app_path); QString qexamplesdir; #ifdef Q_WS_MAC exdir.cd("../Resources"); // Examples can be bundled @@ -486,7 +506,7 @@ int gui(const std::string &application_path, vector<string> &inputFiles, const f qexamplesdir = exdir.path(); } MainWindow::setExamplesDir(qexamplesdir); - parser_init(application_path, true); + parser_init(app_path.toLocal8Bit().constData(), true); #ifdef Q_WS_MAC installAppleEventHandlers(); @@ -508,20 +528,20 @@ int gui(const std::string &application_path, vector<string> &inputFiles, const f if (!inputFiles.size()) inputFiles.push_back(""); #ifdef ENABLE_MDI BOOST_FOREACH(const string &infile, inputFiles) { - new MainWindow(QString::fromLocal8Bit(boosty::stringy(original_path / infile).c_str())); + new MainWindow(assemblePath(original_path, infile)); } app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); #else - MainWindow *m = new MainWindow(QString::fromLocal8Bit(boosty::stringy(original_path / inputFiles[0]).c_str())); + MainWindow *m = new MainWindow(assemblePath(original_path, inputFiles[0])); app.connect(m, SIGNAL(destroyed()), &app, SLOT(quit())); #endif return app.exec(); } #else // OPENSCAD_QTGUI bool QtUseGUI() { return false; } -int gui(const std::string &application_path, const vector<string> &inputFiles, const fs::path &original_path, int argc, char ** argv) +int gui(const vector<string> &inputFiles, const fs::path &original_path, int argc, char ** argv) { - fprintf(stderr,"Error: compiled without QT, but trying to run GUI\n"); + PRINT("Error: compiled without QT, but trying to run GUI\n"); return 1; } #endif // OPENSCAD_QTGUI @@ -529,7 +549,9 @@ int gui(const std::string &application_path, const vector<string> &inputFiles, c int main(int argc, char **argv) { int rc = 0; - +#ifdef Q_WS_MAC + set_output_handler(CocoaUtils::nslog, NULL); +#endif #ifdef ENABLE_CGAL // Causes CGAL errors to abort directly instead of throwing exceptions // (which we don't catch). This gives us stack traces without rerunning in gdb. @@ -572,10 +594,10 @@ int main(int argc, char **argv) po::variables_map vm; try { - po::store(po::command_line_parser(argc, argv).options(all_options).positional(p).run(), vm); + po::store(po::command_line_parser(argc, argv).options(all_options).allow_unregistered().positional(p).run(), vm); } catch(const std::exception &e) { // Catches e.g. unknown options - fprintf(stderr, "%s\n", e.what()); + PRINTB("%s\n", e.what()); help(argv[0]); } @@ -596,12 +618,12 @@ int main(int argc, char **argv) output_file = vm["o"].as<string>().c_str(); } if (vm.count("s")) { - fprintf(stderr, "DEPRECATED: The -s option is deprecated. Use -o instead.\n"); + PRINT("DEPRECATED: The -s option is deprecated. Use -o instead.\n"); if (output_file) help(argv[0]); output_file = vm["s"].as<string>().c_str(); } if (vm.count("x")) { - fprintf(stderr, "DEPRECATED: The -x option is deprecated. Use -o instead.\n"); + PRINT("DEPRECATED: The -x option is deprecated. Use -o instead.\n"); if (output_file) help(argv[0]); output_file = vm["x"].as<string>().c_str(); } @@ -645,21 +667,15 @@ int main(int argc, char **argv) cmdlinemode = true; if (!inputFiles.size()) help(argv[0]); } - const std::string application_path = -#ifdef OPENSCAD_QTGUI - QApplication::instance()->applicationDirPath().toLocal8Bit().constData(); -#else - boosty::stringy(boosty::absolute(boost::filesystem::path(argv[0]).parent_path())); -#endif if (cmdlinemode) { - rc = cmdline(application_path, deps_output_file, inputFiles[0], camera, output_file, original_path, renderer, argv); + rc = cmdline(deps_output_file, inputFiles[0], camera, output_file, original_path, renderer, argc, argv); } else if (QtUseGUI()) { - rc = gui(application_path, inputFiles, original_path, argc, argv); + rc = gui(inputFiles, original_path, argc, argv); } else { - fprintf(stderr, "Requested GUI mode but can't open display!\n"); + PRINT("Requested GUI mode but can't open display!\n"); help(argv[0]); } diff --git a/src/primitives.cc b/src/primitives.cc index 13a6794..a587d43 100644 --- a/src/primitives.cc +++ b/src/primitives.cc @@ -57,6 +57,8 @@ public: primitive_type_e type; PrimitiveModule(primitive_type_e type) : type(type) { } virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; +private: + Value lookup_radius(const Context &ctx, const std::string &radius_var, const std::string &diameter_var) const; }; class PrimitiveNode : public AbstractPolyNode @@ -105,6 +107,35 @@ public: virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const; }; +/** + * Return a radius value by looking up both a diameter and radius variable. + * The diameter has higher priority, so if found an additionally set radius + * value is ignored. + * + * @param ctx data context with variable values. + * @param radius_var name of the variable to lookup for the radius value. + * @param diameter_var name of the variable to lookup for the diameter value. + * @return radius value of type Value::NUMBER or Value::UNDEFINED if both + * variables are invalid or not set. + */ +Value PrimitiveModule::lookup_radius(const Context &ctx, const std::string &diameter_var, const std::string &radius_var) const +{ + const Value d = ctx.lookup_variable(diameter_var, true); + const Value r = ctx.lookup_variable(radius_var, true); + const bool r_defined = (r.type() == Value::NUMBER); + + if (d.type() == Value::NUMBER) { + if (r_defined) { + PRINTB("WARNING: Ignoring radius variable '%s' as diameter '%s' is defined too.", radius_var % diameter_var); + } + return Value(d.toDouble() / 2.0); + } else if (r_defined) { + return r; + } else { + return Value(); + } +} + AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { PrimitiveNode *node = new PrimitiveNode(inst, this->type); @@ -170,22 +201,21 @@ AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInsta } if (type == SPHERE) { - Value r = c.lookup_variable("r"); + const Value r = lookup_radius(c, "d", "r"); if (r.type() == Value::NUMBER) { node->r1 = r.toDouble(); } } if (type == CYLINDER) { - Value h = c.lookup_variable("h"); - Value r, r1, r2; - r1 = c.lookup_variable("r1"); - r2 = c.lookup_variable("r2"); - r = c.lookup_variable("r", true); // silence warning since r has no default value - Value center = c.lookup_variable("center"); + const Value h = c.lookup_variable("h"); if (h.type() == Value::NUMBER) { node->h = h.toDouble(); } + + const Value r = lookup_radius(c, "d", "r"); + const Value r1 = lookup_radius(c, "d1", "r1"); + const Value r2 = lookup_radius(c, "d2", "r2"); if (r.type() == Value::NUMBER) { node->r1 = r.toDouble(); node->r2 = r.toDouble(); @@ -196,6 +226,8 @@ AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInsta if (r2.type() == Value::NUMBER) { node->r2 = r2.toDouble(); } + + const Value center = c.lookup_variable("center"); if (center.type() == Value::BOOL) { node->center = center.toBool(); } @@ -218,7 +250,7 @@ AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInsta } if (type == CIRCLE) { - Value r = c.lookup_variable("r"); + const Value r = lookup_radius(c, "d", "r"); if (r.type() == Value::NUMBER) { node->r1 = r.toDouble(); } diff --git a/testdata/scad/features/circle-tests.scad b/testdata/scad/features/circle-tests.scad index 90cd9f6..57b1992 100644 --- a/testdata/scad/features/circle-tests.scad +++ b/testdata/scad/features/circle-tests.scad @@ -8,4 +8,6 @@ translate([6,-3,0]) circle(1, $fn=12); translate([0,-6,0]) circle(1, $fa=20, $fs=0.3); translate([3,-6,0]) circle(1, $fa=30, $fs=0.3); translate([6,-6,0]) circle(1, $fa=40, $fs=0.3); -translate([3,-9,0]) circle(1, $fn=0.1); +translate([0,-9,0]) circle(1, $fn=0.1); +translate([3,-9,0]) circle(d=2, $fn=8); +translate([6,-9,0]) circle(r=10, d=2, $fn=8); diff --git a/testdata/scad/features/cylinder-diameter-tests.scad b/testdata/scad/features/cylinder-diameter-tests.scad new file mode 100644 index 0000000..57eab65 --- /dev/null +++ b/testdata/scad/features/cylinder-diameter-tests.scad @@ -0,0 +1,13 @@ +cylinder(); +translate([-11,-11,0]) cylinder(h=3, r=5); +translate([-11, 0,0]) cylinder(h=5, d=10); +translate([-11, 11,0]) cylinder(h=7, r=1, d=10); +translate([ 11,-11,0]) cylinder(h=5, r1=5); +translate([ 11, 0,0]) cylinder(h=7, d1=10); +translate([ 11, 11,0]) cylinder(h=9, r1=1, d1=10); +translate([ 22,-11,0]) cylinder(h=5, r2=5); +translate([ 22, 0,0]) cylinder(h=7, d2=10); +translate([ 22, 11,0]) cylinder(h=9, r2=1, d2=10); +translate([ 33,-11,0]) cylinder(h=5, r1=5, r2=5); +translate([ 33, 0,0]) cylinder(h=7, d1=10, d2=10); +translate([ 33, 11,0]) cylinder(h=9, r1=1, d1=10, r2=1, d2=10); diff --git a/testdata/scad/features/sphere-tests.scad b/testdata/scad/features/sphere-tests.scad index cc80738..5c38f6b 100644 --- a/testdata/scad/features/sphere-tests.scad +++ b/testdata/scad/features/sphere-tests.scad @@ -9,3 +9,5 @@ translate([22,-11, 0]) sphere(5, $fa=20, $fs=0.3); translate([22, 0, 0]) sphere(5, $fa=30, $fs=0.3); translate([22, 11, 0]) sphere(5, $fa=40, $fs=0.3); translate([11, 22, 0]) sphere(5, $fn=0.1); +translate([33, 0, 0]) sphere(d=10); +translate([33, 11, 0]) sphere(r=1, d=10); diff --git a/tests/regression/cgalpngtest/circle-tests-expected.png b/tests/regression/cgalpngtest/circle-tests-expected.png Binary files differindex d640042..39a3481 100644 --- a/tests/regression/cgalpngtest/circle-tests-expected.png +++ b/tests/regression/cgalpngtest/circle-tests-expected.png diff --git a/tests/regression/cgalpngtest/cylinder-diameter-tests-expected.png b/tests/regression/cgalpngtest/cylinder-diameter-tests-expected.png Binary files differnew file mode 100644 index 0000000..0877e5b --- /dev/null +++ b/tests/regression/cgalpngtest/cylinder-diameter-tests-expected.png diff --git a/tests/regression/cgalpngtest/sphere-tests-expected.png b/tests/regression/cgalpngtest/sphere-tests-expected.png Binary files differindex 781d8a9..fd1549f 100644 --- a/tests/regression/cgalpngtest/sphere-tests-expected.png +++ b/tests/regression/cgalpngtest/sphere-tests-expected.png diff --git a/tests/regression/dumptest/circle-tests-expected.csg b/tests/regression/dumptest/circle-tests-expected.csg index b522850..3e183ee 100644 --- a/tests/regression/dumptest/circle-tests-expected.csg +++ b/tests/regression/dumptest/circle-tests-expected.csg @@ -27,7 +27,13 @@ group() { multmatrix([[1, 0, 0, 6], [0, 1, 0, -6], [0, 0, 1, 0], [0, 0, 0, 1]]) { circle($fn = 0, $fa = 40, $fs = 0.3, r = 1); } - multmatrix([[1, 0, 0, 3], [0, 1, 0, -9], [0, 0, 1, 0], [0, 0, 0, 1]]) { + multmatrix([[1, 0, 0, 0], [0, 1, 0, -9], [0, 0, 1, 0], [0, 0, 0, 1]]) { circle($fn = 0.1, $fa = 12, $fs = 2, r = 1); } + multmatrix([[1, 0, 0, 3], [0, 1, 0, -9], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 8, $fa = 12, $fs = 2, r = 1); + } + multmatrix([[1, 0, 0, 6], [0, 1, 0, -9], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 8, $fa = 12, $fs = 2, r = 1); + } } diff --git a/tests/regression/dumptest/cylinder-diameter-tests-expected.csg b/tests/regression/dumptest/cylinder-diameter-tests-expected.csg new file mode 100644 index 0000000..98fab0d --- /dev/null +++ b/tests/regression/dumptest/cylinder-diameter-tests-expected.csg @@ -0,0 +1,39 @@ +group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 1, r2 = 1, center = false); + multmatrix([[1, 0, 0, -11], [0, 1, 0, -11], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 3, r1 = 5, r2 = 5, center = false); + } + multmatrix([[1, 0, 0, -11], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 5, r1 = 5, r2 = 5, center = false); + } + multmatrix([[1, 0, 0, -11], [0, 1, 0, 11], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 7, r1 = 5, r2 = 5, center = false); + } + multmatrix([[1, 0, 0, 11], [0, 1, 0, -11], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 5, r1 = 5, r2 = 1, center = false); + } + multmatrix([[1, 0, 0, 11], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 7, r1 = 5, r2 = 1, center = false); + } + multmatrix([[1, 0, 0, 11], [0, 1, 0, 11], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 9, r1 = 5, r2 = 1, center = false); + } + multmatrix([[1, 0, 0, 22], [0, 1, 0, -11], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 5, r1 = 1, r2 = 5, center = false); + } + multmatrix([[1, 0, 0, 22], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 7, r1 = 1, r2 = 5, center = false); + } + multmatrix([[1, 0, 0, 22], [0, 1, 0, 11], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 9, r1 = 1, r2 = 5, center = false); + } + multmatrix([[1, 0, 0, 33], [0, 1, 0, -11], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 5, r1 = 5, r2 = 5, center = false); + } + multmatrix([[1, 0, 0, 33], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 7, r1 = 5, r2 = 5, center = false); + } + multmatrix([[1, 0, 0, 33], [0, 1, 0, 11], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 9, r1 = 5, r2 = 5, center = false); + } +} diff --git a/tests/regression/dumptest/sphere-tests-expected.csg b/tests/regression/dumptest/sphere-tests-expected.csg index 45c0858..783b7e8 100644 --- a/tests/regression/dumptest/sphere-tests-expected.csg +++ b/tests/regression/dumptest/sphere-tests-expected.csg @@ -30,4 +30,10 @@ group() { multmatrix([[1, 0, 0, 11], [0, 1, 0, 22], [0, 0, 1, 0], [0, 0, 0, 1]]) { sphere($fn = 0.1, $fa = 12, $fs = 2, r = 5); } + multmatrix([[1, 0, 0, 33], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + sphere($fn = 0, $fa = 12, $fs = 2, r = 5); + } + multmatrix([[1, 0, 0, 33], [0, 1, 0, 11], [0, 0, 1, 0], [0, 0, 0, 1]]) { + sphere($fn = 0, $fa = 12, $fs = 2, r = 5); + } } diff --git a/tests/regression/opencsgtest/circle-tests-expected.png b/tests/regression/opencsgtest/circle-tests-expected.png Binary files differindex 06f7d9c..20f9ca2 100644 --- a/tests/regression/opencsgtest/circle-tests-expected.png +++ b/tests/regression/opencsgtest/circle-tests-expected.png diff --git a/tests/regression/opencsgtest/cylinder-diameter-tests-expected.png b/tests/regression/opencsgtest/cylinder-diameter-tests-expected.png Binary files differnew file mode 100644 index 0000000..7425635 --- /dev/null +++ b/tests/regression/opencsgtest/cylinder-diameter-tests-expected.png diff --git a/tests/regression/opencsgtest/sphere-tests-expected.png b/tests/regression/opencsgtest/sphere-tests-expected.png Binary files differindex d1b4845..65a6cf2 100644 --- a/tests/regression/opencsgtest/sphere-tests-expected.png +++ b/tests/regression/opencsgtest/sphere-tests-expected.png diff --git a/tests/regression/throwntogethertest/circle-tests-expected.png b/tests/regression/throwntogethertest/circle-tests-expected.png Binary files differindex 06f7d9c..2d5bde0 100644 --- a/tests/regression/throwntogethertest/circle-tests-expected.png +++ b/tests/regression/throwntogethertest/circle-tests-expected.png diff --git a/tests/regression/throwntogethertest/cylinder-diameter-tests-expected.png b/tests/regression/throwntogethertest/cylinder-diameter-tests-expected.png Binary files differnew file mode 100644 index 0000000..7425635 --- /dev/null +++ b/tests/regression/throwntogethertest/cylinder-diameter-tests-expected.png diff --git a/tests/regression/throwntogethertest/sphere-tests-expected.png b/tests/regression/throwntogethertest/sphere-tests-expected.png Binary files differindex d1b4845..65a6cf2 100644 --- a/tests/regression/throwntogethertest/sphere-tests-expected.png +++ b/tests/regression/throwntogethertest/sphere-tests-expected.png |