summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/MainWindow.h4
-rw-r--r--src/PlatformUtils.cc26
-rw-r--r--src/control.cc101
-rw-r--r--src/expr.cc3
-rw-r--r--src/mainwin.cc11
-rw-r--r--src/openscad.cc682
-rw-r--r--src/parsersettings.cc1
-rw-r--r--src/svg.cc110
-rw-r--r--src/value.cc9
-rw-r--r--src/value.h17
-rw-r--r--src/version_check.h3
11 files changed, 562 insertions, 405 deletions
diff --git a/src/MainWindow.h b/src/MainWindow.h
index 79e2080..4f88fbf 100644
--- a/src/MainWindow.h
+++ b/src/MainWindow.h
@@ -54,6 +54,7 @@ public:
std::vector<shared_ptr<CSGTerm> > background_terms;
CSGChain *background_chain;
QString last_compiled_doc;
+ static QString qexamplesdir;
static const int maxRecentFiles = 10;
QAction *actionRecentFile[maxRecentFiles];
@@ -134,6 +135,7 @@ private slots:
void actionFlushCaches();
public:
+ static void setExamplesDir(const QString &dir) { MainWindow::qexamplesdir = dir; }
void viewModeActionsUncheck();
void setCurrentOutput();
void clearCurrentOutput();
@@ -201,7 +203,7 @@ public:
static void unlock() { gui_locked--; }
private:
- static unsigned int gui_locked;
+ static unsigned int gui_locked;
};
#endif
diff --git a/src/PlatformUtils.cc b/src/PlatformUtils.cc
index a64162c..5059b78 100644
--- a/src/PlatformUtils.cc
+++ b/src/PlatformUtils.cc
@@ -40,11 +40,12 @@ std::string PlatformUtils::libraryPath()
}
#include "version_check.h"
-#include "cgal.h"
-#include <boost/algorithm/string.hpp>
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
+#ifdef ENABLE_CGAL
+#include "cgal.h"
+#include <boost/algorithm/string.hpp>
#if defined(__GNUG__)
#define GCC_INT_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 )
#if GCC_INT_VERSION > 40600 || defined(__clang__)
@@ -52,6 +53,7 @@ std::string PlatformUtils::libraryPath()
#define __openscad_info_demangle__ 1
#endif // GCC_INT_VERSION
#endif // GNUG
+#endif // ENABLE_CGAL
std::string PlatformUtils::info()
{
@@ -79,6 +81,13 @@ std::string PlatformUtils::info()
#define OPENCSG_VERSION_STRING "unknown, <1.3.2"
#endif
+#ifdef QT_VERSION
+ std::string qtVersion = qVersion();
+#else
+ std::string qtVersion = "Qt disabled";
+#endif
+
+#ifdef ENABLE_CGAL
std::string cgal_3d_kernel = typeid(CGAL_Kernel3).name();
std::string cgal_2d_kernel = typeid(CGAL_Kernel2).name();
std::string cgal_2d_kernelEx = typeid(CGAL_ExactKernel2).name();
@@ -87,20 +96,25 @@ std::string PlatformUtils::info()
cgal_3d_kernel = std::string( abi::__cxa_demangle( cgal_3d_kernel.c_str(), 0, 0, &status ) );
cgal_2d_kernel = std::string( abi::__cxa_demangle( cgal_2d_kernel.c_str(), 0, 0, &status ) );
cgal_2d_kernelEx = std::string( abi::__cxa_demangle( cgal_2d_kernelEx.c_str(), 0, 0, &status ) );
-#endif
+#endif // demangle
boost::replace_all( cgal_3d_kernel, "CGAL::", "" );
boost::replace_all( cgal_2d_kernel, "CGAL::", "" );
boost::replace_all( cgal_2d_kernelEx, "CGAL::", "" );
+#else // ENABLE_CGAL
+ std::string cgal_3d_kernel = "";
+ std::string cgal_2d_kernel = "";
+ std::string cgal_2d_kernelEx = "";
+#endif // ENABLE_CGAL
s << "OpenSCAD Version: " << TOSTRING(OPENSCAD_VERSION)
- << "\nCompiler: " << compiler_info
- << "\nCompile date: " << __DATE__
+ << "\nCompiler, build date: " << compiler_info << ", " << __DATE__
<< "\nBoost version: " << BOOST_LIB_VERSION
<< "\nEigen version: " << EIGEN_WORLD_VERSION << "." << EIGEN_MAJOR_VERSION << "." << EIGEN_MINOR_VERSION
<< "\nCGAL version, kernels: " << TOSTRING(CGAL_VERSION) << ", " << cgal_3d_kernel << ", " << cgal_2d_kernel << ", " << cgal_2d_kernelEx
<< "\nOpenCSG version: " << OPENCSG_VERSION_STRING
- << "\nQt version: " << qVersion()
+ << "\nQt version: " << qtVersion
<< "\nMingW build: " << mingwstatus
+ << "\nOPENSCADPATH: " << getenv("OPENSCADPATH")
;
return s.str();
}
diff --git a/src/control.cc b/src/control.cc
index ec13650..10aadf0 100644
--- a/src/control.cc
+++ b/src/control.cc
@@ -24,6 +24,7 @@
*
*/
+#include <boost/foreach.hpp>
#include "module.h"
#include "node.h"
#include "evalcontext.h"
@@ -33,6 +34,10 @@
#include <sstream>
#include "mathc99.h"
+
+#define foreach BOOST_FOREACH
+
+
class ControlModule : public AbstractModule
{
public: // types
@@ -56,6 +61,8 @@ public: // methods
const Context *ctx, const EvalContext *evalctx);
static const EvalContext* getLastModuleCtx(const EvalContext *evalctx);
+
+ static AbstractNode* getChild(const Value& value, const EvalContext* modulectx);
private: // data
Type type;
@@ -71,12 +78,8 @@ void ControlModule::for_eval(AbstractNode &node, const ModuleInstantiation &inst
Context c(ctx);
if (it_values.type() == Value::RANGE) {
Value::RangeType range = it_values.toRange();
- if (range.end < range.begin) {
- double t = range.begin;
- range.begin = range.end;
- range.end = t;
- }
- if (range.step > 0 && (range.begin-range.end)/range.step < 10000) {
+ range.normalize();
+ if (range.nbsteps()<10000) {
for (double i = range.begin; i <= range.end; i += range.step) {
c.set_variable(it_name, Value(i));
for_eval(node, inst, l+1, &c, evalctx);
@@ -119,7 +122,38 @@ const EvalContext* ControlModule::getLastModuleCtx(const EvalContext *evalctx)
return NULL;
}
-AbstractNode *ControlModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+// static
+AbstractNode* ControlModule::getChild(const Value& value, const EvalContext* modulectx)
+{
+ if (value.type()!=Value::NUMBER) {
+ // Invalid parameter
+ // (e.g. first child of difference is invalid)
+ PRINTB("WARNING: Bad parameter type (%s) for children, only accept: empty, number, vector, range.", value.toString());
+ return NULL;
+ }
+ double v;
+ if (!value.getDouble(v)) {
+ PRINTB("WARNING: Bad parameter type (%s) for children, only accept: empty, number, vector, range.", value.toString());
+ return NULL;
+ }
+
+ int n = trunc(v);
+ if (n < 0) {
+ PRINTB("WARNING: Negative children index (%d) not allowed", n);
+ return NULL; // Disallow negative child indices
+ }
+ if (n>=(int)modulectx->numChildren()) {
+ // How to deal with negative objects in this case?
+ // (e.g. first child of difference is invalid)
+ PRINTB("WARNING: Children index (%d) out of bounds (%d children)"
+ , n % modulectx->numChildren());
+ return NULL;
+ }
+ // OK
+ return modulectx->getChild(n)->evaluate(modulectx);
+}
+
+AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
AbstractNode *node = NULL;
@@ -162,14 +196,57 @@ AbstractNode *ControlModule::instantiate(const Context *ctx, const ModuleInstant
if (modulectx==NULL) {
return NULL;
}
- AbstractNode* node = new AbstractNode(inst);
// This will trigger if trying to invoke child from the root of any file
// assert(filectx->evalctx);
- for (int n = 0; n < (int)modulectx->numChildren(); ++n) {
- AbstractNode* childnode = modulectx->getChild(n)->evaluate(modulectx);
- node->children.push_back(childnode);
+ if (evalctx->numArgs()<=0) {
+ // no parameters => all children
+ AbstractNode* node = new AbstractNode(inst);
+ for (int n = 0; n < (int)modulectx->numChildren(); ++n) {
+ AbstractNode* childnode = modulectx->getChild(n)->evaluate(modulectx);
+ if (childnode==NULL) continue; // error
+ node->children.push_back(childnode);
+ }
+ return node;
}
- return node;
+ else if (evalctx->numArgs()>0) {
+ // one (or more ignored) parameter
+ const Value& value = evalctx->getArgValue(0);
+ if (value.type() == Value::NUMBER) {
+ return getChild(value,modulectx);
+ }
+ else if (value.type() == Value::VECTOR) {
+ AbstractNode* node = new AbstractNode(inst);
+ const Value::VectorType& vect = value.toVector();
+ foreach (const Value::VectorType::value_type& vectvalue, vect) {
+ AbstractNode* childnode = getChild(vectvalue,modulectx);
+ if (childnode==NULL) continue; // error
+ node->children.push_back(childnode);
+ }
+ return node;
+ }
+ else if (value.type() == Value::RANGE) {
+ AbstractNode* node = new AbstractNode(inst);
+ Value::RangeType range = value.toRange();
+ range.normalize();
+ if (range.nbsteps()>=10000) {
+ PRINTB("WARNING: Bad range parameter for children: too many elements (%d).", (int)((range.begin-range.end)/range.step));
+ return NULL;
+ }
+ for (double i = range.begin; i <= range.end; i += range.step) {
+ AbstractNode* childnode = getChild(Value(i),modulectx); // with error cases
+ if (childnode==NULL) continue; // error
+ node->children.push_back(childnode);
+ }
+ return node;
+ }
+ else {
+ // Invalid parameter
+ // (e.g. first child of difference is invalid)
+ PRINTB("WARNING: Bad parameter type (%s) for children, only accept: empty, number, vector, range.", value.toString());
+ return NULL;
+ }
+ }
+ return NULL;
}
if (type == INT_FOR)
diff --git a/src/expr.cc b/src/expr.cc
index 8500d13..594fccf 100644
--- a/src/expr.cc
+++ b/src/expr.cc
@@ -119,7 +119,8 @@ Value Expression::evaluate(const Context *context) const
Value v2 = this->children[1]->evaluate(context);
Value v3 = this->children[2]->evaluate(context);
if (v1.type() == Value::NUMBER && v2.type() == Value::NUMBER && v3.type() == Value::NUMBER) {
- return Value(v1.toDouble(), v2.toDouble(), v3.toDouble());
+ Value::RangeType range(v1.toDouble(), v2.toDouble(), v3.toDouble());
+ return Value(range);
}
return Value();
}
diff --git a/src/mainwin.cc b/src/mainwin.cc
index fd1c552..65c511f 100644
--- a/src/mainwin.cc
+++ b/src/mainwin.cc
@@ -27,7 +27,6 @@
#include "PolySetCache.h"
#include "ModuleCache.h"
#include "MainWindow.h"
-#include "openscad.h" // examplesdir
#include "parsersettings.h"
#include "Preferences.h"
#include "printutils.h"
@@ -103,10 +102,9 @@
#include "boosty.h"
-extern QString examplesdir;
-
// Global application state
unsigned int GuiLocker::gui_locked = 0;
+QString MainWindow::qexamplesdir;
#define QUOTE(x__) # x__
#define QUOTED(x__) QUOTE(x__)
@@ -253,10 +251,9 @@ MainWindow::MainWindow(const QString &filename)
this->menuOpenRecent->addAction(this->fileActionClearRecent);
connect(this->fileActionClearRecent, SIGNAL(triggered()),
this, SLOT(clearRecentFiles()));
-
- if (!examplesdir.isEmpty()) {
+ if (!qexamplesdir.isEmpty()) {
bool found_example = false;
- QStringList examples = QDir(examplesdir).entryList(QStringList("*.scad"),
+ QStringList examples = QDir(qexamplesdir).entryList(QStringList("*.scad"),
QDir::Files | QDir::Readable, QDir::Name);
foreach (const QString &ex, examples) {
this->menuExamples->addAction(ex, this, SLOT(actionOpenExample()));
@@ -985,7 +982,7 @@ void MainWindow::actionOpenExample()
{
QAction *action = qobject_cast<QAction *>(sender());
if (action) {
- openFile(examplesdir + QDir::separator() + action->text());
+ openFile(qexamplesdir + QDir::separator() + action->text());
}
}
diff --git a/src/openscad.cc b/src/openscad.cc
index fb5ee44..f4f4014 100644
--- a/src/openscad.cc
+++ b/src/openscad.cc
@@ -25,19 +25,18 @@
*/
#include "openscad.h"
-#include "MainWindow.h"
#include "node.h"
#include "module.h"
#include "modcontext.h"
#include "value.h"
#include "export.h"
#include "builtin.h"
-#include "nodedumper.h"
#include "printutils.h"
#include "handle_dep.h"
#include "parsersettings.h"
#include "rendersettings.h"
#include "PlatformUtils.h"
+#include "nodedumper.h"
#include <string>
#include <vector>
@@ -53,13 +52,9 @@
#include "CSGTermEvaluator.h"
#include "CsgInfo.h"
-#include <QApplication>
-#include <QString>
-#include <QDir>
#include <sstream>
-#ifdef Q_WS_MAC
-#include "EventFilter.h"
+#ifdef __APPLE__
#include "AppleEvents.h"
#ifdef OPENSCAD_DEPLOY
#include "SparkleAutoUpdater.h"
@@ -79,6 +74,28 @@
namespace po = boost::program_options;
namespace fs = boost::filesystem;
+namespace Render { enum type { CGAL, OPENCSG, THROWNTOGETHER }; };
+std::string commandline_commands;
+std::string currentdir;
+using std::string;
+using std::vector;
+using boost::lexical_cast;
+using boost::is_any_of;
+
+class Echostream : public std::ofstream
+{
+public:
+ Echostream( const char * filename ) : std::ofstream( filename ) {
+ set_output_handler( &Echostream::output, this );
+ }
+ static void output( const std::string &msg, void *userdata ) {
+ Echostream *thisp = static_cast<Echostream*>(userdata);
+ *thisp << msg << "\n";
+ }
+ ~Echostream() {
+ this->close();
+ }
+};
static void help(const char *progname)
{
@@ -119,15 +136,6 @@ static void info()
exit(0);
}
-std::string commandline_commands;
-std::string currentdir;
-QString examplesdir;
-
-using std::string;
-using std::vector;
-using boost::lexical_cast;
-using boost::is_any_of;
-
Camera get_camera( po::variables_map vm )
{
Camera camera;
@@ -182,17 +190,257 @@ Camera get_camera( po::variables_map vm )
return camera;
}
-int main(int argc, char **argv)
+int cmdline(const char *deps_output_file, const std::string &filename, Camera &camera, const char *output_file, const fs::path &original_path, Render::type renderer, char ** argv )
{
- int rc = 0;
+ parser_init(boosty::stringy(boost::filesystem::path( argv[0] ).parent_path()));
+ Tree tree;
+#ifdef ENABLE_CGAL
+ CGALEvaluator cgalevaluator(tree);
+ PolySetCGALEvaluator psevaluator(cgalevaluator);
+#endif
+ const char *stl_output_file = NULL;
+ const char *off_output_file = NULL;
+ const char *dxf_output_file = NULL;
+ const char *csg_output_file = NULL;
+ const char *png_output_file = NULL;
+ const char *ast_output_file = NULL;
+ const char *term_output_file = NULL;
+ const char *echo_output_file = NULL;
+
+ std::string suffix = boosty::extension_str( output_file );
+ boost::algorithm::to_lower( suffix );
+
+ if (suffix == ".stl") stl_output_file = output_file;
+ else if (suffix == ".off") off_output_file = output_file;
+ else if (suffix == ".dxf") dxf_output_file = output_file;
+ else if (suffix == ".csg") csg_output_file = output_file;
+ else if (suffix == ".png") png_output_file = output_file;
+ else if (suffix == ".ast") ast_output_file = output_file;
+ else if (suffix == ".term") term_output_file = output_file;
+ else if (suffix == ".echo") echo_output_file = output_file;
+ else {
+ fprintf(stderr, "Unknown suffix for output file %s\n", output_file);
+ return 1;
+ }
+ // Top context - this context only holds builtins
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
+#if 0 && DEBUG
+ top_ctx.dump(NULL, NULL);
+#endif
+ shared_ptr<Echostream> echostream;
+ if (echo_output_file)
+ echostream.reset( new Echostream( echo_output_file ) );
+
+ FileModule *root_module;
+ ModuleInstantiation root_inst("group");
+ AbstractNode *root_node;
+ AbstractNode *absolute_root_node;
+ CGAL_Nef_polyhedron root_N;
+
+ handle_dep(filename.c_str());
+
+ std::ifstream ifs(filename.c_str());
+ if (!ifs.is_open()) {
+ fprintf(stderr, "Can't open input file '%s'!\n", filename.c_str());
+ return 1;
+ }
+ std::string text((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
+ text += "\n" + commandline_commands;
+ fs::path abspath = boosty::absolute(filename);
+ std::string parentpath = boosty::stringy(abspath.parent_path());
+ root_module = parse(text.c_str(), parentpath.c_str(), false);
+ if (!root_module) {
+ fprintf(stderr, "Can't parse file '%s'!\n", filename.c_str());
+ return 1;
+ }
+ root_module->handleDependencies();
+
+ fs::path fpath = boosty::absolute(fs::path(filename));
+ fs::path fparent = fpath.parent_path();
+ fs::current_path(fparent);
+ top_ctx.setDocumentPath(fparent.string());
+
+ AbstractNode::resetIndexCounter();
+ absolute_root_node = root_module->instantiate(&top_ctx, &root_inst, NULL);
+
+ // Do we have an explicit root node (! modifier)?
+ if (!(root_node = find_root_tag(absolute_root_node)))
+ root_node = absolute_root_node;
+
+ tree.setRoot(root_node);
+
+ if (csg_output_file) {
+ fs::current_path(original_path);
+ std::ofstream fstream(csg_output_file);
+ if (!fstream.is_open()) {
+ PRINTB("Can't open file \"%s\" for export", csg_output_file);
+ }
+ else {
+ fs::current_path(fparent); // Force exported filenames to be relative to document path
+ fstream << tree.getString(*root_node) << "\n";
+ fstream.close();
+ }
+ }
+ else if (ast_output_file) {
+ fs::current_path(original_path);
+ std::ofstream fstream(ast_output_file);
+ if (!fstream.is_open()) {
+ PRINTB("Can't open file \"%s\" for export", ast_output_file);
+ }
+ else {
+ fs::current_path(fparent); // Force exported filenames to be relative to document path
+ fstream << root_module->dump("", "") << "\n";
+ fstream.close();
+ }
+ }
+ else if (term_output_file) {
+ std::vector<shared_ptr<CSGTerm> > highlight_terms;
+ std::vector<shared_ptr<CSGTerm> > background_terms;
+
+ CSGTermEvaluator csgRenderer(tree, &psevaluator);
+ shared_ptr<CSGTerm> root_raw_term = csgRenderer.evaluateCSGTerm(*root_node, highlight_terms, background_terms);
+
+ fs::current_path(original_path);
+ std::ofstream fstream(term_output_file);
+ if (!fstream.is_open()) {
+ PRINTB("Can't open file \"%s\" for export", term_output_file);
+ }
+ else {
+ if (!root_raw_term)
+ fstream << "No top-level CSG object\n";
+ else {
+ fstream << root_raw_term->dump() << "\n";
+ }
+ fstream.close();
+ }
+ }
+ else {
#ifdef ENABLE_CGAL
- // Causes CGAL errors to abort directly instead of throwing exceptions
- // (which we don't catch). This gives us stack traces without rerunning in gdb.
- CGAL::set_error_behaviour(CGAL::ABORT);
+ if ((echo_output_file || png_output_file) && !(renderer==Render::CGAL)) {
+ // echo or OpenCSG png -> don't necessarily need CGALMesh evaluation
+ } else {
+ root_N = cgalevaluator.evaluateCGALMesh(*tree.root());
+ }
+
+ fs::current_path(original_path);
+
+ if (deps_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 if ( png_output_file ) geom_out = std::string(png_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");
+ return 1;
+ }
+ int result = write_deps( deps_out, geom_out );
+ if ( !result ) {
+ PRINT("error writing deps");
+ return 1;
+ }
+ }
+
+ if (stl_output_file) {
+ if (root_N.dim != 3) {
+ fprintf(stderr, "Current top level object is not a 3D object.\n");
+ return 1;
+ }
+ if (!root_N.p3->is_simple()) {
+ fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
+ return 1;
+ }
+ std::ofstream fstream(stl_output_file);
+ if (!fstream.is_open()) {
+ PRINTB("Can't open file \"%s\" for export", stl_output_file);
+ }
+ else {
+ export_stl(&root_N, fstream);
+ fstream.close();
+ }
+ }
+
+ if (off_output_file) {
+ if (root_N.dim != 3) {
+ fprintf(stderr, "Current top level object is not a 3D object.\n");
+ return 1;
+ }
+ if (!root_N.p3->is_simple()) {
+ fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
+ return 1;
+ }
+ std::ofstream fstream(off_output_file);
+ if (!fstream.is_open()) {
+ PRINTB("Can't open file \"%s\" for export", off_output_file);
+ }
+ else {
+ export_off(&root_N, fstream);
+ fstream.close();
+ }
+ }
+
+ if (dxf_output_file) {
+ if (root_N.dim != 2) {
+ fprintf(stderr, "Current top level object is not a 2D object.\n");
+ return 1;
+ }
+ std::ofstream fstream(dxf_output_file);
+ if (!fstream.is_open()) {
+ PRINTB("Can't open file \"%s\" for export", dxf_output_file);
+ }
+ else {
+ export_dxf(&root_N, fstream);
+ fstream.close();
+ }
+ }
+
+ if (png_output_file) {
+ std::ofstream fstream(png_output_file,std::ios::out|std::ios::binary);
+ if (!fstream.is_open()) {
+ PRINTB("Can't open file \"%s\" for export", png_output_file);
+ }
+ else {
+ if (renderer==Render::CGAL) {
+ export_png_with_cgal(&root_N, camera, fstream);
+ } else if (renderer==Render::THROWNTOGETHER) {
+ export_png_with_throwntogether(tree, camera, fstream);
+ } else {
+ export_png_with_opencsg(tree, camera, fstream);
+ }
+ fstream.close();
+ }
+ }
+#else
+ fprintf(stderr, "OpenSCAD has been compiled without CGAL support!\n");
+ return 1;
+#endif
+ }
+ delete root_node;
+ return 0;
+}
+
+#ifdef OPENSCAD_TESTING
+#undef OPENSCAD_QTGUI
+#else
+#define OPENSCAD_QTGUI 1
#endif
- Builtins::instance()->initialize();
+
+#ifdef OPENSCAD_QTGUI
+#include "MainWindow.h"
+ #ifdef __APPLE__
+ #include "EventFilter.h"
+ #endif
+#include <QApplication>
+#include <QString>
+#include <QDir>
+
+bool QtUseGUI()
+{
#ifdef Q_WS_X11
// see <http://qt.nokia.com/doc/4.5/qapplication.html#QApplication-2>:
// On X11, the window system is initialized if GUIenabled is true. If GUIenabled
@@ -203,18 +451,95 @@ int main(int argc, char **argv)
#else
bool useGUI = true;
#endif
- QApplication app(argc, argv, useGUI);
+ return useGUI;
+}
+
+int gui(vector<string> &inputFiles, const fs::path &original_path, int argc, char ** argv)
+{
+ QApplication app(argc, argv, true); //useGUI);
#ifdef Q_WS_MAC
app.installEventFilter(new EventFilter(&app));
#endif
- fs::path original_path = fs::current_path();
-
// set up groups for QSettings
QCoreApplication::setOrganizationName("OpenSCAD");
QCoreApplication::setOrganizationDomain("openscad.org");
QCoreApplication::setApplicationName("OpenSCAD");
QCoreApplication::setApplicationVersion(TOSTRING(OPENSCAD_VERSION));
+ QDir exdir(QApplication::instance()->applicationDirPath());
+ QString qexamplesdir;
+#ifdef Q_WS_MAC
+ exdir.cd("../Resources"); // Examples can be bundled
+ if (!exdir.exists("examples")) exdir.cd("../../..");
+#elif defined(Q_OS_UNIX)
+ if (exdir.cd("../share/openscad/examples")) {
+ qexamplesdir = exdir.path();
+ } else
+ if (exdir.cd("../../share/openscad/examples")) {
+ qexamplesdir = exdir.path();
+ } else
+ if (exdir.cd("../../examples")) {
+ qexamplesdir = exdir.path();
+ } else
+#endif
+ if (exdir.cd("examples")) {
+ qexamplesdir = exdir.path();
+ }
+ MainWindow::setExamplesDir(qexamplesdir);
+
+ parser_init(QApplication::instance()->applicationDirPath().toLocal8Bit().constData());
+
+#ifdef Q_WS_MAC
+ installAppleEventHandlers();
+#endif
+
+#if defined(OPENSCAD_DEPLOY) && defined(Q_WS_MAC)
+ AutoUpdater *updater = new SparkleAutoUpdater;
+ AutoUpdater::setUpdater(updater);
+ if (updater->automaticallyChecksForUpdates()) updater->checkForUpdates();
+#endif
+
+#if 0 /*** disabled by clifford wolf: adds rendering artefacts with OpenCSG ***/
+ // turn on anti-aliasing
+ QGLFormat f;
+ f.setSampleBuffers(true);
+ f.setSamples(4);
+ QGLFormat::setDefaultFormat(f);
+#endif
+ if (!inputFiles.size()) inputFiles.push_back("");
+#ifdef ENABLE_MDI
+ BOOST_FOREACH(const string &infile, inputFiles) {
+ new MainWindow(QString::fromLocal8Bit(boosty::stringy(original_path / infile).c_str()));
+ }
+ app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
+#else
+ MainWindow *m = new MainWindow(QString::fromLocal8Bit(boosty::stringy(original_path / inputFiles[0]).c_str()));
+ app.connect(m, SIGNAL(destroyed()), &app, SLOT(quit()));
+#endif
+ return app.exec();
+}
+#else // OPENSCAD_QTGUI
+bool QtUseGUI() { return false; }
+int gui(const vector<string> &inputFiles, const fs::path &original_path, int argc, char ** argv)
+{
+ fprintf(stderr,"Error: compiled without QT, but trying to run GUI\n");
+ return 1;
+}
+#endif // OPENSCAD_QTGUI
+
+int main(int argc, char **argv)
+{
+ int rc = 0;
+
+#ifdef ENABLE_CGAL
+ // Causes CGAL errors to abort directly instead of throwing exceptions
+ // (which we don't catch). This gives us stack traces without rerunning in gdb.
+ CGAL::set_error_behaviour(CGAL::ABORT);
+#endif
+ Builtins::instance()->initialize();
+
+ fs::path original_path = fs::current_path();
+
const char *filename = NULL;
const char *output_file = NULL;
const char *deps_output_file = NULL;
@@ -259,6 +584,13 @@ int main(int argc, char **argv)
if (vm.count("version")) version();
if (vm.count("info")) info();
+ Render::type renderer = Render::OPENCSG;
+ if (vm.count("render"))
+ renderer = Render::CGAL;
+ if (vm.count("preview"))
+ if (vm["preview"].as<string>() == "throwntogether")
+ renderer = Render::THROWNTOGETHER;
+
if (vm.count("o")) {
// FIXME: Allow for multiple output files?
if (output_file) help(argv[0]);
@@ -291,13 +623,12 @@ int main(int argc, char **argv)
commandline_commands += ";\n";
}
}
-
- if (vm.count("input-file")) {
- filename = vm["input-file"].as< vector<string> >().begin()->c_str();
+ vector<string> inputFiles;
+ if (vm.count("input-file")) {
+ inputFiles = vm["input-file"].as<vector<string> >();
}
-
#ifndef ENABLE_MDI
- if (vm.count("input-file") > 1) {
+ if (inputFiles.size() > 1) {
help(argv[0]);
}
#endif
@@ -306,297 +637,20 @@ int main(int argc, char **argv)
Camera camera = get_camera( vm );
- QDir exdir(QApplication::instance()->applicationDirPath());
-#ifdef Q_WS_MAC
- exdir.cd("../Resources"); // Examples can be bundled
- if (!exdir.exists("examples")) exdir.cd("../../..");
-#elif defined(Q_OS_UNIX)
- if (exdir.cd("../share/openscad/examples")) {
- examplesdir = exdir.path();
- } else
- if (exdir.cd("../../share/openscad/examples")) {
- examplesdir = exdir.path();
- } else
- if (exdir.cd("../../examples")) {
- examplesdir = exdir.path();
- } else
-#endif
- if (exdir.cd("examples")) {
- examplesdir = exdir.path();
- }
-
- parser_init(QApplication::instance()->applicationDirPath().toLocal8Bit().constData());
-
// Initialize global visitors
NodeCache nodecache;
NodeDumper dumper(nodecache);
- Tree tree;
-#ifdef ENABLE_CGAL
- CGALEvaluator cgalevaluator(tree);
- PolySetCGALEvaluator psevaluator(cgalevaluator);
-#endif
- if (output_file)
- {
- const char *stl_output_file = NULL;
- const char *off_output_file = NULL;
- const char *dxf_output_file = NULL;
- const char *csg_output_file = NULL;
- const char *png_output_file = NULL;
- const char *ast_output_file = NULL;
- const char *term_output_file = NULL;
- bool null_output = false;
-
- QString suffix = QFileInfo(output_file).suffix().toLower();
- if (suffix == "stl") stl_output_file = output_file;
- else if (suffix == "off") off_output_file = output_file;
- else if (suffix == "dxf") dxf_output_file = output_file;
- else if (suffix == "csg") csg_output_file = output_file;
- else if (suffix == "png") png_output_file = output_file;
- else if (suffix == "ast") ast_output_file = output_file;
- else if (suffix == "term") term_output_file = output_file;
- else if (strcmp(output_file, "null") == 0) null_output = true;
- else {
- fprintf(stderr, "Unknown suffix for output file %s\n", output_file);
- exit(1);
- }
-
- if (!filename) help(argv[0]);
-
- // Top context - this context only holds builtins
- ModuleContext top_ctx;
- top_ctx.registerBuiltin();
-#if 0 && DEBUG
- top_ctx.dump(NULL, NULL);
-#endif
-
- FileModule *root_module;
- ModuleInstantiation root_inst("group");
- AbstractNode *root_node;
- AbstractNode *absolute_root_node;
- CGAL_Nef_polyhedron root_N;
-
- handle_dep(filename);
-
- std::ifstream ifs(filename);
- if (!ifs.is_open()) {
- fprintf(stderr, "Can't open input file '%s'!\n", filename);
- exit(1);
- }
- std::string text((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
- text += "\n" + commandline_commands;
- fs::path abspath = boosty::absolute(filename);
- std::string parentpath = boosty::stringy(abspath.parent_path());
- root_module = parse(text.c_str(), parentpath.c_str(), false);
- if (!root_module) exit(1);
- root_module->handleDependencies();
-
- fs::path fpath = boosty::absolute(fs::path(filename));
- fs::path fparent = fpath.parent_path();
- fs::current_path(fparent);
- top_ctx.setDocumentPath(fparent.string());
-
- AbstractNode::resetIndexCounter();
- absolute_root_node = root_module->instantiate(&top_ctx, &root_inst, NULL);
-
- // Do we have an explicit root node (! modifier)?
- if (!(root_node = find_root_tag(absolute_root_node)))
- root_node = absolute_root_node;
-
- tree.setRoot(root_node);
-
- if (csg_output_file) {
- fs::current_path(original_path);
- std::ofstream fstream(csg_output_file);
- if (!fstream.is_open()) {
- PRINTB("Can't open file \"%s\" for export", csg_output_file);
- }
- else {
- fs::current_path(fparent); // Force exported filenames to be relative to document path
- fstream << tree.getString(*root_node) << "\n";
- fstream.close();
- }
- }
- else if (ast_output_file) {
- fs::current_path(original_path);
- std::ofstream fstream(ast_output_file);
- if (!fstream.is_open()) {
- PRINTB("Can't open file \"%s\" for export", ast_output_file);
- }
- else {
- fs::current_path(fparent); // Force exported filenames to be relative to document path
- fstream << root_module->dump("", "") << "\n";
- fstream.close();
- }
- }
- else if (term_output_file) {
- std::vector<shared_ptr<CSGTerm> > highlight_terms;
- std::vector<shared_ptr<CSGTerm> > background_terms;
-
- CSGTermEvaluator csgrenderer(tree, &psevaluator);
- shared_ptr<CSGTerm> root_raw_term = csgrenderer.evaluateCSGTerm(*root_node, highlight_terms, background_terms);
-
- fs::current_path(original_path);
- std::ofstream fstream(term_output_file);
- if (!fstream.is_open()) {
- PRINTB("Can't open file \"%s\" for export", term_output_file);
- }
- else {
- if (!root_raw_term)
- fstream << "No top-level CSG object\n";
- else {
- fstream << root_raw_term->dump() << "\n";
- }
- fstream.close();
- }
- }
- else {
-#ifdef ENABLE_CGAL
- if ((null_output || png_output_file) && !vm.count("render")) {
- // null output or OpenCSG png -> don't necessarily need CGALMesh evaluation
- } else {
- root_N = cgalevaluator.evaluateCGALMesh(*tree.root());
- }
-
- fs::current_path(original_path);
-
- if (deps_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 if ( png_output_file ) geom_out = std::string(png_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);
- }
- }
-
- if (stl_output_file) {
- if (root_N.dim != 3) {
- fprintf(stderr, "Current top level object is not a 3D object.\n");
- exit(1);
- }
- if (!root_N.p3->is_simple()) {
- fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
- exit(1);
- }
- std::ofstream fstream(stl_output_file);
- if (!fstream.is_open()) {
- PRINTB("Can't open file \"%s\" for export", stl_output_file);
- }
- else {
- export_stl(&root_N, fstream);
- fstream.close();
- }
- }
-
- if (off_output_file) {
- if (root_N.dim != 3) {
- fprintf(stderr, "Current top level object is not a 3D object.\n");
- exit(1);
- }
- if (!root_N.p3->is_simple()) {
- fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
- exit(1);
- }
- std::ofstream fstream(off_output_file);
- if (!fstream.is_open()) {
- PRINTB("Can't open file \"%s\" for export", off_output_file);
- }
- else {
- export_off(&root_N, fstream);
- fstream.close();
- }
- }
-
- if (dxf_output_file) {
- if (root_N.dim != 2) {
- fprintf(stderr, "Current top level object is not a 2D object.\n");
- exit(1);
- }
- std::ofstream fstream(dxf_output_file);
- if (!fstream.is_open()) {
- PRINTB("Can't open file \"%s\" for export", dxf_output_file);
- }
- else {
- export_dxf(&root_N, fstream);
- fstream.close();
- }
- }
-
- if (png_output_file) {
- std::ofstream fstream(png_output_file,std::ios::out|std::ios::binary);
- if (!fstream.is_open()) {
- PRINTB("Can't open file \"%s\" for export", png_output_file);
- }
- else {
- if (vm.count("render")) {
- export_png_with_cgal(&root_N, camera, fstream);
- } else if (vm.count("preview") && vm["preview"].as<string>() == "throwntogether" ) {
- export_png_with_throwntogether(tree, camera, fstream);
- } else {
- export_png_with_opencsg(tree, camera, fstream);
- }
- fstream.close();
- }
- }
-#else
- fprintf(stderr, "OpenSCAD has been compiled without CGAL support!\n");
- exit(1);
-#endif
- }
- delete root_node;
+ if (output_file) {
+ if (!inputFiles.size()) help(argv[0]);
+ rc = cmdline(deps_output_file, inputFiles[0], camera, output_file, original_path, renderer, argv);
}
- else if (useGUI)
- {
-#ifdef Q_WS_MAC
- installAppleEventHandlers();
-#endif
-
-#if defined(OPENSCAD_DEPLOY) && defined(Q_WS_MAC)
- AutoUpdater *updater = new SparkleAutoUpdater;
- AutoUpdater::setUpdater(updater);
- if (updater->automaticallyChecksForUpdates()) updater->checkForUpdates();
-#endif
-
- QString qfilename;
- if (filename) qfilename = QString::fromLocal8Bit(boosty::stringy(boosty::absolute(filename)).c_str());
-
-#if 0 /*** disabled by clifford wolf: adds rendering artefacts with OpenCSG ***/
- // turn on anti-aliasing
- QGLFormat f;
- f.setSampleBuffers(true);
- f.setSamples(4);
- QGLFormat::setDefaultFormat(f);
-#endif
-#ifdef ENABLE_MDI
- new MainWindow(qfilename);
- vector<string> inputFiles;
- if (vm.count("input-file")) {
- inputFiles = vm["input-file"].as<vector<string> >();
- for (vector<string>::const_iterator infile = inputFiles.begin()+1; infile != inputFiles.end(); infile++) {
- new MainWindow(QString::fromLocal8Bit(boosty::stringy(original_path / *infile).c_str()));
- }
- }
- app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
-#else
- MainWindow *m = new MainWindow(qfilename);
- app.connect(m, SIGNAL(destroyed()), &app, SLOT(quit()));
-#endif
- rc = app.exec();
+ else if (QtUseGUI()) {
+ rc = gui(inputFiles, original_path, argc, argv);
}
- else
- {
+ else {
fprintf(stderr, "Requested GUI mode but can't open display!\n");
- exit(1);
+ help(argv[0]);
}
Builtins::instance(true);
diff --git a/src/parsersettings.cc b/src/parsersettings.cc
index 5ad30e1..63a7713 100644
--- a/src/parsersettings.cc
+++ b/src/parsersettings.cc
@@ -130,5 +130,6 @@ void parser_init(const std::string &applicationpath)
if (is_directory(tmpdir = libdir / "libraries")) {
librarydir = boosty::stringy(tmpdir);
}
+
if (!librarydir.empty()) add_librarydir(librarydir);
}
diff --git a/src/svg.cc b/src/svg.cc
index a21e844..b3a7afa 100644
--- a/src/svg.cc
+++ b/src/svg.cc
@@ -32,16 +32,16 @@ std::string svg_styleblock(std::string strokewidth)
std::stringstream out;
// halfedge: f1/f0 = face mark, b1/b0 = body or hole, m1/m0 = halfedge mark
out << "\
- <style type='text/css'>\n\
- .halfedge_f0_b1_m0 { stroke: gold; stroke-width: __STROKEW__px } \n\
- .halfedge_f0_b1_m1 { stroke: gold; stroke-width: __STROKEW__px } \n\
- .halfedge_f0_b0_m0 { stroke: green; stroke-width: __STROKEW__px } \n\
- .halfedge_f0_b0_m1 { stroke: green; stroke-width: __STROKEW__px } \n\
- .halfedge_f1_b1_m0 { stroke: gold; stroke-width: __STROKEW__px } \n\
- .halfedge_f1_b1_m1 { stroke: gold; stroke-width: __STROKEW__px } \n\
- .halfedge_f1_b0_m0 { stroke: green; stroke-width: __STROKEW__px } \n\
- .halfedge_f1_b0_m1 { stroke: green; stroke-width: __STROKEW__px } \n\
- </style>";
+ <style type='text/css'>\n\
+ .halfedge_f0_b1_m0 { stroke: gold; stroke-width: __STROKEW__px } \n\
+ .halfedge_f0_b1_m1 { stroke: gold; stroke-width: __STROKEW__px } \n\
+ .halfedge_f0_b0_m0 { stroke: green; stroke-width: __STROKEW__px } \n\
+ .halfedge_f0_b0_m1 { stroke: green; stroke-width: __STROKEW__px } \n\
+ .halfedge_f1_b1_m0 { stroke: gold; stroke-width: __STROKEW__px } \n\
+ .halfedge_f1_b1_m1 { stroke: gold; stroke-width: __STROKEW__px } \n\
+ .halfedge_f1_b0_m0 { stroke: green; stroke-width: __STROKEW__px } \n\
+ .halfedge_f1_b0_m1 { stroke: green; stroke-width: __STROKEW__px } \n\
+ </style>";
std::string tmp = out.str();
boost::replace_all( tmp, "__STROKEW__", strokewidth );
return tmp;
@@ -119,14 +119,14 @@ std::string dump_cgal_nef_polyhedron2_face_svg(
style << "halfedge_f" << facemark << "_b" << body << "_m";
std::string styleclass = style.str();
- std::stringstream out;
+ std::stringstream out;
CGAL_For_all(c1, c2) {
if ( explorer.is_standard( explorer.target(c1) ) ) {
-CGAL_Nef_polyhedron2::Explorer::Point source = explorer.point( explorer.source( c1 ) );
+ CGAL_Nef_polyhedron2::Explorer::Point source = explorer.point( explorer.source( c1 ) );
CGAL_Point_2e target = explorer.point( explorer.target( c1 ) );
out << " <!-- Halfedge. Mark: " << c1->mark() << " -->\n";
std::string he_mark = boost::lexical_cast<std::string>(c1->mark());
- out << " <line"
+ out << " <line"
<< " x1='" << CGAL::to_double(source.x()) << "'"
<< " y1='" << CGAL::to_double(source.y()) << "'"
<< " x2='" << CGAL::to_double(target.x()) << "'"
@@ -141,10 +141,10 @@ CGAL_Nef_polyhedron2::Explorer::Point source = explorer.point( explorer.source(
std::string dump_svg( const CGAL_Nef_polyhedron2 &N )
{
- std::stringstream out;
- CGAL_Nef_polyhedron2::Explorer explorer = N.explorer();
+ 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;
+ CGAL_Nef_polyhedron2::Explorer::Face_const_iterator i;
std::string linewidth = "0.05";
@@ -152,23 +152,23 @@ std::string dump_svg( const CGAL_Nef_polyhedron2 &N )
out << svg_header() << "\n" << svg_styleblock( linewidth ) << "\n";
for ( i = explorer.faces_begin(); i!= explorer.faces_end(); ++i ) {
- out << " <!-- face begin. mark: " << i->mark() << " -->\n";
- out << " <!-- body begin -->\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, i->mark(), true );
- out << " <!-- body end -->\n";
+ out << " <!-- face begin. mark: " << i->mark() << " -->\n";
+ out << " <!-- body begin -->\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, i->mark(), true );
+ out << " <!-- body end -->\n";
- 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() );
- out << " <!-- hole end -->\n";
- }
- out << " <!-- face end -->\n";
- }
- out << "</svg>";
+ 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() );
+ out << " <!-- hole end -->\n";
+ }
+ out << " <!-- face end -->\n";
+ }
+ out << "</svg>";
std::string tmp = out.str();
boost::replace_all( tmp, "'", "\"" );
return tmp;
@@ -212,14 +212,14 @@ public:
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 << " <!-- " << CGAL::to_double(source.x()) << ","
- << CGAL::to_double(source.y()) << ","
- << CGAL::to_double(source.z()) << " -->\n";
+ out << " <!-- " << CGAL::to_double(source.x()) << ","
+ << CGAL::to_double(source.y()) << ","
+ << CGAL::to_double(source.z()) << " -->\n";
out << " <line "
- << "x1='" << CGAL::to_double(tp1.x()) << "' "
- << "y1='" << CGAL::to_double(tp1.y()) << "' "
- << "x2='" << CGAL::to_double(tp2.x()) << "' "
- << "y2='" << CGAL::to_double(tp2.y()) << "' "
+ << "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";
@@ -234,31 +234,31 @@ public:
std::string dump_svg( const CGAL_Nef_polyhedron3 &N )
{
- std::stringstream out;
+ std::stringstream out;
std::string linewidth = "0.05";
out << "<!--CGAL_Nef_polyhedron3 dump begin-->\n";
out << svg_header() << "\n" << svg_border() << "\n";
out << svg_styleblock( linewidth ) << "\n" << svg_axes() << "\n";
- CGAL_Nef_polyhedron3::Volume_const_iterator c;
- CGAL_forall_volumes(c,N) {
- out << " <!--Volume begin-->\n";
- out << " <!--Mark: " << (*c).mark() << "-->\n";
- CGAL_Nef_polyhedron3::Shell_entry_const_iterator it;
- CGAL_forall_shells_of(it,c) {
- out << " <!--Shell begin-->\n";
- NefPoly3_dumper_svg dumper_svg(N);
- N.visit_shell_objects(CGAL_Nef_polyhedron3::SFace_const_handle(it), dumper_svg );
+ CGAL_Nef_polyhedron3::Volume_const_iterator c;
+ CGAL_forall_volumes(c,N) {
+ out << " <!--Volume begin-->\n";
+ out << " <!--Mark: " << (*c).mark() << "-->\n";
+ CGAL_Nef_polyhedron3::Shell_entry_const_iterator it;
+ CGAL_forall_shells_of(it,c) {
+ out << " <!--Shell begin-->\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 << " <!--Shell end-->\n";
- }
- out << " <!--Volume end-->\n";
- }
- out << "<!--CGAL_Nef_polyhedron3 dump end-->\n";
+ out << " <!--Shell end-->\n";
+ }
+ out << " <!--Volume end-->\n";
+ }
+ out << "<!--CGAL_Nef_polyhedron3 dump end-->\n";
out << "</svg>";
std::string tmp = out.str();
boost::replace_all( tmp, "'", "\"" );
- return tmp;
+ return tmp;
}
} // namespace
diff --git a/src/value.cc b/src/value.cc
index a281409..ac33a3b 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -117,11 +117,6 @@ Value::Value(const RangeType &v) : value(v)
// std::cout << "creating range\n";
}
-Value::Value(double begin, double step, double end) : value(RangeType(begin, step, end))
-{
- // std::cout << "creating range from numbers\n";
-}
-
Value::ValueType Value::type() const
{
return static_cast<ValueType>(this->value.which());
@@ -590,7 +585,7 @@ public:
Value operator()(const std::string &str, const double &idx) const {
int i = int(idx);
Value v;
- if (i >= 0 && i < str.size()) {
+ if ((i >= 0) && (i < (int)str.size())) {
v = Value(str[int(idx)]);
// std::cout << "bracket_visitor: " << v << "\n";
}
@@ -599,7 +594,7 @@ public:
Value operator()(const Value::VectorType &vec, const double &idx) const {
int i = int(idx);
- if (i >= 0 && i < vec.size()) return vec[int(idx)];
+ if ((i >= 0) && (i < (int)vec.size())) return vec[int(idx)];
return Value::undefined;
}
diff --git a/src/value.h b/src/value.h
index 24e1b45..388b721 100644
--- a/src/value.h
+++ b/src/value.h
@@ -3,6 +3,8 @@
#include <vector>
#include <string>
+#include <algorithm>
+#include <limits>
// Workaround for https://bugreports.qt-project.org/browse/QTBUG-22829
#ifndef Q_MOC_RUN
@@ -39,6 +41,20 @@ public:
this->end == other.end;
}
+ /// inverse begin/end if begin is upper than end
+ void normalize() {
+ if ((step>0) && (end < begin)) {
+ std::swap(begin,end);
+ }
+ }
+ /// return number of steps, max int value if step is null
+ int nbsteps() const {
+ if (step<=0) {
+ return std::numeric_limits<int>::max();
+ }
+ return (int)((begin-end)/step);
+ }
+
double begin;
double step;
double end;
@@ -65,7 +81,6 @@ public:
Value(const char v);
Value(const VectorType &v);
Value(const RangeType &v);
- Value(double begin, double step, double end);
~Value() {}
ValueType type() const;
diff --git a/src/version_check.h b/src/version_check.h
index db17962..6e07208 100644
--- a/src/version_check.h
+++ b/src/version_check.h
@@ -87,11 +87,12 @@ a time, to avoid confusion.
#else
#endif // ENABLE_OPENCSG
+#ifndef OPENSCAD_TESTING
#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
#endif // QT
-
+#endif
#ifdef ENABLE_OPENCSG
#endif // OpenCSG
contact: Jan Huwald // Impressum