From ed4529404a4d447b04da33aa86dd1dced4a3df16 Mon Sep 17 00:00:00 2001 From: Patrick Bogen Date: Wed, 30 Oct 2013 19:40:03 -0700 Subject: More robust searching through README files for dependency versions. diff --git a/scripts/check-dependencies.sh b/scripts/check-dependencies.sh index c4f2893..49d2d85 100755 --- a/scripts/check-dependencies.sh +++ b/scripts/check-dependencies.sh @@ -261,32 +261,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() -- cgit v0.10.1 From 8521cb132efa8c119f4194776c1535d4cca2fc5d Mon Sep 17 00:00:00 2001 From: Patrick Bogen Date: Wed, 30 Oct 2013 19:40:24 -0700 Subject: Use quotes for values that might end up empty, so that pretty print displays missing version numbers properly. diff --git a/scripts/check-dependencies.sh b/scripts/check-dependencies.sh index 49d2d85..826a665 100755 --- a/scripts/check-dependencies.sh +++ b/scripts/check-dependencies.sh @@ -548,7 +548,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 -- cgit v0.10.1 From c6df50759023a49bb8d0ae4c070782e920dc1ddb Mon Sep 17 00:00:00 2001 From: Patrick Bogen Date: Wed, 30 Oct 2013 19:53:23 -0700 Subject: Use find instead of ls and grep to locate gmp.h (or gmp-blah.h) for gmp_sysver diff --git a/scripts/check-dependencies.sh b/scripts/check-dependencies.sh index 826a665..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" -- cgit v0.10.1 From a40530d73d35edc5f7bfbba410a418d3058741cb Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Thu, 31 Oct 2013 14:41:02 -0400 Subject: bugfix: CMAKE_BUILDTYPE typo 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 -- cgit v0.10.1 From be4c72d9e9e03a2f70eb55d8aa70ca43d084045f Mon Sep 17 00:00:00 2001 From: Torsten Paul Date: Thu, 31 Oct 2013 22:54:05 +0100 Subject: Add menu entry "Reset View" to reset viewport to initial settings (fixes Issue #434). diff --git a/src/MainWindow.h b/src/MainWindow.h index 4f88fbf..ac999bf 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -164,6 +164,7 @@ public slots: void viewCenter(); void viewPerspective(); void viewOrthogonal(); + void viewResetView(); void hideConsole(); void animateUpdateDocChanged(); void animateUpdate(); diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 68bc064..4cb043f 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -213,6 +213,8 @@ + + @@ -697,6 +699,11 @@ Show Library Folder... + + + Reset View + + diff --git a/src/QGLView.cc b/src/QGLView.cc index 8aaeaf2..25ed323 100644 --- a/src/QGLView.cc +++ b/src/QGLView.cc @@ -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(); diff --git a/src/QGLView.h b/src/QGLView.h index f3e3681..12be085 100644 --- a/src/QGLView.h +++ b/src/QGLView.h @@ -41,6 +41,7 @@ public: } std::string getRendererInfo() const; bool save(const char *filename); + void resetView(); public: QLabel *statusLabel; diff --git a/src/mainwin.cc b/src/mainwin.cc index 65c511f..5b986b1 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -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())); @@ -1772,6 +1773,12 @@ void MainWindow::viewOrthogonal() this->qglview->updateGL(); } +void MainWindow::viewResetView() +{ + this->qglview->resetView(); + this->qglview->updateGL(); +} + void MainWindow::hideConsole() { QSettings settings; -- cgit v0.10.1 From e05a9745a348d7805fcc7ef8879fe74c5e66d8f7 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Fri, 1 Nov 2013 11:35:58 -0400 Subject: Bumped to eigen-3.2.0 diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh index 994d2a1..d1c5985 100755 --- a/scripts/macosx-build-dependencies.sh +++ b/scripts/macosx-build-dependencies.sh @@ -312,7 +312,8 @@ build_eigen() 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 +440,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 -- cgit v0.10.1 From 5aa01edb938cc0ddb01deef98452bafb6d34f351 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Fri, 1 Nov 2013 12:10:03 -0400 Subject: Fix potential memory alignment issue with eigen. This might make us dependent on eigen3, but it's about time anyway 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 > points; -#else std::vector points; -#endif std::vector paths; std::vector 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 #include #include +#include +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 BoundingBox; using Eigen::Matrix3f; using Eigen::Matrix3d; -- cgit v0.10.1 From e722d906ceb520b3f89775a0583b0c539f9c9223 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Fri, 8 Nov 2013 00:34:01 -0500 Subject: Get rid of leading zeros in date tags, causing them to be interpreted as octal in C++ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c560b4f..0e5981f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -450,9 +450,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}) -- cgit v0.10.1 From 7872e7a229ea26127a19d8b3fc707fe9dc5da583 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Fri, 8 Nov 2013 00:53:58 -0500 Subject: Re-fix: don't add path to empty files. Fixes #536 diff --git a/src/openscad.cc b/src/openscad.cc index 6bbaedb..ece6818 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -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)); } -- cgit v0.10.1 From e5d535e900ae5bc5923fc76c80fb3b3f9153a80e Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Fri, 8 Nov 2013 00:57:38 -0500 Subject: Fixes #533 diff --git a/icons/openscad.desktop b/icons/openscad.desktop index 07df5aa..f0282ac 100644 --- a/icons/openscad.desktop +++ b/icons/openscad.desktop @@ -4,4 +4,4 @@ Version=1.0 Name=OpenSCAD Icon=openscad Exec=openscad %f -Categories=Graphics;3DGraphics;Engineering; +Categories=Graphics;3DGraphics;Engineering;Programming; -- cgit v0.10.1 From af8359993a6dfffed8f57bc5605f2ca77a353ffa Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sun, 10 Nov 2013 16:43:46 -0600 Subject: download eigen 3 package , eigen2 no longer works diff --git a/scripts/uni-get-dependencies.sh b/scripts/uni-get-dependencies.sh index 31337c8..8e0b9d3 100755 --- a/scripts/uni-get-dependencies.sh +++ b/scripts/uni-get-dependencies.sh @@ -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 } -- cgit v0.10.1 From 00a329f0bd4ab940c1063106ee6ba7db7811a090 Mon Sep 17 00:00:00 2001 From: Torsten Paul Date: Sun, 10 Nov 2013 02:42:58 +0100 Subject: Add support for handling negative step values in ranges (fixes #500). diff --git a/src/control.cc b/src/control.cc index 10aadf0..6b10a28 100644 --- a/src/control.cc +++ b/src/control.cc @@ -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); - } + unsigned long 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)); + unsigned long 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); } diff --git a/src/expr.cc b/src/expr.cc index 594fccf..51accf3 100644 --- a/src/expr.cc +++ b/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") { diff --git a/src/parser.y b/src/parser.y index 5645104..6446e82 100644 --- a/src/parser.y +++ b/src/parser.y @@ -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 ']' diff --git a/src/value.cc b/src/value.cc index ac33a3b..931c616 100644 --- a/src/value.cc +++ b/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."); + } +} + +unsigned long Value::RangeType::nbsteps() const { + if (begin_val == end_val) { + return 0; + } + + if (step_val == 0) { + return std::numeric_limits::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); +} diff --git a/src/value.h b/src/value.h index 388b721..4671cdc 100644 --- a/src/value.h +++ b/src/value.h @@ -31,33 +31,64 @@ std::ostream &operator<<(std::ostream &stream, const Filename &filename); class Value { public: - struct RangeType { + class RangeType { + private: + double begin_val; + double step_val; + double end_val; + + /// inverse begin/end if begin is upper than end + void normalize(); + + 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(); + } + RangeType(double begin, double step, double end) - : begin(begin), step(step), end(end) {} + : begin_val(begin), step_val(step), end_val(end) {} bool operator==(const RangeType &other) const { - return this->begin == other.begin && - this->step == other.step && - this->end == other.end; + return this->begin_val == other.begin_val && + this->step_val == other.step_val && + this->end_val == other.end_val; } - /// 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::max(); - } - return (int)((begin-end)/step); - } - - double begin; - double step; - double end; + iterator begin() { return iterator(*this, RANGE_TYPE_BEGIN); } + iterator end() { return iterator(*this, RANGE_TYPE_END); } + + /// return number of steps, max int value if step is null + unsigned long nbsteps() const; + + friend class tostring_visitor; + friend class bracket_visitor; }; typedef std::vector VectorType; -- cgit v0.10.1 From bcba02fac33e107af959c93e7ddadce3aa18926f Mon Sep 17 00:00:00 2001 From: Torsten Paul Date: Sun, 10 Nov 2013 03:12:03 +0100 Subject: Add test cases for new range expression handling. diff --git a/testdata/scad/misc/range-tests.scad b/testdata/scad/misc/range-tests.scad new file mode 100644 index 0000000..42ef2a4 --- /dev/null +++ b/testdata/scad/misc/range-tests.scad @@ -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); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0e5981f..6aff17b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -804,7 +804,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 diff --git a/tests/regression/echotest/range-tests-expected.echo b/tests/regression/echotest/range-tests-expected.echo new file mode 100644 index 0000000..ddff38e --- /dev/null +++ b/tests/regression/echotest/range-tests-expected.echo @@ -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 -- cgit v0.10.1 From 3c0e9f4f182dccea6dc0636daf8dbc06dd7c190f Mon Sep 17 00:00:00 2001 From: Torsten Paul Date: Sun, 10 Nov 2013 23:33:48 +0100 Subject: Update 'children' test case using range [4 : -1 : 0] which is now valid. diff --git a/testdata/scad/misc/children-tests.scad b/testdata/scad/misc/children-tests.scad index a9a3cf9..1c3d9ea 100644 --- a/testdata/scad/misc/children-tests.scad +++ b/testdata/scad/misc/children-tests.scad @@ -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() { diff --git a/tests/regression/echotest/children-tests-expected.echo b/tests/regression/echotest/children-tests-expected.echo index 7b8278a..cdd2eb1 100644 --- a/tests/regression/echotest/children-tests-expected.echo +++ b/tests/regression/echotest/children-tests-expected.echo @@ -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" -- cgit v0.10.1 From e6b2884805e79d4ce1b55916977ddede46fc7396 Mon Sep 17 00:00:00 2001 From: Torsten Paul Date: Mon, 11 Nov 2013 01:16:57 +0100 Subject: Fix output of range expressions. diff --git a/src/expr.cc b/src/expr.cc index 51accf3..08615ba 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -199,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 << "["; diff --git a/tests/regression/moduledumptest/allexpressions-expected.ast b/tests/regression/moduledumptest/allexpressions-expected.ast index 6d9de40..69ec746 100644 --- a/tests/regression/moduledumptest/allexpressions-expected.ast +++ b/tests/regression/moduledumptest/allexpressions-expected.ast @@ -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"; -- cgit v0.10.1 From 1fcad169e623d776eb297c324304fb6836ec1e62 Mon Sep 17 00:00:00 2001 From: Torsten Paul Date: Mon, 11 Nov 2013 01:28:30 +0100 Subject: Update 'for' test cases to match the new range expression handling. diff --git a/testdata/scad/features/for-tests.scad b/testdata/scad/features/for-tests.scad index fe36789..10295b1 100644 --- a/testdata/scad/features/for-tests.scad +++ b/testdata/scad/features/for-tests.scad @@ -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 diff --git a/tests/regression/cgalpngtest/for-tests-expected.png b/tests/regression/cgalpngtest/for-tests-expected.png index bf1970a..65db59f 100644 Binary files a/tests/regression/cgalpngtest/for-tests-expected.png and b/tests/regression/cgalpngtest/for-tests-expected.png differ diff --git a/tests/regression/dumptest/for-tests-expected.csg b/tests/regression/dumptest/for-tests-expected.csg index 7aa29d7..b61d9cd 100644 --- a/tests/regression/dumptest/for-tests-expected.csg +++ b/tests/regression/dumptest/for-tests-expected.csg @@ -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); diff --git a/tests/regression/opencsgtest/for-tests-expected.png b/tests/regression/opencsgtest/for-tests-expected.png index 968659d..5218b8b 100644 Binary files a/tests/regression/opencsgtest/for-tests-expected.png and b/tests/regression/opencsgtest/for-tests-expected.png differ diff --git a/tests/regression/throwntogethertest/for-tests-expected.png b/tests/regression/throwntogethertest/for-tests-expected.png index 6641555..7b58005 100644 Binary files a/tests/regression/throwntogethertest/for-tests-expected.png and b/tests/regression/throwntogethertest/for-tests-expected.png differ -- cgit v0.10.1 From f46bd3788f75e691b65aaf0e4ffb1db1029ef717 Mon Sep 17 00:00:00 2001 From: Torsten Paul Date: Fri, 15 Nov 2013 19:41:37 +0100 Subject: Change nbsteps() to uint32_t to make it independent from 32/64-bit platform. diff --git a/src/control.cc b/src/control.cc index 6b10a28..d5f664e 100644 --- a/src/control.cc +++ b/src/control.cc @@ -78,7 +78,7 @@ void ControlModule::for_eval(AbstractNode &node, const ModuleInstantiation &inst Context c(ctx); if (it_values.type() == Value::RANGE) { Value::RangeType range = it_values.toRange(); - unsigned long steps = range.nbsteps(); + uint32_t steps = range.nbsteps(); if (steps >= 10000) { PRINTB("WARNING: Bad range parameter in for statement: too many elements (%lu).", steps); } else { @@ -229,7 +229,7 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns else if (value.type() == Value::RANGE) { AbstractNode* node = new AbstractNode(inst); Value::RangeType range = value.toRange(); - unsigned long steps = range.nbsteps(); + uint32_t steps = range.nbsteps(); if (steps >= 10000) { PRINTB("WARNING: Bad range parameter for children: too many elements (%lu).", steps); return NULL; diff --git a/src/value.cc b/src/value.cc index 931c616..5afb650 100644 --- a/src/value.cc +++ b/src/value.cc @@ -625,13 +625,13 @@ void Value::RangeType::normalize() { } } -unsigned long Value::RangeType::nbsteps() const { +uint32_t Value::RangeType::nbsteps() const { if (begin_val == end_val) { return 0; } if (step_val == 0) { - return std::numeric_limits::max(); + return std::numeric_limits::max(); } double steps; diff --git a/src/value.h b/src/value.h index 4671cdc..8197806 100644 --- a/src/value.h +++ b/src/value.h @@ -84,8 +84,8 @@ public: iterator begin() { return iterator(*this, RANGE_TYPE_BEGIN); } iterator end() { return iterator(*this, RANGE_TYPE_END); } - /// return number of steps, max int value if step is null - unsigned long nbsteps() const; + /// return number of steps, max uint32_ value if step is 0 + uint32_t nbsteps() const; friend class tostring_visitor; friend class bracket_visitor; -- cgit v0.10.1 From 3e3caaa62500431b047072d3ecf1e5e3fdd7e502 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Fri, 15 Nov 2013 15:48:43 -0500 Subject: Removed eigen2 from build system and documentation. We now require eigen3 diff --git a/README.md b/README.md index c22871a..27f12ce 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,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/) diff --git a/scripts/check-dependencies.sh b/scripts/check-dependencies.sh index 120aed9..b63c677 100755 --- a/scripts/check-dependencies.sh +++ b/scripts/check-dependencies.sh @@ -472,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" diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh index d1c5985..19c9709 100755 --- a/scripts/macosx-build-dependencies.sh +++ b/scripts/macosx-build-dependencies.sh @@ -309,7 +309,6 @@ 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; diff --git a/scripts/uni-build-dependencies.sh b/scripts/uni-build-dependencies.sh index 620c705..e652c47 100755 --- a/scripts/uni-build-dependencies.sh +++ b/scripts/uni-build-dependencies.sh @@ -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. diff --git a/scripts/uni-get-dependencies.sh b/scripts/uni-get-dependencies.sh index 8e0b9d3..a0306ef 100755 --- a/scripts/uni-get-dependencies.sh +++ b/scripts/uni-get-dependencies.sh @@ -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; diff --git a/src/AboutDialog.html b/src/AboutDialog.html index b5a5d7c..99e7c3b 100644 --- a/src/AboutDialog.html +++ b/src/AboutDialog.html @@ -47,7 +47,7 @@ Please visit this link for a copy of the license: GNU GMP
  • GNU MPFR
  • CGAL -
  • Eigen2 +
  • Eigen
  • OpenCSG
  • OpenGL
  • GLEW diff --git a/src/version_check.h b/src/version_check.h index 6e07208..86e769c 100644 --- a/src/version_check.h +++ b/src/version_check.h @@ -35,8 +35,8 @@ a time, to avoid confusion. #include -#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,7 +104,7 @@ a time, to avoid confusion. #endif // ENABLE_CGAL #endif // Boost -#endif // Eigen2 +#endif // Eigen #endif // MPFR #endif // GMP diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6aff17b..4be8245 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -212,30 +212,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") @@ -250,18 +241,6 @@ if (NOT EIGEN_INCLUDE_DIR) 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() message(STATUS "Eigen found in " ${EIGEN_INCLUDE_DIR}) -- cgit v0.10.1 From 2162aaed64d4c60c4821fbb89f7eae3e37130011 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Wed, 20 Nov 2013 01:27:46 -0500 Subject: Split up projection tests to avoid long running times diff --git a/testdata/scad/features/projection-extrude-tests.scad b/testdata/scad/features/projection-extrude-tests.scad new file mode 100644 index 0000000..d9c216c --- /dev/null +++ b/testdata/scad/features/projection-extrude-tests.scad @@ -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); diff --git a/testdata/scad/features/projection-tests.scad b/testdata/scad/features/projection-tests.scad index e6c52ea..bc2111c 100644 --- a/testdata/scad/features/projection-tests.scad +++ b/testdata/scad/features/projection-tests.scad @@ -5,16 +5,15 @@ projection() { } // 2D child projection(cut=true) { 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); - +projection(cut=false) cube(10); +projection(cut=true) translate([20,0,0]) cube(10, center=true); // 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); +translate([0,20,0]) projection(cut=true) translate([0,0,-4.999999]) cube(10, 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); } - } +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); } + } +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4be8245..3d3aad1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -834,12 +834,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 diff --git a/tests/regression/cgalpngtest/projection-extrude-tests-expected.png b/tests/regression/cgalpngtest/projection-extrude-tests-expected.png new file mode 100644 index 0000000..b5d7338 Binary files /dev/null and b/tests/regression/cgalpngtest/projection-extrude-tests-expected.png differ diff --git a/tests/regression/cgalpngtest/projection-tests-expected.png b/tests/regression/cgalpngtest/projection-tests-expected.png index 2610507..3be3654 100644 Binary files a/tests/regression/cgalpngtest/projection-tests-expected.png and b/tests/regression/cgalpngtest/projection-tests-expected.png differ diff --git a/tests/regression/dumptest/projection-extrude-tests-expected.csg b/tests/regression/dumptest/projection-extrude-tests-expected.csg new file mode 100644 index 0000000..0199ea0 --- /dev/null +++ b/tests/regression/dumptest/projection-extrude-tests-expected.csg @@ -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); + } + } + } + } +} diff --git a/tests/regression/dumptest/projection-tests-expected.csg b/tests/regression/dumptest/projection-tests-expected.csg index 86423a1..da3e5ce 100644 --- a/tests/regression/dumptest/projection-tests-expected.csg +++ b/tests/regression/dumptest/projection-tests-expected.csg @@ -4,52 +4,33 @@ group() { projection(cut = true, 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) { - sphere($fn = 0, $fa = 12, $fs = 2, r = 10); - } + projection(cut = false, convexity = 0) { + cube(size = [10, 10, 10], center = false); } - 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); - } - } + 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, 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, 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, -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, -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, 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() { + 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, 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); - } - } } } } diff --git a/tests/regression/opencsgtest/projection-extrude-tests-expected.png b/tests/regression/opencsgtest/projection-extrude-tests-expected.png new file mode 100644 index 0000000..d68bd59 Binary files /dev/null and b/tests/regression/opencsgtest/projection-extrude-tests-expected.png differ diff --git a/tests/regression/opencsgtest/projection-tests-expected.png b/tests/regression/opencsgtest/projection-tests-expected.png index 9aabe36..b808ffe 100644 Binary files a/tests/regression/opencsgtest/projection-tests-expected.png and b/tests/regression/opencsgtest/projection-tests-expected.png differ diff --git a/tests/regression/throwntogethertest/projection-extrude-tests-expected.png b/tests/regression/throwntogethertest/projection-extrude-tests-expected.png new file mode 100644 index 0000000..d68bd59 Binary files /dev/null and b/tests/regression/throwntogethertest/projection-extrude-tests-expected.png differ diff --git a/tests/regression/throwntogethertest/projection-tests-expected.png b/tests/regression/throwntogethertest/projection-tests-expected.png index 3be3ae0..b808ffe 100644 Binary files a/tests/regression/throwntogethertest/projection-tests-expected.png and b/tests/regression/throwntogethertest/projection-tests-expected.png differ -- cgit v0.10.1 From 34d7f37fe7d37a23b43cec2faaf90605204937e1 Mon Sep 17 00:00:00 2001 From: Torsten Paul Date: Sat, 23 Nov 2013 15:12:44 +0100 Subject: Fix compilation error on Ubuntu where uint32_t is not defined. diff --git a/src/value.h b/src/value.h index 8197806..75dff2b 100644 --- a/src/value.h +++ b/src/value.h @@ -11,6 +11,7 @@ #include #include #endif +#include class QuotedString : public std::string { @@ -84,7 +85,7 @@ public: iterator begin() { return iterator(*this, RANGE_TYPE_BEGIN); } iterator end() { return iterator(*this, RANGE_TYPE_END); } - /// return number of steps, max uint32_ value if step is 0 + /// return number of steps, max uint32_t value if step is 0 uint32_t nbsteps() const; friend class tostring_visitor; -- cgit v0.10.1 From b204aba444bd838bd3fe27675323dce6d4123b19 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sat, 23 Nov 2013 18:38:45 -0600 Subject: mxe64 build fix. make 'qt disabled' message less confusing on test binary. diff --git a/scripts/mingw-x-build-dependencies.sh b/scripts/mingw-x-build-dependencies.sh index e9f124b..df8572f 100755 --- a/scripts/mingw-x-build-dependencies.sh +++ b/scripts/mingw-x-build-dependencies.sh @@ -48,11 +48,7 @@ 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 diff --git a/src/PlatformUtils.cc b/src/PlatformUtils.cc index cfa5731..b02b822 100644 --- a/src/PlatformUtils.cc +++ b/src/PlatformUtils.cc @@ -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 -- cgit v0.10.1 From 7b526bc27ab70f362332640987bc3f8c363b3659 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Sat, 23 Nov 2013 20:00:19 -0500 Subject: Added test for polygon with hole diff --git a/testdata/scad/features/polygon-tests.scad b/testdata/scad/features/polygon-tests.scad index b4e92b6..0cd259f 100644 --- a/testdata/scad/features/polygon-tests.scad +++ b/testdata/scad/features/polygon-tests.scad @@ -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 diff --git a/tests/regression/cgalpngtest/polygon-tests-expected.png b/tests/regression/cgalpngtest/polygon-tests-expected.png index 5ceabe8..28e4e9f 100644 Binary files a/tests/regression/cgalpngtest/polygon-tests-expected.png and b/tests/regression/cgalpngtest/polygon-tests-expected.png differ diff --git a/tests/regression/dumptest/polygon-tests-expected.csg b/tests/regression/dumptest/polygon-tests-expected.csg index 56995a5..e19bcb0 100644 --- a/tests/regression/dumptest/polygon-tests-expected.csg +++ b/tests/regression/dumptest/polygon-tests-expected.csg @@ -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); + } } diff --git a/tests/regression/opencsgtest/polygon-tests-expected.png b/tests/regression/opencsgtest/polygon-tests-expected.png index fe84a80..94bd131 100644 Binary files a/tests/regression/opencsgtest/polygon-tests-expected.png and b/tests/regression/opencsgtest/polygon-tests-expected.png differ diff --git a/tests/regression/throwntogethertest/polygon-tests-expected.png b/tests/regression/throwntogethertest/polygon-tests-expected.png index 779b878..2ce6b75 100644 Binary files a/tests/regression/throwntogethertest/polygon-tests-expected.png and b/tests/regression/throwntogethertest/polygon-tests-expected.png differ -- cgit v0.10.1 From 91c2b8909ce670e65d341f98fc5f7e456622bba4 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Sat, 23 Nov 2013 22:10:05 -0500 Subject: Added test for implicit union of render() children diff --git a/testdata/scad/features/render-2d-tests.scad b/testdata/scad/features/render-2d-tests.scad index 683ffe4..f8df115 100644 --- a/testdata/scad/features/render-2d-tests.scad +++ b/testdata/scad/features/render-2d-tests.scad @@ -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); +} diff --git a/tests/regression/cgalpngtest/render-2d-tests-expected.png b/tests/regression/cgalpngtest/render-2d-tests-expected.png index 19ea16a..2418968 100644 Binary files a/tests/regression/cgalpngtest/render-2d-tests-expected.png and b/tests/regression/cgalpngtest/render-2d-tests-expected.png differ diff --git a/tests/regression/dumptest/render-2d-tests-expected.csg b/tests/regression/dumptest/render-2d-tests-expected.csg index 75739b3..bcc5e96 100644 --- a/tests/regression/dumptest/render-2d-tests-expected.csg +++ b/tests/regression/dumptest/render-2d-tests-expected.csg @@ -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); } } } diff --git a/tests/regression/opencsgtest/render-2d-tests-expected.png b/tests/regression/opencsgtest/render-2d-tests-expected.png index 0bf6288..47e57dd 100644 Binary files a/tests/regression/opencsgtest/render-2d-tests-expected.png and b/tests/regression/opencsgtest/render-2d-tests-expected.png differ diff --git a/tests/regression/throwntogethertest/render-2d-tests-expected.png b/tests/regression/throwntogethertest/render-2d-tests-expected.png index 0bf6288..47e57dd 100644 Binary files a/tests/regression/throwntogethertest/render-2d-tests-expected.png and b/tests/regression/throwntogethertest/render-2d-tests-expected.png differ -- cgit v0.10.1 From 825fbc7b9e7756ef8c2b49a85efd9abe3ebf8d95 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sun, 24 Nov 2013 19:01:11 -0600 Subject: revert to GMPQ number type kernel due to bugs like issue #481 diff --git a/src/cgal.h b/src/cgal.h index 45228be..efc53d3 100644 --- a/src/cgal.h +++ b/src/cgal.h @@ -48,9 +48,10 @@ typedef CGAL::Exact_predicates_exact_constructions_kernel CGAL_ExactKernel2; typedef CGAL::Polygon_2 CGAL_Poly2; typedef CGAL::Polygon_with_holes_2 CGAL_Poly2h; - //typedef CGAL::Cartesian 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 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_Nef_polyhedron3; typedef CGAL_Nef_polyhedron3::Aff_transformation_3 CGAL_Aff_transformation; -- cgit v0.10.1 From de2db22b5f82855b9cf42829c4dde3b4bd231273 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Mon, 25 Nov 2013 00:27:15 -0500 Subject: Split projection tests into cut vs. project diff --git a/testdata/scad/features/projection-cut-tests.scad b/testdata/scad/features/projection-cut-tests.scad new file mode 100644 index 0000000..0409a3e --- /dev/null +++ b/testdata/scad/features/projection-cut-tests.scad @@ -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); } + } +} diff --git a/testdata/scad/features/projection-tests.scad b/testdata/scad/features/projection-tests.scad index bc2111c..27d03fe 100644 --- a/testdata/scad/features/projection-tests.scad +++ b/testdata/scad/features/projection-tests.scad @@ -3,17 +3,25 @@ projection(); // No children projection() { } // 2D child -projection(cut=true) { square(); } +projection() { square(); } +// Simple projection(cut=false) cube(10); -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); } - } +// Two children +translate([-12,0]) projection(cut=false) { + cube(10); + difference() { + sphere(10); + cylinder(h=30, r=5, center=true); + } +} + +// Holes +translate([6,-12]) projection(cut=false) { + cube(10); + difference() { + sphere(10); + cylinder(h=30, r=5, center=true); + } } diff --git a/tests/regression/cgalpngtest/projection-cut-tests-expected.png b/tests/regression/cgalpngtest/projection-cut-tests-expected.png new file mode 100644 index 0000000..7189447 Binary files /dev/null and b/tests/regression/cgalpngtest/projection-cut-tests-expected.png differ diff --git a/tests/regression/cgalpngtest/projection-tests-expected.png b/tests/regression/cgalpngtest/projection-tests-expected.png index 3be3654..c0d5289 100644 Binary files a/tests/regression/cgalpngtest/projection-tests-expected.png and b/tests/regression/cgalpngtest/projection-tests-expected.png differ diff --git a/tests/regression/dumptest/projection-cut-tests-expected.csg b/tests/regression/dumptest/projection-cut-tests-expected.csg new file mode 100644 index 0000000..4c37fa2 --- /dev/null +++ b/tests/regression/dumptest/projection-cut-tests-expected.csg @@ -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); + } + } + } + } + } +} diff --git a/tests/regression/dumptest/projection-tests-expected.csg b/tests/regression/dumptest/projection-tests-expected.csg index da3e5ce..04cd404 100644 --- a/tests/regression/dumptest/projection-tests-expected.csg +++ b/tests/regression/dumptest/projection-tests-expected.csg @@ -1,37 +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); } projection(cut = false, convexity = 0) { cube(size = [10, 10, 10], 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, -12], [0, 1, 0, 0], [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); } } } - 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); - } - } + 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); } } } diff --git a/tests/regression/opencsgtest/projection-cut-tests-expected.png b/tests/regression/opencsgtest/projection-cut-tests-expected.png new file mode 100644 index 0000000..5063301 Binary files /dev/null and b/tests/regression/opencsgtest/projection-cut-tests-expected.png differ diff --git a/tests/regression/opencsgtest/projection-tests-expected.png b/tests/regression/opencsgtest/projection-tests-expected.png index b808ffe..b3af1e1 100644 Binary files a/tests/regression/opencsgtest/projection-tests-expected.png and b/tests/regression/opencsgtest/projection-tests-expected.png differ diff --git a/tests/regression/throwntogethertest/projection-cut-tests-expected.png b/tests/regression/throwntogethertest/projection-cut-tests-expected.png new file mode 100644 index 0000000..5063301 Binary files /dev/null and b/tests/regression/throwntogethertest/projection-cut-tests-expected.png differ diff --git a/tests/regression/throwntogethertest/projection-tests-expected.png b/tests/regression/throwntogethertest/projection-tests-expected.png index b808ffe..b3af1e1 100644 Binary files a/tests/regression/throwntogethertest/projection-tests-expected.png and b/tests/regression/throwntogethertest/projection-tests-expected.png differ -- cgit v0.10.1 From cf9f19818ca5886275019f8e93c7fb8ec0e4bde6 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Tue, 26 Nov 2013 20:04:57 -0600 Subject: prevent crash in CGAL nef3. fix #issue 410 . also deal w qmake bug re .h files diff --git a/openscad.pro b/openscad.pro index fd9f494..b38419e 100644 --- a/openscad.pro +++ b/openscad.pro @@ -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 \ diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc index ec01315..242fe0f 100644 --- a/src/CGALEvaluator.cc +++ b/src/CGALEvaluator.cc @@ -159,9 +159,19 @@ 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(&CGAL_Polyhedron::Vertex::point), _1)); + bool err = false; + try{ + err = nefworkaround::convert_to_Polyhedron( *(chN.p3), P ); + //chN.p3->convert_to_Polyhedron(P); + } catch (...) { + err = true; + } + if (err) { + PRINT("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed"); + } else { + std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points3d), + boost::bind(static_cast(&CGAL_Polyhedron::Vertex::point), _1)); + } } } chnode->progress_report(); diff --git a/src/CGAL_Nef_polyhedron.cc b/src/CGAL_Nef_polyhedron.cc index 440f4ed..4761d26 100644 --- a/src/CGAL_Nef_polyhedron.cc +++ b/src/CGAL_Nef_polyhedron.cc @@ -98,11 +98,22 @@ PolySet *CGAL_Nef_polyhedron::convertToPolyset() CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); try { CGAL_Polyhedron P; - this->p3->convert_to_Polyhedron(P); - ps = createPolySetFromPolyhedron(P); + bool err = nefworkaround::convert_to_Polyhedron( *(this->p3), P ); + //this->p3->convert_to_Polyhedron(P); + if (err) { + PRINT("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed"); + } else { + ps = createPolySetFromPolyhedron(P); + } } catch (const CGAL::Precondition_exception &e) { - PRINTB("CGAL error in CGAL_Nef_polyhedron::convertToPolyset(): %s", e.what()); + PRINTB("CGAL Precondition error in CGAL_Nef_polyhedron::convertToPolyset(): %s", e.what()); + } + catch (const CGAL::Assertion_exception &e) { + PRINTB("CGAL Assertion error in CGAL_Nef_polyhedron::convertToPolyset(): %s", e.what()); + } + catch (...) { + PRINT("CGAL unknown error in CGAL_Nef_polyhedron::convertToPolyset()"); } CGAL::set_error_behaviour(old_behaviour); } diff --git a/src/cgal.h b/src/cgal.h index 45228be..69c8c27 100644 --- a/src/cgal.h +++ b/src/cgal.h @@ -27,6 +27,7 @@ using boost::uintmax_t; #include #include #include +#include #include #include #include @@ -48,9 +49,10 @@ typedef CGAL::Exact_predicates_exact_constructions_kernel CGAL_ExactKernel2; typedef CGAL::Polygon_2 CGAL_Poly2; typedef CGAL::Polygon_with_holes_2 CGAL_Poly2h; - //typedef CGAL::Cartesian 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 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_Nef_polyhedron3; typedef CGAL_Nef_polyhedron3::Aff_transformation_3 CGAL_Aff_transformation; diff --git a/src/export.cc b/src/export.cc index ec6e576..cef323e 100644 --- a/src/export.cc +++ b/src/export.cc @@ -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( *(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); } -- cgit v0.10.1 From faf008ce24e5169dcfe75d90bfbc988abdfd7f93 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Tue, 26 Nov 2013 20:29:29 -0600 Subject: simplify nef polyhedron code. attempt to add test for bug diff --git a/src/CGAL_Nef_polyhedron.cc b/src/CGAL_Nef_polyhedron.cc index 4761d26..49b9a53 100644 --- a/src/CGAL_Nef_polyhedron.cc +++ b/src/CGAL_Nef_polyhedron.cc @@ -96,24 +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; - bool err = nefworkaround::convert_to_Polyhedron( *(this->p3), P ); + err = nefworkaround::convert_to_Polyhedron( *(this->p3), P ); //this->p3->convert_to_Polyhedron(P); - if (err) { - PRINT("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed"); - } else { - ps = createPolySetFromPolyhedron(P); - } } - catch (const CGAL::Precondition_exception &e) { - PRINTB("CGAL Precondition error in CGAL_Nef_polyhedron::convertToPolyset(): %s", e.what()); + catch (const CGAL::Failure_exception &e) { + err = true; + errmsg = std::string(e.what()); } - catch (const CGAL::Assertion_exception &e) { - PRINTB("CGAL Assertion error in CGAL_Nef_polyhedron::convertToPolyset(): %s", e.what()); - } - catch (...) { - PRINT("CGAL unknown error in CGAL_Nef_polyhedron::convertToPolyset()"); + 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); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3d3aad1..731a418 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -800,6 +800,7 @@ list(APPEND CGALPNGTEST_FILES ${FEATURES_FILES} ${SCAD_DXF_FILES} ${EXAMPLE_FILE 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) -- cgit v0.10.1 From fd715c6526e961cb7f3d6ba6a0563788d7d1674d Mon Sep 17 00:00:00 2001 From: Don Bright Date: Tue, 26 Nov 2013 20:55:26 -0600 Subject: finish adding new test, add png for new test diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 731a418..0477a45 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -794,6 +794,7 @@ 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}) @@ -823,6 +824,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 diff --git a/tests/regression/cgalpngtest/stl-cgal-convert_to_Polyhedron-crash-expected.png b/tests/regression/cgalpngtest/stl-cgal-convert_to_Polyhedron-crash-expected.png new file mode 100644 index 0000000..318cbaa Binary files /dev/null and b/tests/regression/cgalpngtest/stl-cgal-convert_to_Polyhedron-crash-expected.png differ diff --git a/tests/regression/dumptest/stl-cgal-convert_to_Polyhedron-crash-expected.csg b/tests/regression/dumptest/stl-cgal-convert_to_Polyhedron-crash-expected.csg new file mode 100644 index 0000000..acad52f --- /dev/null +++ b/tests/regression/dumptest/stl-cgal-convert_to_Polyhedron-crash-expected.csg @@ -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); + } +} -- cgit v0.10.1 From 7b64944738d91eb2eef92f93f526cc29436adf15 Mon Sep 17 00:00:00 2001 From: Ricardo Markiewicz Date: Fri, 29 Nov 2013 00:16:40 -0300 Subject: Try to keep cursor and scroll in place on refresh When the file is saving, the cursor position was resetting to the top and you should keep scrolling by hand every time you save the file. This patch saves the scroll and cursor position and set it again after the file is refreshed so we can continue edition from where we were. diff --git a/src/mainwin.cc b/src/mainwin.cc index 5b986b1..8c21b20 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -75,6 +75,7 @@ #include #include #include +#include #include @@ -605,7 +606,15 @@ void MainWindow::refreshDocument() reader.setCodec("UTF-8"); QString text = reader.readAll(); PRINTB("Loaded design '%s'.", this->fileName.toLocal8Bit().constData()); + int y = editor->verticalScrollBar()->sliderPosition(); + // Save current cursor position + QTextCursor cursor = editor->textCursor(); + int n = cursor.position(); editor->setPlainText(text); + // Restore cursor position + cursor.setPosition(n); + editor->setTextCursor(cursor); + editor->verticalScrollBar()->setSliderPosition(y); } } setCurrentOutput(); -- cgit v0.10.1 From afe1fbcb53ff286b2f6efdb99efb6ed9947304f9 Mon Sep 17 00:00:00 2001 From: Ricardo Markiewicz Date: Fri, 29 Nov 2013 01:40:28 -0300 Subject: Move main code inside Editor class Before open a new file now we cleanup the Editor, so the new file get the cursor on the first character. diff --git a/src/editor.cc b/src/editor.cc index 08bf005..069101f 100644 --- a/src/editor.cc +++ b/src/editor.cc @@ -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); + } +} diff --git a/src/editor.h b/src/editor.h index 09484f5..8d092a9 100644 --- a/src/editor.h +++ b/src/editor.h @@ -2,6 +2,7 @@ #include #include #include +#include #include 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(); diff --git a/src/mainwin.cc b/src/mainwin.cc index 8c21b20..1ad8bc8 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -75,7 +75,6 @@ #include #include #include -#include #include @@ -505,6 +504,7 @@ MainWindow::openFile(const QString &new_filename) } #endif setFileName(actual_filename); + editor->setPlainText(""); fileChangedOnDisk(); // force cached autoReloadId to update refreshDocument(); @@ -606,15 +606,7 @@ void MainWindow::refreshDocument() reader.setCodec("UTF-8"); QString text = reader.readAll(); PRINTB("Loaded design '%s'.", this->fileName.toLocal8Bit().constData()); - int y = editor->verticalScrollBar()->sliderPosition(); - // Save current cursor position - QTextCursor cursor = editor->textCursor(); - int n = cursor.position(); editor->setPlainText(text); - // Restore cursor position - cursor.setPosition(n); - editor->setTextCursor(cursor); - editor->verticalScrollBar()->setSliderPosition(y); } } setCurrentOutput(); -- cgit v0.10.1 From 6f6a8dff7669322a35ddc33ad195f2cb3de45de8 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sat, 30 Nov 2013 13:42:09 -0600 Subject: MXE c/o 'stable' instd of 'master' from github b/c master has gcc 4.8.2 which is causing crashes. also allow 'build only' builder.sh script command diff --git a/scripts/builder.sh b/scripts/builder.sh index 552d559..ca7e5b2 100755 --- a/scripts/builder.sh +++ b/scripts/builder.sh @@ -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 diff --git a/scripts/mingw-x-build-dependencies.sh b/scripts/mingw-x-build-dependencies.sh index df8572f..c0f658d 100755 --- a/scripts/mingw-x-build-dependencies.sh +++ b/scripts/mingw-x-build-dependencies.sh @@ -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: # @@ -54,11 +59,19 @@ 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 -- cgit v0.10.1 From f175bae46a8f15823780c5a9c89b11476acb3107 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sat, 30 Nov 2013 15:13:03 -0600 Subject: disallow gcc 4.8.2 diff --git a/src/version_check.h b/src/version_check.h index 86e769c..fbea077 100644 --- a/src/version_check.h +++ b/src/version_check.h @@ -108,5 +108,13 @@ a time, to avoid confusion. #endif // MPFR #endif // GMP +// see github issue #552 +#define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) +#if GCC_VERSION == 40802 +#error OpenSCAD isn't compatible with gcc 4.8.2. Please try a different version +#endif + #endif // OPENSCAD_SKIP_VERSION_CHECK -- cgit v0.10.1 From 9ea7713335122eabdd243cfcf1e5ae87a8bd23d1 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sat, 30 Nov 2013 15:43:00 -0600 Subject: print errmsg for applyHull. add quotes around err msg in version check. diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc index 242fe0f..4a05274 100644 --- a/src/CGALEvaluator.cc +++ b/src/CGALEvaluator.cc @@ -160,14 +160,15 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node) } else { bool err = false; + std::string errmsg(""); try{ err = nefworkaround::convert_to_Polyhedron( *(chN.p3), P ); //chN.p3->convert_to_Polyhedron(P); - } catch (...) { + catch (const CGAL::Failure_exception &e) { err = true; } if (err) { - PRINT("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed"); + PRINTB("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed. %s", e.what()); } else { std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points3d), boost::bind(static_cast(&CGAL_Polyhedron::Vertex::point), _1)); diff --git a/src/version_check.h b/src/version_check.h index fbea077..be52e61 100644 --- a/src/version_check.h +++ b/src/version_check.h @@ -113,7 +113,7 @@ a time, to avoid confusion. + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) #if GCC_VERSION == 40802 -#error OpenSCAD isn't compatible with gcc 4.8.2. Please try a different version +#error "OpenSCAD isnt compatible with gcc 4.8.2. Please try a different version" #endif #endif // OPENSCAD_SKIP_VERSION_CHECK -- cgit v0.10.1 From 791a49b9e8489818e41deae2b1d4ba2b6ff50e5f Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sat, 30 Nov 2013 17:26:50 -0600 Subject: build bug fix diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc index 4a05274..86118d7 100644 --- a/src/CGALEvaluator.cc +++ b/src/CGALEvaluator.cc @@ -161,14 +161,15 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node) else { bool err = false; std::string errmsg(""); - try{ + try { err = nefworkaround::convert_to_Polyhedron( *(chN.p3), P ); //chN.p3->convert_to_Polyhedron(P); - catch (const CGAL::Failure_exception &e) { + } catch (const CGAL::Failure_exception &e) { err = true; + errmsg = std::string(e.what()); } if (err) { - PRINTB("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed. %s", e.what()); + 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(&CGAL_Polyhedron::Vertex::point), _1)); diff --git a/src/CGAL_Nef3_workaround.h b/src/CGAL_Nef3_workaround.h new file mode 100644 index 0000000..c2482ac --- /dev/null +++ b/src/CGAL_Nef3_workaround.h @@ -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 +// Miguel Granados +// Susan Hert +// Lutz Kettner +// Ralf Osbild +// Peter Hachenberger + +/* + 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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "printutils.h" + +namespace nefworkaround { + +template +class Triangulation_handler2 { + + typedef typename CGAL::Triangulation_vertex_base_2 Vb; + typedef typename CGAL::Constrained_triangulation_face_base_2 Fb; + typedef typename CGAL::Triangulation_data_structure_2 TDS; + typedef typename CGAL::Constrained_triangulation_2 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 visited; + CGAL::Unique_hash_map 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 + 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 + 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 Build_polyhedron : public CGAL::Modifier_base { +public: + bool error; // added for OpenSCAD + class Visitor { + typedef typename CGAL::Projection_traits_xy_3 XY; + typedef typename CGAL::Projection_traits_yz_3 YZ; + typedef typename CGAL::Projection_traits_xz_3 XZ; + + const CGAL::Object_index& VI; + CGAL::Polyhedron_incremental_builder_3& B; + const typename Nef::SNC_const_decorator& D; + + public: + bool error;//added for OpenSCAD + Visitor(CGAL::Polyhedron_incremental_builder_3& BB, + const typename Nef::SNC_const_decorator& sd, + CGAL::Object_index& 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 th(f); + th.handle_triangles(B, VI); + } else if(c == 1) { + Triangulation_handler2 th(f); + th.handle_triangles(B, VI); + } else if(c == 2) { + Triangulation_handler2 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 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 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 +bool convert_to_Polyhedron( const CGAL::Nef_polyhedron_3 &N, CGAL::Polyhedron_3 &P ) +{ + // several lines here added for OpenSCAD + typedef typename CGAL::Nef_polyhedron_3 Nef3; + typedef typename CGAL::Polyhedron_3 Polyhedron; + typedef typename Polyhedron::HalfedgeDS HalfedgeDS; + CGAL_precondition(N.is_simple()); + P.clear(); + Build_polyhedron bp(N); + P.delegate(bp); + return bp.error; +} + + + + + +} //namespace nefworkaround + + + + +#endif + -- cgit v0.10.1 From 69cbb17497ab52620e39874a2323db1aadf6dcbe Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Wed, 4 Dec 2013 01:15:19 -0500 Subject: Killed warnings diff --git a/src/CocoaUtils.mm b/src/CocoaUtils.mm index 92640fd..9856b3d 100644 --- a/src/CocoaUtils.mm +++ b/src/CocoaUtils.mm @@ -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()); } diff --git a/src/modcontext.cc b/src/modcontext.cc index 5b48009..7941cf5 100644 --- a/src/modcontext.cc +++ b/src/modcontext.cc @@ -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(); } -- cgit v0.10.1 From f2fe074e1d947f74e34833453cc613e46e5450a6 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Wed, 4 Dec 2013 01:15:34 -0500 Subject: clang fix: Clang claims to be gcc diff --git a/src/stl-utils.cc b/src/stl-utils.cc index 790fd17..027339c 100644 --- a/src/stl-utils.cc +++ b/src/stl-utils.cc @@ -1,4 +1,4 @@ -#if defined(__APPLE__) && defined(__GNUC__) +#if defined(__APPLE__) && defined(__GNUC__) && !defined(__clang__) #include -- cgit v0.10.1 From 301ef946f05a320768d4b8f974a95e2a04a5fc0d Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Thu, 5 Dec 2013 12:20:40 -0500 Subject: Qt4 patches to make it build on 10.9 diff --git a/patches/qt4/patch-libtiff.diff b/patches/qt4/patch-libtiff.diff new file mode 100644 index 0000000..5b7f9ec --- /dev/null +++ b/patches/qt4/patch-libtiff.diff @@ -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 does not define. */ + /* #undef off_t */ + diff --git a/patches/qt4/patch-src_corelib_global_qglobal.h.diff b/patches/qt4/patch-src_corelib_global_qglobal.h.diff new file mode 100644 index 0000000..8c55c5a --- /dev/null +++ b/patches/qt4/patch-src_corelib_global_qglobal.h.diff @@ -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 diff --git a/patches/qt4/patch-src_plugins_bearer_corewlan_qcorewlanengine.mm.diff b/patches/qt4/patch-src_plugins_bearer_corewlan_qcorewlanengine.mm.diff new file mode 100644 index 0000000..61b2eef --- /dev/null +++ b/patches/qt4/patch-src_plugins_bearer_corewlan_qcorewlanengine.mm.diff @@ -0,0 +1,1382 @@ +--- src/plugins/bearer/corewlan/qcorewlanengine.mm ++++ src/plugins/bearer/corewlan/qcorewlanengine.mm +@@ -52,29 +52,17 @@ + #include + + #include +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +-#include +- +-#include ++ ++extern "C" { // Otherwise it won't find CWKeychain* symbols at link time ++#import ++} ++ + #include "private/qcore_mac_p.h" + + #include + #include + +-inline QString qt_NSStringToQString(const NSString *nsstr) +-{ return QCFString::toQString(reinterpret_cast(nsstr)); } +- +-inline NSString *qt_QStringToNSString(const QString &qstr) +-{ return [const_cast(reinterpret_cast(QCFString::toCFStringRef(qstr))) autorelease]; } +- ++#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 + + @interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject + { +@@ -86,6 +74,7 @@ inline NSString *qt_QStringToNSString(const QString &qstr) + - (void)notificationHandler;//:(NSNotification *)notification; + - (void)remove; + - (void)setEngine:(QCoreWlanEngine *)coreEngine; ++- (QCoreWlanEngine *)engine; + - (void)dealloc; + + @property (assign) QCoreWlanEngine* engine; +@@ -93,7 +82,6 @@ inline NSString *qt_QStringToNSString(const QString &qstr) + @end + + @implementation QT_MANGLE_NAMESPACE(QNSListener) +-@synthesize engine; + + - (id) init + { +@@ -101,7 +89,7 @@ inline NSString *qt_QStringToNSString(const QString &qstr) + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + notificationCenter = [NSNotificationCenter defaultCenter]; + currentInterface = [CWInterface interfaceWithName:nil]; +- [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:kCWPowerDidChangeNotification object:nil]; ++ [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:CWPowerDidChangeNotification object:nil]; + [locker unlock]; + [autoreleasepool release]; + return self; +@@ -120,6 +108,11 @@ inline NSString *qt_QStringToNSString(const QString &qstr) + [locker unlock]; + } + ++-(QCoreWlanEngine *)engine ++{ ++ return engine; ++} ++ + -(void)remove + { + [locker lock]; +@@ -133,7 +126,7 @@ inline NSString *qt_QStringToNSString(const QString &qstr) + } + @end + +-QT_MANGLE_NAMESPACE(QNSListener) *listener = 0; ++static QT_MANGLE_NAMESPACE(QNSListener) *listener = 0; + + QT_BEGIN_NAMESPACE + +@@ -170,36 +163,28 @@ void QScanThread::run() + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + QStringList found; + mutex.lock(); +- CWInterface *currentInterface = [CWInterface interfaceWithName:qt_QStringToNSString(interfaceName)]; ++ CWInterface *currentInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceName)]; + mutex.unlock(); + +- if([currentInterface power]) { ++ if (currentInterface.powerOn) { + NSError *err = nil; +- NSDictionary *parametersDict = [NSDictionary dictionaryWithObjectsAndKeys: +- [NSNumber numberWithBool:YES], kCWScanKeyMerge, +- [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, +- [NSNumber numberWithInteger:100], kCWScanKeyRestTime, nil]; + +- NSArray* apArray = [currentInterface scanForNetworksWithParameters:parametersDict error:&err]; +- CWNetwork *apNetwork; ++ NSSet* apSet = [currentInterface scanForNetworksWithName:nil error:&err]; + + if (!err) { +- +- for(uint row=0; row < [apArray count]; row++ ) { +- apNetwork = [apArray objectAtIndex:row]; +- +- const QString networkSsid = qt_NSStringToQString([apNetwork ssid]); ++ for (CWNetwork *apNetwork in apSet) { ++ const QString networkSsid = QCFString::toQString(CFStringRef([apNetwork ssid])); + const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); + found.append(id); + + QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; + bool known = isKnownSsid(networkSsid); +- if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { +- if( networkSsid == qt_NSStringToQString( [currentInterface ssid])) { ++ if (currentInterface.serviceActive) { ++ if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) { + state = QNetworkConfiguration::Active; + } + } +- if(state == QNetworkConfiguration::Undefined) { ++ if (state == QNetworkConfiguration::Undefined) { + if(known) { + state = QNetworkConfiguration::Discovered; + } else { +@@ -207,7 +192,7 @@ void QScanThread::run() + } + } + QNetworkConfiguration::Purpose purpose = QNetworkConfiguration::UnknownPurpose; +- if([[apNetwork securityMode] intValue] == kCWSecurityModeOpen) { ++ if ([apNetwork supportsSecurity:kCWSecurityNone]) { + purpose = QNetworkConfiguration::PublicPurpose; + } else { + purpose = QNetworkConfiguration::PrivatePurpose; +@@ -237,8 +222,8 @@ void QScanThread::run() + interfaceName = ij.value(); + } + +- if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { +- if( networkSsid == qt_NSStringToQString([currentInterface ssid])) { ++ if (currentInterface.serviceActive) { ++ if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) { + state = QNetworkConfiguration::Active; + } + } +@@ -300,14 +285,14 @@ void QScanThread::getUserConfigurations() + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + userProfiles.clear(); + +- NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; +- for(uint row=0; row < [wifiInterfaces count]; row++ ) { ++ NSSet *wifiInterfaces = [CWInterface interfaceNames]; ++ for (NSString *ifName in wifiInterfaces) { + +- CWInterface *wifiInterface = [CWInterface interfaceWithName: [wifiInterfaces objectAtIndex:row]]; +- if ( ![wifiInterface power] ) ++ CWInterface *wifiInterface = [CWInterface interfaceWithName: ifName]; ++ if (!wifiInterface.powerOn) + continue; + +- NSString *nsInterfaceName = [wifiInterface name]; ++ NSString *nsInterfaceName = wifiInterface.ssid; + // add user configured system networks + SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, (CFStringRef)@"Qt corewlan", nil, nil); + NSDictionary * airportPlist = (NSDictionary *)SCDynamicStoreCopyValue(dynRef, (CFStringRef)[NSString stringWithFormat:@"Setup:/Network/Interface/%@/AirPort", nsInterfaceName]); +@@ -316,11 +301,11 @@ void QScanThread::getUserConfigurations() + NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"]; + + NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"]; +- for(NSString *ssidkey in thisSsidarray) { +- QString thisSsid = qt_NSStringToQString(ssidkey); ++ for (NSString *ssidkey in thisSsidarray) { ++ QString thisSsid = QCFString::toQString(CFStringRef(ssidkey)); + if(!userProfiles.contains(thisSsid)) { + QMap map; +- map.insert(thisSsid, qt_NSStringToQString(nsInterfaceName)); ++ map.insert(thisSsid, QCFString::toQString(CFStringRef(nsInterfaceName))); + userProfiles.insert(thisSsid, map); + } + } +@@ -329,7 +314,7 @@ void QScanThread::getUserConfigurations() + + // 802.1X user profiles + QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist"; +- NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile:qt_QStringToNSString(userProfilePath)] autorelease]; ++ NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile: (NSString *)QCFString::toCFStringRef(userProfilePath)] autorelease]; + if(eapDict != nil) { + NSString *profileStr= @"Profiles"; + NSString *nameStr = @"UserDefinedName"; +@@ -348,15 +333,15 @@ void QScanThread::getUserConfigurations() + QString ssid; + for(int i = 0; i < dictSize; i++) { + if([nameStr isEqualToString:keys[i]]) { +- networkName = qt_NSStringToQString(objects[i]); ++ networkName = QCFString::toQString(CFStringRef(objects[i])); + } + if([networkSsidStr isEqualToString:keys[i]]) { +- ssid = qt_NSStringToQString(objects[i]); ++ ssid = QCFString::toQString(CFStringRef(objects[i])); + } + if(!userProfiles.contains(networkName) + && !ssid.isEmpty()) { + QMap map; +- map.insert(ssid, qt_NSStringToQString(nsInterfaceName)); ++ map.insert(ssid, QCFString::toQString(CFStringRef(nsInterfaceName))); + userProfiles.insert(networkName, map); + } + } +@@ -444,7 +429,7 @@ void QCoreWlanEngine::initialize() + QMutexLocker locker(&mutex); + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + +- if([[CWInterface supportedInterfaces] count] > 0 && !listener) { ++ if ([[CWInterface interfaceNames] count] > 0 && !listener) { + listener = [[QT_MANGLE_NAMESPACE(QNSListener) alloc] init]; + listener.engine = this; + hasWifi = true; +@@ -479,141 +464,68 @@ void QCoreWlanEngine::connectToId(const QString &id) + QString interfaceString = getInterfaceFromId(id); + + CWInterface *wifiInterface = +- [CWInterface interfaceWithName: qt_QStringToNSString(interfaceString)]; ++ [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)]; + +- if ([wifiInterface power]) { ++ if (wifiInterface.powerOn) { + NSError *err = nil; +- NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0]; +- + QString wantedSsid; +- + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + + const QString idHash = QString::number(qHash(QLatin1String("corewlan:") + ptr->name)); + const QString idHash2 = QString::number(qHash(QLatin1String("corewlan:") + scanThread->getNetworkNameFromSsid(ptr->name))); + +- bool using8021X = false; +- if (idHash2 != id) { +- NSArray *array = [CW8021XProfile allUser8021XProfiles]; +- +- for (NSUInteger i = 0; i < [array count]; ++i) { +- const QString networkNameHashCheck = QString::number(qHash(QLatin1String("corewlan:") + qt_NSStringToQString([[array objectAtIndex:i] userDefinedName]))); +- +- const QString ssidHash = QString::number(qHash(QLatin1String("corewlan:") + qt_NSStringToQString([[array objectAtIndex:i] ssid]))); +- +- if (id == networkNameHashCheck || id == ssidHash) { +- const QString thisName = scanThread->getSsidFromNetworkName(id); +- if (thisName.isEmpty()) +- wantedSsid = id; +- else +- wantedSsid = thisName; +- +- [params setValue: [array objectAtIndex:i] forKey:kCWAssocKey8021XProfile]; +- using8021X = true; +- break; +- } ++ QString wantedNetwork; ++ QMapIterator > i(scanThread->userProfiles); ++ while (i.hasNext()) { ++ i.next(); ++ wantedNetwork = i.key(); ++ const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork)); ++ if (id == networkNameHash) { ++ wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork); ++ break; + } + } + +- if (!using8021X) { +- QString wantedNetwork; +- QMapIterator > i(scanThread->userProfiles); +- while (i.hasNext()) { +- i.next(); +- wantedNetwork = i.key(); +- const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork)); +- if (id == networkNameHash) { +- wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork); +- break; +- } +- } +- } +- NSDictionary *scanParameters = [NSDictionary dictionaryWithObjectsAndKeys: +- [NSNumber numberWithBool:YES], kCWScanKeyMerge, +- [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, +- [NSNumber numberWithInteger:100], kCWScanKeyRestTime, +- qt_QStringToNSString(wantedSsid), kCWScanKeySSID, +- nil]; +- +- NSArray *scanArray = [wifiInterface scanForNetworksWithParameters:scanParameters error:&err]; ++ NSSet *scanSet = [wifiInterface scanForNetworksWithName:(NSString *)QCFString::toCFStringRef(wantedSsid) error:&err]; + + if(!err) { +- for(uint row=0; row < [scanArray count]; row++ ) { +- CWNetwork *apNetwork = [scanArray objectAtIndex:row]; +- +- if(wantedSsid == qt_NSStringToQString([apNetwork ssid])) { +- +- if(!using8021X) { +- SecKeychainAttribute attributes[3]; +- +- NSString *account = [apNetwork ssid]; +- NSString *keyKind = @"AirPort network password"; +- NSString *keyName = account; +- +- attributes[0].tag = kSecAccountItemAttr; +- attributes[0].data = (void *)[account UTF8String]; +- attributes[0].length = [account length]; +- +- attributes[1].tag = kSecDescriptionItemAttr; +- attributes[1].data = (void *)[keyKind UTF8String]; +- attributes[1].length = [keyKind length]; +- +- attributes[2].tag = kSecLabelItemAttr; +- attributes[2].data = (void *)[keyName UTF8String]; +- attributes[2].length = [keyName length]; +- +- SecKeychainAttributeList attributeList = {3,attributes}; +- +- SecKeychainSearchRef searchRef; +- SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributeList, &searchRef); +- +- NSString *password = @""; +- SecKeychainItemRef searchItem; +- +- if (SecKeychainSearchCopyNext(searchRef, &searchItem) == noErr) { +- UInt32 realPasswordLength; +- SecKeychainAttribute attributesW[8]; +- attributesW[0].tag = kSecAccountItemAttr; +- SecKeychainAttributeList listW = {1,attributesW}; +- char *realPassword; +- OSStatus status = SecKeychainItemCopyContent(searchItem, NULL, &listW, &realPasswordLength,(void **)&realPassword); +- +- if (status == noErr) { +- if (realPassword != NULL) { +- +- QByteArray pBuf; +- pBuf.resize(realPasswordLength); +- pBuf.prepend(realPassword); +- pBuf.insert(realPasswordLength,'\0'); +- +- password = [NSString stringWithUTF8String:pBuf]; +- } +- SecKeychainItemFreeContent(&listW, realPassword); +- } +- +- CFRelease(searchItem); +- } else { +- qDebug() << "SecKeychainSearchCopyNext error"; +- } +- [params setValue: password forKey: kCWAssocKeyPassphrase]; +- } // end using8021X +- +- +- bool result = [wifiInterface associateToNetwork: apNetwork parameters:[NSDictionary dictionaryWithDictionary:params] error:&err]; ++ for (CWNetwork *apNetwork in scanSet) { ++ CFDataRef ssidData = (CFDataRef)[apNetwork ssidData]; ++ bool result = false; ++ ++ SecIdentityRef identity = 0; ++ // Check first whether we require IEEE 802.1X authentication for the wanted SSID ++ if (CWKeychainCopyEAPIdentity(ssidData, &identity) == errSecSuccess) { ++ CFStringRef username = 0; ++ CFStringRef password = 0; ++ if (CWKeychainCopyEAPUsernameAndPassword(ssidData, &username, &password) == errSecSuccess) { ++ result = [wifiInterface associateToEnterpriseNetwork:apNetwork ++ identity:identity username:(NSString *)username password:(NSString *)password ++ error:&err]; ++ CFRelease(username); ++ CFRelease(password); ++ } ++ CFRelease(identity); ++ } else { ++ CFStringRef password = 0; ++ if (CWKeychainCopyPassword(ssidData, &password) == errSecSuccess) { ++ result = [wifiInterface associateToNetwork:apNetwork password:(NSString *)password error:&err]; ++ CFRelease(password); ++ } ++ } + +- if(!err) { +- if(!result) { +- emit connectionError(id, ConnectError); +- } else { +- return; +- } ++ if (!err) { ++ if (!result) { ++ emit connectionError(id, ConnectError); + } else { +- qDebug() <<"associate ERROR"<< qt_NSStringToQString([err localizedDescription ]); ++ return; + } ++ } else { ++ qDebug() <<"associate ERROR"<< QCFString::toQString(CFStringRef([err localizedDescription ])); + } + } //end scan network + } else { +- qDebug() <<"scan ERROR"<< qt_NSStringToQString([err localizedDescription ]); ++ qDebug() <<"scan ERROR"<< QCFString::toQString(CFStringRef([err localizedDescription ])); + } + emit connectionError(id, InterfaceLookupError); + } +@@ -631,10 +543,10 @@ void QCoreWlanEngine::disconnectFromId(const QString &id) + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + + CWInterface *wifiInterface = +- [CWInterface interfaceWithName: qt_QStringToNSString(interfaceString)]; ++ [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)]; + + [wifiInterface disassociate]; +- if ([[wifiInterface interfaceState]intValue] != kCWInterfaceStateInactive) { ++ if (wifiInterface.serviceActive) { + locker.unlock(); + emit connectionError(id, DisconnectionError); + locker.relock(); +@@ -654,9 +566,9 @@ void QCoreWlanEngine::doRequestUpdate() + + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; + +- NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; +- for (uint row = 0; row < [wifiInterfaces count]; ++row) { +- scanThread->interfaceName = qt_NSStringToQString([wifiInterfaces objectAtIndex:row]); ++ NSSet *wifiInterfaces = [CWInterface interfaceNames]; ++ for (NSString *ifName in wifiInterfaces) { ++ scanThread->interfaceName = QCFString::toQString(CFStringRef(ifName)); + scanThread->start(); + } + locker.unlock(); +@@ -669,8 +581,8 @@ bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName) + bool haswifi = false; + if(hasWifi) { + NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; +- CWInterface *defaultInterface = [CWInterface interfaceWithName: qt_QStringToNSString(wifiDeviceName)]; +- if([defaultInterface power]) { ++ CWInterface *defaultInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(wifiDeviceName)]; ++ if (defaultInterface.powerOn) { + haswifi = true; + } + [autoreleasepool release]; +@@ -898,7 +810,7 @@ quint64 QCoreWlanEngine::startTime(const QString &identifier) + bool ok = false; + for(int i = 0; i < dictSize; i++) { + if([ssidStr isEqualToString:keys[i]]) { +- const QString ident = QString::number(qHash(QLatin1String("corewlan:") + qt_NSStringToQString(objects[i]))); ++ const QString ident = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef(objects[i])))); + if(ident == identifier) { + ok = true; + } +@@ -944,3 +856,7 @@ quint64 QCoreWlanEngine::getBytes(const QString &interfaceName, bool b) + } + + QT_END_NAMESPACE ++ ++#else // QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE ++#include "qcorewlanengine_10_6.mm" ++#endif +diff --git a/src/plugins/bearer/corewlan/qcorewlanengine_10_6.mm b/src/plugins/bearer/corewlan/qcorewlanengine_10_6.mm +new file mode 100644 +index 0000000..a3bf615 +--- /dev/null ++++ src/plugins/bearer/corewlan/qcorewlanengine_10_6.mm +@@ -0,0 +1,916 @@ ++/**************************************************************************** ++** ++** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ++** Contact: http://www.qt-project.org/legal ++** ++** This file is part of the plugins of the Qt Toolkit. ++** ++** $QT_BEGIN_LICENSE:LGPL$ ++** Commercial License Usage ++** Licensees holding valid commercial Qt licenses may use this file in ++** accordance with the commercial license agreement provided with the ++** Software or, alternatively, in accordance with the terms contained in ++** a written agreement between you and Digia. For licensing terms and ++** conditions see http://qt.digia.com/licensing. For further information ++** use the contact form at http://qt.digia.com/contact-us. ++** ++** GNU Lesser General Public License Usage ++** Alternatively, this file may be used under the terms of the GNU Lesser ++** General Public License version 2.1 as published by the Free Software ++** Foundation and appearing in the file LICENSE.LGPL included in the ++** packaging of this file. Please review the following information to ++** ensure the GNU Lesser General Public License version 2.1 requirements ++** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ++** ++** In addition, as a special exception, Digia gives you certain additional ++** rights. These rights are described in the Digia Qt LGPL Exception ++** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ++** ++** GNU General Public License Usage ++** Alternatively, this file may be used under the terms of the GNU ++** General Public License version 3.0 as published by the Free Software ++** Foundation and appearing in the file LICENSE.GPL included in the ++** packaging of this file. Please review the following information to ++** ensure the GNU General Public License version 3.0 requirements will be ++** met: http://www.gnu.org/copyleft/gpl.html. ++** ++** ++** $QT_END_LICENSE$ ++** ++****************************************************************************/ ++ ++#include ++ ++@interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject ++{ ++ NSNotificationCenter *notificationCenter; ++ CWInterface *currentInterface; ++ QCoreWlanEngine *engine; ++ NSLock *locker; ++} ++- (void)notificationHandler;//:(NSNotification *)notification; ++- (void)remove; ++- (void)setEngine:(QCoreWlanEngine *)coreEngine; ++- (QCoreWlanEngine *)engine; ++- (void)dealloc; ++ ++@property (assign) QCoreWlanEngine* engine; ++ ++@end ++ ++@implementation QT_MANGLE_NAMESPACE(QNSListener) ++ ++- (id) init ++{ ++ [locker lock]; ++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; ++ notificationCenter = [NSNotificationCenter defaultCenter]; ++ currentInterface = [CWInterface interfaceWithName:nil]; ++ [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:kCWPowerDidChangeNotification object:nil]; ++ [locker unlock]; ++ [autoreleasepool release]; ++ return self; ++} ++ ++-(void)dealloc ++{ ++ [super dealloc]; ++} ++ ++-(void)setEngine:(QCoreWlanEngine *)coreEngine ++{ ++ [locker lock]; ++ if(!engine) ++ engine = coreEngine; ++ [locker unlock]; ++} ++ ++-(QCoreWlanEngine *)engine ++{ ++ return engine; ++} ++ ++-(void)remove ++{ ++ [locker lock]; ++ [notificationCenter removeObserver:self]; ++ [locker unlock]; ++} ++ ++- (void)notificationHandler//:(NSNotification *)notification ++{ ++ engine->requestUpdate(); ++} ++@end ++ ++static QT_MANGLE_NAMESPACE(QNSListener) *listener = 0; ++ ++QT_BEGIN_NAMESPACE ++ ++void networkChangeCallback(SCDynamicStoreRef/* store*/, CFArrayRef changedKeys, void *info) ++{ ++ for ( long i = 0; i < CFArrayGetCount(changedKeys); i++) { ++ ++ QString changed = QCFString::toQString(CFStringRef((CFStringRef)CFArrayGetValueAtIndex(changedKeys, i))); ++ if( changed.contains("/Network/Global/IPv4")) { ++ QCoreWlanEngine* wlanEngine = static_cast(info); ++ wlanEngine->requestUpdate(); ++ } ++ } ++ return; ++} ++ ++ ++QScanThread::QScanThread(QObject *parent) ++ :QThread(parent) ++{ ++} ++ ++QScanThread::~QScanThread() ++{ ++} ++ ++void QScanThread::quit() ++{ ++ wait(); ++} ++ ++void QScanThread::run() ++{ ++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; ++ QStringList found; ++ mutex.lock(); ++ CWInterface *currentInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceName)]; ++ mutex.unlock(); ++ ++ if([currentInterface power]) { ++ NSError *err = nil; ++ NSDictionary *parametersDict = [NSDictionary dictionaryWithObjectsAndKeys: ++ [NSNumber numberWithBool:YES], kCWScanKeyMerge, ++ [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, ++ [NSNumber numberWithInteger:100], kCWScanKeyRestTime, nil]; ++ ++ NSArray* apArray = [currentInterface scanForNetworksWithParameters:parametersDict error:&err]; ++ CWNetwork *apNetwork; ++ ++ if (!err) { ++ ++ for(uint row=0; row < [apArray count]; row++ ) { ++ apNetwork = [apArray objectAtIndex:row]; ++ ++ const QString networkSsid = QCFString::toQString(CFStringRef([apNetwork ssid])); ++ const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); ++ found.append(id); ++ ++ QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; ++ bool known = isKnownSsid(networkSsid); ++ if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { ++ if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) { ++ state = QNetworkConfiguration::Active; ++ } ++ } ++ if(state == QNetworkConfiguration::Undefined) { ++ if(known) { ++ state = QNetworkConfiguration::Discovered; ++ } else { ++ state = QNetworkConfiguration::Undefined; ++ } ++ } ++ QNetworkConfiguration::Purpose purpose = QNetworkConfiguration::UnknownPurpose; ++ if([[apNetwork securityMode] intValue] == kCWSecurityModeOpen) { ++ purpose = QNetworkConfiguration::PublicPurpose; ++ } else { ++ purpose = QNetworkConfiguration::PrivatePurpose; ++ } ++ ++ found.append(foundNetwork(id, networkSsid, state, interfaceName, purpose)); ++ ++ } ++ } ++ } ++ // add known configurations that are not around. ++ QMapIterator > i(userProfiles); ++ while (i.hasNext()) { ++ i.next(); ++ ++ QString networkName = i.key(); ++ const QString id = QString::number(qHash(QLatin1String("corewlan:") + networkName)); ++ ++ if(!found.contains(id)) { ++ QString networkSsid = getSsidFromNetworkName(networkName); ++ const QString ssidId = QString::number(qHash(QLatin1String("corewlan:") + networkSsid)); ++ QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Undefined; ++ QString interfaceName; ++ QMapIterator ij(i.value()); ++ while (ij.hasNext()) { ++ ij.next(); ++ interfaceName = ij.value(); ++ } ++ ++ if( [currentInterface.interfaceState intValue] == kCWInterfaceStateRunning) { ++ if( networkSsid == QCFString::toQString(CFStringRef([currentInterface ssid]))) { ++ state = QNetworkConfiguration::Active; ++ } ++ } ++ if(state == QNetworkConfiguration::Undefined) { ++ if( userProfiles.contains(networkName) ++ && found.contains(ssidId)) { ++ state = QNetworkConfiguration::Discovered; ++ } ++ } ++ ++ if(state == QNetworkConfiguration::Undefined) { ++ state = QNetworkConfiguration::Defined; ++ } ++ ++ found.append(foundNetwork(id, networkName, state, interfaceName, QNetworkConfiguration::UnknownPurpose)); ++ } ++ } ++ emit networksChanged(); ++ [autoreleasepool release]; ++} ++ ++QStringList QScanThread::foundNetwork(const QString &id, const QString &name, const QNetworkConfiguration::StateFlags state, const QString &interfaceName, const QNetworkConfiguration::Purpose purpose) ++{ ++ QStringList found; ++ QMutexLocker locker(&mutex); ++ QNetworkConfigurationPrivate *ptr = new QNetworkConfigurationPrivate; ++ ++ ptr->name = name; ++ ptr->isValid = true; ++ ptr->id = id; ++ ptr->state = state; ++ ptr->type = QNetworkConfiguration::InternetAccessPoint; ++ ptr->bearerType = QNetworkConfiguration::BearerWLAN; ++ ptr->purpose = purpose; ++ ++ fetchedConfigurations.append( ptr); ++ configurationInterface.insert(ptr->id, interfaceName); ++ ++ locker.unlock(); ++ locker.relock(); ++ found.append(id); ++ return found; ++} ++ ++QList QScanThread::getConfigurations() ++{ ++ QMutexLocker locker(&mutex); ++ ++ QList foundConfigurations = fetchedConfigurations; ++ fetchedConfigurations.clear(); ++ ++ return foundConfigurations; ++} ++ ++void QScanThread::getUserConfigurations() ++{ ++ QMutexLocker locker(&mutex); ++ ++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; ++ userProfiles.clear(); ++ ++ NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; ++ for(uint row=0; row < [wifiInterfaces count]; row++ ) { ++ ++ CWInterface *wifiInterface = [CWInterface interfaceWithName: [wifiInterfaces objectAtIndex:row]]; ++ if ( ![wifiInterface power] ) ++ continue; ++ ++ NSString *nsInterfaceName = [wifiInterface name]; ++// add user configured system networks ++ SCDynamicStoreRef dynRef = SCDynamicStoreCreate(kCFAllocatorSystemDefault, (CFStringRef)@"Qt corewlan", nil, nil); ++ NSDictionary * airportPlist = (NSDictionary *)SCDynamicStoreCopyValue(dynRef, (CFStringRef)[NSString stringWithFormat:@"Setup:/Network/Interface/%@/AirPort", nsInterfaceName]); ++ CFRelease(dynRef); ++ if(airportPlist != nil) { ++ NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"]; ++ ++ NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"]; ++ for(NSString *ssidkey in thisSsidarray) { ++ QString thisSsid = QCFString::toQString(CFStringRef(ssidkey)); ++ if(!userProfiles.contains(thisSsid)) { ++ QMap map; ++ map.insert(thisSsid, QCFString::toQString(CFStringRef(nsInterfaceName))); ++ userProfiles.insert(thisSsid, map); ++ } ++ } ++ CFRelease(airportPlist); ++ } ++ ++ // 802.1X user profiles ++ QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist"; ++ NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile: (NSString *)QCFString::toCFStringRef(userProfilePath)] autorelease]; ++ if(eapDict != nil) { ++ NSString *profileStr= @"Profiles"; ++ NSString *nameStr = @"UserDefinedName"; ++ NSString *networkSsidStr = @"Wireless Network"; ++ for (id profileKey in eapDict) { ++ if ([profileStr isEqualToString:profileKey]) { ++ NSDictionary *itemDict = [eapDict objectForKey:profileKey]; ++ for (id itemKey in itemDict) { ++ ++ NSInteger dictSize = [itemKey count]; ++ id objects[dictSize]; ++ id keys[dictSize]; ++ ++ [itemKey getObjects:objects andKeys:keys]; ++ QString networkName; ++ QString ssid; ++ for(int i = 0; i < dictSize; i++) { ++ if([nameStr isEqualToString:keys[i]]) { ++ networkName = QCFString::toQString(CFStringRef(objects[i])); ++ } ++ if([networkSsidStr isEqualToString:keys[i]]) { ++ ssid = QCFString::toQString(CFStringRef(objects[i])); ++ } ++ if(!userProfiles.contains(networkName) ++ && !ssid.isEmpty()) { ++ QMap map; ++ map.insert(ssid, QCFString::toQString(CFStringRef(nsInterfaceName))); ++ userProfiles.insert(networkName, map); ++ } ++ } ++ } ++ } ++ } ++ } ++ } ++ [autoreleasepool release]; ++} ++ ++QString QScanThread::getSsidFromNetworkName(const QString &name) ++{ ++ QMutexLocker locker(&mutex); ++ ++ QMapIterator > i(userProfiles); ++ while (i.hasNext()) { ++ i.next(); ++ QMap map = i.value(); ++ QMapIterator ij(i.value()); ++ while (ij.hasNext()) { ++ ij.next(); ++ const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") +i.key())); ++ if(name == i.key() || name == networkNameHash) { ++ return ij.key(); ++ } ++ } ++ } ++ return QString(); ++} ++ ++QString QScanThread::getNetworkNameFromSsid(const QString &ssid) ++{ ++ QMutexLocker locker(&mutex); ++ ++ QMapIterator > i(userProfiles); ++ while (i.hasNext()) { ++ i.next(); ++ QMap map = i.value(); ++ QMapIterator ij(i.value()); ++ while (ij.hasNext()) { ++ ij.next(); ++ if(ij.key() == ssid) { ++ return i.key(); ++ } ++ } ++ } ++ return QString(); ++} ++ ++bool QScanThread::isKnownSsid(const QString &ssid) ++{ ++ QMutexLocker locker(&mutex); ++ ++ QMapIterator > i(userProfiles); ++ while (i.hasNext()) { ++ i.next(); ++ QMap map = i.value(); ++ if(map.keys().contains(ssid)) { ++ return true; ++ } ++ } ++ return false; ++} ++ ++ ++QCoreWlanEngine::QCoreWlanEngine(QObject *parent) ++: QBearerEngineImpl(parent), scanThread(0) ++{ ++ scanThread = new QScanThread(this); ++ connect(scanThread, SIGNAL(networksChanged()), ++ this, SLOT(networksChanged())); ++} ++ ++QCoreWlanEngine::~QCoreWlanEngine() ++{ ++ while (!foundConfigurations.isEmpty()) ++ delete foundConfigurations.takeFirst(); ++ [listener remove]; ++ [listener release]; ++} ++ ++void QCoreWlanEngine::initialize() ++{ ++ QMutexLocker locker(&mutex); ++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; ++ ++ if([[CWInterface supportedInterfaces] count] > 0 && !listener) { ++ listener = [[QT_MANGLE_NAMESPACE(QNSListener) alloc] init]; ++ listener.engine = this; ++ hasWifi = true; ++ } else { ++ hasWifi = false; ++ } ++ storeSession = NULL; ++ ++ startNetworkChangeLoop(); ++ [autoreleasepool release]; ++} ++ ++ ++QString QCoreWlanEngine::getInterfaceFromId(const QString &id) ++{ ++ QMutexLocker locker(&mutex); ++ ++ return scanThread->configurationInterface.value(id); ++} ++ ++bool QCoreWlanEngine::hasIdentifier(const QString &id) ++{ ++ QMutexLocker locker(&mutex); ++ ++ return scanThread->configurationInterface.contains(id); ++} ++ ++void QCoreWlanEngine::connectToId(const QString &id) ++{ ++ QMutexLocker locker(&mutex); ++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; ++ QString interfaceString = getInterfaceFromId(id); ++ ++ CWInterface *wifiInterface = ++ [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)]; ++ ++ if ([wifiInterface power]) { ++ NSError *err = nil; ++ NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0]; ++ ++ QString wantedSsid; ++ ++ QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); ++ ++ const QString idHash = QString::number(qHash(QLatin1String("corewlan:") + ptr->name)); ++ const QString idHash2 = QString::number(qHash(QLatin1String("corewlan:") + scanThread->getNetworkNameFromSsid(ptr->name))); ++ ++ bool using8021X = false; ++ if (idHash2 != id) { ++ NSArray *array = [CW8021XProfile allUser8021XProfiles]; ++ ++ for (NSUInteger i = 0; i < [array count]; ++i) { ++ const QString networkNameHashCheck = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef([[array objectAtIndex:i] userDefinedName])))); ++ ++ const QString ssidHash = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef([[array objectAtIndex:i] ssid])))); ++ ++ if (id == networkNameHashCheck || id == ssidHash) { ++ const QString thisName = scanThread->getSsidFromNetworkName(id); ++ if (thisName.isEmpty()) ++ wantedSsid = id; ++ else ++ wantedSsid = thisName; ++ ++ [params setValue: [array objectAtIndex:i] forKey:kCWAssocKey8021XProfile]; ++ using8021X = true; ++ break; ++ } ++ } ++ } ++ ++ if (!using8021X) { ++ QString wantedNetwork; ++ QMapIterator > i(scanThread->userProfiles); ++ while (i.hasNext()) { ++ i.next(); ++ wantedNetwork = i.key(); ++ const QString networkNameHash = QString::number(qHash(QLatin1String("corewlan:") + wantedNetwork)); ++ if (id == networkNameHash) { ++ wantedSsid = scanThread->getSsidFromNetworkName(wantedNetwork); ++ break; ++ } ++ } ++ } ++ NSDictionary *scanParameters = [NSDictionary dictionaryWithObjectsAndKeys: ++ [NSNumber numberWithBool:YES], kCWScanKeyMerge, ++ [NSNumber numberWithInt:kCWScanTypeFast], kCWScanKeyScanType, ++ [NSNumber numberWithInteger:100], kCWScanKeyRestTime, ++ (NSString *)QCFString::toCFStringRef(wantedSsid), kCWScanKeySSID, ++ nil]; ++ ++ NSArray *scanArray = [wifiInterface scanForNetworksWithParameters:scanParameters error:&err]; ++ ++ if(!err) { ++ for(uint row=0; row < [scanArray count]; row++ ) { ++ CWNetwork *apNetwork = [scanArray objectAtIndex:row]; ++ ++ if(wantedSsid == QCFString::toQString(CFStringRef([apNetwork ssid]))) { ++ ++ if(!using8021X) { ++ SecKeychainAttribute attributes[3]; ++ ++ NSString *account = [apNetwork ssid]; ++ NSString *keyKind = @"AirPort network password"; ++ NSString *keyName = account; ++ ++ attributes[0].tag = kSecAccountItemAttr; ++ attributes[0].data = (void *)[account UTF8String]; ++ attributes[0].length = [account length]; ++ ++ attributes[1].tag = kSecDescriptionItemAttr; ++ attributes[1].data = (void *)[keyKind UTF8String]; ++ attributes[1].length = [keyKind length]; ++ ++ attributes[2].tag = kSecLabelItemAttr; ++ attributes[2].data = (void *)[keyName UTF8String]; ++ attributes[2].length = [keyName length]; ++ ++ SecKeychainAttributeList attributeList = {3,attributes}; ++ ++ SecKeychainSearchRef searchRef; ++ SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributeList, &searchRef); ++ ++ NSString *password = @""; ++ SecKeychainItemRef searchItem; ++ ++ if (SecKeychainSearchCopyNext(searchRef, &searchItem) == noErr) { ++ UInt32 realPasswordLength; ++ SecKeychainAttribute attributesW[8]; ++ attributesW[0].tag = kSecAccountItemAttr; ++ SecKeychainAttributeList listW = {1,attributesW}; ++ char *realPassword; ++ OSStatus status = SecKeychainItemCopyContent(searchItem, NULL, &listW, &realPasswordLength,(void **)&realPassword); ++ ++ if (status == noErr) { ++ if (realPassword != NULL) { ++ ++ QByteArray pBuf; ++ pBuf.resize(realPasswordLength); ++ pBuf.prepend(realPassword); ++ pBuf.insert(realPasswordLength,'\0'); ++ ++ password = [NSString stringWithUTF8String:pBuf]; ++ } ++ SecKeychainItemFreeContent(&listW, realPassword); ++ } ++ ++ CFRelease(searchItem); ++ } else { ++ qDebug() << "SecKeychainSearchCopyNext error"; ++ } ++ [params setValue: password forKey: kCWAssocKeyPassphrase]; ++ } // end using8021X ++ ++ ++ bool result = [wifiInterface associateToNetwork: apNetwork parameters:[NSDictionary dictionaryWithDictionary:params] error:&err]; ++ ++ if(!err) { ++ if(!result) { ++ emit connectionError(id, ConnectError); ++ } else { ++ return; ++ } ++ } else { ++ qDebug() <<"associate ERROR"<< QCFString::toQString(CFStringRef([err localizedDescription ])); ++ } ++ } ++ } //end scan network ++ } else { ++ qDebug() <<"scan ERROR"<< QCFString::toQString(CFStringRef([err localizedDescription ])); ++ } ++ emit connectionError(id, InterfaceLookupError); ++ } ++ ++ locker.unlock(); ++ emit connectionError(id, InterfaceLookupError); ++ [autoreleasepool release]; ++} ++ ++void QCoreWlanEngine::disconnectFromId(const QString &id) ++{ ++ QMutexLocker locker(&mutex); ++ ++ QString interfaceString = getInterfaceFromId(id); ++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; ++ ++ CWInterface *wifiInterface = ++ [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(interfaceString)]; ++ ++ [wifiInterface disassociate]; ++ if ([[wifiInterface interfaceState]intValue] != kCWInterfaceStateInactive) { ++ locker.unlock(); ++ emit connectionError(id, DisconnectionError); ++ locker.relock(); ++ } ++ [autoreleasepool release]; ++} ++ ++void QCoreWlanEngine::requestUpdate() ++{ ++ scanThread->getUserConfigurations(); ++ doRequestUpdate(); ++} ++ ++void QCoreWlanEngine::doRequestUpdate() ++{ ++ QMutexLocker locker(&mutex); ++ ++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; ++ ++ NSArray *wifiInterfaces = [CWInterface supportedInterfaces]; ++ for (uint row = 0; row < [wifiInterfaces count]; ++row) { ++ scanThread->interfaceName = QCFString::toQString(CFStringRef([wifiInterfaces objectAtIndex:row])); ++ scanThread->start(); ++ } ++ locker.unlock(); ++ [autoreleasepool release]; ++} ++ ++bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName) ++{ ++ QMutexLocker locker(&mutex); ++ bool haswifi = false; ++ if(hasWifi) { ++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; ++ CWInterface *defaultInterface = [CWInterface interfaceWithName: (NSString *)QCFString::toCFStringRef(wifiDeviceName)]; ++ if([defaultInterface power]) { ++ haswifi = true; ++ } ++ [autoreleasepool release]; ++ } ++ return haswifi; ++} ++ ++ ++QNetworkSession::State QCoreWlanEngine::sessionStateForId(const QString &id) ++{ ++ QMutexLocker locker(&mutex); ++ QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); ++ ++ if (!ptr) ++ return QNetworkSession::Invalid; ++ ++ if (!ptr->isValid) { ++ return QNetworkSession::Invalid; ++ } else if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { ++ return QNetworkSession::Connected; ++ } else if ((ptr->state & QNetworkConfiguration::Discovered) == ++ QNetworkConfiguration::Discovered) { ++ return QNetworkSession::Disconnected; ++ } else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) { ++ return QNetworkSession::NotAvailable; ++ } else if ((ptr->state & QNetworkConfiguration::Undefined) == ++ QNetworkConfiguration::Undefined) { ++ return QNetworkSession::NotAvailable; ++ } ++ ++ return QNetworkSession::Invalid; ++} ++ ++QNetworkConfigurationManager::Capabilities QCoreWlanEngine::capabilities() const ++{ ++ return QNetworkConfigurationManager::ForcedRoaming; ++} ++ ++void QCoreWlanEngine::startNetworkChangeLoop() ++{ ++ ++ SCDynamicStoreContext dynStoreContext = { 0, this/*(void *)storeSession*/, NULL, NULL, NULL }; ++ storeSession = SCDynamicStoreCreate(NULL, ++ CFSTR("networkChangeCallback"), ++ networkChangeCallback, ++ &dynStoreContext); ++ if (!storeSession ) { ++ qWarning() << "could not open dynamic store: error:" << SCErrorString(SCError()); ++ return; ++ } ++ ++ CFMutableArrayRef notificationKeys; ++ notificationKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); ++ CFMutableArrayRef patternsArray; ++ patternsArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); ++ ++ CFStringRef storeKey; ++ storeKey = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, ++ kSCDynamicStoreDomainState, ++ kSCEntNetIPv4); ++ CFArrayAppendValue(notificationKeys, storeKey); ++ CFRelease(storeKey); ++ ++ storeKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, ++ kSCDynamicStoreDomainState, ++ kSCCompAnyRegex, ++ kSCEntNetIPv4); ++ CFArrayAppendValue(patternsArray, storeKey); ++ CFRelease(storeKey); ++ ++ if (!SCDynamicStoreSetNotificationKeys(storeSession , notificationKeys, patternsArray)) { ++ qWarning() << "register notification error:"<< SCErrorString(SCError()); ++ CFRelease(storeSession ); ++ CFRelease(notificationKeys); ++ CFRelease(patternsArray); ++ return; ++ } ++ CFRelease(notificationKeys); ++ CFRelease(patternsArray); ++ ++ runloopSource = SCDynamicStoreCreateRunLoopSource(NULL, storeSession , 0); ++ if (!runloopSource) { ++ qWarning() << "runloop source error:"<< SCErrorString(SCError()); ++ CFRelease(storeSession ); ++ return; ++ } ++ ++ CFRunLoopAddSource(CFRunLoopGetCurrent(), runloopSource, kCFRunLoopDefaultMode); ++ return; ++} ++ ++QNetworkSessionPrivate *QCoreWlanEngine::createSessionBackend() ++{ ++ return new QNetworkSessionPrivateImpl; ++} ++ ++QNetworkConfigurationPrivatePointer QCoreWlanEngine::defaultConfiguration() ++{ ++ return QNetworkConfigurationPrivatePointer(); ++} ++ ++bool QCoreWlanEngine::requiresPolling() const ++{ ++ return true; ++} ++ ++void QCoreWlanEngine::networksChanged() ++{ ++ QMutexLocker locker(&mutex); ++ ++ QStringList previous = accessPointConfigurations.keys(); ++ ++ QList foundConfigurations = scanThread->getConfigurations(); ++ while (!foundConfigurations.isEmpty()) { ++ QNetworkConfigurationPrivate *cpPriv = foundConfigurations.takeFirst(); ++ ++ previous.removeAll(cpPriv->id); ++ ++ if (accessPointConfigurations.contains(cpPriv->id)) { ++ QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(cpPriv->id); ++ ++ bool changed = false; ++ ++ ptr->mutex.lock(); ++ ++ if (ptr->isValid != cpPriv->isValid) { ++ ptr->isValid = cpPriv->isValid; ++ changed = true; ++ } ++ ++ if (ptr->name != cpPriv->name) { ++ ptr->name = cpPriv->name; ++ changed = true; ++ } ++ ++ if (ptr->bearerType != cpPriv->bearerType) { ++ ptr->bearerType = cpPriv->bearerType; ++ changed = true; ++ } ++ ++ if (ptr->state != cpPriv->state) { ++ ptr->state = cpPriv->state; ++ changed = true; ++ } ++ ++ ptr->mutex.unlock(); ++ ++ if (changed) { ++ locker.unlock(); ++ emit configurationChanged(ptr); ++ locker.relock(); ++ } ++ ++ delete cpPriv; ++ } else { ++ QNetworkConfigurationPrivatePointer ptr(cpPriv); ++ ++ accessPointConfigurations.insert(ptr->id, ptr); ++ ++ locker.unlock(); ++ emit configurationAdded(ptr); ++ locker.relock(); ++ } ++ } ++ ++ while (!previous.isEmpty()) { ++ QNetworkConfigurationPrivatePointer ptr = ++ accessPointConfigurations.take(previous.takeFirst()); ++ ++ locker.unlock(); ++ emit configurationRemoved(ptr); ++ locker.relock(); ++ } ++ ++ locker.unlock(); ++ emit updateCompleted(); ++ ++} ++ ++quint64 QCoreWlanEngine::bytesWritten(const QString &id) ++{ ++ QMutexLocker locker(&mutex); ++ const QString interfaceStr = getInterfaceFromId(id); ++ return getBytes(interfaceStr,false); ++} ++ ++quint64 QCoreWlanEngine::bytesReceived(const QString &id) ++{ ++ QMutexLocker locker(&mutex); ++ const QString interfaceStr = getInterfaceFromId(id); ++ return getBytes(interfaceStr,true); ++} ++ ++quint64 QCoreWlanEngine::startTime(const QString &identifier) ++{ ++ QMutexLocker locker(&mutex); ++ NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; ++ quint64 timestamp = 0; ++ ++ NSString *filePath = @"/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist"; ++ NSDictionary* plistDict = [[[NSDictionary alloc] initWithContentsOfFile:filePath] autorelease]; ++ if(plistDict == nil) ++ return timestamp; ++ NSString *input = @"KnownNetworks"; ++ NSString *timeStampStr = @"_timeStamp"; ++ ++ NSString *ssidStr = @"SSID_STR"; ++ ++ for (id key in plistDict) { ++ if ([input isEqualToString:key]) { ++ ++ NSDictionary *knownNetworksDict = [plistDict objectForKey:key]; ++ if(knownNetworksDict == nil) ++ return timestamp; ++ for (id networkKey in knownNetworksDict) { ++ bool isFound = false; ++ NSDictionary *itemDict = [knownNetworksDict objectForKey:networkKey]; ++ if(itemDict == nil) ++ return timestamp; ++ NSInteger dictSize = [itemDict count]; ++ id objects[dictSize]; ++ id keys[dictSize]; ++ ++ [itemDict getObjects:objects andKeys:keys]; ++ bool ok = false; ++ for(int i = 0; i < dictSize; i++) { ++ if([ssidStr isEqualToString:keys[i]]) { ++ const QString ident = QString::number(qHash(QLatin1String("corewlan:") + QCFString::toQString(CFStringRef(objects[i])))); ++ if(ident == identifier) { ++ ok = true; ++ } ++ } ++ if(ok && [timeStampStr isEqualToString:keys[i]]) { ++ timestamp = (quint64)[objects[i] timeIntervalSince1970]; ++ isFound = true; ++ break; ++ } ++ } ++ if(isFound) ++ break; ++ } ++ } ++ } ++ [autoreleasepool release]; ++ return timestamp; ++} ++ ++quint64 QCoreWlanEngine::getBytes(const QString &interfaceName, bool b) ++{ ++ struct ifaddrs *ifAddressList, *ifAddress; ++ struct if_data *if_data; ++ ++ quint64 bytes = 0; ++ ifAddressList = nil; ++ if(getifaddrs(&ifAddressList) == 0) { ++ for(ifAddress = ifAddressList; ifAddress; ifAddress = ifAddress->ifa_next) { ++ if(interfaceName == ifAddress->ifa_name) { ++ if_data = (struct if_data*)ifAddress->ifa_data; ++ if(b) { ++ bytes = if_data->ifi_ibytes; ++ break; ++ } else { ++ bytes = if_data->ifi_obytes; ++ break; ++ } ++ } ++ } ++ freeifaddrs(ifAddressList); ++ } ++ return bytes; ++} ++ ++QT_END_NAMESPACE -- cgit v0.10.1 From 8c060691d732c95ca5868a26334a1c0381e0f586 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Thu, 5 Dec 2013 12:21:10 -0500 Subject: Update Mac deployment target to make it build on 10.9, apply Qt4 patches diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh index 19c9709..d4ca1f7 100755 --- a/scripts/macosx-build-dependencies.sh +++ b/scripts/macosx-build-dependencies.sh @@ -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 -- cgit v0.10.1 From 38a342215970396a5590281cd66d0ca9c9ab7e98 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Fri, 6 Dec 2013 00:39:21 -0500 Subject: #559 fixes for 10.9 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0477a45..b84775b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -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) @@ -14,9 +14,16 @@ include(CMakeParseArguments.cmake) # Detect Lion and force gcc IF (APPLE) + # 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) 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++") + 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") -- cgit v0.10.1 From e3317ecc64659ae8be2a7b02d4df17dad6d875db Mon Sep 17 00:00:00 2001 From: "David Eccles (gringer)" Date: Fri, 6 Dec 2013 13:14:09 +1300 Subject: Fail if any polygon points for rotate_extrude are less than 0 diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc index bc9206f..e5eba2b 100644 --- a/src/PolySetCGALEvaluator.cc +++ b/src/PolySetCGALEvaluator.cc @@ -457,7 +457,13 @@ 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"); + PRINT((boost::format("[Point %d on path %d has X coordinate %f]") % j % i % point_x).str()); + return NULL; + } + max_x = fmax(max_x, point_x); } int fragments = get_fragments_from_r(max_x, node.fn, node.fs, node.fa); -- cgit v0.10.1 From ede5c4b6882692dc28fc7017c4aeb87ec9222f8e Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Fri, 6 Dec 2013 00:52:51 -0500 Subject: delete ps when short-circuiting return, no need for explicit boost::format diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc index e5eba2b..599fd7f 100644 --- a/src/PolySetCGALEvaluator.cc +++ b/src/PolySetCGALEvaluator.cc @@ -458,9 +458,10 @@ PolySet *PolySetCGALEvaluator::rotateDxfData(const RotateExtrudeNode &node, DxfD double max_x = 0; for (size_t j = 0; j < dxf.paths[i].indices.size(); j++) { double point_x = dxf.points[dxf.paths[i].indices[j]][0]; - if(point_x < 0){ + if (point_x < 0) { PRINT("ERROR: all points for rotate_extrude() must have non-negative X coordinates"); - PRINT((boost::format("[Point %d on path %d has X coordinate %f]") % j % i % point_x).str()); + 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); -- cgit v0.10.1 From 40ae8c7b343fc5dafc8c9bdc7d8a63f6e8032fca Mon Sep 17 00:00:00 2001 From: a-e-m Date: Sat, 7 Dec 2013 14:38:22 -0800 Subject: Add html report upload to test_pretty_print.py, removed wiki support diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py index a31b1a8..c26b919 100755 --- a/tests/test_pretty_print.py +++ b/tests/test_pretty_print.py @@ -25,544 +25,428 @@ # 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 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 - -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 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 '' - + 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 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 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:(.*?)", - '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:(.*?)", + '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 = """ -

    [[WIKI_ROOTPATH]] test run report

    - -'''Sysid''': SYSID - -'''Result summary''': NUMPASSED / NUMTESTS tests passed ( PERCENTPASSED % )
    - -'''System info''': -
    -SYSINFO
    -
    - -start time: STARTDATE
    -end time : ENDDATE
    - -'''Image tests''' - - -{| border=1 cellspacing=0 cellpadding=1 -|- -| colspan=2 | FTESTNAME -|- -| Expected image || Actual image -|- -| [[File:EXPECTEDFILE|250px]] || ACTUALFILE_WIKI -|} - -
    -TESTLOG
    -
    - - - -
    - - -'''Text tests''' - - -{|border=1 cellspacing=0 cellpadding=1 -|- -| FTESTNAME -|} - -
    -TESTLOG
    -
    - - -
    - -'''build.make and flags.make''' - -*[[MAKEFILE_NAME]] - -""" - 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('(.*?)',s) - repeat2 = ezsearch('(.*?)',s) - repeat3 = ezsearch('(.*?)',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('\n','',s) - s = re.sub('','',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
    \n'+makefiles[mf]+'\n
    ' - - 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 = '' - tail = '' - - 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

    ' - s+= '\nSystem info\n' - s+= '\n

    ' - s+= '

    '+sysinfo+'
    \n' - - s+= '\n
    '
    -	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
    ' - - if not include_passed: - s+= '

    Failed tests:

    \n' - - if len(tests_to_report)==0: - s+= '

    none

    ' - - for t in tests_to_report: - if t.type in ('txt', 'ast', 'csg', 'term', 'echo'): - s+='\n
    '+t.fullname+'
    \n' - s+='

    '+t.fulltestlog+'
    \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 = ' - # imatag_a = ' - imgtag_e = png_encode64( t.expectedfile, 250 ) - imgtag_a = png_encode64( t.actualfile, 250 ) - s+='' - s+='\n' - s+='\n ' - s+='\n
    '+t.fullname - s+='\n
    ExpectedActual' - s+='\n
    ' + imgtag_e + '' + imgtag_a + '
    ' - s+='\n
    '
    -			s+=t.fulltestlog
    -			s+='\n
    ' - else: - raise Exception("Unknown test type %r"%t.type) - - s+='\n\n

    \n\n' - - s+= '

    CMake .build files

    \n' - s+= '\n
    '
    -	makefiles_wikinames = {}
    -	for mf in sorted(makefiles.keys()):
    -		mfname = mf.strip().lstrip(os.path.sep)
    -		text = open(os.path.join(builddir,mfname)).read()
    -		s+= '

    '+mfname+'

    '
    -		s+= text
    -		tmp = mf.replace('CMakeFiles','').replace('.dir','')
    -		wikiname = wikify_filename(tmp,wiki_rootpath,sysid)
    -		# s += '\n'+wikiname+'
    ' - s+= '\n
    ' - 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' + 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 = '''''' + if data == '': + alt = 'alt="error: no image generated" ' + else: + alt = 'alt="openscad_test_image" ' + tag %= (data_uri, width, alt) + return tag + 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 = ''' + Test run for {sysid} + {style} + + +

    {project_name} test run report

    +

    + Sysid: {sysid} +

    +

    + Result summary: {numpassed} / {numtests} tests passed ({percent}%) +

    + +

    System info

    +
    {sysinfo}
    + +

    start time: {startdate}

    +

    end time: {enddate}

    + +

    Image tests

    + {image_tests} + +

    Text tests

    + {text_tests} + +

    build.make and flags.make

    + {makefiles} + ''' + + style = ''' + ''' + + image_template = ''' + + + + + +
    {test_name}
    Expected image Actual image
    {expected} {actual}
    + +
    +    {test_log}
    +    
    + ''' + + text_template = ''' + {test_name} + +
    +    {test_log}
    +    
    + ''' + + makefile_template = ''' +

    {name}

    +
    +        {text}
    +    
    + ''' + + 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[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 +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 - - wikisite = 'cakebaby.wikia.com' - wiki_api_path = '/' - wiki_rootpath = 'OpenSCAD' - if '--debug' in string.join(sys.argv): debug_test_pp=True - maxretry = 10 - - if bool(os.getenv("TEST_GENERATE")): sys.exit(0) - - include_passed = False - if '--include-passed' in sys.argv: include_passed = True - - 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 ) - - 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' - - 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]) - - 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 '--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' ) + 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 + + include_passed = False + if '--include-passed' in sys.argv: + include_passed = True + + dry = False + debug('running test_pretty_print') + if '--dryrun' in sys.argv: + dry = 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) + + # --- End Command Line Parsing --- + + sysinfo, sysid = read_sysinfo(os.path.join(builddir, 'sysinfo.txt')) + makefiles = load_makefiles(builddir) + logfilename = findlogfile(builddir) + testlog = tryread(logfilename) + startdate, tests, enddate = parselog(testlog) + if debug_test_pp: + print 'found sysinfo.txt,', + print 'found', len(makefiles),'makefiles,', + print 'found', len(tests),'test results' + + html = to_html(project_name, startdate, tests, enddate, sysinfo, sysid, makefiles) + html_basename = sysid + '_report.html' + html_filename = os.path.join(builddir, 'Testing', 'Temporary', html_basename) + debug('saving ' + html_filename + ' ' + str(len(htmldata)) + ' bytes') + trysave(html_filename, html) + + page_url = create_page() + if upload_html(page_url, title='OpenSCAD test results', html=html): + share_url = page_url.partition('?')[0] + print 'html report uploaded at', share_url + else: + print 'could not upload html report' + + debug('test_pretty_print complete') if __name__=='__main__': - main() + main() -- cgit v0.10.1 From 8d3365a79ab7afd287545da3f8b2ba12f0c43585 Mon Sep 17 00:00:00 2001 From: a-e-m Date: Sat, 7 Dec 2013 14:50:49 -0800 Subject: Update design philosopy comments diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py index c26b919..44df156 100755 --- a/tests/test_pretty_print.py +++ b/tests/test_pretty_print.py @@ -17,11 +17,9 @@ # Design philosophy # # 1. parse the data (images, logs) into easy-to-use data structures -# 2. wikifiy the data -# 3. save the wikified data to disk -# 4. generate html, including base64 encoding of images -# 5. save html file -# 6. upload html to public site and share with others +# 2. generate html, including base64 encoding of images +# 3. save html file +# 4. upload html to public site and share with others # todo # -- cgit v0.10.1 From 8a21092dc01dfe54550b8fceada35999bed3056b Mon Sep 17 00:00:00 2001 From: a-e-m Date: Sat, 7 Dec 2013 17:59:07 -0800 Subject: Adding imports diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py index 44df156..c2deab8 100755 --- a/tests/test_pretty_print.py +++ b/tests/test_pretty_print.py @@ -33,6 +33,13 @@ import hashlib import subprocess import time import platform +try: + from urllib.request import urlopen + from urllib.parse import urlencode +except ImportError: + from urllib2 import urlopen + from urllib import urlencode + def tryread(filename): data = None -- cgit v0.10.1 From b131464f954b2d10f6b065b45038652af2379742 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Sun, 8 Dec 2013 13:50:03 -0500 Subject: #559 CMAKE_OSX_DEPLOYMENT_TARGET needs to be cached diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b84775b..f92eddf 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -14,14 +14,14 @@ include(CMakeParseArguments.cmake) # Detect Lion and force gcc IF (APPLE) - # 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) EXECUTE_PROCESS(COMMAND sw_vers -productVersion OUTPUT_VARIABLE MACOSX_VERSION) 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") -- cgit v0.10.1 From cb2b094b269646c79f48f525306b74cd7bc0f633 Mon Sep 17 00:00:00 2001 From: a-e-m Date: Sun, 8 Dec 2013 10:51:25 -0800 Subject: Fixed small error in Templates.get diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py index c2deab8..349a730 100755 --- a/tests/test_pretty_print.py +++ b/tests/test_pretty_print.py @@ -304,10 +304,10 @@ class Templates(object): def add(self, template, var, *args, **kwargs): self.filled[var] = self.filled.get(var, '') + self.fill(template, *args, **kwargs) - return self.filled[var] + return self.get(var) def get(self, var): - return self.filled[var] + return self.filled.get(var, '') def to_html(project_name, startdate, tests, enddate, sysinfo, sysid, makefiles): -- cgit v0.10.1 From 8971c67fa209fe29ead54034cd0f9be39c0909ff Mon Sep 17 00:00:00 2001 From: a-e-m Date: Sun, 8 Dec 2013 11:18:58 -0800 Subject: Fixed variable name error diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py index 349a730..359165e 100755 --- a/tests/test_pretty_print.py +++ b/tests/test_pretty_print.py @@ -441,7 +441,7 @@ def main(): 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(htmldata)) + ' bytes') + debug('saving ' + html_filename + ' ' + str(len(html)) + ' bytes') trysave(html_filename, html) page_url = create_page() -- cgit v0.10.1 From a22ebd608d941b5ae1767a2903f4bacc925840ed Mon Sep 17 00:00:00 2001 From: a-e-m Date: Sun, 8 Dec 2013 11:28:19 -0800 Subject: Moved include_passed diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py index 359165e..c3035c5 100755 --- a/tests/test_pretty_print.py +++ b/tests/test_pretty_print.py @@ -395,6 +395,7 @@ def debug(x): print 'test_pretty_print: ' + x debug_test_pp = False +include_passed = False builddir = os.getcwd() def main(): @@ -411,7 +412,6 @@ def main(): debug_test_pp = True maxretry = 10 - include_passed = False if '--include-passed' in sys.argv: include_passed = True -- cgit v0.10.1 From e27f971d9c3dc26a9a023a2aea4c265dac53437b Mon Sep 17 00:00:00 2001 From: a-e-m Date: Sun, 8 Dec 2013 12:15:04 -0800 Subject: Changed upload code to use gists diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py index c3035c5..a88a22e 100755 --- a/tests/test_pretty_print.py +++ b/tests/test_pretty_print.py @@ -17,9 +17,11 @@ # Design philosophy # # 1. parse the data (images, logs) into easy-to-use data structures -# 2. generate html, including base64 encoding of images -# 3. save html file -# 4. upload html to public site and share with others +# 2. wikifiy the data +# 3. save the wikified data to disk +# 4. generate html, including base64 encoding of images +# 5. save html file +# 6. upload html to public site and share with others # todo # @@ -34,12 +36,12 @@ import subprocess import time import platform try: - from urllib.request import urlopen - from urllib.parse import urlencode -except ImportError: - from urllib2 import urlopen - from urllib import urlencode - + from urllib.request import urlopen, Request +except: + from urllib2 import urlopen, Request +import json +import base64 + def tryread(filename): data = None @@ -304,7 +306,7 @@ class Templates(object): def add(self, template, var, *args, **kwargs): self.filled[var] = self.filled.get(var, '') + self.fill(template, *args, **kwargs) - return self.get(var) + return self.filled[var] def get(self, var): return self.filled.get(var, '') @@ -361,32 +363,46 @@ def to_html(project_name, startdate, tests, enddate, sysinfo, sysid, makefiles): # --- Web Upload --- -def postify(data): - return urlencode(data).encode() - -def create_page(): - data = { - 'action': 'create', - 'type': 'html' - } +API_URL = 'https://api.github.com/%s' +# Username is personal access token, from https://github.com/settings/applications +# This way, no password is needed +USERNAME = 'b2af28787fb1efd9a5b3a3b4f1be8a3ac9b5b335' +PASSWORD = '' + +def make_auth(username, password): + auth = '%s:%s' % (USERNAME, PASSWORD) + return base64.b64encode(auth.encode()) + +def post_gist(name, content): + gist = '''{ + "description": "", + "public": true, + "files": { + "%s": { + "content": "%s" + } + } + }''' + gist = gist % (name, content) + + req = Request(API_URL % 'gists') + req.add_header('Authorization', b'Basic ' + make_auth(USERNAME, PASSWORD)) try: - response = urlopen('http://www.dinkypage.com', data=postify(data)) + result = urlopen(req, data=gist) except: + print 'Could not upload results' 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() + return json.loads(result.read()) + + +def get_raw_urls(result): + files = result.get('files', {}) + for file in files: + yield files[file].get('raw_url').replace('gist.github.com', 'rawgithub.com') + +result = post_gist('aaabbb.html', '''

    I\'m asdf

    ''') +for url in get_raw_urls(result): + print(url) # --- End Web Upload --- @@ -438,18 +454,20 @@ def main(): print 'found', len(makefiles),'makefiles,', print 'found', len(tests),'test results' + html = to_html(project_name, startdate, tests, enddate, sysinfo, sysid, makefiles) html_basename = sysid + '_report.html' html_filename = os.path.join(builddir, 'Testing', 'Temporary', html_basename) debug('saving ' + html_filename + ' ' + str(len(html)) + ' bytes') trysave(html_filename, html) - 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: + result = post_gist(name=html_basename, content=html) + if result is None: print 'could not upload html report' + return + + for url in get_raw_urls(result): + print 'html report uploaded at', url debug('test_pretty_print complete') -- cgit v0.10.1 From 88cc7edafd47ec167609c05eb22c3f8eb642d225 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Sun, 8 Dec 2013 15:16:58 -0500 Subject: #559 Fix Qt font rendering on OS X 10.9 diff --git a/patches/qt4/patch-qeventdispatcher.diff b/patches/qt4/patch-qeventdispatcher.diff new file mode 100644 index 0000000..89ed478 --- /dev/null +++ b/patches/qt4/patch-qeventdispatcher.diff @@ -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 cocoaModalSessionStack; ++ static QStack 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 QEventDispatcherMacPrivate::cocoaModalSessionStack; ++QStack 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(); diff --git a/patches/qt4/patch-qfontdatabase.diff b/patches/qt4/patch-qfontdatabase.diff new file mode 100644 index 0000000..c078890 --- /dev/null +++ b/patches/qt4/patch-qfontdatabase.diff @@ -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 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 ctFont = CTFontCreateWithName(QCFString(db->families[k]->name), 12, NULL); ++ QCFType ctFont = CTFontCreateWithName(QCFString(db->families[k]->postscriptName), 12, NULL); + if (ctFont) { + fontName = CTFontCopyFullName(ctFont); + goto found; -- cgit v0.10.1 From eb046015d2fd4fa3e4e3c8844cd6dc8f4d3eca99 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Sun, 8 Dec 2013 15:17:17 -0500 Subject: #559 Fix Qt font rendering on OS X 10.9 diff --git a/src/openscad.cc b/src/openscad.cc index ece6818..ab84235 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -474,6 +474,13 @@ bool QtUseGUI() int gui(vector &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)); -- cgit v0.10.1 From d6bffc4691cf1467cf93d527724f7278b418273d Mon Sep 17 00:00:00 2001 From: a-e-m Date: Sun, 8 Dec 2013 12:17:19 -0800 Subject: Taking out test accidentially left in, my user token diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py index a88a22e..b601c84 100755 --- a/tests/test_pretty_print.py +++ b/tests/test_pretty_print.py @@ -366,7 +366,7 @@ def to_html(project_name, startdate, tests, enddate, sysinfo, sysid, makefiles): API_URL = 'https://api.github.com/%s' # Username is personal access token, from https://github.com/settings/applications # This way, no password is needed -USERNAME = 'b2af28787fb1efd9a5b3a3b4f1be8a3ac9b5b335' +USERNAME = '' # add OpenScad user token PASSWORD = '' def make_auth(username, password): @@ -400,9 +400,6 @@ def get_raw_urls(result): for file in files: yield files[file].get('raw_url').replace('gist.github.com', 'rawgithub.com') -result = post_gist('aaabbb.html', '''

    I\'m asdf

    ''') -for url in get_raw_urls(result): - print(url) # --- End Web Upload --- -- cgit v0.10.1 From b7c818bf00b5c9e23ee97ce6669eb66a9b404562 Mon Sep 17 00:00:00 2001 From: a-e-m Date: Sun, 8 Dec 2013 16:15:50 -0800 Subject: Revert to uploading to dinkypage, gists won't work diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py index b601c84..675867e 100755 --- a/tests/test_pretty_print.py +++ b/tests/test_pretty_print.py @@ -36,12 +36,11 @@ import subprocess import time import platform try: - from urllib.request import urlopen, Request + from urllib.request import urlopen + from urllib.parse import urlencode except: - from urllib2 import urlopen, Request -import json -import base64 - + from urllib2 import urlopen + from urllib import urlencode def tryread(filename): data = None @@ -363,43 +362,32 @@ def to_html(project_name, startdate, tests, enddate, sysinfo, sysid, makefiles): # --- Web Upload --- -API_URL = 'https://api.github.com/%s' -# Username is personal access token, from https://github.com/settings/applications -# This way, no password is needed -USERNAME = '' # add OpenScad user token -PASSWORD = '' - -def make_auth(username, password): - auth = '%s:%s' % (USERNAME, PASSWORD) - return base64.b64encode(auth.encode()) - -def post_gist(name, content): - gist = '''{ - "description": "", - "public": true, - "files": { - "%s": { - "content": "%s" - } - } - }''' - gist = gist % (name, content) - - req = Request(API_URL % 'gists') - req.add_header('Authorization', b'Basic ' + make_auth(USERNAME, PASSWORD)) +def postify(data): + return urlencode(data).encode() + +def create_page(): + data = { + 'action': 'create', + 'type': 'html' + } try: - result = urlopen(req, data=gist) + response = urlopen('http://www.dinkypage.com', data=postify(data)) except: - print 'Could not upload results' return None - return json.loads(result.read()) - - -def get_raw_urls(result): - files = result.get('files', {}) - for file in files: - yield files[file].get('raw_url').replace('gist.github.com', 'rawgithub.com') - + 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 --- @@ -458,13 +446,12 @@ def main(): debug('saving ' + html_filename + ' ' + str(len(html)) + ' bytes') trysave(html_filename, html) - result = post_gist(name=html_basename, content=html) - if result is None: + 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' - return - - for url in get_raw_urls(result): - print 'html report uploaded at', url debug('test_pretty_print complete') -- cgit v0.10.1 From 58bf7386a11d6f6fb247cf95b89bbbb2682832ca Mon Sep 17 00:00:00 2001 From: a-e-m Date: Sun, 8 Dec 2013 16:32:36 -0800 Subject: Added --upload command line option diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py index 675867e..c0d35bb 100755 --- a/tests/test_pretty_print.py +++ b/tests/test_pretty_print.py @@ -426,6 +426,11 @@ def main(): if not 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 --- @@ -446,12 +451,13 @@ def main(): debug('saving ' + html_filename + ' ' + str(len(html)) + ' bytes') trysave(html_filename, html) - 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 upload: + page_url = create_page() + if upload_html(page_url, title='OpenSCAD test results', html=html): + share_url = page_url.partition('?')[0] + print 'html report uploaded at', share_url + else: + print 'could not upload html report' debug('test_pretty_print complete') -- cgit v0.10.1