2011-07-31 03:58:51 +04:00
|
|
|
#include "CGALEvaluator.h"
|
2010-03-19 06:07:01 +03:00
|
|
|
#include "visitor.h"
|
|
|
|
#include "state.h"
|
|
|
|
#include "module.h" // FIXME: Temporarily for ModuleInstantiation
|
2010-03-31 00:39:52 +04:00
|
|
|
#include "printutils.h"
|
2010-03-19 06:07:01 +03:00
|
|
|
|
|
|
|
#include "csgnode.h"
|
2010-03-28 19:57:39 +04:00
|
|
|
#include "transformnode.h"
|
2010-03-29 05:31:47 +04:00
|
|
|
#include "polyset.h"
|
|
|
|
#include "dxfdata.h"
|
|
|
|
#include "dxftess.h"
|
2010-03-19 06:07:01 +03:00
|
|
|
|
2011-09-01 06:09:06 +04:00
|
|
|
#include "cgal.h"
|
2010-03-31 00:39:52 +04:00
|
|
|
#include <CGAL/assertions_behaviour.h>
|
|
|
|
#include <CGAL/exceptions.h>
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <map>
|
|
|
|
#include <list>
|
2010-03-19 06:07:01 +03:00
|
|
|
#include <sstream>
|
|
|
|
#include <iostream>
|
2010-03-28 19:57:39 +04:00
|
|
|
#include <assert.h>
|
2010-03-19 06:07:01 +03:00
|
|
|
#include <QRegExp>
|
|
|
|
|
2011-07-31 03:58:51 +04:00
|
|
|
CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const AbstractNode &node)
|
2010-03-19 06:07:01 +03:00
|
|
|
{
|
2010-03-29 05:31:47 +04:00
|
|
|
if (!isCached(node)) {
|
2011-07-31 03:58:51 +04:00
|
|
|
Traverser evaluate(*this, node, Traverser::PRE_AND_POSTFIX);
|
|
|
|
evaluate.execute();
|
2010-03-29 05:31:47 +04:00
|
|
|
assert(isCached(node));
|
|
|
|
}
|
2010-04-12 08:57:02 +04:00
|
|
|
return this->cache[this->tree.getString(node)];
|
2010-03-19 06:07:01 +03:00
|
|
|
}
|
|
|
|
|
2011-07-31 03:58:51 +04:00
|
|
|
bool CGALEvaluator::isCached(const AbstractNode &node) const
|
2010-03-19 06:07:01 +03:00
|
|
|
{
|
2010-04-12 08:57:02 +04:00
|
|
|
return this->cache.contains(this->tree.getString(node));
|
2010-03-19 06:07:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Modifies target by applying op to target and src:
|
|
|
|
target = target [op] src
|
|
|
|
*/
|
2011-08-13 03:48:59 +04:00
|
|
|
void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CGALEvaluator::CsgOp op)
|
2010-03-19 06:07:01 +03:00
|
|
|
{
|
2010-03-29 05:31:47 +04:00
|
|
|
if (target.dim != 2 && target.dim != 3) {
|
|
|
|
assert(false && "Dimension of Nef polyhedron must be 2 or 3");
|
|
|
|
}
|
2011-09-02 22:19:34 +04:00
|
|
|
if (src.empty()) return; // Empty polyhedron. This can happen for e.g. square([0,0])
|
2011-09-01 22:03:35 +04:00
|
|
|
assert(target.dim == src.dim);
|
2010-03-29 05:31:47 +04:00
|
|
|
|
2011-09-01 06:09:06 +04:00
|
|
|
switch (op) {
|
|
|
|
case CGE_UNION:
|
|
|
|
target += src;
|
|
|
|
break;
|
|
|
|
case CGE_INTERSECTION:
|
|
|
|
target *= src;
|
|
|
|
break;
|
|
|
|
case CGE_DIFFERENCE:
|
|
|
|
target -= src;
|
|
|
|
break;
|
|
|
|
case CGE_MINKOWSKI:
|
2011-09-01 22:03:35 +04:00
|
|
|
target.minkowski(src);
|
2011-09-01 06:09:06 +04:00
|
|
|
break;
|
|
|
|
case CGE_HULL:
|
|
|
|
//FIXME: Port convex hull to a binary operator or process it all in the end somehow
|
|
|
|
// target.p2 = convexhull2(target.p2, src.p2);
|
|
|
|
// target.p2 = convexhull2(polys);
|
|
|
|
// FIXME: Print warning: hull() not supported in 3D
|
|
|
|
break;
|
2010-03-19 06:07:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-29 05:31:47 +04:00
|
|
|
/*!
|
|
|
|
FIXME: Let caller insert into the cache since caller might modify the result
|
|
|
|
(e.g. transform)
|
|
|
|
*/
|
2011-07-31 03:58:51 +04:00
|
|
|
void CGALEvaluator::applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op)
|
2010-03-19 06:07:01 +03:00
|
|
|
{
|
2010-03-29 05:31:47 +04:00
|
|
|
CGAL_Nef_polyhedron N;
|
2010-03-28 19:57:39 +04:00
|
|
|
if (this->visitedchildren[node.index()].size() > 0) {
|
|
|
|
for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin();
|
|
|
|
iter != this->visitedchildren[node.index()].end();
|
|
|
|
iter++) {
|
|
|
|
const AbstractNode *chnode = iter->first;
|
2010-04-12 08:57:02 +04:00
|
|
|
const string &chcacheid = iter->second;
|
2010-03-28 19:57:39 +04:00
|
|
|
// FIXME: Don't use deep access to modinst members
|
|
|
|
if (chnode->modinst->tag_background) continue;
|
2010-03-29 05:31:47 +04:00
|
|
|
assert(isCached(*chnode));
|
2011-09-02 22:19:34 +04:00
|
|
|
if (N.empty()) {
|
2011-09-01 22:03:35 +04:00
|
|
|
N = this->cache[chcacheid].copy();
|
2010-03-28 19:57:39 +04:00
|
|
|
} else {
|
|
|
|
process(N, this->cache[chcacheid], op);
|
|
|
|
}
|
|
|
|
chnode->progress_report();
|
2010-03-19 06:07:01 +03:00
|
|
|
}
|
|
|
|
}
|
2011-09-01 22:03:35 +04:00
|
|
|
const std::string &cacheid = this->tree.getString(node);
|
|
|
|
this->cache.insert(cacheid, N);
|
2010-03-19 06:07:01 +03:00
|
|
|
}
|
|
|
|
|
2010-03-28 19:57:39 +04:00
|
|
|
/*
|
|
|
|
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()
|
|
|
|
*/
|
|
|
|
|
2011-07-31 03:58:51 +04:00
|
|
|
Response CGALEvaluator::visit(State &state, const AbstractNode &node)
|
2010-03-19 06:07:01 +03:00
|
|
|
{
|
2010-03-28 19:57:39 +04:00
|
|
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
2010-03-19 06:07:01 +03:00
|
|
|
if (state.isPostfix()) {
|
2011-08-13 03:48:59 +04:00
|
|
|
if (!isCached(node)) applyToChildren(node, CGE_UNION);
|
2010-03-28 19:57:39 +04:00
|
|
|
addToParent(state, node);
|
2010-03-19 06:07:01 +03:00
|
|
|
}
|
|
|
|
return ContinueTraversal;
|
|
|
|
}
|
|
|
|
|
2011-07-31 03:58:51 +04:00
|
|
|
Response CGALEvaluator::visit(State &state, const AbstractIntersectionNode &node)
|
2010-03-19 06:07:01 +03:00
|
|
|
{
|
2010-03-28 19:57:39 +04:00
|
|
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
2010-03-19 06:07:01 +03:00
|
|
|
if (state.isPostfix()) {
|
2011-08-13 03:48:59 +04:00
|
|
|
if (!isCached(node)) applyToChildren(node, CGE_INTERSECTION);
|
2010-03-28 19:57:39 +04:00
|
|
|
addToParent(state, node);
|
2010-03-19 06:07:01 +03:00
|
|
|
}
|
|
|
|
return ContinueTraversal;
|
|
|
|
}
|
|
|
|
|
2011-07-31 03:58:51 +04:00
|
|
|
Response CGALEvaluator::visit(State &state, const CsgNode &node)
|
2010-03-19 06:07:01 +03:00
|
|
|
{
|
2010-03-28 19:57:39 +04:00
|
|
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
2010-03-19 06:07:01 +03:00
|
|
|
if (state.isPostfix()) {
|
2010-03-28 19:57:39 +04:00
|
|
|
if (!isCached(node)) {
|
2011-08-13 03:48:59 +04:00
|
|
|
CGALEvaluator::CsgOp op;
|
2010-03-28 19:57:39 +04:00
|
|
|
switch (node.type) {
|
|
|
|
case CSG_TYPE_UNION:
|
2011-08-13 03:48:59 +04:00
|
|
|
op = CGE_UNION;
|
2010-03-28 19:57:39 +04:00
|
|
|
break;
|
|
|
|
case CSG_TYPE_DIFFERENCE:
|
2011-08-13 03:48:59 +04:00
|
|
|
op = CGE_DIFFERENCE;
|
2010-03-28 19:57:39 +04:00
|
|
|
break;
|
|
|
|
case CSG_TYPE_INTERSECTION:
|
2011-08-13 03:48:59 +04:00
|
|
|
op = CGE_INTERSECTION;
|
2010-03-28 19:57:39 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
applyToChildren(node, op);
|
|
|
|
}
|
|
|
|
addToParent(state, node);
|
2010-03-19 06:07:01 +03:00
|
|
|
}
|
|
|
|
return ContinueTraversal;
|
|
|
|
}
|
|
|
|
|
2011-07-31 03:58:51 +04:00
|
|
|
Response CGALEvaluator::visit(State &state, const TransformNode &node)
|
2010-03-19 06:07:01 +03:00
|
|
|
{
|
2010-03-28 19:57:39 +04:00
|
|
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
|
|
|
if (state.isPostfix()) {
|
|
|
|
if (!isCached(node)) {
|
|
|
|
// First union all children
|
2011-08-13 03:48:59 +04:00
|
|
|
applyToChildren(node, CGE_UNION);
|
2010-03-29 05:31:47 +04:00
|
|
|
|
|
|
|
// Then apply transform
|
2010-04-12 08:57:02 +04:00
|
|
|
CGAL_Nef_polyhedron N = this->cache[this->tree.getString(node)];
|
2010-07-09 02:47:43 +04:00
|
|
|
// If there is no geometry under the transform, N will be empty and of dim 0,
|
|
|
|
// just just silently ignore such nodes
|
2010-03-29 05:31:47 +04:00
|
|
|
if (N.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!
|
|
|
|
|
|
|
|
CGAL_Aff_transformation2 t(
|
2010-09-07 04:01:51 +04:00
|
|
|
node.matrix[0], node.matrix[4], node.matrix[12],
|
|
|
|
node.matrix[1], node.matrix[5], node.matrix[13], node.matrix[15]);
|
2010-03-29 05:31:47 +04:00
|
|
|
|
2011-09-01 06:09:06 +04:00
|
|
|
DxfData *dd = N.convertToDxfData();
|
2011-09-04 22:34:17 +04:00
|
|
|
for (size_t i=0; i < dd->points.size(); i++) {
|
2011-09-01 06:09:06 +04:00
|
|
|
CGAL_Kernel2::Point_2 p = CGAL_Kernel2::Point_2(dd->points[i][0], dd->points[i][1]);
|
2010-03-29 05:31:47 +04:00
|
|
|
p = t.transform(p);
|
2011-09-01 06:09:06 +04:00
|
|
|
dd->points[i][0] = to_double(p.x());
|
|
|
|
dd->points[i][1] = to_double(p.y());
|
2010-03-29 05:31:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
PolySet ps;
|
|
|
|
ps.is2d = true;
|
2011-09-01 19:03:34 +04:00
|
|
|
dxf_tesselate(&ps, *dd, 0, true, false, 0);
|
2010-03-29 05:31:47 +04:00
|
|
|
|
2011-07-31 03:58:51 +04:00
|
|
|
N = evaluateCGALMesh(ps);
|
2010-03-29 05:31:47 +04:00
|
|
|
ps.refcount = 0;
|
2011-09-01 06:09:06 +04:00
|
|
|
delete dd;
|
2010-03-29 05:31:47 +04:00
|
|
|
}
|
|
|
|
else if (N.dim == 3) {
|
|
|
|
CGAL_Aff_transformation t(
|
2010-09-07 04:01:51 +04:00
|
|
|
node.matrix[0], node.matrix[4], node.matrix[ 8], node.matrix[12],
|
|
|
|
node.matrix[1], node.matrix[5], node.matrix[ 9], node.matrix[13],
|
|
|
|
node.matrix[2], node.matrix[6], node.matrix[10], node.matrix[14], node.matrix[15]);
|
2011-09-01 06:09:06 +04:00
|
|
|
N.p3->transform(t);
|
2010-03-29 05:31:47 +04:00
|
|
|
}
|
2011-09-01 22:03:35 +04:00
|
|
|
const std::string &cacheid = this->tree.getString(node);
|
|
|
|
this->cache.insert(cacheid, N);
|
2010-03-28 19:57:39 +04:00
|
|
|
}
|
|
|
|
addToParent(state, node);
|
|
|
|
}
|
2010-03-19 06:07:01 +03:00
|
|
|
return ContinueTraversal;
|
|
|
|
}
|
|
|
|
|
2011-07-31 03:58:51 +04:00
|
|
|
// FIXME: EvaluateNode: Union over children + some magic
|
2010-03-19 06:07:01 +03:00
|
|
|
// FIXME: CgaladvNode: Iterate over children. Special operation
|
|
|
|
|
|
|
|
// FIXME: Subtypes of AbstractPolyNode:
|
|
|
|
// ProjectionNode
|
|
|
|
// DxfLinearExtrudeNode
|
|
|
|
// DxfRotateExtrudeNode
|
|
|
|
// (SurfaceNode)
|
|
|
|
// (PrimitiveNode)
|
2011-07-31 03:58:51 +04:00
|
|
|
Response CGALEvaluator::visit(State &state, const AbstractPolyNode &node)
|
2010-03-19 06:07:01 +03:00
|
|
|
{
|
2010-03-28 19:57:39 +04:00
|
|
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
|
|
|
if (state.isPostfix()) {
|
|
|
|
if (!isCached(node)) {
|
2010-03-29 05:31:47 +04:00
|
|
|
// First union all children
|
2011-08-13 03:48:59 +04:00
|
|
|
applyToChildren(node, CGE_UNION);
|
2010-03-28 19:57:39 +04:00
|
|
|
|
2010-03-29 05:31:47 +04:00
|
|
|
// Then apply polyset operation
|
2011-07-31 03:58:51 +04:00
|
|
|
PolySet *ps = node.evaluate_polyset(AbstractPolyNode::RENDER_CGAL, &this->psevaluator);
|
2010-11-08 01:50:57 +03:00
|
|
|
if (ps) {
|
|
|
|
try {
|
2011-07-31 03:58:51 +04:00
|
|
|
CGAL_Nef_polyhedron N = evaluateCGALMesh(*ps);
|
2010-03-29 05:31:47 +04:00
|
|
|
// print_messages_pop();
|
2010-11-08 01:50:57 +03:00
|
|
|
node.progress_report();
|
|
|
|
|
|
|
|
ps->unlink();
|
2011-09-01 22:03:35 +04:00
|
|
|
const std::string &cacheid = this->tree.getString(node);
|
|
|
|
this->cache.insert(cacheid, N);
|
2010-11-08 01:50:57 +03:00
|
|
|
}
|
|
|
|
catch (...) { // Don't leak the PolySet on ProgressCancelException
|
|
|
|
ps->unlink();
|
|
|
|
throw;
|
|
|
|
}
|
2010-03-29 05:31:47 +04:00
|
|
|
}
|
2010-03-28 19:57:39 +04:00
|
|
|
}
|
|
|
|
addToParent(state, node);
|
2010-03-19 06:07:01 +03:00
|
|
|
}
|
|
|
|
return ContinueTraversal;
|
|
|
|
}
|
|
|
|
|
2010-03-28 19:57:39 +04:00
|
|
|
/*!
|
|
|
|
Adds ourself to out parent's list of traversed children.
|
|
|
|
Call this for _every_ node which affects output during the postfix traversal.
|
|
|
|
*/
|
2011-07-31 03:58:51 +04:00
|
|
|
void CGALEvaluator::addToParent(const State &state, const AbstractNode &node)
|
2010-03-19 06:07:01 +03:00
|
|
|
{
|
2010-03-28 19:57:39 +04:00
|
|
|
assert(state.isPostfix());
|
|
|
|
this->visitedchildren.erase(node.index());
|
2010-04-12 04:16:36 +04:00
|
|
|
if (state.parent()) {
|
2010-04-12 08:57:02 +04:00
|
|
|
this->visitedchildren[state.parent()->index()].push_back(std::make_pair(&node, this->tree.getString(node)));
|
2010-03-19 06:07:01 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-29 05:31:47 +04:00
|
|
|
#if 0
|
|
|
|
/*!
|
2011-07-31 03:58:51 +04:00
|
|
|
Static function to evaluate CGAL meshes.
|
2010-03-29 05:31:47 +04:00
|
|
|
NB! This is just a support function used for development and debugging
|
|
|
|
*/
|
2011-07-31 03:58:51 +04:00
|
|
|
CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const AbstractPolyNode &node)
|
2010-03-29 05:31:47 +04:00
|
|
|
{
|
|
|
|
// FIXME: Lookup Nef polyhedron in cache.
|
|
|
|
|
|
|
|
// print_messages_push();
|
|
|
|
|
2011-07-31 03:58:51 +04:00
|
|
|
PolySet *ps = node.evaluate_polyset(AbstractPolyNode::RENDER_CGAL);
|
2010-11-08 01:50:57 +03:00
|
|
|
if (ps) {
|
|
|
|
try {
|
2011-07-31 03:58:51 +04:00
|
|
|
CGAL_Nef_polyhedron N = ps->evaluateCSGMesh();
|
2010-11-08 01:50:57 +03:00
|
|
|
// FIXME: Insert into cache
|
|
|
|
// print_messages_pop();
|
|
|
|
node.progress_report();
|
|
|
|
|
|
|
|
ps->unlink();
|
|
|
|
return N;
|
|
|
|
}
|
|
|
|
catch (...) { // Don't leak the PolySet on ProgressCancelException
|
|
|
|
ps->unlink();
|
|
|
|
throw;
|
|
|
|
}
|
2010-03-29 05:31:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ENABLE_CGAL
|
|
|
|
|
|
|
|
#undef GEN_SURFACE_DEBUG
|
|
|
|
|
|
|
|
class CGAL_Build_PolySet : public CGAL::Modifier_base<CGAL_HDS>
|
|
|
|
{
|
|
|
|
public:
|
2011-08-05 04:11:20 +04:00
|
|
|
typedef CGAL_HDS::Vertex::Point CGALPoint;
|
2010-03-29 05:31:47 +04:00
|
|
|
|
|
|
|
const PolySet &ps;
|
|
|
|
CGAL_Build_PolySet(const PolySet &ps) : ps(ps) { }
|
|
|
|
|
|
|
|
void operator()(CGAL_HDS& hds)
|
|
|
|
{
|
|
|
|
CGAL_Polybuilder B(hds, true);
|
|
|
|
|
2011-09-04 22:34:17 +04:00
|
|
|
std::vector<CGALPoint> vertices;
|
2010-03-29 05:31:47 +04:00
|
|
|
Grid3d<int> vertices_idx(GRID_FINE);
|
|
|
|
|
2011-08-05 04:11:20 +04:00
|
|
|
for (size_t i = 0; i < ps.polygons.size(); i++) {
|
2010-03-29 05:31:47 +04:00
|
|
|
const PolySet::Polygon *poly = &ps.polygons[i];
|
2011-08-05 04:11:20 +04:00
|
|
|
for (size_t j = 0; j < poly->size(); j++) {
|
|
|
|
const Vector3d &p = poly->at(j);
|
|
|
|
if (!vertices_idx.has(p[0], p[1], p[2])) {
|
|
|
|
vertices_idx.data(p[0], p[1], p[2]) = vertices.size();
|
2011-09-04 22:34:17 +04:00
|
|
|
vertices.push_back(CGALPoint(p[0], p[1], p[2]));
|
2010-03-29 05:31:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
B.begin_surface(vertices.size(), ps.polygons.size());
|
|
|
|
#ifdef GEN_SURFACE_DEBUG
|
|
|
|
printf("=== CGAL Surface ===\n");
|
|
|
|
#endif
|
|
|
|
|
2011-08-05 04:11:20 +04:00
|
|
|
for (size_t i = 0; i < vertices.size(); i++) {
|
|
|
|
const CGALPoint &p = vertices[i];
|
|
|
|
B.add_vertex(p);
|
2010-03-29 05:31:47 +04:00
|
|
|
#ifdef GEN_SURFACE_DEBUG
|
2011-08-05 04:11:20 +04:00
|
|
|
printf("%d: %f %f %f\n", i, p[0], p[1], p[2]);
|
2010-03-29 05:31:47 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2011-08-05 04:11:20 +04:00
|
|
|
for (size_t i = 0; i < ps.polygons.size(); i++) {
|
2010-03-29 05:31:47 +04:00
|
|
|
const PolySet::Polygon *poly = &ps.polygons[i];
|
|
|
|
QHash<int,int> fc;
|
|
|
|
bool facet_is_degenerated = false;
|
2011-08-05 04:11:20 +04:00
|
|
|
for (size_t j = 0; j < poly->size(); j++) {
|
|
|
|
const Vector3d &p = poly->at(j);
|
|
|
|
int v = vertices_idx.data(p[0], p[1], p[2]);
|
2010-03-29 05:31:47 +04:00
|
|
|
if (fc[v]++ > 0)
|
|
|
|
facet_is_degenerated = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!facet_is_degenerated)
|
|
|
|
B.begin_facet();
|
|
|
|
#ifdef GEN_SURFACE_DEBUG
|
|
|
|
printf("F:");
|
|
|
|
#endif
|
2011-08-05 04:11:20 +04:00
|
|
|
for (size_t j = 0; j < poly->size(); j++) {
|
|
|
|
const Vector3d &p = poly->at(j);
|
2010-03-29 05:31:47 +04:00
|
|
|
#ifdef GEN_SURFACE_DEBUG
|
2011-08-05 04:11:20 +04:00
|
|
|
printf(" %d (%f,%f,%f)", vertices_idx.data(p[0], p[1], p[2]), p[0], p[1], p[2]);
|
2010-03-29 05:31:47 +04:00
|
|
|
#endif
|
|
|
|
if (!facet_is_degenerated)
|
2011-08-05 04:11:20 +04:00
|
|
|
B.add_vertex_to_facet(vertices_idx.data(p[0], p[1], p[2]));
|
2010-03-29 05:31:47 +04:00
|
|
|
}
|
|
|
|
#ifdef GEN_SURFACE_DEBUG
|
|
|
|
if (facet_is_degenerated)
|
|
|
|
printf(" (degenerated)");
|
|
|
|
printf("\n");
|
|
|
|
#endif
|
|
|
|
if (!facet_is_degenerated)
|
|
|
|
B.end_facet();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef GEN_SURFACE_DEBUG
|
|
|
|
printf("====================\n");
|
|
|
|
#endif
|
|
|
|
B.end_surface();
|
|
|
|
|
|
|
|
#undef PointKey
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* ENABLE_CGAL */
|
|
|
|
|
2011-07-31 03:58:51 +04:00
|
|
|
CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps)
|
2010-03-29 05:31:47 +04:00
|
|
|
{
|
2011-09-02 00:43:14 +04:00
|
|
|
if (ps.empty()) return CGAL_Nef_polyhedron();
|
|
|
|
|
2010-03-29 05:31:47 +04:00
|
|
|
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 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 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;
|
|
|
|
QHash< QPair<int,int>, QPair<int,int> > egde_to_poly;
|
|
|
|
QHash< int, CGAL_Nef_polyhedron2::Point > points;
|
|
|
|
QHash< int, QList<int> > polygons;
|
|
|
|
int poly_n;
|
|
|
|
|
|
|
|
void add_edges(int pn)
|
|
|
|
{
|
|
|
|
for (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->egde_to_poly[QPair<int,int>(a, b)].first == 0)
|
|
|
|
this->egde_to_poly[QPair<int,int>(a, b)].first = pn;
|
|
|
|
else if (this->egde_to_poly[QPair<int,int>(a, b)].second == 0)
|
|
|
|
this->egde_to_poly[QPair<int,int>(a, b)].second = pn;
|
|
|
|
else
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void del_poly(int pn)
|
|
|
|
{
|
|
|
|
for (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->egde_to_poly[QPair<int,int>(a, b)].first == pn)
|
|
|
|
this->egde_to_poly[QPair<int,int>(a, b)].first = 0;
|
|
|
|
if (this->egde_to_poly[QPair<int,int>(a, b)].second == pn)
|
|
|
|
this->egde_to_poly[QPair<int,int>(a, b)].second = 0;
|
|
|
|
}
|
|
|
|
this->polygons.remove(pn);
|
|
|
|
}
|
|
|
|
|
|
|
|
PolyReducer(const PolySet &ps) : grid(GRID_COARSE), poly_n(1)
|
|
|
|
{
|
|
|
|
int point_n = 1;
|
2011-08-05 04:11:20 +04:00
|
|
|
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];
|
2010-03-29 05:31:47 +04:00
|
|
|
if (this->grid.has(x, y)) {
|
|
|
|
this->polygons[this->poly_n].append(this->grid.data(x, y));
|
|
|
|
} else {
|
|
|
|
this->grid.align(x, y) = point_n;
|
|
|
|
this->polygons[this->poly_n].append(point_n);
|
|
|
|
this->points[point_n] = CGAL_Nef_polyhedron2::Point(x, y);
|
|
|
|
point_n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
add_edges(this->poly_n);
|
|
|
|
this->poly_n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int merge(int p1, int p1e, int p2, int p2e)
|
|
|
|
{
|
|
|
|
for (int i = 1; i < this->polygons[p1].size(); i++) {
|
|
|
|
int j = (p1e + i) % this->polygons[p1].size();
|
|
|
|
this->polygons[this->poly_n].append(this->polygons[p1][j]);
|
|
|
|
}
|
|
|
|
for (int i = 1; i < this->polygons[p2].size(); i++) {
|
|
|
|
int j = (p2e + i) % this->polygons[p2].size();
|
|
|
|
this->polygons[this->poly_n].append(this->polygons[p2][j]);
|
|
|
|
}
|
|
|
|
del_poly(p1);
|
|
|
|
del_poly(p2);
|
|
|
|
add_edges(this->poly_n);
|
|
|
|
return this->poly_n++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void reduce()
|
|
|
|
{
|
|
|
|
QList<int> work_queue;
|
|
|
|
QHashIterator< int, QList<int> > it(polygons);
|
|
|
|
while (it.hasNext()) {
|
|
|
|
it.next();
|
|
|
|
work_queue.append(it.key());
|
|
|
|
}
|
|
|
|
while (!work_queue.isEmpty()) {
|
|
|
|
int poly1_n = work_queue.first();
|
|
|
|
work_queue.removeFirst();
|
|
|
|
if (!this->polygons.contains(poly1_n))
|
|
|
|
continue;
|
|
|
|
for (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->egde_to_poly[QPair<int,int>(a, b)].first != 0 &&
|
|
|
|
this->egde_to_poly[QPair<int,int>(a, b)].second != 0) {
|
|
|
|
int poly2_n = this->egde_to_poly[QPair<int,int>(a, b)].first +
|
|
|
|
this->egde_to_poly[QPair<int,int>(a, b)].second - poly1_n;
|
|
|
|
int poly2_edge = -1;
|
|
|
|
for (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->egde_to_poly[QPair<int,int>(c, d)].first +
|
|
|
|
this->egde_to_poly[QPair<int,int>(c, d)].second - poly2_n;
|
|
|
|
if (poly3_n < 0)
|
|
|
|
continue;
|
|
|
|
if (poly3_n == poly1_n)
|
|
|
|
goto next_poly1_edge;
|
|
|
|
}
|
|
|
|
work_queue.append(merge(poly1_n, j-1, poly2_n, poly2_edge));
|
|
|
|
goto next_poly1;
|
|
|
|
}
|
|
|
|
next_poly1_edge:;
|
|
|
|
}
|
|
|
|
next_poly1:;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-01 06:09:06 +04:00
|
|
|
CGAL_Nef_polyhedron2 *toNef()
|
2010-03-29 05:31:47 +04:00
|
|
|
{
|
2011-09-01 06:09:06 +04:00
|
|
|
CGAL_Nef_polyhedron2 *N = new CGAL_Nef_polyhedron2;
|
2010-03-29 05:31:47 +04:00
|
|
|
|
|
|
|
QHashIterator< int, QList<int> > it(polygons);
|
|
|
|
while (it.hasNext()) {
|
|
|
|
it.next();
|
|
|
|
std::list<CGAL_Nef_polyhedron2::Point> plist;
|
|
|
|
for (int j = 0; j < it.value().size(); j++) {
|
|
|
|
int p = it.value()[j];
|
|
|
|
plist.push_back(points[p]);
|
|
|
|
}
|
2011-09-01 06:09:06 +04:00
|
|
|
*N += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED);
|
2010-03-29 05:31:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return N;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
PolyReducer pr(ps);
|
|
|
|
// printf("Number of polygons before reduction: %d\n", pr.polygons.size());
|
|
|
|
pr.reduce();
|
|
|
|
// printf("Number of polygons after reduction: %d\n", pr.polygons.size());
|
|
|
|
return 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 CGAL_Nef_polyhedron(N);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
2010-03-31 00:39:52 +04:00
|
|
|
else // not (this->is2d)
|
2010-03-29 05:31:47 +04:00
|
|
|
{
|
2010-03-31 00:39:52 +04:00
|
|
|
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
|
|
|
try {
|
2010-03-29 05:31:47 +04:00
|
|
|
CGAL_Polyhedron P;
|
|
|
|
CGAL_Build_PolySet builder(ps);
|
|
|
|
P.delegate(builder);
|
|
|
|
#if 0
|
|
|
|
std::cout << P;
|
|
|
|
#endif
|
2011-09-01 06:09:06 +04:00
|
|
|
CGAL_Nef_polyhedron3 *N = new CGAL_Nef_polyhedron3(P);
|
2010-03-29 05:31:47 +04:00
|
|
|
return CGAL_Nef_polyhedron(N);
|
2010-03-31 00:39:52 +04:00
|
|
|
}
|
|
|
|
catch (CGAL::Assertion_exception e) {
|
2011-09-02 22:19:34 +04:00
|
|
|
PRINTF("CGAL error: %s", e.what());
|
2010-03-31 00:39:52 +04:00
|
|
|
CGAL::set_error_behaviour(old_behaviour);
|
|
|
|
return CGAL_Nef_polyhedron();
|
|
|
|
}
|
2010-03-29 05:31:47 +04:00
|
|
|
}
|
|
|
|
return CGAL_Nef_polyhedron();
|
|
|
|
}
|