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  | 
