From fa0211df269a3398dd70467982f9e129c79e501b Mon Sep 17 00:00:00 2001 From: Tamito Kajiyama Date: Sat, 22 Dec 2012 18:25:01 +0000 Subject: [PATCH] Another "insanely" big code clean-up patch by Bastien Montagne, many thanks! --- .../blender/freestyle/intern/geometry/BBox.h | 241 ++- .../freestyle/intern/geometry/Bezier.cpp | 161 +- .../freestyle/intern/geometry/Bezier.h | 121 +- .../freestyle/intern/geometry/FastGrid.cpp | 119 +- .../freestyle/intern/geometry/FastGrid.h | 151 +- .../freestyle/intern/geometry/FitCurve.cpp | 737 ++++--- .../freestyle/intern/geometry/FitCurve.h | 182 +- .../blender/freestyle/intern/geometry/Geom.h | 132 +- .../freestyle/intern/geometry/GeomCleaner.cpp | 385 ++-- .../freestyle/intern/geometry/GeomCleaner.h | 392 ++-- .../freestyle/intern/geometry/GeomUtils.cpp | 1366 ++++++------ .../freestyle/intern/geometry/GeomUtils.h | 513 +++-- .../freestyle/intern/geometry/Grid.cpp | 704 ++++--- .../blender/freestyle/intern/geometry/Grid.h | 591 +++--- .../freestyle/intern/geometry/GridHelpers.cpp | 87 +- .../freestyle/intern/geometry/GridHelpers.h | 168 +- .../freestyle/intern/geometry/HashGrid.cpp | 74 +- .../freestyle/intern/geometry/HashGrid.h | 183 +- .../freestyle/intern/geometry/Noise.cpp | 395 ++-- .../blender/freestyle/intern/geometry/Noise.h | 118 +- .../freestyle/intern/geometry/Polygon.h | 339 +-- .../freestyle/intern/geometry/SweepLine.h | 547 +++-- .../freestyle/intern/geometry/VecMat.h | 1857 +++++++++-------- .../freestyle/intern/geometry/matrix_util.cpp | 489 ++--- .../freestyle/intern/geometry/matrix_util.h | 105 +- .../intern/geometry/normal_cycle.cpp | 157 +- .../freestyle/intern/geometry/normal_cycle.h | 218 +- .../freestyle/intern/image/GaussianFilter.cpp | 144 +- .../freestyle/intern/image/GaussianFilter.h | 231 +- source/blender/freestyle/intern/image/Image.h | 666 +++--- .../freestyle/intern/image/ImagePyramid.cpp | 334 +-- .../freestyle/intern/image/ImagePyramid.h | 180 +- 32 files changed, 6234 insertions(+), 5853 deletions(-) diff --git a/source/blender/freestyle/intern/geometry/BBox.h b/source/blender/freestyle/intern/geometry/BBox.h index 9c46d7918e2..b13960a4d2e 100644 --- a/source/blender/freestyle/intern/geometry/BBox.h +++ b/source/blender/freestyle/intern/geometry/BBox.h @@ -1,141 +1,154 @@ -// -// Filename : BBox.h -// Author(s) : Stephane Grabli -// Purpose : A class to hold a bounding box -// Date of creation : 22/05/2003 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BBOX_H__ +#define __BBOX_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef BBOX_H -# define BBOX_H +/** \file blender/freestyle/intern/geometry/BBox.h + * \ingroup freestyle + * \brief A class to hold a bounding box + * \author Stephane Grabli + * \date 22/05/2003 + */ template class BBox { - public: +public: + inline BBox() + { + _empty = true; + } - inline BBox() { - _empty = true; - } + template + inline BBox(const T& min_in, const T& max_in) : _min(min_in), _max(max_in) + { + _empty = false; + } - template - inline BBox(const T& min_in, const T& max_in) : _min(min_in), _max(max_in) { - _empty = false; - } + template + inline BBox(const BBox& b) : _min(b.getMin()), _max(b.getMax()) + { + _empty = false; + } - template - inline BBox(const BBox& b) : _min(b.getMin()), _max(b.getMax()) { - _empty = false; - } + template + inline void extendToContain(const T& p) + { + if (_empty) { + _min = p; + _max = p; + _empty = false; + return; + } + for (unsigned int i = 0; i < Point::dim(); i++) { + if (p[i] < _min[i]) + _min[i] = p[i]; + else if (p[i] > _max[i]) + _max[i] = p[i]; + } + _empty = false; + } - template - inline void extendToContain(const T& p) { - if (_empty) { - _min = p; - _max = p; - _empty = false; - return; - } - for (unsigned i = 0; i < Point::dim(); i++) { - if (p[i] < _min[i]) - _min[i] = p[i]; - else if (p[i] > _max[i]) - _max[i] = p[i]; - } - _empty = false; - } + inline void clear() + { + _empty = true; + } - inline void clear() { - _empty = true; - } + inline bool empty() const + { + return _empty; + } - inline bool empty() const { - return _empty; - } + inline const Point& getMin() const + { + return _min; + } - inline const Point& getMin() const { - return _min; - } + inline const Point& getMax() const + { + return _max; + } - inline const Point& getMax() const { - return _max; - } + inline BBox& operator=(const BBox& b) + { + _min = b.getMin(); + _max = b.getMax(); + _empty = false; + return *this; + } - inline BBox& operator=(const BBox& b) { - _min = b.getMin(); - _max = b.getMax(); - _empty = false; - return *this; - } + inline BBox& operator+=(const BBox& b) + { + if (_empty) { + _min = b.getMin(); + _max = b.getMax(); + _empty = false; + } + else { + for (unsigned int i = 0; i < Point::dim(); i++) { + if (b.getMin()[i] < _min[i]) + _min[i] = b.getMin()[i]; + if (b.getMax()[i] > _max[i]) + _max[i] = b.getMax()[i]; + } + } + return *this; + } - inline BBox& operator+=(const BBox& b) { - if (_empty) { - _min = b.getMin(); - _max = b.getMax(); - _empty = false; - } - else { - for (unsigned i = 0; i < Point::dim(); i++) { - if (b.getMin()[i] < _min[i]) - _min[i] = b.getMin()[i]; - if (b.getMax()[i] > _max[i]) - _max[i] = b.getMax()[i]; - } - } - return *this; - } - - inline bool inside(const Point& p){ - if(empty()) - return false; - for (unsigned i = 0; i < Point::dim(); i++) { - if((_min[i]>p[i]) || (_max[i]p[i]) || (_max[i] BBox& operator+(const BBox &b1, const BBox &b2) { - Point new_min; - Point new_max; + Point new_min; + Point new_max; - for (unsigned i = 0; i < Point::dim(); i++) { - new_min[i] = b1.getMin()[i] < b2.getMin()[i] ? b1.getMin()[i] : b2.getMin()[i]; - new_max[i] = b1.getMax()[i] > b2.getMax()[i] ? b1.getMax()[i] : b2.getMax()[i]; - } + for (unsigned int i = 0; i < Point::dim(); i++) { + new_min[i] = b1.getMin()[i] < b2.getMin()[i] ? b1.getMin()[i] : b2.getMin()[i]; + new_max[i] = b1.getMax()[i] > b2.getMax()[i] ? b1.getMax()[i] : b2.getMax()[i]; + } - return BBox(new_min, new_max); + return BBox(new_min, new_max); } -#endif // BBOX_H +#endif // __BBOX_H__ diff --git a/source/blender/freestyle/intern/geometry/Bezier.cpp b/source/blender/freestyle/intern/geometry/Bezier.cpp index 8f9771f29d3..9140f1f947d 100644 --- a/source/blender/freestyle/intern/geometry/Bezier.cpp +++ b/source/blender/freestyle/intern/geometry/Bezier.cpp @@ -1,23 +1,36 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/Bezier.cpp + * \ingroup freestyle + * \brief Class to define a Bezier curve of order 4. + * \author Stephane Grabli + * \date 04/06/2003 + */ #include "Bezier.h" #include "FitCurve.h" @@ -34,85 +47,81 @@ BezierCurveSegment::~BezierCurveSegment() void BezierCurveSegment::AddControlPoint(const Vec2d& iPoint) { - _ControlPolygon.push_back(iPoint); - if(_ControlPolygon.size() == 4) - Build(); + _ControlPolygon.push_back(iPoint); + if (_ControlPolygon.size() == 4) + Build(); } void BezierCurveSegment::Build() { - if(_ControlPolygon.size() != 4) - return; + if (_ControlPolygon.size() != 4) + return; - // Compute the rightmost part of the matrix: - vector::const_iterator p0,p1,p2,p3; - p0 = _ControlPolygon.begin(); - p1 = p0;++p1; - p2 = p1;++p2; - p3 = p2;++p3; - float x[4], y[4]; - - x[0] = -p0->x()+3*p1->x()-3*p2->x()+p3->x(); - x[1] = 3*p0->x()-6*p1->x()+3*p2->x(); - x[2] = -3*p0->x()+3*p1->x(); - x[3] = p0->x(); + // Compute the rightmost part of the matrix: + vector::const_iterator p0,p1,p2,p3; + p0 = _ControlPolygon.begin(); + p1 = p0; + ++p1; + p2 = p1; + ++p2; + p3 = p2; + ++p3; + float x[4], y[4]; - y[0] = -p0->y()+3*p1->y()-3*p2->y()+p3->y(); - y[1] = 3*p0->y()-6*p1->y()+3*p2->y(); - y[2] = -3*p0->y()+3*p1->y(); - y[3] = p0->y(); + x[0] = -p0->x() + 3 * p1->x() - 3 * p2->x() + p3->x(); + x[1] = 3 * p0->x() - 6 * p1->x() + 3 * p2->x(); + x[2] = -3 * p0->x() + 3 * p1->x(); + x[3] = p0->x(); - int nvertices = 12; - float increment = 1.0/(float)nvertices; - float t = 0.f; - for(int i=0; i<=nvertices; ++i) - { - _Vertices.push_back(Vec2d((x[3] + t*(x[2] + t*(x[1] + t*x[0]))), - (y[3] + t*(y[2] + t*(y[1] + t*y[0]))))); - t+=increment; - } + y[0] = -p0->y() + 3 * p1->y() - 3 * p2->y() + p3->y(); + y[1] = 3 * p0->y() - 6 * p1->y() + 3 * p2->y(); + y[2] = -3 * p0->y() + 3 * p1->y(); + y[3] = p0->y(); + + int nvertices = 12; + float increment = 1.0 / (float)nvertices; + float t = 0.0f; + for (int i = 0; i <= nvertices; ++i) { + _Vertices.push_back(Vec2d((x[3] + t * (x[2] + t * (x[1] + t * x[0]))), + (y[3] + t * (y[2] + t * (y[1] + t * y[0]))))); + t += increment; + } } BezierCurve::BezierCurve() { - _currentSegment = new BezierCurveSegment; + _currentSegment = new BezierCurveSegment; } BezierCurve::BezierCurve(vector& iPoints, double error) { - FitCurveWrapper fitcurve; - _currentSegment = new BezierCurveSegment; - vector curve; + FitCurveWrapper fitcurve; + _currentSegment = new BezierCurveSegment; + vector curve; - fitcurve.FitCurve(iPoints, curve, error); - int i=0; - vector::iterator v,vend; - for(v=curve.begin(),vend=curve.end(); - v!=vend; - ++v) - { - if((i == 0) || (i%4 != 0)) - AddControlPoint(*v); - ++i; - } + fitcurve.FitCurve(iPoints, curve, error); + int i = 0; + vector::iterator v,vend; + for (v = curve.begin(), vend = curve.end(); v != vend; ++v) { + if ((i == 0) || (i % 4 != 0)) + AddControlPoint(*v); + ++i; + } } BezierCurve::~BezierCurve() { - if(_currentSegment) - delete _currentSegment; + if(_currentSegment) + delete _currentSegment; } void BezierCurve::AddControlPoint(const Vec2d& iPoint) { - _ControlPolygon.push_back(iPoint); - _currentSegment->AddControlPoint(iPoint); - if(_currentSegment->size() == 4) - { - _Segments.push_back(_currentSegment); - _currentSegment = new BezierCurveSegment; - _currentSegment->AddControlPoint(iPoint); - } + _ControlPolygon.push_back(iPoint); + _currentSegment->AddControlPoint(iPoint); + if (_currentSegment->size() == 4) { + _Segments.push_back(_currentSegment); + _currentSegment = new BezierCurveSegment; + _currentSegment->AddControlPoint(iPoint); + } } - - diff --git a/source/blender/freestyle/intern/geometry/Bezier.h b/source/blender/freestyle/intern/geometry/Bezier.h index acae71bbb2c..51f32e9e0b3 100644 --- a/source/blender/freestyle/intern/geometry/Bezier.h +++ b/source/blender/freestyle/intern/geometry/Bezier.h @@ -1,73 +1,96 @@ -// -// Filename : Bezier.h -// Author(s) : Stephane Grabli -// Purpose : Class to define a Bezier curve of order 4. -// Date of creation : 04/06/2003 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BEZIER_H__ +#define __BEZIER_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef BEZIER_H -# define BEZIER_H +/** \file blender/freestyle/intern/geometry/Bezier.h + * \ingroup freestyle + * \brief Class to define a Bezier curve of order 4. + * \author Stephane Grabli + * \date 04/06/2003 + */ #include -#include "../system/FreestyleConfig.h" + #include "Geom.h" +#include "../system/FreestyleConfig.h" + using namespace Geometry; -class LIB_GEOMETRY_EXPORT BezierCurveSegment +class LIB_GEOMETRY_EXPORT BezierCurveSegment { private: - std::vector _ControlPolygon; - std::vector _Vertices; + std::vector _ControlPolygon; + std::vector _Vertices; public: - BezierCurveSegment(); - virtual ~BezierCurveSegment(); + BezierCurveSegment(); + virtual ~BezierCurveSegment(); - void AddControlPoint(const Vec2d& iPoint); - void Build(); - inline int size() const {return _ControlPolygon.size();} - inline std::vector& vertices() {return _Vertices;} + void AddControlPoint(const Vec2d& iPoint); + void Build(); + + inline int size() const + { + return _ControlPolygon.size(); + } + + inline std::vector& vertices() + { + return _Vertices; + } }; class LIB_GEOMETRY_EXPORT BezierCurve { private: - std::vector _ControlPolygon; - std::vector _Segments; - BezierCurveSegment *_currentSegment; + std::vector _ControlPolygon; + std::vector _Segments; + BezierCurveSegment *_currentSegment; public: - BezierCurve(); - BezierCurve(std::vector& iPoints, double error=4.0); - virtual ~BezierCurve(); + BezierCurve(); + BezierCurve(std::vector& iPoints, double error=4.0); + virtual ~BezierCurve(); - void AddControlPoint(const Vec2d& iPoint); - std::vector& controlPolygon() {return _ControlPolygon;} - std::vector& segments() {return _Segments;} + void AddControlPoint(const Vec2d& iPoint); + + std::vector& controlPolygon() + { + return _ControlPolygon; + } + + std::vector& segments() + { + return _Segments; + } }; -#endif // BEZIER_H +#endif // __BEZIER_H__ diff --git a/source/blender/freestyle/intern/geometry/FastGrid.cpp b/source/blender/freestyle/intern/geometry/FastGrid.cpp index 325126b4b96..f5f9bc1079e 100644 --- a/source/blender/freestyle/intern/geometry/FastGrid.cpp +++ b/source/blender/freestyle/intern/geometry/FastGrid.cpp @@ -1,62 +1,83 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/FastGrid.h + * \ingroup freestyle + * \brief Class to define a cell grid surrounding the bounding box of the scene + * \author Stephane Grabli + * \date 30/07/2002 + */ #include "FastGrid.h" -void FastGrid::clear() { - if(!_cells) - return; +void FastGrid::clear() +{ + if (!_cells) + return; - for(unsigned i = 0; i < _cells_size; i++) - if (_cells[i]) - delete _cells[i]; - delete[] _cells; - _cells = NULL; - _cells_size = 0; + for (unsigned int i = 0; i < _cells_size; i++) { + if (_cells[i]) + delete _cells[i]; + } + delete[] _cells; + _cells = NULL; + _cells_size = 0; - Grid::clear(); + Grid::clear(); } -void FastGrid::configure(const Vec3r& orig, const Vec3r& size, unsigned nb) { - Grid::configure(orig, size, nb); - _cells_size = _cells_nb[0] * _cells_nb[1] * _cells_nb[2]; - _cells = new Cell*[_cells_size]; - memset(_cells, 0, _cells_size * sizeof(*_cells)); +void FastGrid::configure(const Vec3r& orig, const Vec3r& size, unsigned nb) +{ + Grid::configure(orig, size, nb); + _cells_size = _cells_nb[0] * _cells_nb[1] * _cells_nb[2]; + _cells = new Cell*[_cells_size]; + memset(_cells, 0, _cells_size * sizeof(*_cells)); } -Cell* FastGrid::getCell(const Vec3u& p) { - //cout << _cells<< " "<< p << " " <<_cells_nb[0]<<"-"<< _cells_nb[1]<<"-"<< _cells_nb[2]<< " "<<_cells_size<< endl; - assert(_cells||("_cells is a null pointer")); - assert((_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0])<_cells_size); - assert(p[0]<_cells_nb[0]); - assert(p[1]<_cells_nb[1]); - assert(p[2]<_cells_nb[2]); - return _cells[_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]]; +Cell *FastGrid::getCell(const Vec3u& p) +{ +#if 0 + cout << _cells << " " << p << " " << _cells_nb[0] << "-" << _cells_nb[1] << "-" << _cells_nb[2] + << " " << _cells_size << endl; +#endif + assert(_cells || ("_cells is a null pointer")); + assert((_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]) < _cells_size); + assert(p[0] < _cells_nb[0]); + assert(p[1] < _cells_nb[1]); + assert(p[2] < _cells_nb[2]); + return _cells[_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]]; } -void FastGrid::fillCell(const Vec3u& p, Cell& cell) { - assert(_cells||("_cells is a null pointer")); - assert((_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0])<_cells_size); - assert(p[0]<_cells_nb[0]); - assert(p[1]<_cells_nb[1]); - assert(p[2]<_cells_nb[2]); - _cells[_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]] = &cell; +void FastGrid::fillCell(const Vec3u& p, Cell& cell) +{ + assert(_cells || ("_cells is a null pointer")); + assert((_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]) < _cells_size); + assert(p[0] < _cells_nb[0]); + assert(p[1] < _cells_nb[1]); + assert(p[2] < _cells_nb[2]); + _cells[_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]] = &cell; } diff --git a/source/blender/freestyle/intern/geometry/FastGrid.h b/source/blender/freestyle/intern/geometry/FastGrid.h index e620ff24385..3a2ed392533 100644 --- a/source/blender/freestyle/intern/geometry/FastGrid.h +++ b/source/blender/freestyle/intern/geometry/FastGrid.h @@ -1,85 +1,86 @@ -// -// Filename : FastGrid.h -// Author(s) : Stephane Grabli -// Purpose : Class to define a cell grid surrounding the -// bounding box of the scene -// Date of creation : 30/07/2002 -// -/////////////////////////////////////////////////////////////////////////////// - - -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef FASTGRID_H -# define FASTGRID_H - -# include "Grid.h" -# include -/*! Class to define a regular grid used for ray - * casting computations - * We don't use a hashtable here. The grid is - * explicitly stored for faster computations. - * However, this might result in significant - * increase in memory usage (compared to the regular grid) +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** */ +#ifndef __FASTGRID_H__ +#define __FASTGRID_H__ + +/** \file blender/freestyle/intern/geometry/FastGrid.h + * \ingroup freestyle + * \brief Class to define a cell grid surrounding the bounding box of the scene + * \author Stephane Grabli + * \date 30/07/2002 + */ + +#include + +#include "Grid.h" + +/*! Class to define a regular grid used for ray casting computations + * We don't use a hashtable here. The grid is explicitly stored for faster computations. + * However, this might result in significant increase in memory usage (compared to the regular grid) + */ class LIB_GEOMETRY_EXPORT FastGrid : public Grid { - public: +public: + FastGrid() : Grid() + { + _cells = NULL; + _cells_size = 0; + } - FastGrid() : Grid() { - _cells = NULL; - _cells_size = 0; - } - - virtual ~FastGrid() { - clear(); - } + virtual ~FastGrid() + { + clear(); + } - /*! clears the grid - * Deletes all the cells, clears the hashtable, - * resets size, size of cell, number of cells. - */ - virtual void clear(); - - /*! Sets the different parameters of the grid - * orig - * The grid origin - * size - * The grid's dimensions - * nb - * The number of cells of the grid - */ - virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb); - - /*! returns the cell whose coordinates are pased as argument */ - Cell* getCell(const Vec3u& p) ; - - /*! Fills the case p with the cell iCell */ - virtual void fillCell(const Vec3u& p, Cell& cell); + /*! clears the grid + * Deletes all the cells, clears the hashtable, resets size, size of cell, number of cells. + */ + virtual void clear(); + + /*! Sets the different parameters of the grid + * orig + * The grid origin + * size + * The grid's dimensions + * nb + * The number of cells of the grid + */ + virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb); + + /*! returns the cell whose coordinates are pased as argument */ + Cell* getCell(const Vec3u& p); + + /*! Fills the case p with the cell iCell */ + virtual void fillCell(const Vec3u& p, Cell& cell); protected: - - Cell** _cells; - unsigned _cells_size; + Cell **_cells; + unsigned _cells_size; }; -#endif // FASTGRID_H +#endif // __FASTGRID_H__ diff --git a/source/blender/freestyle/intern/geometry/FitCurve.cpp b/source/blender/freestyle/intern/geometry/FitCurve.cpp index f71af130d7f..4eae543c9f9 100644 --- a/source/blender/freestyle/intern/geometry/FitCurve.cpp +++ b/source/blender/freestyle/intern/geometry/FitCurve.cpp @@ -1,33 +1,49 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/FitCurve.cpp + * \ingroup freestyle + * \brief An Algorithm for Automatically Fitting Digitized Curves by Philip J. Schneider, + * \brief from "Graphics Gems", Academic Press, 1990 + * \author Stephane Grabli + * \date 06/06/2003 + */ #include // for malloc and free #include #include + #include "FitCurve.h" using namespace std; typedef Vector2 *BezierCurve; +// XXX Do we need "#ifdef __cplusplus" at all here??? #ifdef __cplusplus extern "C" { @@ -46,379 +62,367 @@ static Vector2 ComputeLeftTangent(Vector2 *d, int end); static Vector2 ComputeLeftTangent(Vector2 *d, int end); static double ComputeMaxError(Vector2 *d, int first, int last, BezierCurve bezCurve, double *u, int *splitPoint); static double *ChordLengthParameterize(Vector2 *d, int first, int last); -static BezierCurve GenerateBezier(Vector2 *d, int first, int last, double *uPrime, Vector2 tHat1, Vector2 tHat2); +static BezierCurve GenerateBezier(Vector2 *d, int first, int last, double *uPrime, Vector2 tHat1, Vector2 tHat2); static Vector2 V2AddII(Vector2 a, Vector2 b); static Vector2 V2ScaleIII(Vector2 v, double s); static Vector2 V2SubII(Vector2 a, Vector2 b); +#define MAXPOINTS 1000 /* The most points you can have */ -#define MAXPOINTS 1000 /* The most points you can have */ - -/* returns squared length of input vector */ -static double V2SquaredLength(Vector2 *a) -{ return(((*a)[0] * (*a)[0])+((*a)[1] * (*a)[1])); +/* returns squared length of input vector */ +static double V2SquaredLength(Vector2 *a) +{ + return (((*a)[0] * (*a)[0]) + ((*a)[1] * (*a)[1])); } - + /* returns length of input vector */ static double V2Length(Vector2 *a) { - return(sqrt(V2SquaredLength(a))); + return (sqrt(V2SquaredLength(a))); } -static Vector2 *V2Scale(Vector2 *v, double newlen) +static Vector2 *V2Scale(Vector2 *v, double newlen) { - double len = V2Length(v); - if (len != 0.0) { (*v)[0] *= newlen/len; (*v)[1] *= newlen/len; } - return(v); + double len = V2Length(v); + if (len != 0.0) { + (*v)[0] *= newlen / len; + (*v)[1] *= newlen / len; + } + return v; } /* return the dot product of vectors a and b */ -static double V2Dot(Vector2 *a, Vector2 *b) +static double V2Dot(Vector2 *a, Vector2 *b) { - return(((*a)[0]*(*b)[0])+((*a)[1]*(*b)[1])); + return (((*a)[0] * (*b)[0]) + ((*a)[1] * (*b)[1])); } /* return the distance between two points */ static double V2DistanceBetween2Points(Vector2 *a, Vector2 *b) { -double dx = (*a)[0] - (*b)[0]; -double dy = (*a)[1] - (*b)[1]; - return(sqrt((dx*dx)+(dy*dy))); + double dx = (*a)[0] - (*b)[0]; + double dy = (*a)[1] - (*b)[1]; + return (sqrt((dx * dx) + (dy * dy))); } /* return vector sum c = a+b */ static Vector2 *V2Add(Vector2 *a, Vector2 *b, Vector2 *c) { - (*c)[0] = (*a)[0]+(*b)[0]; (*c)[1] = (*a)[1]+(*b)[1]; - return(c); + (*c)[0] = (*a)[0] + (*b)[0]; + (*c)[1] = (*a)[1] + (*b)[1]; + return c; } /* normalizes the input vector and returns it */ -static Vector2 *V2Normalize(Vector2 *v) +static Vector2 *V2Normalize(Vector2 *v) { -double len = V2Length(v); - if (len != 0.0) { (*v)[0] /= len; (*v)[1] /= len; } - return(v); + double len = V2Length(v); + if (len != 0.0) { + (*v)[0] /= len; + (*v)[1] /= len; + } + return v; } /* negates the input vector and returns it */ -static Vector2 *V2Negate(Vector2 *v) +static Vector2 *V2Negate(Vector2 *v) { - (*v)[0] = -(*v)[0]; (*v)[1] = -(*v)[1]; - return(v); + (*v)[0] = -(*v)[0]; + (*v)[1] = -(*v)[1]; + return v; } - -/* - * GenerateBezier : +/* GenerateBezier: * Use least-squares method to find Bezier control points for region. - * + * Vector2 *d; Array of digitized points + * int first, last; Indices defining region + * double *uPrime; Parameter values for region + * Vector2 tHat1, tHat2; Unit tangents at endpoints */ static BezierCurve GenerateBezier(Vector2 *d, int first, int last, double *uPrime, Vector2 tHat1, Vector2 tHat2) -// Vector2 *d; /* Array of digitized points */ -// int first, last; /* Indices defining region */ -// double *uPrime; /* Parameter values for region */ -// Vector2 tHat1, tHat2; /* Unit tangents at endpoints */ { - int i; - Vector2 A[MAXPOINTS][2]; /* Precomputed rhs for eqn */ - int nPts; /* Number of pts in sub-curve */ - double C[2][2]; /* Matrix C */ - double X[2]; /* Matrix X */ - double det_C0_C1, /* Determinants of matrices */ - det_C0_X, - det_X_C1; - double alpha_l, /* Alpha values, left and right */ - alpha_r; - Vector2 tmp; /* Utility variable */ - BezierCurve bezCurve; /* RETURN bezier curve ctl pts */ + int i; + Vector2 A[MAXPOINTS][2]; /* Precomputed rhs for eqn */ + int nPts; /* Number of pts in sub-curve */ + double C[2][2]; /* Matrix C */ + double X[2]; /* Matrix X */ + double det_C0_C1; /* Determinants of matrices */ + double det_C0_X; + double det_X_C1; + double alpha_l; /* Alpha values, left and right */ + double alpha_r; + Vector2 tmp; /* Utility variable */ + BezierCurve bezCurve; /* RETURN bezier curve ctl pts */ - bezCurve = (Vector2 *)malloc(4 * sizeof(Vector2)); - nPts = last - first + 1; + bezCurve = (Vector2*)malloc(4 * sizeof(Vector2)); + nPts = last - first + 1; - - /* Compute the A's */ - for (i = 0; i < nPts; i++) { - Vector2 v1, v2; + /* Compute the A's */ + for (i = 0; i < nPts; i++) { + Vector2 v1, v2; v1 = tHat1; v2 = tHat2; V2Scale(&v1, B1(uPrime[i])); V2Scale(&v2, B2(uPrime[i])); A[i][0] = v1; A[i][1] = v2; - } + } - /* Create the C and X matrices */ - C[0][0] = 0.0; - C[0][1] = 0.0; - C[1][0] = 0.0; - C[1][1] = 0.0; - X[0] = 0.0; - X[1] = 0.0; - - for (i = 0; i < nPts; i++) { - C[0][0] += V2Dot(&A[i][0], &A[i][0]); + /* Create the C and X matrices */ + C[0][0] = 0.0; + C[0][1] = 0.0; + C[1][0] = 0.0; + C[1][1] = 0.0; + X[0] = 0.0; + X[1] = 0.0; + for (i = 0; i < nPts; i++) { + C[0][0] += V2Dot(&A[i][0], &A[i][0]); C[0][1] += V2Dot(&A[i][0], &A[i][1]); -/* C[1][0] += V2Dot(&A[i][0], &A[i][1]);*/ +// C[1][0] += V2Dot(&A[i][0], &A[i][1]); C[1][0] = C[0][1]; C[1][1] += V2Dot(&A[i][1], &A[i][1]); tmp = V2SubII(d[first + i], - V2AddII( - V2ScaleIII(d[first], B0(uPrime[i])), - V2AddII( - V2ScaleIII(d[first], B1(uPrime[i])), - V2AddII( - V2ScaleIII(d[last], B2(uPrime[i])), - V2ScaleIII(d[last], B3(uPrime[i])))))); - + V2AddII(V2ScaleIII(d[first], B0(uPrime[i])), + V2AddII(V2ScaleIII(d[first], B1(uPrime[i])), + V2AddII(V2ScaleIII(d[last], B2(uPrime[i])), + V2ScaleIII(d[last], B3(uPrime[i])) + ) + ) + ) + ); - X[0] += V2Dot(&((A[i])[0]), &tmp); - X[1] += V2Dot(&((A[i])[1]), &tmp); - } + X[0] += V2Dot(&((A[i])[0]), &tmp); + X[1] += V2Dot(&((A[i])[1]), &tmp); + } - /* Compute the determinants of C and X */ - det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1]; - det_C0_X = C[0][0] * X[1] - C[0][1] * X[0]; - det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1]; + /* Compute the determinants of C and X */ + det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1]; + det_C0_X = C[0][0] * X[1] - C[0][1] * X[0]; + det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1]; - /* Finally, derive alpha values */ - if (det_C0_C1 == 0.0) { - det_C0_C1 = (C[0][0] * C[1][1]) * 10e-12; - } - alpha_l = det_X_C1 / det_C0_C1; - alpha_r = det_C0_X / det_C0_C1; + /* Finally, derive alpha values */ + if (det_C0_C1 == 0.0) { + det_C0_C1 = (C[0][0] * C[1][1]) * 10.0e-12; + } + alpha_l = det_X_C1 / det_C0_C1; + alpha_r = det_C0_X / det_C0_C1; - /* If alpha negative, use the Wu/Barsky heuristic (see text) */ - /* (if alpha is 0, you get coincident control points that lead to - * divide by zero in any subsequent NewtonRaphsonRootFind() call. */ - if (alpha_l < 1.0e-6 || alpha_r < 1.0e-6) { - double dist = V2DistanceBetween2Points(&d[last], &d[first]) / - 3.0; + /* If alpha negative, use the Wu/Barsky heuristic (see text) (if alpha is 0, you get coincident control points + * that lead to divide by zero in any subsequent NewtonRaphsonRootFind() call). + */ + if (alpha_l < 1.0e-6 || alpha_r < 1.0e-6) { + double dist = V2DistanceBetween2Points(&d[last], &d[first]) / 3.0; bezCurve[0] = d[first]; bezCurve[3] = d[last]; V2Add(&(bezCurve[0]), V2Scale(&(tHat1), dist), &(bezCurve[1])); V2Add(&(bezCurve[3]), V2Scale(&(tHat2), dist), &(bezCurve[2])); - return (bezCurve); - } + return bezCurve; + } - /* First and last control points of the Bezier curve are */ - /* positioned exactly at the first and last data points */ - /* Control points 1 and 2 are positioned an alpha distance out */ - /* on the tangent vectors, left and right, respectively */ - bezCurve[0] = d[first]; - bezCurve[3] = d[last]; - V2Add(&bezCurve[0], V2Scale(&tHat1, alpha_l), &bezCurve[1]); - V2Add(&bezCurve[3], V2Scale(&tHat2, alpha_r), &bezCurve[2]); - return (bezCurve); + /* First and last control points of the Bezier curve are positioned exactly at the first and last data points + * Control points 1 and 2 are positioned an alpha distance out on the tangent vectors, left and right, respectively + */ + bezCurve[0] = d[first]; + bezCurve[3] = d[last]; + V2Add(&bezCurve[0], V2Scale(&tHat1, alpha_l), &bezCurve[1]); + V2Add(&bezCurve[3], V2Scale(&tHat2, alpha_r), &bezCurve[2]); + return (bezCurve); } - /* * Reparameterize: - * Given set of points and their parameterization, try to find - * a better parameterization. - * + * Given set of points and their parameterization, try to find a better parameterization. + * Vector2 *d; Array of digitized points + * int first, last; Indices defining region + * double *u; Current parameter values + * BezierCurve bezCurve; Current fitted curve */ static double *Reparameterize(Vector2 *d, int first, int last, double *u, BezierCurve bezCurve) -// Vector2 *d; /* Array of digitized points */ -// int first, last; /* Indices defining region */ -// double *u; /* Current parameter values */ -// BezierCurve bezCurve; /* Current fitted curve */ { - int nPts = last-first+1; - int i; - double *uPrime; /* New parameter values */ + int nPts = last - first + 1; + int i; + double *uPrime; /* New parameter values */ - uPrime = (double *)malloc(nPts * sizeof(double)); - for (i = first; i <= last; i++) { - uPrime[i-first] = NewtonRaphsonRootFind(bezCurve, d[i], u[i- - first]); - } - return (uPrime); + uPrime = (double*)malloc(nPts * sizeof(double)); + for (i = first; i <= last; i++) { + uPrime[i-first] = NewtonRaphsonRootFind(bezCurve, d[i], u[i - first]); + } + return (uPrime); } - - /* - * NewtonRaphsonRootFind : - * Use Newton-Raphson iteration to find better root. + * NewtonRaphsonRootFind: + * Use Newton-Raphson iteration to find better root. + * BezierCurve Q; Current fitted curve + * Vector2 P; Digitized point + * double u; Parameter value for "P" */ static double NewtonRaphsonRootFind(BezierCurve Q, Vector2 P, double u) -// BezierCurve Q; /* Current fitted curve */ -// Vector2 P; /* Digitized point */ -// double u; /* Parameter value for "P" */ { - double numerator, denominator; - Vector2 Q1[3], Q2[2]; /* Q' and Q'' */ - Vector2 Q_u, Q1_u, Q2_u; /*u evaluated at Q, Q', & Q'' */ - double uPrime; /* Improved u */ - int i; - - /* Compute Q(u) */ - Q_u = BezierII(3, Q, u); - - /* Generate control vertices for Q' */ - for (i = 0; i <= 2; i++) { - Q1[i][0] = (Q[i+1][0] - Q[i][0]) * 3.0; - Q1[i][1] = (Q[i+1][1] - Q[i][1]) * 3.0; - } - - /* Generate control vertices for Q'' */ - for (i = 0; i <= 1; i++) { - Q2[i][0] = (Q1[i+1][0] - Q1[i][0]) * 2.0; - Q2[i][1] = (Q1[i+1][1] - Q1[i][1]) * 2.0; - } - - /* Compute Q'(u) and Q''(u) */ - Q1_u = BezierII(2, Q1, u); - Q2_u = BezierII(1, Q2, u); - - /* Compute f(u)/f'(u) */ - numerator = (Q_u[0] - P[0]) * (Q1_u[0]) + (Q_u[1] - P[1]) * (Q1_u[1]); - denominator = (Q1_u[0]) * (Q1_u[0]) + (Q1_u[1]) * (Q1_u[1]) + - (Q_u[0] - P[0]) * (Q2_u[0]) + (Q_u[1] - P[1]) * (Q2_u[1]); - - /* u = u - f(u)/f'(u) */ - if(denominator == 0) // FIXME - return u; - uPrime = u - (numerator/denominator); - return (uPrime); + double numerator, denominator; + Vector2 Q1[3], Q2[2]; /* Q' and Q'' */ + Vector2 Q_u, Q1_u, Q2_u; /* u evaluated at Q, Q', & Q'' */ + double uPrime; /* Improved u */ + int i; + + /* Compute Q(u) */ + Q_u = BezierII(3, Q, u); + + /* Generate control vertices for Q' */ + for (i = 0; i <= 2; i++) { + Q1[i][0] = (Q[i + 1][0] - Q[i][0]) * 3.0; + Q1[i][1] = (Q[i + 1][1] - Q[i][1]) * 3.0; + } + + /* Generate control vertices for Q'' */ + for (i = 0; i <= 1; i++) { + Q2[i][0] = (Q1[i + 1][0] - Q1[i][0]) * 2.0; + Q2[i][1] = (Q1[i + 1][1] - Q1[i][1]) * 2.0; + } + + /* Compute Q'(u) and Q''(u) */ + Q1_u = BezierII(2, Q1, u); + Q2_u = BezierII(1, Q2, u); + + /* Compute f(u)/f'(u) */ + numerator = (Q_u[0] - P[0]) * (Q1_u[0]) + (Q_u[1] - P[1]) * (Q1_u[1]); + denominator = (Q1_u[0]) * (Q1_u[0]) + (Q1_u[1]) * (Q1_u[1]) + + (Q_u[0] - P[0]) * (Q2_u[0]) + (Q_u[1] - P[1]) * (Q2_u[1]); + + /* u = u - f(u)/f'(u) */ + if (denominator == 0) // FIXME + return u; + uPrime = u - (numerator / denominator); + return uPrime; } - - /* - * Bezier : - * Evaluate a Bezier curve at a particular parameter value - * + * Bezier: + * Evaluate a Bezier curve at a particular parameter value + * int degree; The degree of the bezier curve + * Vector2 *V; Array of control points + * double t; Parametric value to find point for */ static Vector2 BezierII(int degree, Vector2 *V, double t) -// int degree; /* The degree of the bezier curve */ -// Vector2 *V; /* Array of control points */ -// double t; /* Parametric value to find point for */ { - int i, j; - Vector2 Q; /* Point on curve at parameter t */ - Vector2 *Vtemp; /* Local copy of control points */ + int i, j; + Vector2 Q; /* Point on curve at parameter t */ + Vector2 *Vtemp; /* Local copy of control points */ - /* Copy array */ - Vtemp = (Vector2 *)malloc((unsigned)((degree+1) - * sizeof (Vector2))); - for (i = 0; i <= degree; i++) { + /* Copy array */ + Vtemp = (Vector2*)malloc((unsigned)((degree + 1) * sizeof (Vector2))); + for (i = 0; i <= degree; i++) { Vtemp[i] = V[i]; - } + } - /* Triangle computation */ - for (i = 1; i <= degree; i++) { + /* Triangle computation */ + for (i = 1; i <= degree; i++) { for (j = 0; j <= degree-i; j++) { - Vtemp[j][0] = (1.0 - t) * Vtemp[j][0] + t * Vtemp[j+1][0]; - Vtemp[j][1] = (1.0 - t) * Vtemp[j][1] + t * Vtemp[j+1][1]; + Vtemp[j][0] = (1.0 - t) * Vtemp[j][0] + t * Vtemp[j + 1][0]; + Vtemp[j][1] = (1.0 - t) * Vtemp[j][1] + t * Vtemp[j + 1][1]; } - } + } - Q = Vtemp[0]; - free((void *)Vtemp); - return Q; + Q = Vtemp[0]; + free((void*)Vtemp); + return Q; } - /* - * B0, B1, B2, B3 : - * Bezier multipliers + * B0, B1, B2, B3: + * Bezier multipliers */ static double B0(double u) { - double tmp = 1.0 - u; - return (tmp * tmp * tmp); + double tmp = 1.0 - u; + return (tmp * tmp * tmp); } static double B1(double u) { - double tmp = 1.0 - u; - return (3 * u * (tmp * tmp)); + double tmp = 1.0 - u; + return (3 * u * (tmp * tmp)); } static double B2(double u) { - double tmp = 1.0 - u; - return (3 * u * u * tmp); + double tmp = 1.0 - u; + return (3 * u * u * tmp); } static double B3(double u) { - return (u * u * u); + return (u * u * u); } - - /* - * ComputeLeftTangent, ComputeRightTangent, ComputeCenterTangent : - *Approximate unit tangents at endpoints and "center" of digitized curve + * ComputeLeftTangent, ComputeRightTangent, ComputeCenterTangent: + * Approximate unit tangents at endpoints and "center" of digitized curve + */ +/* Vector2 *d; Digitized points + * int end; Index to "left" end of region */ static Vector2 ComputeLeftTangent(Vector2 *d, int end) -// Vector2 *d; /* Digitized points*/ -// int end; /* Index to "left" end of region */ { - Vector2 tHat1; - tHat1 = V2SubII(d[end+1], d[end]); - tHat1 = *V2Normalize(&tHat1); - return tHat1; + Vector2 tHat1; + tHat1 = V2SubII(d[end + 1], d[end]); + tHat1 = *V2Normalize(&tHat1); + return tHat1; } +/* Vector2 *d; Digitized points + * int end; Index to "right" end of region + */ static Vector2 ComputeRightTangent(Vector2 *d, int end) -// Vector2 *d; /* Digitized points */ -// int end; /* Index to "right" end of region */ { - Vector2 tHat2; - tHat2 = V2SubII(d[end-1], d[end]); - tHat2 = *V2Normalize(&tHat2); - return tHat2; + Vector2 tHat2; + tHat2 = V2SubII(d[end - 1], d[end]); + tHat2 = *V2Normalize(&tHat2); + return tHat2; } +/* Vector2 *d; Digitized points + * int end; Index to point inside region + */ static Vector2 ComputeCenterTangent(Vector2 *d, int center) -// Vector2 *d; /* Digitized points */ -// int center; /* Index to point inside region */ { - Vector2 V1, V2, tHatCenter; + Vector2 V1, V2, tHatCenter; - V1 = V2SubII(d[center-1], d[center]); - V2 = V2SubII(d[center], d[center+1]); - tHatCenter[0] = (V1[0] + V2[0])/2.0; - tHatCenter[1] = (V1[1] + V2[1])/2.0; - tHatCenter = *V2Normalize(&tHatCenter); - return tHatCenter; + V1 = V2SubII(d[center - 1], d[center]); + V2 = V2SubII(d[center], d[center + 1]); + tHatCenter[0] = (V1[0] + V2[0]) / 2.0; + tHatCenter[1] = (V1[1] + V2[1]) / 2.0; + tHatCenter = *V2Normalize(&tHatCenter); + return tHatCenter; } - /* - * ChordLengthParameterize : - * Assign parameter values to digitized points - * using relative distances between points. + * ChordLengthParameterize: + * Assign parameter values to digitized points using relative distances between points. + * Vector2 *d; Array of digitized points + * int first, last; Indices defining region */ static double *ChordLengthParameterize(Vector2 *d, int first, int last) -// Vector2 *d; /* Array of digitized points */ -// int first, last; /* Indices defining region */ { - int i; - double *u; /* Parameterization */ + int i; + double *u; /* Parameterization */ - u = (double *)malloc((unsigned)(last-first+1) * sizeof(double)); + u = (double*)malloc((unsigned)(last - first + 1) * sizeof(double)); - u[0] = 0.0; - for (i = first+1; i <= last; i++) { - u[i-first] = u[i-first-1] + - V2DistanceBetween2Points(&d[i], &d[i-1]); - } + u[0] = 0.0; + for (i = first + 1; i <= last; i++) { + u[i - first] = u[i - first - 1] + V2DistanceBetween2Points(&d[i], &d[i - 1]); + } - for (i = first + 1; i <= last; i++) { - u[i-first] = u[i-first] / u[last-first]; - } + for (i = first + 1; i <= last; i++) { + u[i - first] = u[i - first] / u[last - first]; + } - return(u); + return u; } @@ -426,53 +430,57 @@ static double *ChordLengthParameterize(Vector2 *d, int first, int last) /* * ComputeMaxError : - * Find the maximum squared distance of digitized points - * to fitted curve. -*/ + * Find the maximum squared distance of digitized points to fitted curve. + * Vector2 *d; Array of digitized points + * int first, last; Indices defining region + * BezierCurve bezCurve; Fitted Bezier curve + * double *u; Parameterization of points + * int *splitPoint; Point of maximum error + */ static double ComputeMaxError(Vector2 *d, int first, int last, BezierCurve bezCurve, double *u, int *splitPoint) -// Vector2 *d; /* Array of digitized points */ -// int first, last; /* Indices defining region */ -// BezierCurve bezCurve; /* Fitted Bezier curve */ -// double *u; /* Parameterization of points */ -// int *splitPoint; /* Point of maximum error */ { - int i; - double maxDist; /* Maximum error */ - double dist; /* Current error */ - Vector2 P; /* Point on curve */ - Vector2 v; /* Vector from point to curve */ + int i; + double maxDist; /* Maximum error */ + double dist; /* Current error */ + Vector2 P; /* Point on curve */ + Vector2 v; /* Vector from point to curve */ - *splitPoint = (last - first + 1)/2; - maxDist = 0.0; - for (i = first + 1; i < last; i++) { - P = BezierII(3, bezCurve, u[i-first]); + *splitPoint = (last - first + 1) / 2; + maxDist = 0.0; + for (i = first + 1; i < last; i++) { + P = BezierII(3, bezCurve, u[i - first]); v = V2SubII(P, d[i]); dist = V2SquaredLength(&v); if (dist >= maxDist) { - maxDist = dist; - *splitPoint = i; + maxDist = dist; + *splitPoint = i; } - } - return (maxDist); + } + return maxDist; } + static Vector2 V2AddII(Vector2 a, Vector2 b) { - Vector2 c; - c[0] = a[0] + b[0]; c[1] = a[1] + b[1]; - return (c); + Vector2 c; + c[0] = a[0] + b[0]; + c[1] = a[1] + b[1]; + return c; } + static Vector2 V2ScaleIII(Vector2 v, double s) { - Vector2 result; - result[0] = v[0] * s; result[1] = v[1] * s; - return (result); + Vector2 result; + result[0] = v[0] * s; + result[1] = v[1] * s; + return result; } static Vector2 V2SubII(Vector2 a, Vector2 b) { - Vector2 c; - c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; - return (c); + Vector2 c; + c[0] = a[0] - b[0]; + c[1] = a[1] - b[1]; + return c; } #ifdef __cplusplus @@ -488,116 +496,107 @@ FitCurveWrapper::FitCurveWrapper() FitCurveWrapper::~FitCurveWrapper() { - _vertices.clear(); + _vertices.clear(); } -void FitCurveWrapper::DrawBezierCurve(int n, Vector2 *curve ) +void FitCurveWrapper::DrawBezierCurve(int n, Vector2 *curve) { - for(int i=0; i& data, vector& oCurve, double error) { - int size = data.size(); - Vector2 *d = new Vector2[size]; - for(int i=0; i::iterator v=_vertices.begin(), vend=_vertices.end(); - v!=vend; - ++v) - { - oCurve.push_back(Vec2d(v->x(), v->y())) ; - } - + // copy results + for (vector::iterator v = _vertices.begin(), vend = _vertices.end(); v != vend; ++v) { + oCurve.push_back(Vec2d(v->x(), v->y())) ; + } } void FitCurveWrapper::FitCurve(Vector2 *d, int nPts, double error) { - Vector2 tHat1, tHat2; /* Unit tangent vectors at endpoints */ + Vector2 tHat1, tHat2; /* Unit tangent vectors at endpoints */ - tHat1 = ComputeLeftTangent(d, 0); - tHat2 = ComputeRightTangent(d, nPts - 1); - FitCubic(d, 0, nPts - 1, tHat1, tHat2, error); + tHat1 = ComputeLeftTangent(d, 0); + tHat2 = ComputeRightTangent(d, nPts - 1); + FitCubic(d, 0, nPts - 1, tHat1, tHat2, error); } void FitCurveWrapper::FitCubic(Vector2 *d, int first, int last, Vector2 tHat1, Vector2 tHat2, double error) { - BezierCurve bezCurve; /*Control points of fitted Bezier curve*/ - double *u; /* Parameter values for point */ - double *uPrime; /* Improved parameter values */ - double maxError; /* Maximum fitting error */ - int splitPoint; /* Point to split point set at */ - int nPts; /* Number of points in subset */ - double iterationError; /*Error below which you try iterating */ - int maxIterations = 4; /* Max times to try iterating */ - Vector2 tHatCenter; /* Unit tangent vector at splitPoint */ - int i; + BezierCurve bezCurve; /* Control points of fitted Bezier curve */ + double *u; /* Parameter values for point */ + double *uPrime; /* Improved parameter values */ + double maxError; /* Maximum fitting error */ + int splitPoint; /* Point to split point set at */ + int nPts; /* Number of points in subset */ + double iterationError; /* Error below which you try iterating */ + int maxIterations = 4; /* Max times to try iterating */ + Vector2 tHatCenter; /* Unit tangent vector at splitPoint */ + int i; - iterationError = error * error; - nPts = last - first + 1; + iterationError = error * error; + nPts = last - first + 1; - /* Use heuristic if region only has two points in it */ - if (nPts == 2) { - double dist = V2DistanceBetween2Points(&d[last], &d[first]) / 3.0; + /* Use heuristic if region only has two points in it */ + if (nPts == 2) { + double dist = V2DistanceBetween2Points(&d[last], &d[first]) / 3.0; - bezCurve = (Vector2 *)malloc(4 * sizeof(Vector2)); + bezCurve = (Vector2*)malloc(4 * sizeof(Vector2)); bezCurve[0] = d[first]; bezCurve[3] = d[last]; V2Add(&bezCurve[0], V2Scale(&tHat1, dist), &bezCurve[1]); V2Add(&bezCurve[3], V2Scale(&tHat2, dist), &bezCurve[2]); DrawBezierCurve(3, bezCurve); - free((void *)bezCurve); + free((void*)bezCurve); return; - } - - /* Parameterize points, and attempt to fit curve */ - u = ChordLengthParameterize(d, first, last); - bezCurve = GenerateBezier(d, first, last, u, tHat1, tHat2); - - /* Find max deviation of points to fitted curve */ - maxError = ComputeMaxError(d, first, last, bezCurve, u, &splitPoint); - if (maxError < error) { - DrawBezierCurve(3, bezCurve); - free((void *)u); - free((void *)bezCurve); - return; - } - - - /* If error not too large, try some reparameterization */ - /* and iteration */ - if (maxError < iterationError) { - for (i = 0; i < maxIterations; i++) { - uPrime = Reparameterize(d, first, last, u, bezCurve); - bezCurve = GenerateBezier(d, first, last, uPrime, tHat1, tHat2); - maxError = ComputeMaxError(d, first, last, - bezCurve, uPrime, &splitPoint); - if (maxError < error) { - DrawBezierCurve(3, bezCurve); - free((void *)u); - free((void *)bezCurve); - return; - } - free((void *)u); - u = uPrime; } - } - /* Fitting failed -- split at max error point and fit recursively */ - free((void *)u); - free((void *)bezCurve); - tHatCenter = ComputeCenterTangent(d, splitPoint); - FitCubic(d, first, splitPoint, tHat1, tHatCenter, error); - V2Negate(&tHatCenter); - FitCubic(d, splitPoint, last, tHatCenter, tHat2, error); + /* Parameterize points, and attempt to fit curve */ + u = ChordLengthParameterize(d, first, last); + bezCurve = GenerateBezier(d, first, last, u, tHat1, tHat2); + /* Find max deviation of points to fitted curve */ + maxError = ComputeMaxError(d, first, last, bezCurve, u, &splitPoint); + if (maxError < error) { + DrawBezierCurve(3, bezCurve); + free((void*)u); + free((void*)bezCurve); + return; + } + + /* If error not too large, try some reparameterization and iteration */ + if (maxError < iterationError) { + for (i = 0; i < maxIterations; i++) { + uPrime = Reparameterize(d, first, last, u, bezCurve); + bezCurve = GenerateBezier(d, first, last, uPrime, tHat1, tHat2); + maxError = ComputeMaxError(d, first, last, + bezCurve, uPrime, &splitPoint); + if (maxError < error) { + DrawBezierCurve(3, bezCurve); + free((void*)u); + free((void*)bezCurve); + return; + } + free((void*)u); + u = uPrime; + } + } + + /* Fitting failed -- split at max error point and fit recursively */ + free((void*)u); + free((void*)bezCurve); + tHatCenter = ComputeCenterTangent(d, splitPoint); + FitCubic(d, first, splitPoint, tHat1, tHatCenter, error); + V2Negate(&tHatCenter); + FitCubic(d, splitPoint, last, tHatCenter, tHat2, error); } - diff --git a/source/blender/freestyle/intern/geometry/FitCurve.h b/source/blender/freestyle/intern/geometry/FitCurve.h index ed7cbe34780..0a80c2f28f9 100644 --- a/source/blender/freestyle/intern/geometry/FitCurve.h +++ b/source/blender/freestyle/intern/geometry/FitCurve.h @@ -1,101 +1,125 @@ -// -// Filename : FitCurve.h -// Author(s) : Stephane Grabli -// Purpose : An Algorithm for Automatically Fitting Digitized Curves -// by Philip J. Schneider -// from "Graphics Gems", Academic Press, 1990 -// Date of creation : 06/06/2003 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __FITCURVE_H__ +#define __FITCURVE_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef FITCURVE_H -# define FITCURVE_H +/** \file blender/freestyle/intern/geometry/FitCurve.h + * \ingroup freestyle + * \brief An Algorithm for Automatically Fitting Digitized Curves by Philip J. Schneider, + * \brief from "Graphics Gems", Academic Press, 1990 + * \author Stephane Grabli + * \date 06/06/2003 + */ #include -#include "../system/FreestyleConfig.h" + #include "Geom.h" +#include "../system/FreestyleConfig.h" + using namespace Geometry; -typedef struct Point2Struct { /* 2d point */ +/* 2d point */ +typedef struct Point2Struct +{ double coordinates[2]; - Point2Struct() {coordinates[0]=0;coordinates[1]=0;} - inline double operator[](const int i) const - { - return coordinates[i]; - } - inline double& operator[](const int i) - { - return coordinates[i]; - } - inline double x() const {return coordinates[0];} - inline double y() const {return coordinates[1];} - } Point2; + + Point2Struct() + { + coordinates[0] = 0; + coordinates[1] = 0; + } + + inline double operator[](const int i) const + { + return coordinates[i]; + } + + inline double& operator[](const int i) + { + return coordinates[i]; + } + + inline double x() const + { + return coordinates[0]; + } + + inline double y() const + { + return coordinates[1]; + } +} Point2; typedef Point2 Vector2; - class LIB_GEOMETRY_EXPORT FitCurveWrapper { private: - std::vector _vertices; + std::vector _vertices; public: - FitCurveWrapper(); - ~FitCurveWrapper(); + FitCurveWrapper(); + ~FitCurveWrapper(); + + /*! Fits a set of 2D data points to a set of Bezier Curve segments + * data + * Input data points + * oCurve + * Control points of the sets of bezier curve segments. + * Each segment is made of 4 points (polynomial degree of curve = 3) + * error + * max error tolerance between resulting curve and input data + */ + void FitCurve(std::vector& data, std::vector& oCurve, double error); - /*! Fits a set of 2D data points to a set of Bezier Curve segments - * data - * Input data points - * oCurve - * Control points of the sets of bezier curve segments. - * Each segment is made of 4 points (polynomial degree of curve = 3) - * error - * max error tolerance between resulting curve and input data - */ - void FitCurve(std::vector& data, std::vector& oCurve, double error); protected: - /* Vec2d *d; Array of digitized points */ - /* int nPts; Number of digitized points */ - /* double error; User-defined error squared */ - void FitCurve(Vector2 *d, int nPts, double error); - - /*! Draws a Bezier curve segment - * n - * degree of curve (=3) - * curve - * bezier segments control points - */ - void DrawBezierCurve(int n, Vector2 *curve); - - /* Vec2d *d; Array of digitized points */ - /* int first, last; Indices of first and last pts in region */ - /* Vec2d tHat1, tHat2; Unit tangent vectors at endpoints */ - /* double error; User-defined error squared */ - void FitCubic(Vector2 *d, int first, int last, Vector2 tHat1, Vector2 tHat2, double error); - + /* Vec2d *d; Array of digitized points + * int nPts; Number of digitized points + * double error; User-defined error squared + */ + void FitCurve(Vector2 *d, int nPts, double error); + + /*! Draws a Bezier curve segment + * n + * degree of curve (=3) + * curve + * bezier segments control points + */ + void DrawBezierCurve(int n, Vector2 *curve); + + /* Vec2d *d; Array of digitized points + * int first, last; Indices of first and last pts in region + * Vec2d tHat1, tHat2; Unit tangent vectors at endpoints + * double error; User-defined error squared + */ + void FitCubic(Vector2 *d, int first, int last, Vector2 tHat1, Vector2 tHat2, double error); }; -#endif // FITCURVE_H +#endif // __FITCURVE_H__ diff --git a/source/blender/freestyle/intern/geometry/Geom.h b/source/blender/freestyle/intern/geometry/Geom.h index ac94213fe98..f241346ec85 100644 --- a/source/blender/freestyle/intern/geometry/Geom.h +++ b/source/blender/freestyle/intern/geometry/Geom.h @@ -1,78 +1,84 @@ -// -// Filename : Geom.h -// Author(s) : Sylvain Paris -// Emmanuel Turquin -// Stephane Grabli -// Purpose : Vectors and Matrices (useful type definitions) -// Date of creation : 20/05/2003 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __GEOM_H__ +#define __GEOM_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/Geom.h + * \ingroup freestyle + * \brief Vectors and Matrices (useful type definitions) + * \author Sylvain Paris + * \author Emmanuel Turquin + * \author Stephane Grabli + * \date 20/05/2003 + */ -#ifndef GEOM_H -# define GEOM_H +#include "VecMat.h" -# include "VecMat.h" -# include "../system/Precision.h" +#include "../system/Precision.h" namespace Geometry { - typedef VecMat::Vec2 Vec2u; - typedef VecMat::Vec2 Vec2i; - typedef VecMat::Vec2 Vec2f; - typedef VecMat::Vec2 Vec2d; - typedef VecMat::Vec2 Vec2r; +typedef VecMat::Vec2 Vec2u; +typedef VecMat::Vec2 Vec2i; +typedef VecMat::Vec2 Vec2f; +typedef VecMat::Vec2 Vec2d; +typedef VecMat::Vec2 Vec2r; - typedef VecMat::Vec3 Vec3u; - typedef VecMat::Vec3 Vec3i; - typedef VecMat::Vec3 Vec3f; - typedef VecMat::Vec3 Vec3d; - typedef VecMat::Vec3 Vec3r; +typedef VecMat::Vec3 Vec3u; +typedef VecMat::Vec3 Vec3i; +typedef VecMat::Vec3 Vec3f; +typedef VecMat::Vec3 Vec3d; +typedef VecMat::Vec3 Vec3r; - typedef VecMat::HVec3 HVec3u; - typedef VecMat::HVec3 HVec3i; - typedef VecMat::HVec3 HVec3f; - typedef VecMat::HVec3 HVec3d; - typedef VecMat::HVec3 HVec3r; +typedef VecMat::HVec3 HVec3u; +typedef VecMat::HVec3 HVec3i; +typedef VecMat::HVec3 HVec3f; +typedef VecMat::HVec3 HVec3d; +typedef VecMat::HVec3 HVec3r; - typedef VecMat::SquareMatrix Matrix22u; - typedef VecMat::SquareMatrix Matrix22i; - typedef VecMat::SquareMatrix Matrix22f; - typedef VecMat::SquareMatrix Matrix22d; - typedef VecMat::SquareMatrix Matrix22r; +typedef VecMat::SquareMatrix Matrix22u; +typedef VecMat::SquareMatrix Matrix22i; +typedef VecMat::SquareMatrix Matrix22f; +typedef VecMat::SquareMatrix Matrix22d; +typedef VecMat::SquareMatrix Matrix22r; - typedef VecMat::SquareMatrix Matrix33u; - typedef VecMat::SquareMatrix Matrix33i; - typedef VecMat::SquareMatrix Matrix33f; - typedef VecMat::SquareMatrix Matrix33d; - typedef VecMat::SquareMatrix Matrix33r; +typedef VecMat::SquareMatrix Matrix33u; +typedef VecMat::SquareMatrix Matrix33i; +typedef VecMat::SquareMatrix Matrix33f; +typedef VecMat::SquareMatrix Matrix33d; +typedef VecMat::SquareMatrix Matrix33r; - typedef VecMat::SquareMatrix Matrix44u; - typedef VecMat::SquareMatrix Matrix44i; - typedef VecMat::SquareMatrix Matrix44f; - typedef VecMat::SquareMatrix Matrix44d; - typedef VecMat::SquareMatrix Matrix44r; +typedef VecMat::SquareMatrix Matrix44u; +typedef VecMat::SquareMatrix Matrix44i; +typedef VecMat::SquareMatrix Matrix44f; +typedef VecMat::SquareMatrix Matrix44d; +typedef VecMat::SquareMatrix Matrix44r; } // end of namespace Geometry -#endif // GEOM_H +#endif // __GEOM_H__ diff --git a/source/blender/freestyle/intern/geometry/GeomCleaner.cpp b/source/blender/freestyle/intern/geometry/GeomCleaner.cpp index c148c521a46..aba845a2faf 100644 --- a/source/blender/freestyle/intern/geometry/GeomCleaner.cpp +++ b/source/blender/freestyle/intern/geometry/GeomCleaner.cpp @@ -1,240 +1,233 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/GeomCleaner.cpp + * \ingroup freestyle + * \brief Class to define a cleaner of geometry providing a set of useful tools + * \author Stephane Grabli + * \date 04/03/2002 + */ -//#if defined(__GNUC__) && (__GNUC__ >= 3) -//// hash_map is not part of the C++ standard anymore; -//// hash_map.h has been kept though for backward compatibility -//# include -//#else -//# include -//#endif +#if 0 +#if defined(__GNUC__) && (__GNUC__ >= 3) +// hash_map is not part of the C++ standard anymore; +// hash_map.h has been kept though for backward compatibility +# include +#else +# include +#endif +#endif #include #include #include -#include "../system/TimeUtils.h" + #include "GeomCleaner.h" +#include "../system/TimeUtils.h" + using namespace std; -void GeomCleaner::SortIndexedVertexArray( const float *iVertices, unsigned iVSize, - const unsigned *iIndices, unsigned iISize, - real **oVertices, - unsigned **oIndices) +void GeomCleaner::SortIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices, + unsigned iISize, real **oVertices, unsigned **oIndices) { - // First, we build a list of IndexVertex: - list indexedVertices; - unsigned i; - for(i=0; i indexedVertices; + unsigned i; + for (i = 0; i < iVSize; i += 3) { + indexedVertices.push_back(IndexedVertex(Vec3r(iVertices[i], iVertices[i + 1], iVertices[i + 2]), i / 3)); + } - // q-sort - indexedVertices.sort(); + // q-sort + indexedVertices.sort(); - // build the indices mapping array: - unsigned *mapIndices = new unsigned[iVSize/3]; - *oVertices = new real[iVSize]; - list::iterator iv; - unsigned newIndex = 0; - unsigned vIndex = 0; - for(iv=indexedVertices.begin(); iv!=indexedVertices.end(); iv++) - { - // Build the final results: - (*oVertices)[vIndex] = iv->x(); - (*oVertices)[vIndex+1] = iv->y(); - (*oVertices)[vIndex+2] = iv->z(); + // build the indices mapping array: + unsigned *mapIndices = new unsigned[iVSize / 3]; + *oVertices = new real[iVSize]; + list::iterator iv; + unsigned newIndex = 0; + unsigned vIndex = 0; + for (iv = indexedVertices.begin(); iv != indexedVertices.end(); iv++) { + // Build the final results: + (*oVertices)[vIndex] = iv->x(); + (*oVertices)[vIndex + 1] = iv->y(); + (*oVertices)[vIndex + 2] = iv->z(); - mapIndices[iv->index()] = newIndex; - newIndex++; - vIndex+=3; - } + mapIndices[iv->index()] = newIndex; + newIndex++; + vIndex += 3; + } - - // Build the final index array: - *oIndices = new unsigned[iISize]; - for(i=0; i vertices; - unsigned i; - for(i=0; i vertices; + unsigned i; + for (i = 0; i < iVSize; i += 3) { + vertices.push_back(Vec3r(iVertices[i], iVertices[i + 1], iVertices[i + 2])); + } - unsigned *mapVertex = new unsigned[iVSize]; - vector::iterator v = vertices.begin(); - - vector compressedVertices; - Vec3r previous = *v; - mapVertex[0] = 0; - compressedVertices.push_back(vertices.front()); + unsigned *mapVertex = new unsigned[iVSize]; + vector::iterator v = vertices.begin(); - v++; - Vec3r current; - i=1; - for(; v!=vertices.end(); v++) - { - current = *v; - if(current == previous) - mapVertex[i] = compressedVertices.size()-1; - else - { - compressedVertices.push_back(current); - mapVertex[i] = compressedVertices.size()-1; - } - previous = current; - i++; - } + vector compressedVertices; + Vec3r previous = *v; + mapVertex[0] = 0; + compressedVertices.push_back(vertices.front()); - // Builds the resulting vertex array: - *oVSize = 3*compressedVertices.size(); - *oVertices = new real [*oVSize]; - i=0; - for(v=compressedVertices.begin(); v!=compressedVertices.end(); v++) - { - (*oVertices)[i] = (*v)[0]; - (*oVertices)[i+1] = (*v)[1]; - (*oVertices)[i+2] = (*v)[2]; - i += 3; - } + v++; + Vec3r current; + i = 1; + for (; v != vertices.end(); v++) { + current = *v; + if (current == previous) + mapVertex[i] = compressedVertices.size() - 1; + else { + compressedVertices.push_back(current); + mapVertex[i] = compressedVertices.size() - 1; + } + previous = current; + i++; + } - // Map the index array: - *oIndices = new unsigned[iISize]; - for(i=0; i cleanHashTable; - vector vertices; - unsigned i; - for(i=0; i newIndices; - vector newVertices; - - // elimination of needless points - unsigned currentIndex = 0; - vector::const_iterator v = vertices.begin(); - vector::const_iterator end = vertices.end(); - cleanHashTable::const_iterator found; - for(; v!=end; v++) - { - found = ht.find(*v); - if(found != ht.end()) - { - // The vertex is already in the new array. - newIndices.push_back((*found).second); - } - else - { - newVertices.push_back(*v); - newIndices.push_back(currentIndex); - ht[*v] = currentIndex; - currentIndex++; - } - } + typedef map cleanHashTable; + vector vertices; + unsigned i; + for (i = 0; i < iVSize; i += 3) + vertices.push_back(Vec3r(iVertices[i], iVertices[i + 1], iVertices[i + 2])); - // creation of oVertices array: - *oVSize = 3*newVertices.size(); - *oVertices = new real[*oVSize]; - currentIndex = 0; - end = newVertices.end(); - for(v=newVertices.begin(); v!=end ; v++) - { - (*oVertices)[currentIndex++] = (*v)[0]; - (*oVertices)[currentIndex++] = (*v)[1]; - (*oVertices)[currentIndex++] = (*v)[2]; - } + cleanHashTable ht; + vector newIndices; + vector newVertices; - // map new indices: - *oIndices = new unsigned[iISize]; - for(i=0; i::const_iterator v = vertices.begin(); + vector::const_iterator end = vertices.end(); + cleanHashTable::const_iterator found; + for (; v != end; v++) { + found = ht.find(*v); + if (found != ht.end()) { + // The vertex is already in the new array. + newIndices.push_back((*found).second); + } + else { + newVertices.push_back(*v); + newIndices.push_back(currentIndex); + ht[*v] = currentIndex; + currentIndex++; + } + } + + // creation of oVertices array: + *oVSize = 3 * newVertices.size(); + *oVertices = new real[*oVSize]; + currentIndex = 0; + end = newVertices.end(); + for (v = newVertices.begin(); v != end ; v++) { + (*oVertices)[currentIndex++] = (*v)[0]; + (*oVertices)[currentIndex++] = (*v)[1]; + (*oVertices)[currentIndex++] = (*v)[2]; + } + + // map new indices: + *oIndices = new unsigned[iISize]; + for (i = 0; i < iISize; i++) + (*oIndices)[i] = 3 * newIndices[iIndices[i] / 3]; } diff --git a/source/blender/freestyle/intern/geometry/GeomCleaner.h b/source/blender/freestyle/intern/geometry/GeomCleaner.h index 5fdfda0162a..334145f3bcd 100644 --- a/source/blender/freestyle/intern/geometry/GeomCleaner.h +++ b/source/blender/freestyle/intern/geometry/GeomCleaner.h @@ -1,219 +1,227 @@ -// -// Filename : GeomCleaner.h -// Author : Stephane Grabli -// Purpose : Class to define a cleaner of geometry providing -// a set of useful tools -// Date of creation : 04/03/2002 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __GEOMCLEANER_H__ +#define __GEOMCLEANER_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/GeomCleaner.h + * \ingroup freestyle + * \brief Class to define a cleaner of geometry providing a set of useful tools + * \author Stephane Grabli + * \date 04/03/2002 + */ -#ifndef GEOMCLEANER_H -# define GEOMCLEANER_H +#include "Geom.h" -# include "../system/FreestyleConfig.h" -# include "Geom.h" +#include "../system/FreestyleConfig.h" using namespace Geometry; class LIB_GEOMETRY_EXPORT GeomCleaner { public: + inline GeomCleaner() {} + inline ~GeomCleaner() {} - inline GeomCleaner() {} - inline ~GeomCleaner() {} + /*! Sorts an array of Indexed vertices + * iVertices + * Array of vertices to sort. It is organized as a float series of vertex coordinates: XYZXYZXYZ... + * iVSize + * The size of iVertices array. + * iIndices + * The array containing the vertex indices (used to refer to the vertex coordinates in an indexed face). Each + * element is an unsignedeger multiple of 3. + * iISize + * The size of iIndices array + * oVertices + * Output of sorted vertices. A vertex v1 precedes another one v2 in this array if v1.x A[0])&&(A[0] > min[0]))&&((max[0] > B[0])&&(B[0] > min[0]))) - && (((max[1] > A[1])&&(A[1] > min[1]))&&((max[1] > B[1])&&(B[1] > min[1])))) - return true; - return false; - } +bool include2dSeg2dArea(const Vec2r& min, const Vec2r& max, const Vec2r& A, const Vec2r& B) +{ + if ((((max[0] > A[0]) && (A[0] > min[0])) && ((max[0] > B[0]) && (B[0] > min[0]))) && + (((max[1] > A[1]) && (A[1] > min[1])) && ((max[1] > B[1]) && (B[1] > min[1])))) + return true; + return false; +} - intersection_test intersect2dSeg2dSeg(const Vec2r& p1, - const Vec2r& p2, - const Vec2r& p3, - const Vec2r& p4, - Vec2r& res) { - real a1, a2, b1, b2, c1, c2; // Coefficients of line eqns - real r1, r2, r3, r4; // 'Sign' values - real denom, num; // Intermediate values +intersection_test intersect2dSeg2dSeg(const Vec2r& p1, const Vec2r& p2, const Vec2r& p3, const Vec2r& p4, Vec2r& res) +{ + real a1, a2, b1, b2, c1, c2; // Coefficients of line eqns + real r1, r2, r3, r4; // 'Sign' values + real denom, num; // Intermediate values - // Compute a1, b1, c1, where line joining points p1 and p2 - // is "a1 x + b1 y + c1 = 0". - a1 = p2[1] - p1[1]; - b1 = p1[0] - p2[0]; - c1 = p2[0] * p1[1] - p1[0] * p2[1]; + // Compute a1, b1, c1, where line joining points p1 and p2 is "a1 x + b1 y + c1 = 0". + a1 = p2[1] - p1[1]; + b1 = p1[0] - p2[0]; + c1 = p2[0] * p1[1] - p1[0] * p2[1]; - // Compute r3 and r4. - r3 = a1 * p3[0] + b1 * p3[1] + c1; - r4 = a1 * p4[0] + b1 * p4[1] + c1; + // Compute r3 and r4. + r3 = a1 * p3[0] + b1 * p3[1] + c1; + r4 = a1 * p4[0] + b1 * p4[1] + c1; - // Check signs of r3 and r4. If both point 3 and point 4 lie on - // same side of line 1, the line segments do not intersect. - if ( r3 != 0 && r4 != 0 && r3 * r4 > 0.0) - return (DONT_INTERSECT); + // Check signs of r3 and r4. If both point 3 and point 4 lie on same side of line 1, + // the line segments do not intersect. + if ( r3 != 0 && r4 != 0 && r3 * r4 > 0.0) + return (DONT_INTERSECT); - // Compute a2, b2, c2 - a2 = p4[1] - p3[1]; - b2 = p3[0] - p4[0]; - c2 = p4[0] * p3[1] - p3[0] * p4[1]; + // Compute a2, b2, c2 + a2 = p4[1] - p3[1]; + b2 = p3[0] - p4[0]; + c2 = p4[0] * p3[1] - p3[0] * p4[1]; - // Compute r1 and r2 - r1 = a2 * p1[0] + b2 * p1[1] + c2; - r2 = a2 * p2[0] + b2 * p2[1] + c2; + // Compute r1 and r2 + r1 = a2 * p1[0] + b2 * p1[1] + c2; + r2 = a2 * p2[0] + b2 * p2[1] + c2; - // Check signs of r1 and r2. If both point 1 and point 2 lie - // on same side of second line segment, the line segments do - // not intersect. - if ( r1 != 0 && r2 != 0 && r1 * r2 > 0.0) - return (DONT_INTERSECT); + // Check signs of r1 and r2. If both point 1 and point 2 lie on same side of second line segment, + // the line segments do not intersect. + if (r1 != 0 && r2 != 0 && r1 * r2 > 0.0) + return (DONT_INTERSECT); - // Line segments intersect: compute intersection point. - denom = a1 * b2 - a2 * b1; - if (fabs(denom) < M_EPSILON) - return (COLINEAR); - - num = b1 * c2 - b2 * c1; - res[0] = num / denom; + // Line segments intersect: compute intersection point. + denom = a1 * b2 - a2 * b1; + if (fabs(denom) < M_EPSILON) + return (COLINEAR); - num = a2 * c1 - a1 * c2; - res[1] = num / denom; + num = b1 * c2 - b2 * c1; + res[0] = num / denom; - return (DO_INTERSECT); - } + num = a2 * c1 - a1 * c2; + res[1] = num / denom; - intersection_test intersect2dLine2dLine(const Vec2r& p1, - const Vec2r& p2, - const Vec2r& p3, - const Vec2r& p4, - Vec2r& res) { - real a1, a2, b1, b2, c1, c2; // Coefficients of line eqns - real denom, num; // Intermediate values + return (DO_INTERSECT); +} - // Compute a1, b1, c1, where line joining points p1 and p2 - // is "a1 x + b1 y + c1 = 0". - a1 = p2[1] - p1[1]; - b1 = p1[0] - p2[0]; - c1 = p2[0] * p1[1] - p1[0] * p2[1]; +intersection_test intersect2dLine2dLine(const Vec2r& p1, const Vec2r& p2, const Vec2r& p3, const Vec2r& p4, Vec2r& res) +{ + real a1, a2, b1, b2, c1, c2; // Coefficients of line eqns + real denom, num; // Intermediate values - // Compute a2, b2, c2 - a2 = p4[1] - p3[1]; - b2 = p3[0] - p4[0]; - c2 = p4[0] * p3[1] - p3[0] * p4[1]; + // Compute a1, b1, c1, where line joining points p1 and p2 is "a1 x + b1 y + c1 = 0". + a1 = p2[1] - p1[1]; + b1 = p1[0] - p2[0]; + c1 = p2[0] * p1[1] - p1[0] * p2[1]; - // Line segments intersect: compute intersection point. - denom = a1 * b2 - a2 * b1; - if (fabs(denom) < M_EPSILON) - return (COLINEAR); + // Compute a2, b2, c2 + a2 = p4[1] - p3[1]; + b2 = p3[0] - p4[0]; + c2 = p4[0] * p3[1] - p3[0] * p4[1]; - num = b1 * c2 - b2 * c1; - res[0] = num / denom; + // Line segments intersect: compute intersection point. + denom = a1 * b2 - a2 * b1; + if (fabs(denom) < M_EPSILON) + return (COLINEAR); - num = a2 * c1 - a1 * c2; - res[1] = num / denom; + num = b1 * c2 - b2 * c1; + res[0] = num / denom; - return (DO_INTERSECT); - } + num = a2 * c1 - a1 * c2; + res[1] = num / denom; - intersection_test intersect2dSeg2dSegParametric(const Vec2r& p1, - const Vec2r& p2, - const Vec2r& p3, - const Vec2r& p4, - real& t, - real& u, - real epsilon) { - real a1, a2, b1, b2, c1, c2; // Coefficients of line eqns - real r1, r2, r3, r4; // 'Sign' values - real denom, num; // Intermediate values + return (DO_INTERSECT); +} - // Compute a1, b1, c1, where line joining points p1 and p2 - // is "a1 x + b1 y + c1 = 0". - a1 = p2[1] - p1[1]; - b1 = p1[0] - p2[0]; - c1 = p2[0] * p1[1] - p1[0] * p2[1]; +intersection_test intersect2dSeg2dSegParametric(const Vec2r& p1, const Vec2r& p2, const Vec2r& p3, const Vec2r& p4, + real& t, real& u, real epsilon) +{ + real a1, a2, b1, b2, c1, c2; // Coefficients of line eqns + real r1, r2, r3, r4; // 'Sign' values + real denom, num; // Intermediate values - // Compute r3 and r4. - r3 = a1 * p3[0] + b1 * p3[1] + c1; - r4 = a1 * p4[0] + b1 * p4[1] + c1; + // Compute a1, b1, c1, where line joining points p1 and p2 is "a1 x + b1 y + c1 = 0". + a1 = p2[1] - p1[1]; + b1 = p1[0] - p2[0]; + c1 = p2[0] * p1[1] - p1[0] * p2[1]; - // Check signs of r3 and r4. If both point 3 and point 4 lie on - // same side of line 1, the line segments do not intersect. - if ( r3 != 0 && r4 != 0 && r3 * r4 > 0.0) - return (DONT_INTERSECT); + // Compute r3 and r4. + r3 = a1 * p3[0] + b1 * p3[1] + c1; + r4 = a1 * p4[0] + b1 * p4[1] + c1; - // Compute a2, b2, c2 - a2 = p4[1] - p3[1]; - b2 = p3[0] - p4[0]; - c2 = p4[0] * p3[1] - p3[0] * p4[1]; + // Check signs of r3 and r4. If both point 3 and point 4 lie on same side of line 1, + // the line segments do not intersect. + if (r3 != 0 && r4 != 0 && r3 * r4 > 0.0) + return (DONT_INTERSECT); - // Compute r1 and r2 - r1 = a2 * p1[0] + b2 * p1[1] + c2; - r2 = a2 * p2[0] + b2 * p2[1] + c2; + // Compute a2, b2, c2 + a2 = p4[1] - p3[1]; + b2 = p3[0] - p4[0]; + c2 = p4[0] * p3[1] - p3[0] * p4[1]; - // Check signs of r1 and r2. If both point 1 and point 2 lie - // on same side of second line segment, the line segments do - // not intersect. - if ( r1 != 0 && r2 != 0 && r1 * r2 > 0.0) - return (DONT_INTERSECT); + // Compute r1 and r2 + r1 = a2 * p1[0] + b2 * p1[1] + c2; + r2 = a2 * p2[0] + b2 * p2[1] + c2; - // Line segments intersect: compute intersection point. - denom = a1 * b2 - a2 * b1; - if (fabs(denom) < epsilon) - return (COLINEAR); - - real d1, d2, e1; + // Check signs of r1 and r2. If both point 1 and point 2 lie on same side of second line segment, + // the line segments do not intersect. + if (r1 != 0 && r2 != 0 && r1 * r2 > 0.0) + return (DONT_INTERSECT); - d1 = p1[1] - p3[1]; - d2 = p2[1] - p1[1]; - e1 = p1[0] - p3[0]; + // Line segments intersect: compute intersection point. + denom = a1 * b2 - a2 * b1; + if (fabs(denom) < epsilon) + return (COLINEAR); - num = -b2 * d1 - a2 * e1; - t = num / denom; + real d1, d2, e1; - num = -b1 * d1 - a1 * e1; - u = num / denom; + d1 = p1[1] - p3[1]; + d2 = p2[1] - p1[1]; + e1 = p1[0] - p3[0]; - return (DO_INTERSECT); - } + num = -b2 * d1 - a2 * e1; + t = num / denom; - // AABB-triangle overlap test code - // by Tomas Akenine-Möller - // Function: int triBoxOverlap(real boxcenter[3], - // real boxhalfsize[3],real triverts[3][3]); - // History: - // 2001-03-05: released the code in its first version - // 2001-06-18: changed the order of the tests, faster - // - // Acknowledgement: Many thanks to Pierre Terdiman for - // suggestions and discussions on how to optimize code. - // Thanks to David Hunt for finding a ">="-bug! + num = -b1 * d1 - a1 * e1; + u = num / denom; + + return (DO_INTERSECT); +} + +// AABB-triangle overlap test code by Tomas Akenine-Möller +// Function: int triBoxOverlap(real boxcenter[3], real boxhalfsize[3],real triverts[3][3]); +// History: +// 2001-03-05: released the code in its first version +// 2001-06-18: changed the order of the tests, faster +// +// Acknowledgement: Many thanks to Pierre Terdiman for suggestions and discussions on how to optimize code. +// Thanks to David Hunt for finding a ">="-bug! #define X 0 #define Y 1 #define Z 2 #define FINDMINMAX(x0, x1, x2, min, max) \ - min = max = x0; \ - if(x1max) max=x1; \ - if(x2max) max=x2; + { \ + min = max = x0; \ + if (x1 < min) \ + min = x1; \ + if (x1 > max) \ + max = x1; \ + if (x2 < min) \ + min = x2; \ + if (x2 > max) \ + max = x2; \ + } (void)0 - //======================== X-tests ========================// -#define AXISTEST_X01(a, b, fa, fb) \ - p0 = a*v0[Y] - b*v0[Z]; \ - p2 = a*v2[Y] - b*v2[Z]; \ - if(p0rad || max<-rad) return 0; +//======================== X-tests ========================// +#define AXISTEST_X01(a, b, fa, fb) \ + { \ + p0 = a * v0[Y] - b * v0[Z]; \ + p2 = a * v2[Y] - b * v2[Z]; \ + if (p0 < p2) { \ + min = p0; \ + max = p2; \ + } \ + else { \ + min = p2; \ + max = p0; \ + } \ + rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z]; \ + if (min > rad || max < -rad) \ + return 0; \ + } (void)0 -#define AXISTEST_X2(a, b, fa, fb) \ - p0 = a*v0[Y] - b*v0[Z]; \ - p1 = a*v1[Y] - b*v1[Z]; \ - if(p0rad || max<-rad) return 0; +#define AXISTEST_X2(a, b, fa, fb) \ + { \ + p0 = a * v0[Y] - b * v0[Z]; \ + p1 = a * v1[Y] - b * v1[Z]; \ + if (p0 < p1) { \ + min = p0; \ + max = p1; \ + } \ + else { \ + min = p1; \ + max = p0; \ + } \ + rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z]; \ + if (min > rad || max < -rad) \ + return 0; \ + } (void)0 - //======================== Y-tests ========================// -#define AXISTEST_Y02(a, b, fa, fb) \ - p0 = -a*v0[X] + b*v0[Z]; \ - p2 = -a*v2[X] + b*v2[Z]; \ - if(p0rad || max<-rad) return 0; +//======================== Y-tests ========================// +#define AXISTEST_Y02(a, b, fa, fb) \ + { \ + p0 = -a * v0[X] + b * v0[Z]; \ + p2 = -a * v2[X] + b * v2[Z]; \ + if (p0 < p2) { \ + min = p0; \ + max = p2; \ + } \ + else { \ + min = p2; \ + max = p0; \ + } \ + rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z]; \ + if (min > rad || max < -rad) \ + return 0; \ + } (void)0 -#define AXISTEST_Y1(a, b, fa, fb) \ - p0 = -a*v0[X] + b*v0[Z]; \ - p1 = -a*v1[X] + b*v1[Z]; \ - if(p0rad || max<-rad) return 0; +#define AXISTEST_Y1(a, b, fa, fb) \ + { \ + p0 = -a * v0[X] + b * v0[Z]; \ + p1 = -a * v1[X] + b * v1[Z]; \ + if (p0 < p1) { \ + min = p0; \ + max = p1; \ + } \ + else { \ + min = p1; \ + max = p0; \ + } \ + rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z]; \ + if (min > rad || max < -rad) \ + return 0; \ + } (void)0 - //======================== Z-tests ========================// -#define AXISTEST_Z12(a, b, fa, fb) \ - p1 = a*v1[X] - b*v1[Y]; \ - p2 = a*v2[X] - b*v2[Y]; \ - if(p2rad || max<-rad) return 0; +//======================== Z-tests ========================// +#define AXISTEST_Z12(a, b, fa, fb) \ + { \ + p1 = a * v1[X] - b * v1[Y]; \ + p2 = a * v2[X] - b * v2[Y]; \ + if (p2 < p1) { \ + min = p2; \ + max = p1; \ + } \ + else { \ + min = p1; \ + max = p2; \ + } \ + rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y]; \ + if (min > rad || max < -rad) \ + return 0; \ + } (void)0 -#define AXISTEST_Z0(a, b, fa, fb) \ - p0 = a*v0[X] - b*v0[Y]; \ - p1 = a*v1[X] - b*v1[Y]; \ - if(p0rad || max<-rad) return 0; - - // This internal procedure is defined below. - bool overlapPlaneBox(Vec3r& normal, real d, Vec3r& maxbox); +#define AXISTEST_Z0(a, b, fa, fb) \ + { \ + p0 = a * v0[X] - b * v0[Y]; \ + p1 = a * v1[X] - b * v1[Y]; \ + if (p0 < p1) { \ + min = p0; \ + max = p1; \ + } \ + else { \ + min = p1; \ + max = p0; \ + } \ + rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y]; \ + if (min > rad || max < -rad) \ + return 0; \ + } (void)0 - // Use separating axis theorem to test overlap between triangle and box - // need to test for overlap in these directions: - // 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle - // we do not even need to test these) - // 2) normal of the triangle - // 3) crossproduct(edge from tri, {x,y,z}-directin) - // this gives 3x3=9 more tests - bool overlapTriangleBox(Vec3r& boxcenter, - Vec3r& boxhalfsize, - Vec3r triverts[3]) { - Vec3r v0, v1, v2, normal, e0, e1, e2; - real min, max, d, p0, p1, p2, rad, fex, fey, fez; +// This internal procedure is defined below. +bool overlapPlaneBox(Vec3r& normal, real d, Vec3r& maxbox); - // This is the fastest branch on Sun - // move everything so that the boxcenter is in (0, 0, 0) - v0 = triverts[0] - boxcenter; - v1 = triverts[1] - boxcenter; - v2 = triverts[2] - boxcenter; +// Use separating axis theorem to test overlap between triangle and box need to test for overlap in these directions: +// 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle we do not even need to test these) +// 2) normal of the triangle +// 3) crossproduct(edge from tri, {x,y,z}-directin) this gives 3x3=9 more tests +bool overlapTriangleBox(Vec3r& boxcenter, Vec3r& boxhalfsize, Vec3r triverts[3]) +{ + Vec3r v0, v1, v2, normal, e0, e1, e2; + real min, max, d, p0, p1, p2, rad, fex, fey, fez; - // compute triangle edges - e0 = v1 - v0; - e1 = v2 - v1; - e2 = v0 - v2; + // This is the fastest branch on Sun + // move everything so that the boxcenter is in (0, 0, 0) + v0 = triverts[0] - boxcenter; + v1 = triverts[1] - boxcenter; + v2 = triverts[2] - boxcenter; - // Bullet 3: - // Do the 9 tests first (this was faster) - fex = fabs(e0[X]); - fey = fabs(e0[Y]); - fez = fabs(e0[Z]); - AXISTEST_X01(e0[Z], e0[Y], fez, fey); - AXISTEST_Y02(e0[Z], e0[X], fez, fex); - AXISTEST_Z12(e0[Y], e0[X], fey, fex); + // compute triangle edges + e0 = v1 - v0; + e1 = v2 - v1; + e2 = v0 - v2; - fex = fabs(e1[X]); - fey = fabs(e1[Y]); - fez = fabs(e1[Z]); - AXISTEST_X01(e1[Z], e1[Y], fez, fey); - AXISTEST_Y02(e1[Z], e1[X], fez, fex); - AXISTEST_Z0(e1[Y], e1[X], fey, fex); - - fex = fabs(e2[X]); - fey = fabs(e2[Y]); - fez = fabs(e2[Z]); - AXISTEST_X2(e2[Z], e2[Y], fez, fey); - AXISTEST_Y1(e2[Z], e2[X], fez, fex); - AXISTEST_Z12(e2[Y], e2[X], fey, fex); + // Bullet 3: + // Do the 9 tests first (this was faster) + fex = fabs(e0[X]); + fey = fabs(e0[Y]); + fez = fabs(e0[Z]); + AXISTEST_X01(e0[Z], e0[Y], fez, fey); + AXISTEST_Y02(e0[Z], e0[X], fez, fex); + AXISTEST_Z12(e0[Y], e0[X], fey, fex); - // Bullet 1: - // first test overlap in the {x,y,z}-directions - // find min, max of the triangle each direction, and test for overlap in - // that direction -- this is equivalent to testing a minimal AABB around - // the triangle against the AABB + fex = fabs(e1[X]); + fey = fabs(e1[Y]); + fez = fabs(e1[Z]); + AXISTEST_X01(e1[Z], e1[Y], fez, fey); + AXISTEST_Y02(e1[Z], e1[X], fez, fex); + AXISTEST_Z0(e1[Y], e1[X], fey, fex); - // test in X-direction - FINDMINMAX(v0[X], v1[X], v2[X], min, max); - if (min > boxhalfsize[X] || max < -boxhalfsize[X]) - return false; + fex = fabs(e2[X]); + fey = fabs(e2[Y]); + fez = fabs(e2[Z]); + AXISTEST_X2(e2[Z], e2[Y], fez, fey); + AXISTEST_Y1(e2[Z], e2[X], fez, fex); + AXISTEST_Z12(e2[Y], e2[X], fey, fex); - // test in Y-direction - FINDMINMAX(v0[Y], v1[Y], v2[Y], min, max); - if (min > boxhalfsize[Y] || max < -boxhalfsize[Y]) - return false; + // Bullet 1: + // first test overlap in the {x,y,z}-directions + // find min, max of the triangle each direction, and test for overlap in that direction -- this is equivalent + // to testing a minimal AABB around the triangle against the AABB - // test in Z-direction - FINDMINMAX(v0[Z], v1[Z], v2[Z], min, max); - if(min > boxhalfsize[Z] || max < -boxhalfsize[Z]) - return false; + // test in X-direction + FINDMINMAX(v0[X], v1[X], v2[X], min, max); + if (min > boxhalfsize[X] || max < -boxhalfsize[X]) + return false; - // Bullet 2: - // test if the box intersects the plane of the triangle - // compute plane equation of triangle: normal * x + d = 0 - normal = e0 ^ e1; - d = -(normal * v0); // plane eq: normal.x + d = 0 - if (!overlapPlaneBox(normal, d, boxhalfsize)) - return false; - - return true; // box and triangle overlaps - } + // test in Y-direction + FINDMINMAX(v0[Y], v1[Y], v2[Y], min, max); + if (min > boxhalfsize[Y] || max < -boxhalfsize[Y]) + return false; - // Fast, Minimum Storage Ray-Triangle Intersection - // - // Tomas Möller - // Prosolvia Clarus AB - // Sweden - // tompa@clarus.se - // - // Ben Trumbore - // Cornell University - // Ithaca, New York - // wbt@graphics.cornell.edu + // test in Z-direction + FINDMINMAX(v0[Z], v1[Z], v2[Z], min, max); + if (min > boxhalfsize[Z] || max < -boxhalfsize[Z]) + return false; - bool intersectRayTriangle(const Vec3r& orig, const Vec3r& dir, - const Vec3r& v0, const Vec3r& v1, const Vec3r& v2, - real& t, real& u, real& v, const real epsilon) { - Vec3r edge1, edge2, tvec, pvec, qvec; - real det, inv_det; + // Bullet 2: + // test if the box intersects the plane of the triangle + // compute plane equation of triangle: normal * x + d = 0 + normal = e0 ^ e1; + d = -(normal * v0); // plane eq: normal.x + d = 0 + if (!overlapPlaneBox(normal, d, boxhalfsize)) + return false; - // find vectors for two edges sharing v0 - edge1 = v1 - v0; - edge2 = v2 - v0; + return true; // box and triangle overlaps +} - // begin calculating determinant - also used to calculate U parameter - pvec = dir ^ edge2; +// Fast, Minimum Storage Ray-Triangle Intersection +// +// Tomas Möller +// Prosolvia Clarus AB +// Sweden +// tompa@clarus.se +// +// Ben Trumbore +// Cornell University +// Ithaca, New York +// wbt@graphics.cornell.edu +bool intersectRayTriangle(const Vec3r& orig, const Vec3r& dir, const Vec3r& v0, const Vec3r& v1, const Vec3r& v2, + real& t, real& u, real& v, const real epsilon) +{ + Vec3r edge1, edge2, tvec, pvec, qvec; + real det, inv_det; - // if determinant is near zero, ray lies in plane of triangle - det = edge1 * pvec; + // find vectors for two edges sharing v0 + edge1 = v1 - v0; + edge2 = v2 - v0; - // calculate distance from v0 to ray origin - tvec = orig - v0; - inv_det = 1.0 / det; - - qvec = tvec ^ edge1; - - if (det > epsilon) { - u = tvec * pvec; - if (u < 0.0 || u > det) - return false; - - // calculate V parameter and test bounds - v = dir * qvec; - if (v < 0.0 || u + v > det) - return false; - } - else if(det < -epsilon) { - // calculate U parameter and test bounds - u = tvec * pvec; - if (u > 0.0 || u < det) - return false; - - // calculate V parameter and test bounds - v = dir * qvec; - if (v > 0.0 || u + v < det) - return false; - } - else - return false; // ray is parallell to the plane of the triangle + // begin calculating determinant - also used to calculate U parameter + pvec = dir ^ edge2; - u *= inv_det; - v *= inv_det; - t = (edge2 * qvec) * inv_det; + // if determinant is near zero, ray lies in plane of triangle + det = edge1 * pvec; - return true; - } + // calculate distance from v0 to ray origin + tvec = orig - v0; + inv_det = 1.0 / det; - // Intersection between plane and ray, adapted from Graphics Gems, Didier Badouel - intersection_test intersectRayPlane(const Vec3r& orig, const Vec3r& dir, - const Vec3r& norm, const real d, - real& t, - const real epsilon) { - real denom = norm * dir; + qvec = tvec ^ edge1; - if(fabs(denom) <= epsilon) { // plane and ray are parallel - if(fabs((norm * orig) + d) <= epsilon) - return COINCIDENT; // plane and ray are coincident - else - return COLINEAR; - } + if (det > epsilon) { + u = tvec * pvec; + if (u < 0.0 || u > det) + return false; - t = -(d + (norm * orig)) / denom; - - if (t < 0.0f) - return DONT_INTERSECT; - - return DO_INTERSECT; - } - - bool intersectRayBBox(const Vec3r& orig, const Vec3r& dir, // ray origin and direction - const Vec3r& boxMin, const Vec3r& boxMax, // the bbox - real t0, real t1, - real& tmin, real& tmax, // I0=orig+tmin*dir is the first intersection, I1=orig+tmax*dir is the second intersection - real epsilon){ - - float tymin, tymax, tzmin, tzmax; - Vec3r inv_direction(1.0/dir[0], 1.0/dir[1], 1.0/dir[2]); - int sign[3]; - sign[0] = (inv_direction.x() < 0); - sign[1] = (inv_direction.y() < 0); - sign[2] = (inv_direction.z() < 0); - - Vec3r bounds[2]; - bounds[0] = boxMin; - bounds[1] = boxMax; - - tmin = (bounds[sign[0]].x() - orig.x()) * inv_direction.x(); - tmax = (bounds[1-sign[0]].x() - orig.x()) * inv_direction.x(); - tymin = (bounds[sign[1]].y() - orig.y()) * inv_direction.y(); - tymax = (bounds[1-sign[1]].y() - orig.y()) * inv_direction.y(); - if ( (tmin > tymax) || (tymin > tmax) ) - return false; - if (tymin > tmin) - tmin = tymin; - if (tymax < tmax) - tmax = tymax; - tzmin = (bounds[sign[2]].z() - orig.z()) * inv_direction.z(); - tzmax = (bounds[1-sign[2]].z() - orig.z()) * inv_direction.z(); - if ( (tmin > tzmax) || (tzmin > tmax) ) - return false; - if (tzmin > tmin) - tmin = tzmin; - if (tzmax < tmax) - tmax = tzmax; - return ( (tmin < t1) && (tmax > t0) ); - } - - // Checks whether 3D points p lies inside or outside of the triangle ABC - bool includePointTriangle(const Vec3r& P, - const Vec3r& A, - const Vec3r& B, - const Vec3r& C) { - Vec3r AB(B - A); - Vec3r BC(C - B); - Vec3r CA(A - C); - Vec3r AP(P - A); - Vec3r BP(P - B); - Vec3r CP(P - C); - - Vec3r N(AB ^ BC); // triangle's normal - - N.normalize(); - - Vec3r J(AB ^ AP), K(BC ^ BP), L(CA ^ CP); - J.normalize(); - K.normalize(); - L.normalize(); - - if(J * N < 0) - return false; // on the right of AB - - if(K * N < 0) - return false; // on the right of BC - - if(L * N < 0) - return false; // on the right of CA - - return true; - } - - void transformVertex(const Vec3r& vert, - const Matrix44r& matrix, - Vec3r& res) { - HVec3r hvert(vert), res_tmp; - real scale; - for (unsigned j = 0; j < 4; j++) { - scale = hvert[j]; - for (unsigned i = 0; i < 4; i++) - res_tmp[i] += matrix(i, j) * scale; - } - - res[0] = res_tmp.x(); - res[1] = res_tmp.y(); - res[2] = res_tmp.z(); - } - - void transformVertices(const vector& vertices, - const Matrix44r& trans, - vector& res) { - for (vector::const_iterator v = vertices.begin(); - v != vertices.end(); - v++) { - Vec3r *res_tmp = new Vec3r; - transformVertex(*v, trans, *res_tmp); - res.push_back(*res_tmp); - } - } - - Vec3r rotateVector(const Matrix44r& mat, const Vec3r& v) { - Vec3r res; - for (unsigned i = 0; i < 3; i++) { - res[i] = 0; - for (unsigned j = 0; j < 3; j++) - res[i] += mat(i, j) * v[j]; - } - res.normalize(); - return res; - } - - // This internal procedure is defined below. - void fromCoordAToCoordB(const Vec3r& p, - Vec3r& q, - const real transform[4][4]); - - void fromWorldToCamera(const Vec3r& p, - Vec3r& q, - const real model_view_matrix[4][4]) { - fromCoordAToCoordB(p, q, model_view_matrix); - } - - void fromCameraToRetina(const Vec3r& p, - Vec3r& q, - const real projection_matrix[4][4]) { - fromCoordAToCoordB(p, q, projection_matrix); - } - - void fromRetinaToImage(const Vec3r& p, - Vec3r& q, - const int viewport[4]) { - // winX: - q[0] = viewport[0] + viewport[2] * (p[0] + 1.0) / 2.0; - - // winY: - q[1] = viewport[1] + viewport[3] * (p[1] + 1.0) / 2.0; - - // winZ: - q[2] = (p[2] + 1.0) / 2.0; - } - - void fromWorldToImage(const Vec3r& p, - Vec3r& q, - const real model_view_matrix[4][4], - const real projection_matrix[4][4], - const int viewport[4]) { - Vec3r p1, p2; - fromWorldToCamera(p, p1, model_view_matrix); - fromCameraToRetina(p1, p2, projection_matrix); - fromRetinaToImage(p2, q, viewport); - q[2] = p1[2]; - } - - void fromWorldToImage(const Vec3r& p, - Vec3r& q, - const real transform[4][4], - const int viewport[4]) { - fromCoordAToCoordB(p, q, transform); - - // winX: - q[0] = viewport[0] + viewport[2] * (q[0] + 1.0) / 2.0; - - //winY: - q[1] = viewport[1] + viewport[3] * (q[1] + 1.0) / 2.0; - } - - void fromImageToRetina(const Vec3r& p, - Vec3r& q, - const int viewport[4]) { - q = p; - q[0] = 2.0 * (q[0] - viewport[0]) / viewport[2] - 1; - q[1] = 2.0 * (q[1] - viewport[1]) / viewport[3] - 1; - } - - void fromRetinaToCamera(const Vec3r& p, - Vec3r& q, - real focal, - const real projection_matrix[4][4]) { - - if( projection_matrix[3][3] == 0.0 ) // perspective - { - q[0] = (-p[0] * focal) / projection_matrix[0][0]; - q[1] = (-p[1] * focal) / projection_matrix[1][1]; - q[2] = focal; + // calculate V parameter and test bounds + v = dir * qvec; + if (v < 0.0 || u + v > det) + return false; } - else // orthogonal - { - q[0] = p[0] / projection_matrix[0][0]; - q[1] = p[1] / projection_matrix[1][1]; - q[2] = focal; - } - } + else if (det < -epsilon) { + // calculate U parameter and test bounds + u = tvec * pvec; + if (u > 0.0 || u < det) + return false; - void fromCameraToWorld(const Vec3r& p, - Vec3r& q, - const real model_view_matrix[4][4]) { - - real translation[3] = { model_view_matrix[0][3], - model_view_matrix[1][3], - model_view_matrix[2][3] }; - for (unsigned i = 0; i < 3; i++) { - q[i] = 0.0; - for (unsigned short j = 0; j < 3; j++) - q[i] += model_view_matrix[j][i] * (p[j] - translation[j]); - } - } - - - // - // Internal code - // - ///////////////////////////////////////////////////////////////////////////// - - // Copyright 2001, softSurfer (www.softsurfer.com) - // This code may be freely used and modified for any purpose - // providing that this copyright notice is included with it. - // SoftSurfer makes no warranty for this code, and cannot be held - // liable for any real or imagined damage resulting from its use. - // Users of this code must verify correctness for their application. - -#define perp(u,v) ((u)[0] * (v)[1] - (u)[1] * (v)[0]) // 2D perp product - - inline bool intersect2dSegPoly(Vec2r* seg, - Vec2r* poly, - unsigned n) { - if (seg[0] == seg[1]) - return false; - - real tE = 0; // the maximum entering segment parameter - real tL = 1; // the minimum leaving segment parameter - real t, N, D; // intersect parameter t = N / D - Vec2r dseg; // the segment direction vector - dseg = seg[1] - seg[0]; - Vec2r e; // edge vector - - for (unsigned i = 0; i < n; i++) { // process polygon edge poly[i]poly[i+1] - e = poly[i+1] - poly[i]; - N = perp(e, seg[0] - poly[i]); - D = -perp(e, dseg); - if (fabs(D) < M_EPSILON) { - if (N < 0) - return false; - else - continue; - } - - t = N / D; - if (D < 0) { // segment seg is entering across this edge - if (t > tE) { // new max tE - tE = t; - if (tE > tL) // seg enters after leaving polygon - return false; - } - } - else { // segment seg is leaving across this edge - if (t < tL) { // new min tL - tL = t; - if (tL < tE) // seg leaves before entering polygon - return false; - } - } - } - - // tE <= tL implies that there is a valid intersection subsegment - return true; - } - - inline bool overlapPlaneBox(Vec3r& normal, real d, Vec3r& maxbox) { - Vec3r vmin, vmax; - - for(unsigned q = X; q <= Z; q++) { - if(normal[q] > 0.0f) { - vmin[q] = -maxbox[q]; - vmax[q] = maxbox[q]; + // calculate V parameter and test bounds + v = dir * qvec; + if (v > 0.0 || u + v < det) + return false; } else { - vmin[q] = maxbox[q]; - vmax[q] = -maxbox[q]; + return false; // ray is parallell to the plane of the triangle } - } - if((normal * vmin) + d > 0.0f) - return false; - if((normal * vmax) + d >= 0.0f) - return true; - return false; - } - inline void fromCoordAToCoordB(const Vec3r&p, - Vec3r& q, - const real transform[4][4]) { - HVec3r hp(p); - HVec3r hq(0, 0, 0, 0); + u *= inv_det; + v *= inv_det; + t = (edge2 * qvec) * inv_det; - for (unsigned i = 0; i < 4; i++) - for (unsigned j = 0; j < 4; j++) - hq[i] += transform[i][j] * hp[j]; + return true; +} - if(hq[3] == 0) { - q = p; - return; - } +// Intersection between plane and ray, adapted from Graphics Gems, Didier Badouel +intersection_test intersectRayPlane(const Vec3r& orig, const Vec3r& dir, const Vec3r& norm, const real d, + real& t, const real epsilon) +{ + real denom = norm * dir; - for (unsigned k = 0; k < 3; k++) - q[k] = hq[k] / hq[3]; - } + if (fabs(denom) <= epsilon) { // plane and ray are parallel + if (fabs((norm * orig) + d) <= epsilon) + return COINCIDENT; // plane and ray are coincident + else + return COLINEAR; + } + + t = -(d + (norm * orig)) / denom; + + if (t < 0.0f) + return DONT_INTERSECT; + + return DO_INTERSECT; +} + +bool intersectRayBBox(const Vec3r& orig, const Vec3r& dir, // ray origin and direction + const Vec3r& boxMin, const Vec3r& boxMax, // the bbox + real t0, real t1, + real& tmin, // I0 = orig + tmin * dir is the first intersection + real& tmax, // I1 = orig + tmax * dir is the second intersection + real epsilon) +{ + float tymin, tymax, tzmin, tzmax; + Vec3r inv_direction(1.0 / dir[0], 1.0 / dir[1], 1.0 / dir[2]); + int sign[3]; + sign[0] = (inv_direction.x() < 0); + sign[1] = (inv_direction.y() < 0); + sign[2] = (inv_direction.z() < 0); + + Vec3r bounds[2]; + bounds[0] = boxMin; + bounds[1] = boxMax; + + tmin = (bounds[sign[0]].x() - orig.x()) * inv_direction.x(); + tmax = (bounds[1-sign[0]].x() - orig.x()) * inv_direction.x(); + tymin = (bounds[sign[1]].y() - orig.y()) * inv_direction.y(); + tymax = (bounds[1-sign[1]].y() - orig.y()) * inv_direction.y(); + if ((tmin > tymax) || (tymin > tmax)) + return false; + if (tymin > tmin) + tmin = tymin; + if (tymax < tmax) + tmax = tymax; + tzmin = (bounds[sign[2]].z() - orig.z()) * inv_direction.z(); + tzmax = (bounds[1-sign[2]].z() - orig.z()) * inv_direction.z(); + if ((tmin > tzmax) || (tzmin > tmax)) + return false; + if (tzmin > tmin) + tmin = tzmin; + if (tzmax < tmax) + tmax = tzmax; + return ((tmin < t1) && (tmax > t0)); +} + +// Checks whether 3D points p lies inside or outside of the triangle ABC +bool includePointTriangle(const Vec3r& P, const Vec3r& A, const Vec3r& B, const Vec3r& C) +{ + Vec3r AB(B - A); + Vec3r BC(C - B); + Vec3r CA(A - C); + Vec3r AP(P - A); + Vec3r BP(P - B); + Vec3r CP(P - C); + + Vec3r N(AB ^ BC); // triangle's normal + + N.normalize(); + + Vec3r J(AB ^ AP), K(BC ^ BP), L(CA ^ CP); + J.normalize(); + K.normalize(); + L.normalize(); + + if (J * N < 0) + return false; // on the right of AB + + if (K * N < 0) + return false; // on the right of BC + + if (L * N < 0) + return false; // on the right of CA + + return true; +} + +void transformVertex(const Vec3r& vert, const Matrix44r& matrix, Vec3r& res) +{ + HVec3r hvert(vert), res_tmp; + real scale; + for (unsigned int j = 0; j < 4; j++) { + scale = hvert[j]; + for (unsigned int i = 0; i < 4; i++) + res_tmp[i] += matrix(i, j) * scale; + } + + res[0] = res_tmp.x(); + res[1] = res_tmp.y(); + res[2] = res_tmp.z(); +} + +void transformVertices(const vector& vertices, const Matrix44r& trans, vector& res) +{ + for (vector::const_iterator v = vertices.begin(); v != vertices.end(); v++) { + Vec3r *res_tmp = new Vec3r; + transformVertex(*v, trans, *res_tmp); + res.push_back(*res_tmp); + } +} + +Vec3r rotateVector(const Matrix44r& mat, const Vec3r& v) { + Vec3r res; + for (unsigned int i = 0; i < 3; i++) { + res[i] = 0; + for (unsigned int j = 0; j < 3; j++) + res[i] += mat(i, j) * v[j]; + } + res.normalize(); + return res; +} + +// This internal procedure is defined below. +void fromCoordAToCoordB(const Vec3r& p, Vec3r& q, const real transform[4][4]); + +void fromWorldToCamera(const Vec3r& p, Vec3r& q, const real model_view_matrix[4][4]) +{ + fromCoordAToCoordB(p, q, model_view_matrix); +} + +void fromCameraToRetina(const Vec3r& p, Vec3r& q, const real projection_matrix[4][4]) +{ + fromCoordAToCoordB(p, q, projection_matrix); +} + +void fromRetinaToImage(const Vec3r& p, Vec3r& q, const int viewport[4]) +{ + // winX: + q[0] = viewport[0] + viewport[2] * (p[0] + 1.0) / 2.0; + + // winY: + q[1] = viewport[1] + viewport[3] * (p[1] + 1.0) / 2.0; + + // winZ: + q[2] = (p[2] + 1.0) / 2.0; +} + +void fromWorldToImage(const Vec3r& p, Vec3r& q, const real model_view_matrix[4][4], + const real projection_matrix[4][4], const int viewport[4]) +{ + Vec3r p1, p2; + fromWorldToCamera(p, p1, model_view_matrix); + fromCameraToRetina(p1, p2, projection_matrix); + fromRetinaToImage(p2, q, viewport); + q[2] = p1[2]; +} + +void fromWorldToImage(const Vec3r& p, Vec3r& q, const real transform[4][4], const int viewport[4]) +{ + fromCoordAToCoordB(p, q, transform); + + // winX: + q[0] = viewport[0] + viewport[2] * (q[0] + 1.0) / 2.0; + + //winY: + q[1] = viewport[1] + viewport[3] * (q[1] + 1.0) / 2.0; +} + +void fromImageToRetina(const Vec3r& p, Vec3r& q, const int viewport[4]) +{ + q = p; + q[0] = 2.0 * (q[0] - viewport[0]) / viewport[2] - 1.0; + q[1] = 2.0 * (q[1] - viewport[1]) / viewport[3] - 1.0; +} + +void fromRetinaToCamera(const Vec3r& p, Vec3r& q, real focal, const real projection_matrix[4][4]) +{ + if (projection_matrix[3][3] == 0.0) { // perspective + q[0] = (-p[0] * focal) / projection_matrix[0][0]; + q[1] = (-p[1] * focal) / projection_matrix[1][1]; + q[2] = focal; + } + else { // orthogonal + q[0] = p[0] / projection_matrix[0][0]; + q[1] = p[1] / projection_matrix[1][1]; + q[2] = focal; + } +} + +void fromCameraToWorld(const Vec3r& p, Vec3r& q, const real model_view_matrix[4][4]) +{ + real translation[3] = { + model_view_matrix[0][3], + model_view_matrix[1][3], + model_view_matrix[2][3] + }; + for (unsigned short i = 0; i < 3; i++) { + q[i] = 0.0; + for (unsigned short j = 0; j < 3; j++) + q[i] += model_view_matrix[j][i] * (p[j] - translation[j]); + } +} + + +// +// Internal code +// +///////////////////////////////////////////////////////////////////////////// + +// Copyright 2001, softSurfer (www.softsurfer.com) +// This code may be freely used and modified for any purpose providing that this copyright notice is included with it. +// SoftSurfer makes no warranty for this code, and cannot be held liable for any real or imagined damage resulting +// from its use. +// Users of this code must verify correctness for their application. + +#define PERP(u, v) ((u)[0] * (v)[1] - (u)[1] * (v)[0]) // 2D perp product + +inline bool intersect2dSegPoly(Vec2r* seg, Vec2r* poly, unsigned n) +{ + if (seg[0] == seg[1]) + return false; + + real tE = 0; // the maximum entering segment parameter + real tL = 1; // the minimum leaving segment parameter + real t, N, D; // intersect parameter t = N / D + Vec2r dseg = seg[1] - seg[0]; // the segment direction vector + Vec2r e; // edge vector + + for (unsigned int i = 0; i < n; i++) { // process polygon edge poly[i]poly[i+1] + e = poly[i+1] - poly[i]; + N = PERP(e, seg[0] - poly[i]); + D = -PERP(e, dseg); + if (fabs(D) < M_EPSILON) { + if (N < 0) + return false; + else + continue; + } + + t = N / D; + if (D < 0) { // segment seg is entering across this edge + if (t > tE) { // new max tE + tE = t; + if (tE > tL) // seg enters after leaving polygon + return false; + } + } + else { // segment seg is leaving across this edge + if (t < tL) { // new min tL + tL = t; + if (tL < tE) // seg leaves before entering polygon + return false; + } + } + } + + // tE <= tL implies that there is a valid intersection subsegment + return true; +} + +inline bool overlapPlaneBox(Vec3r& normal, real d, Vec3r& maxbox) +{ + Vec3r vmin, vmax; + + for (unsigned int q = X; q <= Z; q++) { + if (normal[q] > 0.0f) { + vmin[q] = -maxbox[q]; + vmax[q] = maxbox[q]; + } + else { + vmin[q] = maxbox[q]; + vmax[q] = -maxbox[q]; + } + } + if ((normal * vmin) + d > 0.0f) + return false; + if ((normal * vmax) + d >= 0.0f) + return true; + return false; +} + +inline void fromCoordAToCoordB(const Vec3r&p, Vec3r& q, const real transform[4][4]) +{ + HVec3r hp(p); + HVec3r hq(0, 0, 0, 0); + + for (unsigned int i = 0; i < 4; i++) { + for (unsigned int j = 0; j < 4; j++) { + hq[i] += transform[i][j] * hp[j]; + } + } + + if (hq[3] == 0) { + q = p; + return; + } + + for (unsigned int k = 0; k < 3; k++) + q[k] = hq[k] / hq[3]; +} } // end of namespace GeomUtils diff --git a/source/blender/freestyle/intern/geometry/GeomUtils.h b/source/blender/freestyle/intern/geometry/GeomUtils.h index 7fd6fe3cdb9..1b90f99c2ed 100644 --- a/source/blender/freestyle/intern/geometry/GeomUtils.h +++ b/source/blender/freestyle/intern/geometry/GeomUtils.h @@ -1,310 +1,277 @@ -// -// Filename : GeomUtils.h -// Author(s) : Stephane Grabli -// Purpose : Various tools for geometry -// Date of creation : 12/04/2002 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __GEOMUTILS_H__ +#define __GEOMUTILS_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/GeomUtils.h + * \ingroup freestyle + * \brief Various tools for geometry + * \author Stephane Grabli + * \date 12/04/2002 + */ -#ifndef GEOMUTILS_H -# define GEOMUTILS_H +#include -# include -# include "../system/FreestyleConfig.h" -# include "Geom.h" +#include "Geom.h" + +#include "../system/FreestyleConfig.h" using namespace std; using namespace Geometry; namespace GeomUtils { - // - // Templated procedures - // - ///////////////////////////////////////////////////////////////////////////// +// +// Templated procedures +// +///////////////////////////////////////////////////////////////////////////// - /*! Computes the distance from a point P to a segment AB */ - template - real distPointSegment( const T& P, const T& A , const T& B) { - T AB, AP, BP; - AB = B - A; - AP = P - A; - BP = P - B; +/*! Computes the distance from a point P to a segment AB */ +template +real distPointSegment( const T& P, const T& A , const T& B) +{ + T AB, AP, BP; + AB = B - A; + AP = P - A; + BP = P - B; - real c1(AB * AP); - if (c1 <= 0) - return AP.norm(); + real c1(AB * AP); + if (c1 <= 0) + return AP.norm(); - real c2(AB * AB); - if (c2 <= c1) - return BP.norm(); + real c2(AB * AB); + if (c2 <= c1) + return BP.norm(); - real b = c1 / c2; - T Pb, PPb; - Pb = A + b * AB; - PPb = P - Pb; + real b = c1 / c2; + T Pb, PPb; + Pb = A + b * AB; + PPb = P - Pb; - return PPb.norm(); - } + return PPb.norm(); +} - // - // Non-templated procedures - // - ///////////////////////////////////////////////////////////////////////////// +// +// Non-templated procedures +// +///////////////////////////////////////////////////////////////////////////// +typedef enum { + DONT_INTERSECT, + DO_INTERSECT, + COLINEAR, + COINCIDENT, +} intersection_test; - typedef enum { - DONT_INTERSECT, - DO_INTERSECT, - COLINEAR, - COINCIDENT - } intersection_test; +LIB_GEOMETRY_EXPORT +intersection_test intersect2dSeg2dSeg(const Vec2r& p1, const Vec2r& p2, // first segment + const Vec2r& p3, const Vec2r& p4, // second segment + Vec2r& res); // found intersection point - LIB_GEOMETRY_EXPORT - intersection_test intersect2dSeg2dSeg(const Vec2r& p1, const Vec2r& p2, // first segment - const Vec2r& p3, const Vec2r& p4, // second segment - Vec2r& res); // found intersection point +LIB_GEOMETRY_EXPORT +intersection_test intersect2dLine2dLine(const Vec2r& p1, const Vec2r& p2, // first segment + const Vec2r& p3, const Vec2r& p4, // second segment + Vec2r& res); // found intersection point - LIB_GEOMETRY_EXPORT - intersection_test intersect2dLine2dLine(const Vec2r& p1, const Vec2r& p2, // first segment - const Vec2r& p3, const Vec2r& p4, // second segment - Vec2r& res); // found intersection point +LIB_GEOMETRY_EXPORT +intersection_test intersect2dSeg2dSegParametric(const Vec2r& p1, const Vec2r& p2, // first segment + const Vec2r& p3, const Vec2r& p4, // second segment + real& t, // I = P1 + t * P1P2) + real& u, // I = P3 + u * P3P4 + real epsilon = M_EPSILON); - LIB_GEOMETRY_EXPORT - intersection_test intersect2dSeg2dSegParametric(const Vec2r& p1, const Vec2r& p2, // first segment - const Vec2r& p3, const Vec2r& p4, // second segment - real& t, // I = P1 + t * P1P2) - real& u, // I = P3 + u * P3P4 - real epsilon = M_EPSILON); +/*! check whether a 2D segment intersect a 2D region or not */ +LIB_GEOMETRY_EXPORT +bool intersect2dSeg2dArea(const Vec2r& min, const Vec2r& max, const Vec2r& A, const Vec2r& B); - /*! check whether a 2D segment intersect a 2D region or not */ - LIB_GEOMETRY_EXPORT - bool intersect2dSeg2dArea(const Vec2r& min, - const Vec2r& max, - const Vec2r& A, - const Vec2r& B); - - /*! check whether a 2D segment is included in a 2D region or not */ - LIB_GEOMETRY_EXPORT - bool include2dSeg2dArea(const Vec2r& min, - const Vec2r& max, - const Vec2r& A, - const Vec2r& B); +/*! check whether a 2D segment is included in a 2D region or not */ +LIB_GEOMETRY_EXPORT +bool include2dSeg2dArea(const Vec2r& min, const Vec2r& max, const Vec2r& A, const Vec2r& B); - /*! Box-triangle overlap test, adapted from Tomas Akenine-Möller code */ - LIB_GEOMETRY_EXPORT - bool overlapTriangleBox(Vec3r& boxcenter, - Vec3r& boxhalfsize, - Vec3r triverts[3]); +/*! Box-triangle overlap test, adapted from Tomas Akenine-Möller code */ +LIB_GEOMETRY_EXPORT +bool overlapTriangleBox(Vec3r& boxcenter, Vec3r& boxhalfsize, Vec3r triverts[3]); - /*! Fast, Minimum Storage Ray-Triangle Intersection, - * adapted from Tomas Möller and Ben Trumbore code. - */ - LIB_GEOMETRY_EXPORT - bool intersectRayTriangle(const Vec3r& orig, const Vec3r& dir, - const Vec3r& v0, const Vec3r& v1, const Vec3r& v2, - real& t, // I = orig + t * dir - real& u, real& v, // I = (1-u-v)*v0+u*v1+v*v2 - const real epsilon = M_EPSILON); // the epsilon to use +/*! Fast, Minimum Storage Ray-Triangle Intersection, adapted from Tomas Möller and Ben Trumbore code. */ +LIB_GEOMETRY_EXPORT +bool intersectRayTriangle(const Vec3r& orig, const Vec3r& dir, const Vec3r& v0, const Vec3r& v1, const Vec3r& v2, + real& t, // I = orig + t * dir + real& u, real& v, // I = (1 - u - v) * v0 + u * v1 + v * v2 + const real epsilon = M_EPSILON); // the epsilon to use - /*! Intersection between plane and ray - * adapted from Graphics Gems, Didier Badouel - */ - LIB_GEOMETRY_EXPORT - intersection_test intersectRayPlane(const Vec3r& orig, const Vec3r& dir, // ray origin and direction - const Vec3r& norm, const real d, // plane's normal and offset (plane = { P / P.N + d = 0 }) - real& t, // I = orig + t * dir - const real epsilon = M_EPSILON); // the epsilon to use +/*! Intersection between plane and ray adapted from Graphics Gems, Didier Badouel */ +LIB_GEOMETRY_EXPORT +intersection_test intersectRayPlane(const Vec3r& orig, const Vec3r& dir, // ray origin and direction + // plane's normal and offset (plane = { P / P.N + d = 0 }) + const Vec3r& norm, const real d, + real& t, // I = orig + t * dir + const real epsilon = M_EPSILON); // the epsilon to use - /*! Intersection Ray-Bounding box (axis aligned). - * Adapted from Williams et al, "An Efficient Robust Ray-Box Intersection Algorithm", - * JGT 10:1 (2005), pp. 49-54. - * Returns - */ - LIB_GEOMETRY_EXPORT - bool intersectRayBBox(const Vec3r& orig, const Vec3r& dir, // ray origin and direction - const Vec3r& boxMin, const Vec3r& boxMax, // the bbox - real t0, real t1, // the interval in which at least on of the intersections must happen - real& tmin, real& tmax, // Imin=orig+tmin*dir is the first intersection, Imax=orig+tmax*dir is the second intersection - real epsilon = M_EPSILON); // the epsilon to use +/*! Intersection Ray-Bounding box (axis aligned). + * Adapted from Williams et al, "An Efficient Robust Ray-Box Intersection Algorithm", JGT 10:1 (2005), pp. 49-54. + */ +LIB_GEOMETRY_EXPORT +bool intersectRayBBox(const Vec3r& orig, const Vec3r& dir, // ray origin and direction + const Vec3r& boxMin, const Vec3r& boxMax, // the bbox + // the interval in which at least on of the intersections must happen + real t0, real t1, + real& tmin, // Imin = orig + tmin * dir is the first intersection + real& tmax, // Imax = orig + tmax * dir is the second intersection + real epsilon = M_EPSILON); // the epsilon to use +/*! Checks whether 3D point P lies inside or outside of the triangle ABC */ +LIB_GEOMETRY_EXPORT +bool includePointTriangle(const Vec3r& P, const Vec3r& A, const Vec3r& B, const Vec3r& C); - /*! Checks whether 3D point P lies inside or outside of the triangle ABC */ - LIB_GEOMETRY_EXPORT - bool includePointTriangle(const Vec3r& P, - const Vec3r& A, - const Vec3r& B, - const Vec3r& C); +LIB_GEOMETRY_EXPORT +void transformVertex(const Vec3r& vert, const Matrix44r& matrix, Vec3r& res); - LIB_GEOMETRY_EXPORT - void transformVertex(const Vec3r& vert, - const Matrix44r& matrix, - Vec3r& res); - - LIB_GEOMETRY_EXPORT - void transformVertices(const vector& vertices, - const Matrix44r& trans, - vector& res); +LIB_GEOMETRY_EXPORT +void transformVertices(const vector& vertices, const Matrix44r& trans, vector& res); - LIB_GEOMETRY_EXPORT - Vec3r rotateVector(const Matrix44r& mat, const Vec3r& v); +LIB_GEOMETRY_EXPORT +Vec3r rotateVector(const Matrix44r& mat, const Vec3r& v); - // - // Coordinates systems changing procedures - // - ///////////////////////////////////////////////////////////////////////////// +// +// Coordinates systems changing procedures +// +///////////////////////////////////////////////////////////////////////////// - /*! From world to image - * p - * point's coordinates expressed in world coordinates system - * q - * vector in which the result will be stored - * model_view_matrix - * The model view matrix expressed in line major order (OpenGL - * matrices are column major ordered) - * projection_matrix - * The projection matrix expressed in line major order (OpenGL - * matrices are column major ordered) - * viewport - * The viewport: x,y coordinates followed by width and height (OpenGL like viewport) - */ - LIB_GEOMETRY_EXPORT - void fromWorldToImage(const Vec3r& p, - Vec3r& q, - const real model_view_matrix[4][4], - const real projection_matrix[4][4], - const int viewport[4]); +/*! From world to image + * p + * point's coordinates expressed in world coordinates system + * q + * vector in which the result will be stored + * model_view_matrix + * The model view matrix expressed in line major order (OpenGL + * matrices are column major ordered) + * projection_matrix + * The projection matrix expressed in line major order (OpenGL + * matrices are column major ordered) + * viewport + * The viewport: x,y coordinates followed by width and height (OpenGL like viewport) + */ +LIB_GEOMETRY_EXPORT +void fromWorldToImage(const Vec3r& p, Vec3r& q, const real model_view_matrix[4][4], const real projection_matrix[4][4], + const int viewport[4]); - /*! From world to image - * p - * point's coordinates expressed in world coordinates system - * q - * vector in which the result will be stored - * transform - * The transformation matrix (gathering model view and projection), - * expressed in line major order (OpenGL matrices are column major ordered) - * viewport - * The viewport: x,y coordinates followed by width and height (OpenGL like viewport) - */ - LIB_GEOMETRY_EXPORT - void fromWorldToImage(const Vec3r& p, - Vec3r& q, - const real transform[4][4], - const int viewport[4]); +/*! From world to image + * p + * point's coordinates expressed in world coordinates system + * q + * vector in which the result will be stored + * transform + * The transformation matrix (gathering model view and projection), + * expressed in line major order (OpenGL matrices are column major ordered) + * viewport + * The viewport: x,y coordinates followed by width and height (OpenGL like viewport) + */ +LIB_GEOMETRY_EXPORT +void fromWorldToImage(const Vec3r& p, Vec3r& q, const real transform[4][4], const int viewport[4]); - /*! Projects from world coordinates to camera coordinates - * Returns the point's coordinates expressed in the camera's - * coordinates system. - * p - * point's coordinates expressed in world coordinates system - * q - * vector in which the result will be stored - * model_view_matrix - * The model view matrix expressed in line major order (OpenGL - * matrices are column major ordered) - */ - LIB_GEOMETRY_EXPORT - void fromWorldToCamera(const Vec3r& p, - Vec3r& q, - const real model_view_matrix[4][4]); - - /*! Projects from World Coordinates to retina coordinates - * Returns the point's coordinates expressed in Retina system. - * p - * point's coordinates expressed in camera system - * q - * vector in which the result will be stored - * projection_matrix - * The projection matrix expressed in line major order (OpenGL - * matrices are column major ordered) - */ - LIB_GEOMETRY_EXPORT - void fromCameraToRetina(const Vec3r& p, - Vec3r& q, - const real projection_matrix[4][4]); - - /*! From retina to image. - * Returns the coordinates expressed in Image coorinates system. - * p - * point's coordinates expressed in retina system - * q - * vector in which the result will be stored - * viewport - * The viewport: x,y coordinates followed by width and height (OpenGL like viewport). - */ - LIB_GEOMETRY_EXPORT - void fromRetinaToImage(const Vec3r& p, - Vec3r& q, - const int viewport[4]); - - /*! From image to retina - * p - * point's coordinates expressed in image system - * q - * vector in which the result will be stored - * viewport - * The viewport: x,y coordinates followed by width and height (OpenGL like viewport). - */ - LIB_GEOMETRY_EXPORT - void fromImageToRetina(const Vec3r& p, - Vec3r& q, - const int viewport[4]); - - /*! computes the coordinates of q in the camera coordinates system, - * using the known z coordinates of the 3D point. - * That means that this method does not inverse any matrices, - * it only computes X and Y from x,y and Z) - * p - * point's coordinates expressed in retina system - * q - * vector in which the result will be stored - * projection_matrix - * The projection matrix expressed in line major order (OpenGL - * matrices are column major ordered) - - */ - LIB_GEOMETRY_EXPORT - void fromRetinaToCamera(const Vec3r& p, - Vec3r& q, - real z, - const real projection_matrix[4][4]); +/*! Projects from world coordinates to camera coordinates + * Returns the point's coordinates expressed in the camera's + * coordinates system. + * p + * point's coordinates expressed in world coordinates system + * q + * vector in which the result will be stored + * model_view_matrix + * The model view matrix expressed in line major order (OpenGL + * matrices are column major ordered) + */ +LIB_GEOMETRY_EXPORT +void fromWorldToCamera(const Vec3r& p, Vec3r& q, const real model_view_matrix[4][4]); - /*! Projects from camera coordinates to world coordinates - * Returns the point's coordinates expressed in the world's - * coordinates system. - * p - * point's coordinates expressed in the camera coordinates system - * q - * vector in which the result will be stored - * model_view_matrix - * The model view matrix expressed in line major order (OpenGL - * matrices are column major ordered) - */ - LIB_GEOMETRY_EXPORT - void fromCameraToWorld(const Vec3r& p, - Vec3r& q, - const real model_view_matrix[4][4]); +/*! Projects from World Coordinates to retina coordinates + * Returns the point's coordinates expressed in Retina system. + * p + * point's coordinates expressed in camera system + * q + * vector in which the result will be stored + * projection_matrix + * The projection matrix expressed in line major order (OpenGL + * matrices are column major ordered) + */ +LIB_GEOMETRY_EXPORT +void fromCameraToRetina(const Vec3r& p, Vec3r& q, const real projection_matrix[4][4]); + +/*! From retina to image. + * Returns the coordinates expressed in Image coorinates system. + * p + * point's coordinates expressed in retina system + * q + * vector in which the result will be stored + * viewport + * The viewport: x,y coordinates followed by width and height (OpenGL like viewport). + */ +LIB_GEOMETRY_EXPORT +void fromRetinaToImage(const Vec3r& p, Vec3r& q, const int viewport[4]); + +/*! From image to retina + * p + * point's coordinates expressed in image system + * q + * vector in which the result will be stored + * viewport + * The viewport: x,y coordinates followed by width and height (OpenGL like viewport). + */ +LIB_GEOMETRY_EXPORT +void fromImageToRetina(const Vec3r& p, Vec3r& q, const int viewport[4]); + +/*! computes the coordinates of q in the camera coordinates system, + * using the known z coordinates of the 3D point. + * That means that this method does not inverse any matrices, + * it only computes X and Y from x,y and Z) + * p + * point's coordinates expressed in retina system + * q + * vector in which the result will be stored + * projection_matrix + * The projection matrix expressed in line major order (OpenGL + * matrices are column major ordered) + */ +LIB_GEOMETRY_EXPORT +void fromRetinaToCamera(const Vec3r& p, Vec3r& q, real z, const real projection_matrix[4][4]); + +/*! Projects from camera coordinates to world coordinates + * Returns the point's coordinates expressed in the world's + * coordinates system. + * p + * point's coordinates expressed in the camera coordinates system + * q + * vector in which the result will be stored + * model_view_matrix + * The model view matrix expressed in line major order (OpenGL + * matrices are column major ordered) + */ +LIB_GEOMETRY_EXPORT +void fromCameraToWorld(const Vec3r& p, Vec3r& q, const real model_view_matrix[4][4]); } // end of namespace GeomUtils -#endif // GEOMUTILS_H +#endif // __GEOMUTILS_H__ diff --git a/source/blender/freestyle/intern/geometry/Grid.cpp b/source/blender/freestyle/intern/geometry/Grid.cpp index bb0b3d80c30..11c4f11b281 100644 --- a/source/blender/freestyle/intern/geometry/Grid.cpp +++ b/source/blender/freestyle/intern/geometry/Grid.cpp @@ -1,392 +1,390 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/Grid.cpp + * \ingroup freestyle + * \brief Base class to define a cell grid surrounding the bounding box of the scene + * \author Stephane Grabli + * \date 30/07/2002 + */ -#include "Grid.h" -#include "BBox.h" #include #include +#include "BBox.h" +#include "Grid.h" + // Grid Visitors ///////////////// -void allOccludersGridVisitor::examineOccluder(Polygon3r *occ){ - occluders_.push_back(occ); +void allOccludersGridVisitor::examineOccluder(Polygon3r *occ) +{ + occluders_.push_back(occ); } -static bool inBox(const Vec3r& inter, const Vec3r& box_min, const Vec3r& box_max){ - if(((inter.x()>=box_min.x()) && (inter.x() =box_min.y()) && (inter.y() =box_min.z()) && (inter.z() getVertices())[0]); - Vec3d normal((occ)->getNormal()); - //soc unused - double d = -(v1 * normal); - - double tmp_u, tmp_v, tmp_t; - if((occ)->rayIntersect(ray_org_, ray_dir_, tmp_t, tmp_u, tmp_v)){ - if (fabs(ray_dir_ * normal) > 0.0001){ - // Check whether the intersection is in the cell: - if(inBox(ray_org_+tmp_t*ray_dir_/ray_dir_.norm(), current_cell_->getOrigin(), current_cell_->getOrigin()+cell_size_)){ - - //Vec3d bboxdiag(_scene3d->bbox().getMax()-_scene3d->bbox().getMin()); - //if ((t>1.0E-06*(min(min(bboxdiag.x(),bboxdiag.y()),bboxdiag.z()))) && (tuserdata2 = 0; - } - } - } +static bool inBox(const Vec3r& inter, const Vec3r& box_min, const Vec3r& box_max) +{ + if (((inter.x() >= box_min.x()) && (inter.x() < box_max.x())) && + ((inter.y() >= box_min.y()) && (inter.y() < box_max.y())) && + ((inter.z() >= box_min.z()) && (inter.z() < box_max.z()))) + { + return true; + } + return false; } -bool firstIntersectionGridVisitor::stop(){ - if(occluder_) - return true; - return false; +void firstIntersectionGridVisitor::examineOccluder(Polygon3r *occ) +{ + // check whether the edge and the polygon plane are coincident: + //------------------------------------------------------------- + //first let us compute the plane equation. + Vec3r v1(((occ)->getVertices())[0]); + Vec3d normal((occ)->getNormal()); + //soc unused - double d = -(v1 * normal); + + double tmp_u, tmp_v, tmp_t; + if ((occ)->rayIntersect(ray_org_, ray_dir_, tmp_t, tmp_u, tmp_v)) { + if (fabs(ray_dir_ * normal) > 0.0001) { + // Check whether the intersection is in the cell: + if (inBox(ray_org_ + tmp_t * ray_dir_ / ray_dir_.norm(), current_cell_->getOrigin(), + current_cell_->getOrigin() + cell_size_)) + { +#if 0 + Vec3d bboxdiag(_scene3d->bbox().getMax() - _scene3d->bbox().getMin()); + if ((t > 1.0e-06 * (min(min(bboxdiag.x(), bboxdiag.y()), bboxdiag.z()))) && (t < raylength)) { +#else + if (tmp_t < t_) { +#endif + occluder_ = occ; + u_ = tmp_u; + v_ = tmp_v; + t_ = tmp_t; + } + } + else { + occ->userdata2 = 0; + } + } + } +} + +bool firstIntersectionGridVisitor::stop() +{ + if (occluder_) + return true; + return false; } // Grid ///////////////// - -void Grid::clear() { - if (_occluders.size() != 0) { - for(OccludersSet::iterator it = _occluders.begin(); - it != _occluders.end(); - it++) { - delete (*it); - } - _occluders.clear(); - } - - _size = Vec3r(0, 0, 0); - _cell_size = Vec3r(0, 0, 0); - _orig = Vec3r(0, 0, 0); - _cells_nb = Vec3u(0, 0, 0); - //_ray_occluders.clear(); -} - -void Grid::configure(const Vec3r& orig, - const Vec3r& size, - unsigned nb) { - - _orig = orig; - Vec3r tmpSize=size; - // Compute the volume of the desired grid - real grid_vol = size[0] * size[1] * size[2]; - - if(grid_vol == 0){ - double min=DBL_MAX; - int index=0; - int nzeros=0; - for(int i=0;i<3;++i){ - if(size[i] == 0){ - ++nzeros; - index=i; - } - if((size[i]!=0) && (min>size[i])){ - min=size[i]; - } - } - if(nzeros>1){ - throw std::runtime_error("Warning: the 3D grid has more than one null dimension"); - } - tmpSize[index]=min; - _orig[index] = _orig[index]-min/2; - } - // Compute the desired volume of a single cell - real cell_vol = grid_vol / nb; - // The edge of such a cubic cell is cubic root of cellVolume - real edge = pow(cell_vol, 1.0 / 3.0); - - // We compute the number of cells par edge - // such as we cover at least the whole box. - unsigned i; - for (i = 0; i < 3; i++) - _cells_nb[i] = (unsigned)floor(tmpSize[i] / edge) + 1; - - _size = tmpSize; - - for(i = 0; i < 3; i++) - _cell_size[i] = _size[i] / _cells_nb[i]; -} - -void Grid::insertOccluder(Polygon3r* occluder) { - const vector vertices = occluder->getVertices(); - if (vertices.size() == 0) - return; - - // add this occluder to the grid's occluders list - addOccluder(occluder); - - // find the bbox associated to this polygon - Vec3r min, max; - occluder->getBBox(min, max); - - // Retrieve the cell x, y, z cordinates associated with these min and max - Vec3u imax, imin; - getCellCoordinates(max, imax); - getCellCoordinates(min, imin); - - // We are now going to fill in the cells overlapping with the - // polygon bbox. - // If the polygon is a triangle (most of cases), we also - // check for each of these cells if it is overlapping with - // the triangle in order to only fill in the ones really overlapping - // the triangle. - - unsigned i, x, y, z; - vector::const_iterator it; - Vec3u coord; - - if (vertices.size() == 3) { // Triangle case - Vec3r triverts[3]; - i = 0; - for(it = vertices.begin(); - it != vertices.end(); - it++) { - triverts[i] = Vec3r(*it); - i++; - } - - Vec3r boxmin, boxmax; - - for (z = imin[2]; z <= imax[2]; z++) - for (y = imin[1]; y <= imax[1]; y++) - for (x = imin[0]; x <= imax[0]; x++) { - coord[0] = x; - coord[1] = y; - coord[2] = z; - // We retrieve the box coordinates of the current cell - getCellBox(coord, boxmin, boxmax); - // We check whether the triangle and the box ovewrlap: - Vec3r boxcenter((boxmin + boxmax) / 2.0); - Vec3r boxhalfsize(_cell_size / 2.0); - if (GeomUtils::overlapTriangleBox(boxcenter, boxhalfsize, triverts)) { - // We must then create the Cell and add it to the cells list - // if it does not exist yet. - // We must then add the occluder to the occluders list of this cell. - Cell* cell = getCell(coord); - if (!cell) { - cell = new Cell(boxmin); - fillCell(coord, *cell); - } - cell->addOccluder(occluder); - } +void Grid::clear() +{ + if (_occluders.size() != 0) { + for (OccludersSet::iterator it = _occluders.begin(); it != _occluders.end(); it++) { + delete (*it); + } + _occluders.clear(); } - } - else { // The polygon is not a triangle, we add all the cells overlapping the polygon bbox. - for (z = imin[2]; z <= imax[2]; z++) - for (y = imin[1]; y <= imax[1]; y++) - for (x = imin[0]; x <= imax[0]; x++) { - coord[0] = x; - coord[1] = y; - coord[2] = z; - Cell* cell = getCell(coord); - if (!cell) { - Vec3r orig; - getCellOrigin(coord, orig); - cell = new Cell(orig); - fillCell(coord, *cell); - } - cell->addOccluder(occluder); + + _size = Vec3r(0, 0, 0); + _cell_size = Vec3r(0, 0, 0); + _orig = Vec3r(0, 0, 0); + _cells_nb = Vec3u(0, 0, 0); + //_ray_occluders.clear(); +} + +void Grid::configure(const Vec3r& orig, const Vec3r& size, unsigned nb) +{ + _orig = orig; + Vec3r tmpSize = size; + // Compute the volume of the desired grid + real grid_vol = size[0] * size[1] * size[2]; + + if (grid_vol == 0) { + double min = DBL_MAX; + int index = 0; + int nzeros = 0; + for (int i = 0; i < 3; ++i) { + if (size[i] == 0) { + ++nzeros; + index = i; + } + if ((size[i] != 0) && (min > size[i])) { + min = size[i]; + } + } + if (nzeros > 1) { + throw std::runtime_error("Warning: the 3D grid has more than one null dimension"); + } + tmpSize[index] = min; + _orig[index] = _orig[index] - min / 2; } - } + // Compute the desired volume of a single cell + real cell_vol = grid_vol / nb; + // The edge of such a cubic cell is cubic root of cellVolume + real edge = pow(cell_vol, 1.0 / 3.0); + + // We compute the number of cells par edge such as we cover at least the whole box. + unsigned i; + for (i = 0; i < 3; i++) + _cells_nb[i] = (unsigned)floor(tmpSize[i] / edge) + 1; + + _size = tmpSize; + + for (i = 0; i < 3; i++) + _cell_size[i] = _size[i] / _cells_nb[i]; } -bool Grid::nextRayCell(Vec3u& current_cell, Vec3u& next_cell) { - next_cell = current_cell; - real t_min, t; - unsigned i; - - t_min = FLT_MAX; // init tmin with handle of the case where one or 2 _u[i] = 0. - unsigned coord = 0; // predominant coord(0=x, 1=y, 2=z) +void Grid::insertOccluder(Polygon3r* occluder) +{ + const vector vertices = occluder->getVertices(); + if (vertices.size() == 0) + return; + // add this occluder to the grid's occluders list + addOccluder(occluder); - // using a parametric equation of - // a line : B = A + t u, we find - // the tx, ty and tz respectively coresponding - // to the intersections with the plans: - // x = _cell_size[0], y = _cell_size[1], z = _cell_size[2] - for (i = 0; i < 3; i++) { - if (_ray_dir[i] == 0) - continue; - if (_ray_dir[i] > 0) - t = (_cell_size[i] - _pt[i]) / _ray_dir[i]; - else - t = -_pt[i] / _ray_dir[i]; - if (t < t_min) { - t_min = t; - coord = i; - } - } + // find the bbox associated to this polygon + Vec3r min, max; + occluder->getBBox(min, max); - // We use the parametric line equation and - // the found t (tamx) to compute the - // B coordinates: - Vec3r pt_tmp(_pt); - _pt = pt_tmp + t_min * _ray_dir; - - // We express B coordinates in the next cell - // coordinates system. We just have to - // set the coordinate coord of B to 0 - // of _CellSize[coord] depending on the sign - // of _u[coord] - if (_ray_dir[coord] > 0) { - next_cell[coord]++; - _pt[coord] -= _cell_size[coord]; - // if we are out of the grid, we must stop - if (next_cell[coord] >= _cells_nb[coord]) - return false; - } - else { - int tmp = next_cell[coord] - 1; - _pt[coord] = _cell_size[coord]; - if (tmp < 0) - return false; - next_cell[coord]--; - } + // Retrieve the cell x, y, z cordinates associated with these min and max + Vec3u imax, imin; + getCellCoordinates(max, imax); + getCellCoordinates(min, imin); - _t += t_min; - if (_t >= _t_end) - return false; + // We are now going to fill in the cells overlapping with the polygon bbox. + // If the polygon is a triangle (most of cases), we also check for each of these cells if it is overlapping with + // the triangle in order to only fill in the ones really overlapping the triangle. - return true; + unsigned i, x, y, z; + vector::const_iterator it; + Vec3u coord; + + if (vertices.size() == 3) { // Triangle case + Vec3r triverts[3]; + i = 0; + for (it = vertices.begin(); it != vertices.end(); it++) { + triverts[i] = Vec3r(*it); + i++; + } + + Vec3r boxmin, boxmax; + + for (z = imin[2]; z <= imax[2]; z++) { + for (y = imin[1]; y <= imax[1]; y++) { + for (x = imin[0]; x <= imax[0]; x++) { + coord[0] = x; + coord[1] = y; + coord[2] = z; + // We retrieve the box coordinates of the current cell + getCellBox(coord, boxmin, boxmax); + // We check whether the triangle and the box ovewrlap: + Vec3r boxcenter((boxmin + boxmax) / 2.0); + Vec3r boxhalfsize(_cell_size / 2.0); + if (GeomUtils::overlapTriangleBox(boxcenter, boxhalfsize, triverts)) { + // We must then create the Cell and add it to the cells list if it does not exist yet. + // We must then add the occluder to the occluders list of this cell. + Cell* cell = getCell(coord); + if (!cell) { + cell = new Cell(boxmin); + fillCell(coord, *cell); + } + cell->addOccluder(occluder); + } + } + } + } + } + else { // The polygon is not a triangle, we add all the cells overlapping the polygon bbox. + for (z = imin[2]; z <= imax[2]; z++) { + for (y = imin[1]; y <= imax[1]; y++) { + for (x = imin[0]; x <= imax[0]; x++) { + coord[0] = x; + coord[1] = y; + coord[2] = z; + Cell* cell = getCell(coord); + if (!cell) { + Vec3r orig; + getCellOrigin(coord, orig); + cell = new Cell(orig); + fillCell(coord, *cell); + } + cell->addOccluder(occluder); + } + } + } + } } -void Grid::castRay(const Vec3r& orig, - const Vec3r& end, - OccludersSet& occluders, - unsigned timestamp) { - initRay(orig, end, timestamp); - allOccludersGridVisitor visitor(occluders); - castRayInternal(visitor); +bool Grid::nextRayCell(Vec3u& current_cell, Vec3u& next_cell) +{ + next_cell = current_cell; + real t_min, t; + unsigned i; + + t_min = FLT_MAX; // init tmin with handle of the case where one or 2 _u[i] = 0. + unsigned coord = 0; // predominant coord(0=x, 1=y, 2=z) + + + // using a parametric equation of a line : B = A + t u, we find the tx, ty and tz respectively coresponding + // to the intersections with the plans: + // x = _cell_size[0], y = _cell_size[1], z = _cell_size[2] + for (i = 0; i < 3; i++) { + if (_ray_dir[i] == 0) + continue; + if (_ray_dir[i] > 0) + t = (_cell_size[i] - _pt[i]) / _ray_dir[i]; + else + t = -_pt[i] / _ray_dir[i]; + if (t < t_min) { + t_min = t; + coord = i; + } + } + + // We use the parametric line equation and the found t (tamx) to compute the B coordinates: + Vec3r pt_tmp(_pt); + _pt = pt_tmp + t_min * _ray_dir; + + // We express B coordinates in the next cell coordinates system. We just have to + // set the coordinate coord of B to 0 of _CellSize[coord] depending on the sign of _u[coord] + if (_ray_dir[coord] > 0) { + next_cell[coord]++; + _pt[coord] -= _cell_size[coord]; + // if we are out of the grid, we must stop + if (next_cell[coord] >= _cells_nb[coord]) + return false; + } + else { + int tmp = next_cell[coord] - 1; + _pt[coord] = _cell_size[coord]; + if (tmp < 0) + return false; + next_cell[coord]--; + } + + _t += t_min; + if (_t >= _t_end) + return false; + + return true; } -void Grid::castInfiniteRay(const Vec3r& orig, - const Vec3r& dir, - OccludersSet& occluders, - unsigned timestamp) { - Vec3r end = Vec3r(orig + FLT_MAX * dir / dir.norm()); - bool inter = initInfiniteRay(orig, dir, timestamp); - if(!inter) - return; - allOccludersGridVisitor visitor(occluders); - castRayInternal(visitor); +void Grid::castRay(const Vec3r& orig, const Vec3r& end, OccludersSet& occluders, unsigned timestamp) +{ + initRay(orig, end, timestamp); + allOccludersGridVisitor visitor(occluders); + castRayInternal(visitor); } - -Polygon3r* Grid::castRayToFindFirstIntersection(const Vec3r& orig, - const Vec3r& dir, - double& t, - double& u, - double& v, - unsigned timestamp){ - Polygon3r *occluder = 0; - Vec3r end = Vec3r(orig + FLT_MAX * dir / dir.norm()); - bool inter = initInfiniteRay(orig, dir, timestamp); - if(!inter){ - return 0; - } - firstIntersectionGridVisitor visitor(orig,dir,_cell_size); - castRayInternal(visitor); + +void Grid::castInfiniteRay(const Vec3r& orig, const Vec3r& dir, OccludersSet& occluders, unsigned timestamp) +{ + Vec3r end = Vec3r(orig + FLT_MAX * dir / dir.norm()); + bool inter = initInfiniteRay(orig, dir, timestamp); + if (!inter) + return; + allOccludersGridVisitor visitor(occluders); + castRayInternal(visitor); +} + +Polygon3r* Grid::castRayToFindFirstIntersection(const Vec3r& orig, const Vec3r& dir, double& t, + double& u, double& v, unsigned timestamp) +{ + Polygon3r *occluder = 0; + Vec3r end = Vec3r(orig + FLT_MAX * dir / dir.norm()); + bool inter = initInfiniteRay(orig, dir, timestamp); + if (!inter) { + return 0; + } + firstIntersectionGridVisitor visitor(orig, dir, _cell_size); + castRayInternal(visitor); // ARB: This doesn't work, because occluders are unordered within any cell - // visitor.occluder() will be an occluder, but we have no guarantee - // it will be the *first* occluder. + // visitor.occluder() will be an occluder, but we have no guarantee it will be the *first* occluder. // I assume that is the reason this code is not actually used for FindOccludee. - occluder = visitor.occluder(); - t = visitor.t_; - u = visitor.u_; - v = visitor.v_; - return occluder; + occluder = visitor.occluder(); + t = visitor.t_; + u = visitor.u_; + v = visitor.v_; + return occluder; } -void Grid::initRay (const Vec3r &orig, - const Vec3r& end, - unsigned timestamp) { - _ray_dir = end - orig; - _t_end = _ray_dir.norm(); - _t = 0; - _ray_dir.normalize(); - _timestamp = timestamp; - - for(unsigned i = 0; i < 3; i++) { - _current_cell[i] = (unsigned)floor((orig[i] - _orig[i]) / _cell_size[i]); - //soc unused - unsigned u = _current_cell[i]; - _pt[i] = orig[i] - _orig[i] - _current_cell[i] * _cell_size[i]; - } - //_ray_occluders.clear(); +void Grid::initRay (const Vec3r &orig, const Vec3r& end, unsigned timestamp) +{ + _ray_dir = end - orig; + _t_end = _ray_dir.norm(); + _t = 0; + _ray_dir.normalize(); + _timestamp = timestamp; + for (unsigned i = 0; i < 3; i++) { + _current_cell[i] = (unsigned)floor((orig[i] - _orig[i]) / _cell_size[i]); + //soc unused - unsigned u = _current_cell[i]; + _pt[i] = orig[i] - _orig[i] - _current_cell[i] * _cell_size[i]; + } + //_ray_occluders.clear(); } -bool Grid::initInfiniteRay (const Vec3r &orig, - const Vec3r& dir, - unsigned timestamp) { - _ray_dir = dir; - _t_end = FLT_MAX; - _t = 0; - _ray_dir.normalize(); - _timestamp = timestamp; +bool Grid::initInfiniteRay (const Vec3r &orig, const Vec3r& dir, unsigned timestamp) { + _ray_dir = dir; + _t_end = FLT_MAX; + _t = 0; + _ray_dir.normalize(); + _timestamp = timestamp; - // check whether the origin is in or out the box: - Vec3r boxMin(_orig); - Vec3r boxMax(_orig+_size); - BBox box(boxMin, boxMax); - if(box.inside(orig)){ - for(unsigned i = 0; i < 3; i++) { - _current_cell[i] = (unsigned)floor((orig[i] - _orig[i]) / _cell_size[i]); - //soc unused - unsigned u = _current_cell[i]; - _pt[i] = orig[i] - _orig[i] - _current_cell[i] * _cell_size[i]; - } - }else{ - // is the ray intersecting the box? - real tmin(-1.0), tmax(-1.0); - if(GeomUtils::intersectRayBBox(orig, _ray_dir, boxMin, boxMax, 0, _t_end, tmin, tmax)){ - assert(tmin != -1.0); - Vec3r newOrig = orig + tmin*_ray_dir; - for(unsigned i = 0; i < 3; i++) { - _current_cell[i] = (unsigned)floor((newOrig[i] - _orig[i]) / _cell_size[i]); - if(_current_cell[i] == _cells_nb[i]) - _current_cell[i] = _cells_nb[i] - 1; - //soc unused - unsigned u = _current_cell[i]; - _pt[i] = newOrig[i] - _orig[i] - _current_cell[i] * _cell_size[i]; - } - - }else{ - return false; - } - } - //_ray_occluders.clear(); - - return true; + // check whether the origin is in or out the box: + Vec3r boxMin(_orig); + Vec3r boxMax(_orig + _size); + BBox box(boxMin, boxMax); + if (box.inside(orig)) { + for (unsigned int i = 0; i < 3; i++) { + _current_cell[i] = (unsigned int)floor((orig[i] - _orig[i]) / _cell_size[i]); + //soc unused - unsigned u = _current_cell[i]; + _pt[i] = orig[i] - _orig[i] - _current_cell[i] * _cell_size[i]; + } + } + else { + // is the ray intersecting the box? + real tmin(-1.0), tmax(-1.0); + if (GeomUtils::intersectRayBBox(orig, _ray_dir, boxMin, boxMax, 0, _t_end, tmin, tmax)) { + assert(tmin != -1.0); + Vec3r newOrig = orig + tmin * _ray_dir; + for (unsigned int i = 0; i < 3; i++) { + _current_cell[i] = (unsigned)floor((newOrig[i] - _orig[i]) / _cell_size[i]); + if (_current_cell[i] == _cells_nb[i]) + _current_cell[i] = _cells_nb[i] - 1; + //soc unused - unsigned u = _current_cell[i]; + _pt[i] = newOrig[i] - _orig[i] - _current_cell[i] * _cell_size[i]; + } + } + else { + return false; + } + } + //_ray_occluders.clear(); + return true; } - diff --git a/source/blender/freestyle/intern/geometry/Grid.h b/source/blender/freestyle/intern/geometry/Grid.h index a490646ff51..40bd0911c9c 100644 --- a/source/blender/freestyle/intern/geometry/Grid.h +++ b/source/blender/freestyle/intern/geometry/Grid.h @@ -1,49 +1,54 @@ -// -// Filename : Grid.h -// Author(s) : Stephane Grabli -// Purpose : Base class to define a cell grid surrounding -// the bounding box of the scene -// Date of creation : 30/07/2002 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __GRID_H__ +#define __GRID_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/Grid.h + * \ingroup freestyle + * \brief Base class to define a cell grid surrounding the bounding box of the scene + * \author Stephane Grabli + * \date 30/07/2002 + */ -#ifndef GRID_H -# define GRID_H +#include // for memset +#include +#include -# include // for memset -# include -# include -# include "../system/FreestyleConfig.h" -# include "GeomUtils.h" -# include "Geom.h" -# include "Polygon.h" +#include "Geom.h" +#include "GeomUtils.h" +#include "Polygon.h" + +#include "../system/FreestyleConfig.h" using namespace std; using namespace Geometry; -typedef vector OccludersSet; - +typedef vector OccludersSet; // // Class to define cells used by the regular grid @@ -52,84 +57,102 @@ typedef vector OccludersSet; class LIB_GEOMETRY_EXPORT Cell { - public: - - Cell(Vec3r& orig) { - _orig = orig; - } +public: + Cell(Vec3r& orig) { + _orig = orig; + } - virtual ~Cell() {} + virtual ~Cell() {} - inline void addOccluder(Polygon3r* o) { - if (o) - _occluders.push_back(o); - } + inline void addOccluder(Polygon3r* o) { + if (o) + _occluders.push_back(o); + } - inline const Vec3r& getOrigin() { - return _orig; - } + inline const Vec3r& getOrigin() { + return _orig; + } - inline OccludersSet& getOccluders() { - return _occluders; - } - - private: + inline OccludersSet& getOccluders() { + return _occluders; + } - Vec3r _orig; - OccludersSet _occluders; +private: + Vec3r _orig; + OccludersSet _occluders; }; -class GridVisitor{ +class GridVisitor +{ public: virtual ~GridVisitor() {}; //soc - virtual void discoverCell(Cell *cell) {} - virtual void examineOccluder(Polygon3r *occ) {} - virtual void finishCell(Cell *cell) {} - virtual bool stop() {return false;} + + virtual void discoverCell(Cell *cell) {} + + virtual void examineOccluder(Polygon3r *occ) {} + + virtual void finishCell(Cell *cell) {} + + virtual bool stop() { + return false; + } }; -/*! Gathers all the occluders belonging to the cells - * traversed by the ray */ -class allOccludersGridVisitor : public GridVisitor{ +/*! Gathers all the occluders belonging to the cells traversed by the ray */ +class allOccludersGridVisitor : public GridVisitor +{ public: - allOccludersGridVisitor(OccludersSet& occluders) - :GridVisitor(), occluders_(occluders){} - virtual void examineOccluder(Polygon3r *occ); + allOccludersGridVisitor(OccludersSet& occluders) : GridVisitor(), occluders_(occluders) {} - OccludersSet& occluders() {return occluders_;} - void clear() {occluders_.clear();} + virtual void examineOccluder(Polygon3r *occ); + + OccludersSet& occluders() { + return occluders_; + } + + void clear() { + occluders_.clear(); + } private: - OccludersSet& occluders_; + OccludersSet& occluders_; }; -/*! Finds the first intersection and breaks. The occluder and - * the intersection information are stored and accessible. +/*! Finds the first intersection and breaks. + * The occluder and the intersection information are stored and accessible. */ -class firstIntersectionGridVisitor : public GridVisitor { - +class firstIntersectionGridVisitor : public GridVisitor +{ //soc - changed order to remove warnings public: - double u_, v_, t_; + double u_, v_, t_; + private: - Polygon3r *occluder_; + Polygon3r *occluder_; Vec3r ray_org_, ray_dir_, cell_size_; - Cell * current_cell_; + Cell *current_cell_; public: - firstIntersectionGridVisitor(const Vec3r& ray_org, const Vec3r& ray_dir, const Vec3r& cell_size) : - GridVisitor(), u_(0),v_(0),t_(DBL_MAX), - occluder_(0), - ray_org_(ray_org), ray_dir_(ray_dir), cell_size_(cell_size), - current_cell_(0) {} - virtual ~firstIntersectionGridVisitor() {} + firstIntersectionGridVisitor(const Vec3r& ray_org, const Vec3r& ray_dir, const Vec3r& cell_size) : + GridVisitor(), u_(0),v_(0),t_(DBL_MAX), occluder_(0), ray_org_(ray_org), ray_dir_(ray_dir), + cell_size_(cell_size), current_cell_(0) + { + } - virtual void discoverCell(Cell *cell) {current_cell_=cell;} - virtual void examineOccluder(Polygon3r *occ); - virtual bool stop(); + virtual ~firstIntersectionGridVisitor() {} - Polygon3r * occluder() {return occluder_;} + virtual void discoverCell(Cell *cell) { + current_cell_ = cell; + } + + virtual void examineOccluder(Polygon3r *occ); + + virtual bool stop(); + + Polygon3r *occluder() { + return occluder_; + } }; // @@ -140,236 +163,197 @@ public: class LIB_GEOMETRY_EXPORT Grid { public: + /*! Builds a Grid. Must be followed by a call to configure() */ + Grid() {} - /*! Builds a Grid - * Must be followed by a call to configure() - */ - Grid() {} + virtual ~Grid() { + clear(); + } - virtual ~Grid() { - clear(); - } + /*! clears the grid + * Deletes all the cells, clears the hashtable, resets size, size of cell, number of cells. + */ + virtual void clear(); - /*! clears the grid - * Deletes all the cells, clears the hashtable, - * resets size, size of cell, number of cells. - */ - virtual void clear(); + /*! Sets the different parameters of the grid + * orig + * The grid origin + * size + * The grid's dimensions + * nb + * The number of cells of the grid + */ + virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb); - /*! Sets the different parameters of the grid - * orig - * The grid origin - * size - * The grid's dimensions - * nb - * The number of cells of the grid - */ - virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb); - - /*! returns a vector of integer containing the - * coordinates of the cell containing the point - * passed as argument - * p - * The point for which we're looking the cell - */ - inline void getCellCoordinates(const Vec3r& p, Vec3u& res) { - int tmp; - for (int i = 0; i < 3; i++) { - tmp = (int)((p[i] - _orig[i]) / _cell_size[i]); - if (tmp < 0) - res[i] = 0; - else if ((unsigned)tmp >= _cells_nb[i]) - res[i] = _cells_nb[i] - 1; - else - res[i] = tmp; - } - } + /*! returns a vector of integer containing the coordinates of the cell containing the point passed as argument + * p + * The point for which we're looking the cell + */ + inline void getCellCoordinates(const Vec3r& p, Vec3u& res) { + int tmp; + for (int i = 0; i < 3; i++) { + tmp = (int)((p[i] - _orig[i]) / _cell_size[i]); + if (tmp < 0) + res[i] = 0; + else if ((unsigned int)tmp >= _cells_nb[i]) + res[i] = _cells_nb[i] - 1; + else + res[i] = tmp; + } + } - /*! Fills the case corresponding to coord with the cell */ - virtual void fillCell(const Vec3u& coord, Cell& cell) = 0; + /*! Fills the case corresponding to coord with the cell */ + virtual void fillCell(const Vec3u& coord, Cell& cell) = 0; - /*! returns the cell whose coordinates - * are pased as argument - */ - virtual Cell* getCell(const Vec3u& coord) = 0; + /*! returns the cell whose coordinates are pased as argument */ + virtual Cell* getCell(const Vec3u& coord) = 0; - /*! returns the cell containing the point - * passed as argument. If the cell is empty - * (contains no occluder), NULL is returned - * p - * The point for which we're looking the cell - */ - inline Cell* getCell(const Vec3r& p) { - Vec3u coord; - getCellCoordinates(p, coord); - return getCell(coord); - } + /*! returns the cell containing the point passed as argument. If the cell is empty (contains no occluder), + * NULL is returned + * p + * The point for which we're looking the cell + */ + inline Cell* getCell(const Vec3r& p) { + Vec3u coord; + getCellCoordinates(p, coord); + return getCell(coord); + } - /*! Retrieves the x,y,z coordinates of the origin of the cell whose coordinates (i,j,k) - * is passed as argument - * cell_coord - * i,j,k integer coordinates for the cell - * orig - * x,y,x vector to be filled in with the cell origin's coordinates - */ - inline void getCellOrigin(const Vec3u& cell_coord, Vec3r& orig) { - for (unsigned i = 0; i < 3; i++) - orig[i] = _orig[i] + cell_coord[i] * _cell_size[i]; - } + /*! Retrieves the x,y,z coordinates of the origin of the cell whose coordinates (i,j,k) is passed as argument + * cell_coord + * i,j,k integer coordinates for the cell + * orig + * x,y,x vector to be filled in with the cell origin's coordinates + */ + inline void getCellOrigin(const Vec3u& cell_coord, Vec3r& orig) { + for (unsigned int i = 0; i < 3; i++) + orig[i] = _orig[i] + cell_coord[i] * _cell_size[i]; + } - /*! Retrieves the box corresponding to the cell whose coordinates - * are passed as argument. - * cell_coord - * i,j,k integer coordinates for the cell - * min_out - * The min x,y,x vector of the box. Filled in by the method. - * max_out - * The max x,y,z coordinates of the box. Filled in by the method. - */ - inline void getCellBox(const Vec3u& cell_coord, Vec3r& min_out, Vec3r& max_out) { - getCellOrigin(cell_coord, min_out); - max_out = min_out + _cell_size; - } + /*! Retrieves the box corresponding to the cell whose coordinates are passed as argument. + * cell_coord + * i,j,k integer coordinates for the cell + * min_out + * The min x,y,x vector of the box. Filled in by the method. + * max_out + * The max x,y,z coordinates of the box. Filled in by the method. + */ + inline void getCellBox(const Vec3u& cell_coord, Vec3r& min_out, Vec3r& max_out) { + getCellOrigin(cell_coord, min_out); + max_out = min_out + _cell_size; + } - /*! inserts a convex polygon occluder - * This method is quite coarse insofar as it - * adds all cells intersecting the polygon bounding box - * convex_poly - * The list of 3D points constituing a convex polygon - */ - void insertOccluder(Polygon3r * convex_poly); + /*! inserts a convex polygon occluder + * This method is quite coarse insofar as it adds all cells intersecting the polygon bounding box + * convex_poly + * The list of 3D points constituing a convex polygon + */ + void insertOccluder(Polygon3r * convex_poly); - /*! Adds an occluder to the list of occluders */ - void addOccluder(Polygon3r* occluder) { - _occluders.push_back(occluder); - } + /*! Adds an occluder to the list of occluders */ + void addOccluder(Polygon3r* occluder) { + _occluders.push_back(occluder); + } - /*! Casts a ray between a starting point and an ending point - * Returns the list of occluders contained - * in the cells intersected by this ray - * Starts with a call to InitRay. - */ - void castRay(const Vec3r& orig, - const Vec3r& end, - OccludersSet& occluders, - unsigned timestamp); - // Prepares to cast ray without generating OccludersSet - void initAcceleratedRay(const Vec3r& orig, - const Vec3r& end, - unsigned timestamp); + /*! Casts a ray between a starting point and an ending point + * Returns the list of occluders contained in the cells intersected by this ray + * Starts with a call to InitRay. + */ + void castRay(const Vec3r& orig, const Vec3r& end, OccludersSet& occluders, unsigned timestamp); - /*! Casts an infinite ray (still finishing at the end of the grid) from a starting point and in a given direction. - * Returns the list of occluders contained - * in the cells intersected by this ray - * Starts with a call to InitRay. - */ - void castInfiniteRay(const Vec3r& orig, - const Vec3r& dir, - OccludersSet& occluders, - unsigned timestamp); - // Prepares to cast ray without generating OccludersSet. - bool initAcceleratedInfiniteRay(const Vec3r& orig, - const Vec3r& dir, - unsigned timestamp); + // Prepares to cast ray without generating OccludersSet + void initAcceleratedRay(const Vec3r& orig, const Vec3r& end, unsigned timestamp); - /*! Casts an infinite ray (still finishing at the end of the grid) from a starting point and in a given direction. - * Returns the first intersection (occluder,t,u,v) or null. - * Starts with a call to InitRay. - */ - Polygon3r * castRayToFindFirstIntersection(const Vec3r& orig, - const Vec3r& dir, - double& t, - double& u, - double& v, - unsigned timestamp); + /*! Casts an infinite ray (still finishing at the end of the grid) from a starting point and in a given direction. + * Returns the list of occluders contained in the cells intersected by this ray + * Starts with a call to InitRay. + */ + void castInfiniteRay(const Vec3r& orig, const Vec3r& dir, OccludersSet& occluders, unsigned timestamp); + + // Prepares to cast ray without generating OccludersSet. + bool initAcceleratedInfiniteRay(const Vec3r& orig, const Vec3r& dir, unsigned timestamp); + + /*! Casts an infinite ray (still finishing at the end of the grid) from a starting point and in a given direction. + * Returns the first intersection (occluder,t,u,v) or null. + * Starts with a call to InitRay. + */ + Polygon3r * castRayToFindFirstIntersection(const Vec3r& orig, const Vec3r& dir, double& t, + double& u, double& v, unsigned timestamp); - /*! Init all structures and values for computing - * the cells intersected by this new ray - */ - void initRay (const Vec3r &orig, - const Vec3r& end, - unsigned timestamp); + /*! Init all structures and values for computing the cells intersected by this new ray */ + void initRay(const Vec3r &orig, const Vec3r& end, unsigned timestamp); - /*! Init all structures and values for computing - * the cells intersected by this infinite ray. - * Returns false if the ray doesn't intersect the - * grid. - */ - bool initInfiniteRay (const Vec3r &orig, - const Vec3r& dir, - unsigned timestamp); + /*! Init all structures and values for computing the cells intersected by this infinite ray. + * Returns false if the ray doesn't intersect the grid. + */ + bool initInfiniteRay(const Vec3r &orig, const Vec3r& dir, unsigned timestamp); - - /*! Accessors */ - inline const Vec3r& getOrigin() const { - return _orig; - } - inline Vec3r gridSize() const { - return _size; - } - inline Vec3r getCellSize() const { - return _cell_size; - } -//ARB profiling only: - inline OccludersSet* getOccluders() { - return &_occluders; - } - void displayDebug() { - cerr << "Cells nb : " << _cells_nb << endl; - cerr << "Cell size : " << _cell_size << endl; - cerr << "Origin : " << _orig << endl; - cerr << "Occluders nb : " << _occluders.size() << endl; - } + /*! Accessors */ + inline const Vec3r& getOrigin() const { + return _orig; + } - protected: + inline Vec3r gridSize() const { + return _size; + } - /*! Core of castRay and castInfiniteRay, find occluders - * along the given ray - */ - inline void castRayInternal(GridVisitor& visitor) { - Cell* current_cell = NULL; - do { - current_cell = getCell(_current_cell); - if (current_cell){ - visitor.discoverCell(current_cell); - OccludersSet& occluders = current_cell->getOccluders(); // FIXME: I had forgotten the ref & - for (OccludersSet::iterator it = occluders.begin(); - it != occluders.end(); - it++) { - if ((unsigned long)(*it)->userdata2 != _timestamp) { - (*it)->userdata2 = (void*)_timestamp; - visitor.examineOccluder(*it); - } - } - visitor.finishCell(current_cell); - } - } while ((!visitor.stop()) && (nextRayCell(_current_cell, _current_cell))); - } + inline Vec3r getCellSize() const { + return _cell_size; + } - - /*! returns the cell next to the cell - * passed as argument. - */ - bool nextRayCell(Vec3u& current_cell, Vec3u& next_cell); + //ARB profiling only: + inline OccludersSet* getOccluders() { + return &_occluders; + } - unsigned _timestamp; + void displayDebug() { + cerr << "Cells nb : " << _cells_nb << endl; + cerr << "Cell size : " << _cell_size << endl; + cerr << "Origin : " << _orig << endl; + cerr << "Occluders nb : " << _occluders.size() << endl; + } - Vec3u _cells_nb; // number of cells for x,y,z axis - Vec3r _cell_size; // cell x,y,z dimensions - Vec3r _size; // grid x,y,x dimensions - Vec3r _orig; // grid origin +protected: + /*! Core of castRay and castInfiniteRay, find occluders along the given ray */ + inline void castRayInternal(GridVisitor& visitor) { + Cell *current_cell = NULL; + do { + current_cell = getCell(_current_cell); + if (current_cell) { + visitor.discoverCell(current_cell); + OccludersSet& occluders = current_cell->getOccluders(); // FIXME: I had forgotten the ref & + for (OccludersSet::iterator it = occluders.begin(); it != occluders.end(); it++) { + if ((unsigned long)(*it)->userdata2 != _timestamp) { + (*it)->userdata2 = (void*)_timestamp; + visitor.examineOccluder(*it); + } + } + visitor.finishCell(current_cell); + } + } while ((!visitor.stop()) && (nextRayCell(_current_cell, _current_cell))); + } - Vec3r _ray_dir; // direction vector for the ray - Vec3u _current_cell; // The current cell being processed (designated by its 3 coordinates) - Vec3r _pt; // Points corresponding to the incoming and outgoing intersections - // of one cell with the ray - real _t_end; // To know when we are at the end of the ray - real _t; - //OccludersSet _ray_occluders; // Set storing the occluders contained in the cells traversed by a ray - OccludersSet _occluders; // List of all occluders inserted in the grid + /*! returns the cell next to the cell passed as argument. */ + bool nextRayCell(Vec3u& current_cell, Vec3u& next_cell); + + unsigned int _timestamp; + + Vec3u _cells_nb; // number of cells for x,y,z axis + Vec3r _cell_size; // cell x,y,z dimensions + Vec3r _size; // grid x,y,x dimensions + Vec3r _orig; // grid origin + + Vec3r _ray_dir; // direction vector for the ray + Vec3u _current_cell; // The current cell being processed (designated by its 3 coordinates) + Vec3r _pt; // Points corresponding to the incoming and outgoing intersections of one cell with the ray + real _t_end; // To know when we are at the end of the ray + real _t; + + //OccludersSet _ray_occluders; // Set storing the occluders contained in the cells traversed by a ray + OccludersSet _occluders; // List of all occluders inserted in the grid }; // @@ -378,15 +362,16 @@ public: /////////////////////////////////////////////////////////////////////////////// class VirtualOccludersSet { - public: - VirtualOccludersSet(Grid& _grid) : grid (_grid) {}; - Polygon3r* begin(); - Polygon3r* next(); - Polygon3r* next(bool stopOnNewCell); - private: - Polygon3r* firstOccluderFromNextCell(); - Grid& grid; - OccludersSet::iterator it, end; +public: + VirtualOccludersSet(Grid& _grid) : grid (_grid) {}; + Polygon3r* begin(); + Polygon3r* next(); + Polygon3r* next(bool stopOnNewCell); + +private: + Polygon3r* firstOccluderFromNextCell(); + Grid& grid; + OccludersSet::iterator it, end; }; -#endif // GRID_H +#endif // __GRID_H__ diff --git a/source/blender/freestyle/intern/geometry/GridHelpers.cpp b/source/blender/freestyle/intern/geometry/GridHelpers.cpp index dcf24a72efb..055a47f6bd5 100644 --- a/source/blender/freestyle/intern/geometry/GridHelpers.cpp +++ b/source/blender/freestyle/intern/geometry/GridHelpers.cpp @@ -1,49 +1,52 @@ -// -// Filename : GridHelpers.cpp -// Author(s) : Alexander Beels -// Purpose : Class to define a cell grid surrounding -// the projected image of a scene -// Date of creation : 2010-12-21 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/GridHelpers.cpp + * \ingroup freestyle + * \brief Class to define a cell grid surrounding the projected image of a scene + * \author Alexander Beels + * \date 2010-12-21 + */ #include + #include "GridHelpers.h" -void GridHelpers::getDefaultViewProscenium(real viewProscenium[4]) { +void GridHelpers::getDefaultViewProscenium(real viewProscenium[4]) +{ // Get proscenium boundary for culling - // bufferZone determines the amount by which the area processed - // should exceed the actual image area. This is intended to - // avoid visible artifacts generated along the proscenium edge. - // Perhaps this is no longer needed now that entire view edges - // are culled at once, since that theoretically should eliminate - // visible artifacts. - // To the extent it is still useful, bufferZone should be put into - // the UI as configurable percentage value + // bufferZone determines the amount by which the area processed should exceed the actual image area. + // This is intended to avoid visible artifacts generated along the proscenium edge. + // Perhaps this is no longer needed now that entire view edges are culled at once, since that theoretically + // should eliminate visible artifacts. + // To the extent it is still useful, bufferZone should be put into the UI as configurable percentage value const real bufferZone = 0.05; - // borderZone describes a blank border outside the proscenium, but - // still inside the image area. Only intended for exposing possible - // artifacts along or outside the proscenium edge during debugging. + // borderZone describes a blank border outside the proscenium, but still inside the image area. + // Only intended for exposing possible artifacts along or outside the proscenium edge during debugging. const real borderZone = 0.0; viewProscenium[0] = freestyle_viewport[2] * (borderZone - bufferZone); viewProscenium[1] = freestyle_viewport[2] * (1.0f - borderZone + bufferZone); @@ -51,6 +54,6 @@ void GridHelpers::getDefaultViewProscenium(real viewProscenium[4]) { viewProscenium[3] = freestyle_viewport[3] * (1.0f - borderZone + bufferZone); } -GridHelpers::Transform::~Transform () {} - - +GridHelpers::Transform::~Transform () +{ +} diff --git a/source/blender/freestyle/intern/geometry/GridHelpers.h b/source/blender/freestyle/intern/geometry/GridHelpers.h index b079005c1b5..4391b4f61a3 100644 --- a/source/blender/freestyle/intern/geometry/GridHelpers.h +++ b/source/blender/freestyle/intern/geometry/GridHelpers.h @@ -1,47 +1,55 @@ -// -// Filename : GridHelpers.h -// Author(s) : Alexander Beels -// Purpose : Class to define a cell grid surrounding -// the projected image of a scene -// Date of creation : 2010-12-13 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __GRIDHELPERS_H__ +#define __GRIDHELPERS_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef GRIDHELPERS_H -#define GRIDHELPERS_H +/** \file blender/freestyle/intern/geometry/GridHelpers.h + * \ingroup freestyle + * \brief Class to define a cell grid surrounding the projected image of a scene + * \author Alexander Beels + * \date 2010-12-13 + */ #include -#include "Polygon.h" -#include "../winged_edge/WEdge.h" + #include "FRS_freestyle.h" + #include "GeomUtils.h" +#include "Polygon.h" + +#include "../winged_edge/WEdge.h" namespace GridHelpers { /*! Computes the distance from a point P to a segment AB */ template -T closestPointToSegment(const T& P, const T& A , const T& B, real& distance) { +T closestPointToSegment(const T& P, const T& A , const T& B, real& distance) +{ T AB, AP, BP; AB = B - A; AP = P - A; @@ -59,31 +67,32 @@ T closestPointToSegment(const T& P, const T& A , const T& B, real& distance) { return B; // B is closest point } - real b = c1 / c2; - T Pb, PPb; - Pb = A + b * AB; - PPb = P - Pb; + real b = c1 / c2; + T Pb, PPb; + Pb = A + b * AB; + PPb = P - Pb; - distance = PPb.norm(); + distance = PPb.norm(); return Pb; // closest point lies on AB } -inline Vec3r closestPointOnPolygon(const Vec3r& point, const Polygon3r& poly) { +inline Vec3r closestPointOnPolygon(const Vec3r& point, const Polygon3r& poly) +{ // First cast a ray from the point onto the polygon plane // If the ray intersects the polygon, then the intersection point // is the closest point on the polygon real t, u, v; - if ( poly.rayIntersect(point, poly.getNormal(), t, u, v) ) { + if (poly.rayIntersect(point, poly.getNormal(), t, u, v)) { return point + poly.getNormal() * t; } // Otherwise, get the nearest point on each edge, and take the closest real distance; Vec3r closest = closestPointToSegment(point, poly.getVertices()[2], poly.getVertices()[0], distance); - for ( unsigned i = 0; i < 2; ++i ) { + for (unsigned int i = 0; i < 2; ++i) { real t; Vec3r p = closestPointToSegment(point, poly.getVertices()[i], poly.getVertices()[i + 1], t); - if ( t < distance ) { + if (t < distance) { distance = t; closest = p; } @@ -91,57 +100,63 @@ inline Vec3r closestPointOnPolygon(const Vec3r& point, const Polygon3r& poly) { return closest; } -inline real distancePointToPolygon(const Vec3r& point, const Polygon3r& poly) { +inline real distancePointToPolygon(const Vec3r& point, const Polygon3r& poly) +{ // First cast a ray from the point onto the polygon plane // If the ray intersects the polygon, then the intersection point // is the closest point on the polygon real t, u, v; - if ( poly.rayIntersect(point, poly.getNormal(), t, u, v) ) { - return t > 0.0 ? t : -t; + if (poly.rayIntersect(point, poly.getNormal(), t, u, v)) { + return (t > 0.0) ? t : -t; } // Otherwise, get the nearest point on each edge, and take the closest real distance = GeomUtils::distPointSegment(point, poly.getVertices()[2], poly.getVertices()[0]); - for ( unsigned i = 0; i < 2; ++i ) { + for (unsigned int i = 0; i < 2; ++i) { real t = GeomUtils::distPointSegment(point, poly.getVertices()[i], poly.getVertices()[i + 1]); - if ( t < distance ) { + if (t < distance) { distance = t; } } return distance; } -class Transform { +class Transform +{ public: - virtual ~Transform () =0; - virtual Vec3r operator()(const Vec3r& point) const =0; + virtual ~Transform () = 0; + virtual Vec3r operator()(const Vec3r& point) const = 0; }; -inline bool insideProscenium (const real proscenium[4], const Polygon3r& polygon) { - // N.B. The bounding box check is redundant for inserting occluders into - // cells, because the cell selection code in insertOccluders has already - // guaranteed that the bounding boxes will overlap. +inline bool insideProscenium (const real proscenium[4], const Polygon3r& polygon) +{ + // N.B. The bounding box check is redundant for inserting occluders into cells, because the cell selection code + // in insertOccluders has already guaranteed that the bounding boxes will overlap. // First check the viewport edges, since they are the easiest case // Check if the bounding box is entirely outside the proscenium Vec3r bbMin, bbMax; polygon.getBBox(bbMin, bbMax); - if ( bbMax[0] < proscenium[0] - || bbMin[0] > proscenium[1] - || bbMax[1] < proscenium[2] - || bbMin[1] > proscenium[3] ) { + if (bbMax[0] < proscenium[0] || bbMin[0] > proscenium[1] || bbMax[1] < proscenium[2] || bbMin[1] > proscenium[3]) { return false; } - Vec3r boxCenter(proscenium[0] + (proscenium[1] - proscenium[0]) / 2.0, proscenium[2] + (proscenium[3] - proscenium[2]) / 2.0, 0.0); - Vec3r boxHalfSize((proscenium[1] - proscenium[0]) / 2.0, (proscenium[3] - proscenium[2]) / 2.0, 1.0); - Vec3r triverts[3] = { Vec3r(polygon.getVertices()[0][0], polygon.getVertices()[0][1], 0.0), Vec3r(polygon.getVertices()[1][0], polygon.getVertices()[1][1], 0.0), Vec3r(polygon.getVertices()[2][0], polygon.getVertices()[2][1], 0.0) }; + Vec3r boxCenter(proscenium[0] + (proscenium[1] - proscenium[0]) / 2.0, + proscenium[2] + (proscenium[3] - proscenium[2]) / 2.0, 0.0); + Vec3r boxHalfSize((proscenium[1] - proscenium[0]) / 2.0, + (proscenium[3] - proscenium[2]) / 2.0, 1.0); + Vec3r triverts[3] = { + Vec3r(polygon.getVertices()[0][0], polygon.getVertices()[0][1], 0.0), + Vec3r(polygon.getVertices()[1][0], polygon.getVertices()[1][1], 0.0), + Vec3r(polygon.getVertices()[2][0], polygon.getVertices()[2][1], 0.0) + }; return GeomUtils::overlapTriangleBox(boxCenter, boxHalfSize, triverts); } -inline vector enumerateVertices(const vector& fedges) { +inline vector enumerateVertices(const vector& fedges) +{ vector points; // Iterate over vertices, storing projections in points - for(vector::const_iterator woe=fedges.begin(), woend=fedges.end(); woe!=woend; woe++) { + for (vector::const_iterator woe = fedges.begin(), woend = fedges.end(); woe != woend; woe++) { points.push_back((*woe)->GetaVertex()->GetVertex()); } @@ -150,50 +165,51 @@ inline vector enumerateVertices(const vector& fedges) { void getDefaultViewProscenium(real viewProscenium[4]); -inline void expandProscenium (real proscenium[4], const Polygon3r& polygon) { +inline void expandProscenium (real proscenium[4], const Polygon3r& polygon) +{ Vec3r bbMin, bbMax; polygon.getBBox(bbMin, bbMax); const real epsilon = 1.0e-6; - if ( bbMin[0] <= proscenium[0] ) { + if (bbMin[0] <= proscenium[0]) { proscenium[0] = bbMin[0] - epsilon; } - if ( bbMin[1] <= proscenium[2] ) { + if (bbMin[1] <= proscenium[2]) { proscenium[2] = bbMin[1] - epsilon; } - if ( bbMax[0] >= proscenium[1] ) { + if (bbMax[0] >= proscenium[1]) { proscenium[1] = bbMax[0] + epsilon; } - if ( bbMax[1] >= proscenium[3] ) { + if (bbMax[1] >= proscenium[3]) { proscenium[3] = bbMax[1] + epsilon; } } -inline void expandProscenium (real proscenium[4], const Vec3r& point) { +inline void expandProscenium (real proscenium[4], const Vec3r& point) +{ const real epsilon = 1.0e-6; - if ( point[0] <= proscenium[0] ) { + if (point[0] <= proscenium[0]) { proscenium[0] = point[0] - epsilon; } - if ( point[1] <= proscenium[2] ) { + if (point[1] <= proscenium[2]) { proscenium[2] = point[1] - epsilon; } - if ( point[0] >= proscenium[1] ) { + if (point[0] >= proscenium[1]) { proscenium[1] = point[0] + epsilon; } - if ( point[1] >= proscenium[3] ) { + if (point[1] >= proscenium[3]) { proscenium[3] = point[1] + epsilon; } } -}; - -#endif // GRIDHELPERS_H +}; // GridHelpers namespace +#endif // __GRIDHELPERS_H__ diff --git a/source/blender/freestyle/intern/geometry/HashGrid.cpp b/source/blender/freestyle/intern/geometry/HashGrid.cpp index 3cf845d57ef..b0ad9e0f276 100644 --- a/source/blender/freestyle/intern/geometry/HashGrid.cpp +++ b/source/blender/freestyle/intern/geometry/HashGrid.cpp @@ -1,41 +1,53 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/HashGrid.cpp + * \ingroup freestyle + * \brief Class to define a cell grid surrounding the bounding box of the scene + * \author Stephane Grabli + * \date 30/07/2002 + */ #include "HashGrid.h" void HashGrid::clear() { - if(!_cells.empty()) { - for(GridHashTable::iterator it = _cells.begin(); - it !=_cells.end(); - it++) { - Cell* cell = (*it).second; - delete cell; - } - _cells.clear(); - } + if (!_cells.empty()) { + for (GridHashTable::iterator it = _cells.begin(); it !=_cells.end(); it++) { + Cell* cell = (*it).second; + delete cell; + } + _cells.clear(); + } - Grid::clear(); + Grid::clear(); } -void HashGrid::configure(const Vec3r& orig, const Vec3r& size, unsigned nb) { - Grid::configure(orig, size, nb); +void HashGrid::configure(const Vec3r& orig, const Vec3r& size, unsigned nb) +{ + Grid::configure(orig, size, nb); } diff --git a/source/blender/freestyle/intern/geometry/HashGrid.h b/source/blender/freestyle/intern/geometry/HashGrid.h index f6605957676..ca6edb258a9 100644 --- a/source/blender/freestyle/intern/geometry/HashGrid.h +++ b/source/blender/freestyle/intern/geometry/HashGrid.h @@ -1,109 +1,116 @@ -// -// Filename : HashGrid.h -// Author(s) : Stephane Grabli -// Purpose : Class to define a cell grid surrounding the -// bounding box of the scene -// Date of creation : 30/07/2002 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __HASHGRID_H__ +#define __HASHGRID_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/HashGrid.h + * \ingroup freestyle + * \brief Class to define a cell grid surrounding the bounding box of the scene + * \author Stephane Grabli + * \date 30/07/2002 + */ -#ifndef HASHGRID_H -# define HASHGRID_H - -//# if defined(__GNUC__) && (__GNUC__ >= 3) +#if 0 +# if defined(__GNUC__) && (__GNUC__ >= 3) // hash_map is not part of the C++ standard anymore; // hash_map.h has been kept though for backward compatibility -//# include -//# else -//# include -//# endif +# include +# else +# include +# endif +#endif + +#include + +#include "Grid.h" -# include "Grid.h" -# include /*! Defines a hash table used for searching the Cells */ -struct GridHasher{ +struct GridHasher +{ #define _MUL 950706376UL #define _MOD 2147483647UL - inline size_t operator() (const Vec3u& p) const - { - size_t res = ((unsigned long) (p[0] * _MUL)) % _MOD; - res = ((res + (unsigned long) (p[1]) * _MUL)) % _MOD; - return ((res +(unsigned long) (p[2]) * _MUL)) % _MOD; - } + inline size_t operator() (const Vec3u& p) const + { + size_t res = ((unsigned long) (p[0] * _MUL)) % _MOD; + res = ((res + (unsigned long) (p[1]) * _MUL)) % _MOD; + return ((res +(unsigned long) (p[2]) * _MUL)) % _MOD; + } +#undef _MUL +#undef _MOD }; -/*! Class to define a regular grid used for ray - casting computations */ - +/*! Class to define a regular grid used for ray casting computations */ class LIB_GEOMETRY_EXPORT HashGrid : public Grid { - public: +public: + typedef map GridHashTable; - typedef map GridHashTable; - - HashGrid() : Grid() {} + HashGrid() : Grid() {} - virtual ~HashGrid() { - clear(); - } + virtual ~HashGrid() + { + clear(); + } - /*! clears the grid - * Deletes all the cells, clears the hashtable, - * resets size, size of cell, number of cells. - */ - virtual void clear(); + /*! clears the grid + * Deletes all the cells, clears the hashtable, resets size, size of cell, number of cells. + */ + virtual void clear(); - /*! Sets the different parameters of the grid - * orig - * The grid origin - * size - * The grid's dimensions - * nb - * The number of cells of the grid - */ - virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb); - - /*! returns the cell whose coordinates - * are pased as argument - */ - virtual Cell* getCell(const Vec3u& p) { - Cell* found_cell = NULL; - - GridHashTable::const_iterator found = _cells.find(p); - if (found != _cells.end()) - found_cell = (*found).second; - return found_cell; - } - - /*! Fills the case p with the cell iCell */ - virtual void fillCell(const Vec3u& p, Cell& cell) { - _cells[p] = &cell; - } + /*! Sets the different parameters of the grid + * orig + * The grid origin + * size + * The grid's dimensions + * nb + * The number of cells of the grid + */ + virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb); + + /*! returns the cell whose coordinates are pased as argument */ + virtual Cell* getCell(const Vec3u& p) + { + Cell* found_cell = NULL; + + GridHashTable::const_iterator found = _cells.find(p); + if (found != _cells.end()) + found_cell = (*found).second; + return found_cell; + } + + /*! Fills the case p with the cell iCell */ + virtual void fillCell(const Vec3u& p, Cell& cell) + { + _cells[p] = &cell; + } protected: - - GridHashTable _cells; + GridHashTable _cells; }; -#endif // HASHGRID_H +#endif // __HASHGRID_H__ diff --git a/source/blender/freestyle/intern/geometry/Noise.cpp b/source/blender/freestyle/intern/geometry/Noise.cpp index ede8c434d9d..0769664fcbb 100644 --- a/source/blender/freestyle/intern/geometry/Noise.cpp +++ b/source/blender/freestyle/intern/geometry/Noise.cpp @@ -1,264 +1,285 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/Noise.cpp + * \ingroup freestyle + * \brief Class to define Perlin noise + * \author Emmanuel Turquin + * \date 12/01/2004 + */ -#include "Noise.h" -# include -# include -# include +#include +#include +#include #include -#define MINX -1000000 -#define MINY MINX -#define MINZ MINX -#define SCURVE(a) ((a)*(a)*(3.0-2.0*(a))) -#define REALSCALE ( 2.0 / 65536.0 ) -#define NREALSCALE ( 2.0 / 4096.0 ) -#define HASH3D(a,b,c) hashTable[hashTable[hashTable[(a) & 0xfff] ^ ((b) & 0xfff)] ^ ((c) & 0xfff)] -#define HASH(a,b,c) (xtab[(xtab[(xtab[(a) & 0xff] ^ (b)) & 0xff] ^ (c)) & 0xff] & 0xff) -#define INCRSUM(m,s,x,y,z) ((s)*(RTable[m]*0.5 \ - + RTable[m+1]*(x) \ - + RTable[m+2]*(y) \ - + RTable[m+3]*(z))) -#define MAXSIZE 500 -#define nrand() ((float)rand()/(float)RAND_MAX) -#define seednrand(x) srand(x*RAND_MAX) +#include "Noise.h" + +#define MINX -1000000 +#define MINY MINX +#define MINZ MINX + +#define SCURVE(a) ((a) * (a) * (3.0 - 2.0 * (a))) + +#define REALSCALE (2.0 / 65536.0) +#define NREALSCALE (2.0 / 4096.0) + +#define HASH3D(a, b, c) hashTable[hashTable[hashTable[(a) & 0xfff] ^ ((b) & 0xfff)] ^ ((c) & 0xfff)] +#define HASH(a, b, c) (xtab[(xtab[(xtab[(a) & 0xff] ^ (b)) & 0xff] ^ (c)) & 0xff] & 0xff) + +#define INCRSUM(m, s, x, y, z) \ + ((s) * (RTable[m] * 0.5 + RTable[m + 1] * (x) + RTable[m + 2] * (y) + RTable[m + 3] * (z))) + +#define MAXSIZE 500 + +#if 0 // XXX Unused +#define NRAND() ((float)rand() / (float)RAND_MAX) +#endif +#define SEEDNRAND(x) (srand(x * RAND_MAX)) #define BM 0xff - -#define N 0x1000 -#define NP 12 /* 2^N */ +#define N 0x1000 +#define NP 12 /* 2^N */ #define NM 0xfff -#define s_curve(t) ( t * t * (3. - 2. * t) ) +#define LERP(t, a, b) ((a) + (t) * ((b) - (a))) -#define lerp(t, a, b) ( a + t * (b - a) ) - -#define setup(i,b0,b1,r0,r1)\ - t = i + N;\ - b0 = ((int)t) & BM;\ - b1 = (b0+1) & BM;\ - r0 = t - (int)t;\ - r1 = r0 - 1.; +#define SETUP(i, b0, b1, r0, r1) \ + { \ + (t) = (i) + (N); \ + (b0) = ((int)(t)) & BM; \ + (b1) = ((b0) + 1) & BM; \ + (r0) = (t) - (int)(t); \ + (r1) = (r0) - 1.0; \ + } (void)0 static void normalize2(float v[2]) { - float s; + float s; - s = sqrt(v[0] * v[0] + v[1] * v[1]); - v[0] = v[0] / s; - v[1] = v[1] / s; + s = sqrt(v[0] * v[0] + v[1] * v[1]); + v[0] = v[0] / s; + v[1] = v[1] / s; } static void normalize3(float v[3]) { - float s; + float s; - s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); - v[0] = v[0] / s; - v[1] = v[1] / s; - v[2] = v[2] / s; + s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + v[0] = v[0] / s; + v[1] = v[1] / s; + v[2] = v[2] / s; } float Noise::turbulence1(float arg, float freq, float amp, unsigned oct) { - float t; - float vec; - - for (t = 0; oct > 0 && freq > 0; freq *= 2, amp /= 2, --oct) - { - vec = freq * arg; - t += smoothNoise1(vec) * amp; - } - return t; + float t; + float vec; + + for (t = 0; oct > 0 && freq > 0; freq *= 2, amp /= 2, --oct) { + vec = freq * arg; + t += smoothNoise1(vec) * amp; + } + return t; } float Noise::turbulence2(Vec2f& v, float freq, float amp, unsigned oct) { - float t; - Vec2f vec; - - for (t = 0; oct > 0 && freq > 0; freq *= 2, amp /= 2, --oct) - { - vec.x() = freq * v.x(); - vec.y() = freq * v.y(); - t += smoothNoise2(vec) * amp; - } - return t; + float t; + Vec2f vec; + + for (t = 0; oct > 0 && freq > 0; freq *= 2, amp /= 2, --oct) { + vec.x() = freq * v.x(); + vec.y() = freq * v.y(); + t += smoothNoise2(vec) * amp; + } + return t; } float Noise::turbulence3(Vec3f& v, float freq, float amp, unsigned oct) { - float t; - Vec3f vec; - - for (t = 0; oct > 0 && freq > 0; freq *= 2, amp /= 2, --oct) - { - vec.x() = freq * v.x(); - vec.y() = freq * v.y(); - vec.z() = freq * v.z(); - t += smoothNoise3(vec) * amp; - } - return t; + float t; + Vec3f vec; + + for (t = 0; oct > 0 && freq > 0; freq *= 2, amp /= 2, --oct) { + vec.x() = freq * v.x(); + vec.y() = freq * v.y(); + vec.z() = freq * v.z(); + t += smoothNoise3(vec) * amp; + } + return t; } // Noise functions over 1, 2, and 3 dimensions - float Noise::smoothNoise1(float arg) { - int bx0, bx1; - float rx0, rx1, sx, t, u, v, vec; + int bx0, bx1; + float rx0, rx1, sx, t, u, v, vec; - vec = arg; - setup(vec, bx0,bx1, rx0,rx1); + vec = arg; + SETUP(vec, bx0, bx1, rx0, rx1); - sx = s_curve(rx0); + sx = SCURVE(rx0); - u = rx0 * g1[ p[ bx0 ] ]; - v = rx1 * g1[ p[ bx1 ] ]; + u = rx0 * g1[p[bx0]]; + v = rx1 * g1[p[bx1]]; - return lerp(sx, u, v); + return LERP(sx, u, v); } float Noise::smoothNoise2(Vec2f& vec) { - int bx0, bx1, by0, by1, b00, b10, b01, b11; - float rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v; - register int i, j; + int bx0, bx1, by0, by1, b00, b10, b01, b11; + float rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v; + register int i, j; - setup(vec.x(), bx0,bx1, rx0,rx1); - setup(vec.y(), by0,by1, ry0,ry1); + SETUP(vec.x(), bx0, bx1, rx0, rx1); + SETUP(vec.y(), by0, by1, ry0, ry1); - i = p[ bx0 ]; - j = p[ bx1 ]; + i = p[bx0]; + j = p[bx1]; - b00 = p[ i + by0 ]; - b10 = p[ j + by0 ]; - b01 = p[ i + by1 ]; - b11 = p[ j + by1 ]; + b00 = p[i + by0]; + b10 = p[j + by0]; + b01 = p[i + by1]; + b11 = p[j + by1]; - sx = s_curve(rx0); - sy = s_curve(ry0); + sx = SCURVE(rx0); + sy = SCURVE(ry0); -#define at2(rx,ry) ( rx * q[0] + ry * q[1] ) +#define AT2(rx, ry) ((rx) * q[0] + (ry) * q[1]) - q = g2[ b00 ] ; u = at2(rx0,ry0); - q = g2[ b10 ] ; v = at2(rx1,ry0); - a = lerp(sx, u, v); + q = g2[b00]; + u = AT2(rx0, ry0); + q = g2[b10]; + v = AT2(rx1, ry0); + a = LERP(sx, u, v); - q = g2[ b01 ] ; u = at2(rx0,ry1); - q = g2[ b11 ] ; v = at2(rx1,ry1); - b = lerp(sx, u, v); + q = g2[b01]; + u = AT2(rx0, ry1); + q = g2[b11]; + v = AT2(rx1, ry1); + b = LERP(sx, u, v); - return lerp(sy, a, b); +#undef AT2 + + return LERP(sy, a, b); } float Noise::smoothNoise3(Vec3f& vec) { - int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; - float rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v; - register int i, j; + int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; + float rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v; + register int i, j; - setup(vec.x(), bx0,bx1, rx0,rx1); - setup(vec.y(), by0,by1, ry0,ry1); - setup(vec.z(), bz0,bz1, rz0,rz1); + SETUP(vec.x(), bx0, bx1, rx0, rx1); + SETUP(vec.y(), by0, by1, ry0, ry1); + SETUP(vec.z(), bz0, bz1, rz0, rz1); - i = p[ bx0 ]; - j = p[ bx1 ]; + i = p[bx0]; + j = p[bx1]; - b00 = p[ i + by0 ]; - b10 = p[ j + by0 ]; - b01 = p[ i + by1 ]; - b11 = p[ j + by1 ]; + b00 = p[i + by0]; + b10 = p[j + by0]; + b01 = p[i + by1]; + b11 = p[j + by1]; - t = s_curve(rx0); - sy = s_curve(ry0); - sz = s_curve(rz0); + t = SCURVE(rx0); + sy = SCURVE(ry0); + sz = SCURVE(rz0); -#define at3(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] ) +#define AT3(rx, ry, rz) ((rx) * q[0] + (ry) * q[1] + (rz) * q[2]) - q = g3[ b00 + bz0 ] ; - u = at3(rx0,ry0,rz0); - q = g3[ b10 + bz0 ] ; - v = at3(rx1,ry0,rz0); - a = lerp(t, u, v); + q = g3[b00 + bz0]; + u = AT3(rx0, ry0, rz0); + q = g3[b10 + bz0]; + v = AT3(rx1, ry0, rz0); + a = LERP(t, u, v); - q = g3[ b01 + bz0 ] ; - u = at3(rx0,ry1,rz0); - q = g3[ b11 + bz0 ] ; - v = at3(rx1,ry1,rz0); - b = lerp(t, u, v); + q = g3[b01 + bz0]; + u = AT3(rx0, ry1, rz0); + q = g3[b11 + bz0]; + v = AT3(rx1, ry1, rz0); + b = LERP(t, u, v); - c = lerp(sy, a, b); + c = LERP(sy, a, b); - q = g3[ b00 + bz1 ] ; - u = at3(rx0,ry0,rz1); - q = g3[ b10 + bz1 ] ; - v = at3(rx1,ry0,rz1); - a = lerp(t, u, v); + q = g3[b00 + bz1]; + u = AT3(rx0, ry0, rz1); + q = g3[b10 + bz1]; + v = AT3(rx1, ry0, rz1); + a = LERP(t, u, v); - q = g3[ b01 + bz1 ] ; - u = at3(rx0,ry1,rz1); - q = g3[ b11 + bz1 ] ; - v = at3(rx1,ry1,rz1); - b = lerp(t, u, v); + q = g3[b01 + bz1]; + u = AT3(rx0, ry1, rz1); + q = g3[b11 + bz1]; + v = AT3(rx1, ry1, rz1); + b = LERP(t, u, v); - d = lerp(sy, a, b); + d = LERP(sy, a, b); - return lerp(sz, c, d); +#undef AT3 + + return LERP(sz, c, d); } Noise::Noise(long seed) { - int i, j, k; - - seednrand((seed < 0) ? time(NULL) : seed); - for (i = 0 ; i < _Noise_B_ ; i++) - { - p[i] = i; + int i, j, k; - g1[i] = (float)((rand() % (_Noise_B_ + _Noise_B_)) - _Noise_B_) / _Noise_B_; + SEEDNRAND((seed < 0) ? time(NULL) : seed); + for (i = 0 ; i < _NOISE_B ; i++) { + p[i] = i; + g1[i] = (float)((rand() % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B; - for (j = 0 ; j < 2 ; j++) - g2[i][j] = (float)((rand() % (_Noise_B_ + _Noise_B_)) - _Noise_B_) / _Noise_B_; - normalize2(g2[i]); + for (j = 0 ; j < 2 ; j++) + g2[i][j] = (float)((rand() % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B; + normalize2(g2[i]); - for (j = 0 ; j < 3 ; j++) - g3[i][j] = (float)((rand() % (_Noise_B_ + _Noise_B_)) - _Noise_B_) / _Noise_B_; - normalize3(g3[i]); - } + for (j = 0 ; j < 3 ; j++) + g3[i][j] = (float)((rand() % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B; + normalize3(g3[i]); + } - while (--i) - { - k = p[i]; - p[i] = p[j = rand() % _Noise_B_]; - p[j] = k; - } + while (--i) { + k = p[i]; + p[i] = p[j = rand() % _NOISE_B]; + p[j] = k; + } - for (i = 0 ; i < _Noise_B_ + 2 ; i++) - { - p[_Noise_B_ + i] = p[i]; - g1[_Noise_B_ + i] = g1[i]; - for (j = 0 ; j < 2 ; j++) - g2[_Noise_B_ + i][j] = g2[i][j]; - for (j = 0 ; j < 3 ; j++) - g3[_Noise_B_ + i][j] = g3[i][j]; - } + for (i = 0 ; i < _NOISE_B + 2 ; i++) { + p[_NOISE_B + i] = p[i]; + g1[_NOISE_B + i] = g1[i]; + + for (j = 0 ; j < 2 ; j++) + g2[_NOISE_B + i][j] = g2[i][j]; + + for (j = 0 ; j < 3 ; j++) + g3[_NOISE_B + i][j] = g3[i][j]; + } } diff --git a/source/blender/freestyle/intern/geometry/Noise.h b/source/blender/freestyle/intern/geometry/Noise.h index f92cf07e914..35d1af3712f 100644 --- a/source/blender/freestyle/intern/geometry/Noise.h +++ b/source/blender/freestyle/intern/geometry/Noise.h @@ -1,40 +1,45 @@ -// -// Filename : Noise.h -// Author(s) : Emmanuel Turquin -// Purpose : Class to define Perlin noise -// Date of creation : 12/01/2004 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __NOISE_H__ +#define __NOISE_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/Noise.h + * \ingroup freestyle + * \brief Class to define Perlin noise + * \author Emmanuel Turquin + * \date 12/01/2004 + */ -#ifndef NOISE_H -# define NOISE_H +#include "Geom.h" +#include "../system/FreestyleConfig.h" -# include "../system/FreestyleConfig.h" -# include "Geom.h" - -#define _Noise_B_ 0x100 +#define _NOISE_B 0x100 using namespace Geometry; using namespace std; @@ -42,36 +47,37 @@ using namespace std; /*! Class to provide Perlin Noise functionalities */ class LIB_GEOMETRY_EXPORT Noise { - public: +public: + /*! Builds a Noise object */ + Noise(long seed = -1); - /*! Builds a Noise object */ - Noise(long seed = -1); - /*! Destructor */ - ~Noise() {} + /*! Destructor */ + ~Noise() {} - /*! Returns a noise value for a 1D element */ - float turbulence1(float arg, float freq, float amp, unsigned oct = 4); + /*! Returns a noise value for a 1D element */ + float turbulence1(float arg, float freq, float amp, unsigned oct = 4); - /*! Returns a noise value for a 2D element */ - float turbulence2(Vec2f& v, float freq, float amp, unsigned oct = 4); + /*! Returns a noise value for a 2D element */ + float turbulence2(Vec2f& v, float freq, float amp, unsigned oct = 4); - /*! Returns a noise value for a 3D element */ - float turbulence3(Vec3f& v, float freq, float amp, unsigned oct = 4); + /*! Returns a noise value for a 3D element */ + float turbulence3(Vec3f& v, float freq, float amp, unsigned oct = 4); - /*! Returns a smooth noise value for a 1D element */ - float smoothNoise1(float arg); - /*! Returns a smooth noise value for a 2D element */ - float smoothNoise2(Vec2f& vec); - /*! Returns a smooth noise value for a 3D element */ - float smoothNoise3(Vec3f& vec); + /*! Returns a smooth noise value for a 1D element */ + float smoothNoise1(float arg); - private: + /*! Returns a smooth noise value for a 2D element */ + float smoothNoise2(Vec2f& vec); - int p[ _Noise_B_ + _Noise_B_ + 2]; - float g3[ _Noise_B_ + _Noise_B_ + 2][3]; - float g2[ _Noise_B_ + _Noise_B_ + 2][2]; - float g1[ _Noise_B_ + _Noise_B_ + 2]; - int start; + /*! Returns a smooth noise value for a 3D element */ + float smoothNoise3(Vec3f& vec); + +private: + int p[_NOISE_B + _NOISE_B + 2]; + float g3[_NOISE_B + _NOISE_B + 2][3]; + float g2[_NOISE_B + _NOISE_B + 2][2]; + float g1[_NOISE_B + _NOISE_B + 2]; + int start; }; -#endif // NOISE_H +#endif // __NOISE_H__ diff --git a/source/blender/freestyle/intern/geometry/Polygon.h b/source/blender/freestyle/intern/geometry/Polygon.h index 911804d80f7..5ee4353ef5a 100644 --- a/source/blender/freestyle/intern/geometry/Polygon.h +++ b/source/blender/freestyle/intern/geometry/Polygon.h @@ -1,38 +1,44 @@ -// -// Filename : Polygon.h -// Author(s) : Stephane Grabli -// Purpose : Class to define a polygon -// Date of creation : 30/07/2002 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __POLYGON_H__ +#define __POLYGON_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/Polygon.h + * \ingroup freestyle + * \brief Class to define a polygon + * \author Stephane Grabli + * \date 30/07/2002 + */ -#ifndef POLYGON_H -# define POLYGON_H +#include -# include -# include "Geom.h" -# include "GeomUtils.h" +#include "Geom.h" +#include "GeomUtils.h" using namespace std; @@ -41,129 +47,129 @@ namespace Geometry { template class Polygon { - public: +public: + inline Polygon() + { + _id = 0; + userdata = 0; + userdata2 = 0; + } - inline Polygon() { - _id = 0; - userdata = 0; - userdata2 = 0; - } + inline Polygon(const vector& vertices) + { + _vertices = vertices; + computeBBox(); + _id = 0; + userdata = 0; + userdata2 = 0; + } - inline Polygon(const vector& vertices) { - _vertices = vertices; - computeBBox(); - _id = 0; - userdata = 0; - userdata2 = 0; - } + inline Polygon(const Polygon& poly) + { + Point p; + for (typename vector::const_iterator it = poly.getVertices().begin(); + it != poly.getVertices().end(); + it++) + { + p = *it; + _vertices.push_back(p); + } - inline Polygon(const Polygon& poly) { - Point p; - for(typename vector::const_iterator it = poly.getVertices().begin(); - it != poly.getVertices().end(); - it++) { - p = *it; - _vertices.push_back(p); - } + _id = poly.getId(); + poly.getBBox(_min, _max); + userdata = 0; + userdata2 = 0; + } - _id = poly.getId(); - poly.getBBox(_min, _max); - userdata = 0; - userdata2 = 0; - } - - virtual ~Polygon() {} + virtual ~Polygon() {} - // - // Accessors - // - ///////////////////////////////////////////////////////////////////////////// + // + // Accessors + // + ///////////////////////////////////////////////////////////////////////////// + inline const vector& getVertices() const + { + return _vertices; + } - inline const vector& getVertices() const { - return _vertices; - } + inline void getBBox(Point& min, Point& max) const + { + min = _min; + max = _max; + } - inline void getBBox(Point& min, Point& max) const { - min = _min; - max = _max; - } + inline Point& getBBoxCenter() + { + Point result; + result = (_min + _max) / 2; + return result; + } - inline Point& getBBoxCenter() - { - Point result; - result = (_min + _max) / 2; - return result; - } + inline Point& getCenter() + { + Point result; + for (typename vector::iterator it = _vertices.begin(); it != _vertices.end(); it++) + result += *it; + result /= _vertices.size(); + return result; + } - inline Point& getCenter() { - Point result; - for (typename vector::iterator it = _vertices.begin(); - it != _vertices.end(); - it++) - result += *it; - result /= _vertices.size(); - return result; - } + inline unsigned getId() const + { + return _id; + } - inline unsigned getId() const { - return _id; - } + // + // Modifiers + // + ///////////////////////////////////////////////////////////////////////////// + inline void setVertices(const vector& vertices) + { + _vertices.clear(); + Point p; + for (typename vector::const_iterator it = vertices.begin(); it != vertices.end(); it++) { + p = *it; + _vertices.push_back(p); + } + computeBBox(); + } - // - // Modifiers - // - ///////////////////////////////////////////////////////////////////////////// + inline void setId(unsigned id) + { + _id = id; + } - inline void setVertices(const vector& vertices) { - _vertices.clear(); - Point p; - for (typename vector::const_iterator it = vertices.begin(); - it != vertices.end(); - it++) { - p = *it; - _vertices.push_back(p); - } - computeBBox(); - } + // + // Other methods + // + ///////////////////////////////////////////////////////////////////////////// + inline void computeBBox() + { + if (_vertices.empty()) + return; - inline void setId(unsigned id) { - _id = id; - } + _max = _vertices[0]; + _min = _vertices[0]; - // - // Other methods - // - ///////////////////////////////////////////////////////////////////////////// + for (typename vector::iterator it = _vertices.begin(); it != _vertices.end(); it++) { + for (unsigned int i = 0; i < Point::dim(); i++) { + if ((*it)[i] > _max[i]) + _max[i] = (*it)[i]; + if ((*it)[i] < _min[i]) + _min[i] = (*it)[i]; + } + } + } - inline void computeBBox() { - if(_vertices.empty()) - return; - - _max = _vertices[0]; - _min = _vertices[0]; + // FIXME Is it possible to get rid of userdatas ? + void* userdata; + void* userdata2; // Used during ray casting - for(typename vector::iterator it = _vertices.begin(); - it != _vertices.end(); - it++) { - for(unsigned i = 0; i < Point::dim(); i++) { - if((*it)[i] > _max[i]) - _max[i] = (*it)[i]; - if((*it)[i] < _min[i]) - _min[i] = (*it)[i]; - } - } - } - - // FIXME Is it possible to get rid of userdatas ? - void* userdata; - void* userdata2; // Used during ray casting - - protected: - - vector _vertices; - Point _min; - Point _max; - unsigned _id; +protected: + vector _vertices; + Point _min; + Point _max; + unsigned _id; }; @@ -171,44 +177,45 @@ class Polygon // Polygon3r class // /////////////////////////////////////////////////////////////////////////////// - class Polygon3r : public Polygon { - public: - inline Polygon3r() : Polygon() {} +public: + inline Polygon3r() : Polygon() {} - inline Polygon3r(const vector& vertices, - const Vec3r& normal) : Polygon(vertices) { - setNormal(normal); - } + inline Polygon3r(const vector& vertices, const Vec3r& normal) : Polygon(vertices) + { + setNormal(normal); + } - inline Polygon3r(const Polygon3r& poly) : Polygon(poly), _normal(poly._normal) {} - - virtual ~Polygon3r() {} + inline Polygon3r(const Polygon3r& poly) : Polygon(poly), _normal(poly._normal) {} - void setNormal(const Vec3r& normal) { - _normal = normal; - } + virtual ~Polygon3r() {} - inline Vec3r getNormal() const { - return _normal; - } + void setNormal(const Vec3r& normal) + { + _normal = normal; + } - /*! Check whether the Polygon intersects with the ray or not */ - inline bool rayIntersect(const Vec3r& orig, const Vec3r& dir, - real& t, real& u, real& v, real epsilon = M_EPSILON) const { - // if (_vertices.size() < 3) - // return false; - return GeomUtils::intersectRayTriangle(orig, dir, - _vertices[0], _vertices[1], _vertices[2], - t, u, v, epsilon); - } + inline Vec3r getNormal() const + { + return _normal; + } - private: + /*! Check whether the Polygon intersects with the ray or not */ + inline bool rayIntersect(const Vec3r& orig, const Vec3r& dir, real& t, real& u, real& v, + real epsilon = M_EPSILON) const + { +#if 0 + if (_vertices.size() < 3) + return false; +#endif + return GeomUtils::intersectRayTriangle(orig, dir, _vertices[0], _vertices[1], _vertices[2], t, u, v, epsilon); + } - Vec3r _normal; +private: + Vec3r _normal; }; } // end of namespace Geometry -#endif // POLYGON_H +#endif // __POLYGON_H__ diff --git a/source/blender/freestyle/intern/geometry/SweepLine.h b/source/blender/freestyle/intern/geometry/SweepLine.h index deecf3c5485..df73df155c4 100644 --- a/source/blender/freestyle/intern/geometry/SweepLine.h +++ b/source/blender/freestyle/intern/geometry/SweepLine.h @@ -1,198 +1,202 @@ -// -// Filename : SweepLine.h -// Author(s) : Stephane Grabli -// Purpose : Class to define a Sweep Line -// Date of creation : 29/08/2002 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __SWEEPLINE_H__ +#define __SWEEPLINE_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/SweepLine.h + * \ingroup freestyle + * \brief Class to define a Sweep Line + * \author Stephane Grabli + * \date 29/08/2002 + */ -#ifndef SWEEPLINE_H -# define SWEEPLINE_H - -# include -# include +#include +#include /*! Class to define the intersection berween two segments*/ template class Intersection { public: + template + Intersection(EdgeClass* eA, real ta, EdgeClass* eB, real tb) + { + EdgeA = eA; + EdgeB = eB; + tA = ta; + tB = tb; + userdata = 0; + } - template - Intersection(EdgeClass* eA, real ta, EdgeClass* eB, real tb) - { - EdgeA = eA; - EdgeB = eB; - tA = ta; - tB = tb; - userdata = 0; - } + Intersection(const Intersection& iBrother) + { + EdgeA = iBrother.EdgeA; + EdgeB = iBrother.EdgeB; + tA = iBrother.tA; + tB = iBrother.tB; + userdata = 0; + } - Intersection(const Intersection& iBrother) - { - EdgeA = iBrother.EdgeA; - EdgeB = iBrother.EdgeB; - tA = iBrother.tA; - tB = iBrother.tB; - userdata = 0; - } - - /*! returns the parameter giving the - * intersection, for the edge iEdge - */ - real getParameter(Edge *iEdge) - { - if(iEdge == EdgeA) - return tA; - if(iEdge == EdgeB) - return tB; - return 0; - } + /*! returns the parameter giving the intersection, for the edge iEdge */ + real getParameter(Edge *iEdge) + { + if (iEdge == EdgeA) + return tA; + if (iEdge == EdgeB) + return tB; + return 0; + } public: - void * userdata; // FIXME + void * userdata; // FIXME - Edge *EdgeA; // first segment - Edge *EdgeB; // second segment - real tA; // parameter defining the intersection point with respect to the segment EdgeA. - real tB; // parameter defining the intersection point with respect to the segment EdgeB. + Edge *EdgeA; // first segment + Edge *EdgeB; // second segment + real tA; // parameter defining the intersection point with respect to the segment EdgeA. + real tB; // parameter defining the intersection point with respect to the segment EdgeB. }; - - - - - - template class Segment { - public: - Segment() - { - } - Segment(T& s, const Point& iA, const Point& iB) - { - _edge = s; - if(iA < iB) - { - A = iA; - B = iB; - _order = true; - } - else - { - A = iB; - B = iA; - _order = false; - } - } +public: + Segment() + { + } - Segment(Segment& iBrother) - { - _edge = iBrother.edge(); - A = iBrother.A; - B = iBrother.B; - _Intersections = iBrother._Intersections; - _order = iBrother._order; - } + Segment(T& s, const Point& iA, const Point& iB) + { + _edge = s; + if (iA < iB) { + A = iA; + B = iB; + _order = true; + } + else { + A = iB; + B = iA; + _order = false; + } + } - Segment(const Segment& iBrother) - { - _edge = iBrother._edge; - A = iBrother.A; - B = iBrother.B; - _Intersections = iBrother._Intersections; - _order = iBrother._order; - } + Segment(Segment& iBrother) + { + _edge = iBrother.edge(); + A = iBrother.A; + B = iBrother.B; + _Intersections = iBrother._Intersections; + _order = iBrother._order; + } - ~Segment() { - _Intersections.clear(); - } + Segment(const Segment& iBrother) + { + _edge = iBrother._edge; + A = iBrother.A; + B = iBrother.B; + _Intersections = iBrother._Intersections; + _order = iBrother._order; + } - inline Point operator[](const unsigned short int& i) const - { - return i%2==0 ? A : B; - } + ~Segment() + { + _Intersections.clear(); + } - inline bool operator==(const Segment& iBrother) - { - if(_edge == iBrother._edge) - return true; + inline Point operator[](const unsigned short int& i) const + { + return (i % 2 == 0) ? A : B; + } - return false; - } - - /* Adds an intersection for this segment */ - inline void AddIntersection(Intersection > *i) {_Intersections.push_back(i);} + inline bool operator==(const Segment& iBrother) + { + if (_edge == iBrother._edge) + return true; + return false; + } - /*! Checks for a common vertex with another edge */ - inline bool CommonVertex(const Segment& S, Point& CP) - { - if((A == S[0]) || (A == S[1])) - { - CP = A; - return true; - } - if((B == S[0]) || (B == S[1])) - { - CP = B; - return true; - } + /* Adds an intersection for this segment */ + inline void AddIntersection(Intersection > *i) + { + _Intersections.push_back(i); + } - return false; - } + /*! Checks for a common vertex with another edge */ + inline bool CommonVertex(const Segment& S, Point& CP) + { + if ((A == S[0]) || (A == S[1])) { + CP = A; + return true; + } + if ((B == S[0]) || (B == S[1])) { + CP = B; + return true; + } + return false; + } - inline vector >*>& intersections() {return _Intersections;} - inline bool order() {return _order;} - inline T& edge() {return _edge;} + inline vector >*>& intersections() + { + return _Intersections; + } - private: - T _edge; - Point A; - Point B; - std::vector >*> _Intersections; // list of intersections parameters - bool _order; // true if A and B are in the same order than _edge.A and _edge.B. false otherwise. + inline bool order() + { + return _order; + } + + inline T& edge() + { + return _edge; + } + +private: + T _edge; + Point A; + Point B; + std::vector >*> _Intersections; // list of intersections parameters + bool _order; // true if A and B are in the same order than _edge.A and _edge.B. false otherwise. }; -/*! defines a binary function that can be overload - * by the user to specify at each condition - * the intersection between 2 edges must be computed +/*! defines a binary function that can be overload by the user to specify at each condition the intersection + * between 2 edges must be computed */ template -struct binary_rule +struct binary_rule { - binary_rule() {} - template - binary_rule(const binary_rule& brother) {} - virtual ~binary_rule() {} + binary_rule() {} + template binary_rule(const binary_rule& brother) {} + virtual ~binary_rule() {} - virtual bool operator()(T1&, T2&) - { - return true; - } + virtual bool operator()(T1&, T2&) + { + return true; + } }; @@ -200,126 +204,121 @@ template class SweepLine { public: + SweepLine() {} + ~SweepLine() + { + for (typename vector >*>::iterator i = _Intersections.begin(), + iend = _Intersections.end(); + i != iend; + i++) + { + delete (*i); + } + } - SweepLine() {} - ~SweepLine() - { - for(typename vector >*>::iterator i=_Intersections.begin(),iend=_Intersections.end(); - i!=iend; - i++) - { - delete (*i); - } - } + inline void process(Point& p, vector*>& segments, +#if 0 + binary_rule,Segment >& binrule = \ + binary_rule,Segment >(), +#else + binary_rule,Segment >& binrule, +#endif + real epsilon = M_EPSILON) + { + // first we remove the segments that need to be removed and then we add the segments to add + vector*> toadd; + typename vector*>::iterator s, send; + for (s = segments.begin(), send = segments.end(); s != send; s++) { + if (p == (*(*s))[0]) + toadd.push_back((*s)); + else + remove((*s)); + } + for (s = toadd.begin(), send = toadd.end(); s != send; s++) { + add((*s), binrule, epsilon); + } + } - - inline void process(Point& p, - vector*>& segments, - binary_rule,Segment >& binrule, - //binary_rule,Segment >& binrule = binary_rule,Segment >(), - real epsilon = M_EPSILON - ) - { - // first we remove the segments that need to be removed and then - // we add the segments to add - vector*> toadd; - typename vector*>::iterator s, send; - for(s=segments.begin(), send=segments.end(); - s!=send; - s++) - { - if(p == (*(*s))[0]) - toadd.push_back((*s)); - else - remove((*s)); - } - for(s=toadd.begin(), send=toadd.end(); - s!=send; - s++) - { - add((*s), binrule, epsilon); - } - } - - inline void add(Segment* S, - binary_rule,Segment >& binrule, - //binary_rule,Segment >& binrule = binary_rule, Segment >(), - real epsilon - ) - { - real t,u; - Point CP; - Vec2r v0, v1, v2, v3; - if(true == S->order()) - { - v0[0] = ((*S)[0])[0]; - v0[1] = ((*S)[0])[1]; - v1[0] = ((*S)[1])[0]; - v1[1] = ((*S)[1])[1]; - } - else - { - v1[0] = ((*S)[0])[0]; - v1[1] = ((*S)[0])[1]; - v0[0] = ((*S)[1])[0]; - v0[1] = ((*S)[1])[1]; - } - for(typename std::list* >::iterator s=_set.begin(), send=_set.end(); - s!=send; - s++) - { - Segment* currentS = (*s); - if(true != binrule(*S, *currentS)) - continue; + inline void add(Segment* S, +#if 0 + binary_rule,Segment >& binrule = \ + binary_rule, Segment >(), +#else + binary_rule,Segment >& binrule, +#endif + real epsilon) + { + real t,u; + Point CP; + Vec2r v0, v1, v2, v3; + if (true == S->order()) { + v0[0] = ((*S)[0])[0]; + v0[1] = ((*S)[0])[1]; + v1[0] = ((*S)[1])[0]; + v1[1] = ((*S)[1])[1]; + } + else { + v1[0] = ((*S)[0])[0]; + v1[1] = ((*S)[0])[1]; + v0[0] = ((*S)[1])[0]; + v0[1] = ((*S)[1])[1]; + } + for (typename std::list* >::iterator s = _set.begin(), send = _set.end(); s != send; s++) { + Segment* currentS = (*s); + if (true != binrule(*S, *currentS)) + continue; - if(true == currentS->order()) - { - v2[0] = ((*currentS)[0])[0]; - v2[1] = ((*currentS)[0])[1]; - v3[0] = ((*currentS)[1])[0]; - v3[1] = ((*currentS)[1])[1]; - } - else - { - v3[0] = ((*currentS)[0])[0]; - v3[1] = ((*currentS)[0])[1]; - v2[0] = ((*currentS)[1])[0]; - v2[1] = ((*currentS)[1])[1]; - } - if(S->CommonVertex(*currentS, CP)) - continue; // the two edges have a common vertex->no need to check - - if(GeomUtils::intersect2dSeg2dSegParametric(v0, v1, v2, v3, t, u, epsilon) == GeomUtils::DO_INTERSECT) - { - // create the intersection - Intersection > * inter = new Intersection >(S,t,currentS,u); - // add it to the intersections list - _Intersections.push_back(inter); - // add this intersection to the first edge intersections list - S->AddIntersection(inter); - // add this intersection to the second edge intersections list - currentS->AddIntersection(inter); - } - } - // add the added segment to the list of active segments - _set.push_back(S); - } - - inline void remove(Segment* s) - { - if(s->intersections().size() > 0) - _IntersectedEdges.push_back(s); - _set.remove(s); - } + if (true == currentS->order()) { + v2[0] = ((*currentS)[0])[0]; + v2[1] = ((*currentS)[0])[1]; + v3[0] = ((*currentS)[1])[0]; + v3[1] = ((*currentS)[1])[1]; + } + else { + v3[0] = ((*currentS)[0])[0]; + v3[1] = ((*currentS)[0])[1]; + v2[0] = ((*currentS)[1])[0]; + v2[1] = ((*currentS)[1])[1]; + } + if (S->CommonVertex(*currentS, CP)) + continue; // the two edges have a common vertex->no need to check - vector* >& intersectedEdges() {return _IntersectedEdges;} - vector >*>& intersections() {return _Intersections;} - + if (GeomUtils::intersect2dSeg2dSegParametric(v0, v1, v2, v3, t, u, epsilon) == GeomUtils::DO_INTERSECT) { + // create the intersection + Intersection > *inter = new Intersection >(S,t,currentS,u); + // add it to the intersections list + _Intersections.push_back(inter); + // add this intersection to the first edge intersections list + S->AddIntersection(inter); + // add this intersection to the second edge intersections list + currentS->AddIntersection(inter); + } + } + // add the added segment to the list of active segments + _set.push_back(S); + } + + inline void remove(Segment* s) + { + if (s->intersections().size() > 0) + _IntersectedEdges.push_back(s); + _set.remove(s); + } + + vector* >& intersectedEdges() + { + return _IntersectedEdges; + } + + vector >*>& intersections() + { + return _Intersections; + } private: - std::list* > _set; // set of active edges for a given position of the sweep line - std::vector* > _IntersectedEdges; // the list of intersected edges - std::vector >*> _Intersections; // the list of all intersections. + std::list* > _set; // set of active edges for a given position of the sweep line + std::vector* > _IntersectedEdges; // the list of intersected edges + std::vector >*> _Intersections; // the list of all intersections. }; -#endif // SWEEPLINE_H +#endif // __SWEEPLINE_H__ diff --git a/source/blender/freestyle/intern/geometry/VecMat.h b/source/blender/freestyle/intern/geometry/VecMat.h index 9bbec3b1349..5b64a6e4502 100644 --- a/source/blender/freestyle/intern/geometry/VecMat.h +++ b/source/blender/freestyle/intern/geometry/VecMat.h @@ -1,899 +1,976 @@ -// -// Filename : VecMat.h -// Author(s) : Sylvain Paris -// Emmanuel Turquin -// Stephane Grabli -// Purpose : Vectors and Matrices definition and manipulation -// Date of creation : 12/06/2003 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __VECMAT_H__ +#define __VECMAT_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/geometry/VecMat.h + * \ingroup freestyle + * \brief Vectors and Matrices definition and manipulation + * \author Sylvain Paris + * \author Emmanuel Turquin + * \author Stephane Grabli + * \date 12/06/2003 + */ -#ifndef VECMAT_H -# define VECMAT_H - -# include -# include -# include +#include +#include +#include namespace VecMat { - namespace Internal { - - template - struct is_false {}; - - template <> - struct is_false { - static inline void ensure() {} - }; - - } // end of namespace Internal - - // - // Vector class - // - T: value type - // - N: dimension - // - ///////////////////////////////////////////////////////////////////////////// - - template - class Vec - { - public: - - typedef T value_type; - - // constructors - - inline Vec() { - for (unsigned i = 0; i < N; i++) - this->_coord[i] = 0; - } - - ~Vec() { - Internal::is_false<(N == 0)>::ensure(); - } - - template - explicit inline Vec(const U tab[N]) { - for (unsigned i = 0; i < N; i++) - this->_coord[i] = (T)tab[i]; - } - - template - explicit inline Vec(const std::vector& tab) { - for (unsigned i = 0; i < N; i++) - this->_coord[i] = (T)tab[i]; - } - - template - explicit inline Vec(const Vec& v) { - for (unsigned i = 0; i < N; i++) - this->_coord[i] = (T)v[i]; - } - - // accessors - - inline value_type operator[](const unsigned i) const { - return this->_coord[i]; - } - - inline value_type& operator[](const unsigned i) { - return this->_coord[i]; - } - - static inline unsigned dim() { - return N; - } - - // various useful methods - - inline value_type norm() const { - return (T)sqrt((float)squareNorm()); - } - - inline value_type squareNorm() const { - return (*this) * (*this); - } - - inline Vec& normalize() { - value_type n = norm(); - for (unsigned i = 0; i < N; i++) - this->_coord[i] /= n; - return *this; - } - - inline Vec& normalizeSafe() { - value_type n = norm(); - if (n) - for (unsigned i=0; i < N; i++) - this->_coord[i] /= n; - return *this; - } - - // classical operators - inline Vec operator+(const Vec& v) const{ - Vec res(v); - res += *this; - return res; - } - - inline Vec operator-(const Vec& v) const{ - Vec res(*this); - res -= v; - return res; - } - - inline Vec operator*(const typename Vec::value_type r) const{ - Vec res(*this); - res *= r; - return res; - } - - inline Vec operator/(const typename Vec::value_type r) const{ - Vec res(*this); - if (r) - res /= r; - return res; - } - - // dot product - inline value_type operator*(const Vec& v) const{ - value_type sum = 0; - for (unsigned i = 0; i < N; i++) - sum += (*this)[i] * v[i]; - return sum; - } - - template - inline Vec& operator=(const Vec& v) { - if (this != &v) - for (unsigned i = 0; i < N; i++) - this->_coord[i] = (T)v[i]; - return *this; - } - - template - inline Vec& operator+=(const Vec& v) { - for (unsigned i = 0 ; i < N; i++) - this->_coord[i] += (T)v[i]; - return *this; - } - - template - inline Vec& operator-=(const Vec& v) { - for (unsigned i = 0 ; i < N; i++) - this->_coord[i] -= (T)v[i]; - return *this; - } - - template - inline Vec& operator*=(const U r) { - for (unsigned i = 0 ; i < N; i++) - this->_coord[i] *= r; - return *this; - } - - template - inline Vec& operator/=(const U r) { - if (r) - for (unsigned i = 0 ; i < N; i++) - this->_coord[i] /= r; - return *this; - } - - - inline bool operator==(const Vec& v) const { - for(unsigned i = 0; i < N; i++) - if (this->_coord[i] != v[i]) - return false; - return true; - } - - inline bool operator!=(const Vec& v) const { - for(unsigned i = 0; i < N; i++) - if (this->_coord[i] != v[i]) - return true; - return false; - } - - inline bool operator<(const Vec& v) const { - for (unsigned i = 0; i_coord[i] < v[i]) - return true; - if (this->_coord[i] > v[i]) - return false; - if (this->_coord[i] == v[i]) - continue; - } - return false; - } - - inline bool operator>(const Vec& v) const { - for (unsigned i=0; i_coord[i] > v[i]) - return true; - if(this->_coord[i] < v[i]) - return false; - if(this->_coord[i] == v[i]) - continue; - } - return false; - } - - protected: - - value_type _coord[N]; - enum { - _dim = N, - }; - }; - - - // - // Vec2 class (2D Vector) - // - T: value type - // - ///////////////////////////////////////////////////////////////////////////// - - template - class Vec2 : public Vec - { - public: - - typedef typename Vec::value_type value_type; - - inline Vec2() : Vec() {} - - template - explicit inline Vec2(const U tab[2]) : Vec(tab) {} - - template - explicit inline Vec2(const std::vector& tab) : Vec(tab) {} - - template - inline Vec2(const Vec& v) : Vec(v) {} - - inline Vec2(const value_type x, - const value_type y = 0) : Vec() { - this->_coord[0] = (T)x; - this->_coord[1] = (T)y; - } - - inline value_type x() const { - return this->_coord[0]; - } - - inline value_type& x() { - return this->_coord[0]; - } - - inline value_type y() const { - return this->_coord[1]; - } - - inline value_type& y() { - return this->_coord[1]; - } - - inline void setX(const value_type v) { - this->_coord[0] = v; - } - - inline void setY(const value_type v) { - this->_coord[1] = v; - } - - // FIXME: hack swig -- no choice - inline Vec2 operator+(const Vec2& v) const{ - Vec2 res(v); - res += *this; - return res; - } - - inline Vec2 operator-(const Vec2& v) const{ - Vec2 res(*this); - res -= v; - return res; - } - - inline Vec2 operator*(const value_type r) const{ - Vec2 res(*this); - res *= r; - return res; - } - - inline Vec2 operator/(const value_type r) const{ - Vec2 res(*this); - if (r) - res /= r; - return res; - } - - // dot product - inline value_type operator*(const Vec2& v) const{ - value_type sum = 0; - for (unsigned i = 0; i < 2; i++) - sum += (*this)[i] * v[i]; - return sum; - } - }; - - - // - // HVec3 class (3D Vector in homogeneous coordinates) - // - T: value type - // - ///////////////////////////////////////////////////////////////////////////// - - template - class HVec3 : public Vec - { - public: - - typedef typename Vec::value_type value_type; - - inline HVec3() : Vec() {} - - template - explicit inline HVec3(const U tab[4]) : Vec(tab) {} - - template - explicit inline HVec3(const std::vector& tab) : Vec(tab) {} - - template - inline HVec3(const Vec& v) : Vec(v) {} - - inline HVec3(const value_type sx, - const value_type sy = 0, - const value_type sz = 0, - const value_type s = 1) { - this->_coord[0] = sx; - this->_coord[1] = sy; - this->_coord[2] = sz; - this->_coord[3] = s; - } - - template - inline HVec3(const Vec& sv, - const U s = 1) { - this->_coord[0] = (T)sv[0]; - this->_coord[1] = (T)sv[1]; - this->_coord[2] = (T)sv[2]; - this->_coord[3] = (T)s; - } - - inline value_type sx() const { - return this->_coord[0]; - } - - inline value_type& sx() { - return this->_coord[0]; - } - - inline value_type sy() const { - return this->_coord[1]; - } - - inline value_type& sy() { - return this->_coord[1]; - } - - inline value_type sz() const { - return this->_coord[2]; - } - - inline value_type& sz() { - return this->_coord[2]; - } - - inline value_type s() const { - return this->_coord[3]; - } - - inline value_type& s() { - return this->_coord[3]; - } - - // Acces to non-homogeneous coordinates in 3D - - inline value_type x() const { - return this->_coord[0] / this->_coord[3]; - } - - inline value_type y() const { - return this->_coord[1] / this->_coord[3]; - } - - inline value_type z() const { - return this->_coord[2] / this->_coord[3]; - } - }; - - - // - // Vec3 class (3D Vec) - // - T: value type - // - ///////////////////////////////////////////////////////////////////////////// - - template - class Vec3 : public Vec - { - public: - - typedef typename Vec::value_type value_type; - - inline Vec3() : Vec() {} - - template - explicit inline Vec3(const U tab[3]) : Vec(tab) {} - - template - explicit inline Vec3(const std::vector& tab) : Vec(tab) {} - - template - inline Vec3(const Vec& v) : Vec(v) {} - - template - inline Vec3(const HVec3& v) { - this->_coord[0] = (T)v.x(); - this->_coord[1] = (T)v.y(); - this->_coord[2] = (T)v.z(); - } - - inline Vec3(const value_type x, - const value_type y = 0, - const value_type z = 0) : Vec() { - this->_coord[0] = x; - this->_coord[1] = y; - this->_coord[2] = z; - } - - inline value_type x() const { - return this->_coord[0]; - } - - inline value_type& x() { - return this->_coord[0]; - } - - inline value_type y() const { - return this->_coord[1]; - } - - inline value_type& y() { - return this->_coord[1]; - } - - inline value_type z() const { - return this->_coord[2]; - } - - inline value_type& z() { - return this->_coord[2]; - } - - inline void setX(const value_type v) { - this->_coord[0] = v; - } - - inline void setY(const value_type v) { - this->_coord[1] = v; - } - - inline void setZ(const value_type v) { - this->_coord[2] = v; - } - - // classical operators - // FIXME: hack swig -- no choice - inline Vec3 operator+(const Vec3& v) const{ - Vec3 res(v); - res += *this; - return res; - } - - inline Vec3 operator-(const Vec3& v) const{ - Vec3 res(*this); - res -= v; - return res; - } - - inline Vec3 operator*(const value_type r) const{ - Vec3 res(*this); - res *= r; - return res; - } - - inline Vec3 operator/(const value_type r) const{ - Vec3 res(*this); - if (r) - res /= r; - return res; - } - - // dot product - inline value_type operator*(const Vec3& v) const{ - value_type sum = 0; - for (unsigned i = 0; i < 3; i++) - sum += (*this)[i] * v[i]; - return sum; - } - - // cross product for 3D Vectors - // FIXME: hack swig -- no choice - inline Vec3 operator^(const Vec3& v) const{ - Vec3 res((*this)[1] * v[2] - (*this)[2] * v[1], - (*this)[2] * v[0] - (*this)[0] * v[2], - (*this)[0] * v[1] - (*this)[1] * v[0]); - return res; - } - - // cross product for 3D Vectors - template - inline Vec3 operator^(const Vec& v) const{ - Vec3 res((*this)[1] * v[2] - (*this)[2] * v[1], - (*this)[2] * v[0] - (*this)[0] * v[2], - (*this)[0] * v[1] - (*this)[1] * v[0]); - return res; - } - }; - - - // - // Matrix class - // - T: value type - // - M: rows - // - N: cols - // - ///////////////////////////////////////////////////////////////////////////// - - // Dirty, but icc under Windows needs this -# define _SIZE (M * N) - - template - class Matrix - { - public: - - typedef T value_type; - - inline Matrix() { - for (unsigned i = 0; i < _SIZE; i++) - this->_coord[i] = 0; - } - - ~Matrix() { - Internal::is_false<(M == 0)>::ensure(); - Internal::is_false<(N == 0)>::ensure(); - } - - template - explicit inline Matrix(const U tab[_SIZE]) { - for (unsigned i = 0; i < _SIZE; i++) - this->_coord[i] = tab[i]; - } - - template - explicit inline Matrix(const std::vector& tab) { - for (unsigned i = 0; i < _SIZE; i++) - this->_coord[i] = tab[i]; - } - - template - inline Matrix(const Matrix& m) { - for (unsigned i = 0; i < M; i++) - for (unsigned j = 0; j < N; j++) - this->_coord[i * N + j] = (T)m(i, j); - } - - inline value_type operator()(const unsigned i, const unsigned j) const { - return this->_coord[i * N + j]; - } - - inline value_type& operator()(const unsigned i, const unsigned j) { - return this->_coord[i * N + j]; - } - - static inline unsigned rows() { - return M; - } - - static inline unsigned cols() { - return N; - } - - inline Matrix& transpose() const { - Matrix res; - for (unsigned i = 0; i < M; i++) - for (unsigned j = 0; j < N; j++) - res(j,i) = this->_coord[i * N + j]; - return res; - } - - template - inline Matrix& operator=(const Matrix& m) { - if (this != &m) - for (unsigned i = 0; i < M; i++) - for (unsigned j = 0; j < N; j++) - this->_coord[i * N + j] = (T)m(i, j); - return *this; - } - - template - inline Matrix& operator+=(const Matrix& m) { - for (unsigned i = 0; i < M; i++) - for (unsigned j = 0; j < N; j++) - this->_coord[i * N + j] += (T)m(i, j); - return *this; - } - - template - inline Matrix& operator-=(const Matrix& m) { - for (unsigned i = 0; i < M; i++) - for (unsigned j = 0; j < N; j++) - this->_coord[i * N + j] -= (T)m(i, j); - return *this; - } - - template - inline Matrix& operator*=(const U lambda) { - for (unsigned i = 0; i < M; i++) - for (unsigned j = 0; j < N; j++) - this->_coord[i * N + j] *= lambda; - return *this; - } - - template - inline Matrix& operator/=(const U lambda) { - if (lambda) - for (unsigned i = 0; i < M; i++) - for (unsigned j = 0; j < N; j++) - this->_coord[i * N + j] /= lambda; - return *this; - } - - protected: - - value_type _coord[_SIZE]; - }; - - - // - // SquareMatrix class - // - T: value type - // - N: rows & cols - // - ///////////////////////////////////////////////////////////////////////////// - - // Dirty, but icc under Windows needs this -# define __SIZE (N * N) - - template - class SquareMatrix : public Matrix - { - public: - - typedef T value_type; - - inline SquareMatrix() : Matrix() {} - - template - explicit inline SquareMatrix(const U tab[__SIZE]) : Matrix(tab) {} - - template - explicit inline SquareMatrix(const std::vector& tab) : Matrix(tab) {} - - template - inline SquareMatrix(const Matrix& m) : Matrix(m) {} - - static inline SquareMatrix identity() { - SquareMatrix res; - for (unsigned i = 0; i < N; i++) - res(i, i) = 1; - return res; - } - }; - - - // - // Vector external functions - // - ///////////////////////////////////////////////////////////////////////////// - - // template - // inline Vec operator+(const Vec& v1, - // const Vec& v2) { - // Vec res(v1); - // res += v2; - // return res; - // } - // - // template - // inline Vec operator-(const Vec& v1, - // const Vec& v2) { - // Vec res(v1); - // res -= v2; - // return res; - // } - // template - // inline Vec operator*(const Vec& v, - // const typename Vec::value_type r) { - // Vec res(v); - // res *= r; - // return res; - // } - - template - inline Vec operator*(const typename Vec::value_type r, - const Vec& v) { - Vec res(v); - res *= r; - return res; - } - // - // template - // inline Vec operator/(const Vec& v, - // const typename Vec::value_type r) { - // Vec res(v); - // if (r) - // res /= r; - // return res; - // } - // - // dot product - // template - // inline typename Vec::value_type operator*(const Vec& v1, - // const Vec& v2) { - // typename Vec::value_type sum = 0; - // for (unsigned i = 0; i < N; i++) - // sum += v1[i] * v2[i]; - // return sum; - // } - // - // // cross product for 3D Vectors - // template - // inline Vec3 operator^(const Vec& v1, - // const Vec& v2) { - // Vec3 res(v1[1] * v2[2] - v1[2] * v2[1], - // v1[2] * v2[0] - v1[0] * v2[2], - // v1[0] * v2[1] - v1[1] * v2[0]); - // return res; - // } - - // stream operator - template - inline std::ostream& operator<<(std::ostream& s, - const Vec& v) { - unsigned i; - s << "["; - for (i = 0; i < N - 1; i++) - s << v[i] << ", "; - s << v[i] << "]"; - return s; - } - - - // - // Matrix external functions - // - ///////////////////////////////////////////////////////////////////////////// - - template - inline Matrix - operator+(const Matrix& m1, - const Matrix& m2) { - Matrix res(m1); - res += m2; - return res; - } - - template - inline Matrix - operator-(const Matrix& m1, - const Matrix& m2) { - Matrix res(m1); - res -= m2; - return res; - } - - template - inline Matrix - operator*(const Matrix& m1, - const typename Matrix::value_type lambda) { - Matrix res(m1); - res *= lambda; - return res; - } - - template - inline Matrix - operator*(const typename Matrix::value_type lambda, - const Matrix& m1) { - Matrix res(m1); - res *= lambda; - return res; - } - - template - inline Matrix - operator/(const Matrix& m1, - const typename Matrix::value_type lambda) { - Matrix res(m1); - res /= lambda; - return res; - } - - template - inline Matrix - operator*(const Matrix& m1, - const Matrix& m2) { - unsigned i, j, k; - Matrix res; - typename Matrix::value_type scale; - - for (j = 0; j < P; j++) { - for (k = 0; k < N; k++) { - scale = m2(k, j); - for (i = 0; i < N; i++) - res(i, j) += m1(i, k) * scale; - } - } - return res; - } - - template - inline Vec - operator*(const Matrix& m, - const Vec& v) { - - Vec res; - typename Matrix::value_type scale; - - for (unsigned j = 0; j < M; j++) { - scale = v[j]; - for (unsigned i = 0; i < N; i++) - res[i] += m(i, j) * scale; - } - return res; - } - - // stream operator - template - inline std::ostream& operator<<(std::ostream& s, - const Matrix& m) { - unsigned i, j; - for (i = 0; i < M; i++) { - s << "["; - for (j = 0; j < N - 1; j++) - s << m(i, j) << ", "; - s << m(i, j) << "]" << std::endl; - } - return s; - } +namespace Internal { + template + struct is_false {}; + + template <> + struct is_false + { + static inline void ensure() {} + }; +} // end of namespace Internal + +// +// Vector class +// - T: value type +// - N: dimension +// +///////////////////////////////////////////////////////////////////////////// + +template +class Vec +{ +public: + typedef T value_type; + + // constructors + inline Vec() + { + for (unsigned int i = 0; i < N; i++) + this->_coord[i] = 0; + } + + ~Vec() + { + Internal::is_false<(N == 0)>::ensure(); + } + + template + explicit inline Vec(const U tab[N]) + { + for (unsigned int i = 0; i < N; i++) + this->_coord[i] = (T)tab[i]; + } + + template + explicit inline Vec(const std::vector& tab) + { + for (unsigned int i = 0; i < N; i++) + this->_coord[i] = (T)tab[i]; + } + + template + explicit inline Vec(const Vec& v) + { + for (unsigned int i = 0; i < N; i++) + this->_coord[i] = (T)v[i]; + } + + // accessors + inline value_type operator[](const unsigned i) const + { + return this->_coord[i]; + } + + inline value_type& operator[](const unsigned i) + { + return this->_coord[i]; + } + + static inline unsigned dim() + { + return N; + } + + // various useful methods + inline value_type norm() const + { + return (T)sqrt((float)squareNorm()); + } + + inline value_type squareNorm() const + { + return (*this) * (*this); + } + + inline Vec& normalize() + { + value_type n = norm(); + for (unsigned int i = 0; i < N; i++) + this->_coord[i] /= n; + return *this; + } + + inline Vec& normalizeSafe() + { + value_type n = norm(); + if (n) { + for (unsigned int i = 0; i < N; i++) + this->_coord[i] /= n; + } + return *this; + } + + // classical operators + inline Vec operator+(const Vec& v) const + { + Vec res(v); + res += *this; + return res; + } + + inline Vec operator-(const Vec& v) const + { + Vec res(*this); + res -= v; + return res; + } + + inline Vec operator*(const typename Vec::value_type r) const + { + Vec res(*this); + res *= r; + return res; + } + + inline Vec operator/(const typename Vec::value_type r) const + { + Vec res(*this); + if (r) + res /= r; + return res; + } + + // dot product + inline value_type operator*(const Vec& v) const + { + value_type sum = 0; + for (unsigned int i = 0; i < N; i++) + sum += (*this)[i] * v[i]; + return sum; + } + + template + inline Vec& operator=(const Vec& v) + { + if (this != &v) { + for (unsigned int i = 0; i < N; i++) + this->_coord[i] = (T)v[i]; + } + return *this; + } + + template + inline Vec& operator+=(const Vec& v) + { + for (unsigned int i = 0 ; i < N; i++) + this->_coord[i] += (T)v[i]; + return *this; + } + + template + inline Vec& operator-=(const Vec& v) + { + for (unsigned int i = 0 ; i < N; i++) + this->_coord[i] -= (T)v[i]; + return *this; + } + + template + inline Vec& operator*=(const U r) + { + for (unsigned int i = 0 ; i < N; i++) + this->_coord[i] *= r; + return *this; + } + + template + inline Vec& operator/=(const U r) + { + if (r) { + for (unsigned int i = 0 ; i < N; i++) + this->_coord[i] /= r; + } + return *this; + } + + inline bool operator==(const Vec& v) const + { + for (unsigned int i = 0; i < N; i++) { + if (this->_coord[i] != v[i]) + return false; + } + return true; + } + + inline bool operator!=(const Vec& v) const + { + for (unsigned int i = 0; i < N; i++) { + if (this->_coord[i] != v[i]) + return true; + } + return false; + } + + inline bool operator<(const Vec& v) const + { + for (unsigned int i = 0; i < N; i++) { + if (this->_coord[i] < v[i]) + return true; + if (this->_coord[i] > v[i]) + return false; + if (this->_coord[i] == v[i]) + continue; + } + return false; + } + + inline bool operator>(const Vec& v) const + { + for (unsigned int i = 0; i < N; i++) { + if (this->_coord[i] > v[i]) + return true; + if (this->_coord[i] < v[i]) + return false; + if (this->_coord[i] == v[i]) + continue; + } + return false; + } + +protected: + value_type _coord[N]; + enum { + _dim = N, + }; +}; + + +// +// Vec2 class (2D Vector) +// - T: value type +// +///////////////////////////////////////////////////////////////////////////// + +template +class Vec2 : public Vec +{ +public: + typedef typename Vec::value_type value_type; + + inline Vec2() : Vec() {} + + template + explicit inline Vec2(const U tab[2]) : Vec(tab) {} + + template + explicit inline Vec2(const std::vector& tab) : Vec(tab) {} + + template + inline Vec2(const Vec& v) : Vec(v) {} + + inline Vec2(const value_type x, const value_type y = 0) : Vec() + { + this->_coord[0] = (T)x; + this->_coord[1] = (T)y; + } + + inline value_type x() const + { + return this->_coord[0]; + } + + inline value_type& x() + { + return this->_coord[0]; + } + + inline value_type y() const + { + return this->_coord[1]; + } + + inline value_type& y() + { + return this->_coord[1]; + } + + inline void setX(const value_type v) + { + this->_coord[0] = v; + } + + inline void setY(const value_type v) + { + this->_coord[1] = v; + } + + // FIXME: hack swig -- no choice + inline Vec2 operator+(const Vec2& v) const + { + Vec2 res(v); + res += *this; + return res; + } + + inline Vec2 operator-(const Vec2& v) const + { + Vec2 res(*this); + res -= v; + return res; + } + + inline Vec2 operator*(const value_type r) const + { + Vec2 res(*this); + res *= r; + return res; + } + + inline Vec2 operator/(const value_type r) const + { + Vec2 res(*this); + if (r) + res /= r; + return res; + } + + // dot product + inline value_type operator*(const Vec2& v) const + { + value_type sum = 0; + for (unsigned int i = 0; i < 2; i++) + sum += (*this)[i] * v[i]; + return sum; + } +}; + + +// +// HVec3 class (3D Vector in homogeneous coordinates) +// - T: value type +// +///////////////////////////////////////////////////////////////////////////// + +template +class HVec3 : public Vec +{ +public: + typedef typename Vec::value_type value_type; + + inline HVec3() : Vec() {} + + template + explicit inline HVec3(const U tab[4]) : Vec(tab) {} + + template + explicit inline HVec3(const std::vector& tab) : Vec(tab) {} + + template + inline HVec3(const Vec& v) : Vec(v) {} + + inline HVec3(const value_type sx, const value_type sy = 0, const value_type sz = 0, const value_type s = 1) + { + this->_coord[0] = sx; + this->_coord[1] = sy; + this->_coord[2] = sz; + this->_coord[3] = s; + } + + template + inline HVec3(const Vec& sv, const U s = 1) + { + this->_coord[0] = (T)sv[0]; + this->_coord[1] = (T)sv[1]; + this->_coord[2] = (T)sv[2]; + this->_coord[3] = (T)s; + } + + inline value_type sx() const + { + return this->_coord[0]; + } + + inline value_type& sx() + { + return this->_coord[0]; + } + + inline value_type sy() const + { + return this->_coord[1]; + } + + inline value_type& sy(){ + return this->_coord[1]; + } + + inline value_type sz() const + { + return this->_coord[2]; + } + + inline value_type& sz() + { + return this->_coord[2]; + } + + inline value_type s() const + { + return this->_coord[3]; + } + + inline value_type& s() + { + return this->_coord[3]; + } + + // Acces to non-homogeneous coordinates in 3D + inline value_type x() const + { + return this->_coord[0] / this->_coord[3]; + } + + inline value_type y() const + { + return this->_coord[1] / this->_coord[3]; + } + + inline value_type z() const + { + return this->_coord[2] / this->_coord[3]; + } +}; + + +// +// Vec3 class (3D Vec) +// - T: value type +// +///////////////////////////////////////////////////////////////////////////// +template +class Vec3 : public Vec +{ +public: + typedef typename Vec::value_type value_type; + + inline Vec3() : Vec() {} + + template + explicit inline Vec3(const U tab[3]) : Vec(tab) {} + + template + explicit inline Vec3(const std::vector& tab) : Vec(tab) {} + + template + inline Vec3(const Vec& v) : Vec(v) {} + + template + inline Vec3(const HVec3& v) + { + this->_coord[0] = (T)v.x(); + this->_coord[1] = (T)v.y(); + this->_coord[2] = (T)v.z(); + } + + inline Vec3(const value_type x, const value_type y = 0, const value_type z = 0) : Vec() + { + this->_coord[0] = x; + this->_coord[1] = y; + this->_coord[2] = z; + } + + inline value_type x() const + { + return this->_coord[0]; + } + + inline value_type& x() + { + return this->_coord[0]; + } + + inline value_type y() const + { + return this->_coord[1]; + } + + inline value_type& y() + { + return this->_coord[1]; + } + + inline value_type z() const + { + return this->_coord[2]; + } + + inline value_type& z() + { + return this->_coord[2]; + } + + inline void setX(const value_type v) + { + this->_coord[0] = v; + } + + inline void setY(const value_type v) + { + this->_coord[1] = v; + } + + inline void setZ(const value_type v) + { + this->_coord[2] = v; + } + + // classical operators + // FIXME: hack swig -- no choice + inline Vec3 operator+(const Vec3& v) const + { + Vec3 res(v); + res += *this; + return res; + } + + inline Vec3 operator-(const Vec3& v) const + { + Vec3 res(*this); + res -= v; + return res; + } + + inline Vec3 operator*(const value_type r) const + { + Vec3 res(*this); + res *= r; + return res; + } + + inline Vec3 operator/(const value_type r) const + { + Vec3 res(*this); + if (r) + res /= r; + return res; + } + + // dot product + inline value_type operator*(const Vec3& v) const + { + value_type sum = 0; + for (unsigned int i = 0; i < 3; i++) + sum += (*this)[i] * v[i]; + return sum; + } + + // cross product for 3D Vectors + // FIXME: hack swig -- no choice + inline Vec3 operator^(const Vec3& v) const + { + Vec3 res((*this)[1] * v[2] - (*this)[2] * v[1], + (*this)[2] * v[0] - (*this)[0] * v[2], + (*this)[0] * v[1] - (*this)[1] * v[0]); + return res; + } + + // cross product for 3D Vectors + template + inline Vec3 operator^(const Vec& v) const + { + Vec3 res((*this)[1] * v[2] - (*this)[2] * v[1], + (*this)[2] * v[0] - (*this)[0] * v[2], + (*this)[0] * v[1] - (*this)[1] * v[0]); + return res; + } +}; + + +// +// Matrix class +// - T: value type +// - M: rows +// - N: cols +// +///////////////////////////////////////////////////////////////////////////// + +// Dirty, but icc under Windows needs this +#define _SIZE (M * N) + +template +class Matrix +{ +public: + typedef T value_type; + + inline Matrix() + { + for (unsigned int i = 0; i < _SIZE; i++) + this->_coord[i] = 0; + } + + ~Matrix() + { + Internal::is_false<(M == 0)>::ensure(); + Internal::is_false<(N == 0)>::ensure(); + } + + template + explicit inline Matrix(const U tab[_SIZE]) + { + for (unsigned int i = 0; i < _SIZE; i++) + this->_coord[i] = tab[i]; + } + + template + explicit inline Matrix(const std::vector& tab) + { + for (unsigned int i = 0; i < _SIZE; i++) + this->_coord[i] = tab[i]; + } + + template + inline Matrix(const Matrix& m) + { + for (unsigned int i = 0; i < M; i++) { + for (unsigned int j = 0; j < N; j++) + this->_coord[i * N + j] = (T)m(i, j); + } + } + + inline value_type operator()(const unsigned i, const unsigned j) const + { + return this->_coord[i * N + j]; + } + + inline value_type& operator()(const unsigned i, const unsigned j) + { + return this->_coord[i * N + j]; + } + + static inline unsigned rows() + { + return M; + } + + static inline unsigned cols() + { + return N; + } + + inline Matrix& transpose() const + { + Matrix res; + for (unsigned int i = 0; i < M; i++) { + for (unsigned int j = 0; j < N; j++) + res(j, i) = this->_coord[i * N + j]; + } + return res; + } + + template + inline Matrix& operator=(const Matrix& m) + { + if (this != &m) { + for (unsigned int i = 0; i < M; i++) { + for (unsigned int j = 0; j < N; j++) + this->_coord[i * N + j] = (T)m(i, j); + } + } + return *this; + } + + template + inline Matrix& operator+=(const Matrix& m) + { + for (unsigned int i = 0; i < M; i++) { + for (unsigned int j = 0; j < N; j++) + this->_coord[i * N + j] += (T)m(i, j); + } + return *this; + } + + template + inline Matrix& operator-=(const Matrix& m) + { + for (unsigned int i = 0; i < M; i++) { + for (unsigned int j = 0; j < N; j++) + this->_coord[i * N + j] -= (T)m(i, j); + } + return *this; + } + + template + inline Matrix& operator*=(const U lambda) + { + for (unsigned int i = 0; i < M; i++) { + for (unsigned int j = 0; j < N; j++) + this->_coord[i * N + j] *= lambda; + } + return *this; + } + + template + inline Matrix& operator/=(const U lambda) + { + if (lambda) { + for (unsigned int i = 0; i < M; i++) { + for (unsigned int j = 0; j < N; j++) + this->_coord[i * N + j] /= lambda; + } + } + return *this; + } + +protected: + value_type _coord[_SIZE]; +}; + +#undef _SIZE + +// +// SquareMatrix class +// - T: value type +// - N: rows & cols +// +///////////////////////////////////////////////////////////////////////////// + +// Dirty, but icc under Windows needs this +#define _SIZE (N * N) + +template +class SquareMatrix : public Matrix +{ +public: + typedef T value_type; + + inline SquareMatrix() : Matrix() {} + + template + explicit inline SquareMatrix(const U tab[_SIZE]) : Matrix(tab) {} + + template + explicit inline SquareMatrix(const std::vector& tab) : Matrix(tab) {} + + template + inline SquareMatrix(const Matrix& m) : Matrix(m) {} + + static inline SquareMatrix identity() + { + SquareMatrix res; + for (unsigned int i = 0; i < N; i++) + res(i, i) = 1; + return res; + } +}; + +#undef _SIZE + +// +// Vector external functions +// +///////////////////////////////////////////////////////////////////////////// + +#if 0 +template +inline Vec operator+(const Vec& v1, const Vec& v2) +{ + Vec res(v1); + res += v2; + return res; +} + +template +inline Vec operator-(const Vec& v1, const Vec& v2) +{ + Vec res(v1); + res -= v2; + return res; +} + +template +inline Vec operator*(const Vec& v, const typename Vec::value_type r) +{ + Vec res(v); + res *= r; + return res; +} +#endif + +template +inline Vec operator*(const typename Vec::value_type r, const Vec& v) +{ + Vec res(v); + res *= r; + return res; +} + +#if 0 +template +inline Vec operator/(const Vec& v, const typename Vec::value_type r) +{ + Vec res(v); + if (r) + res /= r; + return res; +} + +// dot product +template +inline typename Vec::value_type operator*(const Vec& v1, const Vec& v2) +{ + typename Vec::value_type sum = 0; + for (unsigned int i = 0; i < N; i++) + sum += v1[i] * v2[i]; + return sum; +} + +// cross product for 3D Vectors +template +inline Vec3 operator^(const Vec& v1, const Vec& v2) +{ + Vec3 res(v1[1] * v2[2] - v1[2] * v2[1], v1[2] * v2[0] - v1[0] * v2[2], v1[0] * v2[1] - v1[1] * v2[0]); + return res; +} +#endif + +// stream operator +template +inline std::ostream& operator<<(std::ostream& s, const Vec& v) +{ + unsigned int i; + s << "["; + for (i = 0; i < N - 1; i++) + s << v[i] << ", "; + s << v[i] << "]"; + return s; +} + +// +// Matrix external functions +// +///////////////////////////////////////////////////////////////////////////// + +template +inline Matrix operator+(const Matrix& m1, const Matrix& m2) +{ + Matrix res(m1); + res += m2; + return res; +} + +template +inline Matrix operator-(const Matrix& m1, const Matrix& m2) +{ + Matrix res(m1); + res -= m2; + return res; +} + +template +inline Matrix operator*(const Matrix& m1, const typename Matrix::value_type lambda) +{ + Matrix res(m1); + res *= lambda; + return res; +} + +template +inline Matrix operator*(const typename Matrix::value_type lambda, const Matrix& m1) +{ + Matrix res(m1); + res *= lambda; + return res; +} + +template +inline Matrix operator/(const Matrix& m1, const typename Matrix::value_type lambda) +{ + Matrix res(m1); + res /= lambda; + return res; +} + +template +inline Matrix operator*(const Matrix& m1, const Matrix& m2) +{ + unsigned int i, j, k; + Matrix res; + typename Matrix::value_type scale; + + for (j = 0; j < P; j++) { + for (k = 0; k < N; k++) { + scale = m2(k, j); + for (i = 0; i < N; i++) + res(i, j) += m1(i, k) * scale; + } + } + return res; +} + +template +inline Vec operator*(const Matrix& m, const Vec& v) +{ + Vec res; + typename Matrix::value_type scale; + + for (unsigned int j = 0; j < M; j++) { + scale = v[j]; + for (unsigned int i = 0; i < N; i++) + res[i] += m(i, j) * scale; + } + return res; +} + +// stream operator +template +inline std::ostream& operator<<(std::ostream& s, const Matrix& m) +{ + unsigned int i, j; + for (i = 0; i < M; i++) { + s << "["; + for (j = 0; j < N - 1; j++) + s << m(i, j) << ", "; + s << m(i, j) << "]" << std::endl; + } + return s; +} } // end of namespace VecMat -#endif // VECMAT_H +#endif // __VECMAT_H__ diff --git a/source/blender/freestyle/intern/geometry/matrix_util.cpp b/source/blender/freestyle/intern/geometry/matrix_util.cpp index 2117b06e62f..089535561d7 100644 --- a/source/blender/freestyle/intern/geometry/matrix_util.cpp +++ b/source/blender/freestyle/intern/geometry/matrix_util.cpp @@ -1,265 +1,266 @@ /* - * GXML/Graphite: Geometry and Graphics Programming Library + Utilities - * Copyright (C) 2000 Bruno Levy + * ***** BEGIN GPL LICENSE BLOCK ***** * - * 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. + * 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. * - * 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. + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * If you modify this software, you should include a notice giving the - * name of the person performing the modification, the date of modification, - * and the reason for such modification. + * This Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. * - * Contact: Bruno Levy + * The Original Code is: + * GXML/Graphite: Geometry and Graphics Programming Library + Utilities + * Copyright (C) 2000 Bruno Levy + * Contact: Bruno Levy + * levy@loria.fr + * ISA Project + * LORIA, INRIA Lorraine, + * Campus Scientifique, BP 239 + * 54506 VANDOEUVRE LES NANCY CEDEX + * FRANCE * - * levy@loria.fr + * Contributor(s): none yet. * - * ISA Project - * LORIA, INRIA Lorraine, - * Campus Scientifique, BP 239 - * 54506 VANDOEUVRE LES NANCY CEDEX - * FRANCE - * - * Note that the GNU General Public License does not permit incorporating - * the Software into proprietary programs. + * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/freestyle/intern/geometry/matrix_util.cpp + * \ingroup freestyle + * \author Bruno Levy + */ -#include "matrix_util.h" #include - +#include "matrix_util.h" namespace OGF { - - namespace MatrixUtil { - static const double EPS = 0.00001 ; - static int MAX_ITER = 100 ; - - void semi_definite_symmetric_eigen( - const double *mat, int n, double *eigen_vec, double *eigen_val - ) { - double *a,*v; - double a_norm,a_normEPS,thr,thr_nn; - int nb_iter = 0; - int jj; - int i,j,k,ij,ik,l,m,lm,mq,lq,ll,mm,imv,im,iq,ilv,il,nn; - int *index; - double a_ij,a_lm,a_ll,a_mm,a_im,a_il; - double a_lm_2; - double v_ilv,v_imv; - double x; - double sinx,sinx_2,cosx,cosx_2,sincos; - double delta; - - // Number of entries in mat - - nn = (n*(n+1))/2; - - // Step 1: Copy mat to a - - a = new double[nn]; - - for( ij=0; ij a_normEPS && nb_iter < MAX_ITER ) { - - nb_iter++; - thr_nn = thr / nn; - - for( l=1 ; l< n; l++ ) { - for( m=l+1; m<=n; m++ ) { - - // compute sinx and cosx - - lq = (l*l-l)/2; - mq = (m*m-m)/2; - - lm = l+mq; - a_lm = a[lm]; - a_lm_2 = a_lm*a_lm; - - if( a_lm_2 < thr_nn ) { - continue ; - } - - ll = l+lq; - mm = m+mq; - a_ll = a[ll]; - a_mm = a[mm]; - - delta = a_ll - a_mm; - - if( delta == 0.0 ) { - x = - M_PI/4 ; - } else { - x = - atan( (a_lm+a_lm) / delta ) / 2.0 ; - } +namespace MatrixUtil { - sinx = sin(x) ; - cosx = cos(x) ; - sinx_2 = sinx*sinx; - cosx_2 = cosx*cosx; - sincos = sinx*cosx; - - // rotate L and M columns - - ilv = n*(l-1); - imv = n*(m-1); - - for( i=1; i<=n;i++ ) { - if( (i!=l) && (i!=m) ) { - iq = (i*i-i)/2; - - if( i a_normEPS && nb_iter < MAX_ITER) { + nb_iter++; + thr_nn = thr / nn; + + for (l = 1; l < n; l++) { + for (m = l + 1; m <= n; m++) { + // compute sinx and cosx + lq = (l * l - l) / 2; + mq = (m * m - m) / 2; + + lm = l + mq; + a_lm = a[lm]; + a_lm_2 = a_lm * a_lm; + + if (a_lm_2 < thr_nn) { + continue; + } + + ll = l + lq; + mm = m + mq; + a_ll = a[ll]; + a_mm = a[mm]; + + delta = a_ll - a_mm; + + if (delta == 0.0) { + x = -M_PI / 4; + } + else { + x = -atan((a_lm + a_lm) / delta) / 2.0; + } + + sinx = sin(x); + cosx = cos(x); + sinx_2 = sinx * sinx; + cosx_2 = cosx * cosx; + sincos = sinx * cosx; + + // rotate L and M columns + ilv = n * (l - 1); + imv = n * (m - 1); + + for (i = 1; i <= n; i++) { + if ((i != l) && (i != m)) { + iq = (i * i - i) / 2; + + if (i < m) { + im = i + mq; + } + else { + im = m + iq; + } + a_im = a[im]; + + if (i < l) { + il = i + lq; + } + else { + il = l + iq; + } + a_il = a[il]; + + a[il] = a_il * cosx - a_im * sinx; + a[im] = a_il * sinx + a_im * cosx; + } + + ilv++; + imv++; + + v_ilv = v[ilv]; + v_imv = v[imv]; + + v[ilv] = cosx * v_ilv - sinx * v_imv; + v[imv] = sinx * v_ilv + cosx * v_imv; + } + + x = a_lm * sincos; + x += x; + + a[ll] = a_ll * cosx_2 + a_mm * sinx_2 - x; + a[mm] = a_ll * sinx_2 + a_mm * cosx_2 + x; + a[lm] = 0.0; + + thr = fabs(thr - a_lm_2); + } + } + } + } + + // Step 5: index conversion and copy eigen values + + // back from Fortran to C++ + a++; + + for (i = 0; i < n; i++) { + k = i + (i * (i + 1)) / 2; + eigen_val[i] = a[k]; + } + + delete[] a; + + // Step 6: sort the eigen values and eigen vectors + + index = new int[n]; + for (i = 0; i < n; i++) { + index[i] = i; + } + + for (i = 0; i < (n - 1); i++) { + x = eigen_val[i]; + k = i; + + for (j = i + 1; j < n; j++) { + if (x < eigen_val[j]) { + k = j; + x = eigen_val[j]; + } + } + + eigen_val[k] = eigen_val[i]; + eigen_val[i] = x; + + jj = index[k]; + index[k] = index[i]; + index[i] = jj; + } + + // Step 7: save the eigen vectors + + // back from Fortran to to C++ + v++; + + ij = 0; + for (k = 0; k < n; k++) { + ik = index[k] * n; + for (i = 0; i < n; i++) { + eigen_vec[ij++] = v[ik++]; + } + } + + delete[] v; + delete[] index; + return; + } - // Step 7: save the eigen vectors - - v++; // back from Fortran to to C++ - - ij = 0; - for( k=0; k l0) { - ogf_swap(l0 , l1 ) ; - ogf_swap(i_[0], i_[1]) ; - } - if(l2 > l1) { - ogf_swap(l1 , l2 ) ; - ogf_swap(i_[1], i_[2]) ; - } - if(l1 > l0) { - ogf_swap(l0 , l1 ) ; - ogf_swap(i_[0],i_[1]) ; - } + axis_[0] = Vec3r(eigen_vectors[0], eigen_vectors[1], eigen_vectors[2]); - } + axis_[1] = Vec3r(eigen_vectors[3], eigen_vectors[4], eigen_vectors[5]); + + axis_[2] = Vec3r(eigen_vectors[6], eigen_vectors[7], eigen_vectors[8]); + + // Normalize the eigen vectors + for (int i = 0; i < 3; i++) { + axis_[i].normalize(); + } + + // Sort the eigen vectors + i_[0] = 0; + i_[1] = 1; + i_[2] = 2; + + double l0 = ::fabs(eigen_value_[0]); + double l1 = ::fabs(eigen_value_[1]); + double l2 = ::fabs(eigen_value_[2]); + + if (l1 > l0) { + ogf_swap(l0 , l1 ); + ogf_swap(i_[0], i_[1]); + } + if (l2 > l1) { + ogf_swap(l1 , l2 ); + ogf_swap(i_[1], i_[2]); + } + if (l1 > l0) { + ogf_swap(l0 , l1 ); + ogf_swap(i_[0], i_[1]); + } +} //_________________________________________________________ -} +} // OGF namespace diff --git a/source/blender/freestyle/intern/geometry/normal_cycle.h b/source/blender/freestyle/intern/geometry/normal_cycle.h index cdf00a0b4c5..3fbf4fb58ae 100644 --- a/source/blender/freestyle/intern/geometry/normal_cycle.h +++ b/source/blender/freestyle/intern/geometry/normal_cycle.h @@ -1,110 +1,144 @@ /* - * OGF/Graphite: Geometry and Graphics Programming Library + Utilities - * Copyright (C) 2000 Bruno Levy + * ***** BEGIN GPL LICENSE BLOCK ***** * - * 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. + * 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. * - * 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. + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * If you modify this software, you should include a notice giving the - * name of the person performing the modification, the date of modification, - * and the reason for such modification. + * This Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. * - * Contact: Bruno Levy + * The Original Code is: + * OGF/Graphite: Geometry and Graphics Programming Library + Utilities + * Copyright (C) 2000 Bruno Levy + * Contact: Bruno Levy + * levy@loria.fr + * ISA Project + * LORIA, INRIA Lorraine, + * Campus Scientifique, BP 239 + * 54506 VANDOEUVRE LES NANCY CEDEX + * FRANCE * - * levy@loria.fr + * Contributor(s): none yet. * - * ISA Project - * LORIA, INRIA Lorraine, - * Campus Scientifique, BP 239 - * 54506 VANDOEUVRE LES NANCY CEDEX - * FRANCE - * - * Note that the GNU General Public License does not permit incorporating - * the Software into proprietary programs. + * ***** END GPL LICENSE BLOCK ***** */ #ifndef __MESH_TOOLS_MATH_NORMAL_CYCLE__ #define __MESH_TOOLS_MATH_NORMAL_CYCLE__ -# include "../system/FreestyleConfig.h" -# include "Geom.h" +/** \file blender/freestyle/intern/geometry/normal_cycle.h + * \ingroup freestyle + * \author Bruno Levy + */ + +#include "Geom.h" + +#include "../system/FreestyleConfig.h" + using namespace Geometry; - + namespace OGF { -template inline void ogf_swap(T& x, T& y) { - T z = x ; - x = y ; - y = z ; - } - -//_________________________________________________________ - - /** - * NormalCycle evaluates the curvature tensor in function - * of a set of dihedral angles and associated vectors. - * Reference: - * Restricted Delaunay Triangulation and Normal Cycle, - * D. Cohen-Steiner and J.M. Morvan, - * SOCG 2003 - */ - class LIB_GEOMETRY_EXPORT NormalCycle { - public: - NormalCycle() ; - void begin() ; - void end() ; - /** - * Note: the specified edge vector needs to be pre-clipped - * by the neighborhood. - */ - void accumulate_dihedral_angle( - const Vec3r& edge, real angle, real neigh_area = 1.0 - ) ; - const Vec3r& eigen_vector(int i) const { return axis_[i_[i]] ; } - real eigen_value(int i) const { return eigen_value_[i_[i]] ; } - - const Vec3r& N() const { return eigen_vector(2) ; } - const Vec3r& Kmax() const { return eigen_vector(1) ; } - const Vec3r& Kmin() const { return eigen_vector(0) ; } - - real n() const { return eigen_value(2) ; } - real kmax() const { return eigen_value(1) ; } - real kmin() const { return eigen_value(0) ; } - - private: - real center_[3] ; - Vec3r axis_[3] ; - real eigen_value_[3] ; - real M_[6] ; - int i_[3] ; - } ; - - inline void NormalCycle::accumulate_dihedral_angle( - const Vec3r& edge, const double beta, double neigh_area - ) { - double s = beta * neigh_area / edge.norm(); - - M_[0] += s * edge.x() * edge.x() ; - M_[1] += s * edge.x() * edge.y() ; - M_[2] += s * edge.y() * edge.y() ; - M_[3] += s * edge.x() * edge.z() ; - M_[4] += s * edge.y() * edge.z() ; - M_[5] += s * edge.z() * edge.z() ; - } - -//_________________________________________________________ - +template inline void ogf_swap(T& x, T& y) +{ + T z = x ; + x = y ; + y = z ; } -#endif +//_________________________________________________________ + +/** +* NormalCycle evaluates the curvature tensor in function +* of a set of dihedral angles and associated vectors. +* Reference: +* Restricted Delaunay Triangulation and Normal Cycle, +* D. Cohen-Steiner and J.M. Morvan, +* SOCG 2003 +*/ +class LIB_GEOMETRY_EXPORT NormalCycle { +public: + NormalCycle(); + void begin(); + void end(); + /** + * Note: the specified edge vector needs to be pre-clipped by the neighborhood. + */ + void accumulate_dihedral_angle(const Vec3r& edge, real angle, real neigh_area = 1.0); + + const Vec3r& eigen_vector(int i) const + { + return axis_[i_[i]]; + } + + real eigen_value(int i) const + { + return eigen_value_[i_[i]]; + } + + const Vec3r& N() const + { + return eigen_vector(2); + } + + const Vec3r& Kmax() const + { + return eigen_vector(1); + } + + const Vec3r& Kmin() const + { + return eigen_vector(0); + } + + real n() const + { + return eigen_value(2); + } + + real kmax() const + { + return eigen_value(1); + } + + real kmin() const + { + return eigen_value(0); + } + +private: + real center_[3]; + Vec3r axis_[3]; + real eigen_value_[3]; + real M_[6]; + int i_[3]; +}; + +inline void NormalCycle::accumulate_dihedral_angle(const Vec3r& edge, const double beta, double neigh_area) +{ + double s = beta * neigh_area / edge.norm(); + + M_[0] += s * edge.x() * edge.x(); + M_[1] += s * edge.x() * edge.y(); + M_[2] += s * edge.y() * edge.y(); + M_[3] += s * edge.x() * edge.z(); + M_[4] += s * edge.y() * edge.z(); + M_[5] += s * edge.z() * edge.z(); +} + +//_________________________________________________________ + +} // OGF namespace + +#endif // __MESH_TOOLS_MATH_NORMAL_CYCLE__ diff --git a/source/blender/freestyle/intern/image/GaussianFilter.cpp b/source/blender/freestyle/intern/image/GaussianFilter.cpp index 3a79f5f9949..be0bef8115c 100644 --- a/source/blender/freestyle/intern/image/GaussianFilter.cpp +++ b/source/blender/freestyle/intern/image/GaussianFilter.cpp @@ -1,96 +1,112 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/image/GaussianFilter.cpp + * \ingroup freestyle + * \brief Class to perform gaussian filtering operations on an image + * \author Stephane Grabli + * \date 20/05/2003 + */ -#include "GaussianFilter.h" #include -GaussianFilter::GaussianFilter(float iSigma ) +#include "GaussianFilter.h" + +GaussianFilter::GaussianFilter(float iSigma) { - _sigma = iSigma; - _mask = 0; - computeMask(); + _sigma = iSigma; + _mask = 0; + computeMask(); } -GaussianFilter::GaussianFilter(const GaussianFilter& iBrother) +GaussianFilter::GaussianFilter(const GaussianFilter& iBrother) { - _sigma = iBrother._sigma; - _maskSize = iBrother._maskSize; - _bound = iBrother._bound; - _storedMaskSize = iBrother._storedMaskSize; - _mask = new float[_maskSize*_maskSize]; - memcpy(_mask, iBrother._mask, _maskSize*_maskSize*sizeof(float)); + _sigma = iBrother._sigma; + _maskSize = iBrother._maskSize; + _bound = iBrother._bound; + _storedMaskSize = iBrother._storedMaskSize; + _mask = new float[_maskSize * _maskSize]; + memcpy(_mask, iBrother._mask, _maskSize * _maskSize * sizeof(float)); } - -GaussianFilter& GaussianFilter::operator= (const GaussianFilter& iBrother) +GaussianFilter& GaussianFilter::operator=(const GaussianFilter& iBrother) { - _sigma = iBrother._sigma; - _maskSize = iBrother._maskSize; - _bound = iBrother._bound; - _storedMaskSize = iBrother._storedMaskSize; - _mask = new float[_storedMaskSize*_storedMaskSize]; - memcpy(_mask, iBrother._mask, _storedMaskSize*_storedMaskSize*sizeof(float)); - return *this; + _sigma = iBrother._sigma; + _maskSize = iBrother._maskSize; + _bound = iBrother._bound; + _storedMaskSize = iBrother._storedMaskSize; + _mask = new float[_storedMaskSize * _storedMaskSize]; + memcpy(_mask, iBrother._mask, _storedMaskSize * _storedMaskSize * sizeof(float)); + return *this; } GaussianFilter::~GaussianFilter() { - if(0!=_mask) - { - delete [] _mask; - } + if (0 != _mask) { + delete[] _mask; + } } int GaussianFilter::computeMaskSize(float sigma) { - int maskSize = (int)floor(4*sigma)+1; - if(0 == maskSize%2) - ++maskSize; + int maskSize = (int)floor(4 * sigma) + 1; + if (0 == (maskSize % 2)) + ++maskSize; - return maskSize; + return maskSize; } void GaussianFilter::setSigma(float sigma) { - _sigma = sigma; - computeMask(); + _sigma = sigma; + computeMask(); } void GaussianFilter::computeMask() { - if(0 != _mask){ - delete [] _mask; - } + if (0 != _mask) { + delete[] _mask; + } - _maskSize = computeMaskSize(_sigma); - _storedMaskSize = (_maskSize+1)>>1; - _bound = _storedMaskSize-1; + _maskSize = computeMaskSize(_sigma); + _storedMaskSize = (_maskSize + 1) >> 1; + _bound = _storedMaskSize - 1; - float norm = _sigma*_sigma*2.f*M_PI; - float invNorm = 1.0/norm; - _mask = new float[_storedMaskSize*_storedMaskSize*sizeof(float)]; - for(int i=0; i<_storedMaskSize; ++i) - for(int j=0; j<_storedMaskSize; ++j) - _mask[i*_storedMaskSize+j] = invNorm*exp(-(i*i + j*j)/(2.0*_sigma*_sigma)); - //_mask[i*_storedMaskSize+j] = exp(-(i*i + j*j)/(2.0*_sigma*_sigma)); + float norm = _sigma * _sigma * 2.0f * M_PI; + float invNorm = 1.0f / norm; + _mask = new float[_storedMaskSize * _storedMaskSize * sizeof(float)]; + for (int i = 0; i < _storedMaskSize; ++i) { + for (int j = 0; j < _storedMaskSize; ++j) { +#if 0 + _mask[i * _storedMaskSize + j] = exp(-(i * i + j * j) / (2.0 * _sigma * _sigma)); +#else + _mask[i * _storedMaskSize + j] = invNorm * exp(-(i * i + j * j) / (2.0 * _sigma * _sigma)); +#endif + } + } } - diff --git a/source/blender/freestyle/intern/image/GaussianFilter.h b/source/blender/freestyle/intern/image/GaussianFilter.h index be0e3e2bada..9890e615a7c 100644 --- a/source/blender/freestyle/intern/image/GaussianFilter.h +++ b/source/blender/freestyle/intern/image/GaussianFilter.h @@ -1,95 +1,114 @@ -// -// Filename : Image.h -// Author(s) : Stephane Grabli -// Purpose : Class to perform gaussian filtering operations on an image -// Date of creation : 20/05/2003 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __GAUSSIANFILTER_H__ +#define __GAUSSIANFILTER_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/image/GaussianFilter.h + * \ingroup freestyle + * \brief Class to perform gaussian filtering operations on an image + * \author Stephane Grabli + * \date 20/05/2003 + */ -#ifndef GAUSSIANFILTER_H -# define GAUSSIANFILTER_H - -#include // for memcpy #include // for abs +#include // for memcpy + #include "../system/FreestyleConfig.h" -class LIB_IMAGE_EXPORT GaussianFilter{ +class LIB_IMAGE_EXPORT GaussianFilter +{ protected: - /* the mask is a symetrical 2d array (with respect - to the middle point). - Thus, M(i,j) = M(-i,j) = M(i,-j) = M(-i,-j). - For this reason, to represent a NxN array (N odd), we only store - a ((N+1)/2)x((N+1)/2) array. - */ - float _sigma; - float *_mask; - int _bound; - int _maskSize; // the real mask size (must be odd)(the size of the mask we store is ((_maskSize+1)/2)*((_maskSize+1)/2)) - int _storedMaskSize; //(_maskSize+1)/2) - + /* The mask is a symetrical 2d array (with respect to the middle point). + * Thus, M(i,j) = M(-i,j) = M(i,-j) = M(-i,-j). + * For this reason, to represent a NxN array (N odd), we only store a ((N+1)/2)x((N+1)/2) array. + */ + float _sigma; + float *_mask; + int _bound; + int _maskSize; // the real mask size (must be odd)(the size of the mask we store is ((_maskSize+1)/2)*((_maskSize+1)/2)) + int _storedMaskSize; // (_maskSize+1)/2) + public: - GaussianFilter(float iSigma = 1.f) ; - GaussianFilter(const GaussianFilter&) ; - GaussianFilter& operator= (const GaussianFilter&) ; - virtual ~GaussianFilter() ; + GaussianFilter(float iSigma = 1.0f); + GaussianFilter(const GaussianFilter&); + GaussianFilter& operator=(const GaussianFilter&); + virtual ~GaussianFilter(); - /*! Returns the value for pixel x,y of image "map" after a gaussian blur, - * made using the sigma value. - * The sigma value determines the mask size (~ 2 x sigma). - * \param map - * The image we wish to work on. The Map template must implement the - * foloowing methods: - * - float pixel(unsigned int x,unsigned int y) const; - * - unsigned width() const; - * - unsigned height() const; - * \param x - * The abscissa of the pixel where we want to evaluate the gaussian blur. - * \param y - * The ordinate of the pixel where we want to evaluate the gaussian blur. - * \param sigma - * The sigma value of the gaussian function. - */ - template - float getSmoothedPixel(Map * map, int x, int y) ; - - /*! Compute the mask size and returns the REAL mask size ((2*_maskSize)-1) - * This method is provided for convenience. - */ - static int computeMaskSize(float sigma) ; + /*! Returns the value for pixel x,y of image "map" after a gaussian blur, made using the sigma value. + * The sigma value determines the mask size (~ 2 x sigma). + * \param map + * The image we wish to work on. The Map template must implement the following methods: + * - float pixel(unsigned int x,unsigned int y) const; + * - unsigned width() const; + * - unsigned height() const; + * \param x + * The abscissa of the pixel where we want to evaluate the gaussian blur. + * \param y + * The ordinate of the pixel where we want to evaluate the gaussian blur. + * \param sigma + * The sigma value of the gaussian function. + */ + template + float getSmoothedPixel(Map *map, int x, int y); - /*! accessors */ - inline float sigma() const {return _sigma;} - inline int maskSize() const {return _maskSize;} - inline int getBound() {return _bound;} + /*! Compute the mask size and returns the REAL mask size ((2*_maskSize)-1) + * This method is provided for convenience. + */ + static int computeMaskSize(float sigma); + + /*! accessors */ + inline float sigma() const + { + return _sigma; + } + + inline int maskSize() const + { + return _maskSize; + } + + inline int getBound() + { + return _bound; + } + + /*! modifiers */ + void setSigma(float sigma); +#if 0 + void SetMaskSize(int size) + { + _maskSize = size; + _storedMaskSize = (_maskSize + 1) >> 1; + } +#endif - /*! modifiers */ - void setSigma(float sigma) ; - // void SetMaskSize(int size) {_maskSize = size;_storedMaskSize=(_maskSize+1)>>1;} - - protected: - void computeMask(); + void computeMask(); }; /* @@ -106,41 +125,37 @@ protected: */ - #include #ifdef __MACH__ -#define sqrtf(x) (sqrt(x)) +# define sqrtf(x) (sqrt(x)) #endif template -float GaussianFilter::getSmoothedPixel(Map * map, int x, int y) +float GaussianFilter::getSmoothedPixel(Map *map, int x, int y) { - float sum = 0.f; - float L=0.f; - int w = (int)map->width(); //soc - int h = (int)map->height(); //soc + float sum = 0.0f; + float L = 0.0f; + int w = (int)map->width(); //soc + int h = (int)map->height(); //soc - // Current pixel is x,y - // Sum surrounding pixels L value: - for(int i=-_bound; i<=_bound; ++i) - { - if((y+i < 0) || (y+i >= h)) - continue; - for(int j=-_bound; j<=_bound; ++j) - { - if((x+j < 0) || (x+j >= w)) - continue; - - float tmpL = map->pixel(x+j,y+i); - float m = _mask[abs(i)*_storedMaskSize+abs(j)]; - L += m*tmpL; - sum += m; - } - } - //L /= sum; - return L; + // Current pixel is x,y + // Sum surrounding pixels L value: + for (int i = -_bound; i <= _bound; ++i) { + if ((y + i < 0) || (y + i >= h)) + continue; + for (int j = -_bound; j <= _bound; ++j) { + if ((x + j < 0) || (x + j >= w)) + continue; + + float tmpL = map->pixel(x + j, y + i); + float m = _mask[abs(i) * _storedMaskSize + abs(j)]; + L += m * tmpL; + sum += m; + } + } + //L /= sum; + return L; } - -#endif // GAUSSIANFILTER +#endif // __GAUSSIANFILTER_H__ diff --git a/source/blender/freestyle/intern/image/Image.h b/source/blender/freestyle/intern/image/Image.h index 72affbc1023..1487e43a0b0 100644 --- a/source/blender/freestyle/intern/image/Image.h +++ b/source/blender/freestyle/intern/image/Image.h @@ -1,178 +1,177 @@ -// -// Filename : Image.h -// Author(s) : Stephane Grabli -// Purpose : Class to encapsulate an array of RGB or Gray level values -// Date of creation : 20/05/2003 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __IMAGE_H__ +#define __IMAGE_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/image/Image.h + * \ingroup freestyle + * \brief Class to encapsulate an array of RGB or Gray level values + * \author Stephane Grabli + * \date 20/05/2003 + */ -#ifndef IMAGE_H -# define IMAGE_H - -# include // for memcpy +#include // for memcpy // // Image base class, for all types of images // /////////////////////////////////////////////////////////////////////////////// -/*! This class allows the storing of part of an image, - * while allowing a normal access to its pixel values. - * You can for example only a rectangle of sw*sh, whose - * lower-left corner is at (ox, oy), of an image of - * size w*h, and access these pixels using x,y coordinates - * specified in the whole image coordinate system. +/*! This class allows the storing of part of an image, while allowing a normal access to its pixel values. + * You can for example only a rectangle of sw*sh, whose lower-left corner is at (ox, oy), of an image of + * size w*h, and access these pixels using x,y coordinates specified in the whole image coordinate system. */ class FrsImage { - public: +public: + /*! Default constructor */ + FrsImage() + { + _storedWidth = 0; + _storedHeight = 0; + _width = 0; + _height = 0; + _Ox = 0; + _Oy = 0; + } - /*! Default constructor */ - FrsImage() { - _storedWidth = 0; - _storedHeight = 0; - _width = 0; - _height = 0; - _Ox = 0; - _Oy = 0; - } + /*! Copy constructor */ + FrsImage(const FrsImage& brother) + { + _storedWidth = brother._storedWidth; + _storedHeight = brother._storedHeight; + _width = brother._width; + _height = brother._height; + _Ox = brother._Ox; + _Oy = brother._Oy; + } - /*! Copy constructor */ - FrsImage(const FrsImage& brother) { - _storedWidth = brother._storedWidth; - _storedHeight = brother._storedHeight; - _width = brother._width; - _height = brother._height; - _Ox = brother._Ox; - _Oy = brother._Oy; - } + /*! Builds an FrsImage from its width and height. + * The memory is allocated consequently. + */ + FrsImage(unsigned w, unsigned h) + { + _width = w; + _height = h; + _storedWidth = w; + _storedHeight = h; + _Ox = 0; + _Oy = 0; + } - /*! Builds an FrsImage from its width and height. - * The memory is allocated consequently. - */ - FrsImage(unsigned w, unsigned h) { - _width = w; - _height = h; - _storedWidth = w; - _storedHeight = h; - _Ox = 0; - _Oy = 0; - } + /*! Builds a partial-storing image. + * \param w + * The width of the complete image + * \param h + * The height of the complete image + * \param sw + * The width of the rectangle that will actually be stored. + * \param sh + * The height of the rectangle that will actually be stored. + * \param ox + * The x-abscissa of the origin of the rectangle that will actually be stored. + * \param oy + * The x-abscissa of the origin of the rectangle that will actually be stored. + */ + FrsImage(unsigned w, unsigned h, unsigned sw, unsigned sh, unsigned ox, unsigned oy) + { + _width = w; + _height = h; + _storedWidth = sw; + _storedHeight = sh; + _Ox = ox; + _Oy = oy; + } - /*! Builds a partial-storing image. - * \param w - * The width of the complete image - * \param h - * The height of the complete image - * \param sw - * The width of the rectangle that will actually - * be stored. - * \param sh - * The height of the rectangle that will actually - * be stored. - * \param ox - * The x-abscissa of the origin of the rectangle that will actually - * be stored. - * \param oy - * The x-abscissa of the origin of the rectangle that will actually - * be stored. - */ - FrsImage(unsigned w, unsigned h, unsigned sw, unsigned sh, unsigned ox, unsigned oy) { - _width = w; - _height = h; - _storedWidth = sw; - _storedHeight = sh; - _Ox = ox; - _Oy = oy; - } + /*! Operator= */ + FrsImage& operator=(const FrsImage& brother) + { + _width = brother._width; + _height = brother._height; + _storedWidth = brother._storedWidth; + _storedHeight = brother._storedHeight; + _Ox = brother._Ox; + _Oy = brother._Oy; + return *this; + } - /*! Operator= */ - FrsImage& operator=(const FrsImage& brother) { - _width = brother._width; - _height = brother._height; - _storedWidth = brother._storedWidth; - _storedHeight = brother._storedHeight; - _Ox = brother._Ox; - _Oy = brother._Oy; - return* this; - } + /*! Destructor */ + virtual ~FrsImage() {} - /*! Destructor */ - virtual ~FrsImage() {} + /*! Returns the width of the complete image */ + inline unsigned width() const + { + return _width; + } - /*! Returns the width of the complete image */ - inline unsigned width() const { - return _width; - } - /*! Returns the height of the complete image */ - inline unsigned height() const { - return _height; - } - - /*! Returns the grey value for pixel x,y */ - virtual float pixel(unsigned x, unsigned y) const = 0; + /*! Returns the height of the complete image */ + inline unsigned height() const + { + return _height; + } - /*! Sets the array. - * \param array - * The array containing the values we wish to store. - * Its size is sw*sh. - * \param width - * The width of the complete image - * \param height - * The height of the complete image - * \param sw - * The width of the rectangle that will actually - * be stored. - * \param sh - * The height of the rectangle that will actually - * be stored. - * \param ox - * The x-abscissa of the origin of the rectangle that will actually - * be stored. - * \param oy - * The x-abscissa of the origin of the rectangle that will actually - * be stored. - * \param copy - * If true, the array is copied, otherwise the pointer is - * copied - */ - virtual void setArray(float* array, unsigned width, unsigned height, unsigned sw, unsigned sh, unsigned x, unsigned y, bool copy = true) = 0; - - /*! Returns the array containing the pixels values. - * Its size is sw*sh, i.e. potentially a smaller - * rectangular part of the complete image. - */ - virtual float * getArray() = 0; + /*! Returns the grey value for pixel x,y */ + virtual float pixel(unsigned x, unsigned y) const = 0; - protected: + /*! Sets the array. + * \param array + * The array containing the values we wish to store. + * Its size is sw*sh. + * \param width + * The width of the complete image + * \param height + * The height of the complete image + * \param sw + * The width of the rectangle that will actually be stored. + * \param sh + * The height of the rectangle that will actually be stored. + * \param ox + * The x-abscissa of the origin of the rectangle that will actually be stored. + * \param oy + * The x-abscissa of the origin of the rectangle that will actually be stored. + * \param copy + * If true, the array is copied, otherwise the pointer is copied + */ + virtual void setArray(float *array, unsigned width, unsigned height, unsigned sw, unsigned sh, + unsigned x, unsigned y, bool copy = true) = 0; - unsigned _width; - unsigned _height; - unsigned _storedWidth; - unsigned _storedHeight; - unsigned _Ox; // origin of the stored part - unsigned _Oy; // origin of the stored part + /*! Returns the array containing the pixels values. + * Its size is sw*sh, i.e. potentially a smaller rectangular part of the complete image. + */ + virtual float *getArray() = 0; + +protected: + unsigned _width; + unsigned _height; + unsigned _storedWidth; + unsigned _storedHeight; + unsigned _Ox; // origin of the stored part + unsigned _Oy; // origin of the stored part }; @@ -180,114 +179,130 @@ class FrsImage // RGBImage // /////////////////////////////////////////////////////////////////////////////// - class RGBImage : public FrsImage { - public: +public: + RGBImage() : FrsImage() + { + _rgb = 0; + } - RGBImage() : FrsImage() { - _rgb = 0; - } + RGBImage(const RGBImage& brother) : FrsImage(brother) + { + _rgb = new float[3 * _storedWidth * _storedHeight]; + memcpy(_rgb, brother._rgb, 3 * _storedWidth * _storedHeight * sizeof(float)); + } - RGBImage(const RGBImage& brother) : FrsImage(brother) { - _rgb = new float[3 * _storedWidth * _storedHeight]; - memcpy(_rgb, brother._rgb, 3 * _storedWidth * _storedHeight * sizeof(float)); - } + RGBImage(unsigned w, unsigned h) : FrsImage(w, h) + { + _rgb = new float[3 * _width * _height]; + } - RGBImage(unsigned w, unsigned h) : FrsImage(w, h) { - _rgb = new float[3 * _width * _height]; - } + RGBImage(float *rgb, unsigned w, unsigned h) : FrsImage(w, h) + { + _rgb = new float[3 * _width * _height]; + memcpy(_rgb, rgb, 3 * _width * _height * sizeof(float)); + } - RGBImage(float* rgb, unsigned w, unsigned h) : FrsImage(w, h) { - _rgb = new float[3 * _width * _height]; - memcpy(_rgb, rgb, 3 * _width * _height * sizeof(float)); - } - - /*! Builds an RGB partial image from the useful part buffer. - * \param rgb - * The array of size 3*sw*sh containing the RGB values - * of the sw*sh pixels we need to stored. - * These sw*sh pixels constitute a rectangular part of - * a bigger RGB image containing w*h pixels. - * \param w - * The width of the complete image - * \param h - * The height of the complete image - * \param sw - * The width of the part of the image we want to store and work on - * \param sh - * The height of the part of the image we want to store and work on - */ - RGBImage(float* rgb, unsigned w, unsigned h, unsigned sw, unsigned sh, unsigned ox, unsigned oy) : FrsImage(w, h, sw, sh, ox, oy) { - _rgb = new float[3 * _storedWidth * _storedHeight]; - memcpy(_rgb, rgb, 3 * _storedWidth * _storedHeight * sizeof(float)); - } + /*! Builds an RGB partial image from the useful part buffer. + * \param rgb + * The array of size 3*sw*sh containing the RGB values of the sw*sh pixels we need to stored. + * These sw*sh pixels constitute a rectangular part of a bigger RGB image containing w*h pixels. + * \param w + * The width of the complete image + * \param h + * The height of the complete image + * \param sw + * The width of the part of the image we want to store and work on + * \param sh + * The height of the part of the image we want to store and work on + */ + RGBImage(float *rgb, unsigned w, unsigned h, unsigned sw, unsigned sh, unsigned ox, unsigned oy) + : FrsImage(w, h, sw, sh, ox, oy) + { + _rgb = new float[3 * _storedWidth * _storedHeight]; + memcpy(_rgb, rgb, 3 * _storedWidth * _storedHeight * sizeof(float)); + } - RGBImage& operator=(const RGBImage& brother) { - dynamic_cast(*this) = brother; - _rgb = new float[3 * _storedWidth * _storedHeight]; - memcpy(_rgb, brother._rgb, 3 * _storedWidth * _storedHeight * sizeof(float)); - return* this; - } + RGBImage& operator=(const RGBImage& brother) + { + dynamic_cast(*this) = brother; + _rgb = new float[3 * _storedWidth * _storedHeight]; + memcpy(_rgb, brother._rgb, 3 * _storedWidth * _storedHeight * sizeof(float)); + return *this; + } - virtual ~RGBImage() { - if(_rgb) - delete[] _rgb; - } + virtual ~RGBImage() + { + if(_rgb) + delete[] _rgb; + } - inline float getR(unsigned x, unsigned y) const { - return _rgb[3 * (y-_Oy) * _storedWidth + (x-_Ox) * 3]; - } + inline float getR(unsigned x, unsigned y) const + { + return _rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3]; + } - inline float getG(unsigned x, unsigned y) const { - return _rgb[3 * (y-_Oy) * _storedWidth + (x-_Ox) * 3 + 1]; - } + inline float getG(unsigned x, unsigned y) const + { + return _rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3 + 1]; + } - inline float getB(unsigned x, unsigned y) const { - return _rgb[3 * (y-_Oy) * _storedWidth + (x-_Ox) * 3 + 2]; - } + inline float getB(unsigned x, unsigned y) const + { + return _rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3 + 2]; + } - virtual void setPixel(unsigned x, unsigned y, float r, float g, float b){ - float * tmp = &(_rgb[3 * (y-_Oy) * _storedWidth + (x-_Ox) * 3]); - *tmp = r;++tmp; - *tmp = g;++tmp; - *tmp = b; - } + virtual void setPixel(unsigned x, unsigned y, float r, float g, float b) + { + float *tmp = &(_rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3]); + *tmp = r; + tmp++; + *tmp = g; + tmp++; + *tmp = b; + } - virtual float pixel(unsigned x, unsigned y) const { - float res = 0; - float* tmp = &(_rgb[3 * (y-_Oy) * _storedWidth + (x-_Ox) * 3]); - res += 11 * (*tmp++); - res += 16 * (*tmp++); - res += 5 * (*tmp); - return res / 32; - } + virtual float pixel(unsigned x, unsigned y) const + { + float res = 0.0f; + float *tmp = &(_rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3]); + res += 11.0f * (*tmp); + tmp++; + res += 16.0f * (*tmp); + tmp++; + res += 5.0f * (*tmp); + return res / 32.0f; + } - /*! Sets the RGB array. - * copy - * If true, the array is copied, otherwise the pointer is - * copied - */ - virtual void setArray(float* rgb, unsigned width, unsigned height, unsigned sw, unsigned sh, unsigned x, unsigned y, bool copy = true) { - _width = width; - _height = height; - _storedWidth = sw; - _storedHeight = sh; - _Ox = x; - _Oy = y; - if(!copy) { - _rgb = rgb; - return; - } - - memcpy(_rgb, rgb, 3 * _storedWidth * _storedHeight* sizeof(float)); - } + /*! Sets the RGB array. + * copy + * If true, the array is copied, otherwise the pointer is copied + */ + virtual void setArray(float *rgb, unsigned width, unsigned height, unsigned sw, unsigned sh, + unsigned x, unsigned y, bool copy = true) + { + _width = width; + _height = height; + _storedWidth = sw; + _storedHeight = sh; + _Ox = x; + _Oy = y; + if (!copy) { + _rgb = rgb; + return; + } - virtual float * getArray() {return _rgb;} + memcpy(_rgb, rgb, 3 * _storedWidth * _storedHeight * sizeof(float)); + } - protected: + virtual float *getArray() + { + return _rgb; + } - float* _rgb; +protected: + float *_rgb; }; @@ -298,92 +313,103 @@ class RGBImage : public FrsImage class GrayImage : public FrsImage { - public: +public: + GrayImage() : FrsImage() + { + _lvl = 0; + } - GrayImage() : FrsImage() { - _lvl = 0; - } + GrayImage(const GrayImage& brother) : FrsImage(brother) + { + _lvl = new float[_storedWidth * _storedHeight]; + memcpy(_lvl, brother._lvl, _storedWidth * _storedHeight * sizeof(*_lvl)); + } - GrayImage(const GrayImage& brother) : FrsImage(brother) { - _lvl = new float[_storedWidth*_storedHeight]; - memcpy(_lvl, brother._lvl, _storedWidth*_storedHeight*sizeof(*_lvl)); - } + /*! Builds an empty gray image */ + GrayImage(unsigned w, unsigned h) : FrsImage(w, h) + { + _lvl = new float[_width * _height]; + } - /*! Builds an empty gray image */ - GrayImage(unsigned w, unsigned h) : FrsImage(w, h) { - _lvl = new float[_width*_height]; - } + GrayImage(float *lvl, unsigned w, unsigned h) : FrsImage(w, h) + { + _lvl = new float[_width * _height]; + memcpy(_lvl, lvl, _width * _height * sizeof(*_lvl)); + } - GrayImage(float* lvl, unsigned w, unsigned h) : FrsImage(w, h) { - _lvl = new float[_width*_height]; - memcpy(_lvl, lvl, _width*_height*sizeof(*_lvl)); - } - - /*! Builds a partial image from the useful part buffer. - * \param lvl - * The array of size sw*sh containing the gray values - * of the sw*sh pixels we need to stored. - * These sw*sh pixels constitute a rectangular part of - * a bigger gray image containing w*h pixels. - * \param w - * The width of the complete image - * \param h - * The height of the complete image - * \param sw - * The width of the part of the image we want to store and work on - * \param sh - * The height of the part of the image we want to store and work on - */ - GrayImage(float* lvl, unsigned w, unsigned h, unsigned sw, unsigned sh, unsigned ox, unsigned oy) : FrsImage(w, h, sw, sh, ox, oy) { - _lvl = new float[_storedWidth*_storedHeight]; - memcpy(_lvl, lvl, _storedWidth*_storedHeight*sizeof(float)); - } + /*! Builds a partial image from the useful part buffer. + * \param lvl + * The array of size sw*sh containing the gray values of the sw*sh pixels we need to stored. + * These sw*sh pixels constitute a rectangular part of a bigger gray image containing w*h pixels. + * \param w + * The width of the complete image + * \param h + * The height of the complete image + * \param sw + * The width of the part of the image we want to store and work on + * \param sh + * The height of the part of the image we want to store and work on + */ + GrayImage(float *lvl, unsigned w, unsigned h, unsigned sw, unsigned sh, unsigned ox, unsigned oy) + : FrsImage(w, h, sw, sh, ox, oy) + { + _lvl = new float[_storedWidth * _storedHeight]; + memcpy(_lvl, lvl, _storedWidth * _storedHeight * sizeof(float)); + } - GrayImage& operator=(const GrayImage& brother) { - dynamic_cast(*this) = brother; - _lvl = new float[_storedWidth * _storedHeight]; - memcpy(_lvl, brother._lvl, _storedWidth * _storedHeight * sizeof(float)); - return *this; - } + GrayImage& operator=(const GrayImage& brother) + { + dynamic_cast(*this) = brother; + _lvl = new float[_storedWidth * _storedHeight]; + memcpy(_lvl, brother._lvl, _storedWidth * _storedHeight * sizeof(float)); + return *this; + } - virtual ~GrayImage() { - if(_lvl) - delete[] _lvl; - } + virtual ~GrayImage() + { + if (_lvl) + delete[] _lvl; + } - inline void setPixel(unsigned x, unsigned y, float v){ - _lvl[(y-_Oy) * _storedWidth+ (x-_Ox)] = v; - } + inline void setPixel(unsigned x, unsigned y, float v) + { + _lvl[(y - _Oy) * _storedWidth + (x - _Ox)] = v; + } - inline float pixel(unsigned x, unsigned y) const { - return _lvl[(y-_Oy) * _storedWidth+ (x-_Ox)]; - } + inline float pixel(unsigned x, unsigned y) const + { + return _lvl[(y - _Oy) * _storedWidth + (x - _Ox)]; + } - /*! Sets the array. - * copy - * If true, the array is copie, otherwise the pounsigneder is - * copied - */ - void setArray(float *lvl, unsigned width, unsigned height, unsigned sw, unsigned sh, unsigned x, unsigned y, bool copy = true) { - _width = width; - _height = height; - _storedWidth = sw; - _storedHeight = sh; - _Ox = x; - _Oy = y; - if(!copy) { - _lvl = lvl; - return; - } - - memcpy(_lvl, lvl, _storedWidth * _storedHeight * sizeof(float)); - } - /*! Returns the array containing the gray values. */ - virtual float * getArray() {return _lvl;} + /*! Sets the array. + * copy + * If true, the array is copie, otherwise the pounsigneder is copied + */ + void setArray(float *lvl, unsigned width, unsigned height, unsigned sw, unsigned sh, + unsigned x, unsigned y, bool copy = true) + { + _width = width; + _height = height; + _storedWidth = sw; + _storedHeight = sh; + _Ox = x; + _Oy = y; + if (!copy) { + _lvl = lvl; + return; + } - protected: + memcpy(_lvl, lvl, _storedWidth * _storedHeight * sizeof(float)); + } - float *_lvl; + /*! Returns the array containing the gray values. */ + virtual float *getArray() + { + return _lvl; + } + +protected: + float *_lvl; }; -#endif // IMAGE_H +#endif // __IMAGE_H__ diff --git a/source/blender/freestyle/intern/image/ImagePyramid.cpp b/source/blender/freestyle/intern/image/ImagePyramid.cpp index 542ab7917e3..c7616fbce23 100644 --- a/source/blender/freestyle/intern/image/ImagePyramid.cpp +++ b/source/blender/freestyle/intern/image/ImagePyramid.cpp @@ -1,166 +1,192 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/freestyle/intern/image/ImagePyramid.cpp + * \ingroup freestyle + * \brief Class to represent a pyramid of images + * \author Stephane Grabli + * \date 25/12/2003 + */ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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 "ImagePyramid.h" -#include "Image.h" -#include "GaussianFilter.h" #include +#include "GaussianFilter.h" +#include "Image.h" +#include "ImagePyramid.h" + using namespace std; -//ImagePyramid::ImagePyramid(const GrayImage& level0, unsigned nbLevels){ -// //BuildPyramid(level0,nbLevels); -//} - -ImagePyramid::ImagePyramid(const ImagePyramid& iBrother){ - if(!_levels.empty()){ - for(vector::iterator im=_levels.begin(), imend=_levels.end(); - im!=imend; - ++im){ - _levels.push_back(new GrayImage(**im)); - } - } -} -ImagePyramid::~ImagePyramid(){ - if(!_levels.empty()){ - for(vector::iterator im=_levels.begin(), imend=_levels.end(); - im!=imend; - ++im){ - delete (*im); - } - _levels.clear(); - } -} - -GrayImage * ImagePyramid::getLevel(int l){ - return _levels[l]; -} - -float ImagePyramid::pixel(int x, int y, int level){ - GrayImage *img = _levels[level]; - if(0 == level){ - return img->pixel(x,y); - } - unsigned int i = 1<>level; - unsigned int sy = y>>level; - if(sx >= img->width()) - sx = img->width()-1; - if(sy >= img->height()) - sy = img->height()-1; - - // bilinear interpolation - float A = i*(sx+1)-x; - float B = x-i*sx; - float C = i*(sy+1)-y; - float D = y-i*sy; - - float P1(0), P2(0); - P1 = A*img->pixel(sx,sy); - if(sx < img->width()-1){ - if(x%i != 0) - P1 += B*img->pixel(sx+1,sy); - }else{ - P1 += B*img->pixel(sx,sy); - } - if(syheight()-1){ - if(y%i != 0){ - P2 = A*img->pixel(sx,sy+1); - if(sx < img->width()-1){ - if(x%i != 0) - P2 += B*img->pixel(sx+1,sy+1); - }else{ - P2 += B*img->pixel(sx,sy+1); - } - } - }else{ - P2 = P1; - } - return (1.f/(float)(1<<2*level))*(C*P1 + D*P2); -} - -int ImagePyramid::width(int level){ - return _levels[level]->width(); -} - -int ImagePyramid::height(int level){ - return _levels[level]->height(); -} - -GaussianPyramid::GaussianPyramid(const GrayImage& level0, unsigned nbLevels, float iSigma) - : ImagePyramid() +#if 0 +ImagePyramid::ImagePyramid(const GrayImage& level0, unsigned nbLevels) { - _sigma = iSigma; - BuildPyramid(level0,nbLevels); -} -GaussianPyramid::GaussianPyramid(GrayImage* level0, unsigned nbLevels, float iSigma) - : ImagePyramid() + BuildPyramid(level0,nbLevels); +} +#endif + +ImagePyramid::ImagePyramid(const ImagePyramid& iBrother) { - _sigma = iSigma; - BuildPyramid(level0,nbLevels); + if (!_levels.empty()) { + for (vector::iterator im = _levels.begin(), imend = _levels.end(); im != imend; ++im) { + _levels.push_back(new GrayImage(**im)); + } + } } -GaussianPyramid::GaussianPyramid(const GaussianPyramid& iBrother) -: ImagePyramid(iBrother){ - _sigma = iBrother._sigma; -} -void GaussianPyramid::BuildPyramid(const GrayImage& level0, unsigned nbLevels){ - GrayImage *pLevel = new GrayImage(level0); - BuildPyramid(pLevel, nbLevels); +ImagePyramid::~ImagePyramid() +{ + if (!_levels.empty()) { + for (vector::iterator im = _levels.begin(), imend = _levels.end(); im != imend; ++im) { + delete (*im); + } + _levels.clear(); + } } -void GaussianPyramid::BuildPyramid(GrayImage* level0, unsigned nbLevels){ - GrayImage *pLevel = level0; - _levels.push_back(pLevel); - GaussianFilter gf(_sigma); - // build the nbLevels: - unsigned w = pLevel->width(); - unsigned h = pLevel->height(); - if(nbLevels!=0) - { - for(unsigned i=0; iwidth()>>1; - h = pLevel->height()>>1; - GrayImage *img = new GrayImage(w,h); - for(unsigned y=0; y(pLevel, 2*x,2*y); - img->setPixel(x,y,v); - } - } - _levels.push_back(img); - pLevel = img; - } - }else{ - while((w>1) && (h>1)){ - w = pLevel->width()>>1; - h = pLevel->height()>>1; - GrayImage *img = new GrayImage(w,h); - for(unsigned y=0; y(pLevel, 2*x,2*y); - img->setPixel(x,y,v); - } - } - _levels.push_back(img); - pLevel = img; - } - } +GrayImage * ImagePyramid::getLevel(int l) +{ + return _levels[l]; +} + +float ImagePyramid::pixel(int x, int y, int level) +{ + GrayImage *img = _levels[level]; + if (0 == level) { + return img->pixel(x, y); + } + unsigned int i = 1 << level; + unsigned int sx = x >> level; + unsigned int sy = y >> level; + if (sx >= img->width()) + sx = img->width() - 1; + if (sy >= img->height()) + sy = img->height() - 1; + + // bilinear interpolation + float A = i * (sx + 1) - x; + float B = x - i * sx; + float C = i * (sy + 1) - y; + float D = y - i * sy; + + float P1(0), P2(0); + P1 = A * img->pixel(sx, sy); + if (sx < img->width() - 1) { + if (x % i != 0) + P1 += B * img->pixel(sx + 1, sy); + } + else { + P1 += B * img->pixel(sx, sy); + } + if (sy < img->height() - 1) { + if (y % i != 0) { + P2 = A * img->pixel(sx, sy + 1); + if (sx < img->width() - 1) { + if (x % i != 0) + P2 += B * img->pixel(sx + 1, sy + 1); + } + else { + P2 += B * img->pixel(sx, sy + 1); + } + } + } + else { + P2 = P1; + } + return (1.0f / (float)(1 << (2 * level))) * (C * P1 + D * P2); +} + +int ImagePyramid::width(int level) +{ + return _levels[level]->width(); +} + +int ImagePyramid::height(int level) +{ + return _levels[level]->height(); +} + +GaussianPyramid::GaussianPyramid(const GrayImage& level0, unsigned nbLevels, float iSigma) : ImagePyramid() +{ + _sigma = iSigma; + BuildPyramid(level0, nbLevels); +} + +GaussianPyramid::GaussianPyramid(GrayImage* level0, unsigned nbLevels, float iSigma) : ImagePyramid() +{ + _sigma = iSigma; + BuildPyramid(level0, nbLevels); +} + +GaussianPyramid::GaussianPyramid(const GaussianPyramid& iBrother) : ImagePyramid(iBrother) +{ + _sigma = iBrother._sigma; +} + +void GaussianPyramid::BuildPyramid(const GrayImage& level0, unsigned nbLevels) +{ + GrayImage *pLevel = new GrayImage(level0); + BuildPyramid(pLevel, nbLevels); +} + +void GaussianPyramid::BuildPyramid(GrayImage* level0, unsigned nbLevels) +{ + GrayImage *pLevel = level0; + _levels.push_back(pLevel); + GaussianFilter gf(_sigma); + // build the nbLevels: + unsigned w = pLevel->width(); + unsigned h = pLevel->height(); + if (nbLevels != 0) { + for (unsigned int i = 0; i < nbLevels; ++i) { //soc + w = pLevel->width() >> 1; + h = pLevel->height() >> 1; + GrayImage *img = new GrayImage(w, h); + for (unsigned int y = 0; y < h; ++y) { + for (unsigned int x = 0; x < w; ++x) { + float v = gf.getSmoothedPixel(pLevel, 2 * x, 2 * y); + img->setPixel(x, y, v); + } + } + _levels.push_back(img); + pLevel = img; + } + } + else { + while ((w > 1) && (h > 1)) { + w = pLevel->width() >> 1; + h = pLevel->height() >> 1; + GrayImage *img = new GrayImage(w, h); + for (unsigned int y = 0; y < h; ++y) { + for (unsigned int x = 0; x < w; ++x) { + float v = gf.getSmoothedPixel(pLevel, 2 * x, 2 * y); + img->setPixel(x, y, v); + } + } + _levels.push_back(img); + pLevel = img; + } + } } diff --git a/source/blender/freestyle/intern/image/ImagePyramid.h b/source/blender/freestyle/intern/image/ImagePyramid.h index 9e326757f02..4bab663318e 100644 --- a/source/blender/freestyle/intern/image/ImagePyramid.h +++ b/source/blender/freestyle/intern/image/ImagePyramid.h @@ -1,92 +1,116 @@ -// -// Filename : ImagePyramid.h -// Author(s) : Stephane Grabli -// Purpose : Class to represent a pyramid of images -// Date of creation : 25/12/2003 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __IMAGEPYRAMID_H__ +#define __IMAGEPYRAMID_H__ -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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. -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/** \file blender/freestyle/intern/image/ImagePyramid.h + * \ingroup freestyle + * \brief Class to represent a pyramid of images + * \author Stephane Grabli + * \date 25/12/2003 + */ -#ifndef IMAGEPYRAMID_H -# define IMAGEPYRAMID_H - -#include "../system/FreestyleConfig.h" #include -class GrayImage; -class LIB_IMAGE_EXPORT ImagePyramid{ -protected: - std::vector _levels; - -public: - ImagePyramid(){} - ImagePyramid(const ImagePyramid& iBrother); - //ImagePyramid(const GrayImage& level0, unsigned nbLevels); - virtual ~ImagePyramid(); +#include "../system/FreestyleConfig.h" - /*! Builds the pyramid. - * must be overloaded by inherited classes. - * if nbLevels==0, the complete pyramid is built - */ - virtual void BuildPyramid(const GrayImage& level0, unsigned nbLevels) = 0; - - /*! Builds a pyramid without copying the base level */ - virtual void BuildPyramid(GrayImage* level0, unsigned nbLevels) = 0; - - virtual GrayImage * getLevel(int l); - /*! Returns the pixel x,y using bilinear interpolation. - * \param x - * the abscissa specified in the finest level coordinate system - * \param y - * the ordinate specified in the finest level coordinate system - * \param level - * the level from which we want the pixel to be evaluated - */ - virtual float pixel(int x, int y, int level=0); - /*! Returns the width of the level-th level image */ - virtual int width(int level=0); - /*! Returns the height of the level-th level image */ - virtual int height(int level=0); - /*! Returns the number of levels in the pyramid */ - inline int getNumberOfLevels() const { return _levels.size();} -}; +class GrayImage; + +class LIB_IMAGE_EXPORT ImagePyramid +{ +protected: + std::vector _levels; + +public: + ImagePyramid(){} + ImagePyramid(const ImagePyramid& iBrother); + //ImagePyramid(const GrayImage& level0, unsigned nbLevels); + virtual ~ImagePyramid(); + + /*! Builds the pyramid. + * must be overloaded by inherited classes. + * if nbLevels==0, the complete pyramid is built + */ + virtual void BuildPyramid(const GrayImage& level0, unsigned nbLevels) = 0; + + /*! Builds a pyramid without copying the base level */ + virtual void BuildPyramid(GrayImage* level0, unsigned nbLevels) = 0; + + virtual GrayImage * getLevel(int l); + /*! Returns the pixel x,y using bilinear interpolation. + * \param x + * the abscissa specified in the finest level coordinate system + * \param y + * the ordinate specified in the finest level coordinate system + * \param level + * the level from which we want the pixel to be evaluated + */ + virtual float pixel(int x, int y, int level=0); + + /*! Returns the width of the level-th level image */ + virtual int width(int level=0); + + /*! Returns the height of the level-th level image */ + virtual int height(int level=0); + + /*! Returns the number of levels in the pyramid */ + inline int getNumberOfLevels() const + { + return _levels.size(); + } +}; class LIB_IMAGE_EXPORT GaussianPyramid : public ImagePyramid { protected: - float _sigma; + float _sigma; + public: - GaussianPyramid(float iSigma=1.f) : ImagePyramid() {_sigma=iSigma;} - GaussianPyramid(const GrayImage& level0, unsigned nbLevels, float iSigma=1.f); - GaussianPyramid(GrayImage* level0, unsigned nbLevels, float iSigma=1.f); - GaussianPyramid(const GaussianPyramid& iBrother); - virtual ~GaussianPyramid(){} + GaussianPyramid(float iSigma=1.f) : ImagePyramid() + { + _sigma = iSigma; + } - virtual void BuildPyramid(const GrayImage& level0, unsigned nbLevels); - virtual void BuildPyramid(GrayImage* level0, unsigned nbLevels); - /* accessors */ - inline float getSigma() const {return _sigma;} - /* modifiers */ + GaussianPyramid(const GrayImage& level0, unsigned nbLevels, float iSigma=1.0f); + GaussianPyramid(GrayImage* level0, unsigned nbLevels, float iSigma=1.0f); + GaussianPyramid(const GaussianPyramid& iBrother); + virtual ~GaussianPyramid() {} + virtual void BuildPyramid(const GrayImage& level0, unsigned nbLevels); + virtual void BuildPyramid(GrayImage* level0, unsigned nbLevels); + + /* accessors */ + inline float getSigma() const + { + return _sigma; + } + + /* modifiers */ }; -#endif // IMAGEPYRAMID_H + +#endif // __IMAGEPYRAMID_H__