Merge branch 'master' into text-module

Conflicts:
	scripts/macosx-build-homebrew.sh
	scripts/mingw-x-build-dependencies.sh
	scripts/uni-build-dependencies.sh
	scripts/uni-get-dependencies.sh
	src/GeometryEvaluator.h
	src/MainWindow.ui
	src/clipper-utils.h
	src/mainwin.cc
	tests/CMakeLists.txt
master
Marius Kintel 2014-04-26 22:08:31 -04:00
commit 2cba2a1b55
276 changed files with 4427 additions and 1264 deletions

2
.gitignore vendored
View File

@ -22,3 +22,5 @@ testdata/scad/features/import_dxf-tests.scad
testdata/scad/features/import_stl-tests.scad
testdata/scad/misc/include-tests.scad
testdata/scad/misc/use-tests.scad
/mingw32
/mingw64

View File

@ -8,10 +8,57 @@ before_install:
- sudo apt-get install -qq build-essential libqt4-dev libqt4-opengl-dev libxmu-dev cmake bison flex git-core libboost-all-dev libXi-dev libmpfr-dev libboost-dev libglew-dev libeigen2-dev libeigen3-dev libcgal-dev libgmp3-dev libgmp-dev python-paramiko curl imagemagick
- sudo apt-get install -qq libopencsg-dev
env: OPENSCAD_UPLOAD_TESTS=yes
branches:
only:
- master
before_script:
- echo -e "Host files.openscad.org\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
- echo -n $openscad_rsa_{00..40} >> ~/.ssh/openscad_rsa_base64
- base64 --decode --ignore-garbage ~/.ssh/openscad_rsa_base64 > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
script: ./scripts/travis-ci.sh
env:
global:
- OPENSCAD_UPLOAD_TESTS=yes
- secure: "mBWdnkXe8BL1SqYRBnOOpXn60xtHGfpeVOh+HrK8xZPflLyJLdgAz3jsrgPaaMibfuygOEfn86jm8dFZPDJSeGh+gGbcjbtOywvYtr0d/KJPk2ccCavlGEBsTSdfWVBMH2hqZ+OXrSn4amx12fmcF/rnpRZu0jHxRWrL4SbouXM="
- secure: "gYPUvQekTxYW4bNIDvL6MFdPihd0HFGIq2saEbcOVyGYuZTdyBIzoh3tLIdG6jJNLWb/Nn2iWEsbsSsSIVk9UowW2qmuKVmzOyezKiu7wO2bdk08zeNtZLdFU4f8NsPz/ODXGQBCbjrBr8csnczQ9DKcxQeG2Lr9z1PjpJE43zY="
- secure: "N4tu1zJPq4tDrfArXawiQZ/oAb3jZ1xEonxH2WWMnUXj6CGMSrRbkUD7h7Yx5WcIgxkDE87Q+mMgKDNDhDQuK4RiTngwokXKSCHYn0odo10o1SWiNE42czLpbCTWJeM/5m+nyPhE1Hn8StTwiwqiA2YkBUICh/z+s6cmqV5JaEU="
- secure: "hfkGLUH90vkYIIQlBjAlYRxl/KJE/d5Z8cGnXGN77+RuvmGN2vMspSTXdvIe7KXesLs3ly96iA/mx3LLzW4YQu1qlwaAtffXiX2GBUFgRAHQV4Ty6PJzwRjzTxqZTh2jE+lZukB/6oh0ZlF4lpFYRFIMwLQMP64gGN0aqdQwc0I="
- secure: "UBH3ATAhykSH4su70oG6vmnOfV62ghNDLO/Y5dZwZvZVkKdERdddtpP8tPmJrkeqZp6nZs2DPA1ufgifaShZgv5eo5U1pdg4zFRA8UuOlK51QWdPYdk4/kTbifqeKhiQlNpvMXGnRPfk0a2HdAiaAHk0FKIPBRPAgwJlE03zKf4="
- secure: "YAMu566rDdaAHflMlvBdwkb7F4DNoDa6nJ1/d0bbaPDDk2onxzt5Nos9P3LMMya9XDo/+/8XZWUhdU2t8fwKfKiAanaIPiDYFaS7gZDohu7TI41rqJnnHFF1KNtG624PbABIgKBu8AEHsF1op7EG31SD8ZFyYTBdFOlgVruNWEA="
- secure: "cLVNa1aAtGyO7nHumphZRcNmMnFp+Ts4Bqh6WlclZ3RljEp5rKqHP3knHVgE6T0jC6zMTdNDwKHkyW2jlETRa0l7SGblZI1iuAATnNMwH14FPJgfHP2g30dYu714J6ik6UWUyFNex6o5ZlrVnTnrTuQpTQmF/Ehb4xBcFh780S8="
- secure: "VXa5G1ow1YND0Ap7jTH6oewSlgE3bQz0ZRKPz/bMEQhmImitAW24LG+kLi1RWfvtwJdHBOExlwh/yGpe508WXLF5F/Hv9LKTeAFixUSpFXt1Llsx1/LuApy7i4bq9nmx30Of5GiFvUARTr0wa1a3BbH5E0Sj963vVLwy+FZDiS8="
- secure: "K9pzYAsFc9rvFVz12Y80uFpruH7R5tJpurtGxQJpgSRCr4kRlJO+ODt4/Voq7lzFCiMuhbBiE0G4f8SzylyyiyJaZshAxqRBteEdDEMEnx1ND4FbqDnB9apWnWRoY1AbqBx1ckEy3jCvw1Tn9bRvvvcnOI6qXFxLpTJMP3eY6R4="
- secure: "Oa/blQENesTANzJbqzdQPQ1Hg99DaUVCekms1xkymLBUCSzqPL44KVdz3cxVGYBl/Om7mBwENEQ9BOUI6vGq+CZ7aaTYrYfEUokgvhGUgku0iLjxpHrIH04TH4XwpDXRg/iLwdQZO3d+xq7Q4XTBLOEyHVdzn5uDGP+cNoW9NbM="
- secure: "L3vKi+0gahSm8DF2GGp98FPhuWtUlqRRpCXjAUsSVNCPtru01tI4i6Kls7yqq2L+31FtkyWqBIlm1S1OZw8uiPyis3eUDqMRgASs4tOx/q2Xj2TEK8p+TKK+d3A8mct/y0e806GwdH5JIIppGSPOknPtxT92jZMrv0PnGnPAJSQ="
- secure: "fZzEs4GUtK494s63as9K72kmw0taicfouk2NDym58wHqS88UeRVjvrAkwoIGLJS6rCrh/4NkKhxPkd6JNVRVHy3KH8j2FYoIwtLStEC7YZfT25gi8EiN+O6MrTVre1WA9RT52v5gQ+a2v2YPUU6fBJAy6Xgy372PzoQrXF4iYOA="
- secure: "fNSoCKmJQUJJn4rFxsX0YXHIEtF3JCIixBkM8sCmuzOxjUPFLEjD/5D4x/t+FJfGwb1PR4194L3Tys7AK4IrpIDDXBO8vF3PYK1/evoPLPgj4IkPOReoX2zDUhxsvnEVlF3pGMK6erB6QZoDFCYD6OvqeQUxDDDuEvG8UEvNUgc="
- secure: "apJEmAnp5Ome0UJk+UEsdlVNBOX4bXE9FjBp6yYVrSeAEASFZTZbnIQXP9N8XwFc+TBa5aBlV9s7GZaieVW1/uNZg9njGUsbxPLtqpyHqJTDBgw3edcs7V12jGl+quRJoYVOtbyMQyr5VwCPzV6MmaLOoEtJM75yoSUoerkyNiI="
- secure: "AnXGOWlfhnxEuwqfnir411x/Z2Kvd/R37F8Jcv60+3dugCTLsOL/9i7rY5mwwm2ZFx4uwbCDXEC+UlW/vUhLhvdh8sCYocpghxY+WQye1cib+voqkP6Tgi1AtZL2CxBTJ2Kvyr+kNGTl0TvQC/uv3qI/D+ePijn89KFt9Z2NQEk="
- secure: "KPpkgyXr1mpbNOtxn0NAH2iS0NSy/LC6/DBoR9PBmK80LmHqhQkcB+OAwHy5q4RvRpeNIm2zg49OvV7RgzXQD3NXIy7Eik3uM6IzrcHXlDO6zPye/EAMYt/C0tJylR6ESDfp1+pEI0VyFz6pjFFs7FAX5m9UinaEJns7vucb8SA="
- secure: "Hf1TNzMMPw7msFCttHoF0V2wOFQERbGwYsZSMUac8njBXDjbsP+S/iYNkqoqJIfBjknXbn1U0RDfiDwvs/71lhV0FEoF2zPbOWitO7+ZeqpNcP2oMqnPBLCuCldKWxbsjKLwE5Qgd9KflPh49ZlnHe/cZZdzeDCIpAmHk+Ey/4U="
- secure: "cG7qndC1YAHa05QSLD8CzAZJOyJsHj4+I8OKvv+nfKFO/pQVZzKfF84v0ZVxpqdFNRRUwdH4n7zYCNAaMSoeSQmk++jyf+w8cu+x1MZ9HcnfqduuyirZR5iehmlIy1v/c1CsxAQeovDMulnFJOXGf7q7tUqB3rw/WlZZHn6Fpfc="
- secure: "NHym8MhLToBE5dlldCKTBn8NuLQg9jhjdB/9Gnn0h5j0G3x3O9yx3XbBtVSKNdvtqfGog6NG6XT2UhCYGtv59lTcWVR5tPulYkJV1vqeHfY21QeDYIESr/JOZaAIZ0RQaT/jWnoIghQNe38VMozWdwZ3ulKQ2HnzFagTbftfF5A="
- secure: "mClAXQOm9gc7UXuXpyqfNWp7JJU4n6n3pd792VK8K8ioXKVSySZLbJOFul5KY8ZLePCvdliZ0yfKqyBR7XqbzPFwH/0R3pppaI+T/0mZRi5SqcJ9KnJdf7jkTLsQI73wU25YC/T6ZHodEfANYTaP06Ex7QnY/djWsTvAH3Ga2dA="
- secure: "BdYq/BztHLp4TGExfjAxRW9Qtnpi7aizY6fyQNqOBorF6aYKNLOaaN8i7bURL7I5B+WT2vR/NFDv8Ehz096HFjnDZ8vVFn4tQQgGlxf+BcYrBOeA+AIxA9XR/yp9v6ljONasD7PQ8uDJoyUy9FOimet6T5GAOTy8LO8SRQDvxoY="
- secure: "iHb3IwbyrCKW884oVvckz7BR8F9YhLQXkEUvufc/5oKtsn/zMflHQ1+OV04q4j7B5hdu9/ur8T0q80YysJL8btHT0vnR7kx/uDx/S8tqXlMMb0Tr1JUGLFIHBZWRPUCayXTcBk06BrYRA1wB8cLQnLxqI4OfgMAN+rOv60CGR8k="
- secure: "XzK4KXCtcu5B1Flyiq9jl7hxnsUXXTYcmSq7bmIM4g8dsRz6EdDWrSBJUIstKCLckmoeQcfyCyXYjy2dvGgv7FX+Hu1nNGCZGy/rOIaciiinHf9mQZVTTwUZv1gGPZo2jdue15NvvCLwJt/N6SSZYor8fRyPyuVnK8/PBj4jcao="
- secure: "YFEbESe4qlFKXsgYgST3Z9NRMyNEj2oVYEzgcB+dWsVnfDufhtjUhQ+AGw+vsbYg2g2TIQzyVSWMG+mQo41SX4bLFH0Rwgial4ZnpWP7NHrkCgjIeeZRP/f81KIdGnCyabatOkJPQQ5qS0cZVRpQaXq8Zsxk+aDmYc2kZwWA3xc="
- secure: "Tv1OUgeQDBPwnL5GsEBiKjr1HdMrvsedk5I6ckbpBa6S1dKCzirOJRRHr9ZP4/TiZYEBd84nQZ5fKTIrCxU18CQzrs/gsS2hHyN+Nr8cpWpa6IovKOpMKxCYryLJFpX69cihcOVzp1xQq+a7sZq/yhZJmKaUBFlZchyPtJ1ysmg="
- secure: "iYz1GPvgcYpue6CKaW/O8iEolwC0UFztsZWzJZyrpZGrsw0fZbqpcn9ACEc+LQKYmvTo3hdBj9ewZB4+Bj4VMVIjgTlYsP0rYESsPd7njgpll+WfslRd5WNJLioUiPeb29yC4woiGa+/YHy2ACJI+ix7F6NyHk+2ri0MCOa4BnQ="
- secure: "Xwco3s7JM7hsAuDrAKuaYBjMccNTKWCXsoE48kQsKGlBM/iQ849nGTmImIKvdh0tZG5LDXgc04rbldhnpvMfWmty0hrQZuwjPaHBqHQ7zWXeNl3/CpAIGTBsefO7hTRoT2+xw1I6f4n8a5U7FICaGmWkR/MvykPOJyR+ms/hOQM="
- secure: "lNW2JDlel5MC9kwRu9lvNPWdlkbhAmkLo/YovVsrKyXPZfETWZO6IU2dDfKQvetIB2zQQnplbozdyiRBMywBnAk27FqLRAjbBqlKTC1jPlU4W29SBCMf+kJlVcQHvh0feeJChBZrVb2GQIAiHEkloDFX03E7RhOPAE5GqzvYow0="
- secure: "ZCfE5sS+70M4MVDOxVMlYcge7LewYbHIm0DE7QFfkwJ9sobaVr+uQMWe+9bA3DhxhdvQQ9p6lGE36ST+WYWopO7SHW6Ly+WvH1kM1nOZfY4w5R+BlAJ9QPcudnPUuFMOBXM0Wm8XccPuld2D5Jg7SalmS1F6mdArXsuL55CXxco="
- secure: "G4MDFYa3BbzqUGMfrABOjEjIa/pXHR8/jgOIQxY3FK2/0bYr//2YU/bw1gJBPQc8Ef243LzhTKvfFhntTecSfH2pS0Ezm2HWwtaF+lBg/A5bYCJX5Tek6HAOv1+aajTRZAjjj4X28T0NCqJI6u1WvbHwYFmW8wsfZtYZKB8JFuo="
- secure: "Py01+IBxGWKG7lyV10bZPYnqvLxNNBE+L6i1hvvvQmx078LfKtVr3tdDSZJVjf3H+gMXW0qnEhBYWJlzKPO5zCMhX314s43yxW3a5N+QZ74ucCO0Yvc4JXA8y7+g4lgsihJmzLSGQZziT+xnn0Q4iNpB8G0kXcl7zVT/ZsLFooQ="
- secure: "lkkLCzuHhR1Z3zzV/8me/PbzMConA8kdxUQ6mQb4VZE8h3wsRDh9P8yKciluV/ZVgqZtLG8VbVnLHgVzzu2zDTqf1t/Gsb5u8Rq5w/sTZyqMpB9qpRjHmq+uPds+ScvAplyoPH4oskXS8xQ8G1ykJwPBbRETyZzAU2/JoOgWiOs="
- secure: "KQlczojVt3jfMtsnl1GFiKsCxkPOaIr95MxopGYqqOVxzRDeNvtJcA/xQU1ouibJlx9B/EHZx0K+/DIk6dyr+irAVzgPGdT5pRxmjSREONPDaGEj9f4D6GWS3AtUJW2AqTMdtI3+d6o7oaYFGGXTCeW+qFMcsxEpn3eT1HMJs1A="
- secure: "XeqXuqqHPAW6/5WukY8y3n1PmaP7ASuNvMTd/Xv3sXzcci11ZKWNEOQDxZeRUwuEot4v2WG+m4HuvIqGWbz6mi8+4OaWUynLRitlGWj7JBu1igN9awmOw+HOcM32v2UcxUdsUSB5AdEOs7hafjodbshxrWQbo05ruk6Au4+jrd4="
- secure: "Ej8RRGUT95llMPDUtbx/lF7D9bKGxTCGdKZbTKFdIPjUzTJgE0pm89vIxKvq7y//oMCposX5DjcVolF+dS2Ya2031MTUto3mUwFq+sx3t2knWt812mQ6p2Ow/l6/uOlr2FHxUJKOxPeWqLRB6NYd9YnUiC3OJNlERr8nyHkCx4c="
- secure: "JsOTX5JsRAY3zyKa/5yYkd48Nejt9CAEraXVpN1NDW25jJmsOynyW5d2WYazJ1H0x1oR6Fhc4gstNxaj1MNh/gVM9O3UM2tyFnSxDY6fZnEGWaf17ln4dqi3KHXWU7h2Gdg1ah19NS0nWytooW6VcEXmk+cYSheTqyfc5gK7Sdo="
- secure: "mMc9MyopIjvzpDg3eN6owSmr2PI58JiPnlLhMNvOWW9axUzup5tthfqM+tvR/AqdLQSSMUC9JXwwQK0d543Q4YyoQ0jwVY2RT56VdEywxD5+yWRfXD+ANlJhdQWmlPVc3KsavKYmfQPBLbwe0nyhtQTWGeAgKTYvYT+k1/PD4rg="
- secure: "X7KDSiSOR3XcePJgTXNzwE1wU285yFsxB7crMLskD08wU8xdRqS8NL+1++/Lju6pypOkospI2AYH1JAJ7JK3Sx5QYM4MxgRJcrMHiTMirN3cm3KzkWUuv3iEZNJ7q6ANi5oFfHh3k0D4JhCEnA1ICTDPdq+r9+mOvgkrly8V0Dw="

View File

@ -1,4 +1,4 @@
![Travis CI](https://api.travis-ci.org/openscad/openscad.png)
[![Travis CI](https://api.travis-ci.org/openscad/openscad.png)](https://travis-ci.org/openscad/openscad)
# What is OpenSCAD?
[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=openscad&url=http://openscad.org&title=OpenSCAD&language=&tags=github&category=software)
@ -89,9 +89,9 @@ Follow the instructions for the platform you're compiling on below.
* [Qt4 (4.4 - 4.8)](http://www.qt.nokia.com/)
* [CGAL (3.6 - 4.1)](http://www.cgal.org/)
* [GMP (5.x)](http://www.gmplib.org/)
* [cmake (2.8, required by CGAL and the test framework)](http://www.cmake.org/)
* [MPFR (3.x)](http://www.mpfr.org/)
* [boost (1.35 - 1.53)](http://www.boost.org/)
* [cmake (2.8, required by CGAL and the test framework)](http://www.cmake.org/)
* [boost (1.35 - 1.55)](http://www.boost.org/)
* [OpenCSG (1.3.2)](http://www.opencsg.org/)
* [GLEW (1.5.4 ->)](http://glew.sourceforge.net/)
* [Eigen (3.0 - 3.2)](http://eigen.tuxfamily.org/)
@ -153,7 +153,7 @@ the dependency packages listed above using your system's package
manager. A convenience script is provided that can help with this
process on some systems:
./scripts/uni-get-dependencies.sh
sudo ./scripts/uni-get-dependencies.sh
After installing dependencies, check their versions. You can run this
script to help you:
@ -177,17 +177,9 @@ Then run the script to compile all the prerequisite libraries above:
./scripts/uni-build-dependencies.sh
This may take an hour or more, depending on your network and system. It
is recommended to have at least 1 gigabyte of free disk space. As a
special timesaver if you are only missing CGAL and OpenCSG, you can do
this instead:
./scripts/uni-build-dependencies.sh opencsg
./scripts/uni-build-dependencies.sh cgal
Note that huge dependencies like gcc or qt are not included here, only
the smaller ones (boost, CGAL, opencsg, etc). After the build, again
check dependencies.
Note that huge dependencies like gcc, qt, or glib2 are not included
here, only the smaller ones (boost, CGAL, opencsg, etc). After the
build, again check dependencies.
./scripts/check-dependencies.sh

View File

@ -1,247 +1,240 @@
OpenSCAD YYYY.MM
================
Language Features:
o Added diameter argument: circle(d), cylinder(d, d1, d2) and sphere(d)
o Added parent_module() and $parent_modules
o Added children() as a replacement for child()
o FIXME: Unicode support
o FIXME: Ranges with negative steps
o FIXME: Experimental concat()
# OpenSCAD 2014.03
Program Features:
o Added --info parameter to the cmd-line for system/library info
o Added --enable parameter to enable experimental features
o Added Reset View in GUI
o Added Feature tab in Preferences
**Language Features:**
* Added diameter argument: circle(d), cylinder(d, d1, d2) and sphere(d)
* Added parent_module() and $parent_modules
* Added children() as a replacement for child()
* Unicode strings (using UTF-8) are now correctly handled
* Ranges can have a negative step value
* Added norm() and cross() functions
Bugfixes:
o polyhedron() is now much more robust handling almost planar polygons
o Automatic reloads of large designs are more robust
o Boolean logic in if() statements are now correctly short-circuited
o rands() with zero range caused an infinite loop
o resize(, auto=true) didn't work when shrinking objects
o The $children variable sometimes misbehaved due to dynamic scoping
o The --camera cmd-line option behaved differently then the corresponding GUI function
o PNG export now doesn't leak transparency settings into the target image
o Improved performance of OpenCSG (F5) compilation in some cases
o Some editor misbehaviors were fixed
o Stability fixes of CGAL-related crashes
**Program Features:**
* Cmd-line: --info parameter prints system/library info
* Cmd-line: --csglimit parameter to change CSG rendering limit
* Cmd-line: Better handling of cmd-line arguments under Windows
* GUI: Added Reset View
* GUI: Added Search&Replace in editor
* GUI: Syntax highlighting now has a dark background theme
* GUI: We now create a backup file before rendering to allow for recovery if OpenSCAD crashes/freezes
* GUI: Accessibility features enabled (e.g. screenreading)
Deprecations:
o child() is no longer supported. Use children() instead.
o polyhedron(triangles=[...]): Use polyhedron(faces=[...]) instead.
**Bugfixes/improvements:**
* Reading empty STL files sometimes caused a crash
* OPENSCADPATH now uses semicolon as path separator under Windows
* polyhedron() is now much more robust handling almost planar polygons
* Automatic reloads of large designs are more robust
* Boolean logic in if() statements are now correctly short-circuited
* rands() with zero range caused an infinite loop
* resize(, auto=true) didn't work when shrinking objects
* The $children variable sometimes misbehaved due to dynamic scoping
* The --camera cmd-line option behaved differently then the corresponding GUI function
* PNG export now doesn't leak transparency settings into the target image
* Improved performance of 3D hull() operations
* Some editor misbehaviors were fixed
* Stability fixes of CGAL-related crashes
* Windows cmd-line can now handle spaces in filenames
* Default CSG rendering limit is now 100K elements
* Fixed a crash reading DXF files using comma as decimal separator
* Fixed a crash running the cmd-line without a HOME env. variable
* Intersecting something with nothing now correctly results in an empty object
Misc:
o We now use CGAL's EPEC kernel
o Additional output formats: .ast, .term, null (these are most useful for testing)
o Test framework now shares more code with the GUI app
o Test report can now be automatically uploaded to dinkypage.com
o Better compatibility with BSD systems
**Deprecations:**
* child() is no longer supported. Use children() instead.
* polyhedron(triangles=[...]): Use polyhedron(faces=[...]) instead.
OpenSCAD 2013.06
================
**Misc:**
* Test framework now shares more code with the GUI app
* Test report can now be automatically uploaded to dinkypage.com
* Better compatibility with BSD systems
* Qt5 support
Language Features:
o linear_extrude now takes a scale parameter:
# OpenSCAD 2013.06
**Language Features:**
* linear_extrude now takes a scale parameter:
linear_extrude(height=a, slices=b, twist=c, scale=[x,y])
o Recursive use of modules is now supported (including cascading child() operations):
* Recursive use of modules is now supported (including cascading child() operations):
https://github.com/openscad/openscad/blob/master/examples/example024.scad
o Parameter list values can now depend on earlier values, e.g. for (i=[0:2], j=[0:i]) ..
o value assignments in parameters can now depend on already declared parameters
o Added resize() module:
* Parameter list values can now depend on earlier values, e.g. for (i=[0:2], j=[0:i]) ..
* value assignments in parameters can now depend on already declared parameters
* Added resize() module:
http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#resize
Program Features:
o Added basic syntax highlighting in the editor
o There is now a built-in library path in user-space:
**Program Features:**
* Added basic syntax highlighting in the editor
* There is now a built-in library path in user-space:
http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Libraries#Library_Locations
o Commandline output to PNG, with various camera and rendering settings.
* Commandline output to PNG, with various camera and rendering settings.
Run openscad -h to see usage info or see the OpenSCAD wiki user manual.
o Attempting to open dxf, off or stl files in the GUI will now create an import statement.
o The preview operator (%) will now preserve any manually set color
o The highlight operator (#) will now color the object in transparent red
o Mac: Added document icon
o Mac: Added auto-update check
o Windows: Better cmd-line support using the openscad.com executable
* Attempting to open dxf, off or stl files in the GUI will now create an import statement.
* The preview operator (%) will now preserve any manually set color
* The highlight operator (#) will now color the object in transparent red
* Mac: Added document icon
* Mac: Added auto-update check
* Windows: Better cmd-line support using the openscad.com executable
Bugfixes:
o Importing files is now always relative to the importing script, also for libraries
o We didn't always print a warning when CSG normalization created too many elements
o Binary STLs can now be read on big endian architectures
o Some binary STLs couldn't be read
o Fixed some issues related to ARM builds
o CGAL triangulation more lenient- enables partial rendering of 'bad' DXF data
o The Automatic Reload feature is now more robust
o If a file couldn't be saved it no longer fails silently
o Fixed a number of crashes related to CGAL and OpenCSG rendering or complex models
o The lookup() function had bad boundary condition behavior
o The surface() module failed when the .dat file lacked a trailing newline
o The hull() module could crash if any of the children were empty objects
o Some problems using unicode filenames have been fixed
**Bugfixes:**
* Importing files is now always relative to the importing script, also for libraries
* We didn't always print a warning when CSG normalization created too many elements
* Binary STLs can now be read on big endian architectures
* Some binary STLs couldn't be read
* Fixed some issues related to ARM builds
* CGAL triangulation more lenient- enables partial rendering of 'bad' DXF data
* The Automatic Reload feature is now more robust
* If a file couldn't be saved it no longer fails silently
* Fixed a number of crashes related to CGAL and OpenCSG rendering or complex models
* The lookup() function had bad boundary condition behavior
* The surface() module failed when the .dat file lacked a trailing newline
* The hull() module could crash if any of the children were empty objects
* Some problems using unicode filenames have been fixed
Misc:
o Build scripts have been further improved
o Regression test now creates single monolithic .html file for easier uploading
o Regression test auto-starts & stops Xvfb / Xvnc if on headless unix machine
o The backend is finally independent of Qt
o Windows: We now have a 64-bit version
**Misc:**
* Build scripts have been further improved
* Regression test now creates single monolithic .html file for easier uploading
* Regression test auto-starts & stops Xvfb / Xvnc if on headless unix machine
* The backend is finally independent of Qt
* Windows: We now have a 64-bit version
Known Bugs:
o Linux: command-line png rendering on Gallium is flaky.
**Known Bugs:**
* Linux: command-line png rendering on Gallium is flaky.
Workaround: use CGAL --render or hardware rendering.
# OpenSCAD 2013.01
OpenSCAD 2013.01
================
**Features:**
* Snappier GUI while performing CGAL computations (computations running in separate thread)
* The size of the misc. caches can now be adjusted from Preferences
* The limit for when to disable OpenCSG can now be adjusted from Preferences
* Added Dot product operator: vec * vec
* Added Matrix multiplication operator: vec * mat, mat * mat
* Added search() function
* Dependencies are now tracked - any changes in uses/included files will be detected and cause a recompile
* The OPENSCADPATH environment variable is now implemented will have precedence when searching for libraries
* .csg files can now be opened from the GUI
* linear_extrude() will now assume that the first parameter means 'height' if it's a number
Features:
o Snappier GUI while performing CGAL computations (computations running in separate thread)
o The size of the misc. caches can now be adjusted from Preferences
o The limit for when to disable OpenCSG can now be adjusted from Preferences
o Added Dot product operator: vec * vec
o Added Matrix multiplication operator: vec * mat, mat * mat
o Added search() function
o Dependencies are now tracked - any changes in uses/included files will be detected and cause a recompile
o The OPENSCADPATH environment variable is now implemented will have precedence when searching for libraries
o .csg files can now be opened from the GUI
o linear_extrude() will now assume that the first parameter means 'height' if it's a number
**Bugfixes:**
* use'ing an non-existing file sometimes crashed under Windows
* Better font handling: Ensure a monospace font is chosen as default
* Division by zero caused hang in some cases (e.g. sin(1/0))
* Larger minkowski operations sometimes caused a crash after a CGAL assert was thrown
* Fixed crashes in shared_ptr.hpp (or similar places) due bugs in cache management and CSG normalization
* scale() with a scale factor of zero could cause a crash
* Fixed a number of issues related to use/include
* Providing an unknown parameter on the cmd-line caused a crash
* cmd-line overrides using -D now also work for USEd modules
* Modifier characters can now be used in front of if statements
* rotate() with a vector argument with less that 3 elements used uninitialized variables, ending up being non-deterministic.
* .csg files will now have relative filenames whenever possible
* Don't just ignore geometric nodes having zero volume/area - when doing difference/intersection, they tend to turn negative objects into positive ones.
* Always use utf-8 file encoding, also under Windows
* A lot of build script fixes
* Some other crash bugs fixes
Bugfixes:
o use'ing an non-existing file sometimes crashed under Windows
o Better font handling: Ensure a monospace font is chosen as default
o Division by zero caused hang in some cases (e.g. sin(1/0))
o Larger minkowski operations sometimes caused a crash after a CGAL assert was thrown
o Fixed crashes in shared_ptr.hpp (or similar places) due bugs in cache management and CSG normalization
o scale() with a scale factor of zero could cause a crash
o Fixed a number of issues related to use/include
o Providing an unknown parameter on the cmd-line caused a crash
o cmd-line overrides using -D now also work for USEd modules
o Modifier characters can now be used in front of if statements
o rotate() with a vector argument with less that 3 elements used uninitialized variables, ending up being non-deterministic.
o .csg files will now have relative filenames whenever possible
o Don't just ignore geometric nodes having zero volume/area - when doing difference/intersection, they tend to turn negative objects into positive ones.
o Always use utf-8 file encoding, also under Windows
o A lot of build script fixes
o Some other crash bugs fixes
Deprecations:
o The old include syntax "<filename.scad>" without the include keyword is no
**Deprecations:**
* The old include syntax "<filename.scad>" without the include keyword is no
longer supported and will cause a syntax error.
OpenSCAD 2011.12
================
# OpenSCAD 2011.12
Features:
o The MCAD library is now bundled with OpenSCAD
o Added len() function. Takes one vector or string parameter and returns its length.
o The index operator [] now works on strings
o The version() function will return the OpenSCAD version as a vector, e.g. [2011, 09]
o The version_num() function will return the OpenSCAD version as a number, e.g. 20110923
o hull() Now supports 3D objects
o hull() with 2D object can now use for loops and boolean operations as children
o New import() statement reads the correct file format based on the filename extension
**Features:**
* The MCAD library is now bundled with OpenSCAD
* Added len() function. Takes one vector or string parameter and returns its length.
* The index operator [] now works on strings
* The version() function will return the OpenSCAD version as a vector, e.g. [2011, 09]
* The version_num() function will return the OpenSCAD version as a number, e.g. 20110923
* hull() Now supports 3D objects
* hull() with 2D object can now use for loops and boolean operations as children
* New import() statement reads the correct file format based on the filename extension
(.stl, .dxf and .off is supported)
o The color() statement now supports an alpha parameter, e.g. color(c=[1,0,0], alpha=0.4)
o The color() statement now supports specifying colors as strings, e.g. color("Red")
o The color() statement now overrides colors specified further down in the tree
o if()/else() and the ternary operator can now take any value type as parameter. false, 0, empty string and empty vector or illegal value type will evaluate as false, everything else as true.
o Strings can now be lexographically compared using the <, <=, >, >= operators
o Added PI constant.
o Number literals in scientific notation are now accepted by the parser
o Added import and export of the OFF file format
o Now uses standard shortcuts for save, reload and quit on Linux and Windows. F2/F3 will still work but is deprecated.
* The color() statement now supports an alpha parameter, e.g. color(c=[1,0,0], alpha=0.4)
* The color() statement now supports specifying colors as strings, e.g. color("Red")
* The color() statement now overrides colors specified further down in the tree
* if()/else() and the ternary operator can now take any value type as parameter. false, 0, empty string and empty vector or illegal value type will evaluate as false, everything else as true.
* Strings can now be lexographically compared using the <, <=, >, >= operators
* Added PI constant.
* Number literals in scientific notation are now accepted by the parser
* Added import and export of the OFF file format
* Now uses standard shortcuts for save, reload and quit on Linux and Windows. F2/F3 will still work but is deprecated.
Bugfixes:
o Complex CSG models sometimes took extremely long time to normalize before OpenCSG preview
o square() crashed if any of the dimensions were zero
o Flush Caches didn't flush cached USE'd modules
o STL export should be a bit more robust
o Dropping a file into the editor under Windows didn't work (double C:/C:/ problem)
o On some platforms it was possible to insertion rich text in the editor, causing confusion.
o Less crashes due to CGAL assertions
o OpenCSG should now work on systems with OpenGL 1.x, given that the right extensions are available
o include now searches librarydir
o The $fs parameter yielded only half the number of segments it should have
o surface(center=true) is now correctly centered in the XY plane
**Bugfixes:**
* Complex CSG models sometimes took extremely long time to normalize before OpenCSG preview
* square() crashed if any of the dimensions were zero
* Flush Caches didn't flush cached USE'd modules
* STL export should be a bit more robust
* Dropping a file into the editor under Windows didn't work (double C:/C:/ problem)
* On some platforms it was possible to insertion rich text in the editor, causing confusion.
* Less crashes due to CGAL assertions
* OpenCSG should now work on systems with OpenGL 1.x, given that the right extensions are available
* include now searches librarydir
* The $fs parameter yielded only half the number of segments it should have
* surface(center=true) is now correctly centered in the XY plane
Deprecations:
o dxf_linear_extrude() and dxf_rotate_extrude() are now deprecated.
**Deprecations:**
* dxf_linear_extrude() and dxf_rotate_extrude() are now deprecated.
Use linear_extrude() and rotate_extrude() instead.
o The file, layer, origin and scale parameters to linear_extrude() and rotate_extrude()
* The file, layer, origin and scale parameters to linear_extrude() and rotate_extrude()
are now deprecated. Use an import() child instead.
o import_dxf(), import_stl() and import_off() are now deprecated. Use import() instead.
o When exporting geometry from the cmd-line, use the universal -o option. It will export to the correct file format based on the given suffix (dxf, stl, off). The -x and -s parameters are still working but deprecated.
o F2 and F3 for Save and Reload is now deprecated
* import_dxf(), import_stl() and import_off() are now deprecated. Use import() instead.
* When exporting geometry from the cmd-line, use the universal -o option. It will export to the correct file format based on the given suffix (dxf, stl, off). The -x and -s parameters are still working but deprecated.
* F2 and F3 for Save and Reload is now deprecated
# OpenSCAD 2011.06
OpenSCAD 2011.06
================
* Added "Export as Image" menu.
o Added "Export as Image" menu.
Bugfixes:
o Cylinder tesselation broke existing models which are using cylinders
**Bugfixes:**
* Cylinder tesselation broke existing models which are using cylinders
for e.g. captured nut slots and are dependent on the orientation not
changing.
o DXF output couldn't be imported into e.g. AutoCAD and Solidworks after updating
* DXF output couldn't be imported into e.g. AutoCAD and Solidworks after updating
to using the AutoCAD 2000 (AC1015) format. Reverted to the old entity-only output,
causing LWPOLYLINES to not exported allowed anymore.
# OpenSCAD 2011.04
* Added hull() for convex hulls (2D object only)
* minkowski() now supports 2D objects
* Added functions: rands(), sign()
* Now supports escaping of the following characters in strings: \n, \t, \r, \\, \"
* Support nested includes
* Improved parsing of numbers
* DXF: output LWPOLYLINE instead of just LINE entities
* Bugfixes: More robust DXF export, setting $fs/$fa to 0 caused a crash
* Some bugs fixed, maybe some new bugs added
# OpenSCAD 2010.05
* Added functions and statements
* Added abs() function
* Added exp(x), log(b, x), log(x) and ln(x) functions
* Added minkowski() statement for 3d minkowski sums
* Added 'include <filename>' and 'use <filename>' statements
* Old implicit '<filename>' include statement is now obsolete
* Some bugs fixed, maybe some new bugs added
# OpenSCAD 2010.02
OpenSCAD 2011.04
================
o Added hull() for convex hulls (2D object only)
o minkowski() now supports 2D objects
o Added functions: rands(), sign()
o Now supports escaping of the following characters in strings: \n, \t, \r, \\, \"
o Support nested includes
o Improved parsing of numbers
o DXF: output LWPOLYLINE instead of just LINE entities
o Bugfixes: More robust DXF export, setting $fs/$fa to 0 caused a crash
o Some bugs fixed, maybe some new bugs added
OpenSCAD 2010.05
================
o Added functions and statements
- Added abs() function
- Added exp(x), log(b, x), log(x) and ln(x) functions
- Added minkowski() statement for 3d minkowski sums
o Added 'include <filename>' and 'use <filename>' statements
- Old implicit '<filename>' include statement is now obsolete
o Some bugs fixed, maybe some new bugs added
OpenSCAD 2010.02
================
o Added functions and statements
- Added sqrt() function
- Added round(), ceil() and floor() functions
- Added lookup() function for linear interpolation in value list
- Added projection(cut = true/false) statement
- Added child() statement for accessing child nodes of module instances
- Added mirror() statement
o Improved DXF import code (more entities and some bugs fixed)
o Added feature for dumping animation as PNG files
o Added a preferences dialog
o Now using CGAL's delaunay tesselator
o Now using eigen2 for linear algebra
o Reorganisation of the source tree
o Some bugs fixed, maybe some new bugs added
OpenSCAD 2010.01
================
o Added functions and statements
- Added intersection_for()
- Added str function
- Added min and max function
- Added color() statement
o Added 2D Subsystem
- New primitives: circle(), square() and polygon()
- 2D->3D path: linear_extrude() and rotate_extrude()
- Import of DXF to 2d subsystem: import_dxf()
- Export of 2D data as DXF files
o Some bugs fixed, maybe some new bugs added
* Added functions and statements
* Added sqrt() function
* Added round(), ceil() and floor() functions
* Added lookup() function for linear interpolation in value list
* Added projection(cut = true/false) statement
* Added child() statement for accessing child nodes of module instances
* Added mirror() statement
* Improved DXF import code (more entities and some bugs fixed)
* Added feature for dumping animation as PNG files
* Added a preferences dialog
* Now using CGAL's delaunay tesselator
* Now using eigen2 for linear algebra
* Reorganisation of the source tree
* Some bugs fixed, maybe some new bugs added
# OpenSCAD 2010.01
* Added functions and statements
* Added intersection_for()
* Added str function
* Added min and max function
* Added color() statement
* Added 2D Subsystem
* New primitives: circle(), square() and polygon()
* 2D->3D path: linear_extrude() and rotate_extrude()
* Import of DXF to 2d subsystem: import_dxf()
* Export of 2D data as DXF files
* Some bugs fixed, maybe some new bugs added

View File

@ -8,6 +8,7 @@
<title>OpenSCAD @VERSION@</title>
<pubDate>@VERSIONDATE@</pubDate>
<sparkle:releaseNotesLink>https://raw.github.com/openscad/openscad/master/RELEASE_NOTES</sparkle:releaseNotesLink>
<sparkle:minimumSystemVersion>10.7.0</sparkle:minimumSystemVersion>
<enclosure url="http://files.openscad.org/OpenSCAD-@VERSION@.dmg"
sparkle:version="@VERSIONDATE@"
sparkle:shortVersionString="@VERSION@"

View File

@ -8,6 +8,7 @@
<title>OpenSCAD @VERSION@</title>
<pubDate>@VERSIONDATE@</pubDate>
<sparkle:releaseNotesLink>https://raw.github.com/openscad/openscad/openscad-@VERSION@/RELEASE_NOTES</sparkle:releaseNotesLink>
<sparkle:minimumSystemVersion>10.7.0</sparkle:minimumSystemVersion>
<enclosure url="http://files.openscad.org/OpenSCAD-@VERSION@.dmg"
sparkle:version="@VERSIONDATE@"
sparkle:shortVersionString="@VERSION@"

View File

@ -9,6 +9,8 @@ boost {
win*: QMAKE_LIBDIR += -L$$BOOST_DIR/lib
}
# See https://svn.boost.org/trac/boost/ticket/6219
macx: DEFINES += __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0
CONFIG(mingw-cross-env) {
DEFINES += BOOST_STATIC
DEFINES += BOOST_THREAD_USE_LIB

View File

@ -1,4 +1,4 @@
.TH OPENSCAD 1 "2013-06-xx"
.TH OPENSCAD 1 "2014.03"
.\" Please adjust this date whenever revising the manpage.
.SH NAME
openscad \- script file based graphical CAD environment
@ -19,9 +19,9 @@ the OpenSCAD user manual at http://en.wikibooks.org/wiki/OpenSCAD_User_Manual.
.TP
\fB-o\fP \fIoutputfile\fP
Export the given file to \fIoutputfile\fP in STL, OFF, DXF, or PNG format,
depending on file extension of \fIoutputfile\fP (which has to be lower case).
If this option is given, the GUI will not be started.
Export the given file to \fIoutputfile\fP in STL, OFF, DXF, or PNG
format, depending on file extension of \fIoutputfile\fP. If this
option is given, the GUI will not be started.
Additional formats, which are mainly used for debugging and testing (but can
also be used in automation), are AST (the input file as parsed and serialized
@ -46,12 +46,18 @@ read it again.
This option can be used to assign constant values to OpenSCAD variables. The
variable's value is an expression, so if this mechanism is used to assign
strings, care has to be taken that the shell does not consume quotation marks.
More than one \fB-D\fP options can be given.
More than one \fB-D\fP option can be given.
.TP
.B \-\-render
If exporting an image, use a full CGAL render. (Default is an OpenCSG compile)
.TP
.B \-\-camera=rotx,roty,rotz,transx,transy,transz,distance
.B \-\-preview[=throwntogether]
If exporting an image, use an OpenCSG previce (optionally in throwntogether mode for quicker rendering).
.TP
.B \-\-csglimit=limit
If exporting an image as an OpenCSG preview, stop rendering after encountering \fIlimit\fP elements to avoid runaway resource usage.
.TP
.B \-\-camera=transx,transy,transz,rotx,roty,rotz,distance
If exporting an image, use a Gimbal camera with the given parameters.
Rot is rotation around the x, y, and z axis, trans is the distance to
move the object in the x, y, and z directions, and distance is the
@ -66,7 +72,7 @@ not currently supported.
.B \-\-imgsize=width,height
If exporting an image, specify the pixel width and height
.TP
.B \-\-projection=[o|p]
.B \-\-projection=[o|ortho|p|perspective]
If exporting an image, specify whether to use orthographic or perspective
projection
.TP

View File

@ -11,7 +11,7 @@ o Pre-release preparations
$ cd libraries/MCAD
$ git pull
$ cd ../..
$ git commit -m "Updated MCAD"
$ git commit -m "Updated MCAD" libraries/MCAD
$ git push
(See bottom of this file for how to build release binaries)
@ -29,7 +29,11 @@ o Set VERSION and VERSIONDATE environment variable
scripts/publish-macosx.sh
scripts/publish-mingw-x.sh
o Update RELEASE_NOTES
o Update manpage: doc/openscad.1
o Update releases/$VERSION.md
o scripts/makereleasenotes.sh
o Update version number in doc/openscad.1
o Update copyright year in AboutDialog.html and mainwin.cc
o Tag release
@ -40,15 +44,18 @@ o build source package
o Sanity check; build a binary or two and manually run some tests
o git push --tags
o git push --tags master
o Upload Source package
$ ./scripts/googlecode_upload.py -s 'Source Code' -p openscad -l Featured,Type-Source openscad-$VERSION.src.tar.gz
$ scp openscad-$VERSION.src.tar.gz openscad@files.openscad.org:www
o Remove VERSION environment variable
$ unset VERSION
o Build binaries for all platforms and wait for upload
o Announce:
o ./scripts/github-release.sh $VERSION
o Write release email/blog entry
o Update web page
- news.html
@ -56,12 +63,13 @@ o Update web page
o Update external resources:
- http://en.wikipedia.org/wiki/OpenSCAD
o Write to mailing list
o Tweet
o Tweet as OpenSCAD
o Notify package managers
- Ubuntu: https://launchpad.net/~chrysn
- Fedora: Miro Hrončok <miro@hroncok.cz> or <mhroncok@redhat.com>
- OpenSUSE: Pavol Rusnak <prusnak@opensuse.org>
- MacPorts: Frank Schima <macports2000@gmail.com>
- Arch Linux: Kyle Keen <keenerd@gmail.com>
Build and Upload Release Binaries
---------------------------------

View File

@ -1,9 +1,20 @@
Running regression tests:
-------------------------
Prerequisites: cmake, python, ImageMagick 6.5.9.3 or newer
0) Prerequisites
First, install MCAD.
Install the prerequisite helper programs on your system:
cmake, python2 (not 3), ImageMagick 6.5.9.3 or newer, diff
There are binary installer packages of these tools available for Mac,
Win, Linux, BSD, and other systems. (except maybe diff for Win)
Next, get a working qmake GUI build of the main openscad binary working.
For Windows(TM) this means get a cross-build working from within linux.
See README.md for how to do this.
Then, install MCAD under openscad/libraries.
$ cd openscad
$ git submodule update --init
@ -11,30 +22,29 @@ $ git submodule update --init
A) Building test environment
Linux, Mac:
$ cd tests
$ cmake .
$ make
Windows + MSVC:
$ cd tests
$ cmake .
$ make
The MSVC build hasn't been tested in years. See the README for pointers.
First, gett the main GUI to build. Then, to build the tests:
Windows(TM):
From the QT command prompt:
Cross-build from within linux:
> cd tests
> cmake . -DCMAKE_BUILD_TYPE=Release
> sed -i s/\/MD/\/MT/ CMakeCache.txt
> cmake .
> nmake -f Makefile
64-bit:
$ source ./scripts/setenv-mingw-xbuild.sh 64
$ ./scripts/release-common.sh mingw64 tests
$ # result is .zip file under ./mingw64/
Cross compiling Linux->Win32 and testing under Wine:
Experimental. Please see openscad/tests/CMingw-cross-env.cmake for instructions
on attempting to get it to work.
32-bit:
$ source ./scripts/setenv-mingw-xbuild.sh 32
$ ./scripts/release-common.sh mingw32 tests
$ # result is .zip file under ./mingw32/
B) Running tests
Linux, Mac:
$ ctest Runs tests enabled by default
$ ctest -R <regex> Runs only matching tests, e.g. ctest -R dxf
$ ctest -C <configs> Adds extended tests belonging to configs.
@ -45,6 +55,22 @@ $ ctest -C <configs> Adds extended tests belonging to configs.
Bugs - test known bugs (tests will fail)
All - test everything
Win:
Unzip the OpenSCAD-Tests-YYYY.MM.DD file onto a Windows(TM) machine.
There will be a script called OpenSCAD-Test-Console.py in the parent folder.
Double-click it, and it will open a console, from which you can type the ctest
commands listed above.
C) Automatically upload test results (experimental)
It's possible to automatically upload tests results to an external
server. This is good for CI, as well as being able to easily report
bugs.
To enable this feature, add '-DOPENSCAD_UPLOAD_TESTS=1' to the cmake
cmd-line, e.g.: cmake -DOPENSCAD_UPLOAD_TESTS=1 .
Adding a new test:
------------------
@ -120,7 +146,7 @@ Imagemagick may have crashed while comparing the expected images to the
test-run generated (actual) images. You can try using the alternate
ImageMagick comparison method by by erasing CMakeCache, and re-running
cmake with -DCOMPARATOR=ncc. This will enable the Normalized Cross
Comparison method.
Comparison method which is less accurate but won't usually crash.
4. Testing images fails with 'morphology not found" for ImageMagick in the log
@ -132,7 +158,7 @@ cmake. The comparison will be of lowered reliability.
"terminate called after throwing an instance of 'std::runtime_error'
what(): locale::facet::_S_create_c_locale name not valid"
Is a boost/libstdc++ bug. Fix like so:
Is a boost/libstdc++ bug. Fix like so before running:
$ export LC_MESSAGES=
@ -147,21 +173,43 @@ Is a boost/libstdc++ bug. Fix like so:
useful for debugging and outputting 3d-formats like STL on systems without GL.
This option may break in the future and require tweaking to get working again.
7. Other issues
7. Proprietary GL driver issues
The OpenSCAD User Manual has a section on buildling. Please check there
for updates:
There are sporadic reports of problems running on remote machines with
proprietary GL drivers. Try doing a web search for your exact error
message to see solutions and workarounds that others have found.
8. Windows + MSVC:
The MSVC build was last tested circa 2012. The last time it worked,
these were the necessary commands to run.
> Start the 'QT command prompt'
> cd \where\you\installed\openscad
> cd tests
> cmake . -DCMAKE_BUILD_TYPE=Release
> sed -i s/\/MD/\/MT/ CMakeCache.txt
> cmake .
> nmake -f Makefile
9. Other issues
The OpenSCAD User Manual Wiki has a section on buildling. Please check
there for possible updates and workarounds:
http://en.wikibooks.org/wiki/OpenSCAD_User_Manual
Please report build errors (after double checking the instructions) in
the github issue tracker
http://github.com/openscad/openscad/issues
Migration away from dedicated regression tests:
-----------------------------------------------
10. Migration away from dedicated regression tests:
In 2013 the test programs underwent a major change. These notes are leftover.
In 2013 the test programs underwent a major change. The following notes
are leftover.
This test still needs an intermediate script that mangles away timestamps and
"This test still needs an intermediate script that mangles away timestamps and
near-zero floating point numbers:
* cgalstlsanitytest
@ -174,4 +222,4 @@ These look like tests, but are not actually in use:
* modulecachetest
* cgalcachetest
"

View File

@ -43,14 +43,14 @@ EIGEN_DIR = $$(EIGENDIR)
}
isEmpty(EIGEN_INCLUDEPATH) {
linux*|hurd*|unix: EIGEN_INCLUDEPATH = /usr/include/eigen3
freebsd-g++: EIGEN_INCLUDEPATH = /usr/local/include/eigen3
netbsd*: EIGEN_INCLUDEPATH = /usr/pkg/include/eigen3
linux*|hurd*|unix: EIGEN_INCLUDEPATH = /usr/include/eigen3
macx: EIGEN_INCLUDEPATH = /opt/local/include/eigen3
!exists($$EIGEN_INCLUDEPATH) {
linux*|hurd*|unix*: EIGEN_INCLUDEPATH = /usr/include/eigen2
freebsd-g++: EIGEN_INCLUDEPATH = /usr/local/include/eigen2
netbsd*: EIGEN_INCLUDEPATH = /usr/pkg/include/eigen2
linux*|hurd*|unix*: EIGEN_INCLUDEPATH = /usr/include/eigen2
macx: EIGEN_INCLUDEPATH = /opt/local/include/eigen2
}
}

View File

@ -2,7 +2,7 @@
module step(len, mod)
{
for (i = [0:$children-1])
translate([ len*(i - ($children-1)/2), 0, 0 ]) child((i+mod) % $children);
translate([ len*(i - ($children-1)/2), 0, 0 ]) children((i+mod) % $children);
}
for (i = [1:4])

31
examples/example025.scad Normal file
View File

@ -0,0 +1,31 @@
// Example for offset() usage
// (c) 2014 Torsten Paul
// CC-BY-SA 4.0
$fn = 40;
foot_height = 20;
module outline(wall = 1) {
difference() {
offset(wall / 2) children();
offset(-wall / 2) children();
}
}
// offsetting with a positive value and join_type = "round"
// allows to create rounded corners easily
linear_extrude(height = foot_height, scale = 0.5) {
offset(10, join_type = "round") {
square(50, center = true);
}
}
translate([0, 0, foot_height]) {
linear_extrude(height = 20) {
outline(wall = 2) circle(15);
}
}
%cylinder(r = 14, h = 100);
%translate([0, 0, 100]) sphere(r = 30);

View File

@ -19,6 +19,14 @@ GLIB2_DIR = $$(GLIB2DIR)
}
}
!exists($$GLIB2_INCLUDEPATH/glib.h) {
!exists($$GLIB2_INCLUDEPATH_2/glib.h) {
GLIB2_INCLUDEPATH =
GLIB2_INCLUDEPATH_2 =
GLIB2_LIBPATH =
}
}
isEmpty(GLIB2_INCLUDEPATH) {
GLIB2_CFLAGS = $$system("pkg-config --cflags glib-2.0")
} else {
@ -32,6 +40,27 @@ isEmpty(GLIB2_LIBPATH) {
GLIB2_LIBS = -L$$GLIB2_LIBPATH -lglib-2.0
}
CONFIG(mingw-cross-env) {
#message("mingw")
isEmpty(GLIB2_INCLUDEPATH) {
MXE_TARGET_DIR=$$(MXETARGETDIR)
#message($$MXE_TARGET_DIR)
contains( MXE_TARGET_DIR, .*x86_64-w64-mingw32 ) {
GLIB2_CFLAGS = $$system("x86_64-w64-mingw32-pkg-config --cflags glib-2.0")
GLIB2_LIBS = $$system("x86_64-w64-mingw32-pkg-config --libs glib-2.0")
}
contains( MXE_TARGET_DIR, .*i686-w64-mingw32 ) {
GLIB2_CFLAGS = $$system("i686-w64-mingw32-pkg-config --cflags glib-2.0")
GLIB2_LIBS = $$system("i686-w64-mingw32-pkg-config --libs glib-2.0")
}
contains( MXE_TARGET_DIR, .*i686-pc-mingw32 ) {
GLIB2_CFLAGS = $$system("i686-pc-mingw32-pkg-config --cflags glib-2.0")
GLIB2_LIBS = $$system("i686-pc-mingw32-pkg-config --libs glib-2.0")
}
}
}
QMAKE_CXXFLAGS += $$GLIB2_CFLAGS
LIBS += $$GLIB2_LIBS
}

View File

@ -4,4 +4,5 @@ Version=1.0
Name=OpenSCAD
Icon=openscad
Exec=openscad %f
MimeType=application/x-openscad;
Categories=Graphics;3DGraphics;Engineering;Development;

8
icons/openscad.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/x-openscad">
<comment>OpenSCAD Model</comment>
<glob pattern="*.scad"/>
<icon name="openscad"/>
</mime-type>
</mime-info>

@ -1 +1 @@
Subproject commit 9a958fd11b0a6b5f8becd37c4f8a42f585abfcd8
Subproject commit 85794e4b4f2294a1b445a4d928866bedd5cc64ec

View File

@ -13,6 +13,10 @@
#
# http://en.wikibooks.org/wiki/OpenSCAD_User_Manual
!experimental {
message("If you're building a development binary, consider adding CONFIG+=experimental")
}
isEmpty(QT_VERSION) {
error("Please use qmake for Qt 4 (probably qmake-qt4)")
}
@ -45,6 +49,7 @@ DEPENDPATH += src
# Used when manually installing 3rd party libraries
OPENSCAD_LIBDIR = $$(OPENSCAD_LIBRARIES)
!isEmpty(OPENSCAD_LIBDIR) {
INCLUDEPATH += $$OPENSCAD_LIBDIR/include
QMAKE_INCDIR_QT = $$OPENSCAD_LIBDIR/include $$QMAKE_INCDIR_QT
QMAKE_LIBDIR = $$OPENSCAD_LIBDIR/lib $$QMAKE_LIBDIR
}
@ -74,14 +79,6 @@ macx {
APP_RESOURCES.files = OpenSCAD.sdef dsa_pub.pem icons/SCAD.icns
QMAKE_BUNDLE_DATA += APP_RESOURCES
LIBS += -framework Cocoa -framework ApplicationServices
# FIXME: Somehow, setting the deployment target to a lower version causes a
# seldom crash in debug mode (e.g. the minkowski2-test):
# frame #4: 0x00007fff8b7d5be5 libc++.1.dylib`std::runtime_error::~runtime_error() + 55
# frame #5: 0x0000000100150df5 OpenSCAD`CGAL::Uncertain_conversion_exception::~Uncertain_conversion_exception(this=0x0000000105044488) + 21 at Uncertain.h:78
# The reason for the crash appears to be linking with libgcc_s,
# but it's unclear what's really going on
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.6
}
else {
TARGET = openscad
@ -89,6 +86,7 @@ else {
win* {
RC_FILE = openscad_win32.rc
QTPLUGIN += qtaccessiblewidgets
}
CONFIG += qt
@ -129,6 +127,7 @@ netbsd* {
# See Dec 2011 OpenSCAD mailing list, re: CGAL/GCC bugs.
*g++* {
QMAKE_CXXFLAGS *= -fno-strict-aliasing
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-local-typedefs # ignored before 4.8
}
*clang* {
@ -162,6 +161,11 @@ CONFIG += fontconfig
#Uncomment the following line to enable QCodeEdit
#CONFIG += qcodeedit
# Make experimental features available
experimental {
DEFINES += ENABLE_EXPERIMENTAL
}
mdi {
DEFINES += ENABLE_MDI
}
@ -227,6 +231,7 @@ HEADERS += src/typedefs.h \
src/feature.h \
src/node.h \
src/csgnode.h \
src/offsetnode.h \
src/linearextrudenode.h \
src/rotateextrudenode.h \
src/projectionnode.h \
@ -315,6 +320,7 @@ SOURCES += src/version_check.cc \
src/text.cc \
src/dxfdata.cc \
src/dxfdim.cc \
src/offset.cc \
src/linearextrude.cc \
src/rotateextrude.cc \
src/printutils.cc \
@ -438,6 +444,10 @@ applications.path = $$PREFIX/share/applications
applications.files = icons/openscad.desktop
INSTALLS += applications
mimexml.path = $$PREFIX/share/mime/packages
mimexml.files = icons/openscad.xml
INSTALLS += mimexml
appdata.path = $$PREFIX/share/appdata
appdata.files = openscad.appdata.xml
INSTALLS += appdata

11
releases/2010.01.md Normal file
View File

@ -0,0 +1,11 @@
* Added functions and statements
* Added intersection_for()
* Added str function
* Added min and max function
* Added color() statement
* Added 2D Subsystem
* New primitives: circle(), square() and polygon()
* 2D->3D path: linear_extrude() and rotate_extrude()
* Import of DXF to 2d subsystem: import_dxf()
* Export of 2D data as DXF files
* Some bugs fixed, maybe some new bugs added

14
releases/2010.02.md Normal file
View File

@ -0,0 +1,14 @@
* Added functions and statements
* Added sqrt() function
* Added round(), ceil() and floor() functions
* Added lookup() function for linear interpolation in value list
* Added projection(cut = true/false) statement
* Added child() statement for accessing child nodes of module instances
* Added mirror() statement
* Improved DXF import code (more entities and some bugs fixed)
* Added feature for dumping animation as PNG files
* Added a preferences dialog
* Now using CGAL's delaunay tesselator
* Now using eigen2 for linear algebra
* Reorganisation of the source tree
* Some bugs fixed, maybe some new bugs added

7
releases/2010.05.md Normal file
View File

@ -0,0 +1,7 @@
* Added functions and statements
* Added abs() function
* Added exp(x), log(b, x), log(x) and ln(x) functions
* Added minkowski() statement for 3d minkowski sums
* Added 'include <filename>' and 'use <filename>' statements
* Old implicit '<filename>' include statement is now obsolete
* Some bugs fixed, maybe some new bugs added

9
releases/2011.04.md Normal file
View File

@ -0,0 +1,9 @@
* Added hull() for convex hulls (2D object only)
* minkowski() now supports 2D objects
* Added functions: rands(), sign()
* Now supports escaping of the following characters in strings: \n, \t, \r, \\, \"
* Support nested includes
* Improved parsing of numbers
* DXF: output LWPOLYLINE instead of just LINE entities
* Bugfixes: More robust DXF export, setting $fs/$fa to 0 caused a crash
* Some bugs fixed, maybe some new bugs added

9
releases/2011.06.md Normal file
View File

@ -0,0 +1,9 @@
* Added "Export as Image" menu.
**Bugfixes:**
* Cylinder tesselation broke existing models which are using cylinders
for e.g. captured nut slots and are dependent on the orientation not
changing.
* DXF output couldn't be imported into e.g. AutoCAD and Solidworks after updating
to using the AutoCAD 2000 (AC1015) format. Reverted to the old entity-only output,
causing LWPOLYLINES to not exported allowed anymore.

41
releases/2011.12.md Normal file
View File

@ -0,0 +1,41 @@
**Features:**
* The MCAD library is now bundled with OpenSCAD
* Added len() function. Takes one vector or string parameter and returns its length.
* The index operator [] now works on strings
* The version() function will return the OpenSCAD version as a vector, e.g. [2011, 09]
* The version_num() function will return the OpenSCAD version as a number, e.g. 20110923
* hull() Now supports 3D objects
* hull() with 2D object can now use for loops and boolean operations as children
* New import() statement reads the correct file format based on the filename extension
(.stl, .dxf and .off is supported)
* The color() statement now supports an alpha parameter, e.g. color(c=[1,0,0], alpha=0.4)
* The color() statement now supports specifying colors as strings, e.g. color("Red")
* The color() statement now overrides colors specified further down in the tree
* if()/else() and the ternary operator can now take any value type as parameter. false, 0, empty string and empty vector or illegal value type will evaluate as false, everything else as true.
* Strings can now be lexographically compared using the <, <=, >, >= operators
* Added PI constant.
* Number literals in scientific notation are now accepted by the parser
* Added import and export of the OFF file format
* Now uses standard shortcuts for save, reload and quit on Linux and Windows. F2/F3 will still work but is deprecated.
**Bugfixes:**
* Complex CSG models sometimes took extremely long time to normalize before OpenCSG preview
* square() crashed if any of the dimensions were zero
* Flush Caches didn't flush cached USE'd modules
* STL export should be a bit more robust
* Dropping a file into the editor under Windows didn't work (double C:/C:/ problem)
* On some platforms it was possible to insertion rich text in the editor, causing confusion.
* Less crashes due to CGAL assertions
* OpenCSG should now work on systems with OpenGL 1.x, given that the right extensions are available
* include now searches librarydir
* The $fs parameter yielded only half the number of segments it should have
* surface(center=true) is now correctly centered in the XY plane
**Deprecations:**
* dxf_linear_extrude() and dxf_rotate_extrude() are now deprecated.
Use linear_extrude() and rotate_extrude() instead.
* The file, layer, origin and scale parameters to linear_extrude() and rotate_extrude()
are now deprecated. Use an import() child instead.
* import_dxf(), import_stl() and import_off() are now deprecated. Use import() instead.
* When exporting geometry from the cmd-line, use the universal -o option. It will export to the correct file format based on the given suffix (dxf, stl, off). The -x and -s parameters are still working but deprecated.
* F2 and F3 for Save and Reload is now deprecated

34
releases/2013.01.md Normal file
View File

@ -0,0 +1,34 @@
**Features:**
* Snappier GUI while performing CGAL computations (computations running in separate thread)
* The size of the misc. caches can now be adjusted from Preferences
* The limit for when to disable OpenCSG can now be adjusted from Preferences
* Added Dot product operator: vec * vec
* Added Matrix multiplication operator: vec * mat, mat * mat
* Added search() function
* Dependencies are now tracked - any changes in uses/included files will be detected and cause a recompile
* The OPENSCADPATH environment variable is now implemented will have precedence when searching for libraries
* .csg files can now be opened from the GUI
* linear_extrude() will now assume that the first parameter means 'height' if it's a number
**Bugfixes:**
* use'ing an non-existing file sometimes crashed under Windows
* Better font handling: Ensure a monospace font is chosen as default
* Division by zero caused hang in some cases (e.g. sin(1/0))
* Larger minkowski operations sometimes caused a crash after a CGAL assert was thrown
* Fixed crashes in shared_ptr.hpp (or similar places) due bugs in cache management and CSG normalization
* scale() with a scale factor of zero could cause a crash
* Fixed a number of issues related to use/include
* Providing an unknown parameter on the cmd-line caused a crash
* cmd-line overrides using -D now also work for USEd modules
* Modifier characters can now be used in front of if statements
* rotate() with a vector argument with less that 3 elements used uninitialized variables, ending up being non-deterministic.
* .csg files will now have relative filenames whenever possible
* Don't just ignore geometric nodes having zero volume/area - when doing difference/intersection, they tend to turn negative objects into positive ones.
* Always use utf-8 file encoding, also under Windows
* A lot of build script fixes
* Some other crash bugs fixes
**Deprecations:**
* The old include syntax "<filename.scad>" without the include keyword is no
longer supported and will cause a syntax error.

48
releases/2013.06.md Normal file
View File

@ -0,0 +1,48 @@
**Language Features:**
* linear_extrude now takes a scale parameter:
linear_extrude(height=a, slices=b, twist=c, scale=[x,y])
* Recursive use of modules is now supported (including cascading child() operations):
https://github.com/openscad/openscad/blob/master/examples/example024.scad
* Parameter list values can now depend on earlier values, e.g. for (i=[0:2], j=[0:i]) ..
* value assignments in parameters can now depend on already declared parameters
* Added resize() module:
http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#resize
**Program Features:**
* Added basic syntax highlighting in the editor
* There is now a built-in library path in user-space:
http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Libraries#Library_Locations
* Commandline output to PNG, with various camera and rendering settings.
Run openscad -h to see usage info or see the OpenSCAD wiki user manual.
* Attempting to open dxf, off or stl files in the GUI will now create an import statement.
* The preview operator (%) will now preserve any manually set color
* The highlight operator (#) will now color the object in transparent red
* Mac: Added document icon
* Mac: Added auto-update check
* Windows: Better cmd-line support using the openscad.com executable
**Bugfixes:**
* Importing files is now always relative to the importing script, also for libraries
* We didn't always print a warning when CSG normalization created too many elements
* Binary STLs can now be read on big endian architectures
* Some binary STLs couldn't be read
* Fixed some issues related to ARM builds
* CGAL triangulation more lenient- enables partial rendering of 'bad' DXF data
* The Automatic Reload feature is now more robust
* If a file couldn't be saved it no longer fails silently
* Fixed a number of crashes related to CGAL and OpenCSG rendering or complex models
* The lookup() function had bad boundary condition behavior
* The surface() module failed when the .dat file lacked a trailing newline
* The hull() module could crash if any of the children were empty objects
* Some problems using unicode filenames have been fixed
**Misc:**
* Build scripts have been further improved
* Regression test now creates single monolithic .html file for easier uploading
* Regression test auto-starts & stops Xvfb / Xvnc if on headless unix machine
* The backend is finally independent of Qt
* Windows: We now have a 64-bit version
**Known Bugs:**
* Linux: command-line png rendering on Gallium is flaky.
Workaround: use CGAL --render or hardware rendering.

48
releases/2014.03.md Normal file
View File

@ -0,0 +1,48 @@
**Language Features:**
* Added diameter argument: circle(d), cylinder(d, d1, d2) and sphere(d)
* Added parent_module() and $parent_modules
* Added children() as a replacement for child()
* Unicode strings (using UTF-8) are now correctly handled
* Ranges can have a negative step value
* Added norm() and cross() functions
**Program Features:**
* Cmd-line: --info parameter prints system/library info
* Cmd-line: --csglimit parameter to change CSG rendering limit
* Cmd-line: Better handling of cmd-line arguments under Windows
* GUI: Added Reset View
* GUI: Added Search&Replace in editor
* GUI: Syntax highlighting now has a dark background theme
* GUI: We now create a backup file before rendering to allow for recovery if OpenSCAD crashes/freezes
* GUI: Accessibility features enabled (e.g. screenreading)
**Bugfixes/improvements:**
* Reading empty STL files sometimes caused a crash
* OPENSCADPATH now uses semicolon as path separator under Windows
* polyhedron() is now much more robust handling almost planar polygons
* Automatic reloads of large designs are more robust
* Boolean logic in if() statements are now correctly short-circuited
* rands() with zero range caused an infinite loop
* resize(, auto=true) didn't work when shrinking objects
* The $children variable sometimes misbehaved due to dynamic scoping
* The --camera cmd-line option behaved differently then the corresponding GUI function
* PNG export now doesn't leak transparency settings into the target image
* Improved performance of 3D hull() operations
* Some editor misbehaviors were fixed
* Stability fixes of CGAL-related crashes
* Windows cmd-line can now handle spaces in filenames
* Default CSG rendering limit is now 100K elements
* Fixed a crash reading DXF files using comma as decimal separator
* Fixed a crash running the cmd-line without a HOME env. variable
* Intersecting something with nothing now correctly results in an empty object
**Deprecations:**
* child() is no longer supported. Use children() instead.
* polyhedron(triangles=[...]): Use polyhedron(faces=[...]) instead.
**Misc:**
* Test framework now shares more code with the GUI app
* Test report can now be automatically uploaded to dinkypage.com
* Better compatibility with BSD systems
* Qt5 support

View File

@ -47,50 +47,126 @@
init_variables()
{
BRANCH_TO_BUILD=unstable
#BRANCH_TO_BUILD=master
STARTPATH=$PWD
export STARTPATH
# kilobit (not kilobyte!) per second for scp upload
RATELIMIT=420
DOBUILD=1
DOUPLOAD=1
DRYRUN=
DOSNAPSHOT=1
DOLOOP=
#solar day
LOOPSLEEP=86400
DATECODE=`date +"%Y.%m.%d"`
if [ "`echo $* | grep loop`" ]; then
echo "----------------------------"
echo "loop mode activated! woopee!"
echo "----------------------------"
DOLOOP=1
fi
if [ "`echo $* | grep release`" ]; then
echo "this script cannot yet build releases, only snapshots"
DOSNAPSHOT=
exit 1
fi
if [ "`echo $* | grep uploadonly`" ]; then
DOUPLOAD=1
DOBUILD=
DATECODE=`date +"%Y.%m.%d"`
fi
if [ "`echo $* | grep buildonly`" ]; then
DOUPLOAD=
DOBUILD=1
DATECODE=`date +"%Y.%m.%d"`
fi
if [ "`echo $* | grep dry`" ]; then
DRYRUN=1
fi
export STARTPATH
export BRANCH_TO_BUILD
export DOBUILD
export DOUPLOAD
export DRYRUN
export DATECODE
export DOSNAPSHOT
export DOLOOP
export LOOPSLEEP
export RATELIMIT
export DATECODE
}
check_starting_path()
{
cd $STARTPATH
if [ -e openscad.pro ]; then
echo 'please start from a clean directory outside of openscad'
exit
fi
}
check_nsis()
{
# 64 bit mingw-cross build MXE cannot build nsis.... for now, we can
# just ask the user to install their system's nsis package.
# (it might be possible to d/l & build nsis here, or use pre-existing
# 32-bit-mxe nsis)
if [ ! "`command -v makensis`" ]; then
echo the makensis command was not found.
echo please install nsis for your system. for example
echo on debian, sudo apt-get install nsis
exit 1
else
echo makensis found.
fi
}
get_openscad_source_code()
{
git clone http://github.com/openscad/openscad.git
if [ "`echo $? | grep 0`" ]; then
if [ -d openscad ]; then
cd openscad
if [ $? -ne 0 ]; then
echo cd to 'openscad' directory failed
exit 1
fi
git checkout $BRANCH_TO_BUILD
if [ $? -ne 0 ]; then
echo git checkout $BRANCH_TO_BUILD failed
exit 1
fi
git fetch -a
if [ $? -ne 0 ]; then
echo git fetch -a openscad source code failed
exit 1
fi
git pull origin $BRANCH_TO_BUILD
if [ $? -ne 0 ]; then
echo git pull origin $BRANCH_TO_BUILD failed
exit 1
fi
git submodule update # MCAD
return
else
git clone http://github.com/openscad/openscad.git
fi
if [ $? -eq 0 ]; then
echo clone of source code is ok
else
echo clone of openscad source code failed. exiting
exit 1
if [ $DOUPLOAD ]; then
if [ ! $DOBUILD ]; then
echo upload only - skipping openscad git clone
fi
else
echo clone of openscad source code failed. exiting
exit 1
fi
fi
cd openscad
git checkout $BRANCH_TO_BUILD
if [ $? -ne 0 ]; then
echo git checkout $BRANCH_TO_BUILD failed
exit 1
fi
git submodule update --init # MCAD
#git checkout branch ##debugging
}
build_win32()
@ -98,15 +174,18 @@ build_win32()
. ./scripts/setenv-mingw-xbuild.sh clean
. ./scripts/setenv-mingw-xbuild.sh
./scripts/mingw-x-build-dependencies.sh
./scripts/release-common.sh mingw32
if [ "`echo $? | grep 0`" ]; then
if [ $DOSNAPSHOT ] ; then
./scripts/release-common.sh snapshot mingw32 tests
else
echo "this script cant yet build releases, only snapshots"
exit 1
fi
if [ $? -eq 0 ]; then
echo build of win32 stage over
else
echo build of win32 failed. exiting
exit 1
fi
DATECODE=`date +"%Y.%m.%d"`
export DATECODE
}
build_win64()
@ -114,24 +193,30 @@ build_win64()
. ./scripts/setenv-mingw-xbuild.sh clean
. ./scripts/setenv-mingw-xbuild.sh 64
./scripts/mingw-x-build-dependencies.sh 64
./scripts/release-common.sh mingw64
if [ "`echo $? | grep 0`" ]; then
if [ $DOSNAPSHOT ] ; then
./scripts/release-common.sh snapshot mingw64 tests
else
echo "this script cant yet build releases, only snapshots"
exit 1
fi
if [ $? -eq 0 ]; then
echo build of win64 stage over
else
echo build of win64 failed. exiting
exit 1
fi
DATECODE=`date +"%Y.%m.%d"`
export DATECODE
}
build_lin32()
{
. ./scripts/setenv-unibuild.sh
./scripts/uni-build-dependencies.sh
./scripts/release-common.sh
DATECODE=`date +"%Y.%m.%d"`
export DATECODE
if [ $DOSNAPSHOT ] ; then
./scripts/release-common.sh snapshot
else
echo "this script cant yet build releases, only snapshots"
exit 1
fi
}
upload_win_common()
@ -143,16 +228,21 @@ upload_win_common()
echo 'file "'$filename'" found'
else
echo 'file "'$filename'" not found'
exit 1
fi
opts=
opts="$opts -p openscad"
opts="$opts -u $username"
opts="$opts $filename"
remotepath=www/
if [ $DOSNAPSHOT ]; then
remotepath=www/snapshots/
fi
if [ $DRYRUN ]; then
echo dry run, not uploading to files.openscad.org
echo scp -v $filename openscad@files.openscad.org:www/
echo scp -v -l $RATELIMIT $filename openscad@files.openscad.org:$remotepath
else
scp -v $filename openscad@files.openscad.org:www/
scp -v -l $RATELIMIT $filename openscad@files.openscad.org:$remotepath
fi
}
@ -160,39 +250,52 @@ upload_win32()
{
SUMMARY1="Windows x86-32 Snapshot Installer"
SUMMARY2="Windows x86-32 Snapshot Zipfile"
DATECODE=`date +"%Y.%m.%d"`
SUMMARY3="Windows x86-32 Snapshot Tests"
BASEDIR=./mingw32/
WIN32_PACKAGEFILE1=OpenSCAD-$DATECODE-x86-32-Installer.exe
WIN32_PACKAGEFILE2=OpenSCAD-$DATECODE-x86-32.zip
WIN32_PACKAGEFILE3=OpenSCAD-Tests-$DATECODE-x86-32.zip
upload_win_common "$SUMMARY1" $USERNAME $BASEDIR/$WIN32_PACKAGEFILE1
upload_win_common "$SUMMARY2" $USERNAME $BASEDIR/$WIN32_PACKAGEFILE2
upload_win_common "$SUMMARY3" $USERNAME $BASEDIR/$WIN32_PACKAGEFILE3
export WIN32_PACKAGEFILE1
export WIN32_PACKAGEFILE2
export WIN32_PACKAGEFILE3
WIN32_PACKAGEFILE1_SIZE=`ls -sh $BASEDIR/$WIN32_PACKAGEFILE1 | awk ' {print $1} ';`
WIN32_PACKAGEFILE2_SIZE=`ls -sh $BASEDIR/$WIN32_PACKAGEFILE2 | awk ' {print $1} ';`
WIN32_PACKAGEFILE3_SIZE=`ls -sh $BASEDIR/$WIN32_PACKAGEFILE3 | awk ' {print $1} ';`
WIN32_PACKAGEFILE1_SIZE=`echo "$WIN32_PACKAGEFILE1_SIZE""B"`
WIN32_PACKAGEFILE2_SIZE=`echo "$WIN32_PACKAGEFILE2_SIZE""B"`
WIN32_PACKAGEFILE3_SIZE=`echo "$WIN32_PACKAGEFILE3_SIZE""B"`
export WIN32_PACKAGEFILE1_SIZE
export WIN32_PACKAGEFILE2_SIZE
export WIN32_PACKAGEFILE3_SIZE
}
upload_win64()
{
SUMMARY1="Windows x86-64 Snapshot Zipfile"
SUMMARY2="Windows x86-64 Snapshot Installer"
SUMMARY3="Windows x86-64 Snapshot Tests"
BASEDIR=./mingw64/
WIN64_PACKAGEFILE1=OpenSCAD-$DATECODE-x86-64-Installer.exe
WIN64_PACKAGEFILE2=OpenSCAD-$DATECODE-x86-64.zip
WIN64_PACKAGEFILE3=OpenSCAD-Tests-$DATECODE-x86-64.zip
upload_win_common "$SUMMARY1" $USERNAME $BASEDIR/$WIN64_PACKAGEFILE1
upload_win_common "$SUMMARY2" $USERNAME $BASEDIR/$WIN64_PACKAGEFILE2
upload_win_common "$SUMMARY3" $USERNAME $BASEDIR/$WIN64_PACKAGEFILE3
export WIN64_PACKAGEFILE1
export WIN64_PACKAGEFILE2
export WIN64_PACKAGEFILE3
WIN64_PACKAGEFILE1_SIZE=`ls -sh $BASEDIR/$WIN64_PACKAGEFILE1 | awk ' {print $1} ';`
WIN64_PACKAGEFILE2_SIZE=`ls -sh $BASEDIR/$WIN64_PACKAGEFILE2 | awk ' {print $1} ';`
WIN64_PACKAGEFILE3_SIZE=`ls -sh $BASEDIR/$WIN64_PACKAGEFILE3 | awk ' {print $1} ';`
WIN64_PACKAGEFILE1_SIZE=`echo "$WIN64_PACKAGEFILE1_SIZE""B"`
WIN64_PACKAGEFILE2_SIZE=`echo "$WIN64_PACKAGEFILE2_SIZE""B"`
WIN64_PACKAGEFILE3_SIZE=`echo "$WIN64_PACKAGEFILE3_SIZE""B"`
export WIN64_PACKAGEFILE1_SIZE
export WIN64_PACKAGEFILE2_SIZE
export WIN64_PACKAGEFILE3_SIZE
}
read_username_from_user()
@ -234,29 +337,38 @@ read_password_from_user()
update_win_www_download_links()
{
cd $STARTPATH
rm -rf ./openscad.github.com
git clone git@github.com:openscad/openscad.github.com.git
cd openscad.github.com
cd inc
echo `pwd`
# BASEURL='https://openscad.googlecode.com/files/'
BASEURL='http://files.openscad.org/'
DATECODE=`date +"%Y.%m.%d"`
if [ $DOSNAPSHOT ]; then
BASEURL='http://files.openscad.org/snapshots/'
fi
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
echo "fileinfo['WIN64_SNAPSHOT3_URL'] = '$BASEURL$WIN64_PACKAGEFILE3'" >> win_snapshot_links.js
echo "fileinfo['WIN64_SNAPSHOT1_NAME'] = 'OpenSCAD $DATECODE'" >> win_snapshot_links.js
echo "fileinfo['WIN64_SNAPSHOT2_NAME'] = 'OpenSCAD $DATECODE'" >> win_snapshot_links.js
echo "fileinfo['WIN64_SNAPSHOT3_NAME'] = 'OpenSCAD Tests $DATECODE'" >> win_snapshot_links.js
echo "fileinfo['WIN64_SNAPSHOT1_SIZE'] = '$WIN64_PACKAGEFILE1_SIZE'" >> win_snapshot_links.js
echo "fileinfo['WIN64_SNAPSHOT2_SIZE'] = '$WIN64_PACKAGEFILE2_SIZE'" >> win_snapshot_links.js
echo "fileinfo['WIN64_SNAPSHOT3_SIZE'] = '$WIN64_PACKAGEFILE3_SIZE'" >> win_snapshot_links.js
echo "fileinfo['WIN32_SNAPSHOT1_URL'] = '$BASEURL$WIN32_PACKAGEFILE1'" >> win_snapshot_links.js
echo "fileinfo['WIN32_SNAPSHOT2_URL'] = '$BASEURL$WIN32_PACKAGEFILE2'" >> win_snapshot_links.js
echo "fileinfo['WIN32_SNAPSHOT3_URL'] = '$BASEURL$WIN32_PACKAGEFILE3'" >> win_snapshot_links.js
echo "fileinfo['WIN32_SNAPSHOT1_NAME'] = 'OpenSCAD $DATECODE'" >> win_snapshot_links.js
echo "fileinfo['WIN32_SNAPSHOT2_NAME'] = 'OpenSCAD $DATECODE'" >> win_snapshot_links.js
echo "fileinfo['WIN32_SNAPSHOT3_NAME'] = 'OpenSCAD Tests $DATECODE'" >> win_snapshot_links.js
echo "fileinfo['WIN32_SNAPSHOT1_SIZE'] = '$WIN32_PACKAGEFILE1_SIZE'" >> win_snapshot_links.js
echo "fileinfo['WIN32_SNAPSHOT2_SIZE'] = '$WIN32_PACKAGEFILE2_SIZE'" >> win_snapshot_links.js
echo "fileinfo['WIN32_SNAPSHOT3_SIZE'] = '$WIN32_PACKAGEFILE3_SIZE'" >> win_snapshot_links.js
echo 'modified win_snapshot_links.js'
PAGER=cat git diff
@ -266,6 +378,7 @@ update_win_www_download_links()
else
echo dry run, not updating www links
fi
cd $STARTPATH
}
# FIXME: We might be running this locally and not need an ssh agent.
@ -274,30 +387,55 @@ update_win_www_download_links()
check_ssh_agent()
{
if [ $DRYRUN ]; then echo 'skipping ssh, dry run'; return; fi
if [ $SSH_AUTH_SKIP ]; then
return
fi
if [ ! $SSH_AUTH_SOCK ]; then
echo 'please start an ssh-agent for github.com/openscad/openscad.github.com uploads'
echo 'for example:'
echo
echo ' ssh-agent > .tmp && source .tmp && ssh-add'
echo
echo 'to force a run anyway, set SSH_AUTH_SKIP environment variable to 1'
exit 1
fi
}
init_variables $*
if [ $DOUPLOAD ]; then
check_ssh_agent
fi
check_starting_path
read_username_from_user
read_password_from_user
get_openscad_source_code
if [ $DOBUILD ]; then
build_win32
build_win64
fi
if [ $DOUPLOAD ]; then
upload_win32
upload_win64
update_win_www_download_links
fi
main()
{
init_variables $*
if [ $DOUPLOAD ]; then
check_ssh_agent
fi
check_starting_path
check_nsis
read_username_from_user
read_password_from_user
get_openscad_source_code
if [ $DOBUILD ]; then
build_win32
build_win64
fi
if [ $DOUPLOAD ]; then
upload_win32
upload_win64
update_win_www_download_links
fi
}
if [ $DOLOOP ]; then
while [ 1 ]; do
init_variables $*
main $*
echo ---------------------------------------------------
echo main loop finished. repeating in $LOOPSLEEP seconds
echo ---------------------------------------------------
sleep $LOOPSLEEP
#if [ "`uname | grep -i linux`" ]; then
# rtcwake -m mem -s 86400
#fi
done
else
main $*
fi

View File

@ -37,13 +37,9 @@ debug()
eigen_sysver()
{
debug eigen
eigpath=
eig3path=$1/include/eigen3/Eigen/src/Core/util/Macros.h
eig2path=$1/include/eigen2/Eigen/src/Core/util/Macros.h
if [ -e $eig3path ]; then eigpath=$eig3path; fi
if [ -e $eig2path ]; then eigpath=$eig2path; fi
debug $eig2path
if [ ! $eigpath ]; then return; fi
eigpath=$1/include/eigen3/Eigen/src/Core/util/Macros.h
debug $eigpath
if [ ! -e $eigpath ]; then return; fi
eswrld=`grep "define *EIGEN_WORLD_VERSION *[0-9]*" $eigpath | awk '{print $3}'`
esmaj=`grep "define *EIGEN_MAJOR_VERSION *[0-9]*" $eigpath | awk '{print $3}'`
esmin=`grep "define *EIGEN_MINOR_VERSION *[0-9]*" $eigpath | awk '{print $3}'`
@ -71,20 +67,25 @@ glib2_sysver()
#Get architecture triplet - e.g. x86_64-linux-gnu
glib2archtriplet=`gcc -dumpmachine 2>/dev/null`
if [ -z "$VAR" ]; then
glib2archtriplet=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null`
if [ "`command -v dpkg-architectures`" ]; then
glib2archtriplet=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null`
fi
fi
glib2path=$1/lib/$glib2archtriplet/glib-2.0/include/glibconfig.h
if [ ! -e $glib2path ]; then
#No glib found
#glib can be installed in /usr/lib/i386-linux-gnu/glib-2.0/ on arch i686-linux-gnu (sometimes?)
if [ $glib2archtriplet = "i686-linux-gnu" ]; then
if [ "$glib2archtriplet" = "i686-linux-gnu" ]; then
glib2archtriplet=i386-linux-gnu
glib2path=$1/lib/$glib2archtriplet/glib-2.0/include/glibconfig.h
if [ ! -e $glib2path ]; then return; fi
else
return;
fi
fi
if [ ! -e $glib2path ]; then
glib2path=$1/lib/glib-2.0/include/glibconfig.h
fi
if [ ! -e $glib2path ]; then
return
fi
glib2major=`grep "define *GLIB_MAJOR_VERSION *[0-9.]*" $glib2path | awk '{print $3}'`
glib2minor=`grep "define *GLIB_MINOR_VERSION *[0-9.]*" $glib2path | awk '{print $3}'`
glib2micro=`grep "define *GLIB_MICRO_VERSION *[0-9.]*" $glib2path | awk '{print $3}'`

7
scripts/github-release.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
# Usage (in github root folder): ./scripts/github-release.sh <version>
#
# Requires release.token and releases/<version>.md
curl https://api.github.com/repos/openscad/openscad/releases -H "Authorization: token $(<release.token)" -d "$(./scripts/makereleasejson.py $1)"

View File

@ -30,7 +30,6 @@ OPTION_LLVM=false
OPTION_CLANG=false
OPTION_GCC=false
OPTION_DEPLOY=false
export QMAKESPEC=macx-g++
printUsage()
{
@ -114,6 +113,21 @@ build_qt()
make -j6 install
}
build_qt5()
{
version=$1
echo "Building Qt" $version "..."
cd $BASEDIR/src
rm -rf qt-everywhere-opensource-src-$version
if [ ! -f qt-everywhere-opensource-src-$version.tar.gz ]; then
curl -O -L http://download.qt-project.org/official_releases/qt/5.2/$version/single/qt-everywhere-opensource-src-$version.tar.gz
fi
tar xzf qt-everywhere-opensource-src-$version.tar.gz
cd qt-everywhere-opensource-src-$version
./configure -prefix $DEPLOYDIR -release -opensource -confirm-license -nomake examples -nomake tests -no-xcb -no-c++11
make -j6 install
}
# Hack warning: gmplib is built separately in 32-bit and 64-bit mode
# and then merged afterwards. gmplib's header files are dependent on
# the CPU architecture on which configure was run and will be patched accordingly.
@ -523,7 +537,6 @@ elif $USING_CLANG; then
echo "Using clang compiler"
export CC=clang
export CXX=clang++
export QMAKESPEC=unsupported/macx-clang
fi
echo "Building for $MAC_OSX_VERSION_MIN or later"
@ -548,7 +561,7 @@ fi
echo "Using basedir:" $BASEDIR
mkdir -p $SRCDIR $DEPLOYDIR
build_qt 4.8.5
build_qt5 5.2.1
# NB! For eigen, also update the path in the function
build_eigen 3.2.0
build_gmp 5.1.3

View File

@ -20,7 +20,6 @@ OPENSCADDIR=$PWD
BASEDIR=$OPENSCADDIR/../libraries
DEPLOYDIR=$BASEDIR/homebrew
MAC_OSX_VERSION_MIN=10.7
export QMAKESPEC=unsupported/macx-clang
OPTION_DEPLOY=false
@ -65,8 +64,8 @@ export MACOSX_DEPLOYMENT_TARGET=$MAC_OSX_VERSION_MIN
# Don't use bottles, as they might be built with the wrong deployment target
export HOMEBREW_BUILD_FROM_SOURCE=1
for formula in qt eigen boost cgal glew glib opencsg freetype libxml2 fontconfig harfbuzz; do
brew install --verbose openscad/tap/$formula --macosx-deployment-target=$MAC_OSX_VERSION_MIN
for formula in qt5 eigen boost cgal glew glib opencsg freetype libxml2 fontconfig harfbuzz; do
brew install openscad/tap/$formula
done
if $OPTION_DEPLOY; then
brew install --HEAD openscad/tap/sparkle

13
scripts/makereleasejson.py Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env python
# Used by github-release.sh
import sys
import json
v = sys.argv[1]
print(json.JSONEncoder().encode({
'tag_name': 'openscad-'+v,
'name': 'OpenSCAD '+v,
'body': open('./releases/'+v+'.md').read()
}))

9
scripts/makereleasenotes.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
echo "" > RELEASE_NOTES
for v in `ls -r releases/*.md`; do
mdfile=${v#releases/}
version=${mdfile%.md}
echo "# OpenSCAD $version\n" >> RELEASE_NOTES
cat $v >> RELEASE_NOTES
done

View File

@ -58,19 +58,21 @@ fi
echo "entering" $MXEDIR
cd $MXEDIR
echo 'checkout stable branch'
git checkout stable
if [ "`echo $* | grep 64`" ]; then
MXE_TARGETS='x86_64-w64-mingw32'
if [ "`echo $* | grep download`" ]; then
PACKAGES='download-mpfr download-eigen download-opencsg download-cgal download-qt download-glib download-freetype download-fontconfig download-harfbuzz'
PACKAGES='download-mpfr download-eigen download-opencsg download-cgal download-qt download-qt5 download-glib download-freetype download-fontconfig download-harfbuzz'
else
PACKAGES='mpfr eigen opencsg cgal qt glib freetype fontconfig harfbuzz'
PACKAGES='qt qt5 mpfr eigen opencsg cgal glib freetype fontconfig harfbuzz'
fi
else
MXE_TARGETS='i686-pc-mingw32' # fixme - does this work? test it.
MXE_TARGETS='i686-pc-mingw32'
if [ "`echo $* | grep download`" ]; then
PACKAGES='download-mpfr download-eigen download-opencsg download-cgal download-qt download-nsis download-glib download-freetype download-fontconfig download-harfbuzz'
PACKAGES='download-mpfr download-eigen download-opencsg download-cgal download-qt download-qt5 download-nsis download-glib download-freetype download-fontconfig download-harfbuzz'
else
PACKAGES='mpfr eigen opencsg cgal qt nsis glib freetype fontconfig harfbuzz'
PACKAGES='qt qt5 mpfr eigen opencsg cgal nsis glib freetype fontconfig harfbuzz'
fi
fi
echo make $PACKAGES MXE_TARGETS=$MXE_TARGETS -j $NUMCPU JOBS=$NUMJOBS

View File

@ -1,8 +1,9 @@
#!/bin/sh
# NB! To build a release build, the VERSION and VERSIONDATE environment variables needs to be set.
# See doc/release-checklist.txt
export NUMCPU=$(sysctl -n hw.ncpu)
human_filesize()
{
awk -v sum=$1 'BEGIN {
@ -20,8 +21,9 @@ update_www_download_links()
local $*
filesize=$(human_filesize $filesize)
webdir=../openscad.github.com
# FIXME: release vs. snapshot
incfile=inc/mac_snapshot_links.js
BASEURL='http://files.openscad.org/'
BASEURL='http://files.openscad.org/snapshots'
DATECODE=`date +"%Y.%m.%d"`
if [ -f $webdir/$incfile ]; then
@ -43,20 +45,27 @@ if test -z "$VERSIONDATE"; then
fi
if test -z "$VERSION"; then
VERSION=$VERSIONDATE
COMMIT=-c
SNAPSHOT=true
SNAPSHOT=snapshot
fi
# Turn off ccache, just for safety
PATH=${PATH//\/opt\/local\/libexec\/ccache:}
# FIXME: Somehow, setting the deployment target to a lower version causes a
# seldom crash in debug mode (e.g. the minkowski2-test):
# frame #4: 0x00007fff8b7d5be5 libc++.1.dylib`std::runtime_error::~runtime_error() + 55
# frame #5: 0x0000000100150df5 OpenSCAD`CGAL::Uncertain_conversion_exception::~Uncertain_conversion_exception(this=0x0000000105044488) + 21 at Uncertain.h:78
# The reason for the crash appears to be linking with libgcc_s,
# but it's unclear what's really going on
export MACOSX_DEPLOYMENT_TARGET=10.6
# This is the same location as DEPLOYDIR in macosx-build-dependencies.sh
export OPENSCAD_LIBRARIES=$PWD/../libraries/install
# Make sure that the correct Qt tools are used
export PATH=$OPENSCAD_LIBRARIES/bin:$PATH
`dirname $0`/release-common.sh -v $VERSION $COMMIT
`dirname $0`/release-common.sh -v $VERSION $SNAPSHOT
if [[ $? != 0 ]]; then
exit 1
fi
@ -83,7 +92,7 @@ if [[ $VERSION == $VERSIONDATE ]]; then
fi
echo "Uploading..."
scp OpenSCAD-$VERSION.dmg openscad@files.openscad.org:www
scp OpenSCAD-$VERSION.dmg openscad@files.openscad.org:www/snapshots
if [[ $? != 0 ]]; then
exit 1
fi

View File

@ -1,28 +1,47 @@
#!/bin/bash
#
# This script creates a binary release of OpenSCAD. This should work
# under Mac OS X, Linux 32, Linux 64, and Linux->Win32 MXE cross-build.
# under Mac OS X, Linux 32bit, Linux 64bit, and Linux->Win32 MXE cross-build.
# Windows under msys has not been tested recently.
#
# The script will create a file called openscad-<versionstring>.<extension> in
# the current directory (or under ./mingw32)
# the current directory (or under ./mingw32 or ./mingw64)
#
# Usage: release-common.sh [-v <versionstring>] [-c] [-mingw[32|64]]
# Usage: release-common.sh [-v <versionstring>] [-c] [-mingw[32|64]] [-tests]
# -v Version string (e.g. -v 2010.01)
# -d Version date (e.g. -d 2010.01.23)
# -c Build with commit info
# -mingw32 Cross-compile for win32 using MXE
# -mingw64 Cross-compile for win64 using Tony Theodore's MXE fork
# -mingw64 Cross-compile for win64 using MXE
# -snapshot Build a snapshot binary (make e.g. experimental features available, build with commit info)
# -tests Build additional package containing the regression tests
#
# If no version string or version date is given, todays date will be used (YYYY-MM-DD)
# If only verion date is given, it will be used also as version string.
# If only version date is given, it will be used also as version string.
# If no make target is given, release will be used on Windows, none one Mac OS X
#
# The commit info will extracted from git and be passed to qmake as OPENSCAD_COMMIT
# to identify a build in the about box.
#
# The mingw cross compile depends on the MXE cross-build tools. Please
# see the README.md file on how to install these dependencies.
# see the README.md file on how to install these dependencies. To debug
# the mingw-cross build process, set env var FAKEMAKE=1 to fake-make the
# .exe files
#
# convert end-of-line in given file from unix \n to dos/windows(TM) \r\n
# see https://kb.iu.edu/data/acux.html
lf2crlf()
{
fname=$1
if [ "`command -v unix2dos`" ]; then
unix2dos $fname
return
fi
if [ "`command -v awk`" ]; then
echo using awk to convert end of line markers in $fname
awk 'sub("$", "\r")' $fname > $fname".temp"
mv $fname".temp" $fname
return
fi
echo 'warning- cant change eol to cr eol'
}
printUsage()
{
@ -37,6 +56,8 @@ if [ ! -f $OPENSCADDIR/openscad.pro ]; then
exit 1
fi
CONFIG=deploy
if [[ "$OSTYPE" =~ "darwin" ]]; then
OS=MACOSX
elif [[ $OSTYPE == "msys" ]]; then
@ -63,6 +84,16 @@ if [ "`echo $* | grep mingw64`" ]; then
echo Mingw-cross build using ARCH=64
fi
if [ "`echo $* | grep snapshot`" ]; then
CONFIG="$CONFIG experimental"
OPENSCAD_COMMIT=`git log -1 --pretty=format:"%h"`
fi
BUILD_TESTS=
if [ "`echo $* | grep tests`" ]; then
BUILD_TESTS=1
fi
if [ $OS ]; then
echo "Detected OS: $OS"
else
@ -75,7 +106,6 @@ do
case $c in
v) VERSION=$OPTARG;;
d) VERSIONDATE=$OPTARG;;
c) OPENSCAD_COMMIT=`git log -1 --pretty=format:"%h"`
esac
done
@ -86,6 +116,14 @@ if test -z "$VERSION"; then
VERSION=$VERSIONDATE
fi
export VERSIONDATE
export VERSION
if [ $FAKEMAKE ]; then
echo 'fake make on:' $FAKEMAKE
else
FAKEMAKE=
fi
echo "Checking pre-requisites..."
@ -95,9 +133,17 @@ case $OS in
if [ "`command -v makensis`" ]; then
MAKENSIS=makensis
elif [ "`command -v i686-pc-mingw32-makensis`" ]; then
# we cant find systems nsis so look for the MXE's version.
# MXE has its own makensis, but its only available under
# 32-bit MXE. note that the cross-version in theory works
# the same as the linux version so we can use them, in
# theory, interchangeably. its not really a 'cross' nsis
# todo - when doing 64 bit mingw build, see if we can call
# 32bit nsis here.
MAKENSIS=i686-pc-mingw32-makensis
else
echo "makensis not found. please install nsis"
echo "makensis not found. please install nsis on your system."
echo "(for example, on debian linux, try apt-get install nsis)"
exit 1
fi
echo NSIS makensis found: $MAKENSIS
@ -116,7 +162,7 @@ if [ -d .git ]; then
git submodule update
fi
echo "Building openscad-$VERSION ($VERSIONDATE) $CONFIGURATION..."
echo "Building openscad-$VERSION ($VERSIONDATE) $CONFIG..."
if [ ! $NUMCPU ]; then
echo "note: you can 'export NUMCPU=x' for multi-core compiles (x=number)";
@ -124,7 +170,8 @@ if [ ! $NUMCPU ]; then
fi
echo "NUMCPU: " $NUMCPU
CONFIG=deploy
case $OS in
LINUX|MACOSX)
TARGET=
@ -148,11 +195,11 @@ esac
case $OS in
UNIX_CROSS_WIN)
cd $DEPLOYDIR && qmake VERSION=$VERSION OPENSCAD_COMMIT=$OPENSCAD_COMMIT CONFIG+=$CONFIG CONFIG+=mingw-cross-env CONFIG-=debug ../openscad.pro
cd $DEPLOYDIR && qmake VERSION=$VERSION OPENSCAD_COMMIT=$OPENSCAD_COMMIT CONFIG+="$CONFIG" CONFIG+=mingw-cross-env CONFIG-=debug ../openscad.pro
cd $OPENSCADDIR
;;
*)
qmake VERSION=$VERSION OPENSCAD_COMMIT=$OPENSCAD_COMMIT CONFIG+=$CONFIG CONFIG-=debug openscad.pro
qmake VERSION=$VERSION OPENSCAD_COMMIT=$OPENSCAD_COMMIT CONFIG+="$CONFIG" CONFIG-=debug openscad.pro
;;
esac
@ -184,11 +231,17 @@ case $OS in
;;
esac
echo "Building GUI binary..."
case $OS in
UNIX_CROSS_WIN)
# make main openscad.exe
cd $DEPLOYDIR
make $TARGET -j$NUMCPU ## comment 4 test
if [ $FAKEMAKE ]; then
echo "notexe. debugging build process" > $TARGET/openscad.exe
else
make $TARGET -j$NUMCPU
fi
if [ ! -e $TARGET/openscad.exe ]; then
echo "cant find $TARGET/openscad.exe. build failed. stopping."
exit
@ -200,9 +253,15 @@ case $OS in
echo "cant find $TARGET/openscad.com. build failed. stopping."
exit
fi
cd $OPENSCADDIR
;;
LINUX)
if [ $FAKEMAKE ]; then
echo "notexe. debugging build process" > $TARGET/openscad
else
make $TARGET -j$NUMCPU
fi
;;
*)
make -j$NUMCPU $TARGET
;;
@ -213,6 +272,45 @@ if [[ $? != 0 ]]; then
exit 1
fi
echo "Building test suite..."
if [ $BUILD_TESTS ]; then
case $OS in
UNIX_CROSS_WIN)
TESTBUILD_MACHINE=x86_64-w64-mingw32
# dont use build-machine trilpe in TESTBINDIR because the 'mingw32'
# will confuse people who are on 64 bit machines
TESTBINDIR=tests-build
export TESTBUILD_MACHINE
export TESTBINDIR
if [[ $ARCH == 32 ]]; then
TESTBUILD_MACHINE=i686-pc-mingw32
fi
cd $DEPLOYDIR
mkdir $TESTBINDIR
cd $TESTBINDIR
cmake $OPENSCADDIR/tests/ \
-DCMAKE_TOOLCHAIN_FILE=../tests/CMingw-cross-env.cmake \
-DMINGW_CROSS_ENV_DIR=$MXEDIR \
-DMACHINE=$TESTBUILD_MACHINE
if [ $FAKEMAKE ]; then
echo "notexe. debugging build process" > openscad_nogui.exe
else
make -j$NUMCPU
fi
if [ ! -e openscad_nogui.exe ]; then
echo 'test cross-build failed'
exit 1
fi
cd $OPENSCADDIR
;;
*)
echo 'test suite build not implemented for osx/linux'
;;
esac
fi # BUILD_TESTS
echo "Creating directory structure..."
case $OS in
@ -222,6 +320,7 @@ case $OS in
FONTDIR=OpenSCAD.app/Contents/Resources/fonts
;;
UNIX_CROSS_WIN)
cd $OPENSCADDIR
EXAMPLESDIR=$DEPLOYDIR/openscad-$VERSION/examples/
LIBRARYDIR=$DEPLOYDIR/openscad-$VERSION/libraries/
FONTDIR=$DEPLOYDIR/openscad-$VERSION/fonts/
@ -238,10 +337,10 @@ case $OS in
esac
if [ -n $EXAMPLESDIR ]; then
echo $EXAMPLESDIR
mkdir -p $EXAMPLESDIR
cp examples/* $EXAMPLESDIR
chmod -R 644 $EXAMPLESDIR/*
echo $EXAMPLESDIR
mkdir -p $EXAMPLESDIR
cp examples/* $EXAMPLESDIR
chmod -R 644 $EXAMPLESDIR/*
fi
if [ -n $FONTDIR ]; then
echo $FONTDIR
@ -249,16 +348,16 @@ if [ -n $FONTDIR ]; then
cp -a fonts/* $FONTDIR
fi
if [ -n $LIBRARYDIR ]; then
echo $LIBRARYDIR
mkdir -p $LIBRARYDIR
# exclude the .git stuff from MCAD which is a git submodule.
# tar is a relatively portable way to do exclusion, without the
# risks of rm
rm -f libraries.tar
tar cf libraries.tar --exclude=.git* libraries
cd $LIBRARYDIR/.. && tar xf $OPENSCADDIR/libraries.tar && cd $OPENSCADDIR
rm -f libraries.tar
chmod -R u=rwx,go=r,+X $LIBRARYDIR/*
echo $LIBRARYDIR
mkdir -p $LIBRARYDIR
# exclude the .git stuff from MCAD which is a git submodule.
# tar is a relatively portable way to do exclusion, without the
# risks of rm
rm -f libraries.tar
tar cf libraries.tar --exclude=.git* libraries
cd $LIBRARYDIR/.. && tar xf $OPENSCADDIR/libraries.tar && cd $OPENSCADDIR
rm -f libraries.tar
chmod -R u=rwx,go=r,+X $LIBRARYDIR/*
fi
echo "Creating archive.."
@ -282,12 +381,13 @@ case $OS in
echo "Binary created: openscad-$VERSION.zip"
;;
UNIX_CROSS_WIN)
cd $OPENSCADDIR
cd $DEPLOYDIR
BINFILE=$DEPLOYDIR/OpenSCAD-$VERSION-x86-$ARCH.zip
INSTFILE=$DEPLOYDIR/OpenSCAD-$VERSION-x86-$ARCH-Installer.exe
#package
echo "Creating binary zip package"
cd $DEPLOYDIR
cp $TARGET/openscad.exe openscad-$VERSION
cp $TARGET/openscad.com openscad-$VERSION
rm -f OpenSCAD-$VERSION.x86-$ARCH.zip
@ -351,3 +451,118 @@ case $OS in
echo
;;
esac
if [ $BUILD_TESTS ]; then
echo "Creating regression tests package..."
case $OS in
MACOSX)
echo 'building regression test package on OSX not implemented'
;;
WIN)
echo 'building regression test package on Win not implemented'
;;
UNIX_CROSS_WIN)
# Build a .zip file containing all the files we need to run a
# ctest on Windows(TM). For the sake of simplicity, we do not
# create an installer for the tests.
echo "Copying files..."
cd $OPENSCADDIR
# This copies a lot of unnecessary stuff but that's OK.
# as above, we use tar as a somewhat portable way to do 'exclude'
# while copying.
rm -f ./ostests.tar
for subdir in tests testdata libraries examples doc; do
tar prvf ./ostests.tar --exclude=.git* --exclude=*/mingw64/* --exclude=*/mingw32/* --exclude=*.cc.obj --exclude=*.a $subdir
done
cd $DEPLOYDIR
tar prvf $OPENSCADDIR/ostests.tar --exclude=.git* --exclude=*/mingw* --exclude=*.cc.obj --exclude=*.a $TESTBINDIR
cd $DEPLOYDIR
if [ -e ./OpenSCAD-Tests-$VERSION ]; then
rm -rf ./OpenSCAD-Tests-$VERSION
fi
mkdir OpenSCAD-Tests-$VERSION
cd OpenSCAD-Tests-$VERSION
tar pxf $OPENSCADDIR/ostests.tar
rm -f $OPENSCADDIR/ostests.tar
# Now we have the basic files copied into our tree that will become
# our .zip file. We also want to move some files around for easier
# access for the user:
cd $DEPLOYDIR
cd ./OpenSCAD-Tests-$VERSION
echo "Copying files for ease of use when running from cmdline"
cp -v ./tests/OpenSCAD_Test_Console.py .
cp -v ./tests/WinReadme.txt .
cp -v ./tests/mingw_convert_ctest.py ./$TESTBINDIR
cp -v ./tests/mingwcon.bat ./$TESTBINDIR
echo "Creating mingw_cross_info.py file"
cd $DEPLOYDIR
cd ./OpenSCAD-Tests-$VERSION
cd $TESTBINDIR
if [ -e ./mingw_cross_info.py ]; then
rm -f ./mingw_cross_info.py
fi
echo "# created automatically by release-common.sh from within linux " >> mingw_cross_info.py
echo "linux_abs_basedir='"$OPENSCADDIR"'" >> mingw_cross_info.py
echo "linux_abs_builddir='"$DEPLOYDIR/$TESTBINDIR"'" >> mingw_cross_info.py
echo "bindir='"$TESTBINDIR"'" >> mingw_cross_info.py
# fixme .. parse CTestTestfiles to find linux+convert python strings
# or have CMake itself dump them during it's cross build cmake call
echo "linux_python='"`which python`"'" >> mingw_cross_info.py
# note- this has to match the CMakeLists.txt line that sets the
# convert executable... and CMingw-cross-env.cmake's skip-imagemagick
# setting. what a kludge!
echo "linux_convert='/bin/echo'" >> mingw_cross_info.py
echo "win_installdir='OpenSCAD_Tests_"$VERSIONDATE"'" >> mingw_cross_info.py
echo 'Converting linefeed to carriage-return+linefeed'
for textfile in `find . | grep txt$`; do lf2crlf $textfile; done
for textfile in `find . | grep py$`; do lf2crlf $textfile; done
for textfile in `find . | grep cmake$`; do lf2crlf $textfile; done
for textfile in `find . | grep bat$`; do lf2crlf $textfile; done
# Test binaries can be hundreds of megabytes due to debugging info.
# By default, we strip that. In most cases we wont need it and it
# causes too many problems to have >100MB files.
echo "stripping .exe binaries"
cd $DEPLOYDIR
cd ./OpenSCAD-Tests-$VERSION
cd $TESTBINDIR
if [ "`command -v $TESTBUILD_MACHINE'-strip' `" ]; then
for exefile in *exe; do
ls -sh $exefile
echo $TESTBUILD_MACHINE'-strip' $exefile
$TESTBUILD_MACHINE'-strip' $exefile
ls -sh $exefile
done
fi
# Build the actual .zip archive based on the file tree we've built above
cd $DEPLOYDIR
ZIPFILE=OpenSCAD-Tests-$VERSION-x86-$ARCH.zip
echo "Creating binary zip package for Tests:" $ZIPFILE
rm -f ./$ZIPFILE
"$ZIP" $ZIPARGS $ZIPFILE OpenSCAD-Tests-$VERSION
if [ -e $ZIPFILE ]; then
echo "ZIP package created:" `pwd`/$ZIPFILE
else
echo "Build of Regression Tests package failed. Cannot find" `pwd`/$ZIPFILE
exit 1
fi
cd $OPENSCADDIR
;;
LINUX)
echo 'building regression test package on linux not implemented'
;;
esac
else
echo "Not building regression tests package"
fi # BUILD_TESTS

View File

@ -7,6 +7,7 @@
# source ./scripts/setenv-mingw-xbuild.sh # 32 bit build
# source ./scripts/setenv-mingw-xbuild.sh 64 # 64 bit build
# source ./scripts/setenv-mingw-xbuild.sh clean # Clean up exported variables
# source ./scripts/setenv-mingw-xbuild.sh qt5 # use qt5 (experimental)
#
# Prerequisites:
#
@ -40,6 +41,15 @@ if [ ! $MXEDIR ]; then
fi
fi
if [ ! $MXEQTSUBDIR ]; then
if [ "`echo $* | grep qt5 `" ]; then
MXEQTSUBDIR=qt5
else
# qt4 is just 'qt', see http://mxe.cc
MXEQTSUBDIR=qt
fi
fi
if [ ! -e $DEPLOYDIR ]; then
mkdir -p $DEPLOYDIR
fi
@ -56,7 +66,7 @@ if [ ! $MINGWX_SAVED_ORIGINAL_PATH ]; then
fi
PATH=$MXEDIR/usr/bin:$PATH
PATH=$MXETARGETDIR/qt/bin:$PATH
PATH=$MXETARGETDIR/$MXEQTSUBDIR/bin:$PATH
OPENSCAD_LIBRARIES=$MXETARGETDIR
@ -68,6 +78,7 @@ if [ "`echo $* | grep clean`" ]; then
DEPLOYDIR=
PATH=$MINGWX_SAVED_ORIGINAL_PATH
MINGWX_SAVED_ORIGINAL_PATH=
MXEQTSUBDIR=
else
echo 'linking' $MXETARGETDIR
echo ' to' $DEPLOYDIR/mingw-cross-env
@ -82,16 +93,18 @@ export MXETARGETDIR
export DEPLOYDIR
export PATH
export MINGWX_SAVED_ORIGINAL_PATH
export MXEQTSUBDIR
echo OPENSCAD_LIBRARIES: $OPENSCAD_LIBRARIES
echo BASEDIR: $BASEDIR
echo MXEDIR: $MXEDIR
echo MXETARGETDIR: $MXETARGETDIR
echo DEPLOYDIR: $DEPLOYDIR
echo MXEQTSUBDIR: $MXEQTSUBDIR
if [ "`echo $* | grep clean`" ]; then
echo PATH restored to pre-setenv-mingw-x state
else
echo PATH modified: $MXEDIR/usr/bin
echo PATH modified: $MXETARGETDIR/qt/bin
echo PATH modified: $MXETARGETDIR/$MXEQTSUBDIR/bin
fi

View File

@ -32,11 +32,13 @@
# If your system lacks qt4, build like this:
#
# ./scripts/uni-build-dependencies.sh qt4
# . ./scripts/setenv-unibuild.sh
# . ./scripts/setenv-unibuild.sh #(Rerun to re-detect qt4)
#
# If your system lacks glu, try to build like this:
# If your system lacks glu, gettext, or glib2, you can build them as well:
#
# ./scripts/uni-build-dependencies.sh glu
# ./scripts/uni-build-dependencies.sh glib2
# ./scripts/uni-build-dependencies.sh gettext
#
# If you want to try Clang compiler (experimental, only works on linux):
#
@ -528,6 +530,101 @@ build_eigen()
}
# glib2 and dependencies
build_gettext()
{
version=$1
echo "Building gettext $version..."
cd "$BASEDIR"/src
rm -rf "gettext-$version"
if [ ! -f "glib-$version.tar.gz" ]; then
curl --insecure -LO "http://ftpmirror.gnu.org/gettext/gettext-$version.tar.gz"
fi
tar xzf "gettext-$version.tar.gz"
cd "gettext-$version"
./configure --prefix="$DEPLOYDIR"
make -j$NUMCPU
make install
}
build_pkgconfig()
{
if [ "`command -v pkg-config`" ]; then
echo "pkg-config already installed. not building"
return
fi
version=$1
echo "Building pkg-config $version..."
cd "$BASEDIR"/src
rm -rf "pkg-config-$version"
if [ ! -f "pkg-config-$version.tar.gz" ]; then
curl --insecure -LO "http://pkgconfig.freedesktop.org/releases/pkg-config-$version.tar.gz"
fi
tar xzf "pkg-config-$version.tar.gz"
cd "pkg-config-$version"
./configure --prefix="$DEPLOYDIR" --with-internal-glib
make -j$NUMCPU
make install
}
build_libffi()
{
if [ -e $DEPLOYDIR/include/ffi.h ]; then
echo "libffi already installed. not building"
return
fi
version=$1
echo "Building libffi $version..."
cd "$BASEDIR"/src
rm -rf "libffi-$version"
if [ ! -f "libffi-$version.tar.gz" ]; then
curl --insecure -LO "ftp://sourceware.org/pub/libffi/libffi-$version.tar.gz"
curl --insecure -LO "http://www.linuxfromscratch.org/patches/blfs/svn/libffi-$version-includedir-1.patch"
fi
tar xzf "libffi-$version.tar.gz"
cd "libffi-$version"
if [ ! "`command -v patch`" ]; then
echo cannot proceed, need 'patch' program
exit 1
fi
patch -Np1 -i ../libffi-3.0.13-includedir-1.patch
./configure --prefix="$DEPLOYDIR"
make -j$NUMCPU
make install
}
build_glib2()
{
version="$1"
maj_min_version="${version%.*}" #Drop micro
if [ -e $DEPLOYDIR/lib/glib-2.0 ]; then
echo "glib2 already installed. not building"
return
fi
echo "Building glib2 $version..."
cd "$BASEDIR"/src
rm -rf "glib-$version"
if [ ! -f "glib-$version.tar.xz" ]; then
curl --insecure -LO "http://ftp.gnome.org/pub/gnome/sources/glib/$maj_min_version/glib-$version.tar.xz"
fi
tar xJf "glib-$version.tar.xz"
cd "glib-$version"
./configure --disable-gtk-doc --disable-man --prefix="$DEPLOYDIR" CFLAGS="-I$DEPLOYDIR/include" LDFLAGS="-L$DEPLOYDIR/lib"
make -j$NUMCPU
make install
}
## end of glib2 stuff
# this section allows 'out of tree' builds, as long as the system has
# the 'dirname' command installed
@ -582,7 +679,8 @@ fi
if [ ! "`command -v cmake`" ]; then
build_cmake 2.8.8
fi
if [ "`cmake --version | grep 'version 2.[1-6][^0-9]'`" ]; then
# see README for needed version (this should match 1<minimum)
if [ "`cmake --version | grep 'version 2.[1-8][^0-9][1-4] '`" ]; then
build_cmake 2.8.8
fi
@ -610,6 +708,19 @@ if [ $1 ]; then
build_glu 9.0.0
exit $?
fi
if [ $1 = "gettext" ]; then
# such a huge build, put here by itself
build_gettext 0.18.3.1
exit $?
fi
if [ $1 = "glib2" ]; then
# such a huge build, put here by itself
build_pkgconfig 0.28
build_libffi 3.0.13
#build_gettext 0.18.3.1
build_glib2 2.38.2
exit $?
fi
fi
@ -618,7 +729,11 @@ fi
#
# Main build of libraries
# edit version numbers here as needed.
# This is only for libraries most systems won't have new enough versions of.
# For big things like Qt4, see the notes at the head of this file on
# building individual dependencies.
#
build_eigen 3.1.1
build_gmp 5.0.5
build_mpfr 3.1.1

View File

@ -1,15 +1,15 @@
# auto-install dependency packages using the systems package manager.
# after running this, run ./script/check-dependencies.sh. see README.md
#
# this assumes you have sudo installed or are running as root.
# this assumes you have sudo installed and running, or are running as root.
#
get_fedora_deps()
{
sudo yum install qt-devel bison flex eigen3-devel python-paramiko \
yum install qt-devel bison flex eigen3-devel \
boost-devel mpfr-devel gmp-devel glew-devel CGAL-devel gcc gcc-c++ pkgconfig \
opencsg-devel git libXmu-devel curl imagemagick ImageMagick glib2-devel make \
xorg-x11-server-Xvfb
xorg-x11-server-Xvfb gettext
}
get_qomo_deps()
@ -21,7 +21,7 @@ get_altlinux_deps()
{
for i in boost-devel boost-filesystem-devel gcc4.5 gcc4.5-c++ boost-program_options-devel \
boost-thread-devel boost-system-devel boost-regex-devel eigen3 libmpfr libgmp libgmp_cxx-devel qt4-devel libcgal-devel git-core \
libglew-devel flex bison curl imagemagick glib2-devel; do sudo apt-get install $i; done
libglew-devel flex bison curl imagemagick gettext glib2-devel; do apt-get install $i; done
}
get_freebsd_deps()
@ -29,29 +29,29 @@ get_freebsd_deps()
pkg_add -r bison boost-libs cmake git bash eigen3 flex gmake gmp mpfr \
xorg libGLU libXmu libXi xorg-vfbserver glew \
qt4-corelib qt4-gui qt4-moc qt4-opengl qt4-qmake qt4-rcc qt4-uic \
opencsg cgal curl imagemagick glib2-devel
opencsg cgal curl imagemagick glib2-devel gettext
}
get_netbsd_deps()
{
sudo pkgin install bison boost cmake git bash eigen flex gmake gmp mpfr \
qt4 glew cgal opencsg modular-xorg python27 py27-paramiko curl \
imagemagick ImageMagick glib2-devel
pkgin install bison boost cmake git bash eigen3 flex gmake gmp mpfr \
qt4 glew cgal opencsg python27 curl \
ImageMagick glib2 gettext
}
get_opensuse_deps()
{
sudo zypper install libeigen3-devel mpfr-devel gmp-devel boost-devel \
zypper install libeigen3-devel mpfr-devel gmp-devel boost-devel \
libqt4-devel glew-devel cmake git bison flex cgal-devel opencsg-devel curl \
glib2-devel
glib2-devel gettext
}
get_mageia_deps()
{
sudo urpmi ctags
sudo urpmi task-c-devel task-c++-devel libqt4-devel libgmp-devel \
urpmi ctags
urpmi task-c-devel task-c++-devel libqt4-devel libgmp-devel \
libmpfr-devel libboost-devel eigen3-devel libglew-devel bison flex \
cmake imagemagick glib2-devel python curl git x11-server-xvfb
cmake imagemagick glib2-devel python curl git x11-server-xvfb gettext
}
get_debian_deps()
@ -60,8 +60,8 @@ get_debian_deps()
libxmu-dev cmake bison flex git-core libboost-all-dev \
libXi-dev libmpfr-dev libboost-dev libglew-dev \
libeigen3-dev libcgal-dev libopencsg-dev libgmp3-dev libgmp-dev \
python-paramiko curl imagemagick libfontconfig-dev libfreetype6-dev \
libharfbuzz-dev gtk-doc-tools libglib2.0-dev; do
imagemagick libfontconfig-dev libfreetype6-dev \
libharfbuzz-dev gtk-doc-tools libglib2.0-dev gettext; do
sudo apt-get -y install $pkg;
done
}

10
setenv_mac-qt5.sh Normal file
View File

@ -0,0 +1,10 @@
export OPENSCAD_LIBRARIES=$PWD/../libraries/install
export DYLD_LIBRARY_PATH=$OPENSCAD_LIBRARIES/lib
export DYLD_FRAMEWORK_PATH=$OPENSCAD_LIBRARIES/lib
# Our own Qt
export PATH=$OPENSCAD_LIBRARIES/bin:$PATH
# ccache:
export PATH=/opt/local/libexec/ccache:$PATH
export CCACHE_BASEDIR=$PWD/..

View File

@ -23,7 +23,7 @@
</p>
<p>
Copyright (C) 2009-2013 <a href="https://github.com/kintel">Marius Kintel</a> &lt;marius@kintel.net&gt; and <a href="http://clifford.at">Clifford Wolf</a> &lt;clifford@clifford.at&gt;
Copyright (C) 2009-2014 <a href="https://github.com/kintel">Marius Kintel</a> &lt;marius@kintel.net&gt; and <a href="http://clifford.at">Clifford Wolf</a> &lt;clifford@clifford.at&gt;
</p>
<p>
@ -82,6 +82,7 @@ Please visit this link for a copy of the license: <a href="http://www.gnu.org/li
<li><a href="http://www.github.com/GilesBathgate">Giles Bathgate</a>
<li><a href="https://github.com/brad">Brad Pitcher</a>
<li><a href="https://github.com/donbright">Don Bright</a>
<li><a href="https://github.com/t-paul">Torsten Paul</a>
</ul>
<p>
@ -89,29 +90,46 @@ Please visit this link for a copy of the license: <a href="http://www.gnu.org/li
</p>
<ul>
<li><a href="http://www.debian.org">Debian</a> maintainer:</b>
<a href="http://christian.amsuess.com/">chrysn</a></lu>
<a href="http://christian.amsuess.com/">chrysn</a></li>
<li><a href="http://fedoraproject.org/">Fedora</a> maintainer:</b>
<a href="http://hroncok.cz/">Miro Hrončok</a></lu>
<a href="http://hroncok.cz/">Miro Hrončok</a></li>
<li><a href="https://www.archlinux.org">Arch Linux</a> maintainer:</b>
<a href="http://kmkeen.com">Kyle Keen</a></li>
<li><a href="http://www.opensuse.org">openSUSE</a> maintainer:</b>
<a href="http://stick.gk2.sk">Pavol Rusnak</a></li>
</ul>
<p>
<b>Patches</b>
</p>
<lu>
<li><a href="https://github.com/meta23">meta23</a>
<li><a href="https://github.com/jasonblewis">jasonblewis</a>
<li><a href="https://github.com/gregjurman">gregjurman</a>
<li><a href="https://github.com/brianolson">brianolson</a>
<li><a href="https://github.com/tjhowse">tjhowse</a>
<li><a href="https://github.com/logxen">logxen</a>
<li><a href="https://github.com/iamwilhelm">iamwilhelm</a>
<li><a href="https://github.com/clothbot">clothbot</a>
<li><a href="https://github.com/colah">colah</a>
<li><a href="https://github.com/peteruithoven">Peter Uithoven</a>
</lu>
<p>
<a href="https://github.com/meta23">meta23</a>,
<a href="https://github.com/jasonblewis">jasonblewis</a>,
<a href="https://github.com/gregjurman">gregjurman</a>,
<a href="https://github.com/brianolson">brianolson</a>,
<a href="https://github.com/tjhowse">tjhowse</a>,
<a href="https://github.com/logxen">logxen</a>,
<a href="https://github.com/iamwilhelm">iamwilhelm</a>,
<a href="https://github.com/clothbot">clothbot</a>,
<a href="https://github.com/colah">colah</a>,
<a href="https://github.com/peteruithoven">Peter Uithoven</a>,
<a href="https://github.com/tim-caper">tim-caper</a>,
<a href="https://github.com/sjkelly">sjkelly</a>,
<a href="https://github.com/OskarLinde">OskarLinde</a>,
<a href="https://github.com/Ivoah">Ivoah</a>,
<a href="https://github.com/brodykenrick">brodykenrick</a>,
<a href="https://github.com/a-e-m">a-e-m</a>,
<a href="https://github.com/gringer">gringer</a>,
<a href="https://github.com/Gazer">Gazer</a>,
<a href="https://github.com/pdbogen">pdbogen</a>,
<a href="https://github.com/hzeller">hzeller</a>,
<a href="https://github.com/vicnet">vicnet</a>,
<a href="https://github.com/dmopalmer">dmopalmer</a>,
<a href="https://github.com/steelman">steelman</a>,
<a href="https://github.com/ivoknutsel">ivoknutsel</a>,
<a href="https://github.com/achiestdragon">achiestdragon</a>
</p>
<p>
<b>Mailing list, bug reports, testing, contribs, help, &c</b>

View File

@ -24,7 +24,7 @@ void installAppleEventHandlers()
{
// Reload handler
OSErr err = AEInstallEventHandler('SCAD', 'relo', NewAEEventHandlerUPP(eventHandler), 0, true);
require_noerr(err, CantInstallAppleEventHandler);
__Require_noErr(err, CantInstallAppleEventHandler);
return;
CantInstallAppleEventHandler:

View File

@ -178,10 +178,10 @@ Response CSGTermEvaluator::visit(State &state, const RenderNode &node)
shared_ptr<const Geometry> geom;
if (this->geomevaluator) {
geom = this->geomevaluator->evaluateGeometry(node, false);
t1 = evaluate_csg_term_from_geometry(state, this->highlights, this->background,
geom, node.modinst, node);
node.progress_report();
}
t1 = evaluate_csg_term_from_geometry(state, this->highlights, this->background,
geom, node.modinst, node);
this->stored_term[node.index()] = t1;
addToParent(state, node);
}
@ -196,10 +196,10 @@ Response CSGTermEvaluator::visit(State &state, const CgaladvNode &node)
shared_ptr<const Geometry> geom;
if (this->geomevaluator) {
geom = this->geomevaluator->evaluateGeometry(node, false);
t1 = evaluate_csg_term_from_geometry(state, this->highlights, this->background,
geom, node.modinst, node);
node.progress_report();
}
t1 = evaluate_csg_term_from_geometry(state, this->highlights, this->background,
geom, node.modinst, node);
node.progress_report();
this->stored_term[node.index()] = t1;
addToParent(state, node);
}

View File

@ -363,6 +363,7 @@ void GLView::showSmallaxes()
{
// Fixme - this doesnt work in Vector Camera mode
float dpi = this->getDPI();
// Small axis cross in the lower left corner
glDepthFunc(GL_ALWAYS);
@ -374,14 +375,14 @@ void GLView::showSmallaxes()
glRotated(cam.object_rot.y(), 0.0, 1.0, 0.0);
glRotated(cam.object_rot.z(), 0.0, 0.0, 1.0);
glLineWidth(1);
glLineWidth(dpi);
glBegin(GL_LINES);
glColor3d(1.0, 0.0, 0.0);
glVertex3d(0, 0, 0); glVertex3d(10, 0, 0);
glVertex3d(0, 0, 0); glVertex3d(10*dpi, 0, 0);
glColor3d(0.0, 1.0, 0.0);
glVertex3d(0, 0, 0); glVertex3d(0, 10, 0);
glVertex3d(0, 0, 0); glVertex3d(0, 10*dpi, 0);
glColor3d(0.0, 0.0, 1.0);
glVertex3d(0, 0, 0); glVertex3d(0, 0, 10);
glVertex3d(0, 0, 0); glVertex3d(0, 0, 10*dpi);
glEnd();
GLdouble mat_model[16];
@ -394,15 +395,15 @@ void GLView::showSmallaxes()
glGetIntegerv(GL_VIEWPORT, viewport);
GLdouble xlabel_x, xlabel_y, xlabel_z;
gluProject(12, 0, 0, mat_model, mat_proj, viewport, &xlabel_x, &xlabel_y, &xlabel_z);
gluProject(12*dpi, 0, 0, mat_model, mat_proj, viewport, &xlabel_x, &xlabel_y, &xlabel_z);
xlabel_x = round(xlabel_x); xlabel_y = round(xlabel_y);
GLdouble ylabel_x, ylabel_y, ylabel_z;
gluProject(0, 12, 0, mat_model, mat_proj, viewport, &ylabel_x, &ylabel_y, &ylabel_z);
gluProject(0, 12*dpi, 0, mat_model, mat_proj, viewport, &ylabel_x, &ylabel_y, &ylabel_z);
ylabel_x = round(ylabel_x); ylabel_y = round(ylabel_y);
GLdouble zlabel_x, zlabel_y, zlabel_z;
gluProject(0, 0, 12, mat_model, mat_proj, viewport, &zlabel_x, &zlabel_y, &zlabel_z);
gluProject(0, 0, 12*dpi, mat_model, mat_proj, viewport, &zlabel_x, &zlabel_y, &zlabel_z);
zlabel_x = round(zlabel_x); zlabel_y = round(zlabel_y);
glMatrixMode(GL_PROJECTION);
@ -419,18 +420,19 @@ void GLView::showSmallaxes()
// r=g=b=0;
// bgcol.getRgb(&r, &g, &b);
// glColor3f((255.0f-r)/255.0f, (255.0f-g)/255.0f, (255.0f-b)/255.0f);
float d = 3*dpi;
glColor3f(0.0f, 0.0f, 0.0f);
glBegin(GL_LINES);
// X Label
glVertex3d(xlabel_x-3, xlabel_y-3, 0); glVertex3d(xlabel_x+3, xlabel_y+3, 0);
glVertex3d(xlabel_x-3, xlabel_y+3, 0); glVertex3d(xlabel_x+3, xlabel_y-3, 0);
glVertex3d(xlabel_x-d, xlabel_y-d, 0); glVertex3d(xlabel_x+d, xlabel_y+d, 0);
glVertex3d(xlabel_x-d, xlabel_y+d, 0); glVertex3d(xlabel_x+d, xlabel_y-d, 0);
// Y Label
glVertex3d(ylabel_x-3, ylabel_y-3, 0); glVertex3d(ylabel_x+3, ylabel_y+3, 0);
glVertex3d(ylabel_x-3, ylabel_y+3, 0); glVertex3d(ylabel_x, ylabel_y, 0);
glVertex3d(ylabel_x-d, ylabel_y-d, 0); glVertex3d(ylabel_x+d, ylabel_y+d, 0);
glVertex3d(ylabel_x-d, ylabel_y+d, 0); glVertex3d(ylabel_x, ylabel_y, 0);
// Z Label
glVertex3d(zlabel_x-3, zlabel_y-3, 0); glVertex3d(zlabel_x+3, zlabel_y-3, 0);
glVertex3d(zlabel_x-3, zlabel_y+3, 0); glVertex3d(zlabel_x+3, zlabel_y+3, 0);
glVertex3d(zlabel_x-3, zlabel_y-3, 0); glVertex3d(zlabel_x+3, zlabel_y+3, 0);
glVertex3d(zlabel_x-d, zlabel_y-d, 0); glVertex3d(zlabel_x+d, zlabel_y-d, 0);
glVertex3d(zlabel_x-d, zlabel_y+d, 0); glVertex3d(zlabel_x+d, zlabel_y+d, 0);
glVertex3d(zlabel_x-d, zlabel_y-d, 0); glVertex3d(zlabel_x+d, zlabel_y+d, 0);
// FIXME - depends on gimbal camera 'viewer distance'.. how to fix this
// for VectorCamera?
glEnd();
@ -445,10 +447,11 @@ void GLView::showAxes()
// FIXME: doesn't work under Vector Camera
// Large gray axis cross inline with the model
// FIXME: This is always gray - adjust color to keep contrast with background
glLineWidth(1);
float dpi = this->getDPI();
glLineWidth(1*dpi);
glColor3d(0.5, 0.5, 0.5);
glBegin(GL_LINES);
double l = cam.viewer_distance/10;
double l = cam.viewer_distance*dpi/10;
glVertex3d(-l, 0, 0);
glVertex3d(+l, 0, 0);
glVertex3d(0, -l, 0);

View File

@ -55,6 +55,7 @@ public:
virtual bool save(const char *filename) = 0;
virtual std::string getRendererInfo() const = 0;
virtual float getDPI() { return 1.0f; }
Renderer *renderer;
Camera cam;

View File

@ -2,6 +2,9 @@
#include "printutils.h"
#include "Geometry.h"
#ifdef DEBUG
#ifndef ENABLE_CGAL
#define ENABLE_CGAL
#endif
#include "CGAL_Nef_polyhedron.h"
#endif

View File

@ -6,6 +6,7 @@
#include "Polygon2d.h"
#include "module.h"
#include "state.h"
#include "offsetnode.h"
#include "transformnode.h"
#include "linearextrudenode.h"
#include "rotateextrudenode.h"
@ -92,37 +93,24 @@ GeometryEvaluator::ResultObject GeometryEvaluator::applyToChildren(const Abstrac
*/
GeometryEvaluator::ResultObject GeometryEvaluator::applyToChildren3D(const AbstractNode &node, OpenSCADOperator op)
{
if (op == OPENSCAD_HULL) {
return ResultObject(applyHull3D(node));
}
Geometry::ChildList children = collectChildren3D(node);
if (children.size() == 0) return ResultObject();
if (op == OPENSCAD_HULL) {
CGAL_Polyhedron P;
if (CGALUtils::applyHull(children, P)) {
return ResultObject(new CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron3(P)));
}
else {
return ResultObject();
}
}
// Only one child -> this is a noop
if (children.size() == 1) return ResultObject(children.front().second);
CGAL_Nef_polyhedron *N = NULL;
BOOST_FOREACH(const Geometry::ChildItem &item, children) {
const shared_ptr<const Geometry> &chgeom = item.second;
shared_ptr<const CGAL_Nef_polyhedron> chN;
if (!chgeom) {
chN.reset(new CGAL_Nef_polyhedron); // Create null polyhedron
}
else {
chN = dynamic_pointer_cast<const CGAL_Nef_polyhedron>(chgeom);
if (!chN) {
const PolySet *chps = dynamic_cast<const PolySet*>(chgeom.get());
if (chps) chN.reset(createNefPolyhedronFromGeometry(*chps));
}
}
if (N) CGALUtils::applyBinaryOperator(*N, *chN, op);
// Initialize N on first iteration with first expected geometric object
else if (chN) N = chN->copy();
item.first->progress_report();
}
CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron;
CGALUtils::applyOperator(children, *N, op);
return ResultObject(N);
}
@ -415,6 +403,33 @@ Response GeometryEvaluator::visit(State &state, const AbstractNode &node)
return ContinueTraversal;
}
Response GeometryEvaluator::visit(State &state, const OffsetNode &node)
{
if (state.isPrefix() && isSmartCached(node)) return PruneTraversal;
if (state.isPostfix()) {
shared_ptr<const Geometry> geom;
if (!isSmartCached(node)) {
const Geometry *geometry = applyToChildren2D(node, OPENSCAD_UNION);
if (geometry) {
const Polygon2d *polygon = dynamic_cast<const Polygon2d*>(geometry);
// ClipperLib documentation: The formula for the number of steps in a full
// circular arc is ... Pi / acos(1 - arc_tolerance / abs(delta))
double n = Calc::get_fragments_from_r(10, node.fn, node.fs, node.fa);
double arc_tolerance = abs(node.delta) * (1 - cos(M_PI / n));
const Polygon2d *result = ClipperUtils::applyOffset(*polygon, node.delta, node.join_type, node.miter_limit, arc_tolerance);
assert(result);
geom.reset(result);
delete geometry;
}
}
else {
geom = smartCacheGet(node);
}
addToParent(state, node, geom);
}
return ContinueTraversal;
}
/*!
RenderNodes just pass on convexity
*/

View File

@ -31,6 +31,7 @@ public:
virtual Response visit(State &state, const ProjectionNode &node);
virtual Response visit(State &state, const RenderNode &node);
virtual Response visit(State &state, const TextNode &node);
virtual Response visit(State &state, const OffsetNode &node);
const Tree &getTree() const { return this->tree; }

View File

@ -10,6 +10,14 @@
#include "memory.h"
#include <vector>
#include <QMutex>
#include <QSet>
enum export_type_e {
EXPORT_TYPE_UNKNOWN,
EXPORT_TYPE_STL,
EXPORT_TYPE_AMF,
EXPORT_TYPE_OFF
};
class MainWindow : public QMainWindow, public Ui::MainWindow
{
@ -19,7 +27,6 @@ public:
static void requestOpenFile(const QString &filename);
QString fileName;
class Highlighter *highlighter;
class Preferences *prefs;
@ -70,7 +77,6 @@ private slots:
void updateTVal();
void setFileName(const QString &filename);
void setFont(const QString &family, uint size);
void setSyntaxHighlight(const QString &s);
void showProgress();
void openCSGSettingsChanged();
@ -88,6 +94,9 @@ private:
static void consoleOutput(const std::string &msg, void *userdata);
void loadViewSettings();
void loadDesignSettings();
void saveBackup();
void writeBackup(class QFile *file);
QString get2dExportFilename(QString format, QString extension);
class QMessageBox *openglbox;
class FontListDialog *font_list_dialog;
@ -138,18 +147,22 @@ private slots:
void actionRenderDone(shared_ptr<const class Geometry>);
void cgalRender();
#endif
void actionCheckValidity();
void actionDisplayAST();
void actionDisplayCSGTree();
void actionDisplayCSGProducts();
void actionExportSTLorOFF(bool stl_mode);
void actionExport(export_type_e, const char *, const char *);
void actionExportSTL();
void actionExportOFF();
void actionExportAMF();
void actionExportDXF();
void actionExportSVG();
void actionExportCSG();
void actionExportImage();
void actionFlushCaches();
public:
static QSet<MainWindow*> *windows;
static void setExamplesDir(const QString &dir) { MainWindow::qexamplesdir = dir; }
void viewModeActionsUncheck();
void setCurrentOutput();
@ -179,7 +192,7 @@ public slots:
void viewCenter();
void viewPerspective();
void viewOrthogonal();
void viewResetView();
void viewResetView();
void hideConsole();
void animateUpdateDocChanged();
void animateUpdate();
@ -200,10 +213,14 @@ private:
char const * afterCompileSlot;
bool procevents;
class QTemporaryFile *tempFile;
class ProgressWidget *progresswidget;
class CGALWorker *cgalworker;
QMutex consolemutex;
signals:
void highlightError(int);
void unhighlightLastError();
};
class GuiLocker

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>681</width>
<width>846</width>
<height>647</height>
</rect>
</property>
@ -15,16 +15,7 @@
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>0</number>
</property>
<item>
@ -32,14 +23,14 @@
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="editorlayoutwidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<widget class="QWidget" name="editorPane" native="true">
<property name="enabled">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="margin">
<number>0</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<item>
<widget class="QFrame" name="find_panel">
<property name="enabled">
@ -60,72 +51,8 @@
<property name="lineWidth">
<number>0</number>
</property>
<layout class="QGridLayout" name="horizontalLayout">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="verticalSpacing">
<number>0</number>
</property>
<item row="1" column="3" colspan="2">
<widget class="QPushButton" name="replaceButton">
<property name="text">
<string>Replace</string>
</property>
</widget>
</item>
<item row="1" column="5">
<widget class="QPushButton" name="replaceAllButton">
<property name="text">
<string>All</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLineEdit" name="findInputField">
<property name="placeholderText">
<string>Search string</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLineEdit" name="replaceInputField">
<property name="placeholderText">
<string>Replacement string</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="prevButton">
<property name="text">
<string>&lt;</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="nextButton">
<property name="text">
<string>&gt;</string>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QPushButton" name="hideFindButton">
<property name="text">
<string>Done</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QComboBox" name="findTypeComboBox">
<item>
<property name="text">
@ -139,6 +66,55 @@
</item>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="findInputField">
<property name="placeholderText">
<string>Search string</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="prevButton">
<property name="text">
<string>&lt;</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="nextButton">
<property name="text">
<string>&gt;</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="hideFindButton">
<property name="text">
<string>Done</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="replaceInputField">
<property name="placeholderText">
<string>Replacement string</string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="2">
<widget class="QPushButton" name="replaceButton">
<property name="text">
<string>Replace</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="replaceAllButton">
<property name="text">
<string>All</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -150,6 +126,9 @@
<pointsize>8</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::WheelFocus</enum>
</property>
</widget>
</item>
</layout>
@ -163,6 +142,9 @@
</property>
<widget class="QGLView" name="qglview" native="true"/>
<widget class="QTextEdit" name="console">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
@ -183,17 +165,8 @@
<property name="lineWidth">
<number>0</number>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<layout class="QHBoxLayout" name="horizontalLayoutAnimate">
<property name="margin">
<number>0</number>
</property>
<item>
@ -247,7 +220,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>681</width>
<width>846</width>
<height>22</height>
</rect>
</property>
@ -265,16 +238,33 @@
<string>Examples</string>
</property>
</widget>
<widget class="QMenu" name="menuExport">
<property name="title">
<string>Export</string>
</property>
<addaction name="designActionExportSTL"/>
<addaction name="designActionExportOFF"/>
<addaction name="designActionExportAMF"/>
<addaction name="designActionExportDXF"/>
<addaction name="designActionExportSVG"/>
<addaction name="designActionExportCSG"/>
<addaction name="separator"/>
<addaction name="designActionExportImage"/>
</widget>
<addaction name="fileActionNew"/>
<addaction name="fileActionOpen"/>
<addaction name="menuOpenRecent"/>
<addaction name="menuExamples"/>
<addaction name="fileShowLibraryFolder"/>
<addaction name="separator"/>
<addaction name="fileActionReload"/>
<addaction name="fileActionClose"/>
<addaction name="separator"/>
<addaction name="fileActionSave"/>
<addaction name="fileActionSaveAs"/>
<addaction name="fileActionReload"/>
<addaction name="separator"/>
<addaction name="menuExport"/>
<addaction name="separator"/>
<addaction name="fileShowLibraryFolder"/>
<addaction name="separator"/>
<addaction name="fileActionQuit"/>
</widget>
<widget class="QMenu" name="menu_Edit">
@ -316,16 +306,11 @@
<addaction name="designActionPreview"/>
<addaction name="designActionRender"/>
<addaction name="separator"/>
<addaction name="designCheckValidity"/>
<addaction name="designActionDisplayAST"/>
<addaction name="designActionDisplayCSGTree"/>
<addaction name="designActionDisplayCSGProducts"/>
<addaction name="separator"/>
<addaction name="designActionExportSTL"/>
<addaction name="designActionExportOFF"/>
<addaction name="designActionExportDXF"/>
<addaction name="designActionExportCSG"/>
<addaction name="designActionExportImage"/>
<addaction name="separator"/>
<addaction name="designActionFlushCaches"/>
</widget>
<widget class="QMenu" name="menu_View">
@ -351,6 +336,9 @@
<addaction name="viewActionDiagonal"/>
<addaction name="viewActionCenter"/>
<addaction name="separator"/>
<addaction name="viewActionZoomIn"/>
<addaction name="viewActionZoomOut"/>
<addaction name="separator"/>
<addaction name="viewActionResetView"/>
<addaction name="separator"/>
<addaction name="viewActionPerspective"/>
@ -372,8 +360,8 @@
</widget>
<addaction name="menu_File"/>
<addaction name="menu_Edit"/>
<addaction name="menu_View"/>
<addaction name="menu_Design"/>
<addaction name="menu_View"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
@ -558,6 +546,11 @@
<string>F6</string>
</property>
</action>
<action name="designCheckValidity">
<property name="text">
<string>Check Validity</string>
</property>
</action>
<action name="designActionDisplayAST">
<property name="text">
<string>Display &amp;AST...</string>
@ -888,6 +881,32 @@
<string>Font List</string>
</property>
</action>
<action name="designActionExportSVG">
<property name="text">
<string>Export as SVG...</string>
</property>
</action>
<action name="designActionExportAMF">
<property name="text">
<string>Export as AMF...</string>
</property>
</action>
<action name="viewActionZoomIn">
<property name="text">
<string>Zoom In</string>
</property>
<property name="shortcut">
<string>Ctrl+]</string>
</property>
</action>
<action name="viewActionZoomOut">
<property name="text">
<string>Zoom Out</string>
</property>
<property name="shortcut">
<string>Ctrl+[</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@ -22,51 +22,68 @@
ModuleCache *ModuleCache::inst = NULL;
/*!
Reevaluate the given file and recompile if necessary.
Returns NULL on any error (e.g. compile error or file not found)
Reevaluate the given file and all it's dependencies and recompile anything
needing reevaluation. Updates the cache if necessary.
The given filename must be absolute.
If the given filename is relative, it means that the module hasn't been
previously located.
Sets the module reference to the new module, or NULL on any error (e.g. compile
error or file not found).
Returns true if anything was compiled (module or dependencies) and false otherwise.
*/
FileModule *ModuleCache::evaluate(const std::string &filename)
bool ModuleCache::evaluate(const std::string &filename, FileModule *&module)
{
FileModule *lib_mod = (this->entries.find(filename) != this->entries.end()) ?
&(*this->entries[filename].module) : NULL;
FileModule *lib_mod = NULL;
bool found = false;
if (this->entries.find(filename) != this->entries.end()) {
found = true;
lib_mod = this->entries[filename].module;
}
// Don't try to recursively evaluate - if the file changes
// during evaluation, that would be really bad.
if (lib_mod && lib_mod->isHandlingDependencies()) return lib_mod;
bool shouldCompile = true;
if (lib_mod && lib_mod->isHandlingDependencies()) return false;
// Create cache ID
struct stat st;
memset(&st, 0, sizeof(struct stat));
bool valid = (stat(filename.c_str(), &st) == 0);
// If file isn't there, just return and let the cache retain the old module
if (!valid) return NULL;
// If file isn't there, just return and let the cache retain the old module
if (!valid) return false;
// If the file is present, we'll always cache some result
std::string cache_id = str(boost::format("%x.%x") % st.st_mtime % st.st_size);
// Lookup in cache
if (lib_mod) {
if (this->entries[filename].cache_id == cache_id) {
cache_entry &entry = this->entries[filename];
// Initialize entry, if new
if (!found) {
entry.module = NULL;
entry.cache_id = cache_id;
}
bool shouldCompile = true;
if (found) {
// Files should only be recompiled if the cache ID changed
if (entry.cache_id == cache_id) {
shouldCompile = false;
if (lib_mod->includesChanged()) {
// Recompile if includes changed
if (lib_mod && lib_mod->includesChanged()) {
lib_mod = NULL;
shouldCompile = true;
}
}
}
else {
shouldCompile = valid;
}
#ifdef DEBUG
// Causes too much debug output
//if (!shouldCompile) PRINTB("Using cached library: %s (%p)", filename % lib_mod);
#endif
// If cache lookup failed (non-existing or old timestamp), compile module
if (shouldCompile) {
#ifdef DEBUG
if (this->entries.find(filename) != this->entries.end()) {
if (found) {
PRINTB("Recompiling cached library: %s (%s)", filename % cache_id);
}
else {
@ -79,42 +96,33 @@ FileModule *ModuleCache::evaluate(const std::string &filename)
std::ifstream ifs(filename.c_str());
if (!ifs.is_open()) {
PRINTB("WARNING: Can't open library file '%s'\n", filename);
return NULL;
return false;
}
textbuf << ifs.rdbuf();
}
textbuf << "\n" << commandline_commands;
print_messages_push();
FileModule *oldmodule = NULL;
cache_entry e = { NULL, cache_id };
if (this->entries.find(filename) != this->entries.end()) {
oldmodule = this->entries[filename].module;
}
this->entries[filename] = e;
FileModule *oldmodule = lib_mod;
std::string pathname = boosty::stringy(fs::path(filename).parent_path());
lib_mod = dynamic_cast<FileModule*>(parse(textbuf.str().c_str(), pathname.c_str(), false));
PRINTB_NOCACHE(" compiled module: %p", lib_mod);
if (lib_mod) {
// We defer deletion so we can ensure that the new module won't
// have the same address as the old
delete oldmodule;
this->entries[filename].module = lib_mod;
} else {
this->entries.erase(filename);
}
// We defer deletion so we can ensure that the new module won't
// have the same address as the old
if (oldmodule) delete oldmodule;
entry.module = lib_mod;
entry.cache_id = cache_id;
print_messages_pop();
}
module = lib_mod;
bool depschanged = lib_mod ? lib_mod->handleDependencies() : false;
if (lib_mod) {
lib_mod->handleDependencies();
}
return lib_mod;
return shouldCompile || depschanged;
}
void ModuleCache::clear()
@ -124,7 +132,11 @@ void ModuleCache::clear()
FileModule *ModuleCache::lookup(const std::string &filename)
{
return (this->entries.find(filename) != this->entries.end()) ?
&(*this->entries[filename].module) : NULL;
return isCached(filename) ? this->entries[filename].module : NULL;
}
bool ModuleCache::isCached(const std::string &filename)
{
return this->entries.find(filename) != this->entries.end();
}

View File

@ -8,8 +8,9 @@ class ModuleCache
{
public:
static ModuleCache *instance() { if (!inst) inst = new ModuleCache; return inst; }
class FileModule *evaluate(const std::string &filename);
bool evaluate(const std::string &filename, class FileModule *&module);
class FileModule *lookup(const std::string &filename);
bool isCached(const std::string &filename);
size_t size() { return this->entries.size(); }
void clear();

View File

@ -1,6 +1,11 @@
#include "PlatformUtils.h"
#import <Foundation/Foundation.h>
std::string PlatformUtils::pathSeparatorChar()
{
return ":";
}
std::string PlatformUtils::documentsPath()
{
return std::string([[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] UTF8String]);

View File

@ -1,6 +1,11 @@
#include "PlatformUtils.h"
#include "boosty.h"
std::string PlatformUtils::pathSeparatorChar()
{
return ":";
}
std::string PlatformUtils::documentsPath()
{
const char *home = getenv("HOME");

View File

@ -6,6 +6,11 @@
#endif
#include <shlobj.h>
std::string PlatformUtils::pathSeparatorChar()
{
return ";";
}
// convert from windows api w_char strings (usually utf16) to utf8 std::string
std::string winapi_wstr_to_utf8( std::wstring wstr )
{

View File

@ -1,7 +1,9 @@
#include <glib.h>
#include "PlatformUtils.h"
#include "boosty.h"
#include <glib.h>
extern std::vector<std::string> librarypath;
bool PlatformUtils::createLibraryPath()
{
@ -41,6 +43,40 @@ std::string PlatformUtils::libraryPath()
return boosty::stringy( path );
}
std::string PlatformUtils::backupPath()
{
fs::path path;
try {
std::string pathstr = PlatformUtils::documentsPath();
if (pathstr=="") return "";
path = boosty::canonical(fs::path( pathstr ));
if (path.empty()) return "";
path /= "OpenSCAD";
path /= "backups";
} catch (const fs::filesystem_error& ex) {
PRINTB("ERROR: %s",ex.what());
}
return boosty::stringy( path );
}
bool PlatformUtils::createBackupPath()
{
std::string path = PlatformUtils::backupPath();
bool OK = false;
try {
if (!fs::exists(fs::path(path))) {
OK = fs::create_directories( path );
}
if (!OK) {
PRINTB("ERROR: Cannot create %s", path );
}
} catch (const fs::filesystem_error& ex) {
PRINTB("ERROR: %s",ex.what());
}
return OK;
}
#include "version_check.h"
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
@ -108,6 +144,8 @@ std::string PlatformUtils::info()
std::string cgal_2d_kernelEx = "";
#endif // ENABLE_CGAL
const char *env_path = getenv("OPENSCADPATH");
s << "OpenSCAD Version: " << TOSTRING(OPENSCAD_VERSION)
<< "\nCompiler, build date: " << compiler_info << ", " << __DATE__
<< "\nBoost version: " << BOOST_LIB_VERSION
@ -117,8 +155,12 @@ std::string PlatformUtils::info()
<< "\nQt version: " << qtVersion
<< "\nMingW build: " << mingwstatus
<< "\nGLib version: " << GLIB_MAJOR_VERSION << "." << GLIB_MINOR_VERSION << "." << GLIB_MICRO_VERSION
<< "\nOPENSCADPATH: " << getenv("OPENSCADPATH") << "\n"
;
<< "\nOPENSCADPATH: " << (env_path == NULL ? "<not set>" : env_path)
<< "\nOpenSCAD library path:\n";
for (std::vector<std::string>::iterator it = librarypath.begin();it != librarypath.end();it++) {
s << " " << *it << "\n";
}
return s.str();
}

View File

@ -8,7 +8,18 @@ namespace PlatformUtils {
std::string documentsPath();
std::string libraryPath();
bool createLibraryPath();
std::string backupPath();
bool createBackupPath();
std::string info();
/**
* Single character separating path specifications in a list
* (e.g. OPENSCADPATH). On Windows that's ';' and on most other
* systems ':'.
*
* @return the path separator
*/
std::string pathSeparatorChar();
}
#endif

View File

@ -50,11 +50,11 @@ Preferences::Preferences(QWidget *parent) : QMainWindow(parent)
// Editor pane
// Setup default font (Try to use a nice monospace font)
QString fontfamily;
#ifdef Q_WS_X11
#ifdef Q_OS_X11
fontfamily = "Mono";
#elif defined (Q_WS_WIN)
#elif defined (Q_OS_WIN)
fontfamily = "Console";
#elif defined (Q_WS_MAC)
#elif defined (Q_OS_MAC)
fontfamily = "Monaco";
#endif
QFont font;
@ -65,6 +65,12 @@ Preferences::Preferences(QWidget *parent) : QMainWindow(parent)
this->defaultmap["editor/fontsize"] = 12;
this->defaultmap["editor/syntaxhighlight"] = "For Light Background";
#if defined (Q_OS_MAC)
this->defaultmap["editor/ctrlmousewheelzoom"] = false;
#else
this->defaultmap["editor/ctrlmousewheelzoom"] = true;
#endif
uint savedsize = getValue("editor/fontsize").toUInt();
QFontDatabase db;
foreach(uint size, db.standardSizes()) {
@ -95,8 +101,16 @@ Preferences::Preferences(QWidget *parent) : QMainWindow(parent)
QActionGroup *group = new QActionGroup(this);
addPrefPage(group, prefsAction3DView, page3DView);
addPrefPage(group, prefsActionEditor, pageEditor);
#if defined(OPENSCAD_DEPLOY) && defined(Q_OS_MAC)
addPrefPage(group, prefsActionUpdate, pageUpdate);
#else
this->toolBar->removeAction(prefsActionUpdate);
#endif
#ifdef ENABLE_EXPERIMENTAL
addPrefPage(group, prefsActionFeatures, pageFeatures);
#else
this->toolBar->removeAction(prefsActionFeatures);
#endif
addPrefPage(group, prefsActionAdvanced, pageAdvanced);
connect(group, SIGNAL(triggered(QAction*)), this, SLOT(actionTriggered(QAction*)));
@ -365,9 +379,15 @@ void Preferences::on_forceGoldfeatherBox_toggled(bool state)
emit openCSGSettingsChanged();
}
void Preferences::on_mouseWheelZoomBox_toggled(bool state)
{
QSettings settings;
settings.setValue("editor/ctrlmousewheelzoom", state);
}
void Preferences::keyPressEvent(QKeyEvent *e)
{
#ifdef Q_WS_MAC
#ifdef Q_OS_MAC
if (e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period) {
close();
} else
@ -427,6 +447,8 @@ void Preferences::updateGUI()
int shidx = this->syntaxHighlight->findText(shighlight);
if (shidx >= 0) this->syntaxHighlight->setCurrentIndex(shidx);
this->mouseWheelZoomBox->setChecked(getValue("editor/ctrlmousewheelzoom").toBool());
if (AutoUpdater *updater = AutoUpdater::updater()) {
this->updateCheckBox->setChecked(updater->automaticallyChecksForUpdates());
this->snapshotCheckBox->setChecked(updater->enableSnapshots());

View File

@ -32,6 +32,7 @@ public slots:
void on_polysetCacheSizeEdit_textChanged(const QString &);
void on_opencsgLimitEdit_textChanged(const QString &);
void on_forceGoldfeatherBox_toggled(bool);
void on_mouseWheelZoomBox_toggled(bool);
void on_updateCheckBox_toggled(bool);
void on_snapshotCheckBox_toggled(bool);
void on_checkNowButton_clicked();

View File

@ -165,7 +165,7 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<layout class="QHBoxLayout" name="syntaxHighlightLayout">
<property name="bottomMargin">
<number>0</number>
</property>
@ -182,24 +182,14 @@
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Maximum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>30</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QComboBox" name="syntaxHighlight">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>For Light Background</string>
@ -217,6 +207,62 @@
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>30</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="mouseWheelZoomLayout">
<property name="topMargin">
<number>5</number>
</property>
<item>
<widget class="QLabel" name="label_11">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Use Ctrl/Cmd-Mouse-wheel to zoom text</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="mouseWheelZoomBox">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
@ -386,7 +432,7 @@
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QLabel" name="label_9">
<widget class="QLabel" name="label_10">
<property name="font">
<font>
<weight>75</weight>
@ -418,7 +464,7 @@
<x>0</x>
<y>0</y>
<width>803</width>
<height>311</height>
<height>325</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_10">
@ -577,6 +623,12 @@
<property name="allowedAreas">
<set>Qt::TopToolBarArea</set>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextUnderIcon</enum>
</property>

View File

@ -170,25 +170,6 @@ void QGLView::paintGL()
if (running_under_wine) swapBuffers();
}
void QGLView::keyPressEvent(QKeyEvent *event)
{
switch (event->key()) {
case Qt::Key_Plus: // On many keyboards, this requires to press Shift-equals
case Qt::Key_Equal: // ...so simplify this a bit.
cam.viewer_distance *= 0.9;
updateGL();
break;
case Qt::Key_Minus:
cam.viewer_distance /= 0.9;
updateGL();
break;
case Qt::Key_C: // 'center'
cam.object_trans << 0, 0, 0;
updateGL();
break;
}
}
void QGLView::wheelEvent(QWheelEvent *event)
{
cam.viewer_distance *= pow(0.9, event->delta() / 120.0);
@ -197,7 +178,6 @@ void QGLView::wheelEvent(QWheelEvent *event)
void QGLView::mousePressEvent(QMouseEvent *event)
{
setFocus();
mouse_drag_active = true;
last_mouse = event->globalPos();
}
@ -217,7 +197,7 @@ void QGLView::mouseMoveEvent(QMouseEvent *event)
double dy = (this_mouse.y()-last_mouse.y()) * 0.7;
if (mouse_drag_active) {
if (event->buttons() & Qt::LeftButton
#ifdef Q_WS_MAC
#ifdef Q_OS_MAC
&& !(event->modifiers() & Qt::MetaModifier)
#endif
) {
@ -298,3 +278,14 @@ bool QGLView::save(const char *filename)
return img.save(filename, "PNG");
}
void QGLView::ZoomIn(void)
{
cam.viewer_distance *= 0.9;
updateGL();
}
void QGLView::ZoomOut(void)
{
cam.viewer_distance /= 0.9;
updateGL();
}

View File

@ -40,8 +40,15 @@ public:
else this->cam.projection = Camera::PERSPECTIVE;
}
std::string getRendererInfo() const;
#if QT_VERSION >= 0x050001
float getDPI() { return this->devicePixelRatio(); }
#endif
bool save(const char *filename);
void resetView();
void resetView();
public slots:
void ZoomIn(void);
void ZoomOut(void);
public:
QLabel *statusLabel;
@ -52,7 +59,6 @@ private:
bool mouse_drag_active;
QPoint last_mouse;
void keyPressEvent(QKeyEvent *event);
void wheelEvent(QWheelEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);

View File

@ -16,11 +16,21 @@ Builtins *Builtins::instance(bool erase)
void Builtins::init(const char *name, class AbstractModule *module)
{
#ifndef ENABLE_EXPERIMENTAL
if (module->is_experimental()) {
return;
}
#endif
Builtins::instance()->globalscope.modules[name] = module;
}
void Builtins::init(const char *name, class AbstractFunction *function)
{
#ifndef ENABLE_EXPERIMENTAL
if (function->is_experimental()) {
return;
}
#endif
Builtins::instance()->globalscope.functions[name] = function;
}
@ -35,6 +45,7 @@ extern void register_builtin_render();
extern void register_builtin_import();
extern void register_builtin_projection();
extern void register_builtin_cgaladv();
extern void register_builtin_offset();
extern void register_builtin_dxf_linear_extrude();
extern void register_builtin_dxf_rotate_extrude();
extern void register_builtin_text();
@ -61,6 +72,7 @@ void Builtins::initialize()
register_builtin_import();
register_builtin_projection();
register_builtin_cgaladv();
register_builtin_offset();
register_builtin_dxf_linear_extrude();
register_builtin_dxf_rotate_extrude();
register_builtin_text();
@ -82,18 +94,18 @@ std::string Builtins::isDeprecated(const std::string &name)
Builtins::Builtins()
{
this->globalscope.assignments.push_back(Assignment("$fn", new Expression(Value(0.0))));
this->globalscope.assignments.push_back(Assignment("$fs", new Expression(Value(2.0))));
this->globalscope.assignments.push_back(Assignment("$fa", new Expression(Value(12.0))));
this->globalscope.assignments.push_back(Assignment("$t", new Expression(Value(0.0))));
this->globalscope.assignments.push_back(Assignment("$fn", boost::shared_ptr<Expression>(new Expression(Value(0.0)))));
this->globalscope.assignments.push_back(Assignment("$fs", boost::shared_ptr<Expression>(new Expression(Value(2.0)))));
this->globalscope.assignments.push_back(Assignment("$fa", boost::shared_ptr<Expression>(new Expression(Value(12.0)))));
this->globalscope.assignments.push_back(Assignment("$t", boost::shared_ptr<Expression>(new Expression(Value(0.0)))));
Value::VectorType zero3;
zero3.push_back(Value(0.0));
zero3.push_back(Value(0.0));
zero3.push_back(Value(0.0));
Value zero3val(zero3);
this->globalscope.assignments.push_back(Assignment("$vpt", new Expression(zero3val)));
this->globalscope.assignments.push_back(Assignment("$vpr", new Expression(zero3val)));
this->globalscope.assignments.push_back(Assignment("$vpt", boost::shared_ptr<Expression>(new Expression(zero3val))));
this->globalscope.assignments.push_back(Assignment("$vpr", boost::shared_ptr<Expression>(new Expression(zero3val))));
}
Builtins::~Builtins()

View File

@ -49,16 +49,16 @@ AbstractNode *CgaladvModule::instantiate(const Context *ctx, const ModuleInstant
AssignmentList args;
if (type == MINKOWSKI)
args += Assignment("convexity", NULL);
args += Assignment("convexity");
if (type == GLIDE)
args += Assignment("path", NULL), Assignment("convexity", NULL);
args += Assignment("path"), Assignment("convexity");
if (type == SUBDIV)
args += Assignment("type", NULL), Assignment("level", NULL), Assignment("convexity", NULL);
args += Assignment("type"), Assignment("level"), Assignment("convexity");
if (type == RESIZE)
args += Assignment("newsize", NULL), Assignment("auto", NULL);
args += Assignment("newsize"), Assignment("auto");
Context c(ctx);
c.setVariables(args, evalctx);

View File

@ -20,33 +20,15 @@ namespace CGALUtils {
bool applyHull(const Geometry::ChildList &children, CGAL_Polyhedron &result)
{
// Collect point cloud
std::list<CGAL_Polyhedron::Vertex::Point_3> points;
std::vector<CGAL_Polyhedron::Vertex::Point_3> points;
CGAL_Polyhedron P;
BOOST_FOREACH(const Geometry::ChildItem &item, children) {
const shared_ptr<const Geometry> &chgeom = item.second;
const CGAL_Nef_polyhedron *N = dynamic_cast<const CGAL_Nef_polyhedron *>(chgeom.get());
if (N) {
if (!N->p3->is_simple()) {
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 {
bool err = true;
std::string errmsg("");
try {
err = nefworkaround::convert_to_Polyhedron<CGAL_Kernel3>( *(N->p3), P );
// N->p3->convert_to_Polyhedron(P);
}
catch (const CGAL::Failure_exception &e) {
err = true;
errmsg = std::string(e.what());
}
if (err) {
PRINT("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed.");
if (errmsg!="") PRINTB("ERROR: %s",errmsg);
} else {
std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points),
boost::bind(static_cast<const CGAL_Polyhedron::Vertex::Point_3&(CGAL_Polyhedron::Vertex::*)() const>(&CGAL_Polyhedron::Vertex::point), _1));
}
for (CGAL_Nef_polyhedron3::Vertex_const_iterator i = N->p3->vertices_begin(); i != N->p3->vertices_end(); ++i) {
points.push_back(i->point());
}
}
else {
@ -58,16 +40,103 @@ namespace CGALUtils {
}
}
}
if (points.size() > 0) {
// Apply hull
if (points.size() > 3) {
CGAL::convex_hull_3(points.begin(), points.end(), result);
return true;
if (points.size() <= 3) return false;
// Remove all duplicated points (speeds up the convex_hull computation significantly)
std::vector<CGAL_Polyhedron::Vertex::Point_3> unique_points;
Grid3d<int> grid(GRID_FINE);
BOOST_FOREACH(CGAL_Polyhedron::Vertex::Point_3 const& p, points) {
double x = to_double(p.x()), y = to_double(p.y()), z = to_double(p.z());
int& v = grid.align(x,y,z);
if (v == 0) {
unique_points.push_back(CGAL_Polyhedron::Vertex::Point_3(x,y,z));
v = 1;
}
}
return false;
// Apply hull
if (points.size() >= 4) {
CGAL::convex_hull_3(unique_points.begin(), unique_points.end(), result);
return true;
} else {
return false;
}
}
/*!
Applies op to all children and stores the result in dest.
The child list should be guaranteed to contain non-NULL 3D or empty Geometry objects
*/
void applyOperator(const Geometry::ChildList &children, CGAL_Nef_polyhedron &dest, OpenSCADOperator op)
{
// Speeds up n-ary union operations significantly
CGAL::Nef_nary_union_3<CGAL_Nef_polyhedron3> nary_union;
CGAL_Nef_polyhedron *N = NULL;
BOOST_FOREACH(const Geometry::ChildItem &item, children) {
const shared_ptr<const Geometry> &chgeom = item.second;
shared_ptr<const CGAL_Nef_polyhedron> chN =
dynamic_pointer_cast<const CGAL_Nef_polyhedron>(chgeom);
if (!chN) {
const PolySet *chps = dynamic_cast<const PolySet*>(chgeom.get());
if (chps) chN.reset(createNefPolyhedronFromGeometry(*chps));
}
if (op == OPENSCAD_UNION) {
if (!chN->isEmpty()) nary_union.add_polyhedron(*chN->p3);
continue;
}
// Initialize N with first expected geometric object
if (!N) {
N = chN->copy();;
continue;
}
// Intersecting something with nothing results in nothing
if (chN->isEmpty()) {
if (op == OPENSCAD_INTERSECTION) *N = *chN;
continue;
}
// empty op <something> => empty
if (N->isEmpty()) continue;
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
try {
switch (op) {
case OPENSCAD_INTERSECTION:
*N *= *chN;
break;
case OPENSCAD_DIFFERENCE:
*N -= *chN;
break;
case OPENSCAD_MINKOWSKI:
N->minkowski(*chN);
break;
default:
PRINTB("ERROR: Unsupported CGAL operator: %d", op);
}
}
catch (const CGAL::Failure_exception &e) {
// union && difference assert triggered by testdata/scad/bugs/rotate-diff-nonmanifold-crash.scad and testdata/scad/bugs/issue204.scad
std::string opstr = op == OPENSCAD_INTERSECTION ? "intersection" : op == OPENSCAD_DIFFERENCE ? "difference" : op == OPENSCAD_MINKOWSKI ? "minkowski" : "UNKNOWN";
PRINTB("CGAL error in CGALUtils::applyBinaryOperator %s: %s", opstr % e.what());
// Errors can result in corrupt polyhedrons, so put back the old one
*N = *chN;
}
CGAL::set_error_behaviour(old_behaviour);
}
if (op == OPENSCAD_UNION) {
// FIXME: Catch exceptions
N = new CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron3(nary_union.get_union()));
}
dest = *N;
}
/*!
Modifies target by applying op to target and src:
target = target [op] src
@ -118,6 +187,27 @@ namespace CGALUtils {
CGAL::set_error_behaviour(old_behaviour);
}
static void add_outline_to_poly(CGAL_Nef_polyhedron2::Explorer &explorer,
CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator circ,
CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator end,
bool positive,
Polygon2d *poly) {
Outline2d outline;
CGAL_For_all(circ, end) {
if (explorer.is_standard(explorer.target(circ))) {
CGAL_Nef_polyhedron2::Explorer::Point ep = explorer.point(explorer.target(circ));
outline.vertices.push_back(Vector2d(to_double(ep.x()),
to_double(ep.y())));
}
}
if (!outline.vertices.empty()) {
outline.positive = positive;
poly->addOutline(outline);
}
}
static Polygon2d *convertToPolygon2d(const CGAL_Nef_polyhedron2 &p2)
{
Polygon2d *poly = new Polygon2d;
@ -126,19 +216,23 @@ namespace CGALUtils {
typedef Explorer::Face_const_iterator fci_t;
typedef Explorer::Halfedge_around_face_const_circulator heafcc_t;
Explorer E = p2.explorer();
for (fci_t fit = E.faces_begin(), facesend = E.faces_end(); fit != facesend; ++fit) {
heafcc_t fcirc(E.halfedge(fit)), fend(fcirc);
Outline2d outline;
CGAL_For_all(fcirc, fend) {
if (E.is_standard(E.target(fcirc))) {
Explorer::Point ep = E.point(E.target(fcirc));
outline.vertices.push_back(Vector2d(to_double(ep.x()),
to_double(ep.y())));
}
if (!fit->mark()) continue;
heafcc_t fcirc(E.face_cycle(fit)), fend(fcirc);
add_outline_to_poly(E, fcirc, fend, true, poly);
for (CGAL_Nef_polyhedron2::Explorer::Hole_const_iterator j = E.holes_begin(fit);
j != E.holes_end(fit); ++j) {
CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator hcirc(j), hend(hcirc);
add_outline_to_poly(E, hcirc, hend, false, poly);
}
if (outline.vertices.size() > 0) poly->addOutline(outline);
}
poly->setSanitized(true);
return poly;
}
@ -326,13 +420,14 @@ much slower in many cases.
#include <CGAL/Delaunay_mesh_face_base_2.h>
typedef CGAL_Kernel3 Kernel;
typedef typename CGAL::Triangulation_vertex_base_2<Kernel> Vb;
//typedef typename CGAL::Constrained_triangulation_face_base_2<Kernel> Fb;
//typedef CGAL::Triangulation_vertex_base_2<Kernel> Vb;
typedef CGAL::Triangulation_vertex_base_2<Kernel> Vb;
//typedef CGAL::Constrained_triangulation_face_base_2<Kernel> Fb;
typedef CGAL::Delaunay_mesh_face_base_2<Kernel> Fb;
typedef typename CGAL::Triangulation_data_structure_2<Vb,Fb> TDS;
typedef CGAL::Triangulation_data_structure_2<Vb,Fb> TDS;
typedef CGAL::Exact_intersections_tag ITAG;
typedef typename CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS,ITAG> CDT;
//typedef typename CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS> CDT;
typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS,ITAG> CDT;
//typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS> CDT;
typedef CDT::Vertex_handle Vertex_handle;
typedef CDT::Point CDTPoint;

View File

@ -8,6 +8,7 @@
namespace CGALUtils {
bool applyHull(const Geometry::ChildList &children, CGAL_Polyhedron &P);
void applyOperator(const Geometry::ChildList &children, CGAL_Nef_polyhedron &dest, OpenSCADOperator op);
void applyBinaryOperator(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op);
Polygon2d *project(const CGAL_Nef_polyhedron &N, bool cut);
CGAL_Iso_cuboid_3 boundingBox(const CGAL_Nef_polyhedron3 &N);

View File

@ -234,4 +234,11 @@ namespace ClipperUtils {
return toPolygon2d(polytree);
}
Polygon2d *applyOffset(const Polygon2d& poly, double offset, ClipperLib::JoinType joinType, double miter_limit, double arc_tolerance) {
ClipperLib::ClipperOffset co(miter_limit, arc_tolerance * CLIPPER_SCALE);
co.AddPaths(fromPolygon2d(poly), joinType, ClipperLib::etClosedPolygon);
ClipperLib::PolyTree result;
co.Execute(result, offset * CLIPPER_SCALE);
return toPolygon2d(result);
}
};

View File

@ -6,7 +6,7 @@
namespace ClipperUtils {
static const unsigned int CLIPPER_SCALE = 100000;
static const unsigned int CLIPPER_SCALE = 2 << 17;
ClipperLib::Path fromOutline2d(const Outline2d &poly, bool keep_orientation);
ClipperLib::Paths fromPolygon2d(const Polygon2d &poly);
@ -15,6 +15,7 @@ namespace ClipperUtils {
Polygon2d *toPolygon2d(const ClipperLib::PolyTree &poly);
ClipperLib::Paths process(const ClipperLib::Paths &polygons,
ClipperLib::ClipType, ClipperLib::PolyFillType);
Polygon2d *applyOffset(const Polygon2d& poly, double offset, ClipperLib::JoinType joinType, double miter_limit, double arc_tolerance);
Polygon2d *applyMinkowski(const std::vector<const Polygon2d*> &polygons);
Polygon2d *apply(const std::vector<const Polygon2d*> &polygons, ClipperLib::ClipType);
Polygon2d *apply(const std::vector<ClipperLib::Paths> &pathsvector, ClipperLib::ClipType);

View File

@ -56,7 +56,7 @@ AbstractNode *ColorModule::instantiate(const Context *ctx, const ModuleInstantia
AssignmentList args;
args += Assignment("c", NULL), Assignment("alpha", NULL);
args += Assignment("c"), Assignment("alpha");
Context c(ctx);
c.setVariables(args, evalctx);

View File

@ -36,8 +36,6 @@
namespace fs = boost::filesystem;
#include "boosty.h"
std::vector<const Context*> Context::ctx_stack;
// $children is not a config_variable. config_variables have dynamic scope,
// meaning they are passed down the call chain implicitly.
// $children is simply misnamed and shouldn't have included the '$'.
@ -46,18 +44,30 @@ static bool is_config_variable(const std::string &name) {
}
/*!
Initializes this context. Optionally initializes a context for an external library
Initializes this context. Optionally initializes a context for an
external library. Note that if parent is null, a new stack will be
created, and all children will share the root parent's stack.
*/
Context::Context(const Context *parent)
: parent(parent)
{
ctx_stack.push_back(this);
if (parent) document_path = parent->document_path;
if (parent) {
assert(parent->ctx_stack && "Parent context stack was null!");
this->ctx_stack = parent->ctx_stack;
this->document_path = parent->document_path;
}
else {
this->ctx_stack = new Stack;
}
this->ctx_stack->push_back(this);
}
Context::~Context()
{
ctx_stack.pop_back();
assert(this->ctx_stack && "Context stack was null at destruction!");
this->ctx_stack->pop_back();
if (!parent) delete this->ctx_stack;
}
/*!
@ -103,9 +113,13 @@ void Context::set_constant(const std::string &name, const Value &value)
Value Context::lookup_variable(const std::string &name, bool silent) const
{
if (!this->ctx_stack) {
PRINT("ERROR: Context had null stack in lookup_variable()!!");
return Value();
}
if (is_config_variable(name)) {
for (int i = ctx_stack.size()-1; i >= 0; i--) {
const ValueMap &confvars = ctx_stack[i]->config_variables;
for (int i = this->ctx_stack->size()-1; i >= 0; i--) {
const ValueMap &confvars = ctx_stack->at(i)->config_variables;
if (confvars.find(name) != confvars.end())
return confvars.find(name)->second;
}
@ -150,33 +164,35 @@ std::string Context::getAbsolutePath(const std::string &filename) const
}
#ifdef DEBUG
void Context::dump(const AbstractModule *mod, const ModuleInstantiation *inst)
std::string Context::dump(const AbstractModule *mod, const ModuleInstantiation *inst)
{
if (inst)
PRINTB("ModuleContext %p (%p) for %s inst (%p)", this % this->parent % inst->name() % inst);
else
PRINTB("Context: %p (%p)", this % this->parent);
PRINTB(" document path: %s", this->document_path);
std::stringstream s;
if (inst)
s << boost::format("ModuleContext %p (%p) for %s inst (%p)") % this % this->parent % inst->name() % inst;
else
s << boost::format("Context: %p (%p)") % this % this->parent;
s << boost::format(" document path: %s") % this->document_path;
if (mod) {
const Module *m = dynamic_cast<const Module*>(mod);
if (m) {
PRINT(" module args:");
s << " module args:";
BOOST_FOREACH(const Assignment &arg, m->definition_arguments) {
PRINTB(" %s = %s", arg.first % variables[arg.first]);
s << boost::format(" %s = %s") % arg.first % variables[arg.first];
}
}
}
typedef std::pair<std::string, Value> ValueMapType;
PRINT(" vars:");
BOOST_FOREACH(const ValueMapType &v, constants) {
PRINTB(" %s = %s", v.first % v.second);
}
BOOST_FOREACH(const ValueMapType &v, variables) {
PRINTB(" %s = %s", v.first % v.second);
}
BOOST_FOREACH(const ValueMapType &v, config_variables) {
PRINTB(" %s = %s", v.first % v.second);
}
s << " vars:";
BOOST_FOREACH(const ValueMapType &v, constants) {
s << boost::format(" %s = %s") % v.first % v.second;
}
BOOST_FOREACH(const ValueMapType &v, variables) {
s << boost::format(" %s = %s") % v.first % v.second;
}
BOOST_FOREACH(const ValueMapType &v, config_variables) {
s << boost::format(" %s = %s") % v.first % v.second;
}
return s.str();
}
#endif

View File

@ -10,9 +10,11 @@
class Context
{
public:
typedef std::vector<const Context*> Stack;
Context(const Context *parent = NULL);
virtual ~Context();
const Context *getParent() const { return this->parent; }
virtual Value evaluate_function(const std::string &name, const class EvalContext *evalctx) const;
virtual class AbstractNode *instantiate_module(const class ModuleInstantiation &inst, const EvalContext *evalctx) const;
@ -29,11 +31,11 @@ public:
std::string getAbsolutePath(const std::string &filename) const;
public:
const Context *parent;
static std::vector<const Context*> ctx_stack;
protected:
const Context *parent;
Stack *ctx_stack;
typedef boost::unordered_map<std::string, Value> ValueMap;
ValueMap constants;
ValueMap variables;
@ -41,9 +43,9 @@ protected:
std::string document_path; // FIXME: This is a remnant only needed by dxfdim
#ifdef DEBUG
public:
virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst);
#ifdef DEBUG
virtual std::string dump(const class AbstractModule *mod, const ModuleInstantiation *inst);
#endif
};

View File

@ -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();
uint32_t steps = range.nbsteps();
boost::uint32_t steps = range.nbsteps();
if (steps >= 10000) {
PRINTB("WARNING: Bad range parameter in for statement: too many elements (%lu).", steps);
} else {
@ -109,8 +109,8 @@ const EvalContext* ControlModule::getLastModuleCtx(const EvalContext *evalctx)
// Find the last custom module invocation, which will contain
// an eval context with the children of the module invokation
const Context *tmpc = evalctx;
while (tmpc->parent) {
const ModuleContext *modulectx = dynamic_cast<const ModuleContext*>(tmpc->parent);
while (tmpc->getParent()) {
const ModuleContext *modulectx = dynamic_cast<const ModuleContext*>(tmpc->getParent());
if (modulectx) {
// This will trigger if trying to invoke child from the root of any file
// assert(filectx->evalctx);
@ -119,7 +119,7 @@ const EvalContext* ControlModule::getLastModuleCtx(const EvalContext *evalctx)
}
return NULL;
}
tmpc = tmpc->parent;
tmpc = tmpc->getParent();
}
return NULL;
}
@ -161,6 +161,7 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
if (type == CHILD)
{
printDeprecation("DEPRECATED: child() will be removed in future releases. Use children() instead.");
int n = 0;
if (evalctx->numArgs() > 0) {
double v;
@ -229,7 +230,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();
uint32_t steps = range.nbsteps();
boost::uint32_t steps = range.nbsteps();
if (steps >= 10000) {
PRINTB("WARNING: Bad range parameter for children: too many elements (%lu).", steps);
return NULL;

View File

@ -2,6 +2,18 @@
#include "csgterm.h"
#include "printutils.h"
// Helper function to debug normalization bugs
#if 0
static bool validate_tree(const shared_ptr<CSGTerm> &term)
{
if (term->type == CSGTerm::TYPE_PRIMITIVE) return true;
if (!term->left || !term->right) return false;
if (!validate_tree(term->left)) return false;
if (!validate_tree(term->right)) return false;
return true;
}
#endif
/*!
NB! for e.g. empty intersections, this can normalize a tree to nothing and return NULL.
*/
@ -25,6 +37,7 @@ shared_ptr<CSGTerm> CSGTermNormalizer::normalize(const shared_ptr<CSGTerm> &root
tmproot = newroot;
newroot = collapse_null_terms(tmproot);
}
newroot = cleanup_term(newroot);
return newroot;
}
}

View File

@ -176,22 +176,23 @@ DxfData::DxfData(double fn, double fs, double fa,
in_blocks_section = iddata == "BLOCKS";
}
else if (mode == "LINE") {
ADD_LINE(xverts[0], yverts[0], xverts[1], yverts[1]);
ADD_LINE(xverts.at(0), yverts.at(0), xverts.at(1), yverts.at(1));
}
else if (mode == "LWPOLYLINE") {
assert(xverts.size() == yverts.size());
// polyline flag is stored in 'dimtype'
int numverts = xverts.size();
// assert(xverts.size() == yverts.size());
// Get maximum to enforce managed exception if xverts.size() != yverts.size()
int numverts = std::max(xverts.size(), yverts.size());
for (int i=1;i<numverts;i++) {
ADD_LINE(xverts[i-1], yverts[i-1], xverts[i%numverts], yverts[i%numverts]);
ADD_LINE(xverts.at(i-1), yverts.at(i-1), xverts.at(i%numverts), yverts.at(i%numverts));
}
// polyline flag is stored in 'dimtype'
if (dimtype & 0x01) { // closed polyline
ADD_LINE(xverts[numverts-1], yverts[numverts-1], xverts[0], yverts[0]);
ADD_LINE(xverts.at(numverts-1), yverts.at(numverts-1), xverts.at(0), yverts.at(0));
}
}
else if (mode == "CIRCLE") {
int n = Calc::get_fragments_from_r(radius, fn, fs, fa);
Vector2d center(xverts[0], yverts[0]);
Vector2d center(xverts.at(0), yverts.at(0));
for (int i = 0; i < n; i++) {
double a1 = (2*M_PI*i)/n;
double a2 = (2*M_PI*(i+1))/n;
@ -200,7 +201,7 @@ DxfData::DxfData(double fn, double fs, double fa,
}
}
else if (mode == "ARC") {
Vector2d center(xverts[0], yverts[0]);
Vector2d center(xverts.at(0), yverts.at(0));
int n = Calc::get_fragments_from_r(radius, fn, fs, fa);
while (arc_start_angle > arc_stop_angle)
arc_stop_angle += 360.0;
@ -218,9 +219,9 @@ DxfData::DxfData(double fn, double fs, double fa,
// Commented code is meant as documentation of vector math
while (ellipse_start_angle > ellipse_stop_angle) ellipse_stop_angle += 2 * M_PI;
// Vector2d center(xverts[0], yverts[0]);
Vector2d center(xverts[0], yverts[0]);
Vector2d center(xverts.at(0), yverts.at(0));
// Vector2d ce(xverts[1], yverts[1]);
Vector2d ce(xverts[1], yverts[1]);
Vector2d ce(xverts.at(1), yverts.at(1));
// double r_major = ce.length();
double r_major = sqrt(ce[0]*ce[0] + ce[1]*ce[1]);
// double rot_angle = ce.angle();
@ -271,10 +272,10 @@ DxfData::DxfData(double fn, double fs, double fa,
double ly1 = this->points[blockdata[iddata][i].idx[0]][1] * ellipse_stop_angle;
double lx2 = this->points[blockdata[iddata][i].idx[1]][0] * ellipse_start_angle;
double ly2 = this->points[blockdata[iddata][i].idx[1]][1] * ellipse_stop_angle;
double px1 = (cos(a)*lx1 - sin(a)*ly1) * scale + xverts[0];
double py1 = (sin(a)*lx1 + cos(a)*ly1) * scale + yverts[0];
double px2 = (cos(a)*lx2 - sin(a)*ly2) * scale + xverts[0];
double py2 = (sin(a)*lx2 + cos(a)*ly2) * scale + yverts[0];
double px1 = (cos(a)*lx1 - sin(a)*ly1) * scale + xverts.at(0);
double py1 = (sin(a)*lx1 + cos(a)*ly1) * scale + yverts.at(0);
double px2 = (cos(a)*lx2 - sin(a)*ly2) * scale + xverts.at(0);
double py2 = (sin(a)*lx2 + cos(a)*ly2) * scale + yverts.at(0);
ADD_LINE(px1, py1, px2, py2);
}
}
@ -386,6 +387,9 @@ DxfData::DxfData(double fn, double fs, double fa,
catch (boost::bad_lexical_cast &blc) {
PRINTB("WARNING: Illegal value %s in '%s'", data % filename);
}
catch (const std::out_of_range& oor) {
PRINTB("WARNING: not enough input values for %s in '%s'", data % filename);
}
}
BOOST_FOREACH(const EntityList::value_type &i, unsupported_entities_list) {

View File

@ -1,6 +1,15 @@
#include "editor.h"
#include "Preferences.h"
Editor::Editor(QWidget *parent) : QTextEdit(parent)
{
setAcceptRichText(false);
// This needed to avoid QTextEdit accepting filename drops as we want
// to handle these ourselves in MainWindow
setAcceptDrops(false);
this->highlighter = new Highlighter(this->document());
}
void Editor::indentSelection()
{
QTextCursor cursor = textCursor();
@ -98,7 +107,9 @@ void Editor::zoomOut()
void Editor::wheelEvent ( QWheelEvent * event )
{
if (event->modifiers() == Qt::ControlModifier) {
QSettings settings;
bool wheelzoom_enabled = Preferences::inst()->getValue("editor/ctrlmousewheelzoom").toBool();
if ((event->modifiers() == Qt::ControlModifier) && wheelzoom_enabled ) {
if (event->delta() > 0 )
zoomIn();
else if (event->delta() < 0 )
@ -122,3 +133,27 @@ void Editor::setPlainText(const QString &text)
verticalScrollBar()->setSliderPosition(y);
}
}
void Editor::highlightError(int error_pos)
{
highlighter->highlightError( error_pos );
QTextCursor cursor = this->textCursor();
cursor.setPosition( error_pos );
this->setTextCursor( cursor );
}
void Editor::unhighlightLastError()
{
highlighter->unhighlightLastError();
}
void Editor::setHighlightScheme(const QString &name)
{
highlighter->assignFormatsToTokens( name );
highlighter->rehighlight(); // slow on large files
}
Editor::~Editor()
{
delete highlighter;
}

View File

@ -3,14 +3,15 @@
#include <QWidget>
#include <QWheelEvent>
#include <QScrollBar>
#include <QTextEdit>
#include "highlighter.h"
class Editor : public QTextEdit
{
Q_OBJECT
public:
Editor(QWidget *parent) : QTextEdit(parent) { setAcceptRichText(false); }
void setPlainText(const QString &text);
Editor(QWidget *parent);
~Editor();
public slots:
void zoomIn();
void zoomOut();
@ -21,6 +22,11 @@ public slots:
void unindentSelection();
void commentSelection();
void uncommentSelection();
void setPlainText(const QString &text);
void highlightError(int error_pos);
void unhighlightLastError();
void setHighlightScheme(const QString &name);
private:
void wheelEvent ( QWheelEvent * event );
Highlighter *highlighter;
};

View File

@ -32,33 +32,35 @@ ModuleInstantiation *EvalContext::getChild(size_t i) const
}
#ifdef DEBUG
void EvalContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst)
std::string EvalContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst)
{
if (inst)
PRINTB("EvalContext %p (%p) for %s inst (%p)", this % this->parent % inst->name() % inst);
else
PRINTB("Context: %p (%p)", this % this->parent);
PRINTB(" document path: %s", this->document_path);
std::stringstream s;
if (inst)
s << boost::format("EvalContext %p (%p) for %s inst (%p)") % this % this->parent % inst->name() % inst;
else
s << boost::format("Context: %p (%p)") % this % this->parent;
s << boost::format(" document path: %s") % this->document_path;
PRINT(" eval args:");
s << boost::format(" eval args:");
for (size_t i=0;i<this->eval_arguments.size();i++) {
PRINTB(" %s = %s", this->eval_arguments[i].first % this->eval_arguments[i].second);
s << boost::format(" %s = %s") % this->eval_arguments[i].first % this->eval_arguments[i].second;
}
if (this->scope && this->scope->children.size() > 0) {
PRINT(" children:");
s << boost::format(" children:");
BOOST_FOREACH(const ModuleInstantiation *ch, this->scope->children) {
PRINTB(" %s", ch->name());
s << boost::format(" %s") % ch->name();
}
}
if (mod) {
const Module *m = dynamic_cast<const Module*>(mod);
if (m) {
PRINT(" module args:");
s << boost::format(" module args:");
BOOST_FOREACH(const Assignment &arg, m->definition_arguments) {
PRINTB(" %s = %s", arg.first % variables[arg.first]);
s << boost::format(" %s = %s") % arg.first % variables[arg.first];
}
}
}
return s.str();
}
#endif

View File

@ -25,7 +25,7 @@ public:
ModuleInstantiation *getChild(size_t i) const;
#ifdef DEBUG
virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst);
virtual std::string dump(const class AbstractModule *mod, const ModuleInstantiation *inst);
#endif
private:

View File

@ -31,12 +31,22 @@
#include "dxfdata.h"
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
#define QUOTE(x__) # x__
#define QUOTED(x__) QUOTE(x__)
#ifdef ENABLE_CGAL
#include "CGAL_Nef_polyhedron.h"
#include "cgal.h"
#include "cgalutils.h"
struct triangle {
std::string vs1;
std::string vs2;
std::string vs3;
};
void exportFile(const class Geometry *root_geom, std::ostream &output, FileFormat format)
{
if (const CGAL_Nef_polyhedron *N = dynamic_cast<const CGAL_Nef_polyhedron *>(root_geom)) {
@ -48,6 +58,9 @@ void exportFile(const class Geometry *root_geom, std::ostream &output, FileForma
case OPENSCAD_OFF:
export_off(N, output);
break;
case OPENSCAD_AMF:
export_amf(N, output);
break;
case OPENSCAD_DXF:
assert(false && "Export Nef polyhedron as DXF not supported");
break;
@ -64,12 +77,24 @@ void exportFile(const class Geometry *root_geom, std::ostream &output, FileForma
case OPENSCAD_OFF:
export_off(*ps, output);
break;
case OPENSCAD_AMF:
export_amf(*ps, output);
break;
default:
assert(false && "Unsupported file format");
}
}
else if (const Polygon2d *poly = dynamic_cast<const Polygon2d *>(root_geom)) {
export_dxf(*poly, output);
switch (format) {
case OPENSCAD_SVG:
export_svg(*poly, output);
break;
case OPENSCAD_DXF:
export_dxf(*poly, output);
break;
default:
assert(false && "Unsupported file format");
}
} else {
assert(false && "Not implemented");
}
@ -222,7 +247,8 @@ void export_off(const class PolySet &ps, std::ostream &output)
void export_off(const CGAL_Nef_polyhedron *root_N, std::ostream &output)
{
if (!root_N->p3->is_simple()) {
PRINT("Object isn't a valid 2-manifold! Modify your design.\n");
PRINT("Object isn't a valid 2-manifold! Modify your design.");
return;
}
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
try {
@ -236,6 +262,133 @@ void export_off(const CGAL_Nef_polyhedron *root_N, std::ostream &output)
CGAL::set_error_behaviour(old_behaviour);
}
void export_amf(const class PolySet &ps, std::ostream &output)
{
// FIXME: Implement this without creating a Nef polyhedron
CGAL_Nef_polyhedron *N = createNefPolyhedronFromGeometry(ps);
export_amf(N, output);
delete N;
}
/*!
Saves the current 3D CGAL Nef polyhedron as AMF to the given file.
The file must be open.
*/
void export_amf(const CGAL_Nef_polyhedron *root_N, std::ostream &output)
{
if (!root_N->p3->is_simple()) {
PRINT("Object isn't a valid 2-manifold! Modify your design.");
return;
}
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
try {
CGAL_Polyhedron P;
root_N->p3->convert_to_Polyhedron(P);
typedef CGAL_Polyhedron::Vertex Vertex;
typedef CGAL_Polyhedron::Vertex_const_iterator VCI;
typedef CGAL_Polyhedron::Facet_const_iterator FCI;
typedef CGAL_Polyhedron::Halfedge_around_facet_const_circulator HFCC;
setlocale(LC_NUMERIC, "C"); // Ensure radix is . (not ,) in output
std::vector<std::string> vertices;
std::vector<triangle> triangles;
for (FCI fi = P.facets_begin(); fi != P.facets_end(); ++fi) {
HFCC hc = fi->facet_begin();
HFCC hc_end = hc;
Vertex v1, v2, v3;
v1 = *VCI((hc++)->vertex());
v3 = *VCI((hc++)->vertex());
do {
v2 = v3;
v3 = *VCI((hc++)->vertex());
double x1 = CGAL::to_double(v1.point().x());
double y1 = CGAL::to_double(v1.point().y());
double z1 = CGAL::to_double(v1.point().z());
double x2 = CGAL::to_double(v2.point().x());
double y2 = CGAL::to_double(v2.point().y());
double z2 = CGAL::to_double(v2.point().z());
double x3 = CGAL::to_double(v3.point().x());
double y3 = CGAL::to_double(v3.point().y());
double z3 = CGAL::to_double(v3.point().z());
std::stringstream stream;
stream << x1 << " " << y1 << " " << z1;
std::string vs1 = stream.str();
stream.str("");
stream << x2 << " " << y2 << " " << z2;
std::string vs2 = stream.str();
stream.str("");
stream << x3 << " " << y3 << " " << z3;
std::string vs3 = stream.str();
if (std::find(vertices.begin(), vertices.end(), vs1) == vertices.end())
vertices.push_back(vs1);
if (std::find(vertices.begin(), vertices.end(), vs2) == vertices.end())
vertices.push_back(vs2);
if (std::find(vertices.begin(), vertices.end(), vs3) == vertices.end())
vertices.push_back(vs3);
if (vs1 != vs2 && vs1 != vs3 && vs2 != vs3) {
// The above condition ensures that there are 3 distinct vertices, but
// they may be collinear. If they are, the unit normal is meaningless
// so the default value of "1 0 0" can be used. If the vertices are not
// collinear then the unit normal must be calculated from the
// components.
triangle tri = {vs1, vs2, vs3};
triangles.push_back(tri);
}
} while (hc != hc_end);
}
output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
<< "<amf unit=\"millimeter\">\r\n"
<< " <metadata type=\"producer\">OpenSCAD " << QUOTED(OPENSCAD_VERSION)
#ifdef OPENSCAD_COMMIT
<< " (git " << QUOTED(OPENSCAD_COMMIT) << ")"
#endif
<< "</metadata>\r\n"
<< " <object id=\"0\">\r\n"
<< " <mesh>\r\n";
output << " <vertices>\r\n";
for (size_t i = 0; i < vertices.size(); i++) {
std::string s = vertices[i];
output << " <vertex><coordinates>\r\n";
char* chrs = new char[s.length() + 1];
strcpy(chrs, s.c_str());
std::string coords = strtok(chrs, " ");
output << " <x>" << coords << "</x>\r\n";
coords = strtok(NULL, " ");
output << " <y>" << coords << "</y>\r\n";
coords = strtok(NULL, " ");
output << " <z>" << coords << "</z>\r\n";
output << " </coordinates></vertex>\r\n";
}
output << " </vertices>\r\n";
output << " <volume>\r\n";
for (size_t i = 0; i < triangles.size(); i++) {
triangle t = triangles[i];
output << " <triangle>\r\n";
size_t index;
index = std::distance(vertices.begin(), std::find(vertices.begin(), vertices.end(), t.vs1));
output << " <v1>" << index << "</v1>\r\n";
index = std::distance(vertices.begin(), std::find(vertices.begin(), vertices.end(), t.vs2));
output << " <v2>" << index << "</v2>\r\n";
index = std::distance(vertices.begin(), std::find(vertices.begin(), vertices.end(), t.vs3));
output << " <v3>" << index << "</v3>\r\n";
output << " </triangle>\r\n";
}
output << " </volume>\r\n";
output << " </mesh>\r\n"
<< " </object>\r\n"
<< "</amf>\r\n";
} catch (CGAL::Assertion_exception e) {
PRINTB("CGAL error in CGAL_Nef_polyhedron3::convert_to_Polyhedron(): %s", e.what());
}
CGAL::set_error_behaviour(old_behaviour);
setlocale(LC_NUMERIC, ""); // Set default locale
}
#endif // ENABLE_CGAL
/*!
@ -257,7 +410,7 @@ void export_dxf(const Polygon2d &poly, std::ostream &output)
<< "ENTITIES\n";
BOOST_FOREACH(const Outline2d &o, poly.outlines()) {
for (int i=0;i<o.vertices.size();i++) {
for (unsigned int i=0;i<o.vertices.size();i++) {
const Vector2d &p1 = o.vertices[i];
const Vector2d &p2 = o.vertices[(i+1)%o.vertices.size()];
double x1 = p1[0];
@ -298,3 +451,44 @@ void export_dxf(const Polygon2d &poly, std::ostream &output)
setlocale(LC_NUMERIC, ""); // Set default locale
}
void export_svg(const Polygon2d &poly, std::ostream &output)
{
setlocale(LC_NUMERIC, "C"); // Ensure radix is . (not ,) in output
BoundingBox bbox = poly.getBoundingBox();
int minx = floor(bbox.min().x());
int miny = floor(-bbox.max().y());
int maxx = ceil(bbox.max().x());
int maxy = ceil(-bbox.min().y());
output
<< "<?xml version=\"1.0\" standalone=\"no\"?>\n"
<< "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"
<< "<svg width=\"" << (maxx - minx) << "\" height=\"" << (maxy - miny) << "\" viewBox=\"" << (minx - 1) << " " << (miny - 1) << " " << (maxx - minx + 2) << " " << (maxy - miny + 2) << "\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n"
<< "<title>OpenSCAD Model</title>\n";
output << "<path d=\"\n";
BOOST_FOREACH(const Outline2d &o, poly.outlines()) {
if (o.vertices.empty()) {
continue;
}
const Eigen::Vector2d& p0 = o.vertices[0];
output << "M " << p0.x() << "," << -p0.y();
for (unsigned int idx = 1;idx < o.vertices.size();idx++) {
const Eigen::Vector2d& p = o.vertices[idx];
output << " L " << p.x() << "," << -p.y();
if ((idx % 6) == 5) {
output << "\n";
}
}
output << " z\n";
}
output << "\" stroke=\"black\" fill=\"lightgray\" stroke-width=\"0.5\"/>";
output << "</svg>\n";
setlocale(LC_NUMERIC, ""); // Set default locale
}

View File

@ -10,7 +10,9 @@
enum FileFormat {
OPENSCAD_STL,
OPENSCAD_OFF,
OPENSCAD_DXF
OPENSCAD_AMF,
OPENSCAD_DXF,
OPENSCAD_SVG
};
void exportFile(const class Geometry *root_geom, std::ostream &output, FileFormat format);
@ -20,7 +22,10 @@ void export_stl(const class CGAL_Nef_polyhedron *root_N, std::ostream &output);
void export_stl(const class PolySet &ps, std::ostream &output);
void export_off(const CGAL_Nef_polyhedron *root_N, std::ostream &output);
void export_off(const class PolySet &ps, std::ostream &output);
void export_amf(const class CGAL_Nef_polyhedron *root_N, std::ostream &output);
void export_amf(const class PolySet &ps, std::ostream &output);
void export_dxf(const class Polygon2d &poly, std::ostream &output);
void export_svg(const class Polygon2d &poly, std::ostream &output);
void export_png(const CGAL_Nef_polyhedron *root_N, Camera &c, std::ostream &output);
void export_png_with_opencsg(Tree &tree, Camera &c, std::ostream &output);
void export_png_with_throwntogether(Tree &tree, Camera &c, std::ostream &output);

View File

@ -22,7 +22,7 @@ std::string lookup_file(const std::string &filename,
if (!fs::exists(absfile) && fs::exists(absfile_fallback)) {
resultfile = absfile_fallback.string();
PRINTB("WARNING: Imported file (%s) found in document root instead of relative to the importing module. This behavior is deprecated", filename);
PRINT_DEPRECATION("DEPRECATED: Imported file (%s) found in document root instead of relative to the importing module. This behavior is deprecated", filename);
}
else {
resultfile = absfile.string();

View File

@ -36,6 +36,10 @@
#include "printutils.h"
#include <boost/foreach.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
using boost::math::isnan;
using boost::math::isinf;
/*
Random numbers
@ -79,7 +83,6 @@ std::string AbstractFunction::dump(const std::string &indent, const std::string
Function::~Function()
{
BOOST_FOREACH(const Assignment &arg, this->definition_arguments) delete arg.second;
delete expr;
}
@ -193,9 +196,11 @@ Value builtin_min(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() >= 1 && evalctx->getArgValue(0).type() == Value::NUMBER) {
double val = evalctx->getArgValue(0).toDouble();
for (size_t i = 1; i < evalctx->numArgs(); i++)
if (evalctx->getArgValue(1).type() == Value::NUMBER)
val = fmin(val, evalctx->getArgValue(i).toDouble());
for (size_t i = 1; i < evalctx->numArgs(); i++) {
Value v = evalctx->getArgValue(i);
if (v.type() == Value::NUMBER)
val = fmin(val, v.toDouble());
}
return Value(val);
}
return Value();
@ -205,9 +210,11 @@ Value builtin_max(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() >= 1 && evalctx->getArgValue(0).type() == Value::NUMBER) {
double val = evalctx->getArgValue(0).toDouble();
for (size_t i = 1; i < evalctx->numArgs(); i++)
if (evalctx->getArgValue(1).type() == Value::NUMBER)
val = fmax(val, evalctx->getArgValue(i).toDouble());
for (size_t i = 1; i < evalctx->numArgs(); i++) {
Value v = evalctx->getArgValue(i);
if (v.type() == Value::NUMBER)
val = fmax(val, v.toDouble());
}
return Value(val);
}
return Value();
@ -598,6 +605,71 @@ Value builtin_parent_module(const Context *, const EvalContext *evalctx)
return Value(Module::stack_element(s - 1 - n));
}
Value builtin_norm(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::VECTOR) {
double sum = 0;
Value::VectorType v = evalctx->getArgValue(0).toVector();
for (size_t i = 0; i < v.size(); i++)
if (v[i].type() == Value::NUMBER)
sum += pow(v[i].toDouble(),2);
else {
PRINT(" WARNING: Incorrect arguments to norm()");
return Value();
}
return Value(sqrt(sum));
}
return Value();
}
Value builtin_cross(const Context *, const EvalContext *evalctx)
{
if (evalctx->numArgs() != 2) {
PRINT("WARNING: Invalid number of parameters for cross()");
return Value();
}
Value arg0 = evalctx->getArgValue(0);
Value arg1 = evalctx->getArgValue(1);
if ((arg0.type() != Value::VECTOR) || (arg1.type() != Value::VECTOR)) {
PRINT("WARNING: Invalid type of parameters for cross()");
return Value();
}
Value::VectorType v0 = arg0.toVector();
Value::VectorType v1 = arg1.toVector();
if ((v0.size() != 3) || (v1.size() != 3)) {
PRINT("WARNING: Invalid vector size of parameter for cross()");
return Value();
}
for (unsigned int a = 0;a < 3;a++) {
if ((v0[a].type() != Value::NUMBER) || (v1[a].type() != Value::NUMBER)) {
PRINT("WARNING: Invalid value in parameter vector for cross()");
return Value();
}
double d0 = v0[a].toDouble();
double d1 = v1[a].toDouble();
if (boost::math::isnan(d0) || boost::math::isnan(d1)) {
PRINT("WARNING: Invalid value (NaN) in parameter vector for cross()");
return Value();
}
if (boost::math::isinf(d0) || boost::math::isinf(d1)) {
PRINT("WARNING: Invalid value (INF) in parameter vector for cross()");
return Value();
}
}
double x = v0[1].toDouble() * v1[2].toDouble() - v0[2].toDouble() * v1[1].toDouble();
double y = v0[2].toDouble() * v1[0].toDouble() - v0[0].toDouble() * v1[2].toDouble();
double z = v0[0].toDouble() * v1[1].toDouble() - v0[1].toDouble() * v1[0].toDouble();
Value::VectorType result;
result.push_back(Value(x));
result.push_back(Value(y));
result.push_back(Value(z));
return Value(result);
}
void register_builtin_functions()
{
Builtins::init("abs", new BuiltinFunction(&builtin_abs));
@ -627,5 +699,7 @@ void register_builtin_functions()
Builtins::init("search", new BuiltinFunction(&builtin_search));
Builtins::init("version", new BuiltinFunction(&builtin_version));
Builtins::init("version_num", new BuiltinFunction(&builtin_version_num));
Builtins::init("norm", new BuiltinFunction(&builtin_norm));
Builtins::init("cross", new BuiltinFunction(&builtin_cross));
Builtins::init("parent_module", new BuiltinFunction(&builtin_parent_module));
}

View File

@ -17,7 +17,8 @@ public:
AbstractFunction() : feature(NULL) {}
AbstractFunction(const Feature& feature) : feature(&feature) {}
virtual ~AbstractFunction();
virtual bool is_enabled() const { return (feature == NULL) || feature->is_enabled(); };
virtual bool is_experimental() const { return feature != NULL; }
virtual bool is_enabled() const { return (feature == NULL) || feature->is_enabled(); }
virtual Value evaluate(const class Context *ctx, const class EvalContext *evalctx) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
};

View File

@ -118,6 +118,20 @@
into a blank document.
expected result: don't crash esp. on mac
12. action: start openscad, open example 001. open edit/prefs/editor/
syntax-highlighter, 'for light background'. make your OS use a light
(white) background for the openscad text editor.
expected result: text is clearly visible, colors have good contrast
13. repeat test 12, but with 'for dark background' and dark background
expected result: text is clearly visible, colors have good contrast
14. repeat test 12, but turn the syntax highlighter off.
expected result: text is clearly visible, single color has good contrast
14. repeat test 13, but turn the syntax highlighter off.
expected result: text is clearly visible, single color has good contrast
*/
#include "highlighter.h"

View File

@ -2,20 +2,24 @@
#define HIGHLIGHTER_H_
#include <QSyntaxHighlighter>
#include <QTextDocument>
#include <QTextFormat>
#include <QTextEdit>
#include <QHash>
class Highlighter : public QSyntaxHighlighter
{
Q_OBJECT
public:
enum state_e {NORMAL=-1,QUOTE,COMMENT};
QHash<QString, QTextCharFormat> tokenFormats;
QTextCharFormat errorFormat;
Highlighter(QTextDocument *parent);
void highlightBlock(const QString &text);
void assignFormatsToTokens(const QString &);
void portable_rehighlightBlock( const QTextBlock &text );
void highlightError(int error_pos);
void unhighlightLastError();
void assignFormatsToTokens(const QString &);
private:
QTextBlock lastErrorBlock;
int errorPos;
@ -23,7 +27,6 @@ private:
QMap<QString,QStringList> tokentypes;
QMap<QString,QTextCharFormat> typeformats;
int lastDocumentPos();
void portable_rehighlightBlock( const QTextBlock &text );
};
#endif

View File

@ -67,8 +67,8 @@ public:
AbstractNode *ImportModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
AssignmentList args;
args += Assignment("file", NULL), Assignment("layer", NULL), Assignment("convexity", NULL), Assignment("origin", NULL), Assignment("scale", NULL);
args += Assignment("filename",NULL), Assignment("layername", NULL);
args += Assignment("file"), Assignment("layer"), Assignment("convexity"), Assignment("origin"), Assignment("scale");
args += Assignment("filename"), Assignment("layername");
// FIXME: This is broken. Tag as deprecated and fix
// Map old argnames to new argnames for compatibility
@ -95,7 +95,7 @@ AbstractNode *ImportModule::instantiate(const Context *ctx, const ModuleInstanti
if (v.isUndefined()) {
v = c.lookup_variable("filename");
if (!v.isUndefined()) {
PRINT("DEPRECATED: filename= is deprecated. Please use file=");
printDeprecation("DEPRECATED: filename= is deprecated. Please use file=");
}
}
std::string filename = lookup_file(v.isUndefined() ? "" : v.toString(), inst->path(), ctx->documentPath());
@ -119,7 +119,7 @@ AbstractNode *ImportModule::instantiate(const Context *ctx, const ModuleInstanti
if (layerval.isUndefined()) {
layerval = c.lookup_variable("layername");
if (!layerval.isUndefined()) {
PRINT("DEPRECATED: layername= is deprecated. Please use layer=");
printDeprecation("DEPRECATED: layername= is deprecated. Please use layer=");
}
}
node->layername = layerval.isUndefined() ? "" : layerval.toString();
@ -210,7 +210,7 @@ Geometry *ImportNode::createGeometry() const
bool binary = false;
std::streampos file_size = f.tellg();
f.seekg(80);
if (!f.eof()) {
if (f.good() && !f.eof()) {
uint32_t facenum = 0;
f.read((char *)&facenum, sizeof(uint32_t));
#ifdef BOOST_BIG_ENDIAN
@ -224,13 +224,12 @@ Geometry *ImportNode::createGeometry() const
char data[5];
f.read(data, 5);
if (!binary && !f.eof() && !memcmp(data, "solid", 5)) {
if (!binary && !f.eof() && f.good() && !memcmp(data, "solid", 5)) {
int i = 0;
double vdata[3][3];
std::string line;
std::getline(f, line);
while (!f.eof()) {
std::getline(f, line);
boost::trim(line);
if (boost::regex_search(line, ex_sfe)) {
@ -261,7 +260,7 @@ Geometry *ImportNode::createGeometry() const
}
}
}
else
else if (binary && !f.eof() && f.good())
{
f.ignore(80-5+4);
while (1) {
@ -288,7 +287,6 @@ Geometry *ImportNode::createGeometry() const
else {
file >> poly;
file.close();
bool err = createPolySetFromPolyhedron(poly, *p);
}
#else

View File

@ -149,7 +149,12 @@ use[ \t\r\n>]*"<" { BEGIN(cond_use); }
{D}+{E}? |
{D}*\.{D}+{E}? |
{D}+\.{D}*{E}? { parserlval.number = boost::lexical_cast<double>(yytext); return TOK_NUMBER; }
{D}+\.{D}*{E}? {
try {
parserlval.number = boost::lexical_cast<double>(yytext);
return TOK_NUMBER;
} catch (boost::bad_lexical_cast) {}
}
"$"?[a-zA-Z0-9_]+ { parserlval.text = strdup(yytext); return TOK_ID; }
\" { BEGIN(cond_string); stringcontents.clear(); }

View File

@ -54,7 +54,7 @@ AbstractNode *LinearExtrudeModule::instantiate(const Context *ctx, const ModuleI
LinearExtrudeNode *node = new LinearExtrudeNode(inst);
AssignmentList args;
args += Assignment("file", NULL), Assignment("layer", NULL), Assignment("height", NULL), Assignment("origin", NULL), Assignment("scale", NULL), Assignment("center", NULL), Assignment("twist", NULL), Assignment("slices", NULL);
args += Assignment("file"), Assignment("layer"), Assignment("height"), Assignment("origin"), Assignment("scale"), Assignment("center"), Assignment("twist"), Assignment("slices");
Context c(ctx);
c.setVariables(args, evalctx);
@ -74,7 +74,7 @@ AbstractNode *LinearExtrudeModule::instantiate(const Context *ctx, const ModuleI
Value slices = c.lookup_variable("slices", true);
if (!file.isUndefined() && file.type() == Value::STRING) {
PRINT("DEPRECATED: Support for reading files in linear_extrude will be removed in future releases. Use a child import() instead.");
printDeprecation("DEPRECATED: Support for reading files in linear_extrude will be removed in future releases. Use a child import() instead.");
node->filename = lookup_file(file.toString(), inst->path(), c.documentPath());
}

View File

@ -14,7 +14,6 @@ LocalScope::LocalScope()
LocalScope::~LocalScope()
{
BOOST_FOREACH (ModuleInstantiation *v, children) delete v;
BOOST_FOREACH (const Assignment &v, assignments) delete v.second;
BOOST_FOREACH (FunctionContainer::value_type &f, functions) delete f.second;
BOOST_FOREACH (AbstractModuleContainer::value_type &m, modules) delete m.second;
}

View File

@ -76,6 +76,7 @@
#include <QSettings>
#include <QProgressDialog>
#include <QMutexLocker>
#include <QTemporaryFile>
#include <fstream>
@ -103,6 +104,9 @@
#include "boosty.h"
#include "FontCache.h"
// Keeps track of open window
QSet<MainWindow*> *MainWindow::windows = NULL;
// Global application state
unsigned int GuiLocker::gui_locked = 0;
QString MainWindow::qexamplesdir;
@ -117,7 +121,7 @@ static char helptitle[] =
#endif
"\nhttp://www.openscad.org\n\n";
static char copyrighttext[] =
"Copyright (C) 2009-2013 The OpenSCAD Developers\n"
"Copyright (C) 2009-2014 The OpenSCAD Developers\n"
"\n"
"This program is free software; you can redistribute it and/or modify "
"it under the terms of the GNU General Public License as published by "
@ -156,10 +160,15 @@ settings_valueList(const QString &key, const QList<int> &defaultList = QList<int
}
MainWindow::MainWindow(const QString &filename)
: root_inst("group"), progresswidget(NULL), font_list_dialog(NULL)
: root_inst("group"), tempFile(NULL), progresswidget(NULL), font_list_dialog(NULL)
{
setupUi(this);
this->setAttribute(Qt::WA_DeleteOnClose);
if (!MainWindow::windows) MainWindow::windows = new QSet<MainWindow*>;
MainWindow::windows->insert(this);
#ifdef ENABLE_CGAL
this->cgalworker = new CGALWorker();
connect(this->cgalworker, SIGNAL(done(shared_ptr<const Geometry>)),
@ -188,7 +197,10 @@ MainWindow::MainWindow(const QString &filename)
fps = 0;
fsteps = 1;
highlighter = new Highlighter(editor->document());
editActionZoomIn->setShortcuts(QList<QKeySequence>() << editActionZoomIn->shortcuts() << QKeySequence("CTRL+="));
connect(this, SIGNAL(highlightError(int)), editor, SLOT(highlightError(int)));
connect(this, SIGNAL(unhighlightLastError()), editor, SLOT(unhighlightLastError()));
editor->setTabStopWidth(30);
editor->setLineWrapping(true); // Not designable
@ -254,7 +266,7 @@ MainWindow::MainWindow(const QString &filename)
this, SLOT(clearRecentFiles()));
if (!qexamplesdir.isEmpty()) {
bool found_example = false;
QStringList examples = QDir(qexamplesdir).entryList(QStringList("*.scad"),
QStringList examples = QDir(qexamplesdir).entryList(QStringList("*.scad"),
QDir::Files | QDir::Readable, QDir::Name);
foreach (const QString &ex, examples) {
this->menuExamples->addAction(ex, this, SLOT(actionOpenExample()));
@ -301,12 +313,15 @@ MainWindow::MainWindow(const QString &filename)
#else
this->designActionRender->setVisible(false);
#endif
connect(this->designCheckValidity, SIGNAL(triggered()), this, SLOT(actionCheckValidity()));
connect(this->designActionDisplayAST, SIGNAL(triggered()), this, SLOT(actionDisplayAST()));
connect(this->designActionDisplayCSGTree, SIGNAL(triggered()), this, SLOT(actionDisplayCSGTree()));
connect(this->designActionDisplayCSGProducts, SIGNAL(triggered()), this, SLOT(actionDisplayCSGProducts()));
connect(this->designActionExportSTL, SIGNAL(triggered()), this, SLOT(actionExportSTL()));
connect(this->designActionExportOFF, SIGNAL(triggered()), this, SLOT(actionExportOFF()));
connect(this->designActionExportAMF, SIGNAL(triggered()), this, SLOT(actionExportAMF()));
connect(this->designActionExportDXF, SIGNAL(triggered()), this, SLOT(actionExportDXF()));
connect(this->designActionExportSVG, SIGNAL(triggered()), this, SLOT(actionExportSVG()));
connect(this->designActionExportCSG, SIGNAL(triggered()), this, SLOT(actionExportCSG()));
connect(this->designActionExportImage, SIGNAL(triggered()), this, SLOT(actionExportImage()));
connect(this->designActionFlushCaches, SIGNAL(triggered()), this, SLOT(actionFlushCaches()));
@ -345,6 +360,8 @@ MainWindow::MainWindow(const QString &filename)
connect(this->viewActionPerspective, SIGNAL(triggered()), this, SLOT(viewPerspective()));
connect(this->viewActionOrthogonal, SIGNAL(triggered()), this, SLOT(viewOrthogonal()));
connect(this->viewActionHide, SIGNAL(triggered()), this, SLOT(hideConsole()));
connect(this->viewActionZoomIn, SIGNAL(triggered()), qglview, SLOT(ZoomIn()));
connect(this->viewActionZoomOut, SIGNAL(triggered()), qglview, SLOT(ZoomOut()));
// Help menu
connect(this->helpActionAbout, SIGNAL(triggered()), this, SLOT(helpAbout()));
@ -373,12 +390,12 @@ MainWindow::MainWindow(const QString &filename)
connect(this->qglview, SIGNAL(doAnimateUpdate()), this, SLOT(animateUpdate()));
connect(Preferences::inst(), SIGNAL(requestRedraw()), this->qglview, SLOT(updateGL()));
connect(Preferences::inst(), SIGNAL(fontChanged(const QString&,uint)),
connect(Preferences::inst(), SIGNAL(fontChanged(const QString&,uint)),
this, SLOT(setFont(const QString&,uint)));
connect(Preferences::inst(), SIGNAL(openCSGSettingsChanged()),
this, SLOT(openCSGSettingsChanged()));
connect(Preferences::inst(), SIGNAL(syntaxHighlightChanged(const QString&)),
this, SLOT(setSyntaxHighlight(const QString&)));
connect(Preferences::inst(), SIGNAL(syntaxHighlightChanged(const QString&)),
editor, SLOT(setHighlightScheme(const QString&)));
Preferences::inst()->apply();
connect(this->findTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(selectFindType(int)));
@ -466,6 +483,7 @@ MainWindow::~MainWindow()
{
if (root_module) delete root_module;
if (root_node) delete root_node;
if (root_chain) delete root_chain;
#ifdef ENABLE_CGAL
this->root_geom.reset();
delete this->cgalRenderer;
@ -473,6 +491,8 @@ MainWindow::~MainWindow()
#ifdef ENABLE_OPENCSG
delete this->opencsgRenderer;
#endif
delete this->thrownTogetherRenderer;
MainWindow::windows->remove(this);
}
void MainWindow::showProgress()
@ -484,7 +504,7 @@ void MainWindow::report_func(const class AbstractNode*, void *vp, int mark)
{
MainWindow *thisp = static_cast<MainWindow*>(vp);
int v = (int)((mark*1000.0) / progress_report_count);
int permille = v < 1000 ? v : 999;
int permille = v < 1000 ? v : 999;
if (permille > thisp->progresswidget->value()) {
QMetaObject::invokeMethod(thisp->progresswidget, "setValue", Qt::QueuedConnection,
Q_ARG(int, permille));
@ -526,6 +546,7 @@ MainWindow::openFile(const QString &new_filename)
#endif
setFileName(actual_filename);
editor->setPlainText("");
this->last_compiled_doc = "";
fileChangedOnDisk(); // force cached autoReloadId to update
refreshDocument();
@ -555,7 +576,7 @@ MainWindow::setFileName(const QString &filename)
} else {
this->fileName = fileinfo.fileName();
}
this->top_ctx.setDocumentPath(fileinfo.dir().absolutePath().toLocal8Bit().constData());
QDir::setCurrent(fileinfo.dir().absolutePath());
}
@ -619,7 +640,7 @@ void MainWindow::refreshDocument()
if (!this->fileName.isEmpty()) {
QFile file(this->fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
PRINTB("Failed to open file %s: %s",
PRINTB("Failed to open file %s: %s",
this->fileName.toLocal8Bit().constData() % file.errorString().toLocal8Bit().constData());
}
else {
@ -667,6 +688,7 @@ void MainWindow::compile(bool reload, bool forcedone)
if (shouldcompiletoplevel) {
console->clear();
if (editor->isContentModified()) saveBackup();
compileTopLevelDocument();
didcompile = true;
}
@ -687,6 +709,16 @@ void MainWindow::compile(bool reload, bool forcedone)
return;
}
}
if (!reload && didcompile) {
if (!animate_panel->isVisible()) {
emit unhighlightLastError();
if (!this->root_module) {
emit highlightError( parser_error_pos );
}
}
}
compileDone(didcompile | forcedone);
}
@ -759,15 +791,15 @@ void MainWindow::instantiateRoot()
// Evaluate CSG tree
PRINT("Compiling design (CSG Tree generation)...");
if (this->procevents) QApplication::processEvents();
AbstractNode::resetIndexCounter();
// split these two lines - gcc 4.7 bug
ModuleInstantiation mi = ModuleInstantiation( "group" );
this->root_inst = mi;
this->root_inst = mi;
this->absolute_root_node = this->root_module->instantiate(&top_ctx, &this->root_inst, NULL);
if (this->absolute_root_node) {
// Do we have an explicit root node (! modifier)?
if (!(this->root_node = find_root_tag(this->absolute_root_node))) {
@ -838,7 +870,7 @@ void MainWindow::compileCSG(bool procevents)
if (root_raw_term) {
PRINT("Compiling design (CSG Products normalization)...");
if (procevents) QApplication::processEvents();
size_t normalizelimit = 2 * Preferences::inst()->getValue("advanced/openCSGLimit").toUInt();
CSGTermNormalizer normalizer(normalizelimit);
this->root_norm_term = normalizer.normalize(this->root_raw_term);
@ -851,24 +883,24 @@ void MainWindow::compileCSG(bool procevents)
PRINT("WARNING: CSG normalization resulted in an empty tree");
if (procevents) QApplication::processEvents();
}
if (highlight_terms.size() > 0)
{
PRINTB("Compiling highlights (%d CSG Trees)...", highlight_terms.size());
if (procevents) QApplication::processEvents();
highlights_chain = new CSGChain();
for (unsigned int i = 0; i < highlight_terms.size(); i++) {
highlight_terms[i] = normalizer.normalize(highlight_terms[i]);
highlights_chain->import(highlight_terms[i]);
}
}
if (background_terms.size() > 0)
{
PRINTB("Compiling background (%d CSG Trees)...", background_terms.size());
if (procevents) QApplication::processEvents();
background_chain = new CSGChain();
for (unsigned int i = 0; i < background_terms.size(); i++) {
background_terms[i] = normalizer.normalize(background_terms[i]);
@ -876,22 +908,22 @@ void MainWindow::compileCSG(bool procevents)
}
}
if (this->root_chain &&
(this->root_chain->objects.size() >
if (this->root_chain &&
(this->root_chain->objects.size() >
Preferences::inst()->getValue("advanced/openCSGLimit").toUInt())) {
PRINTB("WARNING: Normalized tree has %d elements!", this->root_chain->objects.size());
PRINT("WARNING: OpenCSG rendering has been disabled.");
}
else {
PRINTB("Normalized CSG tree has %d elements",
PRINTB("Normalized CSG tree has %d elements",
(this->root_chain ? this->root_chain->objects.size() : 0));
this->opencsgRenderer = new OpenCSGRenderer(this->root_chain,
this->highlights_chain,
this->background_chain,
this->opencsgRenderer = new OpenCSGRenderer(this->root_chain,
this->highlights_chain,
this->background_chain,
this->qglview->shaderinfo);
}
this->thrownTogetherRenderer = new ThrownTogetherRenderer(this->root_chain,
this->highlights_chain,
this->thrownTogetherRenderer = new ThrownTogetherRenderer(this->root_chain,
this->highlights_chain,
this->background_chain);
PRINT("CSG generation finished.");
int s = t.elapsed() / 1000;
@ -939,7 +971,7 @@ void MainWindow::actionOpen()
if (!new_filename.isEmpty()) {
if (!maybeSave())
return;
setCurrentOutput();
openFile(new_filename);
clearCurrentOutput();
@ -1015,6 +1047,45 @@ void MainWindow::actionOpenExample()
}
}
void MainWindow::writeBackup(QFile *file)
{
// see MainWindow::saveBackup()
file->resize(0);
QTextStream writer(file);
writer.setCodec("UTF-8");
writer << this->editor->toPlainText();
PRINTB("Saved backup file: %s", file->fileName().toLocal8Bit().constData());
}
void MainWindow::saveBackup()
{
std::string path = PlatformUtils::backupPath();
if ((!fs::exists(path)) && (!PlatformUtils::createBackupPath())) {
PRINTB("WARNING: Cannot create backup path: %s", path);
return;
}
QString backupPath = QString::fromStdString(path);
if (!backupPath.endsWith("/")) backupPath.append("/");
QString basename = "unsaved";
if (!this->fileName.isEmpty()) {
QFileInfo fileInfo = QFileInfo(this->fileName);
basename = fileInfo.baseName();
}
if (!this->tempFile) {
this->tempFile = new QTemporaryFile(backupPath.append(basename + "-backup-XXXXXXXX.scad"));
}
if ((!this->tempFile->isOpen()) && (! this->tempFile->open())) {
PRINT("WARNING: Failed to create backup file");
return;
}
return writeBackup(this->tempFile);
}
void MainWindow::actionSave()
{
if (this->fileName.isEmpty()) {
@ -1091,10 +1162,10 @@ void MainWindow::hideEditor()
{
QSettings settings;
if (editActionHide->isChecked()) {
editor->hide();
editorPane->hide();
settings.setValue("view/hideEditor",true);
} else {
editor->show();
editorPane->show();
settings.setValue("view/hideEditor",false);
}
}
@ -1215,13 +1286,13 @@ bool MainWindow::eventFilter(QObject* obj, QEvent *event)
void MainWindow::updateTemporalVariables()
{
this->top_ctx.set_variable("$t", Value(this->e_tval->text().toDouble()));
Value::VectorType vpt;
vpt.push_back(Value(-qglview->cam.object_trans.x()));
vpt.push_back(Value(-qglview->cam.object_trans.y()));
vpt.push_back(Value(-qglview->cam.object_trans.z()));
this->top_ctx.set_variable("$vpt", Value(vpt));
Value::VectorType vpr;
vpr.push_back(Value(fmodf(360 - qglview->cam.object_rot.x() + 90, 360)));
vpr.push_back(Value(fmodf(360 - qglview->cam.object_rot.y(), 360)));
@ -1229,6 +1300,10 @@ void MainWindow::updateTemporalVariables()
top_ctx.set_variable("$vpr", Value(vpr));
}
/*!
Returns true if the current document is a file on disk and that file has new content.
Returns false if a file on disk has disappeared or if we haven't yet saved.
*/
bool MainWindow::fileChangedOnDisk()
{
if (!this->fileName.isEmpty()) {
@ -1254,30 +1329,22 @@ bool MainWindow::fileChangedOnDisk()
void MainWindow::compileTopLevelDocument()
{
updateTemporalVariables();
resetPrintedDeprecations();
this->last_compiled_doc = editor->toPlainText();
std::string fulltext =
std::string fulltext =
std::string(this->last_compiled_doc.toLocal8Bit().constData()) +
"\n" + commandline_commands;
delete this->root_module;
this->root_module = NULL;
this->root_module = parse(fulltext.c_str(),
this->fileName.isEmpty() ?
"" :
QFileInfo(this->fileName).absolutePath().toLocal8Bit(),
this->fileName.isEmpty() ?
"" :
QFileInfo(this->fileName).absolutePath().toLocal8Bit(),
false);
if (!animate_panel->isVisible()) {
highlighter->unhighlightLastError();
if (!this->root_module) {
QTextCursor cursor = editor->textCursor();
cursor.setPosition(parser_error_pos);
editor->setTextCursor(cursor);
highlighter->highlightError( parser_error_pos );
}
}
}
void MainWindow::checkAutoReload()
@ -1384,7 +1451,7 @@ void MainWindow::csgRender()
filename.sprintf("frame%05d.png", int(round(s*t)));
img.save(filename, "PNG");
}
compileEnded();
}
@ -1407,6 +1474,7 @@ void MainWindow::actionRender()
void MainWindow::cgalRender()
{
if (!this->root_module || !this->root_node) {
compileEnded();
return;
}
@ -1443,7 +1511,6 @@ void MainWindow::actionRenderDone(shared_ptr<const Geometry> root_geom)
if (N->getDimension() == 3) {
PRINT(" Top level object is a 3D object:");
PRINTB(" Simple: %6s", (N->p3->is_simple() ? "yes" : "no"));
PRINTB(" Valid: %6s", (N->p3->is_valid() ? "yes" : "no"));
PRINTB(" Vertices: %6d", N->p3->number_of_vertices());
PRINTB(" Halfedges: %6d", N->p3->number_of_halfedges());
PRINTB(" Edges: %6d", N->p3->number_of_edges());
@ -1528,20 +1595,47 @@ void MainWindow::actionDisplayCSGProducts()
e->setWindowTitle("CSG Products Dump");
e->setReadOnly(true);
e->setPlainText(QString("\nCSG before normalization:\n%1\n\n\nCSG after normalization:\n%2\n\n\nCSG rendering chain:\n%3\n\n\nHighlights CSG rendering chain:\n%4\n\n\nBackground CSG rendering chain:\n%5\n")
.arg(root_raw_term ? QString::fromLocal8Bit(root_raw_term->dump().c_str()) : "N/A",
root_norm_term ? QString::fromLocal8Bit(root_norm_term->dump().c_str()) : "N/A",
this->root_chain ? QString::fromLocal8Bit(this->root_chain->dump().c_str()) : "N/A",
highlights_chain ? QString::fromLocal8Bit(highlights_chain->dump().c_str()) : "N/A",
.arg(root_raw_term ? QString::fromLocal8Bit(root_raw_term->dump().c_str()) : "N/A",
root_norm_term ? QString::fromLocal8Bit(root_norm_term->dump().c_str()) : "N/A",
this->root_chain ? QString::fromLocal8Bit(this->root_chain->dump().c_str()) : "N/A",
highlights_chain ? QString::fromLocal8Bit(highlights_chain->dump().c_str()) : "N/A",
background_chain ? QString::fromLocal8Bit(background_chain->dump().c_str()) : "N/A"));
e->show();
e->resize(600, 400);
clearCurrentOutput();
}
void MainWindow::actionCheckValidity() {
if (GuiLocker::isLocked()) return;
GuiLocker lock;
#ifdef ENABLE_CGAL
void MainWindow::actionExportSTLorOFF(bool stl_mode)
setCurrentOutput();
if (!this->root_geom) {
PRINT("Nothing to validate! Try building first (press F6).");
clearCurrentOutput();
return;
}
if (this->root_geom->getDimension() != 3) {
PRINT("Current top level object is not a 3D object.");
clearCurrentOutput();
return;
}
bool valid = false;
if (const CGAL_Nef_polyhedron *N = dynamic_cast<const CGAL_Nef_polyhedron *>(this->root_geom.get()))
valid = N->p3->is_valid();
PRINTB(" Valid: %6s", (valid ? "yes" : "no"));
clearCurrentOutput();
#endif /* ENABLE_CGAL */
}
#ifdef ENABLE_CGAL
void MainWindow::actionExport(export_type_e export_type, const char *type_name, const char *suffix)
#else
void MainWindow::actionExportSTLorOFF(bool)
void MainWindow::actionExport(export_type_e, QString, QString)
#endif
{
if (GuiLocker::isLocked()) return;
@ -1568,27 +1662,38 @@ void MainWindow::actionExportSTLorOFF(bool)
return;
}
QString suffix = stl_mode ? ".stl" : ".off";
QString stl_filename = QFileDialog::getSaveFileName(this,
stl_mode ? "Export STL File" : "Export OFF File",
this->fileName.isEmpty() ? "Untitled"+suffix : QFileInfo(this->fileName).baseName()+suffix,
stl_mode ? "STL Files (*.stl)" : "OFF Files (*.off)");
if (stl_filename.isEmpty()) {
PRINTB("No filename specified. %s export aborted.", (stl_mode ? "STL" : "OFF"));
QString title = QString("Export %1 File").arg(type_name);
QString filter = QString("%1 Files (*%2)").arg(type_name, suffix);
QString filename = this->fileName.isEmpty() ? QString("Untitled") + suffix : QFileInfo(this->fileName).baseName() + suffix;
QString export_filename = QFileDialog::getSaveFileName(this, title, filename, filter);
if (export_filename.isEmpty()) {
PRINTB("No filename specified. %s export aborted.", type_name);
clearCurrentOutput();
return;
}
std::ofstream fstream(stl_filename.toUtf8());
std::ofstream fstream(export_filename.toUtf8());
if (!fstream.is_open()) {
PRINTB("Can't open file \"%s\" for export", stl_filename.toLocal8Bit().constData());
PRINTB("Can't open file \"%s\" for export", export_filename.toLocal8Bit().constData());
}
else {
if (stl_mode) exportFile(this->root_geom.get(), fstream, OPENSCAD_STL);
else exportFile(this->root_geom.get(), fstream, OPENSCAD_OFF);
switch (export_type) {
case EXPORT_TYPE_STL:
exportFile(this->root_geom.get(), fstream, OPENSCAD_STL);
break;
case EXPORT_TYPE_OFF:
exportFile(this->root_geom.get(), fstream, OPENSCAD_OFF);
break;
case EXPORT_TYPE_AMF:
exportFile(this->root_geom.get(), fstream, OPENSCAD_AMF);
break;
default:
assert(false && "Unknown export type");
break;
}
fstream.close();
PRINTB("%s export finished.", (stl_mode ? "STL" : "OFF"));
PRINTB("%s export finished.", type_name);
}
clearCurrentOutput();
@ -1597,38 +1702,54 @@ void MainWindow::actionExportSTLorOFF(bool)
void MainWindow::actionExportSTL()
{
actionExportSTLorOFF(true);
actionExport(EXPORT_TYPE_STL, "STL", ".stl");
}
void MainWindow::actionExportOFF()
{
actionExportSTLorOFF(false);
actionExport(EXPORT_TYPE_OFF, "OFF", ".off");
}
void MainWindow::actionExportDXF()
void MainWindow::actionExportAMF()
{
#ifdef ENABLE_CGAL
actionExport(EXPORT_TYPE_AMF, "AMF", ".amf");
}
QString MainWindow::get2dExportFilename(QString format, QString extension) {
setCurrentOutput();
if (!this->root_geom) {
PRINT("Nothing to export! Try building first (press F6).");
clearCurrentOutput();
return;
return QString();
}
if (this->root_geom->getDimension() != 2) {
PRINT("Current top level object is not a 2D object.");
clearCurrentOutput();
return;
return QString();
}
QString dxf_filename = QFileDialog::getSaveFileName(this,
"Export DXF File",
this->fileName.isEmpty() ? "Untitled.dxf" : QFileInfo(this->fileName).baseName()+".dxf",
"DXF Files (*.dxf)");
if (dxf_filename.isEmpty()) {
QString caption = QString("Export %1 File").arg(format);
QString suggestion = this->fileName.isEmpty()
? QString("Untitled%1").arg(extension)
: QFileInfo(this->fileName).baseName() + extension;
QString filter = QString("%1 Files (*%2)").arg(format, extension);
QString exportFilename = QFileDialog::getSaveFileName(this, caption, suggestion, filter);
if (exportFilename.isEmpty()) {
PRINT("No filename specified. DXF export aborted.");
clearCurrentOutput();
return QString();
}
return exportFilename;
}
void MainWindow::actionExportDXF()
{
#ifdef ENABLE_CGAL
QString dxf_filename = get2dExportFilename("DXF", ".dxf");
if (dxf_filename.isEmpty()) {
return;
}
@ -1646,6 +1767,26 @@ void MainWindow::actionExportDXF()
#endif /* ENABLE_CGAL */
}
void MainWindow::actionExportSVG()
{
QString svg_filename = get2dExportFilename("SVG", ".svg");
if (svg_filename.isEmpty()) {
return;
}
std::ofstream fstream(svg_filename.toUtf8());
if (!fstream.is_open()) {
PRINTB("Can't open file \"%s\" for export", svg_filename.toLocal8Bit().constData());
}
else {
exportFile(this->root_geom.get(), fstream, OPENSCAD_SVG);
fstream.close();
PRINT("SVG export finished.");
}
clearCurrentOutput();
}
void MainWindow::actionExportCSG()
{
setCurrentOutput();
@ -1656,7 +1797,7 @@ void MainWindow::actionExportCSG()
return;
}
QString csg_filename = QFileDialog::getSaveFileName(this, "Export CSG File",
QString csg_filename = QFileDialog::getSaveFileName(this, "Export CSG File",
this->fileName.isEmpty() ? "Untitled.csg" : QFileInfo(this->fileName).baseName()+".csg",
"CSG Files (*.csg)");
if (csg_filename.isEmpty()) {
@ -2001,6 +2142,10 @@ void MainWindow::closeEvent(QCloseEvent *event)
settings.setValue("window/position", pos());
settings_setValueList("window/splitter1sizes",splitter1->sizes());
settings_setValueList("window/splitter2sizes",splitter2->sizes());
if (this->tempFile) {
delete this->tempFile;
this->tempFile = NULL;
}
event->accept();
} else {
event->ignore();
@ -2025,12 +2170,6 @@ void MainWindow::setFont(const QString &family, uint size)
editor->setFont(font);
}
void MainWindow::setSyntaxHighlight(const QString &s)
{
this->highlighter->assignFormatsToTokens( s );
this->highlighter->rehighlight(); // slow on large files
}
void MainWindow::quit()
{
QCloseEvent ev;
@ -2049,6 +2188,7 @@ void MainWindow::consoleOutput(const std::string &msg, void *userdata)
MainWindow *thisp = static_cast<MainWindow*>(userdata);
QMetaObject::invokeMethod(thisp->console, "append", Qt::QueuedConnection,
Q_ARG(QString, QString::fromLocal8Bit(msg.c_str())));
if (thisp->procevents) QApplication::processEvents();
}
void MainWindow::setCurrentOutput()

View File

@ -115,7 +115,7 @@ const AbstractModule *ModuleContext::findLocalModule(const std::string &name) co
}
std::string replacement = Builtins::instance()->isDeprecated(name);
if (!replacement.empty()) {
PRINTB("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", name % replacement);
PRINT_DEPRECATION("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", name % replacement);
}
return m;
}
@ -139,34 +139,35 @@ AbstractNode *ModuleContext::instantiate_module(const ModuleInstantiation &inst,
}
#ifdef DEBUG
void ModuleContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst)
std::string ModuleContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst)
{
if (inst)
PRINTB("ModuleContext %p (%p) for %s inst (%p) ", this % this->parent % inst->name() % inst);
else
PRINTB("ModuleContext: %p (%p)", this % this->parent);
PRINTB(" document path: %s", this->document_path);
std::stringstream s;
if (inst)
s << boost::format("ModuleContext %p (%p) for %s inst (%p) ") % this % this->parent % inst->name() % inst;
else
s << boost::format("ModuleContext: %p (%p)") % this % this->parent;
s << boost::format(" document path: %s") % this->document_path;
if (mod) {
const Module *m = dynamic_cast<const Module*>(mod);
if (m) {
PRINT(" module args:");
s << " module args:";
BOOST_FOREACH(const Assignment &arg, m->definition_arguments) {
PRINTB(" %s = %s", arg.first % variables[arg.first]);
s << boost::format(" %s = %s") % arg.first % variables[arg.first];
}
}
}
typedef std::pair<std::string, Value> ValueMapType;
PRINT(" vars:");
BOOST_FOREACH(const ValueMapType &v, constants) {
PRINTB(" %s = %s", v.first % v.second);
}
BOOST_FOREACH(const ValueMapType &v, variables) {
PRINTB(" %s = %s", v.first % v.second);
}
BOOST_FOREACH(const ValueMapType &v, config_variables) {
PRINTB(" %s = %s", v.first % v.second);
}
s << " vars:";
BOOST_FOREACH(const ValueMapType &v, constants) {
s << boost::format(" %s = %s") % v.first % v.second;
}
BOOST_FOREACH(const ValueMapType &v, variables) {
s << boost::format(" %s = %s") % v.first % v.second;
}
BOOST_FOREACH(const ValueMapType &v, config_variables) {
s << boost::format(" %s = %s") % v.first % v.second;
}
return s.str();
}
#endif
@ -180,18 +181,18 @@ Value FileContext::evaluate_function(const std::string &name, const EvalContext
{
const AbstractFunction *foundf = findLocalFunction(name);
if (foundf) return foundf->evaluate(this, evalctx);
BOOST_FOREACH(const FileModule::ModuleContainer::value_type &m, this->usedlibs) {
// usedmod is NULL if the library wasn't be compiled (error or file-not-found)
FileModule *usedmod = ModuleCache::instance()->lookup(m);
if (usedmod &&
if (usedmod &&
usedmod->scope.functions.find(name) != usedmod->scope.functions.end()) {
FileContext ctx(*usedmod, this->parent);
ctx.initializeModule(*usedmod);
// FIXME: Set document path
#if 0 && DEBUG
PRINTB("New lib Context for %s func:", name);
ctx.dump(NULL, NULL);
#ifdef DEBUG
PRINTDB("New lib Context for %s func:", name);
PRINTDB("%s",ctx.dump(NULL, NULL));
#endif
return usedmod->scope.functions[name]->evaluate(&ctx, evalctx);
}
@ -208,14 +209,14 @@ AbstractNode *FileContext::instantiate_module(const ModuleInstantiation &inst, c
BOOST_FOREACH(const FileModule::ModuleContainer::value_type &m, this->usedlibs) {
FileModule *usedmod = ModuleCache::instance()->lookup(m);
// usedmod is NULL if the library wasn't be compiled (error or file-not-found)
if (usedmod &&
if (usedmod &&
usedmod->scope.modules.find(inst.name()) != usedmod->scope.modules.end()) {
FileContext ctx(*usedmod, this->parent);
ctx.initializeModule(*usedmod);
// FIXME: Set document path
#if 0 && DEBUG
PRINT("New file Context:");
ctx.dump(NULL, &inst);
#ifdef DEBUG
PRINTD("New file Context:");
PRINTDB("%s",ctx.dump(NULL, &inst));
#endif
return usedmod->scope.modules[inst.name()]->instantiate(&ctx, &inst, evalctx);
}

View File

@ -34,7 +34,7 @@ public:
const class EvalContext *evalctx;
#ifdef DEBUG
virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst);
virtual std::string dump(const class AbstractModule *mod, const ModuleInstantiation *inst);
#endif
private:
// Experimental code. See issue #399

View File

@ -78,7 +78,6 @@ std::string AbstractModule::dump(const std::string &indent, const std::string &n
ModuleInstantiation::~ModuleInstantiation()
{
BOOST_FOREACH(const Assignment &arg, this->arguments) delete arg.second;
}
IfElseModuleInstantiation::~IfElseModuleInstantiation()
@ -291,45 +290,58 @@ bool FileModule::handleDependencies()
if (this->is_handling_dependencies) return false;
this->is_handling_dependencies = true;
bool changed = false;
bool somethingchanged = false;
std::vector<std::pair<std::string,std::string> > updates;
// If a lib in usedlibs was previously missing, we need to relocate it
// by searching the applicable paths. We can identify a previously missing module
// as it will have a relative path.
// Iterating manually since we want to modify the container while iterating
FileModule::ModuleContainer::iterator iter = this->usedlibs.begin();
while (iter != this->usedlibs.end()) {
FileModule::ModuleContainer::iterator curr = iter++;
BOOST_FOREACH(std::string filename, this->usedlibs) {
bool wasmissing = false;
bool found = true;
// Get an absolute filename for the module
std::string filename = *curr;
if (!boosty::is_absolute(filename)) {
wasmissing = true;
fs::path fullpath = find_valid_path(this->path, filename);
if (!fullpath.empty()) filename = boosty::stringy(fullpath);
if (!fullpath.empty()) {
updates.push_back(std::make_pair(filename, boosty::stringy(fullpath)));
filename = boosty::stringy(fullpath);
}
else {
found = false;
}
}
FileModule *oldmodule = ModuleCache::instance()->lookup(filename);
FileModule *newmodule = ModuleCache::instance()->evaluate(filename);
// Detect appearance but not removal of files
if (newmodule && oldmodule != newmodule) {
changed = true;
if (found) {
bool wascached = ModuleCache::instance()->isCached(filename);
FileModule *oldmodule = ModuleCache::instance()->lookup(filename);
FileModule *newmodule;
bool changed = ModuleCache::instance()->evaluate(filename, newmodule);
// Detect appearance but not removal of files, and keep old module
// on compile errors (FIXME: Is this correct behavior?)
if (changed) {
#ifdef DEBUG
PRINTB_NOCACHE(" %s: %p -> %p", filename % oldmodule % newmodule);
PRINTB_NOCACHE(" %s: %p -> %p", filename % oldmodule % newmodule);
#endif
}
if (!newmodule) {
}
somethingchanged |= changed;
// Only print warning if we're not part of an automatic reload
if (!oldmodule && !wasmissing) {
if (!newmodule && !wascached && !wasmissing) {
PRINTB_NOCACHE("WARNING: Failed to compile library '%s'.", filename);
}
}
}
// Relative filenames which were located is reinserted as absolute filenames
typedef std::pair<std::string,std::string> stringpair;
BOOST_FOREACH(const stringpair &files, updates) {
this->usedlibs.erase(files.first);
this->usedlibs.insert(files.second);
}
this->is_handling_dependencies = false;
return changed;
return somethingchanged;
}
AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const

View File

@ -67,7 +67,8 @@ public:
AbstractModule() : feature(NULL) {}
AbstractModule(const Feature& feature) : feature(&feature) {}
virtual ~AbstractModule();
virtual bool is_enabled() const { return (feature == NULL) || feature->is_enabled(); };
virtual bool is_experimental() const { return feature != NULL; }
virtual bool is_enabled() const { return (feature == NULL) || feature->is_enabled(); }
virtual class AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const class EvalContext *evalctx = NULL) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
virtual double lookup_double_variable_with_default(Context &c, std::string variable, double def) const;

View File

@ -102,8 +102,6 @@ void AbstractNode::progress_report() const
std::ostream &operator<<(std::ostream &stream, const AbstractNode &node)
{
// FIXME: Don't use deep access to modinst members
if (node.modinst->isBackground()) stream << "%";
stream << node.toString();
return stream;
}

View File

@ -1,5 +1,6 @@
#include "nodedumper.h"
#include "state.h"
#include "module.h"
#include <string>
#include <sstream>
@ -47,6 +48,7 @@ std::string NodeDumper::dumpChildren(const AbstractNode &node)
iter != this->visitedchildren[node.index()].end();
iter++) {
assert(isCached(**iter));
if ((*iter)->modinst->isBackground()) dump << "%";
dump << this->cache[**iter] << "\n";
}

121
src/offset.cc Normal file
View File

@ -0,0 +1,121 @@
/*
* OpenSCAD (www.openscad.org)
* Copyright (C) 2009-2011 Clifford Wolf <clifford@clifford.at> and
* Marius Kintel <marius@kintel.net>
*
* This program is free software; 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 2 of the License, or
* (at your option) any later version.
*
* As a special exception, you have permission to link this program
* with the CGAL library and distribute executables, as long as you
* follow the requirements of the GNU GPL in regard to all of the
* software in the executable aside from CGAL.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "offsetnode.h"
#include "module.h"
#include "evalcontext.h"
#include "printutils.h"
#include "fileutils.h"
#include "builtin.h"
#include "calc.h"
#include "polyset.h"
#include "mathc99.h"
#include <sstream>
#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
class OffsetModule : public AbstractModule
{
public:
OffsetModule() { }
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
AbstractNode *OffsetModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
OffsetNode *node = new OffsetNode(inst);
AssignmentList args;
args += Assignment("delta");
Context c(ctx);
c.setVariables(args, evalctx);
node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble();
node->fa = c.lookup_variable("$fa").toDouble();
Value delta = c.lookup_variable("delta");
node->delta = 1;
delta.getDouble(node->delta);
Value miter_limit = c.lookup_variable("miter_limit", true);
node->miter_limit = 2;
miter_limit.getDouble(node->miter_limit);
Value join_type = c.lookup_variable("join_type", true);
if (join_type.type() == Value::STRING) {
std::string jt = join_type.toString();
if (std::string("bevel") == jt) {
node->join_type = ClipperLib::jtSquare;
} else if (std::string("round") == jt) {
node->join_type = ClipperLib::jtRound;
} else if (std::string("miter") == jt) {
node->join_type = ClipperLib::jtMiter;
} else {
PRINTB("WARNING: Unknown join_type for offset(): '%s'", jt);
}
if ((node->join_type != ClipperLib::jtMiter) && !miter_limit.isUndefined()) {
PRINTB("WARNING: miter_limit is ignored in offset() for join_type: '%s'", jt);
}
}
std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
std::string OffsetNode::toString() const
{
std::stringstream stream;
stream << this->name()
<< "(delta = " << std::dec << this->delta
<< ", join_type = "
<< (this->join_type == ClipperLib::jtSquare
? "bevel"
: this->join_type == ClipperLib::jtRound
? "round"
: "miter")
<< ", miter_limit = " << this->miter_limit
<< ", $fn = " << this->fn
<< ", $fa = " << this->fa
<< ", $fs = " << this->fs << ")";
return stream.str();
}
void register_builtin_offset()
{
Builtins::init("offset", new OffsetModule());
}

23
src/offsetnode.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef OFFSETNODE_H_
#define OFFSETNODE_H_
#include "node.h"
#include "visitor.h"
#include "value.h"
#include "clipper-utils.h"
class OffsetNode : public AbstractPolyNode
{
public:
OffsetNode(const ModuleInstantiation *mi) : AbstractPolyNode(mi), fn(0), fs(0), fa(0), delta(1), miter_limit(2.0), join_type(ClipperLib::jtMiter) { }
virtual Response accept(class State &state, Visitor &visitor) const {
return visitor.visit(state, *this);
}
virtual std::string toString() const;
virtual std::string name() const { return "offset"; }
double fn, fs, fa, delta, miter_limit;
ClipperLib::JoinType join_type;
};
#endif

View File

@ -111,11 +111,14 @@ static void help(const char *progname)
"%2% --camera=eyex,y,z,centerx,y,z ] \\\n"
"%2%[ --imgsize=width,height ] [ --projection=(o)rtho|(p)ersp] \\\n"
"%2%[ --render | --preview[=throwntogether] ] \\\n"
"%2%[ --enable=<feature> ]"
#ifdef DEBUG
" [ --debug=module ]"
"%2%[ --csglimit=num ]"
#ifdef ENABLE_EXPERIMENTAL
" [ --enable=<feature> ]"
#endif
"\\\n"
#ifdef DEBUG
"%2%[ --debug=module ] \\\n"
#endif
" \\\n"
"%2%filename\n",
progname % (const char *)tabstr);
exit(1);
@ -200,6 +203,13 @@ Camera get_camera( po::variables_map vm )
return camera;
}
#ifdef OPENSCAD_TESTING
#undef OPENSCAD_QTGUI
#else
#define OPENSCAD_QTGUI 1
#include <QApplication>
#endif
int cmdline(const char *deps_output_file, const std::string &filename, Camera &camera, const char *output_file, const fs::path &original_path, Render::type renderer, int argc, char ** argv )
{
#ifdef OPENSCAD_QTGUI
@ -215,7 +225,9 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
#endif
const char *stl_output_file = NULL;
const char *off_output_file = NULL;
const char *amf_output_file = NULL;
const char *dxf_output_file = NULL;
const char *svg_output_file = NULL;
const char *csg_output_file = NULL;
const char *png_output_file = NULL;
const char *ast_output_file = NULL;
@ -227,7 +239,9 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
if (suffix == ".stl") stl_output_file = output_file;
else if (suffix == ".off") off_output_file = output_file;
else if (suffix == ".amf") amf_output_file = output_file;
else if (suffix == ".dxf") dxf_output_file = output_file;
else if (suffix == ".svg") svg_output_file = output_file;
else if (suffix == ".csg") csg_output_file = output_file;
else if (suffix == ".png") png_output_file = output_file;
else if (suffix == ".ast") ast_output_file = output_file;
@ -241,8 +255,8 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
// Top context - this context only holds builtins
ModuleContext top_ctx;
top_ctx.registerBuiltin();
#if 0 && DEBUG
top_ctx.dump(NULL, NULL);
#ifdef DEBUG
PRINTDB("Top ModuleContext:\n%s",top_ctx.dump(NULL, NULL));
#endif
shared_ptr<Echostream> echostream;
if (echo_output_file)
@ -314,7 +328,7 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
std::vector<shared_ptr<CSGTerm> > highlight_terms;
std::vector<shared_ptr<CSGTerm> > background_terms;
CSGTermEvaluator csgRenderer(tree, &geomevaluator);
CSGTermEvaluator csgRenderer(tree);
shared_ptr<CSGTerm> root_raw_term = csgRenderer.evaluateCSGTerm(*root_node, highlight_terms, background_terms);
fs::current_path(original_path);
@ -347,7 +361,9 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
std::string geom_out;
if ( stl_output_file ) geom_out = std::string(stl_output_file);
else if ( off_output_file ) geom_out = std::string(off_output_file);
else if ( amf_output_file ) geom_out = std::string(amf_output_file);
else if ( dxf_output_file ) geom_out = std::string(dxf_output_file);
else if ( svg_output_file ) geom_out = std::string(svg_output_file);
else if ( png_output_file ) geom_out = std::string(png_output_file);
else {
PRINTB("Output file:%s\n",output_file);
@ -391,6 +407,21 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
}
}
if (amf_output_file) {
if (root_geom->getDimension() != 3) {
PRINT("Current top level object is not a 3D object.\n");
return 1;
}
std::ofstream fstream(amf_output_file);
if (!fstream.is_open()) {
PRINTB("Can't open file \"%s\" for export", amf_output_file);
}
else {
exportFile(root_geom.get(), fstream, OPENSCAD_AMF);
fstream.close();
}
}
if (dxf_output_file) {
if (root_geom->getDimension() != 2) {
PRINT("Current top level object is not a 2D object.\n");
@ -405,6 +436,21 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
fstream.close();
}
}
if (svg_output_file) {
if (root_geom->getDimension() != 2) {
PRINT("Current top level object is not a 2D object.\n");
return 1;
}
std::ofstream fstream(svg_output_file);
if (!fstream.is_open()) {
PRINTB("Can't open file \"%s\" for export", svg_output_file);
}
else {
exportFile(root_geom.get(), fstream, OPENSCAD_SVG);
fstream.close();
}
}
if (png_output_file) {
std::ofstream fstream(png_output_file,std::ios::out|std::ios::binary);
@ -432,19 +478,17 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
return 0;
}
#ifdef OPENSCAD_TESTING
#undef OPENSCAD_QTGUI
#else
#define OPENSCAD_QTGUI 1
#endif
#ifdef OPENSCAD_QTGUI
#include <QtPlugin>
#if defined(__MINGW64__) || defined(__MINGW32__) || defined(_MSCVER)
#if QT_VERSION < 0x050000
Q_IMPORT_PLUGIN(qtaccessiblewidgets)
#endif // QT_VERSION
#endif // MINGW64/MINGW32/MSCVER
#include "MainWindow.h"
#ifdef __APPLE__
#include "EventFilter.h"
#endif
#include <QApplication>
#include <QString>
#include <QDir>
#include <QFileInfo>
@ -456,15 +500,16 @@ Q_DECLARE_METATYPE(shared_ptr<const Geometry>);
static QString assemblePath(const fs::path& absoluteBaseDir,
const string& fileName) {
if (fileName.empty()) return "";
QString qsDir( boosty::stringy( absoluteBaseDir ).c_str() );
QString qsFile( fileName.c_str() );
QFileInfo info( qsDir, qsFile ); // if qsfile is absolute, dir is ignored.
QString qsDir = QString::fromLocal8Bit( boosty::stringy( absoluteBaseDir ).c_str() );
QString qsFile = QString::fromLocal8Bit( fileName.c_str() );
// if qsfile is absolute, dir is ignored. (see documentation of QFileInfo)
QFileInfo info( qsDir, qsFile );
return info.absoluteFilePath();
}
bool QtUseGUI()
{
#ifdef Q_WS_X11
#ifdef Q_OS_X11
// see <http://qt.nokia.com/doc/4.5/qapplication.html#QApplication-2>:
// On X11, the window system is initialized if GUIenabled is true. If GUIenabled
// is false, the application does not connect to the X server. On Windows and
@ -487,7 +532,7 @@ int gui(vector<string> &inputFiles, const fs::path &original_path, int argc, cha
}
#endif
QApplication app(argc, argv, true); //useGUI);
#ifdef Q_WS_MAC
#ifdef Q_OS_MAC
app.installEventFilter(new EventFilter(&app));
#endif
// set up groups for QSettings
@ -503,7 +548,7 @@ int gui(vector<string> &inputFiles, const fs::path &original_path, int argc, cha
QDir exdir(app_path);
QString qexamplesdir;
#ifdef Q_WS_MAC
#ifdef Q_OS_MAC
exdir.cd("../Resources"); // Examples can be bundled
if (!exdir.exists("examples")) exdir.cd("../../..");
#elif defined(Q_OS_UNIX)
@ -523,11 +568,11 @@ int gui(vector<string> &inputFiles, const fs::path &original_path, int argc, cha
MainWindow::setExamplesDir(qexamplesdir);
parser_init(app_path.toLocal8Bit().constData());
#ifdef Q_WS_MAC
#ifdef Q_OS_MAC
installAppleEventHandlers();
#endif
#if defined(OPENSCAD_DEPLOY) && defined(Q_WS_MAC)
#if defined(OPENSCAD_DEPLOY) && defined(Q_OS_MAC)
AutoUpdater *updater = new SparkleAutoUpdater;
AutoUpdater::setUpdater(updater);
if (updater->automaticallyChecksForUpdates()) updater->checkForUpdates();
@ -545,12 +590,17 @@ int gui(vector<string> &inputFiles, const fs::path &original_path, int argc, cha
BOOST_FOREACH(const string &infile, inputFiles) {
new MainWindow(assemblePath(original_path, infile));
}
app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
#else
MainWindow *m = new MainWindow(assemblePath(original_path, inputFiles[0]));
app.connect(m, SIGNAL(destroyed()), &app, SLOT(quit()));
new MainWindow(assemblePath(original_path, inputFiles[0]));
#endif
return app.exec();
app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
int rc = app.exec();
if (MainWindow::windows) {
foreach (MainWindow *mainw, *MainWindow::windows) {
delete mainw;
}
}
return rc;
}
#else // OPENSCAD_QTGUI
bool QtUseGUI() { return false; }
@ -564,7 +614,7 @@ int gui(const vector<string> &inputFiles, const fs::path &original_path, int arg
int main(int argc, char **argv)
{
int rc = 0;
#ifdef Q_WS_MAC
#ifdef Q_OS_MAC
set_output_handler(CocoaUtils::nslog, NULL);
#endif
#ifdef ENABLE_CGAL
@ -586,6 +636,7 @@ int main(int argc, char **argv)
("info", "print information about the building process")
("render", "if exporting a png image, do a full CGAL render")
("preview", po::value<string>(), "if exporting a png image, do an OpenCSG(default) or ThrownTogether preview")
("csglimit", po::value<unsigned int>(), "if exporting a png image, stop rendering at the given number of CSG elements")
("camera", po::value<string>(), "parameters for camera when exporting png")
("imgsize", po::value<string>(), "=width,height for exporting png")
("projection", po::value<string>(), "(o)rtho or (p)erspective when exporting png")
@ -596,7 +647,10 @@ int main(int argc, char **argv)
("d,d", po::value<string>(), "deps-file")
("m,m", po::value<string>(), "makefile")
("D,D", po::value<vector<string> >(), "var=val")
("enable", po::value<vector<string> >(), "enable experimental features");
#ifdef ENABLE_EXPERIMENTAL
("enable", po::value<vector<string> >(), "enable experimental features")
#endif
;
po::options_description hidden("Hidden options");
hidden.add_options()
@ -618,7 +672,10 @@ int main(int argc, char **argv)
}
OpenSCAD::debug = "";
if (vm.count("debug")) OpenSCAD::debug = vm["debug"].as<string>();
if (vm.count("debug")) {
OpenSCAD::debug = vm["debug"].as<string>();
PRINTB("Debug on. --debug=%s",OpenSCAD::debug);
}
if (vm.count("help")) help(argv[0]);
if (vm.count("version")) version();
if (vm.count("info")) info();
@ -630,18 +687,22 @@ int main(int argc, char **argv)
if (vm["preview"].as<string>() == "throwntogether")
renderer = Render::THROWNTOGETHER;
if (vm.count("csglimit")) {
RenderSettings::inst()->openCSGTermLimit = vm["csglimit"].as<unsigned int>();
}
if (vm.count("o")) {
// FIXME: Allow for multiple output files?
if (output_file) help(argv[0]);
output_file = vm["o"].as<string>().c_str();
}
if (vm.count("s")) {
PRINT("DEPRECATED: The -s option is deprecated. Use -o instead.\n");
printDeprecation("DEPRECATED: The -s option is deprecated. Use -o instead.\n");
if (output_file) help(argv[0]);
output_file = vm["s"].as<string>().c_str();
}
if (vm.count("x")) {
PRINT("DEPRECATED: The -x option is deprecated. Use -o instead.\n");
printDeprecation("DEPRECATED: The -x option is deprecated. Use -o instead.\n");
if (output_file) help(argv[0]);
output_file = vm["x"].as<string>().c_str();
}
@ -662,11 +723,13 @@ int main(int argc, char **argv)
commandline_commands += ";\n";
}
}
#ifdef ENABLE_EXPERIMENTAL
if (vm.count("enable")) {
BOOST_FOREACH(const string &feature, vm["enable"].as<vector<string> >()) {
Feature::enable_feature(feature);
}
}
#endif
vector<string> inputFiles;
if (vm.count("input-file")) {
inputFiles = vm["input-file"].as<vector<string> >();

Some files were not shown because too many files have changed in this diff Show More