332 lines
9.9 KiB
C++
332 lines
9.9 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/geom2d.hpp>
|
||
|
#include <carve/poly.hpp>
|
||
|
#include <carve/csg.hpp>
|
||
|
|
||
|
namespace carve {
|
||
|
namespace interpolate {
|
||
|
|
||
|
static inline std::vector<double> polyInterpolate(const std::vector<carve::geom2d::P2> &s,
|
||
|
const carve::geom2d::P2 &v) {
|
||
|
// see hormann et al. 2006
|
||
|
const size_t SZ = s.size();
|
||
|
std::vector<double> r;
|
||
|
std::vector<double> A;
|
||
|
std::vector<double> D;
|
||
|
|
||
|
std::vector<double> result;
|
||
|
|
||
|
r.resize(SZ);
|
||
|
A.resize(SZ);
|
||
|
D.resize(SZ);
|
||
|
|
||
|
result.resize(SZ, 0.0);
|
||
|
|
||
|
for (size_t i = 0; i < SZ; ++i) {
|
||
|
size_t i2 = (i + 1) % SZ;
|
||
|
carve::geom2d::P2 si = s[i] - v;
|
||
|
carve::geom2d::P2 si2 = s[i2] - v;
|
||
|
|
||
|
r[i] = sqrt(dot(si, si));
|
||
|
A[i] = cross(si, si2) / 2.0;
|
||
|
D[i] = dot(si, si2);
|
||
|
if (fabs(r[i]) < 1e-16) {
|
||
|
result[i] = 1.0;
|
||
|
return result;
|
||
|
} else if (fabs(A[i]) < 1e-16 && D[i] < 0.0) {
|
||
|
double r2 = sqrt(dot(si2, si2));
|
||
|
result[i2] = r[i] / (r[i] + r2);
|
||
|
result[i] = r2 / (r[i] + r2);
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
double w_sum = 0.0;
|
||
|
|
||
|
for (size_t i = 0; i < SZ; ++i) {
|
||
|
size_t i_m = (i + SZ - 1) % SZ;
|
||
|
size_t i_p = (i + 1) % SZ;
|
||
|
|
||
|
double w = 0.0;
|
||
|
if (fabs(A[i_m]) > 1e-16)
|
||
|
w += (r[i_m] - D[i_m] / r[i]) / A[i_m];
|
||
|
if (fabs(A[i]) > 1e-16)
|
||
|
w += (r[i_p] - D[i] / r[i]) / A[i];
|
||
|
|
||
|
result[i] = w;
|
||
|
w_sum += w;
|
||
|
}
|
||
|
|
||
|
for (size_t i = 0; i < SZ; ++i) {
|
||
|
result[i] /= w_sum;
|
||
|
}
|
||
|
|
||
|
// carve::geom2d::P2 test;
|
||
|
// for (size_t i = 0; i < SZ; ++i) {
|
||
|
// test = test + result[i] * s[i];
|
||
|
// }
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
template<typename iter_t,
|
||
|
typename adapt_t,
|
||
|
typename val_t,
|
||
|
typename mod_t>
|
||
|
val_t interp(iter_t begin,
|
||
|
iter_t end,
|
||
|
adapt_t adapt,
|
||
|
const std::vector<val_t> &vals,
|
||
|
double x,
|
||
|
double y,
|
||
|
mod_t mod = mod_t()) {
|
||
|
std::vector<carve::geom2d::P2> s;
|
||
|
s.reserve(std::distance(begin, end));
|
||
|
std::transform(begin, end, std::back_inserter(s), adapt);
|
||
|
std::vector<double> weight = polyInterpolate(s, carve::geom::VECTOR(x, y));
|
||
|
|
||
|
val_t v;
|
||
|
for (size_t z = 0; z < weight.size(); z++) {
|
||
|
v += weight[z] * vals[z];
|
||
|
}
|
||
|
|
||
|
return mod(v);
|
||
|
}
|
||
|
|
||
|
template<typename iter_t,
|
||
|
typename adapt_t,
|
||
|
typename val_t>
|
||
|
val_t interp(iter_t begin,
|
||
|
iter_t end,
|
||
|
adapt_t adapt,
|
||
|
const std::vector<val_t> &vals,
|
||
|
double x,
|
||
|
double y) {
|
||
|
return interp(begin, end, adapt, vals, x, y, identity_t<val_t>());
|
||
|
}
|
||
|
|
||
|
template<typename vertex_t,
|
||
|
typename adapt_t,
|
||
|
typename val_t,
|
||
|
typename mod_t>
|
||
|
val_t interp(const std::vector<vertex_t> &poly,
|
||
|
adapt_t adapt,
|
||
|
const std::vector<val_t> &vals,
|
||
|
double x,
|
||
|
double y,
|
||
|
mod_t mod = mod_t()) {
|
||
|
return interp(poly.begin(), poly.end(), adapt, vals, x, y, mod);
|
||
|
}
|
||
|
|
||
|
template<typename vertex_t,
|
||
|
typename adapt_t,
|
||
|
typename val_t>
|
||
|
val_t interp(const std::vector<vertex_t> &poly,
|
||
|
adapt_t adapt,
|
||
|
const std::vector<val_t> &vals,
|
||
|
double x,
|
||
|
double y) {
|
||
|
return interp(poly.begin(), poly.end(), adapt, vals, x, y, identity_t<val_t>());
|
||
|
}
|
||
|
|
||
|
template<typename val_t,
|
||
|
typename mod_t>
|
||
|
val_t interp(const std::vector<carve::geom2d::P2> &poly,
|
||
|
const std::vector<val_t> &vals,
|
||
|
double x,
|
||
|
double y,
|
||
|
mod_t mod = mod_t()) {
|
||
|
std::vector<double> weight = polyInterpolate(poly, carve::geom::VECTOR(x, y));
|
||
|
|
||
|
val_t v;
|
||
|
for (size_t z = 0; z < weight.size(); z++) {
|
||
|
v += weight[z] * vals[z];
|
||
|
}
|
||
|
|
||
|
return mod(v);
|
||
|
}
|
||
|
|
||
|
template<typename val_t>
|
||
|
val_t interp(const std::vector<carve::geom2d::P2> &poly,
|
||
|
const std::vector<val_t> &vals,
|
||
|
double x,
|
||
|
double y) {
|
||
|
return interp(poly, vals, x, y, identity_t<val_t>());
|
||
|
}
|
||
|
|
||
|
class Interpolator {
|
||
|
public:
|
||
|
virtual void interpolate(const carve::poly::Polyhedron::face_t *new_face,
|
||
|
const carve::poly::Polyhedron::face_t *orig_face,
|
||
|
bool flipped) =0;
|
||
|
|
||
|
Interpolator() {
|
||
|
}
|
||
|
|
||
|
virtual ~Interpolator() {
|
||
|
}
|
||
|
|
||
|
class Hook : public carve::csg::CSG::Hook {
|
||
|
Interpolator *interpolator;
|
||
|
public:
|
||
|
virtual void resultFace(const carve::poly::Polyhedron::face_t *new_face,
|
||
|
const carve::poly::Polyhedron::face_t *orig_face,
|
||
|
bool flipped) {
|
||
|
interpolator->interpolate(new_face, orig_face, flipped);
|
||
|
}
|
||
|
|
||
|
Hook(Interpolator *_interpolator) : interpolator(_interpolator) {
|
||
|
}
|
||
|
|
||
|
virtual ~Hook() {
|
||
|
}
|
||
|
};
|
||
|
|
||
|
void installHooks(carve::csg::CSG &csg) {
|
||
|
csg.hooks.registerHook(new Hook(this), carve::csg::CSG::Hooks::RESULT_FACE_BIT);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename attr_t>
|
||
|
class FaceVertexAttr : public Interpolator {
|
||
|
|
||
|
protected:
|
||
|
struct fv_hash {
|
||
|
size_t operator()(const std::pair<const carve::poly::Polyhedron::face_t *, unsigned> &v) const {
|
||
|
return size_t(v.first) ^ size_t(v.second);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
typedef std::unordered_map<const carve::poly::Polyhedron::vertex_t *, attr_t, carve::poly::hash_vertex_ptr> attrvmap_t;
|
||
|
typedef std::unordered_map<std::pair<const carve::poly::Polyhedron::face_t *, unsigned>, attr_t, fv_hash> attrmap_t;
|
||
|
|
||
|
attrmap_t attrs;
|
||
|
|
||
|
public:
|
||
|
bool hasAttribute(const carve::poly::Polyhedron::face_t *f, unsigned v) {
|
||
|
return attrs.find(std::make_pair(f, v)) != attrs.end();
|
||
|
}
|
||
|
|
||
|
attr_t getAttribute(const carve::poly::Polyhedron::face_t *f, unsigned v, const attr_t &def = attr_t()) {
|
||
|
typename attrmap_t::const_iterator fv = attrs.find(std::make_pair(f, v));
|
||
|
if (fv != attrs.end()) {
|
||
|
return (*fv).second;
|
||
|
}
|
||
|
return def;
|
||
|
}
|
||
|
|
||
|
void setAttribute(const carve::poly::Polyhedron::face_t *f, unsigned v, const attr_t &attr) {
|
||
|
attrs[std::make_pair(f, v)] = attr;
|
||
|
}
|
||
|
|
||
|
virtual void interpolate(const carve::poly::Polyhedron::face_t *new_face,
|
||
|
const carve::poly::Polyhedron::face_t *orig_face,
|
||
|
bool flipped) {
|
||
|
std::vector<attr_t> vertex_attrs;
|
||
|
attrvmap_t base_attrs;
|
||
|
vertex_attrs.reserve(orig_face->nVertices());
|
||
|
|
||
|
for (size_t i = 0; i < orig_face->nVertices(); ++i) {
|
||
|
typename attrmap_t::const_iterator a = attrs.find(std::make_pair(orig_face, i));
|
||
|
if (a == attrs.end()) return;
|
||
|
vertex_attrs.push_back((*a).second);
|
||
|
base_attrs[orig_face->vertex(i)] = vertex_attrs.back();
|
||
|
}
|
||
|
|
||
|
for (size_t i = 0; i < new_face->nVertices(); ++i) {
|
||
|
const carve::poly::Polyhedron::vertex_t *vertex = new_face->vertex(i);
|
||
|
typename attrvmap_t::const_iterator b = base_attrs.find(vertex);
|
||
|
if (b != base_attrs.end()) {
|
||
|
attrs[std::make_pair(new_face, i)] = (*b).second;
|
||
|
} else {
|
||
|
carve::geom2d::P2 p = carve::poly::face::project(orig_face, new_face->vertex(i)->v);
|
||
|
attr_t attr = interp(orig_face->vbegin(),
|
||
|
orig_face->vend(),
|
||
|
orig_face->projector(),
|
||
|
vertex_attrs,
|
||
|
p.x,
|
||
|
p.y);
|
||
|
attrs[std::make_pair(new_face, i)] = attr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FaceVertexAttr() : Interpolator() {
|
||
|
}
|
||
|
|
||
|
virtual ~FaceVertexAttr() {
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
template<typename attr_t>
|
||
|
class FaceAttr : public Interpolator {
|
||
|
|
||
|
protected:
|
||
|
struct f_hash {
|
||
|
size_t operator()(const carve::poly::Polyhedron::face_t * const &f) const {
|
||
|
return size_t(f);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
typedef std::unordered_map<const carve::poly::Polyhedron::face_t *, attr_t, f_hash> attrmap_t;
|
||
|
|
||
|
attrmap_t attrs;
|
||
|
|
||
|
public:
|
||
|
bool hasAttribute(const carve::poly::Polyhedron::face_t *f) {
|
||
|
return attrs.find(f) != attrs.end();
|
||
|
}
|
||
|
|
||
|
attr_t getAttribute(const carve::poly::Polyhedron::face_t *f, const attr_t &def = attr_t()) {
|
||
|
typename attrmap_t::const_iterator i = attrs.find(f);
|
||
|
if (i != attrs.end()) {
|
||
|
return (*i).second;
|
||
|
}
|
||
|
return def;
|
||
|
}
|
||
|
|
||
|
void setAttribute(const carve::poly::Polyhedron::face_t *f, const attr_t &attr) {
|
||
|
attrs[f] = attr;
|
||
|
}
|
||
|
|
||
|
virtual void interpolate(const carve::poly::Polyhedron::face_t *new_face,
|
||
|
const carve::poly::Polyhedron::face_t *orig_face,
|
||
|
bool flipped) {
|
||
|
typename attrmap_t::const_iterator i = attrs.find(orig_face);
|
||
|
if (i != attrs.end()) {
|
||
|
attrs[new_face] = (*i).second;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FaceAttr() : Interpolator() {
|
||
|
}
|
||
|
|
||
|
virtual ~FaceAttr() {
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
}
|
||
|
}
|