mirror of https://github.com/vitalif/openscad
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.txtmaster
commit
2cba2a1b55
|
@ -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
|
||||
|
|
51
.travis.yml
51
.travis.yml
|
@ -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="
|
||||
|
22
README.md
22
README.md
|
@ -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
|
||||
|
||||
|
|
411
RELEASE_NOTES
411
RELEASE_NOTES
|
@ -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
|
||||
|
|
|
@ -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@"
|
||||
|
|
|
@ -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@"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
---------------------------------
|
||||
|
|
104
doc/testing.txt
104
doc/testing.txt
|
@ -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
|
||||
|
||||
"
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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);
|
29
glib-2.0.pri
29
glib-2.0.pri
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -4,4 +4,5 @@ Version=1.0
|
|||
Name=OpenSCAD
|
||||
Icon=openscad
|
||||
Exec=openscad %f
|
||||
MimeType=application/x-openscad;
|
||||
Categories=Graphics;3DGraphics;Engineering;Development;
|
||||
|
|
|
@ -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
|
26
openscad.pro
26
openscad.pro
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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
|
|
@ -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.
|
||||
|
|
@ -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.
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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}'`
|
||||
|
|
|
@ -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)"
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}))
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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/..
|
|
@ -23,7 +23,7 @@
|
|||
</p>
|
||||
|
||||
<p>
|
||||
Copyright (C) 2009-2013 <a href="https://github.com/kintel">Marius Kintel</a> <marius@kintel.net> and <a href="http://clifford.at">Clifford Wolf</a> <clifford@clifford.at>
|
||||
Copyright (C) 2009-2014 <a href="https://github.com/kintel">Marius Kintel</a> <marius@kintel.net> and <a href="http://clifford.at">Clifford Wolf</a> <clifford@clifford.at>
|
||||
</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>
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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><</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QPushButton" name="nextButton">
|
||||
<property name="text">
|
||||
<string>></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><</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QPushButton" name="nextButton">
|
||||
<property name="text">
|
||||
<string>></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 &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>
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
#include "PlatformUtils.h"
|
||||
#include "boosty.h"
|
||||
|
||||
std::string PlatformUtils::pathSeparatorChar()
|
||||
{
|
||||
return ":";
|
||||
}
|
||||
|
||||
std::string PlatformUtils::documentsPath()
|
||||
{
|
||||
const char *home = getenv("HOME");
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
181
src/cgalutils.cc
181
src/cgalutils.cc
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
12
src/editor.h
12
src/editor.h
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
200
src/export.cc
200
src/export.cc
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
88
src/func.cc
88
src/func.cc
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
312
src/mainwin.cc
312
src/mainwin.cc
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
|
@ -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
|
127
src/openscad.cc
127
src/openscad.cc
|
@ -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
Loading…
Reference in New Issue