diff options
| author | Marius Kintel <marius@kintel.net> | 2011-12-26 15:38:11 (GMT) | 
|---|---|---|
| committer | Marius Kintel <marius@kintel.net> | 2011-12-26 15:38:11 (GMT) | 
| commit | 0be212e75d73644b1cff8291a4b6a6fe0098b942 (patch) | |
| tree | 05bfeea810ad680d3cfbfa385fe694cb7dc0840d | |
| parent | 04f8d5863b5797f25c226b970dba8e87abb836c8 (diff) | |
| parent | 4ff2d1af446c1f276c644b12e6ec4cc6db0b6d65 (diff) | |
Merge branch 'master' into threading
| -rw-r--r-- | doc/OpenSCAD-polygons.graffle | bin | 5047 -> 4215 bytes | |||
| -rw-r--r-- | doc/OpenSCAD-polygons.pdf | bin | 114655 -> 115182 bytes | |||
| -rw-r--r-- | openscad.pro | 46 | ||||
| -rw-r--r-- | src/CGALEvaluator.cc | 4 | ||||
| -rw-r--r-- | src/CSGTermEvaluator.cc | 8 | ||||
| -rw-r--r-- | src/PolySetCGALEvaluator.cc | 6 | ||||
| -rw-r--r-- | src/PolySetEvaluator.cc | 4 | ||||
| -rw-r--r-- | src/context.cc | 15 | ||||
| -rw-r--r-- | src/dxfdata.cc | 14 | ||||
| -rw-r--r-- | src/export.cc | 3 | ||||
| -rw-r--r-- | src/mainwin.cc | 4 | ||||
| -rw-r--r-- | src/module.cc | 23 | ||||
| -rw-r--r-- | src/module.h | 62 | ||||
| -rw-r--r-- | src/node.cc | 2 | ||||
| -rw-r--r-- | src/node.h | 4 | ||||
| -rw-r--r-- | src/parser.y | 19 | ||||
| -rw-r--r-- | src/polyset.cc | 13 | ||||
| -rw-r--r-- | testdata/scad/misc/normal-nan.scad | 16 | ||||
| -rw-r--r-- | tests/CMakeLists.txt | 12 | ||||
| -rw-r--r-- | tests/cgalstlsanitytest.cc | 163 | ||||
| -rw-r--r-- | tests/regression/cgalstlsanitytest/normal-nan-expected.txt | 0 | 
21 files changed, 326 insertions, 92 deletions
| diff --git a/doc/OpenSCAD-polygons.graffle b/doc/OpenSCAD-polygons.graffleBinary files differ index 40df7ab..758d575 100644 --- a/doc/OpenSCAD-polygons.graffle +++ b/doc/OpenSCAD-polygons.graffle diff --git a/doc/OpenSCAD-polygons.pdf b/doc/OpenSCAD-polygons.pdfBinary files differ index ac18baf..97dfd2e 100644 --- a/doc/OpenSCAD-polygons.pdf +++ b/doc/OpenSCAD-polygons.pdf diff --git a/openscad.pro b/openscad.pro index 594e890..710a3bd 100644 --- a/openscad.pro +++ b/openscad.pro @@ -187,20 +187,14 @@ HEADERS += src/renderer.h \             src/system-gl.h \             src/stl-utils.h -SOURCES += src/openscad.cc \ -           src/mainwin.cc \ +SOURCES += src/mathc99.cc \ +	   src/linalg.cc \             src/handle_dep.cc \ -           src/renderer.cc \ -           src/rendersettings.cc \ -           src/ThrownTogetherRenderer.cc \ -           src/glview.cc \ -           src/export.cc \             src/value.cc \             src/expr.cc \             src/func.cc \             src/module.cc \             src/node.cc \ -           src/builtin.cc \             src/context.cc \             src/csgterm.cc \             src/polyset.cc \ @@ -213,28 +207,38 @@ SOURCES += src/openscad.cc \             src/surface.cc \             src/control.cc \             src/render.cc \ -           src/import.cc \             src/dxfdata.cc \ -           src/dxftess.cc \ -           src/dxftess-glu.cc \ -           src/dxftess-cgal.cc \             src/dxfdim.cc \             src/linearextrude.cc \             src/rotateextrude.cc \ -           src/highlighter.cc \             src/printutils.cc \ +           src/progress.cc \ +           \ +           src/nodedumper.cc \ +           src/traverser.cc \ +           src/PolySetEvaluator.cc \ +           src/PolySetCache.cc \ +           src/Tree.cc \ +           \ +           src/rendersettings.cc \ +           src/highlighter.cc \             src/Preferences.cc \             src/OpenCSGWarningDialog.cc \ -           src/progress.cc \             src/editor.cc \ -           src/traverser.cc \ -           src/nodedumper.cc \ +           src/glview.cc \ +           \ +           src/builtin.cc \ +           src/export.cc \ +           src/import.cc \ +           src/renderer.cc \ +           src/ThrownTogetherRenderer.cc \ +           src/dxftess.cc \ +           src/dxftess-glu.cc \ +           src/dxftess-cgal.cc \             src/CSGTermEvaluator.cc \ -           src/Tree.cc \ -	   src/mathc99.cc \ -	   src/linalg.cc \ -           src/PolySetCache.cc \ -           src/PolySetEvaluator.cc +           \ +           src/openscad.cc \ +           src/mainwin.cc  opencsg {    HEADERS += src/OpenCSGRenderer.h diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc index 684ab42..a6b2f06 100644 --- a/src/CGALEvaluator.cc +++ b/src/CGALEvaluator.cc @@ -99,7 +99,7 @@ CGAL_Nef_polyhedron CGALEvaluator::applyToChildren(const AbstractNode &node, CGA  		const AbstractNode *chnode = item.first;  		const CGAL_Nef_polyhedron &chN = item.second;  		// FIXME: Don't use deep access to modinst members -		if (chnode->modinst->tag_background) continue; +		if (chnode->modinst->isBackground()) continue;      // NB! We insert into the cache here to ensure that all children of      // a node is a valid object. If we inserted as we created them, the  @@ -127,7 +127,7 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)  		const AbstractNode *chnode = item.first;  		const CGAL_Nef_polyhedron &chN = item.second;  		// FIXME: Don't use deep access to modinst members -		if (chnode->modinst->tag_background) continue; +		if (chnode->modinst->isBackground()) continue;  		if (dim == 0) {  			dim = chN.dim;  		} diff --git a/src/CSGTermEvaluator.cc b/src/CSGTermEvaluator.cc index fc76d56..65209dd 100644 --- a/src/CSGTermEvaluator.cc +++ b/src/CSGTermEvaluator.cc @@ -56,10 +56,10 @@ void CSGTermEvaluator::applyToChildren(const AbstractNode &node, CSGTermEvaluato  			}  		}  	} -	if (t1 && node.modinst->tag_highlight) { +	if (t1 && node.modinst->isHighlight()) {  		this->highlights.push_back(t1);  	} -	if (t1 && node.modinst->tag_background) { +	if (t1 && node.modinst->isBackground()) {  		this->background.push_back(t1);  		t1.reset(); // don't propagate background tagged nodes  	} @@ -94,10 +94,10 @@ static shared_ptr<CSGTerm> evaluate_csg_term_from_ps(const State &state,  	std::stringstream stream;  	stream << node.name() << node.index();  	shared_ptr<CSGTerm> t(new CSGTerm(ps, state.matrix(), state.color(), stream.str())); -	if (modinst->tag_highlight) { +	if (modinst->isHighlight()) {  		highlights.push_back(t);  	} -	if (modinst->tag_background) { +	if (modinst->isBackground()) {  		background.push_back(t);  		t.reset();  	} diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc index 3285b46..3cd6005 100644 --- a/src/PolySetCGALEvaluator.cc +++ b/src/PolySetCGALEvaluator.cc @@ -26,7 +26,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)  	// Before projecting, union all children  	CGAL_Nef_polyhedron sum;  	BOOST_FOREACH (AbstractNode * v, node.getChildren()) { -		if (v->modinst->tag_background) continue; +		if (v->modinst->isBackground()) continue;  		CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);  		if (N.dim == 3) {  			if (sum.empty()) sum = N.copy(); @@ -259,7 +259,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const LinearExtrudeNode &node)  		// to a single DxfData, then tesselate this into a PolySet  		CGAL_Nef_polyhedron sum;  		BOOST_FOREACH (AbstractNode * v, node.getChildren()) { -			if (v->modinst->tag_background) continue; +			if (v->modinst->isBackground()) continue;  			CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);  			if (N.dim != 2) {  				PRINT("ERROR: linear_extrude() is not defined for 3D child objects!"); @@ -357,7 +357,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const RotateExtrudeNode &node)  		// to a single DxfData, then tesselate this into a PolySet  		CGAL_Nef_polyhedron sum;  		BOOST_FOREACH (AbstractNode * v, node.getChildren()) { -			if (v->modinst->tag_background) continue; +			if (v->modinst->isBackground()) continue;  			CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);  			if (N.dim != 2) {  				PRINT("ERROR: rotate_extrude() is not defined for 3D child objects!"); diff --git a/src/PolySetEvaluator.cc b/src/PolySetEvaluator.cc index b5075ba..fc68fb2 100644 --- a/src/PolySetEvaluator.cc +++ b/src/PolySetEvaluator.cc @@ -7,8 +7,8 @@  /*!  	The task of PolySetEvaluator is to create, keep track of and cache PolySet instances. -	All instances of PolySet which are not strictly temporary should be requested through this -	class. +	All instances of PolySet which are not strictly temporary should be +	requested through this class.  */  /*! diff --git a/src/context.cc b/src/context.cc index 6d0cb3a..f636b05 100644 --- a/src/context.cc +++ b/src/context.cc @@ -45,6 +45,7 @@ Context::Context(const Context *parent, const Module *library)  	ctx_stack.push_back(this);  	if (parent) document_path = parent->document_path;  	if (library) { +		// FIXME: Don't access module members directly  		this->functions_p = &library->functions;  		this->modules_p = &library->modules;  		this->usedlibs_p = &library->usedlibs; @@ -148,24 +149,24 @@ Value Context::evaluate_function(const std::string &name,  AbstractNode *Context::evaluate_module(const ModuleInstantiation &inst) const  { -	if (this->modules_p && this->modules_p->find(inst.modname) != this->modules_p->end()) { -		AbstractModule *m = this->modules_p->find(inst.modname)->second; -		std::string replacement = Builtins::instance()->isDeprecated(inst.modname); +	if (this->modules_p && this->modules_p->find(inst.name()) != this->modules_p->end()) { +		AbstractModule *m = this->modules_p->find(inst.name())->second; +		std::string replacement = Builtins::instance()->isDeprecated(inst.name());  		if (!replacement.empty()) { -			PRINTF("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", inst.modname.c_str(), replacement.c_str()); +			PRINTF("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", inst.name().c_str(), replacement.c_str());  		}  		return m->evaluate(this, &inst);  	}  	if (this->usedlibs_p) {  		BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { -			if (m.second->modules.find(inst.modname) != m.second->modules.end()) { +			if (m.second->modules.find(inst.name()) != m.second->modules.end()) {  				Context ctx(this->parent, m.second); -				return m.second->modules[inst.modname]->evaluate(&ctx, &inst); +				return m.second->modules[inst.name()]->evaluate(&ctx, &inst);  			}  		}  	}  	if (this->parent) return this->parent->evaluate_module(inst); -	PRINTF("WARNING: Ignoring unknown module '%s'.", inst.modname.c_str()); +	PRINTF("WARNING: Ignoring unknown module '%s'.", inst.name().c_str());  	return NULL;  } diff --git a/src/dxfdata.cc b/src/dxfdata.cc index cf9248f..2bc21e2 100644 --- a/src/dxfdata.cc +++ b/src/dxfdata.cc @@ -42,6 +42,20 @@  #include <QDir>  #include "value.h" +/*! \class DxfData + +	The DxfData class fulfils multiple tasks, partially for historical reasons. +	FIXME: It's a bit messy and is a prime target for refactoring. + +	1) Read DXF file from disk +	2) Store contents of DXF files as points, paths and dims +	3) Store 2D polygons, both from the polygon() module and from 2D CSG operations. +	   Used for tesselation into triangles +  4) Store 2D polygons before exporting to DXF +	 + + */ +  struct Line {  	int idx[2]; // indices into DxfData::points  	bool disabled; diff --git a/src/export.cc b/src/export.cc index 99bce98..5ce2d15 100644 --- a/src/export.cc +++ b/src/export.cc @@ -102,6 +102,9 @@ void export_stl(CGAL_Nef_polyhedron *root_N, std::ostream &output, QProgressDial  				double ny = dn[2]*dn[3] - dn[0]*dn[5];  				double nz = dn[0]*dn[4] - dn[1]*dn[3];  				double nlength = sqrt(nx*nx + ny*ny + nz*nz); +				// Avoid generating normals for polygons with zero area +				double eps = 0.000001; +				if (nlength < eps) nlength = 1.0;  				output << "  facet normal "  							 << nx / nlength << " "  							 << ny / nlength << " " diff --git a/src/mainwin.cc b/src/mainwin.cc index 5c81554..82a28c3 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -576,7 +576,7 @@ void MainWindow::load()  AbstractNode *MainWindow::find_root_tag(AbstractNode *n)  {  	BOOST_FOREACH (AbstractNode *v, n->children) { -		if (v->modinst->tag_root) return v; +		if (v->modinst->isRoot()) return v;  		if (AbstractNode *vroot = find_root_tag(v)) return vroot;  	}  	return NULL; @@ -1453,7 +1453,7 @@ void MainWindow::actionFlushCaches()  #endif  	dxf_dim_cache.clear();  	dxf_cross_cache.clear(); -	Module::libs_cache.clear(); +	Module::clear_library_cache();  }  void MainWindow::viewModeActionsUncheck() diff --git a/src/module.cc b/src/module.cc index 269e128..ba0112d 100644 --- a/src/module.cc +++ b/src/module.cc @@ -68,7 +68,6 @@ std::string ModuleInstantiation::dump(const std::string &indent) const  {  	std::stringstream dump;  	dump << indent; -	if (!label.empty()) dump << label <<": ";  	dump << modname + "(";  	for (size_t i=0; i < argnames.size(); i++) {  		if (i > 0) dump << ", "; @@ -96,10 +95,11 @@ AbstractNode *ModuleInstantiation::evaluate(const Context *ctx) const  	if (this->ctx) {  		PRINTF("WARNING: Ignoring recursive module instantiation of '%s'.", modname.c_str());  	} else { +		// FIXME: Casting away const..  		ModuleInstantiation *that = (ModuleInstantiation*)this;  		that->argvalues.clear(); -		BOOST_FOREACH (Expression *v, that->argexpr) { -			that->argvalues.push_back(v->evaluate(ctx)); +		BOOST_FOREACH (Expression *expr, that->argexpr) { +			that->argvalues.push_back(expr->evaluate(ctx));  		}  		that->ctx = ctx;  		node = ctx->evaluate_module(*this); @@ -113,9 +113,9 @@ std::vector<AbstractNode*> ModuleInstantiation::evaluateChildren(const Context *  {  	if (!ctx) ctx = this->ctx;  	std::vector<AbstractNode*> childnodes; -	BOOST_FOREACH (ModuleInstantiation *v, this->children) { -		AbstractNode *n = v->evaluate(ctx); -		if (n != NULL) childnodes.push_back(n); +	BOOST_FOREACH (ModuleInstantiation *modinst, this->children) { +		AbstractNode *node = modinst->evaluate(ctx); +		if (node) childnodes.push_back(node);  	}  	return childnodes;  } @@ -124,9 +124,9 @@ std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(const  {  	if (!ctx) ctx = this->ctx;  	std::vector<AbstractNode*> childnodes; -	BOOST_FOREACH (ModuleInstantiation *v, this->else_children) { -		AbstractNode *n = v->evaluate(this->ctx); -		if (n != NULL) childnodes.push_back(n); +	BOOST_FOREACH (ModuleInstantiation *modinst, this->else_children) { +		AbstractNode *node = modinst->evaluate(ctx); +		if (node != NULL) childnodes.push_back(node);  	}  	return childnodes;  } @@ -200,3 +200,8 @@ std::string Module::dump(const std::string &indent, const std::string &name) con  	}  	return dump.str();  } + +void Module::clear_library_cache() +{ +	Module::libs_cache.clear(); +} diff --git a/src/module.h b/src/module.h index c28ab34..557b7c5 100644 --- a/src/module.h +++ b/src/module.h @@ -9,28 +9,38 @@  class ModuleInstantiation  {  public: -	std::string label; -	std::string modname; +	ModuleInstantiation(const std::string &name = "")  +	: ctx(NULL),  +		tag_root(false), tag_highlight(false), tag_background(false), modname(name) { } +	virtual ~ModuleInstantiation(); + +	std::string dump(const std::string &indent) const; +	class AbstractNode *evaluate(const class Context *ctx) const; +	std::vector<AbstractNode*> evaluateChildren(const Context *ctx = NULL) const; + +	const std::string &name() const { return this->modname; } +	bool isBackground() const { return this->tag_background; } +	bool isHighlight() const { return this->tag_highlight; } +	bool isRoot() const { return this->tag_root; } +  	std::vector<std::string> argnames; -	std::vector<class Expression*> argexpr;  	std::vector<Value> argvalues; +	std::vector<class Expression*> argexpr;  	std::vector<ModuleInstantiation*> children; +	const Context *ctx;  	bool tag_root;  	bool tag_highlight;  	bool tag_background; -	const class Context *ctx; - -	ModuleInstantiation() : tag_root(false), tag_highlight(false), tag_background(false), ctx(NULL) { } -	virtual ~ModuleInstantiation(); +protected: +	std::string modname; -	std::string dump(const std::string &indent) const; -	class AbstractNode *evaluate(const Context *ctx) const; -	std::vector<AbstractNode*> evaluateChildren(const Context *ctx = NULL) const; +	friend class Module;  };  class IfElseModuleInstantiation : public ModuleInstantiation {  public: +	IfElseModuleInstantiation() : ModuleInstantiation("if") { }  	virtual ~IfElseModuleInstantiation();  	std::vector<AbstractNode*> evaluateElseChildren(const Context *ctx = NULL) const; @@ -48,18 +58,18 @@ public:  class Module : public AbstractModule  {  public: -	typedef boost::unordered_map<std::string, class Module*> ModuleContainer; -	ModuleContainer usedlibs; +	Module() { } +	virtual ~Module(); +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual std::string dump(const std::string &indent, const std::string &name) const; + +	void addChild(ModuleInstantiation *ch) { this->children.push_back(ch); } -	struct libs_cache_ent { -		Module *mod; -		std::string cache_id, msg; -	}; -	static boost::unordered_map<std::string, libs_cache_ent> libs_cache;  	static Module *compile_library(std::string filename); +	static void clear_library_cache(); -	std::vector<std::string> argnames; -	std::vector<Expression*> argexpr; +	typedef boost::unordered_map<std::string, class Module*> ModuleContainer; +	ModuleContainer usedlibs;  	std::vector<std::string> assignments_var;  	std::vector<Expression*> assignments_expr; @@ -71,11 +81,17 @@ public:  	std::vector<ModuleInstantiation*> children; -	Module() { } -	virtual ~Module(); +	std::vector<std::string> argnames; +	std::vector<Expression*> argexpr; -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; -	virtual std::string dump(const std::string &indent, const std::string &name) const; +protected: + +private: +	struct libs_cache_ent { +		Module *mod; +		std::string cache_id, msg; +	}; +	static boost::unordered_map<std::string, libs_cache_ent> libs_cache;  };  #endif diff --git a/src/node.cc b/src/node.cc index eccb9a6..e61174f 100644 --- a/src/node.cc +++ b/src/node.cc @@ -97,7 +97,7 @@ void AbstractNode::progress_report() const  std::ostream &operator<<(std::ostream &stream, const AbstractNode &node)  {  	// FIXME: Don't use deep access to modinst members -	if (node.modinst->tag_background) stream << "%"; +	if (node.modinst->isBackground()) stream << "%";  	stream << node.toString();  	return stream;  } @@ -35,7 +35,9 @@ public:  	    overloaded to provide specialization for e.g. CSG nodes, primitive nodes etc.  	    Used for human-readable output. */  	virtual std::string name() const; -  /*! Should return a PolySet of the given geometry. Returns NULL if smth. goes wrong */ +  /*! Should return a PolySet of the given geometry. Returns NULL if smth. goes wrong. +	 This is only called by PolySetEvaluator, to make sure polysets are inserted into  +	 the cache*/  	virtual class PolySet *evaluate_polyset(class PolySetEvaluator *) const { return NULL; }  	const std::vector<AbstractNode*> &getChildren() const {  diff --git a/src/parser.y b/src/parser.y index d703a81..b0df50d 100644 --- a/src/parser.y +++ b/src/parser.y @@ -146,7 +146,7 @@ statement:  	'{' inner_input '}' |  	module_instantiation {  		if ($1) { -			module->children.push_back($1); +			module->addChild($1);  		} else {  			delete $1;  		} @@ -193,10 +193,8 @@ statement:  children_instantiation:  	module_instantiation {  		$$ = new ModuleInstantiation(); -		if ($1) { +		if ($1) {   			$$->children.push_back($1); -		} else { -			delete $1;  		}  	} |  	'{' module_instantiation_list '}' { @@ -206,7 +204,6 @@ children_instantiation:  if_statement:  	TOK_IF '(' expr ')' children_instantiation {  		$$ = new IfElseModuleInstantiation(); -		$$->modname = "if";  		$$->argnames.push_back("");  		$$->argexpr.push_back($3); @@ -262,8 +259,7 @@ module_instantiation_list:  	module_instantiation_list module_instantiation {  		$$ = $1;  		if ($$) { -			if ($2) -				$$->children.push_back($2); +			if ($2) $$->children.push_back($2);  		} else {  			delete $2;  		} @@ -271,19 +267,12 @@ module_instantiation_list:  single_module_instantiation:  	TOK_ID '(' arguments_call ')' { -		$$ = new ModuleInstantiation(); -		$$->modname = $1; +		$$ = new ModuleInstantiation($1);  		$$->argnames = $3->argnames;  		$$->argexpr = $3->argexpr;  		free($1);  		delete $3;  	} | -	TOK_ID ':' single_module_instantiation { -		$$ = $3; -		if ($$) -			$$->label = $1; -		free($1); -	} |  	'!' single_module_instantiation {  		$$ = $2;  		if ($$) diff --git a/src/polyset.cc b/src/polyset.cc index 481cbec..7e40eac 100644 --- a/src/polyset.cc +++ b/src/polyset.cc @@ -25,12 +25,21 @@   */  #include "polyset.h" -// FIXME: Reenable/rewrite - don't be dependant on GUI -// #include "Preferences.h"  #include "linalg.h"  #include <Eigen/LU>  #include <QColor> +/*! /class PolySet + +	The PolySet class fulfils multiple tasks, partially for historical reasons. +	FIXME: It's a bit messy and is a prime target for refactoring. + +	1) Store 2D and 3D polygon meshes from all origins +	2) Store 2D outlines, used for rendering edges +	3) Rendering of polygons and edges + + */ +  PolySet::PolySet() : grid(GRID_FINE), is2d(false), convexity(1)  {  } diff --git a/testdata/scad/misc/normal-nan.scad b/testdata/scad/misc/normal-nan.scad new file mode 100644 index 0000000..1c3f6ce --- /dev/null +++ b/testdata/scad/misc/normal-nan.scad @@ -0,0 +1,16 @@ +/* +  When exporting this to STL, null polygons appear, causing +  problems normalizing normal vectors (nan output in STL files) +*/ + +$fs=0.2; + +difference() {   +  cube(8); +  +  translate([0,20,4]) rotate([90,0,0]) union() { +    translate([0,-3,14.5]) cube([5.4,6,2.4],center=true); +    translate([0,0,13.3]) rotate([0,0,30]) cylinder(r=3.115,h=2.4,$fn=6); +  } +} + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a8ab9b9..b374188 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -361,6 +361,13 @@ set_target_properties(cgaltest PROPERTIES COMPILE_FLAGS "-DENABLE_CGAL ${CGAL_CX  target_link_libraries(cgaltest tests-cgal ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${QT_LIBRARIES} ${OPENGL_LIBRARY} ${Boost_LIBRARIES})  # +# cgalstlsanitytest +# +add_executable(cgalstlsanitytest cgalstlsanitytest.cc) +set_target_properties(cgalstlsanitytest PROPERTIES COMPILE_FLAGS "-DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}") +target_link_libraries(cgalstlsanitytest tests-cgal ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${QT_LIBRARIES} ${OPENGL_LIBRARY} ${Boost_LIBRARIES}) + +#  # cgalpngtest  #  add_executable(cgalpngtest cgalpngtest.cc bboxhelp.cc ../src/CGALRenderer.cc ../src/renderer.cc ../src/rendersettings.cc) @@ -535,6 +542,8 @@ list(APPEND OPENCSGTEST_FILES ${CGALPNGTEST_FILES})  list(APPEND OPENCSGTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/bbox-transform-bug.scad)  list(APPEND THROWNTOGETHERTEST_FILES ${OPENCSGTEST_FILES}) +list(APPEND CGALSTLSANITYTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/normal-nan.scad) +  # Disable tests which are known to cause floating point comparison issues  # Once we're capable of comparing these across platforms, we can put these back in  disable_tests(dumptest_transform-tests @@ -598,6 +607,9 @@ add_cmdline_test(csgtermtest txt ${MINIMAL_FILES})  add_cmdline_test(cgalpngtest png ${CGALPNGTEST_FILES})  add_cmdline_test(opencsgtest png ${OPENCSGTEST_FILES})  add_cmdline_test(throwntogethertest png ${THROWNTOGETHERTEST_FILES}) +# FIXME: We don't actually need to compare the output of cgalstlsanitytest +# with anything. It's self-contained and returns != 0 on error +add_cmdline_test(cgalstlsanitytest txt ${CGALSTLSANITYTEST_FILES})  message("Available test configurations: ${TEST_CONFIGS}")  #foreach(CONF ${TEST_CONFIGS}) diff --git a/tests/cgalstlsanitytest.cc b/tests/cgalstlsanitytest.cc new file mode 100644 index 0000000..a078dff --- /dev/null +++ b/tests/cgalstlsanitytest.cc @@ -0,0 +1,163 @@ +/* + *  OpenSCAD (www.openscad.org) + *  Copyright (C) 2009-2011 Clifford Wolf <clifford@clifford.at> and + *                          Marius Kintel <marius@kintel.net> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  As a special exception, you have permission to link this program + *  with the CGAL library and distribute executables, as long as you + *  follow the requirements of the GNU GPL in regard to all of the + *  software in the executable aside from CGAL. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + */ + +#include "tests-common.h" +#include "openscad.h" +#include "node.h" +#include "module.h" +#include "context.h" +#include "value.h" +#include "export.h" +#include "builtin.h" +#include "Tree.h" +#include "CGAL_Nef_polyhedron.h" +#include "CGALEvaluator.h" +#include "PolySetCGALEvaluator.h" + +#include <QApplication> +#include <QFile> +#include <QDir> +#include <QSet> +#include <QTextStream> +#ifndef _MSC_VER +#include <getopt.h> +#endif +#include <iostream> +#include <assert.h> +#include <sstream> + +std::string commandline_commands; +QString currentdir; +QString examplesdir; +QString librarydir; + +using std::string; + +void cgalTree(Tree &tree) +{ +	assert(tree.root()); + +	CGALEvaluator evaluator(tree); +	Traverser evaluate(evaluator, *tree.root(), Traverser::PRE_AND_POSTFIX); +	evaluate.execute(); +} + +AbstractNode *find_root_tag(AbstractNode *n) +{ +	foreach(AbstractNode *v, n->children) { +		if (v->modinst->tag_root) return v; +		if (AbstractNode *vroot = find_root_tag(v)) return vroot; +	} +	return NULL; +} + +int main(int argc, char **argv) +{ +	int retval = 0; + +	if (argc != 3) { +		fprintf(stderr, "Usage: %s <file.scad> <output.txt>\n", argv[0]); +		exit(1); +	} + +	const char *filename = argv[1]; +	const char *outfilename = argv[2]; + +	Builtins::instance()->initialize(); + +	QApplication app(argc, argv, false); +	QDir original_path = QDir::current(); + +	currentdir = QDir::currentPath(); + +	QDir libdir(QApplication::instance()->applicationDirPath()); +#ifdef Q_WS_MAC +	libdir.cd("../Resources"); // Libraries can be bundled +	if (!libdir.exists("libraries")) libdir.cd("../../.."); +#elif defined(Q_OS_UNIX) +	if (libdir.cd("../share/openscad/libraries")) { +		librarydir = libdir.path(); +	} else +	if (libdir.cd("../../share/openscad/libraries")) { +		librarydir = libdir.path(); +	} else +	if (libdir.cd("../../libraries")) { +		librarydir = libdir.path(); +	} else +#endif +	if (libdir.cd("libraries")) { +		librarydir = libdir.path(); +	} + +	Context root_ctx; +	register_builtin(root_ctx); + +	AbstractModule *root_module; +	ModuleInstantiation root_inst; + +	root_module = parsefile(filename); +	if (!root_module) { +		exit(1); +	} + +	QFileInfo fileInfo(filename); +	QDir::setCurrent(fileInfo.absolutePath()); + +	AbstractNode::resetIndexCounter(); +	AbstractNode *absolute_root_node = root_module->evaluate(&root_ctx, &root_inst); +	AbstractNode *root_node; +	// Do we have an explicit root node (! modifier)? +	if (!(root_node = find_root_tag(absolute_root_node))) root_node = absolute_root_node; + +	Tree tree(root_node); + +	CGALEvaluator cgalevaluator(tree); + 	PolySetCGALEvaluator psevaluator(cgalevaluator); + +	CGAL_Nef_polyhedron N = cgalevaluator.evaluateCGALMesh(*root_node); + +	QDir::setCurrent(original_path.absolutePath()); +	if (!N.empty()) { +		std::ofstream outfile; +		outfile.open(outfilename); + +		std::stringstream out; +		export_stl(&N, out, NULL); +		if (out.str().find("nan") != string::npos) { +			outfile << "Error: nan found\n"; +			retval = 2; +		} +		if (out.str().find("inf") != string::npos) { +			outfile << "Error: inf found\n"; +			retval = 2; +		} +		outfile.close(); +	} + +	Builtins::instance(true); + +	return retval; +} diff --git a/tests/regression/cgalstlsanitytest/normal-nan-expected.txt b/tests/regression/cgalstlsanitytest/normal-nan-expected.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/regression/cgalstlsanitytest/normal-nan-expected.txt | 
