// 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 #include #include #include namespace carve { namespace interpolate { static inline std::vector polyInterpolate(const std::vector &s, const carve::geom2d::P2 &v) { // see hormann et al. 2006 const size_t SZ = s.size(); std::vector r; std::vector A; std::vector D; std::vector 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 val_t interp(iter_t begin, iter_t end, adapt_t adapt, const std::vector &vals, double x, double y, mod_t mod = mod_t()) { std::vector s; s.reserve(std::distance(begin, end)); std::transform(begin, end, std::back_inserter(s), adapt); std::vector 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 val_t interp(iter_t begin, iter_t end, adapt_t adapt, const std::vector &vals, double x, double y) { return interp(begin, end, adapt, vals, x, y, identity_t()); } template val_t interp(const std::vector &poly, adapt_t adapt, const std::vector &vals, double x, double y, mod_t mod = mod_t()) { return interp(poly.begin(), poly.end(), adapt, vals, x, y, mod); } template val_t interp(const std::vector &poly, adapt_t adapt, const std::vector &vals, double x, double y) { return interp(poly.begin(), poly.end(), adapt, vals, x, y, identity_t()); } template val_t interp(const std::vector &poly, const std::vector &vals, double x, double y, mod_t mod = mod_t()) { std::vector 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 val_t interp(const std::vector &poly, const std::vector &vals, double x, double y) { return interp(poly, vals, x, y, identity_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 class FaceVertexAttr : public Interpolator { protected: struct fv_hash { size_t operator()(const std::pair &v) const { return size_t(v.first) ^ size_t(v.second); } }; typedef std::unordered_map attrvmap_t; typedef std::unordered_map, 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 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 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 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() { } }; } }