summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordon bright <hugh.m.bright@gmail.com>2013-01-28 02:42:20 (GMT)
committerdon bright <hugh.m.bright@gmail.com>2013-01-28 02:42:20 (GMT)
commit1e64dddf1ea30282c89de7f35854a68614234652 (patch)
tree165d37c1c66f6ff79d48c74794238b3f0bed09da /src
parent5c779159c208ca3d88c88479ab29f9cd66574859 (diff)
parentd0856efe6da545693f9c50a8a2514a9f999ab5ef (diff)
Merge branch 'master' of github.com:openscad/openscad into issue159
Diffstat (limited to 'src')
-rw-r--r--src/AboutDialog.h7
-rw-r--r--src/AboutDialog.html147
-rw-r--r--src/AboutDialog.ui86
-rw-r--r--src/CGALEvaluator.cc129
-rw-r--r--src/CGALRenderer.cc11
-rw-r--r--src/CGAL_Nef_polyhedron.cc6
-rw-r--r--src/CGAL_Nef_polyhedron.h9
-rw-r--r--src/CGAL_Nef_polyhedron_DxfData.cc31
-rw-r--r--src/MainWindow.ui2
-rw-r--r--src/ModuleCache.cc15
-rw-r--r--src/OpenCSGWarningDialog.cc4
-rw-r--r--src/PolySetCGALEvaluator.cc223
-rw-r--r--src/boosty.h8
-rw-r--r--src/cgal.h12
-rw-r--r--src/cgalutils.cc32
-rw-r--r--src/cgalutils.h2
-rw-r--r--src/cgalworker.cc2
-rw-r--r--src/color.cc5
-rw-r--r--src/context.cc20
-rw-r--r--src/context.h2
-rw-r--r--src/csgterm.cc42
-rw-r--r--src/dxfdata.cc2
-rw-r--r--src/dxfdim.cc11
-rw-r--r--src/dxftess-cgal.cc2
-rw-r--r--src/editor.cc2
-rw-r--r--src/editor.h16
-rw-r--r--src/export.cc4
-rw-r--r--src/func.cc51
-rw-r--r--src/handle_dep.cc8
-rw-r--r--src/highlighter.cc299
-rw-r--r--src/highlighter.h23
-rw-r--r--src/import.cc6
-rw-r--r--src/lexer.l11
-rw-r--r--src/linalg.cc21
-rw-r--r--src/linalg.h7
-rw-r--r--src/mainwin.cc128
-rw-r--r--src/module.cc5
-rw-r--r--src/module.h3
-rw-r--r--src/openscad.cc24
-rw-r--r--src/parser.y41
-rw-r--r--src/parsersettings.cc10
-rw-r--r--src/polyset.cc6
-rw-r--r--src/polyset.h15
-rw-r--r--src/printutils.h22
-rw-r--r--src/renderer.cc1
-rw-r--r--src/stl-utils.cc73
-rw-r--r--src/surface.cc2
-rw-r--r--src/svg.cc249
-rw-r--r--src/svg.h28
-rw-r--r--src/transform.cc4
-rw-r--r--src/traverser.cc2
-rw-r--r--src/version_check.h27
-rw-r--r--src/winconsole.c84
53 files changed, 1497 insertions, 485 deletions
diff --git a/src/AboutDialog.h b/src/AboutDialog.h
index 34122a0..2211e63 100644
--- a/src/AboutDialog.h
+++ b/src/AboutDialog.h
@@ -3,15 +3,22 @@
#include "ui_AboutDialog.h"
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+
class AboutDialog : public QDialog, public Ui::AboutDialog
{
Q_OBJECT;
public:
AboutDialog(QWidget *) {
setupUi(this);
+ this->setWindowTitle( QString("About OpenSCAD ") + QString(TOSTRING( OPENSCAD_VERSION)) );
this->aboutText->setOpenExternalLinks(true);
QUrl flattr_qurl(":icons/flattr.png" );
this->aboutText->loadResource( QTextDocument::ImageResource, flattr_qurl );
+ QString tmp = this->aboutText->toHtml();
+ tmp.replace("__VERSION__",QString(TOSTRING(OPENSCAD_VERSION)));
+ this->aboutText->setHtml(tmp);
}
};
diff --git a/src/AboutDialog.html b/src/AboutDialog.html
new file mode 100644
index 0000000..6203e83
--- /dev/null
+++ b/src/AboutDialog.html
@@ -0,0 +1,147 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+
+<html>
+
+<!-- Please note that Qt's TextBrowser renders things slightly unusually, so
+ a normal browser alone is not a sufficient test. Just edit this file and rerun
+ make to do your testing. -->
+
+<head>
+ <meta name="qrichtext" content="1" />
+</head>
+
+
+<body style="font-family:'Arial'; font-size:13pt;">
+
+<p>
+<a align=right href="https://flattr.com/submit/auto?user_id=openscad&amp;url=http://openscad.org&amp;title=OpenSCAD&amp;language=&amp;tags=github&amp;category=software"><img align=right src=":icons/flattr.png" /></a>
+</p>
+
+<p>
+<a href="http://www.openscad.org">OpenSCAD</a> version __VERSION__
+</p>
+
+<p>
+Copyright (C) 2009-2013 <a href="https://github.com/kintel">Marius Kintel</a> &lt;marius@kintel.net&gt; and <a href="http://clifford.at">Clifford Wolf</a> &lt;clifford@clifford.at&gt;
+</p>
+
+<p>
+<b>License</b>
+</p>
+
+<p>
+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.
+</p>
+<p>
+Please visit this link for a copy of the license: <a href="http://www.gnu.org/licenses/gpl-2.0.html">GPL 2.0</a>
+</p>
+<p>
+<b>Tools &amp; Libraries used</b>
+</p>
+
+<lu>
+<li><a href="http://gmplib.org/">GNU GMP</a>
+<li><a href="http://www.mpfr.org/">GNU MPFR</a>
+<li><a href="http://www.cgal.org">CGAL</a>
+<li><a href="http://eigen.tuxfamily.org">Eigen2</a>
+<li><a href="http://www.opencsg.org">OpenCSG</a>
+<li><a href="http://www.opengl.org/">OpenGL</a>
+<li><a href="http://glew.sourceforge.net">GLEW</a>
+<li><a href="http://qt.nokia.com">Qt Toolkit</a>
+<li><a href="http://www.boost.org">Boost</a>
+<li><a href="http://www.gnu.org/software/bison/">Bison</a>
+<li><a href="http://flex.sourceforge.net/">Flex</a>
+<li><a href="http://www.cmake.org">CMake</a>
+<li><a href="http://www.mingw.org/">MingW</a>
+<li><a href="http://lodev.org/lodepng/">LodePNG</a>
+<li><a href="http://www.mxe.cc">MXE</a>
+<li><a href="http://www.linux.org">Linux</a>
+<li><a href="http://www.apple.com/osx/">Mac OSX</a>
+<li><a href="http://www.stroustrup.com/C++.html">C++</a>, <a href="http://gcc.gnu.org/">GCC</a>, <a href="http://clang.llvm.org/">clang</a>
+<li><a href="http://www.python.org">python</a>
+<li><a href="http://nsis.sourceforge.net/Main_Page">Nullsoft installer</a>
+</lu>
+</p>
+
+<p>
+<b>Acknowledgements</b>
+</p>
+
+<p>
+<b>OpenSCAD Github Project members (public)</b>
+</p>
+
+<lu>
+<li><a href="https://github.com/kintel">Marius Kintel </a>
+<li><a href="http://clifford.at">Clifford Wolf</a>
+<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>
+</lu>
+
+<p>
+<b><a href="http://www.debian.org">Debian</a> maintainer:</b>
+ <a href="http://christian.amsuess.com/">chrysn</a>
+</p>
+
+<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>
+</lu>
+
+
+<p>
+<b>Mailing list, bug reports, testing, contribs, &c</b>
+</p>
+
+nop head, Triffid Hunter, Len Trigg, Kliment Yanev, Christian Siefkes,
+Andrew Plumb, Whosawhatsis, MichaelAtOz, Tony Buser, mrhdias,
+ibyte8bits, Koen Kooi, Tomas Mudrunka, knuds, cadr, mshearn, Hans L,
+Brett Sutton, hmnapier, Eero af Heurlin, caliston, 5263, ghost, 42loop,
+uniqx, Michael Thomson, Michael Ivko, Pierre Doucet, myglc2, Alan Cox,
+Peter Falke, Michael Ambrus, Gordon Wrigley, Ed Nisley, Stony Smith,
+Pasca Andrei, David Goodenough, William A Adams, mrrobinson, 1i7,
+benhowes, 5263, Craig Trader, Miro Hrončok, ... and many others
+
+<p>
+<b>Hosting &amp; resources</b>
+</p>
+
+<lu>
+<li><a href="http://www.github.com">Github</a>
+<li><a href="http://rocklinux.net/pipermail/openscad/">Rock Linux</a>
+<li><a href="http://www.thingiverse.com">Thingiverse</a>
+</lu>
+
+<p>
+<a href="http://guerby.org/">Laurent Guerby</a> and the
+<a href="http://gcc.gnu.org/wiki/CompileFarm">GCC Compile Farm,</a> with
+<a href="http://osuosl.org/">OSUOSL,</a> <a href="http://www.irill.org">IRILL,</a>
+<a href="http://www.fsffrance.org">FSF France,</a> <a href="http://www.amd.com">AMD</a>,
+<a href="http://www.intel.com">Intel</a>, <a href="http://www.ibm.com">IBM</a>, &c.
+</p>
+
+<p>
+Trademarks are property of their owners and do not imply affiliation with OpenSCAD
+</p>
+
+<p>
+Apologies to anyone left out. Please file an issue on OpenSCAD's github if you know of someone who belongs here.
+</p>
+
+</body>
+</html>
diff --git a/src/AboutDialog.ui b/src/AboutDialog.ui
index 93f1401..587d27e 100644
--- a/src/AboutDialog.ui
+++ b/src/AboutDialog.ui
@@ -19,89 +19,17 @@
<property name="readOnly">
<bool>true</bool>
</property>
- <property name="html">
- <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
-&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
-p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://flattr.com/submit/auto?user_id=openscad&amp;amp;url=http://openscad.org&amp;amp;title=OpenSCAD&amp;amp;language=&amp;amp;tags=github&amp;amp;category=software&quot;&gt;&lt;img src=&quot;:icons/flattr.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p align=&quot;right&quot; style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.openscad.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;OpenSCAD&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; is Copyright (C) 2009-2011 &lt;/span&gt;&lt;a href=&quot;https://github.com/kintel&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Marius Kintel &lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; &amp;lt;marius@kintel.net&amp;gt; and &lt;/span&gt;&lt;a href=&quot;http://clifford.at&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Clifford Wolf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; &amp;lt;clifford@clifford.at&amp;gt;&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;License&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;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.&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;Please visit this link for a copy of the license: &lt;/span&gt;&lt;a href=&quot;http://www.gnu.org/licenses/gpl-2.0.html&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;GPL 2.0&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;Tools &amp;amp; Libraries used&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://gmplib.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;GNU GMP&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.mpfr.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;GNU MPFR&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.cgal.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;CGAL&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://eigen.tuxfamily.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Eigen2&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.opencsg.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;OpenCSG&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.opengl.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;OpenGL&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://glew.sourceforge.net&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;GLEW&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://qt.nokia.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Qt Toolkit&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.boost.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Boost&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.gnu.org/software/bison/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Bison&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://flex.sourceforge.net/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Flex&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.cmake.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;CMake&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://lodev.org/lodepng/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;LodePNG&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.mingw.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;MingW&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.mxe.cc&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;MXE&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.linux.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Linux&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.apple.com/osx/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Mac OSX&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.stroustrup.com/C++.html&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;C++&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;, &lt;/span&gt;&lt;a href=&quot;http://gcc.gnu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;GCC&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;, &lt;/span&gt;&lt;a href=&quot;http://clang.llvm.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;clang&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.python.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;python&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://nsis.sourceforge.net/Main_Page&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Nullsoft installer&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#0000ff;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;Acknowledgements&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.github.com/openscad&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;OpenSCAD Github Project&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; members (public):&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/kintel&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Marius Kintel &lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://clifford.at&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Clifford Wolf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; &lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.github.com/GilesBathgate&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Giles Bathgate&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/brad&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Brad Pitcher&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#0000ff;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.debian.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Debian &lt;/span&gt;&lt;/a&gt;maintainer:&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#0000ff;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://christian.amsuess.com/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Christian M. Amsüss&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#0000ff;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Patches:&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/meta23&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;meta23&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/jasonblewis&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;jasonblewis&lt;/span&gt;&lt;/a&gt; &lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/gregjurman&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;gregjurman&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/brianolson&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;brianolson&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/tjhowse&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;tjhowse&lt;/span&gt;&lt;/a&gt; &lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/logxen&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;logxen&lt;/span&gt;&lt;/a&gt; (Mark A Cooper)&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/iamwilhelm&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;iamwilhelm&lt;/span&gt;&lt;/a&gt; (Wil Chung)&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/clothbot&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;clothbot&lt;/span&gt;&lt;/a&gt; (Andrew Plumb)&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/colah&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;colah&lt;/span&gt;&lt;/a&gt; (Christopher Olah)&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt; &lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Bug reports:&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; &lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;nop head, Triffid Hunter, Len Trigg, &lt;/span&gt;Kliment Yanev, Christian Siefkes, Whosawhatsis, MichaelAtOz, mrhdias, ibyte8bits, Koen Kooi, Tomas Mudrunka, knuds, cadr, mshearn, Hans L, Brett Sutton, hmnapier, Eero af Heurlin, caliston, 5263, ghost, 42loop, uniqx, Michael Thomson, Michael Ivko, Pierre Doucet, myglc2, Alan Cox, Peter Falke, Michael Ambrus, Gordon Wrigley, Ed Nisley, Stony Smith, Pasca Andrei, David Goodenough, William A Adams ... and many others&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;Hosting &amp;amp; resources&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.github.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Github&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; source repository&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://rocklinux.net/pipermail/openscad/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Rock Linux&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; mailing list&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#0000ff;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.thingiverse.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Thingiverse&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; &lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://guerby.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Laurent Guerby&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; and the &lt;/span&gt;&lt;a href=&quot;http://gcc.gnu.org/wiki/CompileFarm&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;GCC Compile Farm,&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; with &lt;/span&gt;&lt;a href=&quot;http://osuosl.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;OSUOSL,&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; &lt;/span&gt;&lt;a href=&quot;http://www.ibm.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;IBM&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;, &lt;/span&gt;&lt;a href=&quot;http://www.irill.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;IRILL,&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; &lt;/span&gt;&lt;a href=&quot;http://www.intel.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Intel&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;, &lt;/span&gt;&lt;a href=&quot;http://www.fsffrance.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;FSF France,&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; and &lt;/span&gt;&lt;a href=&quot;http://www.amd.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;AMD&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Apologies to anyone accidentally left out. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <property name="source">
+ <url>
+ <string>qrc:/src/AboutDialog.html</string>
+ </url>
</property>
</widget>
</item>
</layout>
</widget>
- <resources/>
+ <resources>
+ <include location="../openscad.qrc"/>
+ </resources>
<connections/>
</ui>
diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc
index ee04e05..4deb3b3 100644
--- a/src/CGALEvaluator.cc
+++ b/src/CGALEvaluator.cc
@@ -61,14 +61,16 @@ void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedr
if (target.dim != 2 && target.dim != 3) {
assert(false && "Dimension of Nef polyhedron must be 2 or 3");
}
- if (src.empty()) return; // Empty polyhedron. This can happen for e.g. square([0,0])
+ if (src.isEmpty()) return; // Empty polyhedron. This can happen for e.g. square([0,0])
+ if (target.isEmpty() && op != CGE_UNION) return; // empty op <something> => empty
if (target.dim != src.dim) return; // If someone tries to e.g. union 2d and 3d objects
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
try {
switch (op) {
case CGE_UNION:
- target += src;
+ if (target.isEmpty()) target = src.copy();
+ else target += src;
break;
case CGE_INTERSECTION:
target *= src;
@@ -81,15 +83,13 @@ void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedr
break;
}
}
- catch (CGAL::Failure_exception e) {
- // union && difference assert triggered by testdata/scad/bugs/rotate-diff-nonmanifold-crash.scad
+ 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 == CGE_UNION ? "union" : op == CGE_INTERSECTION ? "intersection" : op == CGE_DIFFERENCE ? "difference" : op == CGE_MINKOWSKI ? "minkowski" : "UNKNOWN";
PRINTB("CGAL error in CGAL_Nef_polyhedron's %s operator: %s", opstr % e.what());
- // Minkowski errors can result in corrupt polyhedrons
- if (op == CGE_MINKOWSKI) {
- target = src;
- }
+ // Errors can result in corrupt polyhedrons, so put back the old one
+ target = src;
}
CGAL::set_error_behaviour(old_behaviour);
}
@@ -112,7 +112,8 @@ CGAL_Nef_polyhedron CGALEvaluator::applyToChildren(const AbstractNode &node, CGA
if (!isCached(*chnode)) {
CGALCache::instance()->insert(this->tree.getIdString(*chnode), chN);
}
- if (N.empty()) N = chN.copy();
+ // Initialize N on first iteration with first expected geometric object
+ if (N.isNull() && !N.isEmpty()) N = chN.copy();
else process(N, chN, op);
chnode->progress_report();
@@ -132,6 +133,7 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
const CGAL_Nef_polyhedron &chN = item.second;
// FIXME: Don't use deep access to modinst members
if (chnode->modinst->isBackground()) continue;
+ if (chN.dim == 0) continue; // Ignore object with dimension 0 (e.g. echo)
if (dim == 0) {
dim = chN.dim;
}
@@ -150,9 +152,14 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
}
else if (dim == 3) {
CGAL_Polyhedron P;
- chN.p3->convert_to_Polyhedron(P);
- std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points3d),
- boost::bind(static_cast<const CGAL_Polyhedron::Vertex::Point_3&(CGAL_Polyhedron::Vertex::*)() const>(&CGAL_Polyhedron::Vertex::point), _1));
+ if (!chN.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 {
+ chN.p3->convert_to_Polyhedron(P);
+ std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points3d),
+ boost::bind(static_cast<const CGAL_Polyhedron::Vertex::Point_3&(CGAL_Polyhedron::Vertex::*)() const>(&CGAL_Polyhedron::Vertex::point), _1));
+ }
}
chnode->progress_report();
}
@@ -165,7 +172,8 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
}
else if (dim == 3) {
CGAL_Polyhedron P;
- CGAL::convex_hull_3(points3d.begin(), points3d.end(), P);
+ if (points3d.size()>3)
+ CGAL::convex_hull_3(points3d.begin(), points3d.end(), P);
N = CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron3(P));
}
return N;
@@ -240,53 +248,60 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node)
if (!isCached(node)) {
// First union all children
N = applyToChildren(node, CGE_UNION);
+ if ( matrix_contains_infinity( node.matrix ) || matrix_contains_nan( node.matrix ) ) {
+ // due to the way parse/eval works we can't currently distinguish between NaN and Inf
+ PRINT("Warning: Transformation matrix contains Not-a-Number and/or Infinity - removing object.");
+ N.reset();
+ }
// Then apply transform
- // If there is no geometry under the transform, N will be empty and of dim 0,
- // just just silently ignore such nodes
- if (N.dim == 2) {
- // Unfortunately CGAL provides no transform method for CGAL_Nef_polyhedron2
- // objects. So we convert in to our internal 2d data format, transform it,
- // tesselate it and create a new CGAL_Nef_polyhedron2 from it.. What a hack!
-
- Eigen::Matrix2f testmat;
- testmat << node.matrix(0,0), node.matrix(0,1), node.matrix(1,0), node.matrix(1,1);
- if (testmat.determinant() == 0) {
- PRINT("Warning: Scaling a 2D object with 0 - removing object");
- N.reset();
- }
- else {
- CGAL_Aff_transformation2 t(
- node.matrix(0,0), node.matrix(0,1), node.matrix(0,3),
- node.matrix(1,0), node.matrix(1,1), node.matrix(1,3), node.matrix(3,3));
+ // If there is no geometry under the transform, N will be empty
+ // just silently ignore such nodes
+ if (!N.isNull()) {
+ if (N.dim == 2) {
+ // Unfortunately CGAL provides no transform method for CGAL_Nef_polyhedron2
+ // objects. So we convert in to our internal 2d data format, transform it,
+ // tesselate it and create a new CGAL_Nef_polyhedron2 from it.. What a hack!
- DxfData *dd = N.convertToDxfData();
- for (size_t i=0; i < dd->points.size(); i++) {
- CGAL_Kernel2::Point_2 p = CGAL_Kernel2::Point_2(dd->points[i][0], dd->points[i][1]);
- p = t.transform(p);
- dd->points[i][0] = to_double(p.x());
- dd->points[i][1] = to_double(p.y());
+ Eigen::Matrix2f testmat;
+ testmat << node.matrix(0,0), node.matrix(0,1), node.matrix(1,0), node.matrix(1,1);
+ if (testmat.determinant() == 0) {
+ PRINT("Warning: Scaling a 2D object with 0 - removing object");
+ N.reset();
+ }
+ else {
+ CGAL_Aff_transformation2 t(
+ node.matrix(0,0), node.matrix(0,1), node.matrix(0,3),
+ node.matrix(1,0), node.matrix(1,1), node.matrix(1,3), node.matrix(3,3));
+
+ DxfData *dd = N.convertToDxfData();
+ for (size_t i=0; i < dd->points.size(); i++) {
+ CGAL_Kernel2::Point_2 p = CGAL_Kernel2::Point_2(dd->points[i][0], dd->points[i][1]);
+ p = t.transform(p);
+ dd->points[i][0] = to_double(p.x());
+ dd->points[i][1] = to_double(p.y());
+ }
+
+ PolySet ps;
+ ps.is2d = true;
+ dxf_tesselate(&ps, *dd, 0, true, false, 0);
+
+ N = evaluateCGALMesh(ps);
+ delete dd;
}
-
- PolySet ps;
- ps.is2d = true;
- dxf_tesselate(&ps, *dd, 0, true, false, 0);
-
- N = evaluateCGALMesh(ps);
- delete dd;
- }
- }
- else if (N.dim == 3) {
- if (node.matrix.matrix().determinant() == 0) {
- PRINT("Warning: Scaling a 3D object with 0 - removing object");
- N.reset();
}
- else {
- CGAL_Aff_transformation t(
- node.matrix(0,0), node.matrix(0,1), node.matrix(0,2), node.matrix(0,3),
- node.matrix(1,0), node.matrix(1,1), node.matrix(1,2), node.matrix(1,3),
- node.matrix(2,0), node.matrix(2,1), node.matrix(2,2), node.matrix(2,3), node.matrix(3,3));
- N.p3->transform(t);
+ else if (N.dim == 3) {
+ if (node.matrix.matrix().determinant() == 0) {
+ PRINT("Warning: Scaling a 3D object with 0 - removing object");
+ N.reset();
+ }
+ else {
+ CGAL_Aff_transformation t(
+ node.matrix(0,0), node.matrix(0,1), node.matrix(0,2), node.matrix(0,3),
+ node.matrix(1,0), node.matrix(1,1), node.matrix(1,2), node.matrix(1,3),
+ node.matrix(2,0), node.matrix(2,1), node.matrix(2,2), node.matrix(2,3), node.matrix(3,3));
+ N.p3->transform(t);
+ }
}
}
}
@@ -377,7 +392,7 @@ void CGALEvaluator::addToParent(const State &state, const AbstractNode &node, co
CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps)
{
- if (ps.empty()) return CGAL_Nef_polyhedron();
+ if (ps.empty()) return CGAL_Nef_polyhedron(ps.is2d ? 2 : 3);
if (ps.is2d)
{
@@ -637,7 +652,7 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps)
N = new CGAL_Nef_polyhedron3(*P);
}
}
- catch (CGAL::Assertion_exception e) {
+ catch (const CGAL::Assertion_exception &e) {
PRINTB("CGAL error in CGAL_Nef_polyhedron3(): %s", e.what());
}
CGAL::set_error_behaviour(old_behaviour);
diff --git a/src/CGALRenderer.cc b/src/CGALRenderer.cc
index adf1217..4357e44 100644
--- a/src/CGALRenderer.cc
+++ b/src/CGALRenderer.cc
@@ -43,7 +43,11 @@
CGALRenderer::CGALRenderer(const CGAL_Nef_polyhedron &root) : root(root)
{
- if (root.dim == 2) {
+ if (this->root.isNull()) {
+ this->polyhedron = NULL;
+ this->polyset = NULL;
+ }
+ else if (root.dim == 2) {
DxfData *dd = root.convertToDxfData();
this->polyhedron = NULL;
this->polyset = new PolySet();
@@ -67,10 +71,6 @@ CGALRenderer::CGALRenderer(const CGAL_Nef_polyhedron &root) : root(root)
CGAL::OGL::Nef3_Converter<CGAL_Nef_polyhedron3>::convert_to_OGLPolyhedron(*this->root.p3, this->polyhedron);
this->polyhedron->init();
}
- else {
- this->polyhedron = NULL;
- this->polyset = NULL;
- }
}
CGALRenderer::~CGALRenderer()
@@ -81,6 +81,7 @@ CGALRenderer::~CGALRenderer()
void CGALRenderer::draw(bool showfaces, bool showedges) const
{
+ if (this->root.isNull()) return;
if (this->root.dim == 2) {
// Draw 2D polygons
glDisable(GL_LIGHTING);
diff --git a/src/CGAL_Nef_polyhedron.cc b/src/CGAL_Nef_polyhedron.cc
index ba298ad..8906595 100644
--- a/src/CGAL_Nef_polyhedron.cc
+++ b/src/CGAL_Nef_polyhedron.cc
@@ -61,7 +61,7 @@ CGAL_Nef_polyhedron &CGAL_Nef_polyhedron::minkowski(const CGAL_Nef_polyhedron &o
int CGAL_Nef_polyhedron::weight() const
{
- if (this->empty()) return 0;
+ if (this->isNull()) return 0;
size_t memsize = sizeof(CGAL_Nef_polyhedron);
if (this->dim == 2) {
@@ -84,7 +84,7 @@ int CGAL_Nef_polyhedron::weight() const
*/
PolySet *CGAL_Nef_polyhedron::convertToPolyset()
{
- assert(!this->empty());
+ if (this->isNull()) return new PolySet();
PolySet *ps = NULL;
if (this->dim == 2) {
ps = new PolySet();
@@ -101,7 +101,7 @@ PolySet *CGAL_Nef_polyhedron::convertToPolyset()
this->p3->convert_to_Polyhedron(P);
ps = createPolySetFromPolyhedron(P);
}
- catch (CGAL::Precondition_exception e) {
+ catch (const CGAL::Precondition_exception &e) {
PRINTB("CGAL error in CGAL_Nef_polyhedron::convertToPolyset(): %s", e.what());
}
CGAL::set_error_behaviour(old_behaviour);
diff --git a/src/CGAL_Nef_polyhedron.h b/src/CGAL_Nef_polyhedron.h
index 694b420..d949a2a 100644
--- a/src/CGAL_Nef_polyhedron.h
+++ b/src/CGAL_Nef_polyhedron.h
@@ -8,19 +8,22 @@
class CGAL_Nef_polyhedron
{
public:
- CGAL_Nef_polyhedron() : dim(0) {}
+ CGAL_Nef_polyhedron(int dim = 0) : dim(dim) {}
CGAL_Nef_polyhedron(CGAL_Nef_polyhedron2 *p);
CGAL_Nef_polyhedron(CGAL_Nef_polyhedron3 *p);
~CGAL_Nef_polyhedron() {}
- bool empty() const { return (dim == 0 || (!p2 && !p3)); }
+ // Empty means it is a geometric node which has zero area/volume
+ bool isEmpty() const { return (dim > 0 && !p2 && !p3); }
+ // Null means the node doesn't contain any geometry (for whatever reason)
+ bool isNull() const { return !p2 && !p3; }
void reset() { dim=0; p2.reset(); p3.reset(); }
CGAL_Nef_polyhedron &operator+=(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron &operator*=(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron &operator-=(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron &minkowski(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron copy() const;
- std::string dump_p2() const;
+ std::string dump() const;
int weight() const;
class PolySet *convertToPolyset();
class DxfData *convertToDxfData() const;
diff --git a/src/CGAL_Nef_polyhedron_DxfData.cc b/src/CGAL_Nef_polyhedron_DxfData.cc
index 411a340..0d0b8f0 100644
--- a/src/CGAL_Nef_polyhedron_DxfData.cc
+++ b/src/CGAL_Nef_polyhedron_DxfData.cc
@@ -28,6 +28,8 @@
#include "grid.h"
#include "CGAL_Nef_polyhedron.h"
#include "cgal.h"
+#include "cgalutils.h"
+#include "svg.h"
#ifdef ENABLE_CGAL
@@ -77,29 +79,14 @@ DxfData *CGAL_Nef_polyhedron::convertToDxfData() const
return dxfdata;
}
-// dump the 2 dimensional nef_poly.
-std::string CGAL_Nef_polyhedron::dump_p2() const
+std::string CGAL_Nef_polyhedron::dump() const
{
- std::stringstream out;
- CGAL_Nef_polyhedron2::Explorer explorer = this->p2->explorer();
- CGAL_Nef_polyhedron2::Explorer::Vertex_const_iterator i;
- out << "CGAL_Nef_polyhedron::p2 Vertices";
- for (i = explorer.vertices_begin(); i != explorer.vertices_end(); ++i) {
- if ( explorer.is_standard( i ) ) {
- CGAL_Nef_polyhedron2::Explorer::Point point = explorer.point( i );
- out << "\n Point x y: "
- << CGAL::to_double(point.x()) << " "
- << CGAL::to_double(point.y());
- } else {
- CGAL_Nef_polyhedron2::Explorer::Ray ray = explorer.ray( i );
- CGAL_Nef_polyhedron2::Explorer::Point point = ray.point( 0 );
- out << "\n Ray x y dx dy: "
- << CGAL::to_double(point.x()) << " " << CGAL::to_double(point.y()) << " "
- << CGAL::to_double(ray.direction().dx()) << " " << CGAL::to_double(ray.direction().dy());
- }
- }
- out << "\nCGAL_Nef_polyhedron::p2 Vertices end";
- return out.str();
+ if (this->dim==2)
+ return OpenSCAD::dump_svg( *this->p2 );
+ else if (this->dim==3)
+ return OpenSCAD::dump_svg( *this->p3 );
+ else
+ return std::string("Nef Polyhedron with dimension != 2 or 3");
}
#endif // ENABLE_CGAL
diff --git a/src/MainWindow.ui b/src/MainWindow.ui
index 13bb226..f71ac96 100644
--- a/src/MainWindow.ui
+++ b/src/MainWindow.ui
@@ -217,7 +217,7 @@
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
- <string>Help</string>
+ <string>&amp;Help</string>
</property>
<addaction name="helpActionAbout"/>
<addaction name="helpActionHomepage"/>
diff --git a/src/ModuleCache.cc b/src/ModuleCache.cc
index d03d121..19a3f84 100644
--- a/src/ModuleCache.cc
+++ b/src/ModuleCache.cc
@@ -72,20 +72,27 @@ Module *ModuleCache::evaluate(const std::string &filename)
PRINTB("WARNING: Can't open library file '%s'\n", filename);
return NULL;
}
- std::string text((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
+ std::stringstream textbuf;
+ textbuf << ifs.rdbuf();
+ textbuf << "\n" << commandline_commands;
print_messages_push();
-
+
+ Module *oldmodule = NULL;
cache_entry e = { NULL, cache_id };
if (this->entries.find(filename) != this->entries.end()) {
- delete this->entries[filename].module;
+ oldmodule = this->entries[filename].module;
}
this->entries[filename] = e;
std::string pathname = boosty::stringy(fs::path(filename).parent_path());
- lib_mod = dynamic_cast<Module*>(parse(text.c_str(), pathname.c_str(), false));
+ lib_mod = dynamic_cast<Module*>(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);
diff --git a/src/OpenCSGWarningDialog.cc b/src/OpenCSGWarningDialog.cc
index 5648576..926a55b 100644
--- a/src/OpenCSGWarningDialog.cc
+++ b/src/OpenCSGWarningDialog.cc
@@ -8,12 +8,12 @@ OpenCSGWarningDialog::OpenCSGWarningDialog(QWidget*)
connect(this->showBox, SIGNAL(toggled(bool)),
Preferences::inst()->openCSGWarningBox, SLOT(setChecked(bool)));
connect(this->showBox, SIGNAL(toggled(bool)),
- Preferences::inst(), SLOT(openCSGWarningChanged(bool)));
+ Preferences::inst(), SLOT(on_openCSGWarningBox_toggled(bool)));
connect(this->enableOpenCSGBox, SIGNAL(toggled(bool)),
Preferences::inst()->enableOpenCSGBox, SLOT(setChecked(bool)));
connect(this->enableOpenCSGBox, SIGNAL(toggled(bool)),
- Preferences::inst(), SLOT(enableOpenCSGChanged(bool)));
+ Preferences::inst(), SLOT(on_enableOpenCSGBox_toggled(bool)));
}
void OpenCSGWarningDialog::setText(const QString &text)
diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc
index 3b272d2..224e657 100644
--- a/src/PolySetCGALEvaluator.cc
+++ b/src/PolySetCGALEvaluator.cc
@@ -1,6 +1,8 @@
#include "PolySetCGALEvaluator.h"
#include "cgal.h"
#include "cgalutils.h"
+#include <CGAL/convex_hull_3.h>
+
#include "polyset.h"
#include "CGALEvaluator.h"
#include "projectionnode.h"
@@ -12,53 +14,53 @@
#include "dxftess.h"
#include "module.h"
+#include "svg.h"
#include "printutils.h"
#include "openscad.h" // get_fragments_from_r()
#include <boost/foreach.hpp>
+#include <vector>
/*
-This Visitor is used in the 'cut' process. Essentially, one or more of
-our 3d nef polyhedrons have been 'cut' by the xy-plane, forming a number
-of polygons that are essentially 'flat'. This Visitor object, when
-called repeatedly, collects those flat polygons together and forms a new
-2d nef polyhedron out of them. It keeps track of the 'holes' so that
-in the final resulting polygon, they are preserved properly.
+ZRemover
-The output polygon is stored in the output_nefpoly2d variable.
+This class converts one or more already 'flat' Nef3 polyhedra into a Nef2
+polyhedron by stripping off the 'z' coordinates from the vertices. The
+resulting Nef2 poly is accumulated in the 'output_nefpoly2d' member variable.
-For more information on 3d + 2d nef polyhedrons, facets, halffacets,
-facet cycles, etc, please see these websites:
+The 'z' coordinates will either be all 0s, for an xy-plane intersected Nef3,
+or, they will be a mixture of -eps and +eps, for a thin-box intersected Nef3.
-http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3/Chapter_main.html
-http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3_ref/Class_Nef_polyhedron_3-Traits---Halffacet.html
+Notes on CGAL's Nef Polyhedron2:
-The halffacet iteration 'circulator' code is based on OGL_helper.h
+1. The 'mark' on a 2d Nef face is important when doing unions/intersections.
+ If the 'mark' of a face is wrong the resulting nef2 poly will be unexpected.
+2. The 'mark' can be dependent on the points fed to the Nef2 constructor.
+ This is why we iterate through the 3d faces using the halfedge cycle
+ source()->target() instead of the ordinary source()->source(). The
+ the latter can generate sequences of points that will fail the
+ the CGAL::is_simple_2() test, resulting in improperly marked nef2 polys.
+3. 3d facets have 'two sides'. we throw out the 'down' side to prevent dups.
-Why do we throw out all 'down' half-facets? Imagine a triangle in 3d
-space - it has one 'half face' for one 'side' and another 'half face' for the
-other 'side'. If we iterated over both half-faces we would get the same vertex
-coordinates twice. Instead, we only need one side, in our case, we
-chose the 'up' side.
+The class uses the 'visitor' pattern from the CGAL manual. See also
+http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3/Chapter_main.html
+http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3_ref/Class_Nef_polyhedron3.html
+OGL_helper.h
*/
-class NefShellVisitor_for_cut {
+
+class ZRemover {
public:
- std::stringstream out;
+ logstream log;
CGAL_Nef_polyhedron2::Boundary boundary;
shared_ptr<CGAL_Nef_polyhedron2> tmpnef2d;
shared_ptr<CGAL_Nef_polyhedron2> output_nefpoly2d;
CGAL::Direction_3<CGAL_Kernel3> up;
- bool debug;
- NefShellVisitor_for_cut(bool debug=false)
+ ZRemover()
{
output_nefpoly2d.reset( new CGAL_Nef_polyhedron2() );
boundary = CGAL_Nef_polyhedron2::INCLUDED;
up = CGAL::Direction_3<CGAL_Kernel3>(0,0,1);
- this->debug = debug;
- }
- std::string dump()
- {
- return out.str();
+ log = logstream(5);
}
void visit( CGAL_Nef_polyhedron3::Vertex_const_handle ) {}
void visit( CGAL_Nef_polyhedron3::Halfedge_const_handle ) {}
@@ -66,53 +68,77 @@ public:
void visit( CGAL_Nef_polyhedron3::SHalfloop_const_handle ) {}
void visit( CGAL_Nef_polyhedron3::SFace_const_handle ) {}
void visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet ) {
+ log << " <!-- Halffacet visit. Mark: " << hfacet->mark() << " -->\n";
if ( hfacet->plane().orthogonal_direction() != this->up ) {
- if (debug) out << "down facing half-facet. skipping\n";
+ log << " <!-- down-facing half-facet. skipping -->\n";
+ log << " <!-- Halffacet visit end-->\n";
return;
}
- int numcontours = 0;
- CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator i;
- CGAL_forall_facet_cycles_of( i, hfacet ) {
- CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(i), c2(c1);
- std::list<CGAL_Nef_polyhedron2::Point> contour;
- CGAL_For_all( c1, c2 ) {
- CGAL_Nef_polyhedron3::Point_3 point3d = c1->source()->source()->point();
- CGAL_Nef_polyhedron2::Point point2d( point3d.x(), point3d.y() );
- contour.push_back( point2d );
- }
- tmpnef2d.reset( new CGAL_Nef_polyhedron2( contour.begin(), contour.end(), boundary ) );
- if ( numcontours == 0 ) {
- if (debug) out << " contour is a body. make union(). " << contour.size() << " points.\n" ;
- *output_nefpoly2d += *tmpnef2d;
+ // possible optimization - throw out facets that are 'side facets' between
+ // the top & bottom of the big thin box. (i.e. mixture of z=-eps and z=eps)
+
+ CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator fci;
+ int contour_counter = 0;
+ CGAL_forall_facet_cycles_of( fci, hfacet ) {
+ if ( fci.is_shalfedge() ) {
+ CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(fci), cend(c1);
+ std::vector<CGAL_Nef_polyhedron2::Explorer::Point> contour;
+ CGAL_For_all( c1, cend ) {
+ CGAL_Nef_polyhedron3::Point_3 point3d = c1->source()->target()->point();
+ CGAL_Nef_polyhedron2::Explorer::Point point2d( point3d.x(), point3d.y() );
+ contour.push_back( point2d );
+ }
+
+ if (contour.size()==0) continue;
+
+ log << " <!-- is_simple_2:" << CGAL::is_simple_2( contour.begin(), contour.end() ) << " --> \n";
+
+ tmpnef2d.reset( new CGAL_Nef_polyhedron2( contour.begin(), contour.end(), boundary ) );
+
+ if ( contour_counter == 0 ) {
+ log << " <!-- contour is a body. make union(). " << contour.size() << " points. -->\n" ;
+ *(output_nefpoly2d) += *(tmpnef2d);
+ } else {
+ log << " <!-- contour is a hole. make intersection(). " << contour.size() << " points. -->\n";
+ *(output_nefpoly2d) *= *(tmpnef2d);
+ }
+
+ log << "\n<!-- ======== output tmp nef: ==== -->\n"
+ << OpenSCAD::dump_svg( *tmpnef2d ) << "\n"
+ << "\n<!-- ======== output accumulator: ==== -->\n"
+ << OpenSCAD::dump_svg( *output_nefpoly2d ) << "\n";
+
+ contour_counter++;
} else {
- if (debug) out << " contour is a hole. make intersection(). " << contour.size() << " points.\n";
- *output_nefpoly2d *= *tmpnef2d;
+ log << " <!-- trivial facet cycle skipped -->\n";
}
- numcontours++;
} // next facet cycle (i.e. next contour)
+ log << " <!-- Halffacet visit end -->\n";
} // visit()
};
PolySetCGALEvaluator::PolySetCGALEvaluator(CGALEvaluator &cgalevaluator)
: PolySetEvaluator(cgalevaluator.getTree()), cgalevaluator(cgalevaluator)
{
- this->debug = false;
}
PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
{
+ //openscad_loglevel = 6;
+ logstream log(5);
+
// Before projecting, union all children
CGAL_Nef_polyhedron sum;
BOOST_FOREACH (AbstractNode * v, node.getChildren()) {
if (v->modinst->isBackground()) continue;
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);
if (N.dim == 3) {
- if (sum.empty()) sum = N.copy();
+ if (sum.isNull()) sum = N.copy();
else sum += N;
}
}
- if (sum.empty()) return NULL;
+ if (sum.isNull()) return NULL;
if (!sum.p3->is_simple()) {
if (!node.cut_mode) {
PRINT("WARNING: Body of projection(cut = false) isn't valid 2-manifold! Modify your design..");
@@ -120,32 +146,70 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
}
}
- CGAL_Nef_polyhedron nef_poly;
+ //std::cout << sum.dump();
+ //std::cout.flush();
- if (node.cut_mode)
- {
- // intersect 'sum' with the x-y plane
- CGAL_Nef_polyhedron3::Plane_3 xy_plane = CGAL_Nef_polyhedron3::Plane_3( 0,0,1,0 );
- *sum.p3 = sum.p3->intersection( xy_plane, CGAL_Nef_polyhedron3::PLANE_ONLY);
-
- // Visit each polygon in sum.p3 and union/intersect into a 2d polygon (with holes)
- // For info on Volumes, Shells, Facets, and the 'visitor' pattern, please see
- // http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3/Chapter_main.html
- NefShellVisitor_for_cut shell_visitor;
- CGAL_Nef_polyhedron3::Volume_const_iterator i;
- CGAL_Nef_polyhedron3::Shell_entry_const_iterator j;
- CGAL_Nef_polyhedron3::SFace_const_handle sface_handle;
- for ( i = sum.p3->volumes_begin(); i != sum.p3->volumes_end(); ++i ) {
- for ( j = i->shells_begin(); j != i->shells_end(); ++j ) {
- sface_handle = CGAL_Nef_polyhedron3::SFace_const_handle( j );
- sum.p3->visit_shell_objects( sface_handle , shell_visitor );
+ CGAL_Nef_polyhedron nef_poly(2);
+
+ if (node.cut_mode) {
+ CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
+ try {
+ CGAL_Nef_polyhedron3::Plane_3 xy_plane = CGAL_Nef_polyhedron3::Plane_3( 0,0,1,0 );
+ *sum.p3 = sum.p3->intersection( xy_plane, CGAL_Nef_polyhedron3::PLANE_ONLY);
+ }
+ catch (const CGAL::Failure_exception &e) {
+ PRINTB("CGAL error in projection node during plane intersection: %s", e.what());
+ try {
+ PRINT("Trying alternative intersection using very large thin box: ");
+ std::vector<CGAL_Point_3> pts;
+ // dont use z of 0. there are bugs in CGAL.
+ double inf = 1e8;
+ double eps = 0.001;
+ CGAL_Point_3 minpt( -inf, -inf, -eps );
+ CGAL_Point_3 maxpt( inf, inf, eps );
+ CGAL_Iso_cuboid_3 bigcuboid( minpt, maxpt );
+ for ( int i=0;i<8;i++ ) pts.push_back( bigcuboid.vertex(i) );
+ CGAL_Polyhedron bigbox;
+ CGAL::convex_hull_3( pts.begin(), pts.end(), bigbox );
+ CGAL_Nef_polyhedron3 nef_bigbox( bigbox );
+ *sum.p3 = nef_bigbox.intersection( *sum.p3 );
+ }
+ catch (const CGAL::Failure_exception &e) {
+ PRINTB("CGAL error in projection node during bigbox intersection: %s", e.what());
+ sum.p3->clear();
+ }
+ }
+
+ if (sum.p3->is_empty()) {
+ CGAL::set_error_behaviour(old_behaviour);
+ PRINT("WARNING: projection() failed.");
+ return NULL;
+ }
+
+ // remove z coordinates to make CGAL_Nef_polyhedron2
+ log << OpenSCAD::svg_header( 480, 100000 ) << "\n";
+ try {
+ ZRemover zremover;
+ CGAL_Nef_polyhedron3::Volume_const_iterator i;
+ CGAL_Nef_polyhedron3::Shell_entry_const_iterator j;
+ CGAL_Nef_polyhedron3::SFace_const_handle sface_handle;
+ for ( i = sum.p3->volumes_begin(); i != sum.p3->volumes_end(); ++i ) {
+ log << "<!-- volume. mark: " << i->mark() << " -->\n";
+ for ( j = i->shells_begin(); j != i->shells_end(); ++j ) {
+ log << "<!-- shell. mark: " << i->mark() << " -->\n";
+ sface_handle = CGAL_Nef_polyhedron3::SFace_const_handle( j );
+ sum.p3->visit_shell_objects( sface_handle , zremover );
+ log << "<!-- shell. end. -->\n";
+ }
+ log << "<!-- volume end. -->\n";
}
+ nef_poly.p2 = zremover.output_nefpoly2d;
+ } catch (const CGAL::Failure_exception &e) {
+ PRINTB("CGAL error in projection node while flattening: %s", e.what());
}
- if (debug) std::cout << "shell visitor\n" << shell_visitor.dump() << "\nshell visitor end\n";
+ log << "</svg>\n";
- nef_poly.p2 = shell_visitor.output_nefpoly2d;
- nef_poly.dim = 2;
- if (debug) std::cout << "--\n" << nef_poly.dump_p2() << "\n";
+ CGAL::set_error_behaviour(old_behaviour);
// Extract polygons in the XY plane, ignoring all other polygons
// FIXME: If the polyhedron is really thin, there might be unwanted polygons
@@ -219,8 +283,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
plist.push_back(p);
}
// FIXME: Should the CGAL_Nef_polyhedron2 be cached?
- if (nef_poly.empty()) {
- nef_poly.dim = 2;
+ if (nef_poly.isEmpty()) {
nef_poly.p2.reset(new CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED));
}
else {
@@ -233,7 +296,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
PolySet *ps = nef_poly.convertToPolyset();
assert( ps != NULL );
ps->convexity = node.convexity;
- if (debug) std::cout << "--\n" << ps->dump() << "\n";
+ logstream(9) << ps->dump() << "\n";
return ps;
}
@@ -320,18 +383,18 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const LinearExtrudeNode &node)
BOOST_FOREACH (AbstractNode * v, node.getChildren()) {
if (v->modinst->isBackground()) continue;
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);
- if (!N.empty()) {
+ if (!N.isNull()) {
if (N.dim != 2) {
PRINT("ERROR: linear_extrude() is not defined for 3D child objects!");
}
else {
- if (sum.empty()) sum = N.copy();
+ if (sum.isNull()) sum = N.copy();
else sum += N;
}
}
}
- if (sum.empty()) return NULL;
+ if (sum.isNull()) return NULL;
dxf = sum.convertToDxfData();;
} else {
dxf = new DxfData(node.fn, node.fs, node.fa, node.filename, node.layername, node.origin_x, node.origin_y, node.scale);
@@ -420,18 +483,18 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const RotateExtrudeNode &node)
BOOST_FOREACH (AbstractNode * v, node.getChildren()) {
if (v->modinst->isBackground()) continue;
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);
- if (!N.empty()) {
+ if (!N.isNull()) {
if (N.dim != 2) {
PRINT("ERROR: rotate_extrude() is not defined for 3D child objects!");
}
else {
- if (sum.empty()) sum = N.copy();
+ if (sum.isNull()) sum = N.copy();
else sum += N;
}
}
}
- if (sum.empty()) return NULL;
+ if (sum.isNull()) return NULL;
dxf = sum.convertToDxfData();
} else {
dxf = new DxfData(node.fn, node.fs, node.fa, node.filename, node.layername, node.origin_x, node.origin_y, node.scale);
@@ -446,7 +509,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const CgaladvNode &node)
{
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(node);
PolySet *ps = NULL;
- if (!N.empty()) {
+ if (!N.isNull()) {
ps = N.convertToPolyset();
if (ps) ps->convexity = node.convexity;
}
@@ -458,7 +521,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const RenderNode &node)
{
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(node);
PolySet *ps = NULL;
- if (!N.empty()) {
+ if (!N.isNull()) {
if (N.dim == 3 && !N.p3->is_simple()) {
PRINT("WARNING: Body of render() isn't valid 2-manifold!");
}
diff --git a/src/boosty.h b/src/boosty.h
index 2e7d76b..6ec417a 100644
--- a/src/boosty.h
+++ b/src/boosty.h
@@ -1,5 +1,6 @@
-// boosty.h copyright 2012 don bright. released under the GPL 2, or later,
-// as described in the file named 'COPYING' in OpenSCAD's project root.
+// boosty.h by don bright 2012. Copyright assigned to Marius Kintel and
+// Clifford Wolf 2012. Released under the GPL 2, or later, as described in
+// the file named 'COPYING' in OpenSCAD's project root.
#ifndef boosty_h_
#define boosty_h_
@@ -16,6 +17,7 @@
see also
http://www.boost.org/doc/libs/1_48_0/libs/filesystem/v3/doc/index.htm
+ http://www.boost.org/doc/libs/1_45_0/libs/filesystem/v2/doc/index.htm
http://www.boost.org/doc/libs/1_42_0/libs/filesystem/doc/index.htm
http://www.boost.org/doc/libs/1_35_0/libs/filesystem/doc/index.htm
include/boost/wave/util/filesystem_compatability.hpp
@@ -29,7 +31,7 @@ namespace fs = boost::filesystem;
namespace boosty {
-#if BOOST_VERSION >= 104600 && BOOST_FILESYSTEM_VERSION >= 3
+#if BOOST_VERSION >= 104400 && BOOST_FILESYSTEM_VERSION >= 3
inline bool is_absolute( fs::path p )
{
diff --git a/src/cgal.h b/src/cgal.h
index e5e39dd..a7300c6 100644
--- a/src/cgal.h
+++ b/src/cgal.h
@@ -33,6 +33,8 @@ using boost::uintmax_t;
#include <CGAL/Polygon_with_holes_2.h>
#include <CGAL/minkowski_sum_2.h>
#include <CGAL/minkowski_sum_3.h>
+#include <CGAL/bounding_box.h>
+#include <CGAL/utils.h>
#include <CGAL/assertions_behaviour.h>
#include <CGAL/exceptions.h>
@@ -54,6 +56,16 @@ typedef CGAL::Polyhedron_3<CGAL_Kernel3> CGAL_Polyhedron;
typedef CGAL_Polyhedron::HalfedgeDS CGAL_HDS;
typedef CGAL::Polyhedron_incremental_builder_3<CGAL_HDS> CGAL_Polybuilder;
+typedef CGAL::Point_3<CGAL_Kernel3> CGAL_Point_3;
+typedef CGAL::Iso_cuboid_3<CGAL_Kernel3> CGAL_Iso_cuboid_3;
+
+// CGAL_Nef_polyhedron2 uses CGAL_Kernel2, but Iso_rectangle_2 needs to match
+// CGAL_Nef_polyhedron2::Explorer::Point which is different than
+// CGAL_Kernel2::Point. Hence the suffix 'e'
+typedef CGAL_Nef_polyhedron2::Explorer::Point CGAL_Point_2e;
+typedef CGAL::Iso_rectangle_2< CGAL::Simple_cartesian<NT> > CGAL_Iso_rectangle_2e;
+
+
#ifdef PREV_NDEBUG
#define NDEBUG PREV_NDEBUG
#endif
diff --git a/src/cgalutils.cc b/src/cgalutils.cc
index e39c495..51838df 100644
--- a/src/cgalutils.cc
+++ b/src/cgalutils.cc
@@ -81,7 +81,7 @@ public:
const CGALPoint &p = vertices[i];
B.add_vertex(p);
#ifdef GEN_SURFACE_DEBUG
- printf("%d: %f %f %f\n", i, p[0], p[1], p[2]);
+ printf("%d: %f %f %f\n", i, p.x().to_double(), p.y().to_double(), p.z().to_double());
#endif
}
@@ -136,7 +136,7 @@ CGAL_Polyhedron *createPolyhedronFromPolySet(const PolySet &ps)
CGAL_Build_PolySet builder(ps);
P->delegate(builder);
}
- catch (CGAL::Assertion_exception e) {
+ catch (const CGAL::Assertion_exception &e) {
PRINTB("CGAL error in CGAL_Build_PolySet: %s", e.what());
delete P;
P = NULL;
@@ -145,5 +145,33 @@ CGAL_Polyhedron *createPolyhedronFromPolySet(const PolySet &ps)
return P;
}
+CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N )
+{
+ CGAL_Iso_cuboid_3 result(-1,-1,-1,1,1,1);
+ CGAL_Nef_polyhedron3::Vertex_const_iterator vi;
+ std::vector<CGAL_Nef_polyhedron3::Point_3> points;
+ // can be optimized by rewriting bounding_box to accept vertices
+ CGAL_forall_vertices( vi, N )
+ points.push_back( vi->point() );
+ if (points.size())
+ result = CGAL::bounding_box( points.begin(), points.end() );
+ return result;
+}
+
+CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N )
+{
+ CGAL_Iso_rectangle_2e result(-1,-1,1,1);
+ CGAL_Nef_polyhedron2::Explorer explorer = N.explorer();
+ CGAL_Nef_polyhedron2::Explorer::Vertex_const_iterator vi;
+ std::vector<CGAL_Point_2e> points;
+ // can be optimized by rewriting bounding_box to accept vertices
+ for ( vi = explorer.vertices_begin(); vi != explorer.vertices_end(); ++vi )
+ if ( explorer.is_standard( vi ) )
+ points.push_back( explorer.point( vi ) );
+ if (points.size())
+ result = CGAL::bounding_box( points.begin(), points.end() );
+ return result;
+}
+
#endif /* ENABLE_CGAL */
diff --git a/src/cgalutils.h b/src/cgalutils.h
index a249697..9093c3f 100644
--- a/src/cgalutils.h
+++ b/src/cgalutils.h
@@ -5,5 +5,7 @@
class PolySet *createPolySetFromPolyhedron(const CGAL_Polyhedron &p);
CGAL_Polyhedron *createPolyhedronFromPolySet(const class PolySet &ps);
+CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N );
+CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N );
#endif
diff --git a/src/cgalworker.cc b/src/cgalworker.cc
index 30bb1fe..96fead9 100644
--- a/src/cgalworker.cc
+++ b/src/cgalworker.cc
@@ -31,7 +31,7 @@ void CGALWorker::work()
CGALEvaluator evaluator(*this->tree);
root_N = new CGAL_Nef_polyhedron(evaluator.evaluateCGALMesh(*this->tree->root()));
}
- catch (ProgressCancelException e) {
+ catch (const ProgressCancelException &e) {
PRINT("Rendering cancelled.");
}
diff --git a/src/color.cc b/src/color.cc
index 4220396..acca652 100644
--- a/src/color.cc
+++ b/src/color.cc
@@ -64,8 +64,11 @@ AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiatio
Value v = c.lookup_variable("c");
if (v.type() == Value::VECTOR) {
- for (size_t i = 0; i < 4; i++)
+ for (size_t i = 0; i < 4; i++) {
node->color[i] = i < v.toVector().size() ? v.toVector()[i].toDouble() : 1.0;
+ if (node->color[i] > 1)
+ PRINTB_NOCACHE("WARNING: color() expects numbers between 0.0 and 1.0. Value of %.1f is too large.", node->color[i]);
+ }
} else if (v.type() == Value::STRING) {
std::string colorname = v.toString();
boost::algorithm::to_lower(colorname);
diff --git a/src/context.cc b/src/context.cc
index f48cd86..a2a8d13 100644
--- a/src/context.cc
+++ b/src/context.cc
@@ -43,6 +43,7 @@ std::vector<const Context*> Context::ctx_stack;
Context::Context(const Context *parent, const Module *library)
: parent(parent), inst_p(NULL)
{
+ if (parent) recursioncount = parent->recursioncount;
ctx_stack.push_back(this);
if (parent) document_path = parent->document_path;
if (library) {
@@ -130,10 +131,26 @@ Value Context::lookup_variable(const std::string &name, bool silent) const
return Value();
}
+class RecursionGuard
+{
+public:
+ RecursionGuard(const Context &c, const std::string &name) : c(c), name(name) { c.recursioncount[name]++; }
+ ~RecursionGuard() { if (--c.recursioncount[name] == 0) c.recursioncount.erase(name); }
+ bool recursion_detected() const { return (c.recursioncount[name] > 100); }
+private:
+ const Context &c;
+ const std::string &name;
+};
+
Value Context::evaluate_function(const std::string &name,
const std::vector<std::string> &argnames,
const std::vector<Value> &argvalues) const
{
+ RecursionGuard g(*this, name);
+ if (g.recursion_detected()) {
+ PRINTB("Recursion detected calling function '%s'", name);
+ return Value();
+ }
if (this->functions_p && this->functions_p->find(name) != this->functions_p->end())
return this->functions_p->find(name)->second->evaluate(this, argnames, argvalues);
if (this->usedlibs_p) {
@@ -144,8 +161,7 @@ Value Context::evaluate_function(const std::string &name,
}
}
}
- if (this->parent)
- return this->parent->evaluate_function(name, argnames, argvalues);
+ if (this->parent) return this->parent->evaluate_function(name, argnames, argvalues);
PRINTB("WARNING: Ignoring unknown function '%s'.", name);
return Value();
}
diff --git a/src/context.h b/src/context.h
index f085e01..de5f1ca 100644
--- a/src/context.h
+++ b/src/context.h
@@ -41,6 +41,8 @@ public:
static std::vector<const Context*> ctx_stack;
+ mutable unordered_map<std::string, int> recursioncount;
+
private:
typedef unordered_map<std::string, Value> ValueMap;
ValueMap constants;
diff --git a/src/csgterm.cc b/src/csgterm.cc
index 0e68320..aed97b2 100644
--- a/src/csgterm.cc
+++ b/src/csgterm.cc
@@ -66,16 +66,29 @@ shared_ptr<CSGTerm> CSGTerm::createCSGTerm(type_e type, shared_ptr<CSGTerm> left
// http://www.cc.gatech.edu/~turk/my_papers/pxpl_csg.pdf
const BoundingBox &leftbox = left->getBoundingBox();
const BoundingBox &rightbox = right->getBoundingBox();
+ Vector3d newmin, newmax;
if (type == TYPE_INTERSECTION) {
- BoundingBox newbox(leftbox.min().cwise().max(rightbox.min()),
- leftbox.max().cwise().min(rightbox.max()));
+#if EIGEN_WORLD_VERSION == 2
+ newmin = leftbox.min().cwise().max( rightbox.min() );
+ newmax = leftbox.max().cwise().min( rightbox.max() );
+#else
+ newmin = leftbox.min().array().cwiseMax( rightbox.min().array() );
+ newmax = leftbox.max().array().cwiseMin( rightbox.max().array() );
+#endif
+ BoundingBox newbox( newmin, newmax );
if (newbox.isNull()) {
return shared_ptr<CSGTerm>(); // Prune entire product
}
}
else if (type == TYPE_DIFFERENCE) {
- BoundingBox newbox(leftbox.min().cwise().max(rightbox.min()),
- leftbox.max().cwise().min(rightbox.max()));
+#if EIGEN_WORLD_VERSION == 2
+ newmin = leftbox.min().cwise().max( rightbox.min() );
+ newmax = leftbox.max().cwise().min( rightbox.max() );
+#else
+ newmin = leftbox.min().array().cwiseMax( rightbox.min().array() );
+ newmax = leftbox.max().array().cwiseMin( rightbox.max().array() );
+#endif
+ BoundingBox newbox( newmin, newmax );
if (newbox.isNull()) {
return left; // Prune the negative component
}
@@ -119,14 +132,27 @@ void CSGTerm::initBoundingBox()
else {
const BoundingBox &leftbox = this->left->getBoundingBox();
const BoundingBox &rightbox = this->right->getBoundingBox();
+ Vector3d newmin, newmax;
switch (this->type) {
case TYPE_UNION:
- this->bbox = this->m * BoundingBox(leftbox.min().cwise().min(rightbox.min()),
- leftbox.max().cwise().max(rightbox.max()));
+#if EIGEN_WORLD_VERSION == 2
+ newmin = leftbox.min().cwise().min( rightbox.min() );
+ newmax = leftbox.max().cwise().max( rightbox.max() );
+#else
+ newmin = leftbox.min().array().cwiseMin( rightbox.min().array() );
+ newmax = leftbox.max().array().cwiseMax( rightbox.max().array() );
+#endif
+ this->bbox = this->m * BoundingBox( newmin, newmax );
break;
case TYPE_INTERSECTION:
- this->bbox = this->m * BoundingBox(leftbox.min().cwise().max(rightbox.min()),
- leftbox.max().cwise().min(rightbox.max()));
+#if EIGEN_WORLD_VERSION == 2
+ newmin = leftbox.min().cwise().max( rightbox.min() );
+ newmax = leftbox.max().cwise().min( rightbox.max() );
+#else
+ newmin = leftbox.min().array().cwiseMax( rightbox.min().array() );
+ newmax = leftbox.max().array().cwiseMin( rightbox.max().array() );
+#endif
+ this->bbox = this->m * BoundingBox( newmin, newmax );
break;
case TYPE_DIFFERENCE:
this->bbox = this->m * leftbox;
diff --git a/src/dxfdata.cc b/src/dxfdata.cc
index 4258a4c..2fd40ab 100644
--- a/src/dxfdata.cc
+++ b/src/dxfdata.cc
@@ -141,7 +141,7 @@ DxfData::DxfData(double fn, double fs, double fa,
try {
id = boost::lexical_cast<int>(id_str);
}
- catch (boost::bad_lexical_cast &blc) {
+ catch (const boost::bad_lexical_cast &blc) {
if (!stream.eof()) {
PRINTB("WARNING: Illegal ID '%s' in `%s'", id_str % filename);
}
diff --git a/src/dxfdim.cc b/src/dxfdim.cc
index 8f68ac6..1ed37fa 100644
--- a/src/dxfdim.cc
+++ b/src/dxfdim.cc
@@ -36,10 +36,9 @@
#include <sstream>
#include <boost/filesystem.hpp>
-using namespace boost::filesystem;
-
boost::unordered_map<std::string,Value> dxf_dim_cache;
boost::unordered_map<std::string,Value> dxf_cross_cache;
+namespace fs = boost::filesystem;
Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args)
{
@@ -65,8 +64,8 @@ Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnam
std::stringstream keystream;
keystream << filename << "|" << layername << "|" << name << "|" << xorigin
- << "|" << yorigin <<"|" << scale << "|" << last_write_time(filename)
- << "|" << file_size(filename);
+ << "|" << yorigin <<"|" << scale << "|" << fs::last_write_time(filename)
+ << "|" << fs::file_size(filename);
std::string key = keystream.str();
if (dxf_dim_cache.find(key) != dxf_dim_cache.end())
return dxf_dim_cache.find(key)->second;
@@ -147,8 +146,8 @@ Value builtin_dxf_cross(const Context *ctx, const std::vector<std::string> &argn
std::stringstream keystream;
keystream << filename << "|" << layername << "|" << xorigin << "|" << yorigin
- << "|" << scale << "|" << last_write_time(filename)
- << "|" << file_size(filename);
+ << "|" << scale << "|" << fs::last_write_time(filename)
+ << "|" << fs::file_size(filename);
std::string key = keystream.str();
if (dxf_cross_cache.find(key) != dxf_cross_cache.end())
diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc
index df04b5b..e40f1d3 100644
--- a/src/dxftess-cgal.cc
+++ b/src/dxftess-cgal.cc
@@ -170,7 +170,7 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool /* do_tr
PRINT( "WARNING: Duplicate vertices and/or intersecting lines found during DXF Tessellation. Render may be incorrect." );
}
- catch (CGAL::Assertion_exception e) {
+ catch (const CGAL::Assertion_exception &e) {
PRINTB("CGAL error in dxf_tesselate(): %s", e.what());
CGAL::set_error_behaviour(old_behaviour);
return;
diff --git a/src/editor.cc b/src/editor.cc
index 92aeefe..08bf005 100644
--- a/src/editor.cc
+++ b/src/editor.cc
@@ -1,7 +1,6 @@
#include "editor.h"
#include "Preferences.h"
-#ifndef _QCODE_EDIT_
void Editor::indentSelection()
{
QTextCursor cursor = textCursor();
@@ -109,4 +108,3 @@ void Editor::wheelEvent ( QWheelEvent * event )
}
}
-#endif
diff --git a/src/editor.h b/src/editor.h
index bb338b0..09484f5 100644
--- a/src/editor.h
+++ b/src/editor.h
@@ -3,26 +3,11 @@
#include <QWidget>
#include <QWheelEvent>
-#ifdef _QCODE_EDIT_
-#include <qeditor.h>
-class Editor : public QEditor
-#else
#include <QTextEdit>
class Editor : public QTextEdit
-#endif
{
Q_OBJECT
public:
-#ifdef _QCODE_EDIT_
- Editor(QWidget *parent) : QEditor(parent) {}
- QString toPlainText() const { return text(); }
- void setPlainText(const QString& text) { setText(text); }
-public slots:
- //void zoomIn() { zoom(1); }
- void zoomIn(int n = 1) { zoom(n); }
- //void zoomOut() { zoom(-1); }
- void zoomOut(int n = 1) { zoom(-n); }
-#else
Editor(QWidget *parent) : QTextEdit(parent) { setAcceptRichText(false); }
public slots:
void zoomIn();
@@ -36,5 +21,4 @@ public slots:
void uncommentSelection();
private:
void wheelEvent ( QWheelEvent * event );
-#endif
};
diff --git a/src/export.cc b/src/export.cc
index 40ce6cb..80670ea 100644
--- a/src/export.cc
+++ b/src/export.cc
@@ -111,7 +111,7 @@ void export_stl(CGAL_Nef_polyhedron *root_N, std::ostream &output)
setlocale(LC_NUMERIC, ""); // Set default locale
}
- catch (CGAL::Assertion_exception e) {
+ catch (const CGAL::Assertion_exception &e) {
PRINTB("CGAL error in CGAL_Nef_polyhedron3::convert_to_Polyhedron(): %s", e.what());
}
CGAL::set_error_behaviour(old_behaviour);
@@ -125,7 +125,7 @@ void export_off(CGAL_Nef_polyhedron *root_N, std::ostream &output)
root_N->p3->convert_to_Polyhedron(P);
output << P;
}
- catch (CGAL::Assertion_exception e) {
+ catch (const CGAL::Assertion_exception &e) {
PRINTB("CGAL error in CGAL_Nef_polyhedron3::convert_to_Polyhedron(): %s", e.what());
}
CGAL::set_error_behaviour(old_behaviour);
diff --git a/src/func.cc b/src/func.cc
index 6c5f070..5dcb3e9 100644
--- a/src/func.cc
+++ b/src/func.cc
@@ -35,6 +35,28 @@
#include "stl-utils.h"
#include "printutils.h"
+/*
+ Random numbers
+
+ Newer versions of boost/C++ include a non-deterministic random_device and
+ auto/bind()s for random function objects, but we are supporting older systems.
+*/
+
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_real_distribution.hpp>
+
+#ifdef __WIN32__
+#include <process.h>
+int process_id = _getpid();
+#else
+#include <sys/types.h>
+#include <unistd.h>
+int process_id = getpid();
+#endif
+
+boost::random::mt19937 deterministic_rng;
+boost::random::mt19937 lessdeterministic_rng( std::time(0) + process_id );
+
AbstractFunction::~AbstractFunction()
{
}
@@ -63,9 +85,7 @@ Value Function::evaluate(const Context *ctx,
{
Context c(ctx);
c.args(argnames, argexpr, call_argnames, call_argvalues);
- if (expr)
- return expr->evaluate(&c);
- return Value();
+ return expr ? expr->evaluate(&c) : Value();
}
std::string Function::dump(const std::string &indent, const std::string &name) const
@@ -121,24 +141,15 @@ Value builtin_sign(const Context *, const std::vector<std::string>&, const std::
return Value();
}
-double frand()
-{
- return rand()/(double(RAND_MAX)+1);
-}
-
-double frand(double min, double max)
-{
- return (min>max) ? frand()*(min-max)+max : frand()*(max-min)+min;
-}
-
Value builtin_rands(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
+ bool deterministic = false;
if (args.size() == 3 &&
args[0].type() == Value::NUMBER &&
args[1].type() == Value::NUMBER &&
args[2].type() == Value::NUMBER)
{
- srand((unsigned int)time(0));
+ deterministic = false;
}
else if (args.size() == 4 &&
args[0].type() == Value::NUMBER &&
@@ -146,16 +157,24 @@ Value builtin_rands(const Context *, const std::vector<std::string>&, const std:
args[2].type() == Value::NUMBER &&
args[3].type() == Value::NUMBER)
{
- srand((unsigned int)args[3].toDouble());
+ deterministic_rng.seed( (unsigned int) args[3].toDouble() );
+ deterministic = true;
}
else
{
return Value();
}
+ double min = std::min( args[0].toDouble(), args[1].toDouble() );
+ double max = std::max( args[0].toDouble(), args[1].toDouble() );
+ boost::random::uniform_real_distribution<> distributor( min, max );
Value::VectorType vec;
for (int i=0; i<args[2].toDouble(); i++) {
- vec.push_back(Value(frand(args[0].toDouble(), args[1].toDouble())));
+ if ( deterministic ) {
+ vec.push_back( Value( distributor( deterministic_rng ) ) );
+ } else {
+ vec.push_back( Value( distributor( lessdeterministic_rng ) ) );
+ }
}
return Value(vec);
diff --git a/src/handle_dep.cc b/src/handle_dep.cc
index cbf7157..2d6f3ff 100644
--- a/src/handle_dep.cc
+++ b/src/handle_dep.cc
@@ -6,7 +6,7 @@
#include <boost/foreach.hpp>
#include <boost/regex.hpp>
#include <boost/filesystem.hpp>
-using namespace boost::filesystem;
+namespace fs = boost::filesystem;
#include "boosty.h"
boost::unordered_set<std::string> dependencies;
@@ -14,14 +14,14 @@ const char *make_command = NULL;
void handle_dep(const std::string &filename)
{
- path filepath(filename);
+ fs::path filepath(filename);
if ( boosty::is_absolute( filepath )) {
dependencies.insert(filename);
}
else {
- dependencies.insert((current_path() / filepath).string());
+ dependencies.insert((fs::current_path() / filepath).string());
}
- if (!exists(filepath) && make_command) {
+ if (!fs::exists(filepath) && make_command) {
std::stringstream buf;
buf << make_command << " '" << boost::regex_replace(filename, boost::regex("'"), "'\\''") << "'";
system(buf.str().c_str()); // FIXME: Handle error
diff --git a/src/highlighter.cc b/src/highlighter.cc
index 64ea980..77d1bb8 100644
--- a/src/highlighter.cc
+++ b/src/highlighter.cc
@@ -24,34 +24,295 @@
*
*/
+/*
+ Syntax Highlighter for OpenSCAD
+ based on Syntax Highlight code by Christopher Olah
+
+ Speed Note:
+
+ setFormat() is very slow. normally this doesnt matter because we
+ only highlight a block or two at once. But when OpenSCAD first starts,
+ QT automatigically calls 'highlightBlock' on every single textblock in the file
+ even if it's not visible in the window. On a large file (50,000 lines) this
+ can take several seconds.
+
+ Also, QT 4.5 and lower do not have rehighlightBlock(), so they will be slow
+ on large files as well, as they re-highlight everything after each compile.
+
+ The vast majority of OpenSCAD files, however, are not 50,000 lines and
+ most machines have Qt > 4.5
+
+ See Also:
+
+ Giles Bathgate's Rapcad lexer-based highlighter: rapcad.org
+
+ Test suite:
+
+1. action: open example001, remove first {, hit f5
+ expected result: error highlight appears on last }, cursor moves there
+ action: replace first {, hit f5
+ expected result: error highlight disappears
+
+1a. action: open example001, remove first {, hit f5
+ expected result: error highlight appears on last }, cursor moves there
+ action: replace first { with the letter 'P', hit f5
+ expected result: error highlight on last } disappears, appears on elsewhere
+ action: replace first {, hit f5
+ expected result: error highlight disappears
+
+2. action: type a=b into any file
+ expected result: '=' is highlighted with its appropriate format
+
+2a. action: type a=b=c=d=e=f= into any file
+ expected result: each '=' is highlighted with its appropriate format
+
+3. action: open example001, put '===' after first ; hit f5
+ expected result: error highlight appears in ===
+ action: remove '==='
+ expected result: error highlight disappears
+
+3a. action: open example001, put '=' after first ; hit f5
+ expected result: error highlight appears
+ action: remove '='
+ expected result: error highlight disappears
+
+3b. action: open example001, put '=' after first {
+ expected result: error highlight appears
+ action: remove '='
+ expected result: error highlight disappears
+
+3c. action: open example001, replace first { with '='
+ expected result: error highlight appears
+ action: remove '=', replace with {
+ expected result: error highlight disappears
+
+4. action: open example001, remove last ';' but not trailing whitespace/\n
+ expected result: error highlight appears somewhere near end
+ action: replace last ';'
+ expected result: error highlight disappears
+
+5. action: open file, type in a multi-line comment
+ expected result: multiline comment should be highlighted appropriately
+
+6. action: open example001, remove first ')'
+ expected result: highlight should appear appropriately
+
+7. action: create a large file (50,000 lines). eg at a bash prompt:
+ for i in {1..2000}; do cat examples/example001.scad >> test5k.scad ; done
+ action: open file in openscad
+ expected result: it should load in a reasonable amount of time
+ action: scroll to bottom, put '=' after last ;
+ expected result: there should be a highlight, and a report of syntax error
+ action: comment out the highlighter code from mainwin.cc, recompile,
+ run openscad again on the large file. put '=' after last ;
+ expected result: there should be only a small difference in speed.
+
+8. action: open any file, and hold down 'f5' key to repeatedly reparse
+ expected result: no crashing!
+
+9. action: for i in examples/ex* ; do ./openscad $i ; done
+ expected result: make sure the colors look harmonious
+
+10. action: type random string of [][][][]()()[][90,3904,00,000]
+ expected result: all should be highlighted correctly
+
+*/
+
#include "highlighter.h"
-#include "parsersettings.h" // extern int parser_error_pos;
+#include <QTextDocument>
+#include <QTextCursor>
+#include <QColor>
+//#include <iostream>
-#ifdef _QCODE_EDIT_
-Highlighter::Highlighter(QDocument *parent)
-#else
Highlighter::Highlighter(QTextDocument *parent)
-#endif
: QSyntaxHighlighter(parent)
{
+ tokentypes["operator"] << "=" << "!" << "&&" << "||" << "+" << "-" << "*" << "/" << "%" << "!" << "#" << ";";
+ typeformats["operator"].setForeground(Qt::blue);
+
+ tokentypes["keyword"] << "module" << "function" << "for" << "intersection_for" << "if" << "assign";
+ typeformats["keyword"].setForeground(QColor("Green"));
+ typeformats["keyword"].setToolTip("Keyword");
+
+ tokentypes["transform"] << "scale" << "translate" << "rotate" << "multmatrix" << "color" << "projection" << "hull";
+ typeformats["transform"].setForeground(QColor("Indigo"));
+
+ tokentypes["csgop"] << "union" << "intersection" << "difference" << "render";
+ typeformats["csgop"].setForeground(QColor("DarkGreen"));
+
+ tokentypes["prim3d"] << "cube" << "cylinder" << "sphere" << "polyhedron";
+ typeformats["prim3d"].setForeground(QColor("DarkBlue"));
+
+ tokentypes["prim2d"] << "square" << "polygon" << "circle";
+ typeformats["prim2d"].setForeground(QColor("MidnightBlue"));
+
+ tokentypes["import"] << "include" << "use" << "import_stl" << "import" << "import_dxf" << "dxf_dim" << "dxf_cross";
+ typeformats["import"].setForeground(Qt::darkYellow);
+
+ tokentypes["special"] << "$children" << "child" << "$fn" << "$fa" << "$fb";
+ typeformats["special"].setForeground(Qt::darkGreen);
+
+ tokentypes["extrude"] << "linear_extrude" << "rotate_extrude";
+ typeformats["extrude"].setForeground(Qt::darkGreen);
+
+ tokentypes["bracket"] << "[" << "]" << "(" << ")";
+ typeformats["bracket"].setForeground(QColor("Green"));
+
+ tokentypes["curlies"] << "{" << "}";
+ typeformats["curlies"].setForeground(QColor(32,32,20));
+
+ tokentypes["bool"] << "true" << "false";
+ typeformats["bool"].setForeground(QColor("DarkRed"));
+
+ // Put each tokens into single QHash, mapped to it's format
+ QList<QString>::iterator ki;
+ QList<QString> toktypes = tokentypes.keys();
+ for ( ki=toktypes.begin(); ki!=toktypes.end(); ++ki ) {
+ QString toktype = *ki;
+ QStringList::iterator it;
+ for ( it = tokentypes[toktype].begin(); it < tokentypes[toktype].end(); ++it) {
+ QString token = *it;
+ //std::cout << token.toStdString() << "\n";
+ tokenFormats[ token ] = typeformats [ toktype ];
+ }
+ }
+
+ quoteFormat.setForeground(Qt::darkMagenta);
+ commentFormat.setForeground(Qt::darkCyan);
+ errorFormat.setBackground(Qt::red);
+ numberFormat.setForeground(QColor("DarkRed"));
+
+ errorState = false;
+ errorPos = -1;
+ lastErrorBlock = parent->begin();
+}
+
+void Highlighter::highlightError(int error_pos)
+{
+ errorState = true;
+ errorPos = error_pos;
+
+ QTextBlock err_block = document()->findBlock( errorPos );
+ //std::cout << "error pos: " << error_pos << " doc len: " << document()->characterCount() << "\n";
+
+ while (err_block.text().remove(QRegExp("\\s+")).size()==0) {
+ //std::cout << "special case - errors at end of file w whitespace\n";
+ err_block = err_block.previous();
+ errorPos = err_block.position()+err_block.length() - 2;
+ }
+ if ( errorPos == lastDocumentPos()-1 ) {
+ errorPos--;
+ }
+
+ int block_last_pos = err_block.position() + err_block.length() - 1;
+ if ( errorPos == block_last_pos ) {
+ //std::cout << "special case - errors at ends of certain blocks\n";
+ errorPos--;
+ }
+ err_block = document()->findBlock(errorPos);
+
+ portable_rehighlightBlock( err_block );
+
+ errorState = false;
+ lastErrorBlock = err_block;
}
-void Highlighter::highlightBlock(const QString &text)
+void Highlighter::unhighlightLastError()
{
- int n = previousBlockState();
- if (n < 0)
- n = 0;
- int k = n + text.size() + 1;
- setCurrentBlockState(k);
- if (parser_error_pos >= n && parser_error_pos < k) {
- QTextCharFormat style;
- style.setBackground(Qt::red);
- setFormat(0, text.size(), style);
-#if 0
- style.setBackground(Qt::black);
- style.setForeground(Qt::white);
- setFormat(parser_error_pos - n, 1, style);
+ portable_rehighlightBlock( lastErrorBlock );
+}
+
+void Highlighter::portable_rehighlightBlock( const QTextBlock &block )
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
+ rehighlightBlock( block );
+#else
+ rehighlight(); // slow on very large files
#endif
+}
+
+int Highlighter::lastDocumentPos()
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(4, 5, 0))
+ return document()->characterCount();
+#else
+ QTextBlock lastblock = document()->lastBlock();
+ return lastblock.position() + lastblock.length();
+#endif
+}
+
+void Highlighter::highlightBlock(const QString &text)
+{
+ int block_first_pos = currentBlock().position();
+ //int block_last_pos = block_first_pos + currentBlock().length() - 1;
+ //std::cout << "block[" << block_first_pos << ":" << block_last_pos << "]"
+ // << ", err:" << errorPos << "," << errorState
+ // << ", text:'" << text.toStdString() << "'\n";
+
+ // Split the block into pieces and highlight each as appropriate
+ QString newtext = text;
+ QStringList splitHelpers;
+ QStringList::iterator sh, token;
+ // splitHelpers - so "[a+b]" is treated as "[ a + b ]" and formatted
+ splitHelpers << tokentypes["operator"] << "(" << ")" << "[" << "]" << "," << ":";
+ for ( sh = splitHelpers.begin(); sh!=splitHelpers.end(); ++sh ) {
+ newtext = newtext.replace( *sh, " " + *sh + " ");
}
+ //std::cout << "\nnewtext: " << newtext.toStdString() << "\n";
+ QStringList tokens = newtext.split(QRegExp("\\s"));
+ int tokindex = 0; // tokindex helps w duplicate tokens in a single block
+ bool numtest;
+ for ( token = tokens.begin(); token!=tokens.end(); ++token ){
+ if ( tokenFormats.contains( *token ) ) {
+ tokindex = text.indexOf( *token, tokindex );
+ setFormat( tokindex, token->size(), tokenFormats[ *token ]);
+ //std::cout << "found tok '" << (*token).toStdString() << "' at " << tokindex << "\n";
+ tokindex += token->size();
+ } else {
+ (*token).toDouble( &numtest );
+ if ( numtest ) {
+ tokindex = text.indexOf( *token, tokindex );
+ setFormat( tokindex, token->size(), numberFormat );
+ //std::cout << "found num '" << (*token).toStdString() << "' at " << tokindex << "\n";
+ tokindex += token->size();
+ }
+ }
+ }
+
+ // Quoting and Comments.
+ state_e state = (state_e) previousBlockState();
+ for (int n = 0; n < text.size(); ++n){
+ if (state == NORMAL){
+ if (text[n] == '"'){
+ state = QUOTE;
+ setFormat(n,1,quoteFormat);
+ } else if (text[n] == '/'){
+ if (text[n+1] == '/'){
+ setFormat(n,text.size(),commentFormat);
+ break;
+ } else if (text[n+1] == '*'){
+ setFormat(n++,2,commentFormat);
+ state = COMMENT;
+ }
+ }
+ } else if (state == QUOTE){
+ setFormat(n,1,quoteFormat);
+ if (text[n] == '"' && text[n-1] != '\\')
+ state = NORMAL;
+ } else if (state == COMMENT){
+ setFormat(n,1,commentFormat);
+ if (text[n] == '*' && text[n+1] == '/'){
+ setFormat(++n,1,commentFormat);
+ state = NORMAL;
+ }
+ }
+ }
+ setCurrentBlockState((int) state);
+
+ // Highlight an error. Do it last to 'overwrite' other formatting.
+ if (errorState) {
+ setFormat( errorPos - block_first_pos, 1, errorFormat);
+ }
+
}
diff --git a/src/highlighter.h b/src/highlighter.h
index 1bd54d2..b4ffae8 100644
--- a/src/highlighter.h
+++ b/src/highlighter.h
@@ -2,20 +2,27 @@
#define HIGHLIGHTER_H_
#include <QSyntaxHighlighter>
-
-#ifdef _QCODE_EDIT_
-#include "qdocument.h"
-#endif
+#include <QTextFormat>
+#include <QHash>
class Highlighter : public QSyntaxHighlighter
{
public:
-#ifdef _QCODE_EDIT_
- Highlighter(QDocument *parent);
-#else
+ enum state_e {NORMAL=-1,QUOTE,COMMENT};
+ QHash<QString, QTextCharFormat> tokenFormats;
+ QTextCharFormat errorFormat, commentFormat, quoteFormat, numberFormat;
Highlighter(QTextDocument *parent);
-#endif
void highlightBlock(const QString &text);
+ void highlightError(int error_pos);
+ void unhighlightLastError();
+private:
+ QTextBlock lastErrorBlock;
+ int errorPos;
+ bool errorState;
+ QMap<QString,QStringList> tokentypes;
+ QMap<QString,QTextCharFormat> typeformats;
+ int lastDocumentPos();
+ void portable_rehighlightBlock( const QTextBlock &text );
};
#endif
diff --git a/src/import.cc b/src/import.cc
index dc40c8d..40d34fa 100644
--- a/src/import.cc
+++ b/src/import.cc
@@ -47,7 +47,7 @@
#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>
-using namespace boost::filesystem;
+namespace fs = boost::filesystem;
#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope
#include "boosty.h"
@@ -80,7 +80,7 @@ AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiati
std::string filename = c.getAbsolutePath(v.isUndefined() ? "" : v.toString());
import_type_e actualtype = this->type;
if (actualtype == TYPE_UNKNOWN) {
- std::string extraw = boosty::extension_str( path(filename) );
+ std::string extraw = boosty::extension_str( fs::path(filename) );
std::string ext = boost::algorithm::to_lower_copy( extraw );
if (ext == ".stl") actualtype = TYPE_STL;
else if (ext == ".off") actualtype = TYPE_OFF;
@@ -157,7 +157,7 @@ PolySet *ImportNode::evaluate_polyset(class PolySetEvaluator *) const
vdata[i][v] = boost::lexical_cast<double>(results[v+1]);
}
}
- catch (boost::bad_lexical_cast &blc) {
+ catch (const boost::bad_lexical_cast &blc) {
PRINTB("WARNING: Can't parse vertex line '%s'.", line);
i = 10;
continue;
diff --git a/src/lexer.l b/src/lexer.l
index 1e3bd5b..63b0047 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -80,6 +80,7 @@ void includefile();
fs::path sourcepath();
std::vector<fs::path> path_stack;
std::vector<FILE*> openfiles;
+std::vector<std::string> openfilenames;
std::string filename;
std::string filepath;
@@ -142,6 +143,7 @@ use[ \t\r\n>]*"<" { BEGIN(cond_use); }
assert(!openfiles.empty());
fclose(openfiles.back());
openfiles.pop_back();
+ openfilenames.pop_back();
}
yypop_buffer_state();
if (!YY_CURRENT_BUFFER)
@@ -227,10 +229,15 @@ void includefile()
PRINTB("WARNING: Can't find 'include' file '%s'.", filename);
}
+ std::string fullname = boosty::absolute(finfo).string();
+ // Detect circular includes
+ BOOST_FOREACH(std::string &s, openfilenames) {
+ if (s == fullname) return;
+ }
+
filepath.clear();
path_stack.push_back(finfo.parent_path());
- std::string fullname = boosty::absolute(finfo).string();
handle_dep(fullname);
currmodule->registerInclude(fullname);
yyin = fopen(fullname.c_str(), "r");
@@ -240,6 +247,7 @@ void includefile()
return;
}
openfiles.push_back(yyin);
+ openfilenames.push_back(fullname);
filename.clear();
yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
@@ -253,5 +261,6 @@ void lexerdestroy()
{
BOOST_FOREACH (FILE *f, openfiles) fclose(f);
openfiles.clear();
+ openfilenames.clear();
path_stack.clear();
}
diff --git a/src/linalg.cc b/src/linalg.cc
index 30f23af..2f368f9 100644
--- a/src/linalg.cc
+++ b/src/linalg.cc
@@ -1,4 +1,5 @@
#include "linalg.h"
+#include <boost/math/special_functions/fpclassify.hpp>
// FIXME: We can achieve better pruning by either:
// o Recalculate the box based on the transformed object
@@ -25,3 +26,23 @@ BoundingBox operator*(const Transform3d &m, const BoundingBox &box)
return newbox;
}
+bool matrix_contains_infinity( const Transform3d &m )
+{
+ for (int i=0;i<m.matrix().rows();i++) {
+ for (int j=0;j<m.matrix().cols();j++) {
+ if ((boost::math::isinf)(m(i,j))) return true;
+ }
+ }
+ return false;
+}
+
+bool matrix_contains_nan( const Transform3d &m )
+{
+ for (int i=0;i<m.matrix().rows();i++) {
+ for (int j=0;j<m.matrix().cols();j++) {
+ if ((boost::math::isnan)(m(i,j))) return true;
+ }
+ }
+ return false;
+}
+
diff --git a/src/linalg.h b/src/linalg.h
index 65243dc..48960b7 100644
--- a/src/linalg.h
+++ b/src/linalg.h
@@ -12,7 +12,14 @@ typedef Eigen::AlignedBox<double, 3> BoundingBox;
using Eigen::Matrix3f;
using Eigen::Matrix3d;
using Eigen::Matrix4d;
+#if EIGEN_WORLD_VERSION >= 3
+#define Transform3d Eigen::Affine3d
+#else
using Eigen::Transform3d;
+#endif
+
+bool matrix_contains_infinity( const Transform3d &m );
+bool matrix_contains_nan( const Transform3d &m );
BoundingBox operator*(const Transform3d &m, const BoundingBox &box);
diff --git a/src/mainwin.cc b/src/mainwin.cc
index dc738d7..251c6e1 100644
--- a/src/mainwin.cc
+++ b/src/mainwin.cc
@@ -70,11 +70,6 @@
#include <QSettings>
#include <QProgressDialog>
#include <QMutexLocker>
-#ifdef _QCODE_EDIT_
-#include "qdocument.h"
-#include "qformatscheme.h"
-#include "qlanguagefactory.h"
-#endif
#include <fstream>
@@ -115,11 +110,11 @@ static char helptitle[] =
#endif
"\nhttp://www.openscad.org\n\n";
static char copyrighttext[] =
- "Copyright (C) 2009-2011 Marius Kintel <marius@kintel.net> and Clifford Wolf <clifford@clifford.at>\n"
+ "Copyright (C) 2009-2013 Marius Kintel <marius@kintel.net> and Clifford Wolf <clifford@clifford.at>\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"
- "the Free Software Foundation; either version 2 of the License, or"
+ "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.";
static void
@@ -185,16 +180,8 @@ MainWindow::MainWindow(const QString &filename)
fps = 0;
fsteps = 1;
- highlighter = NULL;
-#ifdef _QCODE_EDIT_
- QFormatScheme *formats = new QFormatScheme("qxs/openscad.qxf");
- QDocument::setDefaultFormatScheme(formats);
- QLanguageFactory *languages = new QLanguageFactory(formats,this);
- languages->addDefinitionPath("qxs");
- languages->setLanguage(editor, "openscad");
-#else
+ highlighter = new Highlighter(editor->document());
editor->setTabStopWidth(30);
-#endif
editor->setLineWrapping(true); // Not designable
this->glview->statusLabel = new QLabel(this);
@@ -348,13 +335,8 @@ MainWindow::MainWindow(const QString &filename)
updateRecentFileActions();
connect(editor->document(), SIGNAL(contentsChanged()), this, SLOT(animateUpdateDocChanged()));
-#ifdef _QCODE_EDIT_
- connect(editor, SIGNAL(contentModified(bool)), this, SLOT(setWindowModified(bool)));
- connect(editor, SIGNAL(contentModified(bool)), fileActionSave, SLOT(setEnabled(bool)));
-#else
connect(editor->document(), SIGNAL(modificationChanged(bool)), this, SLOT(setWindowModified(bool)));
connect(editor->document(), SIGNAL(modificationChanged(bool)), fileActionSave, SLOT(setEnabled(bool)));
-#endif
connect(this->glview, SIGNAL(doAnimateUpdate()), this, SLOT(animateUpdate()));
connect(Preferences::inst(), SIGNAL(requestRedraw()), this->glview, SLOT(updateGL()));
@@ -462,6 +444,7 @@ void MainWindow::report_func(const class AbstractNode*, void *vp, int mark)
QApplication::processEvents();
}
+ // FIXME: Check if cancel was requested by e.g. Application quit
if (thisp->progresswidget->wasCanceled()) throw ProgressCancelException();
}
@@ -483,12 +466,7 @@ void
MainWindow::openFile(const QString &new_filename)
{
#ifdef ENABLE_MDI
-#ifdef _QCODE_EDIT_
- if (this->editor->document()->lines() > 1 ||
- !this->editor->document()->text(true, false).trimmed().isEmpty()) {
-#else
if (!editor->toPlainText().isEmpty()) {
-#endif
new MainWindow(new_filename);
clearCurrentOutput();
return;
@@ -588,7 +566,9 @@ void MainWindow::refreshDocument()
this->fileName.toStdString() % file.errorString().toStdString());
}
else {
- QString text = QTextStream(&file).readAll();
+ QTextStream reader(&file);
+ reader.setCodec("UTF-8");
+ QString text = reader.readAll();
PRINTB("Loaded design '%s'.", this->fileName.toStdString());
editor->setPlainText(text);
}
@@ -709,7 +689,7 @@ void MainWindow::compileCSG(bool procevents)
PolySetCache::instance()->print();
CGALCache::instance()->print();
}
- catch (ProgressCancelException e) {
+ catch (const ProgressCancelException &e) {
PRINT("CSG generation cancelled.");
}
progress_report_fin();
@@ -802,7 +782,8 @@ void MainWindow::actionNew()
void MainWindow::actionOpen()
{
- QString new_filename = QFileDialog::getOpenFileName(this, "Open File", "", "OpenSCAD Designs (*.scad)");
+ QString new_filename = QFileDialog::getOpenFileName(this, "Open File", "",
+ "OpenSCAD Designs (*.scad *.csg)");
#ifdef ENABLE_MDI
if (!new_filename.isEmpty()) {
new MainWindow(new_filename);
@@ -899,7 +880,9 @@ void MainWindow::actionSave()
PRINTB("Failed to open file for writing: %s (%s)", this->fileName.toStdString() % file.errorString().toStdString());
}
else {
- QTextStream(&file) << this->editor->toPlainText();
+ QTextStream writer(&file);
+ writer.setCodec("UTF-8");
+ writer << this->editor->toPlainText();
PRINTB("Saved design '%s'.", this->fileName.toStdString());
this->editor->setContentModified(false);
}
@@ -952,11 +935,7 @@ void MainWindow::hideEditor()
void MainWindow::pasteViewportTranslation()
{
-#ifdef _QCODE_EDIT_
- QDocumentCursor cursor = editor->cursor();
-#else
QTextCursor cursor = editor->textCursor();
-#endif
QString txt;
txt.sprintf("[ %.2f, %.2f, %.2f ]", -this->glview->object_trans_x, -this->glview->object_trans_y, -this->glview->object_trans_z);
cursor.insertText(txt);
@@ -964,11 +943,7 @@ void MainWindow::pasteViewportTranslation()
void MainWindow::pasteViewportRotation()
{
-#ifdef _QCODE_EDIT_
- QDocumentCursor cursor = editor->cursor();
-#else
QTextCursor cursor = editor->textCursor();
-#endif
QString txt;
txt.sprintf("[ %.2f, %.2f, %.2f ]",
fmodf(360 - this->glview->object_rot_x + 90, 360), fmodf(360 - this->glview->object_rot_y, 360), fmodf(360 - this->glview->object_rot_z, 360));
@@ -1062,24 +1037,16 @@ bool MainWindow::compileTopLevelDocument(bool reload)
QFileInfo(this->fileName).absolutePath().toLocal8Bit(),
false);
- // Error highlighting
- delete this->highlighter;
- this->highlighter = NULL;
-
- if (!this->root_module) {
- this->highlighter = new Highlighter(editor->document());
-
- if (!animate_panel->isVisible()) {
-#ifdef _QCODE_EDIT_
- QDocumentCursor cursor = editor->cursor();
- cursor.setPosition(parser_error_pos);
-#else
+ if (!animate_panel->isVisible()) {
+ highlighter->unhighlightLastError();
+ if (!this->root_module) {
QTextCursor cursor = editor->textCursor();
cursor.setPosition(parser_error_pos);
editor->setTextCursor(cursor);
-#endif
+ highlighter->highlightError( parser_error_pos );
}
}
+
}
bool changed = shouldcompiletoplevel;
@@ -1231,35 +1198,37 @@ void MainWindow::actionRenderCGALDone(CGAL_Nef_polyhedron *root_N)
PolySetCache::instance()->print();
CGALCache::instance()->print();
- if (root_N->dim == 2) {
- PRINT(" Top level object is a 2D object:");
- PRINTB(" Empty: %6s", (root_N->p2->is_empty() ? "yes" : "no"));
- PRINTB(" Plane: %6s", (root_N->p2->is_plane() ? "yes" : "no"));
- PRINTB(" Vertices: %6d", root_N->p2->explorer().number_of_vertices());
- PRINTB(" Halfedges: %6d", root_N->p2->explorer().number_of_halfedges());
- PRINTB(" Edges: %6d", root_N->p2->explorer().number_of_edges());
- PRINTB(" Faces: %6d", root_N->p2->explorer().number_of_faces());
- PRINTB(" FaceCycles: %6d", root_N->p2->explorer().number_of_face_cycles());
- PRINTB(" ConnComp: %6d", root_N->p2->explorer().number_of_connected_components());
- }
-
- if (root_N->dim == 3) {
- PRINT(" Top level object is a 3D object:");
- PRINTB(" Simple: %6s", (root_N->p3->is_simple() ? "yes" : "no"));
- PRINTB(" Valid: %6s", (root_N->p3->is_valid() ? "yes" : "no"));
- PRINTB(" Vertices: %6d", root_N->p3->number_of_vertices());
- PRINTB(" Halfedges: %6d", root_N->p3->number_of_halfedges());
- PRINTB(" Edges: %6d", root_N->p3->number_of_edges());
- PRINTB(" Halffacets: %6d", root_N->p3->number_of_halffacets());
- PRINTB(" Facets: %6d", root_N->p3->number_of_facets());
- PRINTB(" Volumes: %6d", root_N->p3->number_of_volumes());
+ if (!root_N->isNull()) {
+ if (root_N->dim == 2) {
+ PRINT(" Top level object is a 2D object:");
+ PRINTB(" Empty: %6s", (root_N->p2->is_empty() ? "yes" : "no"));
+ PRINTB(" Plane: %6s", (root_N->p2->is_plane() ? "yes" : "no"));
+ PRINTB(" Vertices: %6d", root_N->p2->explorer().number_of_vertices());
+ PRINTB(" Halfedges: %6d", root_N->p2->explorer().number_of_halfedges());
+ PRINTB(" Edges: %6d", root_N->p2->explorer().number_of_edges());
+ PRINTB(" Faces: %6d", root_N->p2->explorer().number_of_faces());
+ PRINTB(" FaceCycles: %6d", root_N->p2->explorer().number_of_face_cycles());
+ PRINTB(" ConnComp: %6d", root_N->p2->explorer().number_of_connected_components());
+ }
+
+ if (root_N->dim == 3) {
+ PRINT(" Top level object is a 3D object:");
+ PRINTB(" Simple: %6s", (root_N->p3->is_simple() ? "yes" : "no"));
+ PRINTB(" Valid: %6s", (root_N->p3->is_valid() ? "yes" : "no"));
+ PRINTB(" Vertices: %6d", root_N->p3->number_of_vertices());
+ PRINTB(" Halfedges: %6d", root_N->p3->number_of_halfedges());
+ PRINTB(" Edges: %6d", root_N->p3->number_of_edges());
+ PRINTB(" Halffacets: %6d", root_N->p3->number_of_halffacets());
+ PRINTB(" Facets: %6d", root_N->p3->number_of_facets());
+ PRINTB(" Volumes: %6d", root_N->p3->number_of_volumes());
+ }
}
int s = this->progresswidget->elapsedTime() / 1000;
PRINTB("Total rendering time: %d hours, %d minutes, %d seconds", (s / (60*60)) % ((s / 60) % 60) % (s % 60));
this->root_N = root_N;
- if (!this->root_N->empty()) {
+ if (!this->root_N->isNull()) {
this->cgalRenderer = new CGALRenderer(*this->root_N);
// Go to CGAL view mode
if (viewActionCGALGrid->isChecked()) {
@@ -1761,11 +1730,13 @@ void MainWindow::helpLibrary()
libinfo.sprintf("Boost version: %s\n"
"Eigen version: %d.%d.%d\n"
"CGAL version: %s\n"
- "OpenCSG version: %s\n\n",
+ "OpenCSG version: %s\n"
+ "Qt version: %s\n\n",
BOOST_LIB_VERSION,
EIGEN_WORLD_VERSION, EIGEN_MAJOR_VERSION, EIGEN_MINOR_VERSION,
TOSTRING(CGAL_VERSION),
- OPENCSG_VERSION_STRING);
+ OPENCSG_VERSION_STRING,
+ qVersion());
if (!this->openglbox) {
this->openglbox = new QMessageBox(QMessageBox::Information,
@@ -1838,6 +1809,7 @@ void MainWindow::quit()
QCloseEvent ev;
QApplication::sendEvent(QApplication::instance(), &ev);
if (ev.isAccepted()) QApplication::instance()->quit();
+ // FIXME: Cancel any CGAL calculations
}
void MainWindow::consoleOutput(const std::string &msg, void *userdata)
diff --git a/src/module.cc b/src/module.cc
index fc849ff..cfd73cc 100644
--- a/src/module.cc
+++ b/src/module.cc
@@ -218,6 +218,9 @@ void Module::registerInclude(const std::string &filename)
*/
bool Module::handleDependencies()
{
+ if (this->is_handling_dependencies) return false;
+ this->is_handling_dependencies = true;
+
bool changed = false;
// Iterating manually since we want to modify the container while iterating
Module::ModuleContainer::iterator iter = this->usedlibs.begin();
@@ -236,5 +239,7 @@ bool Module::handleDependencies()
this->usedlibs.erase(curr);
}
}
+
+ this->is_handling_dependencies = false;
return changed;
}
diff --git a/src/module.h b/src/module.h
index cd25287..879d249 100644
--- a/src/module.h
+++ b/src/module.h
@@ -59,7 +59,7 @@ public:
class Module : public AbstractModule
{
public:
- Module() { }
+ Module() : is_handling_dependencies(false) { }
virtual ~Module();
virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
@@ -71,6 +71,7 @@ public:
void registerInclude(const std::string &filename);
typedef boost::unordered_map<std::string, time_t> IncludeContainer;
IncludeContainer includes;
+ bool is_handling_dependencies;
bool handleDependencies();
std::vector<std::string> assignments_var;
diff --git a/src/openscad.cc b/src/openscad.cc
index f508b80..472b5d4 100644
--- a/src/openscad.cc
+++ b/src/openscad.cc
@@ -58,6 +58,7 @@
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
#include "boosty.h"
#ifdef _MSC_VER
@@ -152,7 +153,7 @@ int main(int argc, char **argv)
try {
po::store(po::command_line_parser(argc, argv).options(all_options).positional(p).run(), vm);
}
- catch(std::exception &e) { // Catches e.g. unknown options
+ catch(const std::exception &e) { // Catches e.g. unknown options
fprintf(stderr, "%s\n", e.what());
help(argv[0]);
}
@@ -187,10 +188,8 @@ int main(int argc, char **argv)
}
if (vm.count("D")) {
- const vector<string> &commands = vm["D"].as<vector<string> >();
-
- for (vector<string>::const_iterator i = commands.begin(); i != commands.end(); i++) {
- commandline_commands += *i;
+ BOOST_FOREACH(const string &cmd, vm["D"].as<vector<string> >()) {
+ commandline_commands += cmd;
commandline_commands += ";\n";
}
}
@@ -305,8 +304,19 @@ int main(int argc, char **argv)
fs::current_path(original_path);
if (deps_output_file) {
- if (!write_deps(deps_output_file,
- stl_output_file ? stl_output_file : off_output_file)) {
+ std::string deps_out( deps_output_file );
+ 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 ( dxf_output_file ) geom_out = std::string(dxf_output_file);
+ else {
+ PRINTB("Output file:%s\n",output_file);
+ PRINT("Sorry, don't know how to write deps for that file type. Exiting\n");
+ exit(1);
+ }
+ int result = write_deps( deps_out, geom_out );
+ if ( !result ) {
+ PRINT("error writing deps");
exit(1);
}
}
diff --git a/src/parser.y b/src/parser.y
index b36c41b..3e485ff 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -233,6 +233,22 @@ ifelse_statement:
} ;
module_instantiation:
+ '!' module_instantiation {
+ $$ = $2;
+ if ($$) $$->tag_root = true;
+ } |
+ '#' module_instantiation {
+ $$ = $2;
+ if ($$) $$->tag_highlight = true;
+ } |
+ '%' module_instantiation {
+ $$ = $2;
+ if ($$) $$->tag_background = true;
+ } |
+ '*' module_instantiation {
+ delete $2;
+ $$ = NULL;
+ } |
single_module_instantiation ';' {
$$ = $1;
} |
@@ -271,26 +287,7 @@ single_module_instantiation:
$$->argexpr = $3->argexpr;
free($1);
delete $3;
- } |
- '!' single_module_instantiation {
- $$ = $2;
- if ($$)
- $$->tag_root = true;
- } |
- '#' single_module_instantiation {
- $$ = $2;
- if ($$)
- $$->tag_highlight = true;
- } |
- '%' single_module_instantiation {
- $$ = $2;
- if ($$)
- $$->tag_background = true;
- } |
- '*' single_module_instantiation {
- delete $2;
- $$ = NULL;
- };
+ }
expr:
TOK_TRUE {
@@ -566,11 +563,11 @@ Module *parse(const char *text, const char *path, int debug)
// PRINTB_NOCACHE("New module: %s %p", "root" % rootmodule);
parserdebug = debug;
- parserparse();
+ int parserretval = parserparse();
lexerdestroy();
lexerlex_destroy();
- if (!rootmodule) return NULL;
+ if (parserretval != 0) return NULL;
parser_error_pos = -1;
return rootmodule;
diff --git a/src/parsersettings.cc b/src/parsersettings.cc
index 47859c7..3dda132 100644
--- a/src/parsersettings.cc
+++ b/src/parsersettings.cc
@@ -28,7 +28,15 @@ std::string locate_file(const std::string &filename)
void parser_init(const std::string &applicationpath)
{
- // FIXME: Append paths from OPENSCADPATH before adding built-in paths
+ // Add path from OPENSCADPATH before adding built-in paths
+ const char *openscadpath = getenv("OPENSCADPATH");
+ if (openscadpath) {
+ add_librarydir(boosty::absolute(fs::path(openscadpath)).string());
+ }
+
+ // FIXME: Support specifying more than one path in OPENSCADPATH
+ // FIXME: Add ~/.openscad/libraries
+ // FIXME: Add ~/Documents/OpenSCAD/libraries on Mac?
std::string librarydir;
fs::path libdir(applicationpath);
diff --git a/src/polyset.cc b/src/polyset.cc
index b412f5f..e601585 100644
--- a/src/polyset.cc
+++ b/src/polyset.cc
@@ -157,7 +157,8 @@ void PolySet::render_surface(csgmode_e csgmode, const Transform3d &m, GLint *sha
}
#endif /* ENABLE_OPENCSG */
if (this->is2d) {
- double zbase = csgmode;
+ // Render 2D objects 1mm thick, but differences slightly larger
+ double zbase = 1 + (csgmode & CSGMODE_DIFFERENCE_FLAG) * 0.1;
glBegin(GL_TRIANGLES);
for (double z = -zbase/2; z < zbase; z += zbase)
{
@@ -248,7 +249,8 @@ void PolySet::render_edges(csgmode_e csgmode) const
{
glDisable(GL_LIGHTING);
if (this->is2d) {
- double zbase = csgmode;
+ // Render 2D objects 1mm thick, but differences slightly larger
+ double zbase = 1 + (csgmode & CSGMODE_DIFFERENCE_FLAG) * 0.1;
for (double z = -zbase/2; z < zbase; z += zbase)
{
for (size_t i = 0; i < borders.size(); i++) {
diff --git a/src/polyset.h b/src/polyset.h
index 4ca57bf..6626f79 100644
--- a/src/polyset.h
+++ b/src/polyset.h
@@ -29,14 +29,15 @@ public:
BoundingBox getBoundingBox() const;
+#define CSGMODE_DIFFERENCE_FLAG 0x10
enum csgmode_e {
- CSGMODE_NONE,
- CSGMODE_NORMAL = 1,
- CSGMODE_DIFFERENCE = 2,
- CSGMODE_BACKGROUND = 11,
- CSGMODE_BACKGROUND_DIFFERENCE = 12,
- CSGMODE_HIGHLIGHT = 21,
- CSGMODE_HIGHLIGHT_DIFFERENCE = 22
+ CSGMODE_NONE = 0x00,
+ CSGMODE_NORMAL = 0x01,
+ CSGMODE_DIFFERENCE = CSGMODE_NORMAL | CSGMODE_DIFFERENCE_FLAG,
+ CSGMODE_BACKGROUND = 0x02,
+ CSGMODE_BACKGROUND_DIFFERENCE = CSGMODE_BACKGROUND | CSGMODE_DIFFERENCE_FLAG,
+ CSGMODE_HIGHLIGHT = 0x03,
+ CSGMODE_HIGHLIGHT_DIFFERENCE = CSGMODE_HIGHLIGHT | CSGMODE_DIFFERENCE_FLAG
};
void render_surface(csgmode_e csgmode, const Transform3d &m, GLint *shaderinfo = NULL) const;
diff --git a/src/printutils.h b/src/printutils.h
index 521682c..9d99a19 100644
--- a/src/printutils.h
+++ b/src/printutils.h
@@ -22,4 +22,26 @@ void PRINT(const std::string &msg);
void PRINT_NOCACHE(const std::string &msg);
#define PRINTB_NOCACHE(_fmt, _arg) do { PRINT_NOCACHE(str(boost::format(_fmt) % _arg)); } while (0)
+// extremely simple logging, eventually replace with something like boost.log
+// usage: logstream out(5); openscad_loglevel=6; out << "hi";
+static int openscad_loglevel = 0;
+class logstream
+{
+public:
+ std::ostream *out;
+ int loglevel;
+ logstream( int level = 0 ) {
+ loglevel = level;
+ out = &(std::cout);
+ }
+ template <typename T> logstream & operator<<( T const &t ) {
+ if (out && loglevel <= openscad_loglevel) {
+ (*out) << t ;
+ out->flush();
+ }
+ return *this;
+ }
+};
+
+
#endif
diff --git a/src/renderer.cc b/src/renderer.cc
index db3204f..985b460 100644
--- a/src/renderer.cc
+++ b/src/renderer.cc
@@ -49,6 +49,7 @@ void Renderer::setColor(ColorMode colormode, GLint *shaderinfo) const
col.setRgb(150, 150, 150, 128);
break;
default:
+ return;
break;
}
float rgba[4];
diff --git a/src/stl-utils.cc b/src/stl-utils.cc
new file mode 100644
index 0000000..790fd17
--- /dev/null
+++ b/src/stl-utils.cc
@@ -0,0 +1,73 @@
+#if defined(__APPLE__) && defined(__GNUC__)
+
+#include <iostream>
+
+// Workarounds for symbols that are missing from Leopard stdlibc++.dylib.
+_GLIBCXX_BEGIN_NAMESPACE(std)
+// From ostream_insert.h
+template ostream& __ostream_insert(ostream&, const char*, streamsize);
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+ template wostream& __ostream_insert(wostream&, const wchar_t*, streamsize);
+#endif
+
+// From ostream.tcc
+template ostream& ostream::_M_insert(long);
+template ostream& ostream::_M_insert(unsigned long);
+template ostream& ostream::_M_insert(bool);
+#ifdef _GLIBCXX_USE_LONG_LONG
+ template ostream& ostream::_M_insert(long long);
+ template ostream& ostream::_M_insert(unsigned long long);
+#endif
+template ostream& ostream::_M_insert(double);
+template ostream& ostream::_M_insert(long double);
+template ostream& ostream::_M_insert(const void*);
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+ template wostream& wostream::_M_insert(long);
+ template wostream& wostream::_M_insert(unsigned long);
+ template wostream& wostream::_M_insert(bool);
+ #ifdef _GLIBCXX_USE_LONG_LONG
+ template wostream& wostream::_M_insert(long long);
+ template wostream& wostream::_M_insert(unsigned long long);
+ #endif
+ template wostream& wostream::_M_insert(double);
+ template wostream& wostream::_M_insert(long double);
+ template wostream& wostream::_M_insert(const void*);
+#endif
+
+
+// From istream.tcc
+template istream& istream::_M_extract(unsigned short&);
+template istream& istream::_M_extract(unsigned int&);
+template istream& istream::_M_extract(long&);
+template istream& istream::_M_extract(unsigned long&);
+template istream& istream::_M_extract(bool&);
+#ifdef _GLIBCXX_USE_LONG_LONG
+ template istream& istream::_M_extract(long long&);
+ template istream& istream::_M_extract(unsigned long long&);
+#endif
+template istream& istream::_M_extract(float&);
+template istream& istream::_M_extract(double&);
+template istream& istream::_M_extract(long double&);
+template istream& istream::_M_extract(void*&);
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+ template wistream& wistream::_M_extract(unsigned short&);
+ template wistream& wistream::_M_extract(unsigned int&);
+ template wistream& wistream::_M_extract(long&);
+ template wistream& wistream::_M_extract(unsigned long&);
+ template wistream& wistream::_M_extract(bool&);
+ #ifdef _GLIBCXX_USE_LONG_LONG
+ template wistream& wistream::_M_extract(long long&);
+ template wistream& wistream::_M_extract(unsigned long long&);
+ #endif
+ template wistream& wistream::_M_extract(float&);
+ template wistream& wistream::_M_extract(double&);
+ template wistream& wistream::_M_extract(long double&);
+ template wistream& wistream::_M_extract(void*&);
+#endif
+
+_GLIBCXX_END_NAMESPACE
+
+#endif
diff --git a/src/surface.cc b/src/surface.cc
index 2fa3717..4339ead 100644
--- a/src/surface.cc
+++ b/src/surface.cc
@@ -134,7 +134,7 @@ PolySet *SurfaceNode::evaluate_polyset(class PolySetEvaluator *) const
min_val = std::min(v-1, min_val);
}
}
- catch (boost::bad_lexical_cast &blc) {
+ catch (const boost::bad_lexical_cast &blc) {
if (!stream.eof()) {
PRINTB("WARNING: Illegal value in '%s': %s", filename % blc.what());
}
diff --git a/src/svg.cc b/src/svg.cc
new file mode 100644
index 0000000..e5130b0
--- /dev/null
+++ b/src/svg.cc
@@ -0,0 +1,249 @@
+#include "cgalutils.h"
+#include "svg.h"
+#include <boost/algorithm/string.hpp>
+#include <map>
+
+namespace OpenSCAD {
+
+// SVG code
+// currently for debugging, not necessarily pretty or useful for users. (yet)
+int svg_cursor_py = 0;
+int svg_px_width = SVG_PXW;
+int svg_px_height = SVG_PXH;
+
+std::string svg_header( int widthpx, int heightpx )
+{
+ std::stringstream out;
+ out << "<svg width='" << widthpx << "px' height='" << heightpx << "px'"
+ << " xmlns='http://www.w3.org/2000/svg' version='1.1'>";
+ return out.str();
+}
+
+std::string svg_label(std::string s)
+{
+ std::stringstream out;
+ out << " <text fill='black' x='20' y='40' font-size='24'>" << s << "</text>";
+ return out.str();
+}
+
+std::string svg_border()
+{
+ std::stringstream out;
+ out << " <!-- border -->\n";
+ out << " <polyline points='0,0 "
+ << svg_px_width << ",0 "
+ << svg_px_width << "," << svg_px_height
+ << " 0," << svg_px_height << "'"
+ << " style='fill:none;stroke:black' />\n";
+ out << " <!-- /border -->";
+ return out.str();
+}
+
+std::string svg_axes()
+{
+ std::stringstream out;
+ out << " <!-- axes -->\n";
+ out << " <polyline points='10,455 10,475 10,465 18,465 2,465 10,465 14,461 6,469 10,465'"
+ << " style='fill:none;stroke:black;' />\n";
+ out << " <!-- /axes -->";
+ return out.str();
+}
+
+CGAL_Point_2e project_svg_3to2( CGAL_Point_3 p, CGAL_Iso_cuboid_3 bbox )
+{
+ NT screenw(svg_px_width);
+ NT screenh(svg_px_height);
+ NT screenxc = screenw / 2;
+ NT screenyc = screenh / 2;
+ NT bboxx = ( bbox.xmax() - bbox.xmin() );
+ NT bboxy = ( bbox.ymax() - bbox.ymin() );
+ NT bboxz = ( bbox.zmax() - bbox.zmin() );
+ NT largest_dim = CGAL::max( CGAL::max( bboxx, bboxy ), bboxz );
+ NT bboxxc = bboxx / 2 + bbox.xmin();
+ NT bboxyc = bboxy / 2 + bbox.ymin();
+ NT bboxzc = bboxz / 2 + bbox.zmin();
+ NT xinbox = ( p.x() - bboxxc ) / largest_dim;
+ NT yinbox = ( p.y() - bboxyc ) / largest_dim;
+ NT zinbox = ( p.z() - bboxzc ) / largest_dim;
+ // do simple fake paralell projection
+ NT tx = screenxc + xinbox * screenw / 1.618 + yinbox * screenh / 3.2;
+ NT ty = screenyc - zinbox * screenh / 1.618 - yinbox * screenh / 3.2;
+ return CGAL_Point_2e( tx, ty );
+}
+
+CGAL_Point_2e project_svg_2to2( CGAL_Point_2e p, CGAL_Iso_rectangle_2e bbox )
+{
+ double screenw = svg_px_width;
+ double screenh = svg_px_height;
+ double borderw = screenw * 0.1618;
+ double borderh = screenh * 0.1618;
+ double vizw = screenw - borderw*2;
+ double vizh = screenh - borderh*2;
+ double bboxw = CGAL::to_double( bbox.xmax() - bbox.xmin() );
+ double bboxh = CGAL::to_double( bbox.ymax() - bbox.ymin() );
+ double xinbox = CGAL::to_double( p.x() ) - CGAL::to_double( bbox.xmin() );
+ double yinbox = CGAL::to_double( p.y() ) - CGAL::to_double( bbox.ymin() );
+ double tx = borderw + ( xinbox / ( bboxw==0?1:bboxw ) ) * ( vizw );
+ double ty = screenh - borderh - ( yinbox / ( bboxh==0?1:bboxh ) ) * ( vizh );
+ return CGAL_Point_2e( tx, ty );
+}
+
+std::string dump_cgal_nef_polyhedron2_face_svg(
+ CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c1,
+ CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c2,
+ CGAL_Nef_polyhedron2::Explorer explorer,
+ std::string color,
+ bool mark,
+ CGAL_Iso_rectangle_2e bbox )
+{
+ std::stringstream out;
+ CGAL_For_all(c1, c2) {
+ if ( explorer.is_standard( explorer.target(c1) ) ) {
+ CGAL_Point_2e source = explorer.point( explorer.source( c1 ) );
+ CGAL_Point_2e target = explorer.point( explorer.target( c1 ) );
+ CGAL_Point_2e tp1 = project_svg_2to2( source, bbox );
+ CGAL_Point_2e tp2 = project_svg_2to2( target, bbox );
+ double mod=0;
+ if (color=="green") mod=10;
+ out << " <!-- Halfedge. Mark: " << c1->mark() << " -->\n";
+ out << " <line"
+ << " x1='" << CGAL::to_double(tp1.x()) + mod << "'"
+ << " y1='" << CGAL::to_double(tp1.y()) - mod << "'"
+ << " x2='" << CGAL::to_double(tp2.x()) + mod << "'"
+ << " y2='" << CGAL::to_double(tp2.y()) - mod << "'"
+ << " stroke='" << color << "'";
+ if (!mark) out << " stroke-dasharray='4 4' />\n";
+ else out << " />\n";
+ // crude "arrowhead" to indicate directionality
+ out << " <circle"
+ << " cx='" << CGAL::to_double(tp1.x()+ (tp2.x()-tp1.x())* 7/8) + mod << "'"
+ << " cy='" << CGAL::to_double(tp1.y()+ (tp2.y()-tp1.y())* 7/8) - mod << "'"
+ << " r='2'"
+ << " fill='" << color << "' stroke='" << color << "' />\n";
+ } else {
+ out << " <!-- 2d Nef Rays - not implemented -->\n";
+ }
+ }
+ return out.str();
+}
+
+std::string dump_svg( const CGAL_Nef_polyhedron2 &N )
+{
+ std::stringstream out;
+ CGAL_Nef_polyhedron2::Explorer explorer = N.explorer();
+
+ CGAL_Iso_rectangle_2e bbox = bounding_box( N );
+
+ CGAL_Nef_polyhedron2::Explorer::Face_const_iterator i;
+ out << " <svg y='" << svg_cursor_py << "' width='" << svg_px_width
+ << "' height='" << svg_px_height
+ << "' xmlns='http://www.w3.org/2000/svg' version='1.1'>\n";
+ out << svg_border() << "\n" << svg_axes() << "\n";
+ svg_cursor_py += svg_px_height;
+
+ for ( i = explorer.faces_begin(); i!= explorer.faces_end(); ++i ) {
+ out << " <!-- face begin. mark: " << i->mark() << " -->\n";
+ CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c1
+ = explorer.face_cycle( i ), c2 ( c1 );
+ out << dump_cgal_nef_polyhedron2_face_svg( c1, c2, explorer, "red", i->mark(), bbox );
+
+ CGAL_Nef_polyhedron2::Explorer::Hole_const_iterator j;
+ for ( j = explorer.holes_begin( i ); j!= explorer.holes_end( i ); ++j ) {
+ out << " <!-- hole begin. mark: " << j->mark() << " -->\n";
+ CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c3( j ), c4 ( c3 );
+ out << dump_cgal_nef_polyhedron2_face_svg( c3, c4, explorer, "green", j->mark(), bbox );
+ out << " <!-- hole end -->\n";
+ }
+ out << " <!-- face end -->\n";
+ }
+ out << "</svg>";
+ std::string tmp = out.str();
+ boost::replace_all( tmp, "'", "\"" );
+ return tmp;
+}
+
+
+// This uses the Shell Explorer pattern from the CGAL Manual to dump the 3d Nef Polyhedron information
+// http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3/Chapter_main.html#Subsection_29.7.2
+class NefPoly3_dumper_svg {
+public:
+ std::stringstream out;
+ CGAL_Iso_cuboid_3 bbox;
+ NefPoly3_dumper_svg(const CGAL_Nef_polyhedron3& N)
+ {
+ bbox = bounding_box( N );
+ }
+ void visit(CGAL_Nef_polyhedron3::Vertex_const_handle ) {}
+ void visit(CGAL_Nef_polyhedron3::Halfedge_const_handle ) {}
+ void visit(CGAL_Nef_polyhedron3::SHalfedge_const_handle ) {}
+ void visit(CGAL_Nef_polyhedron3::SHalfloop_const_handle ) {}
+ void visit(CGAL_Nef_polyhedron3::SFace_const_handle ) {}
+ void visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet )
+ {
+ int contour_count = 0;
+ out << " <!-- Halffacet. Mark: " << (*hfacet).mark() << " -->\n";
+ std::string color = "gold";
+ if (!(*hfacet).mark()) color = "green";
+ CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator i;
+ CGAL_forall_facet_cycles_of( i, hfacet ) {
+ CGAL_Nef_polyhedron3::SHalfloop_const_handle shl_handle;
+ out << " <!-- Halffacet cycle: -->\n";
+ if ( contour_count == 0 ) {
+ out << " <!-- Body contour:--> \n";
+ } else {
+ out << " <!-- Hole contour:--> \n" ;
+ }
+ CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(i), c2(c1);
+ CGAL_For_all( c1, c2 ) {
+ out << " <line";
+ // don't know why we use source()->source(), except thats what CGAL does internally
+ CGAL_Point_3 source = c1->source()->source()->point();
+ CGAL_Point_3 target = c1->source()->target()->point();
+ CGAL_Point_2e tp1 = project_svg_3to2 ( source, bbox );
+ CGAL_Point_2e tp2 = project_svg_3to2 ( target, bbox );
+ out << " "
+ << "x1='" << CGAL::to_double(tp1.x()) << "' "
+ << "y1='" << CGAL::to_double(tp1.y()) << "' "
+ << "x2='" << CGAL::to_double(tp2.x()) << "' "
+ << "y2='" << CGAL::to_double(tp2.y()) << "' "
+ << " stroke='" << color << "'";
+ if (!(*hfacet).mark()) out << " stroke-dasharray='4 4' />\n";
+ else out << " />\n";
+ }
+ contour_count++;
+ } // next facet cycle (i.e. next contour)
+ } // visit()
+
+};
+
+
+std::string dump_svg( const CGAL_Nef_polyhedron3 &N )
+{
+ std::stringstream out;
+ out << svg_header() << "\n" << svg_border() << "\n" << svg_axes() << "\n";
+ out << "<!--CGAL_Nef_polyhedron3 dump begin-->\n";
+
+ CGAL_Nef_polyhedron3::Volume_const_iterator c;
+ CGAL_forall_volumes(c,N) {
+ out << " <!--Processing volume...-->\n";
+ out << " <!--Mark: " << (*c).mark() << "-->\n";
+ CGAL_Nef_polyhedron3::Shell_entry_const_iterator it;
+ CGAL_forall_shells_of(it,c) {
+ out << " <!--Processing shell...-->\n";
+ NefPoly3_dumper_svg dumper_svg(N);
+ N.visit_shell_objects(CGAL_Nef_polyhedron3::SFace_const_handle(it), dumper_svg );
+ out << dumper_svg.out.str();
+ out << " <!--Processing shell end-->\n";
+ }
+ out << " <!--Processing volume end-->\n";
+ }
+ out << "<!--CGAL_Nef_polyhedron3 dump end-->\n";
+ out << "</svg>";
+ std::string tmp = out.str();
+ boost::replace_all( tmp, "'", "\"" );
+ return tmp;
+}
+
+} // namespace
+
+
diff --git a/src/svg.h b/src/svg.h
new file mode 100644
index 0000000..828dc39
--- /dev/null
+++ b/src/svg.h
@@ -0,0 +1,28 @@
+#ifndef SVG_H_
+#define SVG_H_
+
+#include "cgal.h"
+#include <boost/algorithm/string.hpp>
+#include <map>
+
+namespace OpenSCAD {
+
+// currently for debugging, not necessarily pretty or useful for users. (yet)
+
+#define SVG_PXW 480
+#define SVG_PXH 480
+extern int svg_cursor_py;
+extern int svg_px_width;
+extern int svg_px_height;
+
+std::string svg_header( int widthpx = SVG_PXW, int heightpx = SVG_PXH );
+std::string svg_label( std::string s );
+std::string svg_border();
+std::string svg_axes();
+std::string dump_svg( const CGAL_Nef_polyhedron2 &N );
+std::string dump_svg( const CGAL_Nef_polyhedron3 &N );
+
+} // namespace
+
+#endif
+
diff --git a/src/transform.cc b/src/transform.cc
index 5b71346..0f678c5 100644
--- a/src/transform.cc
+++ b/src/transform.cc
@@ -98,7 +98,9 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti
Value val_a = c.lookup_variable("a");
if (val_a.type() == Value::VECTOR)
{
- Eigen::AngleAxisd rotx, roty, rotz;
+ Eigen::AngleAxisd rotx(0, Vector3d::UnitX());
+ Eigen::AngleAxisd roty(0, Vector3d::UnitY());
+ Eigen::AngleAxisd rotz(0, Vector3d::UnitZ());
double a;
if (val_a.toVector().size() > 0) {
val_a.toVector()[0].getDouble(a);
diff --git a/src/traverser.cc b/src/traverser.cc
index d9b3dc1..da8c679 100644
--- a/src/traverser.cc
+++ b/src/traverser.cc
@@ -16,7 +16,7 @@ Response Traverser::traverse(const AbstractNode &node, const State &state)
State newstate = state;
newstate.setNumChildren(node.getChildren().size());
- Response response;
+ Response response = ContinueTraversal;
if (traversaltype == PREFIX || traversaltype == PRE_AND_POSTFIX) {
newstate.setPrefix(true);
newstate.setParent(state.parent());
diff --git a/src/version_check.h b/src/version_check.h
index a9556e9..db17962 100644
--- a/src/version_check.h
+++ b/src/version_check.h
@@ -1,12 +1,12 @@
-// version_check.h copyright 2012 don bright. released under the GPL 2, or
-// later, as described in the file named 'COPYING' in OpenSCAD's project root.
-// permission to change this license is given to Marius Kintel & Clifford Wolf
+// version_check.h by don bright 2012. Copyright assigned to Marius Kintel and
+// Clifford Wolf 2012. Released under the GPL 2, or later, as described in
+// the file named 'COPYING' in OpenSCAD's project root.
/* This file will check versions of libraries at compile time. If they
are too old, the user will be warned. If the user wishes to force
compilation, they can run
- qmake CONFIG=skip-version-check
+ qmake CONFIG+=skip-version-check
Otherwise they will be guided to README.md and an -build-dependencies script.
@@ -24,26 +24,26 @@ a time, to avoid confusion.
#define GMPPATCH 0
#define SYS_GMP_VER (__GNU_MP_VERSION * 10000 + __GNU_MP_VERSION_MINOR * 100 + __GNU_MP_VERSION_PATCHLEVEL * 1)
#if SYS_GMP_VER < GMPMAJOR * 10000 + GMPMINOR * 100 + GMPPATCH * 1
-#error GNU GMP library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error GNU GMP library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#else
#include <mpfr.h>
#if MPFR_VERSION < MPFR_VERSION_NUM( 3,0,0 )
-#error GNU MPFR library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error GNU MPFR library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#else
#include <Eigen/Core>
#if not EIGEN_VERSION_AT_LEAST( 2,0,13 )
-#error eigen2 library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error eigen2 library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#else
#include <boost/version.hpp>
// boost 1.3.5 = 103500
#if BOOST_VERSION < 103500
-#error boost library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error boost library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#else
@@ -51,7 +51,7 @@ a time, to avoid confusion.
#include <CGAL/version.h>
#if CGAL_VERSION_NR < 1030601000
-#error CGAL library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error CGAL library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#else
#if CGAL_VERSION_NR < 1040021000
@@ -66,6 +66,9 @@ a time, to avoid confusion.
#warning "."
#warning "."
#warning "======================="
+#ifdef __clang__
+#error For Clang to work, CGAL must be >= 4.0.2
+#endif
#endif // CGAL_VERSION_NR < 10400010000
#endif //ENABLE_CGAL
@@ -73,20 +76,20 @@ a time, to avoid confusion.
#include <GL/glew.h>
// kludge - GLEW doesnt have compiler-accessible version numbering
#ifndef GLEW_ARB_occlusion_query2
-#error GLEW library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error GLEW library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#else
#include <opencsg.h>
// 1.3.2 -> 0x0132
#if OPENCSG_VERSION < 0x0132
-#error OPENCSG library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error OPENCSG library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#else
#endif // ENABLE_OPENCSG
#include <QtCore/qglobal.h>
#if QT_VERSION < 0x040400
-#error QT library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error QT library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#endif // QT
diff --git a/src/winconsole.c b/src/winconsole.c
new file mode 100644
index 0000000..de8e682
--- /dev/null
+++ b/src/winconsole.c
@@ -0,0 +1,84 @@
+/*
+ Enable easy piping under Windows(TM) command line.
+
+ We use the 'devenv'(TM) method, which means we have two binary files:
+
+ openscad.com, with IMAGE_SUBSYSTEM_WINDOWS_CUI flag set
+ openscad.exe, with IMAGE_SUBSYSTEM_WINDOWS_GUI flag set
+
+ The .com version is a 'wrapper' for the .exe version. If you call
+ 'openscad' with no extension from a script or shell, the .com version
+ is prioritized by the OS and feeds the GUI stdout to the console. We use
+ pure C to minimize binary size when cross-compiling (~10kbytes). See Also:
+
+ http://stackoverflow.com/questions/493536/can-one-executable-be-both-a-console-and-gui-app
+ http://blogs.msdn.com/b/oldnewthing/archive/2009/01/01/9259142.aspx
+ http://blogs.msdn.com/b/junfeng/archive/2004/02/06/68531.aspx
+ http://msdn.microsoft.com/en-us/library/aa298534%28v=vs.60%29.aspx
+ http://cournape.wordpress.com/2008/07/29/redirecting-stderrstdout-in-cmdexe/
+ Open Group popen() documentation
+ inkscapec by Jos Hirth work at http://kaioa.com
+ Nop Head's OpenSCAD_cl at github.com
+
+ TODO:
+ Work with unicode: http://www.i18nguy.com/unicode/c-unicode.html
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define MAXCMDLEN 64000
+#define BUFFSIZE 42
+
+int main( int argc, char * argv[] )
+{
+ FILE *cmd_stdout;
+ char cmd[MAXCMDLEN];
+ char buffer[BUFFSIZE];
+ char *fgets_result;
+ int eof = 0;
+ int pclose_result;
+ int i;
+ int result = 0;
+
+ strcat( cmd, "\0" );
+ strcat( cmd, "openscad.exe" );
+ for ( i = 1 ; i < argc ; ++i ) {
+ strcat( cmd, " " );
+ strcat( cmd, argv[i] );
+ }
+ strcat( cmd, " ");
+ strcat( cmd, " 2>&1"); // capture stderr and stdout
+
+ cmd_stdout = _popen( cmd, "rt" );
+ if ( cmd_stdout == NULL ) {
+ printf( "Error opening _popen for command: %s", cmd );
+ perror( "Error message:" );
+ return 1;
+ }
+
+ while ( !eof )
+ {
+ fgets_result = fgets( buffer, BUFFSIZE, cmd_stdout );
+ if ( fgets_result == NULL ) {
+ if ( ferror( cmd_stdout ) ) {
+ printf("Error reading from stdout of %s\n", cmd);
+ result = 1;
+ }
+ if ( feof( cmd_stdout ) ) {
+ eof = 1;
+ }
+ } else {
+ fprintf( stdout, "%s", buffer );
+ }
+ }
+
+ pclose_result = _pclose( cmd_stdout );
+ if ( pclose_result < 0 ) {
+ perror("Error while closing stdout for command:");
+ result = 1;
+ }
+
+ return result;
+}
contact: Jan Huwald // Impressum