312 lines
8.7 KiB
C++
312 lines
8.7 KiB
C++
|
// Begin License:
|
||
|
// Copyright (C) 2006-2008 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||
|
// All rights reserved.
|
||
|
//
|
||
|
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||
|
//
|
||
|
// This file may be used under the terms of the GNU General Public
|
||
|
// License version 2.0 as published by the Free Software Foundation
|
||
|
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||
|
// this file.
|
||
|
//
|
||
|
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||
|
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||
|
// A PARTICULAR PURPOSE.
|
||
|
// End:
|
||
|
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <carve/carve.hpp>
|
||
|
|
||
|
#include <carve/matrix.hpp>
|
||
|
#include <carve/timing.hpp>
|
||
|
#include <carve/rescale.hpp>
|
||
|
|
||
|
namespace carve {
|
||
|
namespace csg {
|
||
|
|
||
|
class CSG_TreeNode {
|
||
|
CSG_TreeNode(const CSG_TreeNode &);
|
||
|
CSG_TreeNode &operator=(const CSG_TreeNode &);
|
||
|
|
||
|
protected:
|
||
|
|
||
|
public:
|
||
|
CSG_TreeNode() {
|
||
|
}
|
||
|
|
||
|
virtual ~CSG_TreeNode() {
|
||
|
}
|
||
|
|
||
|
virtual carve::poly::Polyhedron *eval(bool &is_temp, CSG &csg) =0;
|
||
|
|
||
|
virtual carve::poly::Polyhedron *eval(CSG &csg) {
|
||
|
bool temp;
|
||
|
carve::poly::Polyhedron *r = eval(temp, csg);
|
||
|
if (!temp) r = new carve::poly::Polyhedron(*r);
|
||
|
return r;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
class CSG_TransformNode : public CSG_TreeNode {
|
||
|
carve::math::Matrix transform;
|
||
|
CSG_TreeNode *child;
|
||
|
|
||
|
public:
|
||
|
CSG_TransformNode(const carve::math::Matrix &_transform, CSG_TreeNode *_child) : transform(_transform), child(_child) {
|
||
|
}
|
||
|
virtual ~CSG_TransformNode() {
|
||
|
delete child;
|
||
|
}
|
||
|
|
||
|
virtual carve::poly::Polyhedron *eval(bool &is_temp, CSG &csg) {
|
||
|
carve::poly::Polyhedron *result = child->eval(is_temp, csg);
|
||
|
if (!is_temp) {
|
||
|
result = new carve::poly::Polyhedron(*result);
|
||
|
is_temp = true;
|
||
|
}
|
||
|
result->transform(transform);
|
||
|
return result;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
class CSG_InvertNode : public CSG_TreeNode {
|
||
|
std::vector<bool> selected_groups;
|
||
|
CSG_TreeNode *child;
|
||
|
|
||
|
public:
|
||
|
CSG_InvertNode(CSG_TreeNode *_child) : selected_groups(), child(_child) {
|
||
|
}
|
||
|
CSG_InvertNode(int g_id, CSG_TreeNode *_child) : selected_groups(), child(_child) {
|
||
|
selected_groups.resize(g_id + 1, false);
|
||
|
selected_groups[g_id] = true;
|
||
|
}
|
||
|
virtual ~CSG_InvertNode() {
|
||
|
delete child;
|
||
|
}
|
||
|
|
||
|
template<typename T>
|
||
|
CSG_InvertNode(T start, T end, CSG_TreeNode *_child) : selected_groups(), child(_child) {
|
||
|
while (start != end) {
|
||
|
int g_id = (int)(*start);
|
||
|
if (selected_groups.size() < g_id + 1) selected_groups.resize(g_id + 1, false);
|
||
|
selected_groups[g_id] = true;
|
||
|
++start;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
virtual carve::poly::Polyhedron *eval(bool &is_temp, CSG &csg) {
|
||
|
bool c_temp;
|
||
|
carve::poly::Polyhedron *c = child->eval(c_temp, csg);
|
||
|
carve::poly::Polyhedron *result;
|
||
|
if (!c_temp) {
|
||
|
result = new carve::poly::Polyhedron(*c);
|
||
|
} else {
|
||
|
result = c;
|
||
|
}
|
||
|
if (!selected_groups.size()) {
|
||
|
result->invertAll();
|
||
|
} else {
|
||
|
result->invert(selected_groups);
|
||
|
}
|
||
|
is_temp = true;
|
||
|
return result;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
class CSG_SelectNode : public CSG_TreeNode {
|
||
|
std::vector<bool> selected_manifolds;
|
||
|
CSG_TreeNode *child;
|
||
|
|
||
|
public:
|
||
|
CSG_SelectNode(int m_id, CSG_TreeNode *_child) : selected_manifolds(), child(_child) {
|
||
|
selected_manifolds.resize(m_id + 1, false);
|
||
|
selected_manifolds[m_id] = true;
|
||
|
}
|
||
|
|
||
|
template<typename T>
|
||
|
CSG_SelectNode(T start, T end, CSG_TreeNode *_child) : selected_manifolds(), child(_child) {
|
||
|
while (start != end) {
|
||
|
int m_id = (int)(*start);
|
||
|
if ((int)selected_manifolds.size() < m_id + 1) selected_manifolds.resize(m_id + 1, false);
|
||
|
selected_manifolds[m_id] = true;
|
||
|
++start;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
virtual ~CSG_SelectNode() {
|
||
|
delete child;
|
||
|
}
|
||
|
|
||
|
virtual carve::poly::Polyhedron *eval(bool &is_temp, CSG &csg) {
|
||
|
bool c_temp;
|
||
|
carve::poly::Polyhedron *c = child->eval(c_temp, csg);
|
||
|
carve::poly::Polyhedron *result = new carve::poly::Polyhedron(*c, selected_manifolds);
|
||
|
if (c_temp) delete c;
|
||
|
is_temp = true;
|
||
|
return result;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
class CSG_PolyNode : public CSG_TreeNode {
|
||
|
carve::poly::Polyhedron *poly;
|
||
|
bool del;
|
||
|
|
||
|
public:
|
||
|
CSG_PolyNode(carve::poly::Polyhedron *_poly, bool _del) : poly(_poly), del(_del) {
|
||
|
}
|
||
|
virtual ~CSG_PolyNode() {
|
||
|
static carve::TimingName FUNC_NAME("delete polyhedron");
|
||
|
carve::TimingBlock block(FUNC_NAME);
|
||
|
|
||
|
if (del) delete poly;
|
||
|
}
|
||
|
|
||
|
virtual carve::poly::Polyhedron *eval(bool &is_temp, CSG &csg) {
|
||
|
is_temp = false;
|
||
|
return poly;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
class CSG_OPNode : public CSG_TreeNode {
|
||
|
CSG_TreeNode *left, *right;
|
||
|
CSG::OP op;
|
||
|
bool rescale;
|
||
|
CSG::CLASSIFY_TYPE classify_type;
|
||
|
|
||
|
public:
|
||
|
CSG_OPNode(CSG_TreeNode *_left,
|
||
|
CSG_TreeNode *_right,
|
||
|
CSG::OP _op,
|
||
|
bool _rescale,
|
||
|
CSG::CLASSIFY_TYPE _classify_type = CSG::CLASSIFY_NORMAL) : left(_left), right(_right), op(_op), rescale(_rescale), classify_type(_classify_type) {
|
||
|
}
|
||
|
|
||
|
virtual ~CSG_OPNode() {
|
||
|
delete left;
|
||
|
delete right;
|
||
|
}
|
||
|
|
||
|
void minmax(double &min_x, double &min_y, double &min_z,
|
||
|
double &max_x, double &max_y, double &max_z,
|
||
|
const std::vector<carve::geom3d::Vector> &points) {
|
||
|
for (unsigned i = 1; i < points.size(); ++i) {
|
||
|
min_x = std::min(min_x, points[i].x);
|
||
|
max_x = std::max(max_x, points[i].x);
|
||
|
min_y = std::min(min_y, points[i].y);
|
||
|
max_y = std::max(max_y, points[i].y);
|
||
|
min_z = std::min(min_z, points[i].z);
|
||
|
max_z = std::max(max_z, points[i].z);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
virtual carve::poly::Polyhedron *evalScaled(bool &is_temp, CSG &csg) {
|
||
|
carve::poly::Polyhedron *l, *r;
|
||
|
bool l_temp, r_temp;
|
||
|
|
||
|
l = left->eval(l_temp, csg);
|
||
|
r = right->eval(r_temp, csg);
|
||
|
|
||
|
if (!l_temp) { l = new carve::poly::Polyhedron(*l); }
|
||
|
if (!r_temp) { r = new carve::poly::Polyhedron(*r); }
|
||
|
|
||
|
carve::geom3d::Vector min, max;
|
||
|
carve::geom3d::Vector min_l, max_l;
|
||
|
carve::geom3d::Vector min_r, max_r;
|
||
|
|
||
|
carve::geom::bounds<3>(l->vertices.begin(),
|
||
|
l->vertices.end(),
|
||
|
carve::poly::vec_adapt_vertex_ref(),
|
||
|
min_l,
|
||
|
max_l);
|
||
|
carve::geom::bounds<3>(r->vertices.begin(),
|
||
|
r->vertices.end(),
|
||
|
carve::poly::vec_adapt_vertex_ref(),
|
||
|
min_r,
|
||
|
max_r);
|
||
|
|
||
|
carve::geom::assign_op(min, min_l, min_r, carve::util::min_functor());
|
||
|
carve::geom::assign_op(max, max_l, max_r, carve::util::max_functor());
|
||
|
|
||
|
carve::rescale::rescale scaler(min.x, min.y, min.z, max.x, max.y, max.z);
|
||
|
|
||
|
carve::rescale::fwd fwd_r(scaler);
|
||
|
carve::rescale::rev rev_r(scaler);
|
||
|
|
||
|
l->transform(fwd_r);
|
||
|
r->transform(fwd_r);
|
||
|
|
||
|
carve::poly::Polyhedron *result = NULL;
|
||
|
{
|
||
|
static carve::TimingName FUNC_NAME("csg.compute()");
|
||
|
carve::TimingBlock block(FUNC_NAME);
|
||
|
result = csg.compute(l, r, op, NULL, classify_type);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
static carve::TimingName FUNC_NAME("delete polyhedron");
|
||
|
carve::TimingBlock block(FUNC_NAME);
|
||
|
|
||
|
delete l;
|
||
|
delete r;
|
||
|
}
|
||
|
|
||
|
result->transform(rev_r);
|
||
|
|
||
|
is_temp = true;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
virtual carve::poly::Polyhedron *evalUnscaled(bool &is_temp, CSG &csg) {
|
||
|
carve::poly::Polyhedron *l, *r;
|
||
|
bool l_temp, r_temp;
|
||
|
|
||
|
l = left->eval(l_temp, csg);
|
||
|
r = right->eval(r_temp, csg);
|
||
|
|
||
|
carve::poly::Polyhedron *result = NULL;
|
||
|
{
|
||
|
static carve::TimingName FUNC_NAME("csg.compute()");
|
||
|
carve::TimingBlock block(FUNC_NAME);
|
||
|
result = csg.compute(l, r, op, NULL, classify_type);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
static carve::TimingName FUNC_NAME("delete polyhedron");
|
||
|
carve::TimingBlock block(FUNC_NAME);
|
||
|
|
||
|
if (l_temp) delete l;
|
||
|
if (r_temp) delete r;
|
||
|
}
|
||
|
|
||
|
is_temp = true;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
virtual carve::poly::Polyhedron *eval(bool &is_temp, CSG &csg) {
|
||
|
if (rescale) {
|
||
|
return evalScaled(is_temp, csg);
|
||
|
} else {
|
||
|
return evalUnscaled(is_temp, csg);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
}
|
||
|
}
|