diff options
author | Marius Kintel <marius@kintel.net> | 2013-10-04 07:20:03 (GMT) |
---|---|---|
committer | Marius Kintel <marius@kintel.net> | 2013-10-04 07:20:03 (GMT) |
commit | 0404a921af67a05f236f9f846243d4ffb1f74474 (patch) | |
tree | 132607d2cbf85b9c42a35993d6d44d2c443f8bcc /src | |
parent | 94070f7b51e54f64d977be90339c77521705b444 (diff) | |
parent | 5ed3e28b7a2e3eccb084cd582e4148a7aebb3b86 (diff) |
Merge pull request #499 from openscad/issue480
Issue480
Diffstat (limited to 'src')
-rw-r--r-- | src/EventFilter.h | 4 | ||||
-rw-r--r-- | src/MainWindow.h | 4 | ||||
-rw-r--r-- | src/PlatformUtils.cc | 26 | ||||
-rw-r--r-- | src/mainwin.cc | 11 | ||||
-rw-r--r-- | src/openscad.cc | 680 | ||||
-rw-r--r-- | src/parsersettings.cc | 1 | ||||
-rw-r--r-- | src/svg.cc | 110 | ||||
-rw-r--r-- | src/version_check.h | 3 |
8 files changed, 457 insertions, 382 deletions
diff --git a/src/EventFilter.h b/src/EventFilter.h index c3942b5..c883bfd 100644 --- a/src/EventFilter.h +++ b/src/EventFilter.h @@ -1,6 +1,8 @@ #ifndef FILTER_H_ #define FILTER_H_ +#ifdef OPENSCAD_QTGUI + #include <QObject> #include <QFileOpenEvent> #include "MainWindow.h" @@ -25,4 +27,6 @@ protected: } }; +#endif // OPENSCAD_QTGUI + #endif 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/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 ccaeb91..a8bb24a 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -25,7 +25,6 @@ */ #include "openscad.h" -#include "MainWindow.h" #include "node.h" #include "module.h" #include "modcontext.h" @@ -37,6 +36,7 @@ #include "parsersettings.h" #include "rendersettings.h" #include "PlatformUtils.h" +#include "nodedumper.h" #include <string> #include <vector> @@ -52,12 +52,9 @@ #include "CSGTermEvaluator.h" #include "CsgInfo.h" -#include <QApplication> -#include <QString> -#include <QDir> #include <sstream> -#ifdef Q_WS_MAC +#ifdef __APPLE__ #include "EventFilter.h" #include "AppleEvents.h" #ifdef OPENSCAD_DEPLOY @@ -78,6 +75,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) { @@ -118,15 +137,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; @@ -181,17 +191,254 @@ 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 - Builtins::instance()->initialize(); + } + delete root_node; + return 0; +} + +#ifdef OPENSCAD_TESTING +#undef OPENSCAD_QTGUI +#else +#define OPENSCAD_QTGUI 1 +#endif + +#ifdef OPENSCAD_QTGUI +#include "MainWindow.h" +#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 @@ -202,18 +449,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; @@ -258,6 +582,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]); @@ -290,13 +621,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 @@ -305,294 +635,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()); - - 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()); - } + // Initialize global visitors + NodeCache nodecache; + NodeDumper dumper(nodecache); - 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); } @@ -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/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 |