Cleanup: Removed redundant code

customizer
Marius Kintel 2013-12-24 02:22:50 -05:00
parent 0e5037dce3
commit ace3668736
24 changed files with 102 additions and 1850 deletions

View File

@ -212,7 +212,6 @@ HEADERS += src/typedefs.h \
src/csgtermnormalizer.h \
src/dxfdata.h \
src/dxfdim.h \
src/dxftess.h \
src/export.h \
src/expression.h \
src/function.h \
@ -339,9 +338,6 @@ SOURCES += src/version_check.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/svg.cc \
src/OffscreenView.cc \

View File

@ -1,380 +0,0 @@
#include "CGALCache.h"
#include "CGALEvaluator.h"
#include "GeometryEvaluator.h"
#include "traverser.h"
#include "visitor.h"
#include "state.h"
#include "module.h" // FIXME: Temporarily for ModuleInstantiation
#include "printutils.h"
#include "csgnode.h"
#include "cgaladvnode.h"
#include "transformnode.h"
#include "polyset.h"
#include "Polygon2d.h"
#include "dxfdata.h"
#include "dxftess.h"
#include "Tree.h"
#include "cgal.h"
#include "cgalutils.h"
#include <CGAL/convex_hull_2.h>
#ifdef NDEBUG
#define PREV_NDEBUG NDEBUG
#undef NDEBUG
#endif
#ifdef PREV_NDEBUG
#define NDEBUG PREV_NDEBUG
#endif
#include <string>
#include <map>
#include <list>
#include <sstream>
#include <iostream>
#include <assert.h>
#include <boost/foreach.hpp>
#include <boost/bind.hpp>
#include <map>
shared_ptr<const CGAL_Nef_polyhedron> CGALEvaluator::evaluateCGALMesh(const AbstractNode &node)
{
if (!isCached(node)) {
Traverser evaluate(*this, node, Traverser::PRE_AND_POSTFIX);
evaluate.execute();
return this->root;
}
return CGALCache::instance()->get(this->tree.getIdString(node));
}
bool CGALEvaluator::isCached(const AbstractNode &node) const
{
return CGALCache::instance()->contains(this->tree.getIdString(node));
}
/*!
*/
CGAL_Nef_polyhedron *CGALEvaluator::applyToChildren(const AbstractNode &node, OpenSCADOperator op)
{
CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron;
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
const AbstractNode *chnode = item.first;
const shared_ptr<const CGAL_Nef_polyhedron> chN = item.second;
// FIXME: Don't use deep access to modinst members
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
// cache could have been modified before we reach this point due to a large
// sibling object.
if (!isCached(*chnode)) {
CGALCache::instance()->insert(this->tree.getIdString(*chnode), chN);
}
// Initialize N on first iteration with first expected geometric object
if (chN) {
if (N->isNull() && !N->isEmpty()) *N = chN->copy();
else CGALUtils::applyBinaryOperator(*N, *chN, op);
}
chnode->progress_report();
}
return N;
}
const CGAL_Nef_polyhedron *CGALEvaluator::applyHull(const CgaladvNode &node)
{
unsigned int dim = 0;
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
if (!dim) {
dim = item.second->getDimension();
if (dim) break;
}
}
CGAL_Nef_polyhedron *N = NULL;
if (dim == 2) {
std::list<CGAL_Nef_polyhedron2*> polys;
std::list<CGAL_Nef_polyhedron2::Point> points2d;
std::list<CGAL_Polyhedron::Vertex::Point_3> points3d;
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
const AbstractNode *chnode = item.first;
const shared_ptr<const CGAL_Nef_polyhedron> chN = item.second;
// FIXME: Don't use deep access to modinst members
if (chnode->modinst->isBackground()) continue;
if (chN->getDimension() == 0) continue; // Ignore object with dimension 0 (e.g. echo)
if (dim != chN->getDimension()) {
PRINT("WARNING: hull() does not support mixing 2D and 3D objects.");
continue;
}
if (chN->isNull()) { // If one of the children evaluated to a null object
continue;
}
CGAL_Nef_polyhedron2::Explorer explorer = chN->p2->explorer();
BOOST_FOREACH(const CGAL_Nef_polyhedron2::Explorer::Vertex &vh,
std::make_pair(explorer.vertices_begin(), explorer.vertices_end())) {
if (explorer.is_standard(&vh)) {
points2d.push_back(explorer.point(&vh));
}
}
chnode->progress_report();
}
std::list<CGAL_Nef_polyhedron2::Point> result;
CGAL::convex_hull_2(points2d.begin(), points2d.end(),std:: back_inserter(result));
N = new CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron2(result.begin(), result.end(),
CGAL_Nef_polyhedron2::INCLUDED));
}
else if (dim == 3) {
Geometry::ChildList children;
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
const AbstractNode *chnode = item.first;
const shared_ptr<const CGAL_Nef_polyhedron> chN = item.second;
// FIXME: Don't use deep access to modinst members
if (chnode->modinst->isBackground()) continue;
if (chN->getDimension() == 0) continue; // Ignore object with dimension 0 (e.g. echo)
if (dim == 0) {
dim = chN->getDimension();
}
else if (dim != chN->getDimension()) {
PRINT("WARNING: hull() does not support mixing 2D and 3D objects.");
continue;
}
if (chN->isNull()) { // If one of the children evaluated to a null object
continue;
}
children.push_back(std::make_pair(chnode, chN));
}
CGAL_Polyhedron P;
if (CGALUtils::applyHull(children, P)) {
N = new CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron3(P));
}
}
return N;
}
const CGAL_Nef_polyhedron *CGALEvaluator::applyResize(const CgaladvNode &node)
{
// Based on resize() in Giles Bathgate's RapCAD (but not exactly)
CGAL_Nef_polyhedron *N = applyToChildren(node, OPENSCAD_UNION);
if (N->isNull() || N->isEmpty()) return N;
for (int i=0;i<3;i++) {
if (node.newsize[i]<0) {
PRINT("WARNING: Cannot resize to sizes less than 0.");
return N;
}
}
CGAL_Iso_cuboid_3 bb;
if (N->getDimension() == 2) {
CGAL_Iso_rectangle_2e bbox = bounding_box(*N->p2);
CGAL_Point_2e min2(bbox.min()), max2(bbox.max());
CGAL_Point_3 min3(CGAL::to_double(min2.x()), CGAL::to_double(min2.y()), 0),
max3(CGAL::to_double(max2.x()), CGAL::to_double(max2.y()), 0);
bb = CGAL_Iso_cuboid_3( min3, max3 );
}
else {
bb = bounding_box(*N->p3);
}
std::vector<NT3> scale, bbox_size;
for (int i=0;i<3;i++) scale.push_back( NT3(1) );
bbox_size.push_back( bb.xmax()-bb.xmin() );
bbox_size.push_back( bb.ymax()-bb.ymin() );
bbox_size.push_back( bb.zmax()-bb.zmin() );
int newsizemax_index = 0;
for (int i=0;i<N->getDimension();i++) {
if (node.newsize[i]) {
if (bbox_size[i]==NT3(0)) {
PRINT("WARNING: Resize in direction normal to flat object is not implemented");
return N;
}
else {
scale[i] = NT3(node.newsize[i]) / bbox_size[i];
}
if ( node.newsize[i] > node.newsize[newsizemax_index] )
newsizemax_index = i;
}
}
NT3 autoscale = NT3( 1 );
if ( node.newsize[ newsizemax_index ] != 0 )
autoscale = NT3( node.newsize[ newsizemax_index ] ) / bbox_size[ newsizemax_index ];
for (int i=0;i<N->getDimension();i++) {
if (node.autosize[i] && node.newsize[i]==0)
scale[i] = autoscale;
}
Eigen::Matrix4d t;
t << CGAL::to_double(scale[0]), 0, 0, 0,
0, CGAL::to_double(scale[1]), 0, 0,
0, 0, CGAL::to_double(scale[2]), 0,
0, 0, 0, 1;
N->transform( Transform3d( t ) );
return N;
}
/*
Typical visitor behavior:
o In prefix: Check if we're cached -> prune
o In postfix: Check if we're cached -> don't apply operator to children
o In postfix: addToParent()
*/
Response CGALEvaluator::visit(State &state, const AbstractNode &node)
{
if (state.isPrefix() && isCached(node)) return PruneTraversal;
if (state.isPostfix()) {
shared_ptr<const CGAL_Nef_polyhedron> N;
if (!isCached(node)) N.reset(applyToChildren(node, OPENSCAD_UNION));
else N = CGALCache::instance()->get(this->tree.getIdString(node));
addToParent(state, node, N);
}
return ContinueTraversal;
}
Response CGALEvaluator::visit(State &state, const AbstractIntersectionNode &node)
{
if (state.isPrefix() && isCached(node)) return PruneTraversal;
if (state.isPostfix()) {
shared_ptr<const CGAL_Nef_polyhedron> N;
if (!isCached(node)) N.reset(applyToChildren(node, OPENSCAD_INTERSECTION));
else N = CGALCache::instance()->get(this->tree.getIdString(node));
addToParent(state, node, N);
}
return ContinueTraversal;
}
Response CGALEvaluator::visit(State &state, const CsgNode &node)
{
if (state.isPrefix() && isCached(node)) return PruneTraversal;
if (state.isPostfix()) {
shared_ptr<const CGAL_Nef_polyhedron> N;
if (!isCached(node)) N.reset(applyToChildren(node, node.type));
else N = CGALCache::instance()->get(this->tree.getIdString(node));
addToParent(state, node, N);
}
return ContinueTraversal;
}
Response CGALEvaluator::visit(State &state, const TransformNode &node)
{
if (state.isPrefix() && isCached(node)) return PruneTraversal;
if (state.isPostfix()) {
shared_ptr<const CGAL_Nef_polyhedron> N;
if (!isCached(node)) {
// First union all children
CGAL_Nef_polyhedron *tmpN = applyToChildren(node, OPENSCAD_UNION);
if (matrix_contains_infinity(node.matrix) || matrix_contains_nan(node.matrix)) {
// due to the way parse/eval works we can't currently distinguish between NaN and Inf
PRINT("Warning: Transformation matrix contains Not-a-Number and/or Infinity - removing object.");
N.reset();
}
else {
tmpN->transform(node.matrix);
N.reset(tmpN);
}
}
else {
N = CGALCache::instance()->get(this->tree.getIdString(node));
}
addToParent(state, node, N);
}
return ContinueTraversal;
}
/*!
Handles non-leaf PolyNodes; extrudes, projection
*/
Response CGALEvaluator::visit(State &state, const AbstractPolyNode &node)
{
if (state.isPrefix() && isCached(node)) return PruneTraversal;
if (state.isPostfix()) {
shared_ptr<const CGAL_Nef_polyhedron> N;
if (!isCached(node)) {
// Apply polyset operation
shared_ptr<const Geometry> geom = this->geomevaluator.evaluateGeometry(node, true);
if (geom) {
shared_ptr<const CGAL_Nef_polyhedron> Nptr = dynamic_pointer_cast<const CGAL_Nef_polyhedron>(geom);
if (!Nptr) {
Nptr.reset(createNefPolyhedronFromGeometry(*geom));
}
N = Nptr;
}
node.progress_report();
}
else {
N = CGALCache::instance()->get(this->tree.getIdString(node));
}
addToParent(state, node, N);
}
return ContinueTraversal;
}
Response CGALEvaluator::visit(State &state, const CgaladvNode &node)
{
if (state.isPrefix() && isCached(node)) return PruneTraversal;
if (state.isPostfix()) {
shared_ptr<const CGAL_Nef_polyhedron> N;
if (!isCached(node)) {
OpenSCADOperator op;
switch (node.type) {
case MINKOWSKI:
op = OPENSCAD_MINKOWSKI;
N.reset(applyToChildren(node, op));
break;
case GLIDE:
PRINT("WARNING: glide() is not implemented yet!");
return PruneTraversal;
break;
case SUBDIV:
PRINT("WARNING: subdiv() is not implemented yet!");
return PruneTraversal;
break;
case HULL:
N.reset(applyHull(node));
break;
case RESIZE:
N.reset(applyResize(node));
break;
}
}
else {
N = CGALCache::instance()->get(this->tree.getIdString(node));
}
addToParent(state, node, N);
}
return ContinueTraversal;
}
/*!
Adds ourself to out parent's list of traversed children.
Call this for _every_ node which affects output during the postfix traversal.
*/
void CGALEvaluator::addToParent(const State &state,
const AbstractNode &node,
const shared_ptr<const CGAL_Nef_polyhedron> &N)
{
assert(state.isPostfix());
this->visitedchildren.erase(node.index());
if (state.parent()) {
this->visitedchildren[state.parent()->index()].push_back(std::make_pair(&node, N));
}
else {
// Root node, insert into cache
if (!isCached(node)) {
if (!CGALCache::instance()->insert(this->tree.getIdString(node), N)) {
PRINT("WARNING: CGAL Evaluator: Root node didn't fit into cache");
}
}
this->root = N;
}
}

View File

@ -1,51 +0,0 @@
#ifndef CGALEVALUATOR_H_
#define CGALEVALUATOR_H_
#include "visitor.h"
#include "enums.h"
#include "CGAL_Nef_polyhedron.h"
#include <string>
#include <map>
#include <list>
class CGALEvaluator : public Visitor
{
public:
enum CsgOp {CGE_UNION, CGE_INTERSECTION, CGE_DIFFERENCE, CGE_MINKOWSKI};
CGALEvaluator(const class Tree &tree, class GeometryEvaluator &geomevaluator) :
tree(tree), geomevaluator(geomevaluator) {}
virtual ~CGALEvaluator() {}
virtual Response visit(State &state, const AbstractNode &node);
virtual Response visit(State &state, const AbstractIntersectionNode &node);
virtual Response visit(State &state, const CsgNode &node);
virtual Response visit(State &state, const TransformNode &node);
virtual Response visit(State &state, const AbstractPolyNode &node);
virtual Response visit(State &state, const CgaladvNode &node);
shared_ptr<const CGAL_Nef_polyhedron> evaluateCGALMesh(const AbstractNode &node);
const Tree &getTree() const { return this->tree; }
private:
void addToParent(const State &state, const AbstractNode &node, const shared_ptr<const CGAL_Nef_polyhedron> &N);
bool isCached(const AbstractNode &node) const;
void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op);
CGAL_Nef_polyhedron *applyToChildren(const AbstractNode &node, OpenSCADOperator op);
const CGAL_Nef_polyhedron *applyHull(const CgaladvNode &node);
const CGAL_Nef_polyhedron *applyResize(const CgaladvNode &node);
typedef std::pair<const AbstractNode *, shared_ptr<const CGAL_Nef_polyhedron> > ChildItem;
typedef std::list<ChildItem> ChildList;
std::map<int, ChildList> visitedchildren;
const Tree &tree;
shared_ptr<const CGAL_Nef_polyhedron> root;
public:
// FIXME: Do we need to make this visible? Used for cache management
// Note: psevaluator constructor needs this->tree to be initialized first
class GeometryEvaluator &geomevaluator;
};
#endif

View File

@ -35,7 +35,6 @@
#include "CGALRenderer.h"
#include "CGAL_renderer.h"
#include "dxftess.h"
#include "CGAL_Nef_polyhedron.h"
#include "cgal.h"

View File

@ -3,20 +3,6 @@
#include "cgalutils.h"
#include "printutils.h"
#include "polyset.h"
#include "dxfdata.h"
#include "dxftess.h"
CGAL_Nef_polyhedron::CGAL_Nef_polyhedron(CGAL_Nef_polyhedron2 *p)
{
assert(false);
if (p) {
dim = 2;
p2.reset(p);
}
else {
dim = 0;
}
}
CGAL_Nef_polyhedron::CGAL_Nef_polyhedron(CGAL_Nef_polyhedron3 *p)
{
@ -32,22 +18,19 @@ CGAL_Nef_polyhedron::CGAL_Nef_polyhedron(CGAL_Nef_polyhedron3 *p)
CGAL_Nef_polyhedron& CGAL_Nef_polyhedron::operator+=(const CGAL_Nef_polyhedron &other)
{
if (this->dim == 2) (*this->p2) += (*other.p2);
else if (this->dim == 3) (*this->p3) += (*other.p3);
if (this->dim == 3) (*this->p3) += (*other.p3);
return *this;
}
CGAL_Nef_polyhedron& CGAL_Nef_polyhedron::operator*=(const CGAL_Nef_polyhedron &other)
{
if (this->dim == 2) (*this->p2) *= (*other.p2);
else if (this->dim == 3) (*this->p3) *= (*other.p3);
if (this->dim == 3) (*this->p3) *= (*other.p3);
return *this;
}
CGAL_Nef_polyhedron& CGAL_Nef_polyhedron::operator-=(const CGAL_Nef_polyhedron &other)
{
if (this->dim == 2) (*this->p2) -= (*other.p2);
else if (this->dim == 3) (*this->p3) -= (*other.p3);
if (this->dim == 3) (*this->p3) -= (*other.p3);
return *this;
}
@ -55,8 +38,7 @@ extern CGAL_Nef_polyhedron2 minkowski2(const CGAL_Nef_polyhedron2 &a, const CGAL
CGAL_Nef_polyhedron &CGAL_Nef_polyhedron::minkowski(const CGAL_Nef_polyhedron &other)
{
if (this->dim == 2) (*this->p2) = minkowski2(*this->p2, *other.p2);
else if (this->dim == 3) (*this->p3) = CGAL::minkowski_sum_3(*this->p3, *other.p3);
if (this->dim == 3) (*this->p3) = CGAL::minkowski_sum_3(*this->p3, *other.p3);
return *this;
}
@ -65,12 +47,6 @@ size_t CGAL_Nef_polyhedron::memsize() const
if (this->isNull()) return 0;
size_t memsize = sizeof(CGAL_Nef_polyhedron);
if (this->dim == 2) {
memsize += sizeof(CGAL_Nef_polyhedron2) +
this->p2->explorer().number_of_vertices() * sizeof(CGAL_Nef_polyhedron2::Explorer::Vertex) +
this->p2->explorer().number_of_halfedges() * sizeof(CGAL_Nef_polyhedron2::Explorer::Halfedge) +
this->p2->explorer().number_of_edges() * sizeof(CGAL_Nef_polyhedron2::Explorer::Face);
}
if (this->dim == 3) memsize += this->p3->bytes();
return memsize;
}
@ -84,16 +60,7 @@ PolySet *CGAL_Nef_polyhedron::convertToPolyset() const
{
if (this->isNull()) return new PolySet();
PolySet *ps = NULL;
if (this->dim == 2) {
assert(false);
DxfData *dd = this->convertToDxfData();
Polygon2d *p2d = dd->toPolygon2d();
ps = new PolySet(*p2d);
delete p2d;
dxf_tesselate(ps, *dd, 0, Vector2d(1,1), true, false, 0);
delete dd;
}
else if (this->dim == 3) {
if (this->dim == 3) {
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
ps = new PolySet();
bool err = true;
@ -127,7 +94,6 @@ PolySet *CGAL_Nef_polyhedron::convertToPolyset() const
CGAL_Nef_polyhedron CGAL_Nef_polyhedron::copy() const
{
CGAL_Nef_polyhedron copy = *this;
if (copy.p2) copy.p2.reset(new CGAL_Nef_polyhedron2(*copy.p2));
else if (copy.p3) copy.p3.reset(new CGAL_Nef_polyhedron3(*copy.p3));
if (copy.p3) copy.p3.reset(new CGAL_Nef_polyhedron3(*copy.p3));
return copy;
}

View File

@ -11,7 +11,6 @@ class CGAL_Nef_polyhedron : public Geometry
{
public:
CGAL_Nef_polyhedron(int dim = 0) : dim(dim) {}
CGAL_Nef_polyhedron(CGAL_Nef_polyhedron2 *p);
CGAL_Nef_polyhedron(CGAL_Nef_polyhedron3 *p);
~CGAL_Nef_polyhedron() {}
@ -22,20 +21,17 @@ public:
virtual unsigned int getDimension() const { return this->dim; }
// Empty means it is a geometric node which has zero area/volume
bool isEmpty() const { return (dim > 0 && !p2 && !p3); }
bool isEmpty() const { return (dim > 0 && !p3); }
// Null means the node doesn't contain any geometry (for whatever reason)
bool isNull() const { return !p2 && !p3; }
void reset() { dim=0; p2.reset(); p3.reset(); }
bool isNull() const { return !p3; }
void reset() { dim=0; p3.reset(); }
CGAL_Nef_polyhedron &operator+=(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron &operator*=(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron &operator-=(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron &minkowski(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron copy() const;
class PolySet *convertToPolyset() const;
class DxfData *convertToDxfData() const;
class Polygon2d *convertToPolygon2d() const;
void transform( const Transform3d &matrix );
shared_ptr<CGAL_Nef_polyhedron2> p2;
shared_ptr<CGAL_Nef_polyhedron3> p3;
protected:
int dim;

View File

@ -32,87 +32,13 @@
#include "cgalutils.h"
#include <boost/variant.hpp>
#include "polyset.h"
#include "dxftess.h"
#include "Tree.h"
#ifdef ENABLE_CGAL
DxfData *CGAL_Nef_polyhedron::convertToDxfData() const
{
assert(this->dim == 2);
DxfData *dxfdata = new DxfData();
Grid2d<int> grid(GRID_COARSE);
typedef CGAL_Nef_polyhedron2::Explorer Explorer;
typedef Explorer::Face_const_iterator fci_t;
typedef Explorer::Halfedge_around_face_const_circulator heafcc_t;
Explorer E = this->p2->explorer();
for (fci_t fit = E.faces_begin(), facesend = E.faces_end(); fit != facesend; ++fit)
{
heafcc_t fcirc(E.halfedge(fit)), fend(fcirc);
int first_point = -1, last_point = -1;
CGAL_For_all(fcirc, fend) {
if (E.is_standard(E.target(fcirc))) {
Explorer::Point ep = E.point(E.target(fcirc));
double x = to_double(ep.x()), y = to_double(ep.y());
int this_point = -1;
if (grid.has(x, y)) {
this_point = grid.align(x, y);
} else {
this_point = grid.align(x, y) = dxfdata->points.size();
dxfdata->points.push_back(Vector2d(x, y));
}
if (first_point < 0) {
dxfdata->paths.push_back(DxfData::Path());
first_point = this_point;
}
if (this_point != last_point) {
dxfdata->paths.back().indices.push_back(this_point);
last_point = this_point;
}
}
}
if (first_point >= 0) {
dxfdata->paths.back().is_closed = 1;
dxfdata->paths.back().indices.push_back(first_point);
}
}
dxfdata->fixup_path_direction();
return dxfdata;
}
Polygon2d *CGAL_Nef_polyhedron::convertToPolygon2d() const
{
assert(this->dim == 2);
Polygon2d *poly = new Polygon2d;
typedef CGAL_Nef_polyhedron2::Explorer Explorer;
typedef Explorer::Face_const_iterator fci_t;
typedef Explorer::Halfedge_around_face_const_circulator heafcc_t;
Explorer E = this->p2->explorer();
for (fci_t fit = E.faces_begin(), facesend = E.faces_end(); fit != facesend; ++fit) {
heafcc_t fcirc(E.halfedge(fit)), fend(fcirc);
Outline2d outline;
CGAL_For_all(fcirc, fend) {
if (E.is_standard(E.target(fcirc))) {
Explorer::Point ep = E.point(E.target(fcirc));
outline.push_back(Vector2d(to_double(ep.x()),
to_double(ep.y())));
}
}
if (outline.size() > 0) poly->addOutline(outline);
}
return poly;
}
std::string CGAL_Nef_polyhedron::dump() const
{
if (this->dim==2)
return OpenSCAD::dump_svg( *this->p2 );
else if (this->dim==3)
if (this->dim==3)
return OpenSCAD::dump_svg( *this->p3 );
else
return std::string("Nef Polyhedron with dimension != 2 or 3");
@ -122,43 +48,7 @@ std::string CGAL_Nef_polyhedron::dump() const
void CGAL_Nef_polyhedron::transform( const Transform3d &matrix )
{
if (!this->isNull()) {
assert(this->dim == 3);
if (this->dim == 2) {
// Unfortunately CGAL provides no transform method for CGAL_Nef_polyhedron2
// objects. So we convert in to our internal 2d data format, transform it,
// tesselate it and create a new CGAL_Nef_polyhedron2 from it.. What a hack!
Eigen::Matrix2f testmat;
testmat << matrix(0,0), matrix(0,1), matrix(1,0), matrix(1,1);
if (testmat.determinant() == 0) {
PRINT("Warning: Scaling a 2D object with 0 - removing object");
this->reset();
return;
}
else {
CGAL_Aff_transformation2 t(
matrix(0,0), matrix(0,1), matrix(0,3),
matrix(1,0), matrix(1,1), matrix(1,3), matrix(3,3));
DxfData *dd = this->convertToDxfData();
for (size_t i=0; i < dd->points.size(); i++) {
CGAL_Kernel2::Point_2 p = CGAL_Kernel2::Point_2(dd->points[i][0], dd->points[i][1]);
p = t.transform(p);
dd->points[i][0] = to_double(p.x());
dd->points[i][1] = to_double(p.y());
}
PolySet ps;
ps.is2d = true;
dxf_tesselate(&ps, *dd, 0, Vector2d(1,1), true, false, 0);
CGAL_Nef_polyhedron *Nptr = createNefPolyhedronFromGeometry(ps);
CGAL_Nef_polyhedron N = *Nptr;
delete Nptr;
if (N.p2) this->p2.reset(new CGAL_Nef_polyhedron2(*N.p2));
delete dd;
}
}
else if (this->dim == 3) {
if (this->dim == 3) {
if (matrix.matrix().determinant() == 0) {
PRINT("Warning: Scaling a 3D object with 0 - removing object");
this->reset();

View File

@ -78,9 +78,7 @@ shared_ptr<const Geometry> GeometryEvaluator::evaluateGeometry(const AbstractNod
if (!allownef) {
shared_ptr<const CGAL_Nef_polyhedron> N = dynamic_pointer_cast<const CGAL_Nef_polyhedron>(this->root);
if (N) {
assert(N->getDimension() != 2); // FIXME: Remove 2D code
if (N->getDimension() == 2) this->root.reset(N->convertToPolygon2d());
else if (N->getDimension() == 3) this->root.reset(N->convertToPolyset());
if (N->getDimension() == 3) this->root.reset(N->convertToPolyset());
else this->root.reset();
GeometryCache::instance()->insert(this->tree.getIdString(node), this->root);
}
@ -146,41 +144,6 @@ GeometryEvaluator::ResultObject GeometryEvaluator::applyToChildren3D(const Abstr
item.first->progress_report();
}
/*
CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron;
BOOST_FOREACH(const Geometry::ChildItem &item, this->visitedchildren[node.index()]) {
const AbstractNode *chnode = item.first;
const shared_ptr<const Geometry> &chgeom = item.second;
// FIXME: Don't use deep access to modinst members
if (chnode->modinst->isBackground()) continue;
shared_ptr<const CGAL_Nef_polyhedron> chN = dynamic_pointer_cast<const CGAL_Nef_polyhedron>(chgeom);
if (!chN) {
shared_ptr<const PolySet> chP = dynamic_pointer_cast<const PolySet>(chgeom);
if (chP) chN.reset(createNefPolyhedronFromGeometry(*chP));
}
// 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
// cache could have been modified before we reach this point due to a large
// sibling object.
smartCache(node, chN);
if (chgeom) {
if (chgeom->getDimension() == 3) {
// Initialize N on first iteration with first expected geometric object
if (N->isNull() && !N->isEmpty()) *N = chN->copy();
else CGALUtils::applyBinaryOperator(*N, *chN, op);
}
else {
// FIXME: Fix error message
PRINT("ERROR: this operation is not defined for 2D child objects!");
}
}
chnode->progress_report();
}
*/
return ResultObject(N);
}
@ -230,11 +193,10 @@ void GeometryEvaluator::applyResize3D(CGAL_Nef_polyhedron &N,
const Vector3d &newsize,
const Eigen::Matrix<bool,3,1> &autosize)
{
assert(N.getDimension() != 2); // FIXME: Remove 2D code
// Based on resize() in Giles Bathgate's RapCAD (but not exactly)
if (N.isNull() || N.isEmpty()) return;
CGAL_Iso_cuboid_3 bb = bounding_box(*N.p3);
CGAL_Iso_cuboid_3 bb = CGALUtils::boundingBox(*N.p3);
std::vector<NT3> scale, bbox_size;
for (int i=0;i<3;i++) {
@ -985,8 +947,7 @@ Response GeometryEvaluator::visit(State &state, const ProjectionNode &node)
Nptr.reset(createNefPolyhedronFromGeometry(*newgeom));
}
if (!Nptr->isNull()) {
CGAL_Nef_polyhedron nef_poly = CGALUtils::project(*Nptr, node.cut_mode);
Polygon2d *poly = nef_poly.convertToPolygon2d();
Polygon2d *poly = CGALUtils::project(*Nptr, node.cut_mode);
assert(poly);
poly->setConvexity(node.convexity);
geom.reset(poly);

View File

@ -9,6 +9,7 @@
#include "cgal.h"
#include <CGAL/convex_hull_3.h>
#include "svg.h"
#include <map>
#include <boost/foreach.hpp>
@ -110,11 +111,35 @@ namespace CGALUtils {
CGAL::set_error_behaviour(old_behaviour);
}
CGAL_Nef_polyhedron project(const CGAL_Nef_polyhedron &N, bool cut)
static Polygon2d *convertToPolygon2d(const CGAL_Nef_polyhedron2 &p2)
{
Polygon2d *poly = new Polygon2d;
typedef CGAL_Nef_polyhedron2::Explorer Explorer;
typedef Explorer::Face_const_iterator fci_t;
typedef Explorer::Halfedge_around_face_const_circulator heafcc_t;
Explorer E = p2.explorer();
for (fci_t fit = E.faces_begin(), facesend = E.faces_end(); fit != facesend; ++fit) {
heafcc_t fcirc(E.halfedge(fit)), fend(fcirc);
Outline2d outline;
CGAL_For_all(fcirc, fend) {
if (E.is_standard(E.target(fcirc))) {
Explorer::Point ep = E.point(E.target(fcirc));
outline.push_back(Vector2d(to_double(ep.x()),
to_double(ep.y())));
}
}
if (outline.size() > 0) poly->addOutline(outline);
}
return poly;
}
Polygon2d *project(const CGAL_Nef_polyhedron &N, bool cut)
{
logstream log(5);
CGAL_Nef_polyhedron nef_poly(2);
if (N.getDimension() != 3) return nef_poly;
Polygon2d *poly = NULL;
if (N.getDimension() != 3) return poly;
CGAL_Nef_polyhedron newN;
if (cut) {
@ -148,7 +173,7 @@ namespace CGALUtils {
if (!newN.p3 || newN.p3->is_empty()) {
CGAL::set_error_behaviour(old_behaviour);
PRINT("WARNING: projection() failed.");
return nef_poly;
return poly;
}
log << OpenSCAD::svg_header( 480, 100000 ) << "\n";
@ -167,7 +192,7 @@ namespace CGALUtils {
}
log << "<!-- volume end. -->\n";
}
nef_poly.p2 = zremover.output_nefpoly2d;
poly = convertToPolygon2d(*zremover.output_nefpoly2d);
} catch (const CGAL::Failure_exception &e) {
PRINTB("CGAL error in CGALUtils::project while flattening: %s", e.what());
}
@ -178,20 +203,23 @@ namespace CGALUtils {
// In projection mode all the triangles are projected manually into the XY plane
else {
PolySet *ps3 = N.convertToPolyset();
if (!ps3) return nef_poly;
const Polygon2d *poly = PolysetUtils::project(*ps3);
// FIXME: Convert back to Nef2 and delete poly?
/* if (nef_poly.isEmpty()) {
nef_poly.p2.reset(new CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED));
}
else {
(*nef_poly.p2) += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED);
}
*/
if (!ps3) return poly;
poly = PolysetUtils::project(*ps3);
delete ps3;
}
return nef_poly;
return poly;
}
CGAL_Iso_cuboid_3 boundingBox(const CGAL_Nef_polyhedron3 &N)
{
CGAL_Iso_cuboid_3 result(0,0,0,0,0,0);
CGAL_Nef_polyhedron3::Vertex_const_iterator vi;
std::vector<CGAL_Nef_polyhedron3::Point_3> points;
// can be optimized by rewriting bounding_box to accept vertices
CGAL_forall_vertices(vi, N)
points.push_back(vi->point());
if (points.size()) result = CGAL::bounding_box( points.begin(), points.end() );
return result;
}
};
@ -309,34 +337,6 @@ bool createPolyhedronFromPolySet(const PolySet &ps, CGAL_Polyhedron &p)
return err;
}
CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N )
{
CGAL_Iso_cuboid_3 result(0,0,0,0,0,0);
CGAL_Nef_polyhedron3::Vertex_const_iterator vi;
std::vector<CGAL_Nef_polyhedron3::Point_3> points;
// can be optimized by rewriting bounding_box to accept vertices
CGAL_forall_vertices( vi, N )
points.push_back( vi->point() );
if (points.size())
result = CGAL::bounding_box( points.begin(), points.end() );
return result;
}
CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N )
{
CGAL_Iso_rectangle_2e result(0,0,0,0);
CGAL_Nef_polyhedron2::Explorer explorer = N.explorer();
CGAL_Nef_polyhedron2::Explorer::Vertex_const_iterator vi;
std::vector<CGAL_Point_2e> points;
// can be optimized by rewriting bounding_box to accept vertices
for ( vi = explorer.vertices_begin(); vi != explorer.vertices_end(); ++vi )
if ( explorer.is_standard( vi ) )
points.push_back( explorer.point( vi ) );
if (points.size())
result = CGAL::bounding_box( points.begin(), points.end() );
return result;
}
void ZRemover::visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet )
{
log << " <!-- ZRemover Halffacet visit. Mark: " << hfacet->mark() << " -->\n";
@ -391,276 +391,28 @@ void ZRemover::visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet )
static CGAL_Nef_polyhedron *createNefPolyhedronFromPolySet(const PolySet &ps)
{
if (ps.empty()) return new CGAL_Nef_polyhedron(ps.is2d ? 2 : 3);
assert(ps.getDimension() == 3);
if (ps.empty()) return new CGAL_Nef_polyhedron(3);
if (ps.is2d)
{
#if 0
// This version of the code causes problems in some cases.
// Example testcase: import_dxf("testdata/polygon8.dxf");
//
typedef std::list<CGAL_Nef_polyhedron2::Point> point_list_t;
typedef point_list_t::iterator point_list_it;
std::list< point_list_t > pdata_point_lists;
std::list < std::pair < point_list_it, point_list_it > > pdata;
Grid2d<CGAL_Nef_polyhedron2::Point> grid(GRID_COARSE);
for (int i = 0; i < ps.polygons.size(); i++) {
pdata_point_lists.push_back(point_list_t());
for (int j = 0; j < ps.polygons[i].size(); j++) {
double x = ps.polygons[i][j].x;
double y = ps.polygons[i][j].y;
CGAL_Nef_polyhedron2::Point p;
if (grid.has(x, y)) {
p = grid.data(x, y);
} else {
p = CGAL_Nef_polyhedron2::Point(x, y);
grid.data(x, y) = p;
}
pdata_point_lists.back().push_back(p);
}
pdata.push_back(std::make_pair(pdata_point_lists.back().begin(),
pdata_point_lists.back().end()));
}
CGAL_Nef_polyhedron2 N(pdata.begin(), pdata.end(), CGAL_Nef_polyhedron2::POLYGONS);
return new CGAL_Nef_polyhedron(N);
#endif
#if 0
// This version of the code works fine but is pretty slow.
//
CGAL_Nef_polyhedron2 N;
Grid2d<CGAL_Nef_polyhedron2::Point> grid(GRID_COARSE);
for (int i = 0; i < ps.polygons.size(); i++) {
std::list<CGAL_Nef_polyhedron2::Point> plist;
for (int j = 0; j < ps.polygons[i].size(); j++) {
double x = ps.polygons[i][j].x;
double y = ps.polygons[i][j].y;
CGAL_Nef_polyhedron2::Point p;
if (grid.has(x, y)) {
p = grid.data(x, y);
} else {
p = CGAL_Nef_polyhedron2::Point(x, y);
grid.data(x, y) = p;
}
plist.push_back(p);
}
N += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED);
}
return new CGAL_Nef_polyhedron(N);
#endif
#if 1
// This version of the code does essentially the same thing as the 2nd
// version but merges some triangles before sending them to CGAL. This adds
// complexity but speeds up things..
//
struct PolyReducer
{
Grid2d<int> grid;
std::map<std::pair<int,int>, std::pair<int,int> > edge_to_poly;
std::map<int, CGAL_Nef_polyhedron2::Point> points;
typedef std::map<int, std::vector<int> > PolygonMap;
PolygonMap polygons;
int poly_n;
void add_edges(int pn)
{
for (unsigned int j = 1; j <= this->polygons[pn].size(); j++) {
int a = this->polygons[pn][j-1];
int b = this->polygons[pn][j % this->polygons[pn].size()];
if (a > b) { a = a^b; b = a^b; a = a^b; }
if (this->edge_to_poly[std::pair<int,int>(a, b)].first == 0)
this->edge_to_poly[std::pair<int,int>(a, b)].first = pn;
else if (this->edge_to_poly[std::pair<int,int>(a, b)].second == 0)
this->edge_to_poly[std::pair<int,int>(a, b)].second = pn;
else
abort();
}
}
void del_poly(int pn)
{
for (unsigned int j = 1; j <= this->polygons[pn].size(); j++) {
int a = this->polygons[pn][j-1];
int b = this->polygons[pn][j % this->polygons[pn].size()];
if (a > b) { a = a^b; b = a^b; a = a^b; }
if (this->edge_to_poly[std::pair<int,int>(a, b)].first == pn)
this->edge_to_poly[std::pair<int,int>(a, b)].first = 0;
if (this->edge_to_poly[std::pair<int,int>(a, b)].second == pn)
this->edge_to_poly[std::pair<int,int>(a, b)].second = 0;
}
this->polygons.erase(pn);
}
PolyReducer(const PolySet &ps) : grid(GRID_COARSE), poly_n(1)
{
int point_n = 1;
for (size_t i = 0; i < ps.polygons.size(); i++) {
for (size_t j = 0; j < ps.polygons[i].size(); j++) {
double x = ps.polygons[i][j][0];
double y = ps.polygons[i][j][1];
if (this->grid.has(x, y)) {
int idx = this->grid.data(x, y);
// Filter away two vertices with the same index (due to grid)
// This could be done in a more general way, but we'd rather redo the entire
// grid concept instead.
std::vector<int> &poly = this->polygons[this->poly_n];
if (std::find(poly.begin(), poly.end(), idx) == poly.end()) {
poly.push_back(this->grid.data(x, y));
}
} else {
this->grid.align(x, y) = point_n;
this->polygons[this->poly_n].push_back(point_n);
this->points[point_n] = CGAL_Nef_polyhedron2::Point(x, y);
point_n++;
}
}
if (this->polygons[this->poly_n].size() >= 3) {
add_edges(this->poly_n);
this->poly_n++;
}
else {
this->polygons.erase(this->poly_n);
}
}
}
int merge(int p1, int p1e, int p2, int p2e)
{
for (unsigned int i = 1; i < this->polygons[p1].size(); i++) {
int j = (p1e + i) % this->polygons[p1].size();
this->polygons[this->poly_n].push_back(this->polygons[p1][j]);
}
for (unsigned int i = 1; i < this->polygons[p2].size(); i++) {
int j = (p2e + i) % this->polygons[p2].size();
this->polygons[this->poly_n].push_back(this->polygons[p2][j]);
}
del_poly(p1);
del_poly(p2);
add_edges(this->poly_n);
return this->poly_n++;
}
void reduce()
{
std::deque<int> work_queue;
BOOST_FOREACH(const PolygonMap::value_type &i, polygons) {
work_queue.push_back(i.first);
}
while (!work_queue.empty()) {
int poly1_n = work_queue.front();
work_queue.pop_front();
if (this->polygons.find(poly1_n) == this->polygons.end()) continue;
for (unsigned int j = 1; j <= this->polygons[poly1_n].size(); j++) {
int a = this->polygons[poly1_n][j-1];
int b = this->polygons[poly1_n][j % this->polygons[poly1_n].size()];
if (a > b) { a = a^b; b = a^b; a = a^b; }
if (this->edge_to_poly[std::pair<int,int>(a, b)].first != 0 &&
this->edge_to_poly[std::pair<int,int>(a, b)].second != 0) {
int poly2_n = this->edge_to_poly[std::pair<int,int>(a, b)].first +
this->edge_to_poly[std::pair<int,int>(a, b)].second - poly1_n;
int poly2_edge = -1;
for (unsigned int k = 1; k <= this->polygons[poly2_n].size(); k++) {
int c = this->polygons[poly2_n][k-1];
int d = this->polygons[poly2_n][k % this->polygons[poly2_n].size()];
if (c > d) { c = c^d; d = c^d; c = c^d; }
if (a == c && b == d) {
poly2_edge = k-1;
continue;
}
int poly3_n = this->edge_to_poly[std::pair<int,int>(c, d)].first +
this->edge_to_poly[std::pair<int,int>(c, d)].second - poly2_n;
if (poly3_n < 0)
continue;
if (poly3_n == poly1_n)
goto next_poly1_edge;
}
work_queue.push_back(merge(poly1_n, j-1, poly2_n, poly2_edge));
goto next_poly1;
}
next_poly1_edge:;
}
next_poly1:;
}
}
CGAL_Nef_polyhedron2 *toNef()
{
CGAL_Nef_polyhedron2 *N = new CGAL_Nef_polyhedron2;
BOOST_FOREACH(const PolygonMap::value_type &i, polygons) {
std::list<CGAL_Nef_polyhedron2::Point> plist;
for (unsigned int j = 0; j < i.second.size(); j++) {
int p = i.second[j];
plist.push_back(points[p]);
}
*N += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED);
}
return N;
}
};
PolyReducer pr(ps);
pr.reduce();
return new CGAL_Nef_polyhedron(pr.toNef());
#endif
#if 0
// This is another experimental version. I should run faster than the above,
// is a lot simpler and has only one known weakness: Degenerate polygons, which
// get repaired by GLUTess, might trigger a CGAL crash here. The only
// known case for this is triangle-with-duplicate-vertex.dxf
// FIXME: If we just did a projection, we need to recreate the border!
if (ps.polygons.size() > 0) assert(ps.borders.size() > 0);
CGAL_Nef_polyhedron2 N;
Grid2d<CGAL_Nef_polyhedron2::Point> grid(GRID_COARSE);
for (int i = 0; i < ps.borders.size(); i++) {
std::list<CGAL_Nef_polyhedron2::Point> plist;
for (int j = 0; j < ps.borders[i].size(); j++) {
double x = ps.borders[i][j].x;
double y = ps.borders[i][j].y;
CGAL_Nef_polyhedron2::Point p;
if (grid.has(x, y)) {
p = grid.data(x, y);
} else {
p = CGAL_Nef_polyhedron2::Point(x, y);
grid.data(x, y) = p;
}
plist.push_back(p);
}
// FIXME: If a border (path) has a duplicate vertex in dxf,
// the CGAL_Nef_polyhedron2 constructor will crash.
N ^= CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED);
}
return new CGAL_Nef_polyhedron(N);
#endif
CGAL_Nef_polyhedron3 *N = NULL;
bool plane_error = false;
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
try {
CGAL_Polyhedron P;
bool err = createPolyhedronFromPolySet(ps, P);
if (!err) N = new CGAL_Nef_polyhedron3(P);
}
else // not (this->is2d)
{
CGAL_Nef_polyhedron3 *N = NULL;
bool plane_error = false;
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
try {
CGAL_Polyhedron P;
bool err = createPolyhedronFromPolySet(ps, P);
if (!err) N = new CGAL_Nef_polyhedron3(P);
}
catch (const CGAL::Assertion_exception &e) {
if (std::string(e.what()).find("Plane_constructor")!=std::string::npos) {
if (std::string(e.what()).find("has_on")!=std::string::npos) {
PRINT("PolySet has nonplanar faces. Attempting alternate construction");
plane_error=true;
}
} else {
PRINTB("CGAL error in CGAL_Nef_polyhedron3(): %s", e.what());
catch (const CGAL::Assertion_exception &e) {
if (std::string(e.what()).find("Plane_constructor")!=std::string::npos) {
if (std::string(e.what()).find("has_on")!=std::string::npos) {
PRINT("PolySet has nonplanar faces. Attempting alternate construction");
plane_error=true;
}
} else {
PRINTB("CGAL error in CGAL_Nef_polyhedron3(): %s", e.what());
}
if (plane_error) try {
}
if (plane_error) try {
PolySet ps2;
CGAL_Polyhedron P;
PolysetUtils::tessellate_faces(ps, ps2);
@ -668,12 +420,10 @@ static CGAL_Nef_polyhedron *createNefPolyhedronFromPolySet(const PolySet &ps)
if (!err) N = new CGAL_Nef_polyhedron3(P);
}
catch (const CGAL::Assertion_exception &e) {
PRINTB("Alternate construction failed. CGAL error in CGAL_Nef_polyhedron3(): %s", e.what());
PRINTB("Alternate construction failed. CGAL error in CGAL_Nef_polyhedron3(): %s", e.what());
}
CGAL::set_error_behaviour(old_behaviour);
return new CGAL_Nef_polyhedron(N);
}
return NULL;
CGAL::set_error_behaviour(old_behaviour);
return new CGAL_Nef_polyhedron(N);
}
static CGAL_Nef_polyhedron *createNefPolyhedronFromPolygon2d(const Polygon2d &polygon)

View File

@ -9,14 +9,13 @@
namespace CGALUtils {
bool applyHull(const Geometry::ChildList &children, CGAL_Polyhedron &P);
void applyBinaryOperator(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op);
CGAL_Nef_polyhedron project(const CGAL_Nef_polyhedron &N, bool cut);
Polygon2d *project(const CGAL_Nef_polyhedron &N, bool cut);
CGAL_Iso_cuboid_3 boundingBox(const CGAL_Nef_polyhedron3 &N);
};
CGAL_Nef_polyhedron *createNefPolyhedronFromGeometry(const class Geometry &geom);
bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, PolySet &ps);
bool createPolyhedronFromPolySet(const PolySet &ps, CGAL_Polyhedron &p);
CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N );
CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N );
#include "svg.h"
#include "printutils.h"

View File

@ -1,337 +0,0 @@
#include "printutils.h"
#include "dxftess.h"
#include "dxfdata.h"
#include "polyset.h"
#include "grid.h"
#include "cgal.h"
#ifdef NDEBUG
#define PREV_NDEBUG NDEBUG
#undef NDEBUG
#endif
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/Delaunay_mesher_2.h>
#include <CGAL/Delaunay_mesher_no_edge_refinement_2.h>
#include <CGAL/Delaunay_mesh_face_base_2.h>
#include <CGAL/Delaunay_mesh_criteria_2.h>
#include <CGAL/Mesh_2/Face_badness.h>
#ifdef PREV_NDEBUG
#define NDEBUG PREV_NDEBUG
#endif
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Triangulation_vertex_base_2<K> Vb;
typedef CGAL::Delaunay_mesh_face_base_2<K> Fb;
typedef CGAL::Triangulation_data_structure_2<Vb, Fb> Tds;
typedef CGAL::Constrained_Delaunay_triangulation_2<K, Tds, CGAL::Exact_predicates_tag > CDT;
//typedef CGAL::Delaunay_mesh_criteria_2<CDT> Criteria;
typedef CDT::Vertex_handle Vertex_handle;
typedef CDT::Point CDTPoint;
#include <boost/unordered_map.hpp>
template <class T> class DummyCriteria {
public:
typedef double Quality;
class Is_bad {
public:
CGAL::Mesh_2::Face_badness operator()(const Quality) const {
return CGAL::Mesh_2::NOT_BAD;
}
CGAL::Mesh_2::Face_badness operator()(const typename T::Face_handle&, Quality&q) const {
q = 1;
return CGAL::Mesh_2::NOT_BAD;
}
};
Is_bad is_bad_object() const { return Is_bad(); }
};
struct triangle {
struct { double x, y; } p[3];
bool is_inner, is_marked;
};
struct point_info_t
{
double x, y;
int pathidx, pointidx;
int max_pointidx_in_path;
std::vector<int> triangles;
struct point_info_t *neigh_next;
struct point_info_t *neigh_prev;
point_info_t(double x, double y, int a, int b, int c) :
x(x), y(y), pathidx(a), pointidx(b), max_pointidx_in_path(c) { }
point_info_t() : x(0), y(0), pathidx(-1), pointidx(-1), max_pointidx_in_path(-1) { }
};
typedef std::pair<point_info_t*,point_info_t*> edge_t;
void mark_inner_outer(std::vector<struct triangle> &tri, Grid2d<point_info_t> &point_info,
boost::unordered_map<edge_t,int> &edge_to_triangle,
boost::unordered_map<edge_t,int> &edge_to_path, int idx, bool inner)
{
if (tri[idx].is_marked)
return;
tri[idx].is_inner = inner;
tri[idx].is_marked = true;
point_info_t *p[3] = {
&point_info.data(tri[idx].p[0].x, tri[idx].p[0].y),
&point_info.data(tri[idx].p[1].x, tri[idx].p[1].y),
&point_info.data(tri[idx].p[2].x, tri[idx].p[2].y)
};
edge_t edges[3] = {
edge_t(p[1], p[0]),
edge_t(p[2], p[1]),
edge_t(p[0], p[2])
};
for (int i = 0; i < 3; i++) {
if (edge_to_triangle.find(edges[i]) != edge_to_triangle.end()) {
bool next_inner = (edge_to_path.find(edges[i]) != edge_to_path.end()) ? !inner : inner;
mark_inner_outer(tri, point_info, edge_to_triangle, edge_to_path,
edge_to_triangle[edges[i]], next_inner);
}
}
}
void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool up, bool /* do_triangle_splitting */, double h)
{
CDT cdt;
std::vector<struct triangle> tri;
Grid2d<point_info_t> point_info(GRID_FINE);
boost::unordered_map<edge_t,int> edge_to_triangle;
boost::unordered_map<edge_t,int> edge_to_path;
int duplicate_vertices = 0;
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
try {
// read path data and copy all relevant infos
for (size_t i = 0; i < dxf.paths.size(); i++)
{
if (!dxf.paths[i].is_closed)
continue;
Vertex_handle first, prev;
struct point_info_t *first_pi = NULL, *prev_pi = NULL;
for (size_t j = 1; j < dxf.paths[i].indices.size(); j++)
{
double x = dxf.points[dxf.paths[i].indices[j]][0];
double y = dxf.points[dxf.paths[i].indices[j]][1];
if (point_info.has(x, y)) {
// FIXME: How can the same path set contain the same point twice?
// ..maybe it would be better to assert here. But this would
// break compatibility with the glu tesselator that handled such
// cases just fine.
duplicate_vertices++;
continue;
}
struct point_info_t *pi = &point_info.align(x, y);
*pi = point_info_t(x, y, i, j, dxf.paths[i].indices.size()-1);
Vertex_handle vh = cdt.insert(CDTPoint(x, y));
if (first_pi == NULL) {
first_pi = pi;
first = vh;
} else {
prev_pi->neigh_next = pi;
pi->neigh_prev = prev_pi;
edge_to_path[edge_t(prev_pi, pi)] = 1;
edge_to_path[edge_t(pi, prev_pi)] = 1;
cdt.insert_constraint(prev, vh);
}
prev_pi = pi;
prev = vh;
}
if (first_pi != NULL && first_pi != prev_pi)
{
prev_pi->neigh_next = first_pi;
first_pi->neigh_prev = prev_pi;
edge_to_path[edge_t(first_pi, prev_pi)] = 1;
edge_to_path[edge_t(prev_pi, first_pi)] = 1;
cdt.insert_constraint(prev, first);
}
}
if ( duplicate_vertices > 0 ) {
PRINT( "WARNING: Duplicate vertices and/or intersecting lines found during DXF Tessellation." );
PRINT( "WARNING: Modify the polygon to be a Simple Polygon. Render is incomplete." );
}
}
catch (const CGAL::Assertion_exception &e) {
PRINTB("CGAL error in dxf_tesselate(): %s", e.what());
CGAL::set_error_behaviour(old_behaviour);
return;
}
CGAL::set_error_behaviour(old_behaviour);
// run delaunay triangulation
std::list<CDTPoint> list_of_seeds;
CGAL::refine_Delaunay_mesh_2_without_edge_refinement(cdt,
list_of_seeds.begin(), list_of_seeds.end(), DummyCriteria<CDT>());
// copy triangulation results
CDT::Finite_faces_iterator iter = cdt.finite_faces_begin();
for(; iter != cdt.finite_faces_end(); ++iter)
{
if (!iter->is_in_domain())
continue;
int idx = tri.size();
tri.push_back(triangle());
point_info_t *pi[3];
for (int i=0; i<3; i++) {
double px = iter->vertex(i)->point()[0];
double py = iter->vertex(i)->point()[1];
pi[i] = &point_info.align(px, py);
pi[i]->triangles.push_back(idx);
tri[idx].p[i].x = px;
tri[idx].p[i].y = py;
}
edge_to_triangle[edge_t(pi[0], pi[1])] = idx;
edge_to_triangle[edge_t(pi[1], pi[2])] = idx;
edge_to_triangle[edge_t(pi[2], pi[0])] = idx;
}
// mark trianlges as inner/outer
while (1)
{
double far_left_x = 0;
struct point_info_t *far_left_p = NULL;
for (size_t i = 0; i < tri.size(); i++)
{
if (tri[i].is_marked)
continue;
for (int j = 0; j < 3; j++) {
double x = tri[i].p[j].x;
double y = tri[i].p[j].y;
if (far_left_p == NULL || x < far_left_x) {
far_left_x = x;
far_left_p = &point_info.data(x, y);
}
}
}
if (far_left_p == NULL)
break;
// find one inner triangle and run recursive marking
for (size_t i = 0; i < far_left_p->triangles.size(); i++)
{
int idx = far_left_p->triangles[i];
if (tri[idx].is_marked)
continue;
point_info_t *p0 = &point_info.data(tri[idx].p[0].x, tri[idx].p[0].y);
point_info_t *p1 = &point_info.data(tri[idx].p[1].x, tri[idx].p[1].y);
point_info_t *p2 = &point_info.data(tri[idx].p[2].x, tri[idx].p[2].y);
point_info_t *mp = NULL, *np1 = NULL, *np2 = NULL, *tp = NULL;
if (p0 == far_left_p)
mp = p0, np1 = p1, np2 = p2;
else if (p1 == far_left_p)
mp = p1, np1 = p0, np2 = p2;
else if (p2 == far_left_p)
mp = p2, np1 = p0, np2 = p1;
else
continue;
if (mp->neigh_next == np2 || mp->neigh_prev == np1) {
point_info_t *t = np1;
np1 = np2;
np2 = t;
}
if (mp->neigh_next == np1 && mp->neigh_prev == np2) {
mark_inner_outer(tri, point_info, edge_to_triangle, edge_to_path, idx, true);
goto found_and_marked_inner;
}
if (mp->neigh_next == np1)
tp = np2;
if (mp->neigh_prev == np2)
tp = np1;
if (tp != NULL) {
double z0 = (mp->neigh_next->x - mp->x) * (mp->neigh_prev->y - mp->y) -
(mp->neigh_prev->x - mp->x) * (mp->neigh_next->y - mp->y);
double z1 = (mp->neigh_next->x - mp->x) * (tp->y - mp->y) -
(tp->x - mp->x) * (mp->neigh_next->y - mp->y);
double z2 = (tp->x - mp->x) * (mp->neigh_prev->y - mp->y) -
(mp->neigh_prev->x - mp->x) * (tp->y - mp->y);
if ((z0 < 0 && z1 < 0 && z2 < 0) || (z0 > 0 && z1 > 0 && z2 > 0)) {
mark_inner_outer(tri, point_info, edge_to_triangle, edge_to_path, idx, true);
goto found_and_marked_inner;
}
}
}
// far left point is in the middle of a vertical segment
// -> it is ok to use any unmarked triangle connected to this point
for (size_t i = 0; i < far_left_p->triangles.size(); i++)
{
int idx = far_left_p->triangles[i];
if (tri[idx].is_marked)
continue;
mark_inner_outer(tri, point_info, edge_to_triangle, edge_to_path, idx, true);
break;
}
found_and_marked_inner:;
}
// add all inner triangles to target polyset
for(size_t i = 0; i < tri.size(); i++)
{
if (!tri[i].is_inner)
continue;
ps->append_poly();
int path[3], point[3];
for (int j=0;j<3;j++) {
int idx = up ? j : (2-j);
double px = tri[i].p[idx].x;
double py = tri[i].p[idx].y;
ps->append_vertex(scale[0] * (px * cos(rot*M_PI/180) + py * sin(rot*M_PI/180)),
scale[1] * (px * -sin(rot*M_PI/180) + py * cos(rot*M_PI/180)), h);
path[j] = point_info.data(px, py).pathidx;
point[j] = point_info.data(px, py).pointidx;
}
if (path[0] == path[1] && point[0] == 1 && point[1] == 2)
dxf.paths[path[0]].is_inner = up;
if (path[0] == path[1] && point[0] == 2 && point[1] == 1)
dxf.paths[path[0]].is_inner = !up;
if (path[1] == path[2] && point[1] == 1 && point[2] == 2)
dxf.paths[path[1]].is_inner = up;
if (path[1] == path[2] && point[1] == 2 && point[2] == 1)
dxf.paths[path[1]].is_inner = !up;
if (path[2] == path[0] && point[2] == 1 && point[0] == 2)
dxf.paths[path[2]].is_inner = up;
if (path[2] == path[0] && point[2] == 2 && point[0] == 1)
dxf.paths[path[2]].is_inner = !up;
}
}

View File

@ -1,400 +0,0 @@
#include "dxftess.h"
#include "dxfdata.h"
#include "polyset.h"
#include "grid.h"
#include <stdio.h>
#include <boost/foreach.hpp>
#include "system-gl.h"
#include "mathc99.h"
#ifdef WIN32
# define STDCALL __stdcall
#else
# define STDCALL
#endif
#undef DEBUG_TRIANGLE_SPLITTING
struct tess_vdata {
GLdouble v[3];
};
struct tess_triangle {
GLdouble *p[3];
tess_triangle() { p[0] = NULL; p[1] = NULL; p[2] = NULL; }
tess_triangle(double *p1, double *p2, double *p3) { p[0] = p1; p[1] = p2; p[2] = p3; }
};
static GLenum tess_type;
static int tess_count;
static std::vector<tess_triangle> tess_tri;
static GLdouble *tess_p1, *tess_p2;
static void STDCALL tess_vertex(void *vertex_data)
{
GLdouble *p = (double*)vertex_data;
#if 0
printf(" %d: %f %f %f\n", tess_count, p[0], p[1], p[2]);
#endif
if (tess_type == GL_TRIANGLE_FAN) {
if (tess_count == 0) {
tess_p1 = p;
}
if (tess_count == 1) {
tess_p2 = p;
}
if (tess_count > 1) {
tess_tri.push_back(tess_triangle(tess_p1, tess_p2, p));
tess_p2 = p;
}
}
if (tess_type == GL_TRIANGLE_STRIP) {
if (tess_count == 0) {
tess_p1 = p;
}
if (tess_count == 1) {
tess_p2 = p;
}
if (tess_count > 1) {
if (tess_count % 2 == 1) {
tess_tri.push_back(tess_triangle(tess_p2, tess_p1, p));
} else {
tess_tri.push_back(tess_triangle(tess_p1, tess_p2, p));
}
tess_p1 = tess_p2;
tess_p2 = p;
}
}
if (tess_type == GL_TRIANGLES) {
if (tess_count == 0) {
tess_p1 = p;
}
if (tess_count == 1) {
tess_p2 = p;
}
if (tess_count == 2) {
tess_tri.push_back(tess_triangle(tess_p1, tess_p2, p));
tess_count = -1;
}
}
tess_count++;
}
static void STDCALL tess_begin(GLenum type)
{
#if 0
if (type == GL_TRIANGLE_FAN) {
printf("GL_TRIANGLE_FAN:\n");
}
if (type == GL_TRIANGLE_STRIP) {
printf("GL_TRIANGLE_STRIP:\n");
}
if (type == GL_TRIANGLES) {
printf("GL_TRIANGLES:\n");
}
#endif
tess_count = 0;
tess_type = type;
}
static void STDCALL tess_end(void)
{
/* nothing to be done here */
}
static void STDCALL tess_error(GLenum errno)
{
fprintf(stderr, "GLU tesselation error %s", gluErrorString(errno));
PRINTB("GLU tesselation error %s", gluErrorString(errno));
}
static void STDCALL tess_begin_data()
{
PRINT("GLU tesselation BEGIN_DATA\n");
}
static void STDCALL tess_edge_flag(GLboolean flag)
{
// PRINT("GLU tesselation EDGE_FLAG\n");
}
static void STDCALL tess_edge_flag_data(GLboolean flag, void *polygon_data)
{
PRINT("GLU tesselation EDGE_FLAG_DATA\n");
}
static void STDCALL tess_vertex_data(void *vertex_data, void *polygon_data)
{
PRINT("GLU tesselation VERTEX_DATA\n");
}
static void STDCALL tess_end_data(void *polygon_data)
{
PRINT("GLU tesselation END_DATA\n");
}
static void STDCALL tess_combine(GLdouble coords[3], void *vertex_data[4],
GLfloat weight[4], void **outData )
{
PRINT("GLU tesselation COMBINE\n");
}
static void STDCALL tess_combine_data(GLdouble coords[3], void *vertex_data[4],
GLfloat weight[4], void **outData,
void *polygon_data)
{
PRINT("GLU tesselation COMBINE_DATA\n");
}
static void STDCALL tess_error_data(GLenum errno, void *polygon_data )
{
PRINT("GLU tesselation ERROR_DATA\n");
}
static bool point_on_line(double *p1, double *p2, double *p3)
{
if (fabs(p1[0] - p2[0]) < 0.00001 && fabs(p1[1] - p2[1]) < 0.00001)
return false;
if (fabs(p3[0] - p2[0]) < 0.00001 && fabs(p3[1] - p2[1]) < 0.00001)
return false;
double v1[2] = { p2[0] - p1[0], p2[1] - p1[1] };
double v2[2] = { p3[0] - p1[0], p3[1] - p1[1] };
if (sqrt(v1[0]*v1[0] + v1[1]*v1[1]) > sqrt(v2[0]*v2[0] + v2[1]*v2[1]))
return false;
if (fabs(v1[0]) > fabs(v1[1])) {
// y = x * dy/dx
if (v2[0] == 0 || ((v1[0] > 0) != (v2[0] > 0)))
return false;
double v1_dy_dx = v1[1] / v1[0];
double v2_dy_dx = v2[1] / v2[0];
if (fabs(v1_dy_dx - v2_dy_dx) > 1e-15)
return false;
} else {
// x = y * dx/dy
if (v2[1] == 0 || ((v1[1] > 0) != (v2[1] > 0)))
return false;
double v1_dy_dx = v1[0] / v1[1];
double v2_dy_dx = v2[0] / v2[1];
if (fabs(v1_dy_dx - v2_dy_dx) > 1e-15)
return false;
}
#if 0
printf("Point on line: %f/%f %f/%f %f/%f\n", p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]);
#endif
return true;
}
typedef std::pair<int,int> pair_ii;
inline void do_emplace( boost::unordered_multimap<int, pair_ii> &tri_by_atan2, int ai, const pair_ii &indexes)
{
#if BOOST_VERSION >= 104800
tri_by_atan2.emplace(ai, indexes);
#else
std::pair< int, pair_ii > tmp( ai, indexes );
tri_by_atan2.insert( tmp );
#endif
}
/*!
up: true if the polygon is facing in the normal direction (i.e. normal = [0,0,1])
rot: CLOCKWISE rotation around positive Z axis
*/
void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool up, bool do_triangle_splitting, double h)
{
GLUtesselator *tobj = gluNewTess();
gluTessCallback(tobj, GLU_TESS_VERTEX, (void(STDCALL *)())&tess_vertex);
gluTessCallback(tobj, GLU_TESS_BEGIN, (void(STDCALL *)())&tess_begin);
gluTessCallback(tobj, GLU_TESS_END, (void(STDCALL *)())&tess_end);
gluTessCallback(tobj, GLU_TESS_ERROR, (void(STDCALL *)())&tess_error);
gluTessCallback(tobj, GLU_TESS_EDGE_FLAG, (void(STDCALL *)())&tess_edge_flag);
// gluTessCallback(tobj, GLU_TESS_COMBINE, (void(STDCALL *)())&tess_combine);
/* gluTessCallback(tobj, GLU_TESS_BEGIN_DATA, (void(STDCALL *)())&tess_begin_data); */
/* gluTessCallback(tobj, GLU_TESS_EDGE_FLAG_DATA, (void(STDCALL *)())&tess_edge_flag_data); */
/* gluTessCallback(tobj, GLU_TESS_VERTEX_DATA, (void(STDCALL *)())&tess_vertex_data); */
/* gluTessCallback(tobj, GLU_TESS_END_DATA, (void(STDCALL *)())&tess_end_data); */
/* gluTessCallback(tobj, GLU_TESS_COMBINE_DATA, (void(STDCALL *)())&tess_combine_data); */
/* gluTessCallback(tobj, GLU_TESS_ERROR_DATA, (void(STDCALL *)())&tess_error_data); */
tess_tri.clear();
std::list<tess_vdata> vl;
gluTessBeginPolygon(tobj, NULL);
gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
if (up) {
gluTessNormal(tobj, 0, 0, -1);
} else {
gluTessNormal(tobj, 0, 0, +1);
}
Grid3d< std::pair<int,int> > point_to_path(GRID_COARSE);
for (int i = 0; i < dxf.paths.size(); i++) {
if (!dxf.paths[i].is_closed)
continue;
gluTessBeginContour(tobj);
for (int j = 1; j < dxf.paths[i].indices.size(); j++) {
point_to_path.data(dxf.points[dxf.paths[i].indices[j]][0],
dxf.points[dxf.paths[i].indices[j]][1],
h) = std::pair<int,int>(i, j);
vl.push_back(tess_vdata());
vl.back().v[0] = scale[0] * dxf.points[dxf.paths[i].indices[j]][0];
vl.back().v[1] = scale[1] * dxf.points[dxf.paths[i].indices[j]][1];
vl.back().v[2] = h;
gluTessVertex(tobj, vl.back().v, vl.back().v);
}
gluTessEndContour(tobj);
}
gluTessEndPolygon(tobj);
gluDeleteTess(tobj);
#if 0
for (int i = 0; i < tess_tri.size(); i++) {
printf("~~~\n");
printf(" %f %f %f\n", tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]);
printf(" %f %f %f\n", tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]);
printf(" %f %f %f\n", tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]);
}
#endif
// GLU tessing sometimes generates degenerated triangles. We must find and remove
// them so we can use the triangle array with CGAL..
for (int i = 0; i < tess_tri.size(); i++) {
if (point_on_line(tess_tri[i].p[0], tess_tri[i].p[1], tess_tri[i].p[2]) ||
point_on_line(tess_tri[i].p[1], tess_tri[i].p[2], tess_tri[i].p[0]) ||
point_on_line(tess_tri[i].p[2], tess_tri[i].p[0], tess_tri[i].p[1])) {
// printf("DEBUG: Removed triangle\n");
tess_tri.erase(tess_tri.begin() + i--);
}
}
// GLU tessing creates T-junctions. This is ok for GL displaying but creates
// invalid polyhedrons for CGAL. So we split this tirangles up again in order
// to create polyhedrons that are also accepted by CGAL..
// All triangle edges are sorted by their atan2 and only edges with a simmilar atan2
// value are compared. This speeds up this code block dramatically (compared to the
// n^2 compares that are neccessary in the trivial implementation).
#if 1
if (do_triangle_splitting)
{
bool added_triangles = true;
typedef std::pair<int,int> pair_ii;
boost::unordered_multimap<int, pair_ii> tri_by_atan2;
for (int i = 0; i < tess_tri.size(); i++)
for (int j = 0; j < 3; j++) {
int ai = (int)round(atan2(fabs(tess_tri[i].p[(j+1)%3][0] - tess_tri[i].p[j][0]),
fabs(tess_tri[i].p[(j+1)%3][1] - tess_tri[i].p[j][1])) / 0.001);
do_emplace( tri_by_atan2, ai, std::pair<int,int>(i, j) );
}
while (added_triangles)
{
added_triangles = false;
#ifdef DEBUG_TRIANGLE_SPLITTING
printf("*** Triangle splitting (%d) ***\n", tess_tri.size()+1);
#endif
for (int i = 0; i < tess_tri.size(); i++)
for (int k = 0; k < 3; k++)
{
boost::unordered_map<pair_ii, pair_ii> possible_neigh;
int ai = (int)floor(atan2(fabs(tess_tri[i].p[(k+1)%3][0] - tess_tri[i].p[k][0]),
fabs(tess_tri[i].p[(k+1)%3][1] - tess_tri[i].p[k][1])) / 0.001 - 0.5);
for (int j = 0; j < 2; j++) {
for (boost::unordered_multimap<int, pair_ii>::iterator it = tri_by_atan2.find(ai+j);
it != tri_by_atan2.end();
it++) {
if (i != it->first) possible_neigh[it->second] = it->second;
}
}
#ifdef DEBUG_TRIANGLE_SPLITTING
printf("%d/%d: %d\n", i, k, possible_neigh.size());
#endif
typedef std::pair<pair_ii,pair_ii> ElemPair;
BOOST_FOREACH (const ElemPair &elem, possible_neigh) {
int j = elem.first.first;
for (int l = elem.first.second; l != (elem.first.second + 2) % 3; l = (l + 1) % 3)
if (point_on_line(tess_tri[i].p[k], tess_tri[j].p[l], tess_tri[i].p[(k+1)%3])) {
#ifdef DEBUG_TRIANGLE_SPLITTING
printf("%% %f %f %f %f %f %f [%d %d]\n",
tess_tri[i].p[k][0], tess_tri[i].p[k][1],
tess_tri[j].p[l][0], tess_tri[j].p[l][1],
tess_tri[i].p[(k+1)%3][0], tess_tri[i].p[(k+1)%3][1],
i, j);
#endif
tess_tri.push_back(tess_triangle(tess_tri[j].p[l],
tess_tri[i].p[(k+1)%3], tess_tri[i].p[(k+2)%3]));
for (int m = 0; m < 2; m++) {
int ai = (int)round(atan2(fabs(tess_tri.back().p[(m+1)%3][0] - tess_tri.back().p[m][0]),
fabs(tess_tri.back().p[(m+1)%3][1] - tess_tri.back().p[m][1])) / 0.001 );
do_emplace(tri_by_atan2, ai, std::pair<int,int>(tess_tri.size()-1, m));
}
tess_tri[i].p[(k+1)%3] = tess_tri[j].p[l];
for (int m = 0; m < 2; m++) {
int ai = (int)round(atan2(fabs(tess_tri[i].p[(m+1)%3][0] - tess_tri[i].p[m][0]),
fabs(tess_tri[i].p[(m+1)%3][1] - tess_tri[i].p[m][1])) / 0.001 );
do_emplace(tri_by_atan2, ai, std::pair<int,int>(i, m));
}
added_triangles = true;
}
}
}
}
}
#endif
for (int i = 0; i < tess_tri.size(); i++)
{
#if 0
printf("---\n");
printf(" %f %f %f\n", tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]);
printf(" %f %f %f\n", tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]);
printf(" %f %f %f\n", tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]);
#endif
double x, y;
ps->append_poly();
x = tess_tri[i].p[0][0] * cos(rot*M_PI/180) + tess_tri[i].p[0][1] * sin(rot*M_PI/180);
y = tess_tri[i].p[0][0] * -sin(rot*M_PI/180) + tess_tri[i].p[0][1] * cos(rot*M_PI/180);
ps->insert_vertex(x, y, tess_tri[i].p[0][2]);
x = tess_tri[i].p[1][0] * cos(rot*M_PI/180) + tess_tri[i].p[1][1] * sin(rot*M_PI/180);
y = tess_tri[i].p[1][0] * -sin(rot*M_PI/180) + tess_tri[i].p[1][1] * cos(rot*M_PI/180);
ps->insert_vertex(x, y, tess_tri[i].p[1][2]);
x = tess_tri[i].p[2][0] * cos(rot*M_PI/180) + tess_tri[i].p[2][1] * sin(rot*M_PI/180);
y = tess_tri[i].p[2][0] * -sin(rot*M_PI/180) + tess_tri[i].p[2][1] * cos(rot*M_PI/180);
ps->insert_vertex(x, y, tess_tri[i].p[2][2]);
int i0 = point_to_path.data(tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]).first;
int j0 = point_to_path.data(tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]).second;
int i1 = point_to_path.data(tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]).first;
int j1 = point_to_path.data(tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]).second;
int i2 = point_to_path.data(tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]).first;
int j2 = point_to_path.data(tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]).second;
if (i0 == i1 && j0 == 1 && j1 == 2)
dxf.paths[i0].is_inner = !up;
if (i0 == i1 && j0 == 2 && j1 == 1)
dxf.paths[i0].is_inner = up;
if (i1 == i2 && j1 == 1 && j2 == 2)
dxf.paths[i1].is_inner = !up;
if (i1 == i2 && j1 == 2 && j2 == 1)
dxf.paths[i1].is_inner = up;
if (i2 == i0 && j2 == 1 && j0 == 2)
dxf.paths[i2].is_inner = !up;
if (i2 == i0 && j2 == 2 && j0 == 1)
dxf.paths[i2].is_inner = up;
}
tess_tri.clear();
}

View File

@ -1,59 +0,0 @@
/*
* 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 "printutils.h"
#ifdef ENABLE_CGAL
#include "dxftess-cgal.cc"
#else
#include "dxftess-glu.cc"
#endif
#if 0 // Deprecated
/*!
Converts all paths in the given DxfData to PolySet::borders polygons
without tesselating. Vertex ordering of the resulting polygons
will follow the paths' is_inner flag.
*/
void dxf_border_to_ps(PolySet *ps, const DxfData &dxf)
{
for (size_t i = 0; i < dxf.paths.size(); i++) {
const DxfData::Path &path = dxf.paths[i];
if (!path.is_closed)
continue;
ps->borders.push_back(PolySet::Polygon());
for (size_t j = 1; j < path.indices.size(); j++) {
double x = dxf.points[path.indices[j]][0], y = dxf.points[path.indices[j]][1], z = 0.0;
ps->grid.align(x, y, z);
if (path.is_inner) {
ps->borders.back().push_back(Vector3d(x, y, z));
} else {
ps->borders.back().insert(ps->borders.back().begin(), Vector3d(x, y, z));
}
}
}
}
#endif

View File

@ -1,11 +0,0 @@
#ifndef DXFTESS_H_
#define DXFTESS_H_
#include "linalg.h"
class DxfData;
class PolySet;
void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool up, bool do_triangle_splitting, double h);
void dxf_border_to_ps(PolySet *ps, const DxfData &dxf);
#endif

View File

@ -47,7 +47,7 @@ void exportFile(const class Geometry *root_geom, std::ostream &output, FileForma
export_off(N, output);
break;
case OPENSCAD_DXF:
export_dxf(N, output);
assert(false && "Export Nef polyhedron as DXF not supported");
break;
default:
assert(false && "Unknown file format");
@ -200,70 +200,6 @@ void export_off(const CGAL_Nef_polyhedron *root_N, std::ostream &output)
CGAL::set_error_behaviour(old_behaviour);
}
/*!
Saves the current 2D CGAL Nef polyhedron as DXF to the given absolute filename.
*/
void export_dxf(const CGAL_Nef_polyhedron *root_N, std::ostream &output)
{
setlocale(LC_NUMERIC, "C"); // Ensure radix is . (not ,) in output
// Some importers (e.g. Inkscape) needs a BLOCKS section to be present
output << " 0\n"
<< "SECTION\n"
<< " 2\n"
<< "BLOCKS\n"
<< " 0\n"
<< "ENDSEC\n"
<< " 0\n"
<< "SECTION\n"
<< " 2\n"
<< "ENTITIES\n";
DxfData *dd =root_N->convertToDxfData();
for (size_t i=0; i<dd->paths.size(); i++)
{
for (size_t j=1; j<dd->paths[i].indices.size(); j++) {
const Vector2d &p1 = dd->points[dd->paths[i].indices[j-1]];
const Vector2d &p2 = dd->points[dd->paths[i].indices[j]];
double x1 = p1[0];
double y1 = p1[1];
double x2 = p2[0];
double y2 = p2[1];
output << " 0\n"
<< "LINE\n";
// Some importers (e.g. Inkscape) needs a layer to be specified
output << " 8\n"
<< "0\n"
<< " 10\n"
<< x1 << "\n"
<< " 11\n"
<< x2 << "\n"
<< " 20\n"
<< y1 << "\n"
<< " 21\n"
<< y2 << "\n";
}
}
output << " 0\n"
<< "ENDSEC\n";
// Some importers (e.g. Inkscape) needs an OBJECTS section with a DICTIONARY entry
output << " 0\n"
<< "SECTION\n"
<< " 2\n"
<< "OBJECTS\n"
<< " 0\n"
<< "DICTIONARY\n"
<< " 0\n"
<< "ENDSEC\n";
output << " 0\n"
<<"EOF\n";
delete dd;
setlocale(LC_NUMERIC, ""); // Set default locale
}
#endif // ENABLE_CGAL
/*!

View File

@ -19,7 +19,6 @@ void export_png(const class Geometry *root_geom, Camera &c, std::ostream &output
void export_stl(const class CGAL_Nef_polyhedron *root_N, std::ostream &output);
void export_stl(const class PolySet *ps, std::ostream &output);
void export_off(const CGAL_Nef_polyhedron *root_N, std::ostream &output);
void export_dxf(const CGAL_Nef_polyhedron *root_N, std::ostream &output);
void export_dxf(const class Polygon2d &poly, std::ostream &output);
void export_png(const CGAL_Nef_polyhedron *root_N, Camera &c, std::ostream &output);
void export_png_with_opencsg(Tree &tree, Camera &c, std::ostream &output);

View File

@ -32,7 +32,6 @@
#include "evalcontext.h"
#include "builtin.h"
#include "dxfdata.h"
#include "dxftess.h"
#include "printutils.h"
#include "fileutils.h"
#include "handle_dep.h" // handle_dep()

View File

@ -1316,18 +1316,6 @@ void MainWindow::actionRenderDone(shared_ptr<const Geometry> root_geom)
if (const CGAL_Nef_polyhedron *N = dynamic_cast<const CGAL_Nef_polyhedron *>(root_geom.get())) {
if (!N->isNull()) {
if (N->getDimension() == 2) {
PRINT(" Top level object is a 2D object:");
PRINTB(" Empty: %6s", (N->p2->is_empty() ? "yes" : "no"));
PRINTB(" Plane: %6s", (N->p2->is_plane() ? "yes" : "no"));
PRINTB(" Vertices: %6d", N->p2->explorer().number_of_vertices());
PRINTB(" Halfedges: %6d", N->p2->explorer().number_of_halfedges());
PRINTB(" Edges: %6d", N->p2->explorer().number_of_edges());
PRINTB(" Faces: %6d", N->p2->explorer().number_of_faces());
PRINTB(" FaceCycles: %6d", N->p2->explorer().number_of_face_cycles());
PRINTB(" ConnComp: %6d", N->p2->explorer().number_of_connected_components());
}
if (N->getDimension() == 3) {
PRINT(" Top level object is a 3D object:");
PRINTB(" Simple: %6s", (N->p3->is_simple() ? "yes" : "no"));

View File

@ -52,7 +52,7 @@ namespace PolysetUtils {
// Project all polygons (also back-facing) into a Polygon2d instance.
// It's important to select all faces, since filtering by normal vector here
// will trigger floating point incertainties and cause problems later.
const Polygon2d *project(const PolySet &ps) {
Polygon2d *project(const PolySet &ps) {
Polygon2d *poly = new Polygon2d;
BOOST_FOREACH(const PolySet::Polygon &p, ps.polygons) {

View File

@ -6,7 +6,7 @@ class PolySet;
namespace PolysetUtils {
const Polygon2d *project(const PolySet &ps);
Polygon2d *project(const PolySet &ps);
void tessellate_faces(const PolySet &inps, PolySet &outps);
};

View File

@ -29,8 +29,6 @@
#include "polyset.h"
#include "evalcontext.h"
#include "Polygon2d.h"
#include "dxfdata.h"
#include "dxftess.h"
#include "builtin.h"
#include "printutils.h"
#include "visitor.h"

View File

@ -1,6 +1,6 @@
#ifdef ENABLE_CGAL
#include "cgalutils.h"
#include "svg.h"
#include "cgalutils.h"
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <map>
@ -139,6 +139,21 @@ std::string dump_cgal_nef_polyhedron2_face_svg(
return out.str();
}
static CGAL_Iso_rectangle_2e bounding_box(const CGAL_Nef_polyhedron2 &N)
{
CGAL_Iso_rectangle_2e result(0,0,0,0);
CGAL_Nef_polyhedron2::Explorer explorer = N.explorer();
CGAL_Nef_polyhedron2::Explorer::Vertex_const_iterator vi;
std::vector<CGAL_Point_2e> points;
// can be optimized by rewriting bounding_box to accept vertices
for ( vi = explorer.vertices_begin(); vi != explorer.vertices_end(); ++vi )
if ( explorer.is_standard( vi ) )
points.push_back( explorer.point( vi ) );
if (points.size())
result = CGAL::bounding_box( points.begin(), points.end() );
return result;
}
std::string dump_svg( const CGAL_Nef_polyhedron2 &N )
{
std::stringstream out;
@ -183,7 +198,7 @@ public:
CGAL_Iso_cuboid_3 bbox;
NefPoly3_dumper_svg(const CGAL_Nef_polyhedron3& N)
{
bbox = bounding_box( N );
bbox = CGALUtils::boundingBox(N);
}
void visit(CGAL_Nef_polyhedron3::Vertex_const_handle ) {}
void visit(CGAL_Nef_polyhedron3::Halfedge_const_handle ) {}

View File

@ -547,7 +547,6 @@ set(CORE_SOURCES
set(NOCGAL_SOURCES
../src/builtin.cc
../src/dxftess.cc
../src/import.cc
../src/export.cc)

View File

@ -37,7 +37,6 @@
#include "Tree.h"
#include "CGAL_Nef_polyhedron.h"
#include "GeometryEvaluator.h"
#include "CGALEvaluator.h"
#include "CGALCache.h"
#ifndef _MSC_VER