mirror of https://github.com/vitalif/openscad
Cleanup: Removed redundant code
parent
0e5037dce3
commit
ace3668736
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -35,7 +35,6 @@
|
|||
|
||||
#include "CGALRenderer.h"
|
||||
#include "CGAL_renderer.h"
|
||||
#include "dxftess.h"
|
||||
#include "CGAL_Nef_polyhedron.h"
|
||||
#include "cgal.h"
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
382
src/cgalutils.cc
382
src/cgalutils.cc
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
||||
/*!
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
};
|
||||
|
|
|
@ -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"
|
||||
|
|
19
src/svg.cc
19
src/svg.cc
|
@ -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 ) {}
|
||||
|
|
|
@ -547,7 +547,6 @@ set(CORE_SOURCES
|
|||
|
||||
set(NOCGAL_SOURCES
|
||||
../src/builtin.cc
|
||||
../src/dxftess.cc
|
||||
../src/import.cc
|
||||
../src/export.cc)
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
#include "Tree.h"
|
||||
#include "CGAL_Nef_polyhedron.h"
|
||||
#include "GeometryEvaluator.h"
|
||||
#include "CGALEvaluator.h"
|
||||
#include "CGALCache.h"
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
|
Loading…
Reference in New Issue