diff options
Diffstat (limited to 'source')
32 files changed, 6511 insertions, 6130 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 -// -/////////////////////////////////////////////////////////////////////////////// - - -// -// 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 +/* + * ***** 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__ + +/** \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 Point> class BBox { - public: - - inline BBox() { - _empty = true; - } - - template <class T> - inline BBox(const T& min_in, const T& max_in) : _min(min_in), _max(max_in) { - _empty = false; - } - - template <class T> - inline BBox(const BBox<T>& b) : _min(b.getMin()), _max(b.getMax()) { - _empty = false; - } - - template <class T> - 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 bool empty() const { - return _empty; - } - - inline const Point& getMin() const { - return _min; - } - - inline const Point& getMax() const { - return _max; - } - - inline BBox<Point>& operator=(const BBox<Point>& b) { - _min = b.getMin(); - _max = b.getMax(); - _empty = false; - return *this; - } - - inline BBox<Point>& operator+=(const BBox<Point>& 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])) - return false; - } - return true; - - } +public: + inline BBox() + { + _empty = true; + } + + template <class T> + inline BBox(const T& min_in, const T& max_in) : _min(min_in), _max(max_in) + { + _empty = false; + } + + template <class T> + inline BBox(const BBox<T>& b) : _min(b.getMin()), _max(b.getMax()) + { + _empty = false; + } + + template <class T> + 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; + } + + inline void clear() + { + _empty = true; + } + + inline bool empty() const + { + return _empty; + } + + inline const Point& getMin() const + { + return _min; + } + + inline const Point& getMax() const + { + return _max; + } + + inline BBox<Point>& operator=(const BBox<Point>& b) + { + _min = b.getMin(); + _max = b.getMax(); + _empty = false; + return *this; + } + + inline BBox<Point>& operator+=(const BBox<Point>& 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 bool inside(const Point& p) + { + if (empty()) + return false; + for (unsigned int i = 0; i < Point::dim(); i++) { + if ((_min[i]>p[i]) || (_max[i]<p[i])) + return false; + } + return true; + } private: - - Point _min; - Point _max; - bool _empty; + Point _min; + Point _max; + bool _empty; }; template <class Point> BBox<Point>& operator+(const BBox<Point> &b1, const BBox<Point> &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<Point>(new_min, new_max); + return BBox<Point>(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 @@ - -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** 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/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; - - // Compute the rightmost part of the matrix: - vector<Vec2d>::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(); - - 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.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; - } + if (_ControlPolygon.size() != 4) + return; + + // Compute the rightmost part of the matrix: + vector<Vec2d>::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(); + + 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<Vec2d>& iPoints, double error) { - FitCurveWrapper fitcurve; - _currentSegment = new BezierCurveSegment; - vector<Vec2d> curve; - - fitcurve.FitCurve(iPoints, curve, error); - int i=0; - vector<Vec2d>::iterator v,vend; - for(v=curve.begin(),vend=curve.end(); - v!=vend; - ++v) - { - if((i == 0) || (i%4 != 0)) - AddControlPoint(*v); - ++i; - } + FitCurveWrapper fitcurve; + _currentSegment = new BezierCurveSegment; + vector<Vec2d> curve; + + fitcurve.FitCurve(iPoints, curve, error); + int i = 0; + vector<Vec2d>::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 -// -/////////////////////////////////////////////////////////////////////////////// - - -// -// 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 +/* + * ***** 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__ + +/** \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 <vector> -#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<Vec2d> _ControlPolygon; - std::vector<Vec2d> _Vertices; + std::vector<Vec2d> _ControlPolygon; + std::vector<Vec2d> _Vertices; public: - BezierCurveSegment(); - virtual ~BezierCurveSegment(); + BezierCurveSegment(); + virtual ~BezierCurveSegment(); + + void AddControlPoint(const Vec2d& iPoint); + void Build(); + + inline int size() const + { + return _ControlPolygon.size(); + } - void AddControlPoint(const Vec2d& iPoint); - void Build(); - inline int size() const {return _ControlPolygon.size();} - inline std::vector<Vec2d>& vertices() {return _Vertices;} + inline std::vector<Vec2d>& vertices() + { + return _Vertices; + } }; class LIB_GEOMETRY_EXPORT BezierCurve { private: - std::vector<Vec2d> _ControlPolygon; - std::vector<BezierCurveSegment*> _Segments; - BezierCurveSegment *_currentSegment; + std::vector<Vec2d> _ControlPolygon; + std::vector<BezierCurveSegment*> _Segments; + BezierCurveSegment *_currentSegment; public: - BezierCurve(); - BezierCurve(std::vector<Vec2d>& iPoints, double error=4.0); - virtual ~BezierCurve(); + BezierCurve(); + BezierCurve(std::vector<Vec2d>& iPoints, double error=4.0); + virtual ~BezierCurve(); + + void AddControlPoint(const Vec2d& iPoint); + + std::vector<Vec2d>& controlPolygon() + { + return _ControlPolygon; + } - void AddControlPoint(const Vec2d& iPoint); - std::vector<Vec2d>& controlPolygon() {return _ControlPolygon;} - std::vector<BezierCurveSegment*>& segments() {return _Segments;} + std::vector<BezierCurveSegment*>& 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 -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** 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 + */ -// -// 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 <cassert> -#ifndef FASTGRID_H -# define FASTGRID_H +#include "Grid.h" -# include "Grid.h" -# include <cassert> -/*! 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 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(); -protected: + /*! 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); - Cell** _cells; - unsigned _cells_size; + /*! Fills the case p with the cell iCell */ + virtual void fillCell(const Vec3u& p, Cell& cell); + +protected: + 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 <cstdlib> // for malloc and free #include <stdio.h> #include <math.h> + #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 */ - - bezCurve = (Vector2 *)malloc(4 * sizeof(Vector2)); - nPts = last - first + 1; - - - /* Compute the A's */ - for (i = 0; i < nPts; i++) { - Vector2 v1, v2; + 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; + + /* 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])))))); - - - 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]; - - /* 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; - - - /* 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; + 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); + } + + /* 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]) * 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; 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); - } - - /* 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); -} + 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 */ - - uPrime = (double *)malloc(nPts * sizeof(double)); - for (i = first; i <= last; i++) { - uPrime[i-first] = NewtonRaphsonRootFind(bezCurve, d[i], u[i- - first]); - } - return (uPrime); -} - + 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); +} /* - * 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 */ - - /* Copy array */ - Vtemp = (Vector2 *)malloc((unsigned)((degree+1) - * sizeof (Vector2))); - for (i = 0; i <= degree; i++) { + 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++) { 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; - - 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; + 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; } - /* - * 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 */ - - *splitPoint = (last - first + 1)/2; - maxDist = 0.0; - for (i = first + 1; i < last; i++) { - P = BezierII(3, bezCurve, u[i-first]); + 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]); 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<n+1; ++i) - _vertices.push_back(curve[i]); + for (int i = 0; i < n + 1; ++i) + _vertices.push_back(curve[i]); } void FitCurveWrapper::FitCurve(vector<Vec2d>& data, vector<Vec2d>& oCurve, double error) { - int size = data.size(); - Vector2 *d = new Vector2[size]; - for(int i=0; i<size; ++i) - { - d[i][0] = data[i][0]; - d[i][1] = data[i][1]; - } - - FitCurve(d,size,error); - - // copy results - for(vector<Vector2>::iterator v=_vertices.begin(), vend=_vertices.end(); - v!=vend; - ++v) - { - oCurve.push_back(Vec2d(v->x(), v->y())) ; - } - + int size = data.size(); + Vector2 *d = new Vector2[size]; + for (int i = 0; i < size; ++i) { + d[i][0] = data[i][0]; + d[i][1] = data[i][1]; + } + + FitCurve(d, size, error); + + // copy results + for (vector<Vector2>::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; - - 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; - - bezCurve = (Vector2 *)malloc(4 * sizeof(Vector2)); + 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; + + /* 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[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); + /* 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) { + /* 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); + free((void*)u); + free((void*)bezCurve); return; - } - + } - /* If error not too large, try some reparameterization */ - /* and iteration */ - if (maxError < iterationError) { + /* 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; + 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); + /* 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 -// -/////////////////////////////////////////////////////////////////////////////// - - -// -// 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 +/* + * ***** 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__ + +/** \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 <vector> -#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; -typedef Point2 Vector2; + 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<Vector2> _vertices; + std::vector<Vector2> _vertices; public: - 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<Vec2d>& data, std::vector<Vec2d>& oCurve, double error); + 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<Vec2d>& data, std::vector<Vec2d>& 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<unsigned> Vec2u; - typedef VecMat::Vec2<int> Vec2i; - typedef VecMat::Vec2<float> Vec2f; - typedef VecMat::Vec2<double> Vec2d; - typedef VecMat::Vec2<real> Vec2r; +typedef VecMat::Vec2<unsigned> Vec2u; +typedef VecMat::Vec2<int> Vec2i; +typedef VecMat::Vec2<float> Vec2f; +typedef VecMat::Vec2<double> Vec2d; +typedef VecMat::Vec2<real> Vec2r; - typedef VecMat::Vec3<unsigned> Vec3u; - typedef VecMat::Vec3<int> Vec3i; - typedef VecMat::Vec3<float> Vec3f; - typedef VecMat::Vec3<double> Vec3d; - typedef VecMat::Vec3<real> Vec3r; +typedef VecMat::Vec3<unsigned> Vec3u; +typedef VecMat::Vec3<int> Vec3i; +typedef VecMat::Vec3<float> Vec3f; +typedef VecMat::Vec3<double> Vec3d; +typedef VecMat::Vec3<real> Vec3r; - typedef VecMat::HVec3<unsigned> HVec3u; - typedef VecMat::HVec3<int> HVec3i; - typedef VecMat::HVec3<float> HVec3f; - typedef VecMat::HVec3<double> HVec3d; - typedef VecMat::HVec3<real> HVec3r; +typedef VecMat::HVec3<unsigned> HVec3u; +typedef VecMat::HVec3<int> HVec3i; +typedef VecMat::HVec3<float> HVec3f; +typedef VecMat::HVec3<double> HVec3d; +typedef VecMat::HVec3<real> HVec3r; - typedef VecMat::SquareMatrix<unsigned, 2> Matrix22u; - typedef VecMat::SquareMatrix<int, 2> Matrix22i; - typedef VecMat::SquareMatrix<float, 2> Matrix22f; - typedef VecMat::SquareMatrix<double, 2> Matrix22d; - typedef VecMat::SquareMatrix<real, 2> Matrix22r; +typedef VecMat::SquareMatrix<unsigned, 2> Matrix22u; +typedef VecMat::SquareMatrix<int, 2> Matrix22i; +typedef VecMat::SquareMatrix<float, 2> Matrix22f; +typedef VecMat::SquareMatrix<double, 2> Matrix22d; +typedef VecMat::SquareMatrix<real, 2> Matrix22r; - typedef VecMat::SquareMatrix<unsigned, 3> Matrix33u; - typedef VecMat::SquareMatrix<int, 3> Matrix33i; - typedef VecMat::SquareMatrix<float, 3> Matrix33f; - typedef VecMat::SquareMatrix<double, 3> Matrix33d; - typedef VecMat::SquareMatrix<real, 3> Matrix33r; +typedef VecMat::SquareMatrix<unsigned, 3> Matrix33u; +typedef VecMat::SquareMatrix<int, 3> Matrix33i; +typedef VecMat::SquareMatrix<float, 3> Matrix33f; +typedef VecMat::SquareMatrix<double, 3> Matrix33d; +typedef VecMat::SquareMatrix<real, 3> Matrix33r; - typedef VecMat::SquareMatrix<unsigned, 4> Matrix44u; - typedef VecMat::SquareMatrix<int, 4> Matrix44i; - typedef VecMat::SquareMatrix<float, 4> Matrix44f; - typedef VecMat::SquareMatrix<double, 4> Matrix44d; - typedef VecMat::SquareMatrix<real, 4> Matrix44r; +typedef VecMat::SquareMatrix<unsigned, 4> Matrix44u; +typedef VecMat::SquareMatrix<int, 4> Matrix44i; +typedef VecMat::SquareMatrix<float, 4> Matrix44f; +typedef VecMat::SquareMatrix<double, 4> Matrix44d; +typedef VecMat::SquareMatrix<real, 4> 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 @@ - -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// - -//#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 <hash_map.h> -//#else -//# include <hash_map> -//#endif +/* + * ***** 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/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 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 <hash_map.h> +#else +# include <hash_map> +#endif +#endif #include <stdio.h> #include <list> #include <map> -#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<IndexedVertex> 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(); - - // build the indices mapping array: - unsigned *mapIndices = new unsigned[iVSize/3]; - *oVertices = new real[iVSize]; - list<IndexedVertex>::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; - } - - - // Build the final index array: - *oIndices = new unsigned[iISize]; - for(i=0; i<iISize; i++) - { - (*oIndices)[i] = 3*mapIndices[iIndices[i]/3]; - } - - delete [] mapIndices; + // First, we build a list of IndexVertex: + list<IndexedVertex> 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(); + + // build the indices mapping array: + unsigned *mapIndices = new unsigned[iVSize / 3]; + *oVertices = new real[iVSize]; + list<IndexedVertex>::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; + } + + // Build the final index array: + *oIndices = new unsigned[iISize]; + for (i = 0; i < iISize; i++) { + (*oIndices)[i] = 3 * mapIndices[iIndices[i] / 3]; + } + + delete [] mapIndices; } -void GeomCleaner::CompressIndexedVertexArray(const real *iVertices, unsigned iVSize, - const unsigned *iIndices, unsigned iISize, - real **oVertices, unsigned *oVSize, - unsigned **oIndices) +void GeomCleaner::CompressIndexedVertexArray(const real *iVertices, unsigned iVSize, const unsigned *iIndices, + unsigned iISize, real **oVertices, unsigned *oVSize, unsigned **oIndices) { - // First, we build a list of IndexVertex: - vector<Vec3r> 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<Vec3r>::iterator v = vertices.begin(); - - vector<Vec3r> compressedVertices; - Vec3r previous = *v; - mapVertex[0] = 0; - compressedVertices.push_back(vertices.front()); - - 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++; - } - - // 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; - } - - // Map the index array: - *oIndices = new unsigned[iISize]; - for(i=0; i<iISize; i++) - { - (*oIndices)[i] = 3*mapVertex[iIndices[i]/3]; - } - - delete [] mapVertex; + // First, we build a list of IndexVertex: + vector<Vec3r> 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<Vec3r>::iterator v = vertices.begin(); + + vector<Vec3r> compressedVertices; + Vec3r previous = *v; + mapVertex[0] = 0; + compressedVertices.push_back(vertices.front()); + + 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++; + } + + // 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; + } + + // Map the index array: + *oIndices = new unsigned[iISize]; + for (i = 0; i < iISize; i++) { + (*oIndices)[i] = 3 * mapVertex[iIndices[i] / 3]; + } + + delete [] mapVertex; } -void GeomCleaner::SortAndCompressIndexedVertexArray(const float *iVertices, unsigned iVSize, - const unsigned *iIndices, unsigned iISize, - real **oVertices, unsigned *oVSize, +void GeomCleaner::SortAndCompressIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices, + unsigned iISize, real **oVertices, unsigned *oVSize, unsigned **oIndices) { - - // tmp arrays used to store the sorted data: - real *tmpVertices; - unsigned *tmpIndices; - - Chronometer chrono; - // Sort data - chrono.start(); - GeomCleaner::SortIndexedVertexArray(iVertices, iVSize, - iIndices, iISize, - &tmpVertices, &tmpIndices - ); - printf("Sorting: %lf\n", chrono.stop()); - - // compress data - chrono.start(); - GeomCleaner::CompressIndexedVertexArray(tmpVertices, iVSize, - tmpIndices, iISize, - oVertices, oVSize, - oIndices); - printf("Merging: %lf\n", chrono.stop()); - - // deallocates memory: - delete [] tmpVertices; - delete [] tmpIndices; + // tmp arrays used to store the sorted data: + real *tmpVertices; + unsigned *tmpIndices; + + Chronometer chrono; + // Sort data + chrono.start(); + GeomCleaner::SortIndexedVertexArray(iVertices, iVSize, iIndices, iISize, &tmpVertices, &tmpIndices); + printf("Sorting: %lf\n", chrono.stop()); + + // compress data + chrono.start(); + GeomCleaner::CompressIndexedVertexArray(tmpVertices, iVSize, tmpIndices, iISize, oVertices, oVSize, oIndices); + printf("Merging: %lf\n", chrono.stop()); + + // deallocates memory: + delete [] tmpVertices; + delete [] tmpIndices; } /*! Defines a hash table used for searching the Cells */ struct GeomCleanerHasher{ #define _MUL 950706376UL #define _MOD 2147483647UL - inline size_t operator() (const Vec3r& 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 Vec3r& 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 }; -void GeomCleaner::CleanIndexedVertexArray(const float *iVertices, unsigned iVSize, - const unsigned *iIndices, unsigned iISize, - real **oVertices, unsigned *oVSize, - unsigned **oIndices) +void GeomCleaner::CleanIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices, + unsigned iISize, real **oVertices, unsigned *oVSize, unsigned **oIndices) { - typedef map<Vec3r, unsigned> cleanHashTable; - vector<Vec3r> vertices; - unsigned i; - for(i=0; i<iVSize; i+= 3) - vertices.push_back(Vec3r(iVertices[i], iVertices[i+1], iVertices[i+2])); - - cleanHashTable ht; - vector<unsigned> newIndices; - vector<Vec3r> newVertices; - - // elimination of needless points - unsigned currentIndex = 0; - vector<Vec3r>::const_iterator v = vertices.begin(); - vector<Vec3r>::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]; + typedef map<Vec3r, unsigned> cleanHashTable; + vector<Vec3r> vertices; + unsigned i; + for (i = 0; i < iVSize; i += 3) + vertices.push_back(Vec3r(iVertices[i], iVertices[i + 1], iVertices[i + 2])); + + cleanHashTable ht; + vector<unsigned> newIndices; + vector<Vec3r> newVertices; + + // elimination of needless points + unsigned currentIndex = 0; + vector<Vec3r>::const_iterator v = vertices.begin(); + vector<Vec3r>::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 -// -/////////////////////////////////////////////////////////////////////////////// - - -// -// 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 GEOMCLEANER_H -# define GEOMCLEANER_H - -# include "../system/FreestyleConfig.h" -# include "Geom.h" +/* + * ***** 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__ + +/** \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 + */ + +#include "Geom.h" + +#include "../system/FreestyleConfig.h" using namespace Geometry; class LIB_GEOMETRY_EXPORT GeomCleaner { public: - - 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<v2.x, or v1.x=v2.x && v1.y < v2.y - * or v1.x=v2.y && v1.y=v2.y && v1.z < v2.z. - * The array is organized as a 3-float serie giving - * the vertices coordinates: XYZXYZXYZ... - * oIndices - * Output corresponding to the iIndices array but - * reorganized in order to match the sorted vertex array. - */ - - static void SortIndexedVertexArray(const float *iVertices, unsigned iVSize, - const unsigned *iIndices, unsigned iISize, - real **oVertices, - unsigned **oIndices); - - /*! Compress a SORTED indexed vertex array by eliminating - * multiple appearing occurences of a single vertex. - * iVertices - * The SORTED vertex array to compress. 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 - * The vertex array, result of the compression. - * The array is organized as a 3-float serie giving - * the vertices coordinates: XYZXYZXYZ... - * oVSize - * The size of oVertices. - * oIndices - * The indices array, reorganized to match the compressed - * oVertices array. - */ - - static void CompressIndexedVertexArray(const real *iVertices, unsigned iVSize, - const unsigned *iIndices, unsigned iISize, - real **oVertices, unsigned *oVSize, - unsigned **oIndices); - - /*! Sorts and compress an array of indexed vertices. - * iVertices - * The vertex array to sort then compress. 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 - * The vertex array, result of the sorting-compression. - * The array is organized as a 3-float serie giving - * the vertices coordinates: XYZXYZXYZ... - * oVSize - * The size of oVertices. - * oIndices - * The indices array, reorganized to match the sorted and compressed - * oVertices array. - */ - - static void SortAndCompressIndexedVertexArray(const float *iVertices, unsigned iVSize, - const unsigned *iIndices, unsigned iISize, - real **oVertices, unsigned *oVSize, - unsigned **oIndices); - - /*! Cleans an indexed vertex array. (Identical to - * SortAndCompress except that we use here a hash - * table to create the new array.) - * iVertices - * The vertex array to sort then compress. 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 - * The vertex array, result of the sorting-compression. - * The array is organized as a 3-float serie giving - * the vertices coordinates: XYZXYZXYZ... - * oVSize - * The size of oVertices. - * oIndices - * The indices array, reorganized to match the sorted and compressed - * oVertices array. - */ - - static void CleanIndexedVertexArray(const float *iVertices, unsigned iVSize, - const unsigned *iIndices, unsigned iISize, - real **oVertices, unsigned *oVSize, - unsigned **oIndices); + 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<v2.x, + * or v1.x=v2.x && v1.y < v2.y or v1.x=v2.y && v1.y=v2.y && v1.z < v2.z. + * The array is organized as a 3-float serie giving the vertices coordinates: XYZXYZXYZ... + * oIndices + * Output corresponding to the iIndices array but reorganized in order to match the sorted vertex array. + */ + static void SortIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices, + unsigned iISize, real **oVertices, unsigned **oIndices); + + /*! Compress a SORTED indexed vertex array by eliminating multiple appearing occurences of a single vertex. + * iVertices + * The SORTED vertex array to compress. 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 + * The vertex array, result of the compression. + * The array is organized as a 3-float serie giving the vertices coordinates: XYZXYZXYZ... + * oVSize + * The size of oVertices. + * oIndices + * The indices array, reorganized to match the compressed oVertices array. + */ + static void CompressIndexedVertexArray(const real *iVertices, unsigned iVSize, const unsigned *iIndices, + unsigned iISize, real **oVertices, unsigned *oVSize, unsigned **oIndices); + + /*! Sorts and compress an array of indexed vertices. + * iVertices + * The vertex array to sort then compress. 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 + * The vertex array, result of the sorting-compression. + * The array is organized as a 3-float serie giving the vertices coordinates: XYZXYZXYZ... + * oVSize + * The size of oVertices. + * oIndices + * The indices array, reorganized to match the sorted and compressed oVertices array. + */ + static void SortAndCompressIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices, + unsigned iISize, real **oVertices, unsigned *oVSize, + unsigned **oIndices); + + /*! Cleans an indexed vertex array. (Identical to SortAndCompress except that we use here a hash table + * to create the new array.) + * iVertices + * The vertex array to sort then compress. 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 + * The vertex array, result of the sorting-compression. + * The array is organized as a 3-float serie giving the vertices coordinates: XYZXYZXYZ... + * oVSize + * The size of oVertices. + * oIndices + * The indices array, reorganized to match the sorted and compressed oVertices array. + */ + static void CleanIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices, + unsigned iISize, real **oVertices, unsigned *oVSize, unsigned **oIndices); }; /*! Binary operators */ //inline bool operator<(const IndexedVertex& iv1, const IndexedVertex& iv2); -/*! Class Indexed Vertex. Used to represent - * an indexed vertex by storing the vertex - * coordinates as well as its index - */ +/*! Class Indexed Vertex. Used to represent an indexed vertex by storing the vertex coordinates as well as its index */ class IndexedVertex { -public: - private: - Vec3r _Vector; - unsigned _index; + Vec3r _Vector; + unsigned _index; + public: - inline IndexedVertex() {} - inline IndexedVertex(Vec3r iVector, unsigned iIndex) - { - _Vector = iVector; - _index = iIndex; - } - /*! accessors */ - inline const Vec3r& vector() const {return _Vector;} - inline unsigned index() {return _index;} - inline real x() {return _Vector[0];} - inline real y() {return _Vector[1];} - inline real z() {return _Vector[2];} - - /*! modifiers */ - inline void setVector(const Vec3r& iVector) {_Vector = iVector;} - inline void setIndex(unsigned iIndex) {_index = iIndex;} - - /*! operators */ - IndexedVertex& operator=(const IndexedVertex& iv) - { - _Vector = iv._Vector; - _index = iv._index; - return *this; - } - inline real operator[](const unsigned i) {return _Vector[i];} - //friend inline bool operator<(const IndexedVertex& iv1, const IndexedVertex& iv2); - inline bool operator<(const IndexedVertex& v) const - { - return (_Vector < v._Vector); - } - inline bool operator==(const IndexedVertex& v) - { - return (_Vector == v._Vector); - } + inline IndexedVertex() {} + + inline IndexedVertex(Vec3r iVector, unsigned iIndex) + { + _Vector = iVector; + _index = iIndex; + } + + /*! accessors */ + inline const Vec3r& vector() const + { + return _Vector; + } + + inline unsigned index() + { + return _index; + } + + inline real x() + { + return _Vector[0]; + } + + inline real y() + { + return _Vector[1]; + } + + inline real z() + { + return _Vector[2]; + } + + /*! modifiers */ + inline void setVector(const Vec3r& iVector) + { + _Vector = iVector; + } + + inline void setIndex(unsigned iIndex) + { + _index = iIndex; + } + + /*! operators */ + IndexedVertex& operator=(const IndexedVertex& iv) + { + _Vector = iv._Vector; + _index = iv._index; + return *this; + } + + inline real operator[](const unsigned i) + { + return _Vector[i]; + } + + //friend inline bool operator<(const IndexedVertex& iv1, const IndexedVertex& iv2); + inline bool operator<(const IndexedVertex& v) const + { + return (_Vector < v._Vector); + } + + inline bool operator==(const IndexedVertex& v) + { + return (_Vector == v._Vector); + } }; -//bool operator<(const IndexedVertex& iv1, const IndexedVertex& iv2) -//{ -// return iv1.operator<(iv2); -//} +#if 0 +bool operator<(const IndexedVertex& iv1, const IndexedVertex& iv2) +{ + return iv1.operator<(iv2); +} +#endif -#endif // GEOMCLEANER_H +#endif // __GEOMCLEANER_H__ diff --git a/source/blender/freestyle/intern/geometry/GeomUtils.cpp b/source/blender/freestyle/intern/geometry/GeomUtils.cpp index 61c306e46ee..9d449305466 100644 --- a/source/blender/freestyle/intern/geometry/GeomUtils.cpp +++ b/source/blender/freestyle/intern/geometry/GeomUtils.cpp @@ -1,753 +1,781 @@ - -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** 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/geometry/GeomUtils.cpp + * \ingroup freestyle + * \brief Various tools for geometry + * \author Stephane Grabli + * \date 12/04/2002 + */ #include "GeomUtils.h" namespace GeomUtils { - // This internal procedure is defined below. - bool intersect2dSegPoly(Vec2r* seg, - Vec2r* poly, - unsigned n); - - bool intersect2dSeg2dArea(const Vec2r& min, - const Vec2r& max, - const Vec2r& A, - const Vec2r& B) { - Vec2r seg[2]; - seg[0] = A; - seg[1] = B; - - Vec2r poly[5]; - poly[0][0] = min[0]; - poly[0][1] = min[1]; - poly[1][0] = max[0]; - poly[1][1] = min[1]; - poly[2][0] = max[0]; - poly[2][1] = max[1]; - poly[3][0] = min[0]; - poly[3][1] = max[1]; - poly[4][0] = min[0]; - poly[4][1] = min[1]; - - return intersect2dSegPoly(seg, poly, 4); - } - - 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 - - // 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; - - // 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 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); - - // 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; - - num = a2 * c1 - a1 * c2; - res[1] = num / denom; - - return (DO_INTERSECT); - } - - 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 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 a2, b2, c2 - a2 = p4[1] - p3[1]; - b2 = p3[0] - p4[0]; - c2 = p4[0] * p3[1] - p3[0] * p4[1]; - - // 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; - - num = a2 * c1 - a1 * c2; - res[1] = num / denom; - - return (DO_INTERSECT); - } - - 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 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; - - // 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 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); - - // Line segments intersect: compute intersection point. - denom = a1 * b2 - a2 * b1; - if (fabs(denom) < epsilon) - return (COLINEAR); - - real d1, d2, e1; - - d1 = p1[1] - p3[1]; - d2 = p2[1] - p1[1]; - e1 = p1[0] - p3[0]; - - num = -b2 * d1 - a2 * e1; - t = num / denom; - - 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! +// This internal procedure is defined below. +bool intersect2dSegPoly(Vec2r* seg, Vec2r* poly, unsigned n); + +bool intersect2dSeg2dArea(const Vec2r& min, const Vec2r& max, const Vec2r& A, const Vec2r& B) +{ + Vec2r seg[2]; + seg[0] = A; + seg[1] = B; + + Vec2r poly[5]; + poly[0][0] = min[0]; + poly[0][1] = min[1]; + poly[1][0] = max[0]; + poly[1][1] = min[1]; + poly[2][0] = max[0]; + poly[2][1] = max[1]; + poly[3][0] = min[0]; + poly[3][1] = max[1]; + poly[4][0] = min[0]; + poly[4][1] = min[1]; + + return intersect2dSegPoly(seg, poly, 4); +} + +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 + + // 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; + + // 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 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); + + // 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; + + num = a2 * c1 - a1 * c2; + res[1] = num / denom; + + return (DO_INTERSECT); +} + +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 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 a2, b2, c2 + a2 = p4[1] - p3[1]; + b2 = p3[0] - p4[0]; + c2 = p4[0] * p3[1] - p3[0] * p4[1]; + + // 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; + + num = a2 * c1 - a1 * c2; + res[1] = num / denom; + + return (DO_INTERSECT); +} + +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 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; + + // 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 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); + + // Line segments intersect: compute intersection point. + denom = a1 * b2 - a2 * b1; + if (fabs(denom) < epsilon) + return (COLINEAR); + + real d1, d2, e1; + + d1 = p1[1] - p3[1]; + d2 = p2[1] - p1[1]; + e1 = p1[0] - p3[0]; + + num = -b2 * d1 - a2 * e1; + t = num / denom; + + 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(x1<min) min=x1; \ - if(x1>max) max=x1; \ - if(x2<min) min=x2; \ - if(x2>max) max=x2; - - //======================== 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; - -#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; - - //======================== 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; - -#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; - - //======================== 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; - -#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; - - // This internal procedure is defined below. - bool overlapPlaneBox(Vec3r& normal, real d, Vec3r& maxbox); - - // 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 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; - - // compute triangle edges - e0 = v1 - v0; - e1 = v2 - v1; - e2 = v0 - v2; - - // 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); - - 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 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 X-direction - FINDMINMAX(v0[X], v1[X], v2[X], min, max); - if (min > boxhalfsize[X] || max < -boxhalfsize[X]) - return false; - - // test in Y-direction - FINDMINMAX(v0[Y], v1[Y], v2[Y], min, max); - if (min > boxhalfsize[Y] || max < -boxhalfsize[Y]) - return false; - - // test in Z-direction - FINDMINMAX(v0[Z], v1[Z], v2[Z], min, max); - if(min > boxhalfsize[Z] || max < -boxhalfsize[Z]) - 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 - } - - // 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; - - // find vectors for two edges sharing v0 - edge1 = v1 - v0; - edge2 = v2 - v0; - - // begin calculating determinant - also used to calculate U parameter - pvec = dir ^ edge2; - - // if determinant is near zero, ray lies in plane of triangle - det = edge1 * pvec; - - // 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 - - u *= inv_det; - v *= inv_det; - t = (edge2 * qvec) * inv_det; - - return true; - } - - // 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; - - 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, 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<Vec3r>& vertices, - const Matrix44r& trans, - vector<Vec3r>& res) { - for (vector<Vec3r>::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; + { \ + 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 (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 (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 (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 (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 (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 (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 + +// This internal procedure is defined below. +bool overlapPlaneBox(Vec3r& normal, real d, Vec3r& maxbox); + +// 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 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; + + // compute triangle edges + e0 = v1 - v0; + e1 = v2 - v1; + e2 = v0 - v2; + + // 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); + + 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 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 X-direction + FINDMINMAX(v0[X], v1[X], v2[X], min, max); + if (min > boxhalfsize[X] || max < -boxhalfsize[X]) + return false; + + // test in Y-direction + FINDMINMAX(v0[Y], v1[Y], v2[Y], min, max); + if (min > boxhalfsize[Y] || max < -boxhalfsize[Y]) + return false; + + // test in Z-direction + FINDMINMAX(v0[Z], v1[Z], v2[Z], min, max); + if (min > boxhalfsize[Z] || max < -boxhalfsize[Z]) + 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 +} + +// 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; + + // find vectors for two edges sharing v0 + edge1 = v1 - v0; + edge2 = v2 - v0; + + // begin calculating determinant - also used to calculate U parameter + pvec = dir ^ edge2; + + // if determinant is near zero, ray lies in plane of triangle + det = edge1 * pvec; + + // 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 // orthogonal - { + else { + return false; // ray is parallell to the plane of the triangle + } + + u *= inv_det; + v *= inv_det; + t = (edge2 * qvec) * inv_det; + + return true; +} + +// 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; + + 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<Vec3r>& vertices, const Matrix44r& trans, vector<Vec3r>& res) +{ + for (vector<Vec3r>::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; + 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 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; +} + +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]); } - } - 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; +} + + +// +// 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; - } + // 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 bool overlapPlaneBox(Vec3r& normal, real d, Vec3r& maxbox) { - Vec3r vmin, vmax; +inline void fromCoordAToCoordB(const Vec3r&p, Vec3r& q, const real transform[4][4]) +{ + HVec3r hp(p); + HVec3r hq(0, 0, 0, 0); - for(unsigned q = X; q <= Z; q++) { - if(normal[q] > 0.0f) { - vmin[q] = -maxbox[q]; - vmax[q] = maxbox[q]; + for (unsigned int i = 0; i < 4; i++) { + for (unsigned int j = 0; j < 4; j++) { + hq[i] += transform[i][j] * hp[j]; + } } - else { - vmin[q] = maxbox[q]; - vmax[q] = -maxbox[q]; + + if (hq[3] == 0) { + q = p; + return; } - } - 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 i = 0; i < 4; i++) - for (unsigned j = 0; j < 4; j++) - hq[i] += transform[i][j] * hp[j]; - - if(hq[3] == 0) { - q = p; - return; - } - - for (unsigned k = 0; k < 3; k++) - q[k] = hq[k] / hq[3]; - } + + 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__ + +/** \file blender/freestyle/intern/geometry/GeomUtils.h + * \ingroup freestyle + * \brief Various tools for geometry + * \author Stephane Grabli + * \date 12/04/2002 + */ + +#include <vector> + +#include "Geom.h" + +#include "../system/FreestyleConfig.h" +using namespace std; +using namespace Geometry; + +namespace GeomUtils { // -// 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. +// Templated procedures // -/////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// -#ifndef GEOMUTILS_H -# define GEOMUTILS_H +/*! Computes the distance from a point P to a segment AB */ +template<class T> +real distPointSegment( const T& P, const T& A , const T& B) +{ + T AB, AP, BP; + AB = B - A; + AP = P - A; + BP = P - B; -# include <vector> -# include "../system/FreestyleConfig.h" -# include "Geom.h" + real c1(AB * AP); + if (c1 <= 0) + return AP.norm(); -using namespace std; -using namespace Geometry; + real c2(AB * AB); + if (c2 <= c1) + return BP.norm(); -namespace GeomUtils { + real b = c1 / c2; + T Pb, PPb; + Pb = A + b * AB; + PPb = P - Pb; - // - // Templated procedures - // - ///////////////////////////////////////////////////////////////////////////// - - /*! Computes the distance from a point P to a segment AB */ - template<class T> - 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 c2(AB * AB); - if (c2 <= c1) - return BP.norm(); - - real b = c1 / c2; - T Pb, PPb; - Pb = A + b * AB; - PPb = P - Pb; - - return PPb.norm(); - } - - // - // Non-templated procedures - // - ///////////////////////////////////////////////////////////////////////////// - - 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 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); - - /*! 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); - - /*! 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 - - /*! 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 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 - - - /*! 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 transformVertices(const vector<Vec3r>& vertices, - const Matrix44r& trans, - vector<Vec3r>& res); - - LIB_GEOMETRY_EXPORT - Vec3r rotateVector(const Matrix44r& mat, const Vec3r& v); - - // - // 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 - * 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 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]); + return PPb.norm(); +} + +// +// Non-templated procedures +// +///////////////////////////////////////////////////////////////////////////// +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 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); + +/*! 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); + +/*! 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 + +/*! 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. + */ +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); + +LIB_GEOMETRY_EXPORT +void transformVertex(const Vec3r& vert, const Matrix44r& matrix, Vec3r& res); + +LIB_GEOMETRY_EXPORT +void transformVertices(const vector<Vec3r>& vertices, const Matrix44r& trans, vector<Vec3r>& res); + +LIB_GEOMETRY_EXPORT +Vec3r rotateVector(const Matrix44r& mat, const Vec3r& v); + +// +// 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 + * 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 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 ***** + */ + +/** \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 + */ -// -// 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 "Grid.h" -#include "BBox.h" #include <cassert> #include <stdexcept> +#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_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; +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; } -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_)){ - - //Vec3d bboxdiag(_scene3d->bbox().getMax()-_scene3d->bbox().getMin()); - //if ((t>1.0E-06*(min(min(bboxdiag.x(),bboxdiag.y()),bboxdiag.z()))) && (t<raylength)){ - if(tmp_t < t_){ - occluder_ = occ; - u_ = tmp_u; - v_ = tmp_v; - t_ = tmp_t; - } - }else{ - occ->userdata2 = 0; - } - } - } + +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; +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(); + } -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]; + _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::insertOccluder(Polygon3r* occluder) { - const vector<Vec3r> 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<Vec3r>::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::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; } - } - 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); + // 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<Vec3r> 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<Vec3r>::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); + } + } + } } - } } -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; +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::castRay(const Vec3r& orig, - const Vec3r& end, - OccludersSet& occluders, - unsigned timestamp) { - initRay(orig, end, timestamp); - 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); } -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::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); + +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; - - // check whether the origin is in or out the box: - Vec3r boxMin(_orig); - Vec3r boxMax(_orig+_size); - BBox<Vec3r> 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; +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<Vec3r> 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 + */ + +#include <cstring> // for memset +#include <float.h> +#include <vector> -#ifndef GRID_H -# define GRID_H +#include "Geom.h" +#include "GeomUtils.h" +#include "Polygon.h" -# include <cstring> // for memset -# include <float.h> -# include <vector> -# include "../system/FreestyleConfig.h" -# include "GeomUtils.h" -# include "Geom.h" -# include "Polygon.h" +#include "../system/FreestyleConfig.h" using namespace std; using namespace Geometry; -typedef vector<Polygon3r*> OccludersSet; - +typedef vector<Polygon3r*> OccludersSet; // // Class to define cells used by the regular grid @@ -52,84 +57,102 @@ typedef vector<Polygon3r*> OccludersSet; class LIB_GEOMETRY_EXPORT Cell { - public: - - Cell(Vec3r& orig) { - _orig = orig; - } - - virtual ~Cell() {} - - inline void addOccluder(Polygon3r* o) { - if (o) - _occluders.push_back(o); - } - - inline const Vec3r& getOrigin() { - return _orig; - } - - inline OccludersSet& getOccluders() { - return _occluders; - } - - private: - - Vec3r _orig; - OccludersSet _occluders; +public: + Cell(Vec3r& orig) { + _orig = orig; + } + + virtual ~Cell() {} + + inline void addOccluder(Polygon3r* o) { + if (o) + _occluders.push_back(o); + } + + inline const Vec3r& getOrigin() { + return _orig; + } + + inline OccludersSet& getOccluders() { + return _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) {} + + virtual void examineOccluder(Polygon3r *occ); + + OccludersSet& occluders() { + return occluders_; + } - OccludersSet& occluders() {return occluders_;} - void clear() {occluders_.clear();} + 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() {} - - virtual void discoverCell(Cell *cell) {current_cell_=cell;} - virtual void examineOccluder(Polygon3r *occ); - virtual bool stop(); - - Polygon3r * occluder() {return occluder_;} + 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() {} + + 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() {} - - virtual ~Grid() { - 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 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; - } - } - - /*! 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 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 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); - - /*! 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 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 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; - } - - 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))); - } - - - /*! returns the cell next to the cell - * passed as argument. - */ - bool nextRayCell(Vec3u& current_cell, Vec3u& next_cell); - - unsigned _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 + /*! Builds a Grid. Must be followed by a call to configure() */ + Grid() {} + + virtual ~Grid() { + 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 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; + + /*! 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); + } + + /*! 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; + } + + /*! 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); + } + + /*! 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 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 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; + } + +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))); + } + + + /*! 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 <math.h> + #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 -// -/////////////////////////////////////////////////////////////////////////////// - - -// -// 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 +/* + * ***** 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__ + +/** \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 <vector> -#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<class T> -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<Vec3r> enumerateVertices(const vector<WOEdge*>& fedges) { +inline vector<Vec3r> enumerateVertices(const vector<WOEdge*>& fedges) +{ vector<Vec3r> points; // Iterate over vertices, storing projections in points - for(vector<WOEdge*>::const_iterator woe=fedges.begin(), woend=fedges.end(); woe!=woend; woe++) { + for (vector<WOEdge*>::const_iterator woe = fedges.begin(), woend = fedges.end(); woe != woend; woe++) { points.push_back((*woe)->GetaVertex()->GetVertex()); } @@ -150,50 +165,51 @@ inline vector<Vec3r> enumerateVertices(const vector<WOEdge*>& 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 -// -/////////////////////////////////////////////////////////////////////////////// - - -// -// 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 HASHGRID_H -# define HASHGRID_H - -//# if defined(__GNUC__) && (__GNUC__ >= 3) +/* + * ***** 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__ + +/** \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 + */ + +#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 <hash_map.h> -//# else -//# include <hash_map> -//# endif +# include <hash_map.h> +# else +# include <hash_map> +# endif +#endif + +#include <map> + +#include "Grid.h" -# include "Grid.h" -# include <map> /*! 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: - - typedef map<Vec3u, Cell*> GridHashTable; - - HashGrid() : Grid() {} - - virtual ~HashGrid() { - 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; - } +public: + typedef map<Vec3u, Cell*> GridHashTable; -protected: + HashGrid() : Grid() {} - GridHashTable _cells; + virtual ~HashGrid() + { + 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; + } + +protected: + 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 @@ - -// -// 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. -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** 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/geometry/Noise.cpp + * \ingroup freestyle + * \brief Class to define Perlin noise + * \author Emmanuel Turquin + * \date 12/01/2004 + */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> #include "Noise.h" -# include <stdlib.h> -# include <stdio.h> -# include <math.h> -#include <time.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 -#define nrand() ((float)rand()/(float)RAND_MAX) -#define seednrand(x) srand(x*RAND_MAX) +#define MINX -1000000 +#define MINY MINX +#define MINZ MINX -#define BM 0xff +#define SCURVE(a) ((a) * (a) * (3.0 - 2.0 * (a))) -#define N 0x1000 -#define NP 12 /* 2^N */ -#define NM 0xfff +#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 s_curve(t) ( t * t * (3. - 2. * t) ) +#define MAXSIZE 500 -#define lerp(t, a, b) ( a + t * (b - a) ) +#if 0 // XXX Unused +#define NRAND() ((float)rand() / (float)RAND_MAX) +#endif +#define SEEDNRAND(x) (srand(x * RAND_MAX)) -#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 BM 0xff +#define N 0x1000 +#define NP 12 /* 2^N */ +#define NM 0xfff + +#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.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 = SCURVE(rx0); + sy = SCURVE(ry0); - sx = s_curve(rx0); - sy = s_curve(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); +#undef AT2 - return lerp(sy, a, b); + 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 = SCURVE(rx0); + sy = SCURVE(ry0); + sz = SCURVE(rz0); - t = s_curve(rx0); - sy = s_curve(ry0); - sz = s_curve(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); +#undef AT3 - return lerp(sz, c, d); + 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; - - 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 < 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; - } - - 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]; - } + int i, j, k; + + 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 < 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; + } + + 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 -// -/////////////////////////////////////////////////////////////////////////////// - - -// -// 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 NOISE_H -# define NOISE_H - - -# include "../system/FreestyleConfig.h" -# include "Geom.h" - -#define _Noise_B_ 0x100 +/* + * ***** 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__ + +/** \file blender/freestyle/intern/geometry/Noise.h + * \ingroup freestyle + * \brief Class to define Perlin noise + * \author Emmanuel Turquin + * \date 12/01/2004 + */ + +#include "Geom.h" + +#include "../system/FreestyleConfig.h" + +#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 -// -/////////////////////////////////////////////////////////////////////////////// - - -// -// 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 POLYGON_H -# define POLYGON_H - -# include <vector> -# include "Geom.h" -# include "GeomUtils.h" +/* + * ***** 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__ + +/** \file blender/freestyle/intern/geometry/Polygon.h + * \ingroup freestyle + * \brief Class to define a polygon + * \author Stephane Grabli + * \date 30/07/2002 + */ + +#include <vector> + +#include "Geom.h" +#include "GeomUtils.h" using namespace std; @@ -41,129 +47,129 @@ namespace Geometry { template <class Point> class Polygon { - public: - - inline Polygon() { - _id = 0; - userdata = 0; - userdata2 = 0; - } - - inline Polygon(const vector<Point>& vertices) { - _vertices = vertices; - computeBBox(); - _id = 0; - userdata = 0; - userdata2 = 0; - } - - inline Polygon(const Polygon<Point>& poly) { - Point p; - for(typename vector<Point>::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; - } - - virtual ~Polygon() {} - - // - // Accessors - // - ///////////////////////////////////////////////////////////////////////////// - - inline const vector<Point>& getVertices() const { - return _vertices; - } - - 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& getCenter() { - Point result; - for (typename vector<Point>::iterator it = _vertices.begin(); - it != _vertices.end(); - it++) - result += *it; - result /= _vertices.size(); - return result; - } - - inline unsigned getId() const { - return _id; - } - - // - // Modifiers - // - ///////////////////////////////////////////////////////////////////////////// - - inline void setVertices(const vector<Point>& vertices) { - _vertices.clear(); - Point p; - for (typename vector<Point>::const_iterator it = vertices.begin(); - it != vertices.end(); - it++) { - p = *it; - _vertices.push_back(p); - } - computeBBox(); - } - - inline void setId(unsigned id) { - _id = id; - } - - // - // Other methods - // - ///////////////////////////////////////////////////////////////////////////// - - inline void computeBBox() { - if(_vertices.empty()) - return; - - _max = _vertices[0]; - _min = _vertices[0]; - - for(typename vector<Point>::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<Point> _vertices; - Point _min; - Point _max; - unsigned _id; +public: + inline Polygon() + { + _id = 0; + userdata = 0; + userdata2 = 0; + } + + inline Polygon(const vector<Point>& vertices) + { + _vertices = vertices; + computeBBox(); + _id = 0; + userdata = 0; + userdata2 = 0; + } + + inline Polygon(const Polygon<Point>& poly) + { + Point p; + for (typename vector<Point>::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; + } + + virtual ~Polygon() {} + + // + // Accessors + // + ///////////////////////////////////////////////////////////////////////////// + inline const vector<Point>& getVertices() const + { + return _vertices; + } + + 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& getCenter() + { + Point result; + for (typename vector<Point>::iterator it = _vertices.begin(); it != _vertices.end(); it++) + result += *it; + result /= _vertices.size(); + return result; + } + + inline unsigned getId() const + { + return _id; + } + + // + // Modifiers + // + ///////////////////////////////////////////////////////////////////////////// + inline void setVertices(const vector<Point>& vertices) + { + _vertices.clear(); + Point p; + for (typename vector<Point>::const_iterator it = vertices.begin(); it != vertices.end(); it++) { + p = *it; + _vertices.push_back(p); + } + computeBBox(); + } + + inline void setId(unsigned id) + { + _id = id; + } + + // + // Other methods + // + ///////////////////////////////////////////////////////////////////////////// + inline void computeBBox() + { + if (_vertices.empty()) + return; + + _max = _vertices[0]; + _min = _vertices[0]; + + for (typename vector<Point>::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]; + } + } + } + + // FIXME Is it possible to get rid of userdatas ? + void* userdata; + void* userdata2; // Used during ray casting + +protected: + vector<Point> _vertices; + Point _min; + Point _max; + unsigned _id; }; @@ -171,44 +177,45 @@ class Polygon // Polygon3r class // /////////////////////////////////////////////////////////////////////////////// - class Polygon3r : public Polygon<Vec3r> { - public: - inline Polygon3r() : Polygon<Vec3r>() {} - - inline Polygon3r(const vector<Vec3r>& vertices, - const Vec3r& normal) : Polygon<Vec3r>(vertices) { - setNormal(normal); - } - - inline Polygon3r(const Polygon3r& poly) : Polygon<Vec3r>(poly), _normal(poly._normal) {} - - virtual ~Polygon3r() {} - - void setNormal(const Vec3r& normal) { - _normal = normal; - } - - inline Vec3r getNormal() const { - return _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); - } - - private: - - Vec3r _normal; +public: + inline Polygon3r() : Polygon<Vec3r>() {} + + inline Polygon3r(const vector<Vec3r>& vertices, const Vec3r& normal) : Polygon<Vec3r>(vertices) + { + setNormal(normal); + } + + inline Polygon3r(const Polygon3r& poly) : Polygon<Vec3r>(poly), _normal(poly._normal) {} + + virtual ~Polygon3r() {} + + void setNormal(const Vec3r& normal) + { + _normal = normal; + } + + inline Vec3r getNormal() const + { + return _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 0 + if (_vertices.size() < 3) + return false; +#endif + return GeomUtils::intersectRayTriangle(orig, dir, _vertices[0], _vertices[1], _vertices[2], t, u, v, epsilon); + } + +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 -// -/////////////////////////////////////////////////////////////////////////////// - - -// -// 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 SWEEPLINE_H -# define SWEEPLINE_H - -# include <list> -# include <vector> +/* + * ***** 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__ + +/** \file blender/freestyle/intern/geometry/SweepLine.h + * \ingroup freestyle + * \brief Class to define a Sweep Line + * \author Stephane Grabli + * \date 29/08/2002 + */ + +#include <list> +#include <vector> /*! Class to define the intersection berween two segments*/ template<class Edge> class Intersection { public: - - template<class EdgeClass> - 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; - } - - /*! 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; - } + template<class EdgeClass> + 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; + } + + /*! 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 T, class Point> 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; - } - } - - Segment(Segment<T,Point>& iBrother) - { - _edge = iBrother.edge(); - A = iBrother.A; - B = iBrother.B; - _Intersections = iBrother._Intersections; - _order = iBrother._order; - } - - Segment(const Segment<T,Point>& iBrother) - { - _edge = iBrother._edge; - A = iBrother.A; - B = iBrother.B; - _Intersections = iBrother._Intersections; - _order = iBrother._order; - } - - ~Segment() { - _Intersections.clear(); - } - - inline Point operator[](const unsigned short int& i) const - { - return i%2==0 ? A : B; - } - - inline bool operator==(const Segment<T,Point>& iBrother) - { - if(_edge == iBrother._edge) - return true; - - return false; - } - - /* Adds an intersection for this segment */ - inline void AddIntersection(Intersection<Segment<T,Point> > *i) {_Intersections.push_back(i);} - - /*! Checks for a common vertex with another edge */ - inline bool CommonVertex(const Segment<T,Point>& 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<Intersection<Segment<T,Point> >*>& intersections() {return _Intersections;} - inline bool order() {return _order;} - inline T& edge() {return _edge;} - - private: - T _edge; - Point A; - Point B; - std::vector<Intersection<Segment<T,Point> >*> _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. +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; + } + } + + Segment(Segment<T,Point>& iBrother) + { + _edge = iBrother.edge(); + A = iBrother.A; + B = iBrother.B; + _Intersections = iBrother._Intersections; + _order = iBrother._order; + } + + Segment(const Segment<T,Point>& iBrother) + { + _edge = iBrother._edge; + A = iBrother.A; + B = iBrother.B; + _Intersections = iBrother._Intersections; + _order = iBrother._order; + } + + ~Segment() + { + _Intersections.clear(); + } + + inline Point operator[](const unsigned short int& i) const + { + return (i % 2 == 0) ? A : B; + } + + inline bool operator==(const Segment<T,Point>& iBrother) + { + if (_edge == iBrother._edge) + return true; + return false; + } + + /* Adds an intersection for this segment */ + inline void AddIntersection(Intersection<Segment<T,Point> > *i) + { + _Intersections.push_back(i); + } + + /*! Checks for a common vertex with another edge */ + inline bool CommonVertex(const Segment<T,Point>& 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<Intersection<Segment<T,Point> >*>& intersections() + { + return _Intersections; + } + + inline bool order() + { + return _order; + } + + inline T& edge() + { + return _edge; + } + +private: + T _edge; + Point A; + Point B; + std::vector<Intersection<Segment<T,Point> >*> _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<class T1, class T2> -struct binary_rule +struct binary_rule { - binary_rule() {} - template<class T3,class T4> - binary_rule(const binary_rule<T3,T4>& brother) {} - virtual ~binary_rule() {} - - virtual bool operator()(T1&, T2&) - { - return true; - } + binary_rule() {} + template<class T3,class T4> binary_rule(const binary_rule<T3,T4>& brother) {} + virtual ~binary_rule() {} + + virtual bool operator()(T1&, T2&) + { + return true; + } }; @@ -200,126 +204,121 @@ template<class T,class Point> class SweepLine { public: - - SweepLine() {} - ~SweepLine() - { - for(typename vector<Intersection<Segment<T,Point> >*>::iterator i=_Intersections.begin(),iend=_Intersections.end(); - i!=iend; - i++) - { - delete (*i); - } - } - - - inline void process(Point& p, - vector<Segment<T,Point>*>& segments, - binary_rule<Segment<T,Point>,Segment<T,Point> >& binrule, - //binary_rule<Segment<T,Point>,Segment<T,Point> >& binrule = binary_rule<Segment<T,Point>,Segment<T,Point> >(), - real epsilon = M_EPSILON - ) - { - // first we remove the segments that need to be removed and then - // we add the segments to add - vector<Segment<T,Point>*> toadd; - typename vector<Segment<T,Point>*>::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<T,Point>* S, - binary_rule<Segment<T,Point>,Segment<T,Point> >& binrule, - //binary_rule<Segment<T,Point>,Segment<T,Point> >& binrule = binary_rule<Segment<T,Point>, Segment<T,Point> >(), - 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<Segment<T,Point>* >::iterator s=_set.begin(), send=_set.end(); - s!=send; - s++) - { - Segment<T,Point>* 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<Segment<T,Point> > * inter = new Intersection<Segment<T,Point> >(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<T,Point>* s) - { - if(s->intersections().size() > 0) - _IntersectedEdges.push_back(s); - _set.remove(s); - } - - vector<Segment<T,Point>* >& intersectedEdges() {return _IntersectedEdges;} - vector<Intersection<Segment<T,Point> >*>& intersections() {return _Intersections;} - + SweepLine() {} + ~SweepLine() + { + for (typename vector<Intersection<Segment<T,Point> >*>::iterator i = _Intersections.begin(), + iend = _Intersections.end(); + i != iend; + i++) + { + delete (*i); + } + } + + inline void process(Point& p, vector<Segment<T,Point>*>& segments, +#if 0 + binary_rule<Segment<T,Point>,Segment<T,Point> >& binrule = \ + binary_rule<Segment<T,Point>,Segment<T,Point> >(), +#else + binary_rule<Segment<T,Point>,Segment<T,Point> >& 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<Segment<T,Point>*> toadd; + typename vector<Segment<T,Point>*>::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<T,Point>* S, +#if 0 + binary_rule<Segment<T,Point>,Segment<T,Point> >& binrule = \ + binary_rule<Segment<T,Point>, Segment<T,Point> >(), +#else + binary_rule<Segment<T,Point>,Segment<T,Point> >& 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<Segment<T,Point>* >::iterator s = _set.begin(), send = _set.end(); s != send; s++) { + Segment<T,Point>* 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<Segment<T,Point> > *inter = new Intersection<Segment<T,Point> >(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<T,Point>* s) + { + if (s->intersections().size() > 0) + _IntersectedEdges.push_back(s); + _set.remove(s); + } + + vector<Segment<T,Point>* >& intersectedEdges() + { + return _IntersectedEdges; + } + + vector<Intersection<Segment<T,Point> >*>& intersections() + { + return _Intersections; + } private: - std::list<Segment<T,Point>* > _set; // set of active edges for a given position of the sweep line - std::vector<Segment<T,Point>* > _IntersectedEdges; // the list of intersected edges - std::vector<Intersection<Segment<T,Point> >*> _Intersections; // the list of all intersections. + std::list<Segment<T,Point>* > _set; // set of active edges for a given position of the sweep line + std::vector<Segment<T,Point>* > _IntersectedEdges; // the list of intersected edges + std::vector<Intersection<Segment<T,Point> >*> _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 @@ +/* + * ***** 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__ + +/** \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 + */ + +#include <iostream> +#include <math.h> +#include <vector> + +namespace VecMat { + +namespace Internal { + template <bool B> + struct is_false {}; + + template <> + struct is_false<false> + { + static inline void ensure() {} + }; +} // end of namespace Internal + // -// Filename : VecMat.h -// Author(s) : Sylvain Paris -// Emmanuel Turquin -// Stephane Grabli -// Purpose : Vectors and Matrices definition and manipulation -// Date of creation : 12/06/2003 +// Vector class +// - T: value type +// - N: dimension // -/////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + +template <class T, unsigned N> +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 <class U> + explicit inline Vec(const U tab[N]) + { + for (unsigned int i = 0; i < N; i++) + this->_coord[i] = (T)tab[i]; + } + + template <class U> + explicit inline Vec(const std::vector<U>& tab) + { + for (unsigned int i = 0; i < N; i++) + this->_coord[i] = (T)tab[i]; + } + + template <class U> + explicit inline Vec(const Vec<U, N>& 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<T, N>& normalize() + { + value_type n = norm(); + for (unsigned int i = 0; i < N; i++) + this->_coord[i] /= n; + return *this; + } + + inline Vec<T, N>& 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<T, N> operator+(const Vec<T, N>& v) const + { + Vec<T, N> res(v); + res += *this; + return res; + } + + inline Vec<T, N> operator-(const Vec<T,N>& v) const + { + Vec<T, N> res(*this); + res -= v; + return res; + } + + inline Vec<T, N> operator*(const typename Vec<T,N>::value_type r) const + { + Vec<T, N> res(*this); + res *= r; + return res; + } + + inline Vec<T, N> operator/(const typename Vec<T,N>::value_type r) const + { + Vec<T, N> res(*this); + if (r) + res /= r; + return res; + } + + // dot product + inline value_type operator*(const Vec<T, N>& v) const + { + value_type sum = 0; + for (unsigned int i = 0; i < N; i++) + sum += (*this)[i] * v[i]; + return sum; + } + + template <class U> + inline Vec<T, N>& operator=(const Vec<U, N>& v) + { + if (this != &v) { + for (unsigned int i = 0; i < N; i++) + this->_coord[i] = (T)v[i]; + } + return *this; + } + + template <class U> + inline Vec<T, N>& operator+=(const Vec<U, N>& v) + { + for (unsigned int i = 0 ; i < N; i++) + this->_coord[i] += (T)v[i]; + return *this; + } + + template <class U> + inline Vec<T, N>& operator-=(const Vec<U, N>& v) + { + for (unsigned int i = 0 ; i < N; i++) + this->_coord[i] -= (T)v[i]; + return *this; + } + + template <class U> + inline Vec<T, N>& operator*=(const U r) + { + for (unsigned int i = 0 ; i < N; i++) + this->_coord[i] *= r; + return *this; + } + + template <class U> + inline Vec<T, N>& 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<T, N>& 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<T, N>& 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<T, N>& 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<T, N>& 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, + }; +}; // -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. +// Vec2 class (2D Vector) +// - T: value type +// +///////////////////////////////////////////////////////////////////////////// + +template <class T> +class Vec2 : public Vec<T, 2> +{ +public: + typedef typename Vec<T, 2>::value_type value_type; + + inline Vec2() : Vec<T, 2>() {} + + template <class U> + explicit inline Vec2(const U tab[2]) : Vec<T, 2>(tab) {} + + template <class U> + explicit inline Vec2(const std::vector<U>& tab) : Vec<T, 2>(tab) {} + + template <class U> + inline Vec2(const Vec<U, 2>& v) : Vec<T, 2>(v) {} + + inline Vec2(const value_type x, const value_type y = 0) : Vec<T, 2>() + { + 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<T> operator+(const Vec2<T>& v) const + { + Vec2<T> res(v); + res += *this; + return res; + } + + inline Vec2<T> operator-(const Vec2<T>& v) const + { + Vec2<T> res(*this); + res -= v; + return res; + } + + inline Vec2<T> operator*(const value_type r) const + { + Vec2<T> res(*this); + res *= r; + return res; + } + + inline Vec2<T> operator/(const value_type r) const + { + Vec2<T> res(*this); + if (r) + res /= r; + return res; + } + + // dot product + inline value_type operator*(const Vec2<T>& v) const + { + value_type sum = 0; + for (unsigned int i = 0; i < 2; i++) + sum += (*this)[i] * v[i]; + return sum; + } +}; + + // -// 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. +// HVec3 class (3D Vector in homogeneous coordinates) +// - T: value type // -// 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. +///////////////////////////////////////////////////////////////////////////// + +template <class T> +class HVec3 : public Vec<T, 4> +{ +public: + typedef typename Vec<T, 4>::value_type value_type; + + inline HVec3() : Vec<T, 4>() {} + + template <class U> + explicit inline HVec3(const U tab[4]) : Vec<T, 4>(tab) {} + + template <class U> + explicit inline HVec3(const std::vector<U>& tab) : Vec<T, 4>(tab) {} + + template<class U> + inline HVec3(const Vec<U, 4>& v) : Vec<T, 4>(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 <class U> + inline HVec3(const Vec<U, 3>& 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]; + } +}; + + // -// 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. +// Vec3 class (3D Vec) +// - T: value type // -/////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +template <class T> +class Vec3 : public Vec<T, 3> +{ +public: + typedef typename Vec<T, 3>::value_type value_type; + + inline Vec3() : Vec<T, 3>() {} + + template <class U> + explicit inline Vec3(const U tab[3]) : Vec<T, 3>(tab) {} + + template <class U> + explicit inline Vec3(const std::vector<U>& tab) : Vec<T, 3>(tab) {} + + template<class U> + inline Vec3(const Vec<U, 3>& v) : Vec<T, 3>(v) {} + + template<class U> + inline Vec3(const HVec3<U>& 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<T, 3>() + { + 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<T> operator+(const Vec3<T>& v) const + { + Vec3<T> res(v); + res += *this; + return res; + } + + inline Vec3<T> operator-(const Vec3<T>& v) const + { + Vec3<T> res(*this); + res -= v; + return res; + } + + inline Vec3<T> operator*(const value_type r) const + { + Vec3<T> res(*this); + res *= r; + return res; + } + + inline Vec3<T> operator/(const value_type r) const + { + Vec3<T> res(*this); + if (r) + res /= r; + return res; + } + + // dot product + inline value_type operator*(const Vec3<T>& 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<T> operator^(const Vec3<T>& v) const + { + Vec3<T> 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 <typename U> + inline Vec3<T> operator^(const Vec<U, 3>& v) const + { + Vec3<T> 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; + } +}; -#ifndef VECMAT_H -# define VECMAT_H -# include <math.h> -# include <vector> -# include <iostream> +// +// Matrix class +// - T: value type +// - M: rows +// - N: cols +// +///////////////////////////////////////////////////////////////////////////// + +// Dirty, but icc under Windows needs this +#define _SIZE (M * N) + +template <class T, unsigned M, unsigned N> +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 <class U> + explicit inline Matrix(const U tab[_SIZE]) + { + for (unsigned int i = 0; i < _SIZE; i++) + this->_coord[i] = tab[i]; + } + + template <class U> + explicit inline Matrix(const std::vector<U>& tab) + { + for (unsigned int i = 0; i < _SIZE; i++) + this->_coord[i] = tab[i]; + } + + template <class U> + inline Matrix(const Matrix<U, M, N>& 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<T, M, N>& transpose() const + { + Matrix<T, N, M> 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 <class U> + inline Matrix<T, M, N>& operator=(const Matrix<U, M, N>& 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 <class U> + inline Matrix<T, M, N>& operator+=(const Matrix<U, M, N>& 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 <class U> + inline Matrix<T, M, N>& operator-=(const Matrix<U, M, N>& 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 <class U> + inline Matrix<T, M, N>& 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 <class U> + inline Matrix<T, M, N>& 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 -namespace VecMat { +// +// SquareMatrix class +// - T: value type +// - N: rows & cols +// +///////////////////////////////////////////////////////////////////////////// + +// Dirty, but icc under Windows needs this +#define _SIZE (N * N) + +template <class T, unsigned N> +class SquareMatrix : public Matrix<T, N, N> +{ +public: + typedef T value_type; + + inline SquareMatrix() : Matrix<T, N, N>() {} + + template <class U> + explicit inline SquareMatrix(const U tab[_SIZE]) : Matrix<T, N, N>(tab) {} + + template <class U> + explicit inline SquareMatrix(const std::vector<U>& tab) : Matrix<T, N, N>(tab) {} + + template <class U> + inline SquareMatrix(const Matrix<U, N, N>& m) : Matrix<T, N, N>(m) {} - namespace Internal { - - template <bool B> - struct is_false {}; - - template <> - struct is_false<false> { - static inline void ensure() {} - }; - - } // end of namespace Internal - - // - // Vector class - // - T: value type - // - N: dimension - // - ///////////////////////////////////////////////////////////////////////////// - - template <class T, unsigned N> - 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 <class U> - explicit inline Vec(const U tab[N]) { - for (unsigned i = 0; i < N; i++) - this->_coord[i] = (T)tab[i]; - } - - template <class U> - explicit inline Vec(const std::vector<U>& tab) { - for (unsigned i = 0; i < N; i++) - this->_coord[i] = (T)tab[i]; - } - - template <class U> - explicit inline Vec(const Vec<U, N>& 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<T, N>& normalize() { - value_type n = norm(); - for (unsigned i = 0; i < N; i++) - this->_coord[i] /= n; - return *this; - } - - inline Vec<T, N>& normalizeSafe() { - value_type n = norm(); - if (n) - for (unsigned i=0; i < N; i++) - this->_coord[i] /= n; - return *this; - } - - // classical operators - inline Vec<T, N> operator+(const Vec<T, N>& v) const{ - Vec<T, N> res(v); - res += *this; - return res; - } - - inline Vec<T, N> operator-(const Vec<T,N>& v) const{ - Vec<T, N> res(*this); - res -= v; - return res; - } - - inline Vec<T, N> operator*(const typename Vec<T,N>::value_type r) const{ - Vec<T, N> res(*this); - res *= r; - return res; - } - - inline Vec<T, N> operator/(const typename Vec<T,N>::value_type r) const{ - Vec<T, N> res(*this); - if (r) - res /= r; - return res; - } - - // dot product - inline value_type operator*(const Vec<T, N>& v) const{ - value_type sum = 0; - for (unsigned i = 0; i < N; i++) - sum += (*this)[i] * v[i]; - return sum; - } - - template <class U> - inline Vec<T, N>& operator=(const Vec<U, N>& v) { - if (this != &v) - for (unsigned i = 0; i < N; i++) - this->_coord[i] = (T)v[i]; - return *this; - } - - template <class U> - inline Vec<T, N>& operator+=(const Vec<U, N>& v) { - for (unsigned i = 0 ; i < N; i++) - this->_coord[i] += (T)v[i]; - return *this; - } - - template <class U> - inline Vec<T, N>& operator-=(const Vec<U, N>& v) { - for (unsigned i = 0 ; i < N; i++) - this->_coord[i] -= (T)v[i]; - return *this; - } - - template <class U> - inline Vec<T, N>& operator*=(const U r) { - for (unsigned i = 0 ; i < N; i++) - this->_coord[i] *= r; - return *this; - } - - template <class U> - inline Vec<T, N>& operator/=(const U r) { - if (r) - for (unsigned i = 0 ; i < N; i++) - this->_coord[i] /= r; - return *this; - } - - - inline bool operator==(const Vec<T, N>& v) const { - for(unsigned i = 0; i < N; i++) - if (this->_coord[i] != v[i]) - return false; - return true; - } - - inline bool operator!=(const Vec<T, N>& v) const { - for(unsigned i = 0; i < N; i++) - if (this->_coord[i] != v[i]) - return true; - return false; - } - - inline bool operator<(const Vec<T, N>& v) const { - for (unsigned 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<T, N>& v) const { - for (unsigned 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 T> - class Vec2 : public Vec<T, 2> - { - public: - - typedef typename Vec<T, 2>::value_type value_type; - - inline Vec2() : Vec<T, 2>() {} - - template <class U> - explicit inline Vec2(const U tab[2]) : Vec<T, 2>(tab) {} - - template <class U> - explicit inline Vec2(const std::vector<U>& tab) : Vec<T, 2>(tab) {} - - template <class U> - inline Vec2(const Vec<U, 2>& v) : Vec<T, 2>(v) {} - - inline Vec2(const value_type x, - const value_type y = 0) : Vec<T, 2>() { - 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<T> operator+(const Vec2<T>& v) const{ - Vec2<T> res(v); - res += *this; - return res; - } - - inline Vec2<T> operator-(const Vec2<T>& v) const{ - Vec2<T> res(*this); - res -= v; - return res; - } - - inline Vec2<T> operator*(const value_type r) const{ - Vec2<T> res(*this); - res *= r; - return res; - } - - inline Vec2<T> operator/(const value_type r) const{ - Vec2<T> res(*this); - if (r) - res /= r; - return res; - } - - // dot product - inline value_type operator*(const Vec2<T>& 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 T> - class HVec3 : public Vec<T, 4> - { - public: - - typedef typename Vec<T, 4>::value_type value_type; - - inline HVec3() : Vec<T, 4>() {} - - template <class U> - explicit inline HVec3(const U tab[4]) : Vec<T, 4>(tab) {} - - template <class U> - explicit inline HVec3(const std::vector<U>& tab) : Vec<T, 4>(tab) {} - - template<class U> - inline HVec3(const Vec<U, 4>& v) : Vec<T, 4>(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 <class U> - inline HVec3(const Vec<U, 3>& 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 T> - class Vec3 : public Vec<T, 3> - { - public: - - typedef typename Vec<T, 3>::value_type value_type; - - inline Vec3() : Vec<T, 3>() {} - - template <class U> - explicit inline Vec3(const U tab[3]) : Vec<T, 3>(tab) {} - - template <class U> - explicit inline Vec3(const std::vector<U>& tab) : Vec<T, 3>(tab) {} - - template<class U> - inline Vec3(const Vec<U, 3>& v) : Vec<T, 3>(v) {} - - template<class U> - inline Vec3(const HVec3<U>& 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<T, 3>() { - 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<T> operator+(const Vec3<T>& v) const{ - Vec3<T> res(v); - res += *this; - return res; - } - - inline Vec3<T> operator-(const Vec3<T>& v) const{ - Vec3<T> res(*this); - res -= v; - return res; - } - - inline Vec3<T> operator*(const value_type r) const{ - Vec3<T> res(*this); - res *= r; - return res; - } - - inline Vec3<T> operator/(const value_type r) const{ - Vec3<T> res(*this); - if (r) - res /= r; - return res; - } - - // dot product - inline value_type operator*(const Vec3<T>& 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<T> operator^(const Vec3<T>& v) const{ - Vec3<T> 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 <typename U> - inline Vec3<T> operator^(const Vec<U, 3>& v) const{ - Vec3<T> 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 T, unsigned M, unsigned N> - 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 <class U> - explicit inline Matrix(const U tab[_SIZE]) { - for (unsigned i = 0; i < _SIZE; i++) - this->_coord[i] = tab[i]; - } - - template <class U> - explicit inline Matrix(const std::vector<U>& tab) { - for (unsigned i = 0; i < _SIZE; i++) - this->_coord[i] = tab[i]; - } - - template <class U> - inline Matrix(const Matrix<U, M, N>& 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<T, M, N>& transpose() const { - Matrix<T, N, M> 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 <class U> - inline Matrix<T, M, N>& operator=(const Matrix<U, M, N>& 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 <class U> - inline Matrix<T, M, N>& operator+=(const Matrix<U, M, N>& 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 <class U> - inline Matrix<T, M, N>& operator-=(const Matrix<U, M, N>& 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 <class U> - inline Matrix<T, M, N>& 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 <class U> - inline Matrix<T, M, N>& 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 T, unsigned N> - class SquareMatrix : public Matrix<T, N, N> - { - public: - - typedef T value_type; - - inline SquareMatrix() : Matrix<T, N, N>() {} - - template <class U> - explicit inline SquareMatrix(const U tab[__SIZE]) : Matrix<T, N, N>(tab) {} - - template <class U> - explicit inline SquareMatrix(const std::vector<U>& tab) : Matrix<T, N, N>(tab) {} - - template <class U> - inline SquareMatrix(const Matrix<U, N, N>& m) : Matrix<T, N, N>(m) {} - - static inline SquareMatrix<T, N> identity() { - SquareMatrix<T, N> res; - for (unsigned i = 0; i < N; i++) - res(i, i) = 1; - return res; - } - }; - - - // - // Vector external functions - // - ///////////////////////////////////////////////////////////////////////////// - - // template <class T, unsigned N> - // inline Vec<T, N> operator+(const Vec<T, N>& v1, - // const Vec<T, N>& v2) { - // Vec<T, N> res(v1); - // res += v2; - // return res; - // } - // - // template <class T, unsigned N> - // inline Vec<T, N> operator-(const Vec<T, N>& v1, - // const Vec<T, N>& v2) { - // Vec<T, N> res(v1); - // res -= v2; - // return res; - // } - // template <class T, unsigned N> - // inline Vec<T, N> operator*(const Vec<T, N>& v, - // const typename Vec<T, N>::value_type r) { - // Vec<T, N> res(v); - // res *= r; - // return res; - // } - - template <class T, unsigned N> - inline Vec<T, N> operator*(const typename Vec<T, N>::value_type r, - const Vec<T, N>& v) { - Vec<T, N> res(v); - res *= r; - return res; - } - // - // template <class T, unsigned N> - // inline Vec<T, N> operator/(const Vec<T, N>& v, - // const typename Vec<T, N>::value_type r) { - // Vec<T, N> res(v); - // if (r) - // res /= r; - // return res; - // } - // - // dot product - // template <class T, unsigned N> - // inline typename Vec<T, N>::value_type operator*(const Vec<T, N>& v1, - // const Vec<T, N>& v2) { - // typename Vec<T, N>::value_type sum = 0; - // for (unsigned i = 0; i < N; i++) - // sum += v1[i] * v2[i]; - // return sum; - // } - // - // // cross product for 3D Vectors - // template <typename T> - // inline Vec3<T> operator^(const Vec<T, 3>& v1, - // const Vec<T, 3>& v2) { - // Vec3<T> 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 <class T, unsigned N> - inline std::ostream& operator<<(std::ostream& s, - const Vec<T, N>& v) { - unsigned i; - s << "["; - for (i = 0; i < N - 1; i++) - s << v[i] << ", "; - s << v[i] << "]"; - return s; - } - - - // - // Matrix external functions - // - ///////////////////////////////////////////////////////////////////////////// - - template <class T, unsigned M, unsigned N> - inline Matrix<T, M, N> - operator+(const Matrix<T, M, N>& m1, - const Matrix<T, M, N>& m2) { - Matrix<T, M, N> res(m1); - res += m2; - return res; - } - - template <class T, unsigned M, unsigned N> - inline Matrix<T, M, N> - operator-(const Matrix<T, M, N>& m1, - const Matrix<T, M, N>& m2) { - Matrix<T, M, N> res(m1); - res -= m2; - return res; - } - - template <class T, unsigned M, unsigned N> - inline Matrix<T, M, N> - operator*(const Matrix<T, M, N>& m1, - const typename Matrix<T, M, N>::value_type lambda) { - Matrix<T, M, N> res(m1); - res *= lambda; - return res; - } - - template <class T, unsigned M, unsigned N> - inline Matrix<T, M, N> - operator*(const typename Matrix<T, M, N>::value_type lambda, - const Matrix<T, M, N>& m1) { - Matrix<T, M, N> res(m1); - res *= lambda; - return res; - } - - template <class T, unsigned M, unsigned N> - inline Matrix<T, M, N> - operator/(const Matrix<T, M, N>& m1, - const typename Matrix<T, M, N>::value_type lambda) { - Matrix<T, M, N> res(m1); - res /= lambda; - return res; - } - - template <class T, unsigned M, unsigned N, unsigned P> - inline Matrix<T, M, P> - operator*(const Matrix<T, M, N>& m1, - const Matrix<T, N, P>& m2) { - unsigned i, j, k; - Matrix<T, M, P> res; - typename Matrix<T, N, P>::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 <class T, unsigned M, unsigned N> - inline Vec<T, M> - operator*(const Matrix<T, M, N>& m, - const Vec<T, N>& v) { - - Vec<T, M> res; - typename Matrix<T, M, N>::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 <class T, unsigned M, unsigned N> - inline std::ostream& operator<<(std::ostream& s, - const Matrix<T, M, N>& 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; - } + static inline SquareMatrix<T, N> identity() + { + SquareMatrix<T, N> res; + for (unsigned int i = 0; i < N; i++) + res(i, i) = 1; + return res; + } +}; + +#undef _SIZE + +// +// Vector external functions +// +///////////////////////////////////////////////////////////////////////////// + +#if 0 +template <class T, unsigned N> +inline Vec<T, N> operator+(const Vec<T, N>& v1, const Vec<T, N>& v2) +{ + Vec<T, N> res(v1); + res += v2; + return res; +} + +template <class T, unsigned N> +inline Vec<T, N> operator-(const Vec<T, N>& v1, const Vec<T, N>& v2) +{ + Vec<T, N> res(v1); + res -= v2; + return res; +} + +template <class T, unsigned N> +inline Vec<T, N> operator*(const Vec<T, N>& v, const typename Vec<T, N>::value_type r) +{ + Vec<T, N> res(v); + res *= r; + return res; +} +#endif + +template <class T, unsigned N> +inline Vec<T, N> operator*(const typename Vec<T, N>::value_type r, const Vec<T, N>& v) +{ + Vec<T, N> res(v); + res *= r; + return res; +} + +#if 0 +template <class T, unsigned N> +inline Vec<T, N> operator/(const Vec<T, N>& v, const typename Vec<T, N>::value_type r) +{ + Vec<T, N> res(v); + if (r) + res /= r; + return res; +} + +// dot product +template <class T, unsigned N> +inline typename Vec<T, N>::value_type operator*(const Vec<T, N>& v1, const Vec<T, N>& v2) +{ + typename Vec<T, N>::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 <typename T> +inline Vec3<T> operator^(const Vec<T, 3>& v1, const Vec<T, 3>& v2) +{ + Vec3<T> 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 <class T, unsigned N> +inline std::ostream& operator<<(std::ostream& s, const Vec<T, N>& v) +{ + unsigned int i; + s << "["; + for (i = 0; i < N - 1; i++) + s << v[i] << ", "; + s << v[i] << "]"; + return s; +} + +// +// Matrix external functions +// +///////////////////////////////////////////////////////////////////////////// + +template <class T, unsigned M, unsigned N> +inline Matrix<T, M, N> operator+(const Matrix<T, M, N>& m1, const Matrix<T, M, N>& m2) +{ + Matrix<T, M, N> res(m1); + res += m2; + return res; +} + +template <class T, unsigned M, unsigned N> +inline Matrix<T, M, N> operator-(const Matrix<T, M, N>& m1, const Matrix<T, M, N>& m2) +{ + Matrix<T, M, N> res(m1); + res -= m2; + return res; +} + +template <class T, unsigned M, unsigned N> +inline Matrix<T, M, N> operator*(const Matrix<T, M, N>& m1, const typename Matrix<T, M, N>::value_type lambda) +{ + Matrix<T, M, N> res(m1); + res *= lambda; + return res; +} + +template <class T, unsigned M, unsigned N> +inline Matrix<T, M, N> operator*(const typename Matrix<T, M, N>::value_type lambda, const Matrix<T, M, N>& m1) +{ + Matrix<T, M, N> res(m1); + res *= lambda; + return res; +} + +template <class T, unsigned M, unsigned N> +inline Matrix<T, M, N> operator/(const Matrix<T, M, N>& m1, const typename Matrix<T, M, N>::value_type lambda) +{ + Matrix<T, M, N> res(m1); + res /= lambda; + return res; +} + +template <class T, unsigned M, unsigned N, unsigned P> +inline Matrix<T, M, P> operator*(const Matrix<T, M, N>& m1, const Matrix<T, N, P>& m2) +{ + unsigned int i, j, k; + Matrix<T, M, P> res; + typename Matrix<T, N, P>::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 <class T, unsigned M, unsigned N> +inline Vec<T, M> operator*(const Matrix<T, M, N>& m, const Vec<T, N>& v) +{ + Vec<T, M> res; + typename Matrix<T, M, N>::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 <class T, unsigned M, unsigned N> +inline std::ostream& operator<<(std::ostream& s, const Matrix<T, M, N>& 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 <math.h> - +#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<nn; ij++ ) { - a[ij] = mat[ij]; - } - - // Ugly Fortran-porting trick: indices for a are between 1 and n - a--; - - // Step 2 : Init diagonalization matrix as the unit matrix - v = new double[n*n]; - - ij = 0; - for( i=0; i<n; i++ ) { - for( j=0; j<n; j++ ) { - if( i==j ) { - v[ij++] = 1.0; - } else { - v[ij++] = 0.0; - } - } - } - - // Ugly Fortran-porting trick: indices for v are between 1 and n - v--; - - // Step 3 : compute the weight of the non diagonal terms - ij = 1 ; - a_norm = 0.0; - for( i=1; i<=n; i++ ) { - for( j=1; j<=i; j++ ) { - if( i!=j ) { - a_ij = a[ij]; - a_norm += a_ij*a_ij; - } - ij++; - } - } - - if( a_norm != 0.0 ) { - - a_normEPS = a_norm*EPS; - thr = a_norm ; - - // Step 4 : rotations - while( thr > 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 - - v++; // back from Fortran to to C++ - - 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; - } - + +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 < nn; ij++) { + a[ij] = mat[ij]; + } + + // Ugly Fortran-porting trick: indices for a are between 1 and n + a--; + + // Step 2 : Init diagonalization matrix as the unit matrix + v = new double[n * n]; + + ij = 0; + for (i = 0; i < n; i++) { + for (j = 0; j < n; j++) { + if (i == j) { + v[ij++] = 1.0; + } + else { + v[ij++] = 0.0; + } + } + } + + // Ugly Fortran-porting trick: indices for v are between 1 and n + v--; + + // Step 3 : compute the weight of the non diagonal terms + ij = 1; + a_norm = 0.0; + for (i = 1; i <= n; i++) { + for (j = 1; j <= i; j++) { + if (i != j) { + a_ij = a[ij]; + a_norm += a_ij * a_ij; + } + ij++; + } + } + + if (a_norm != 0.0) { + a_normEPS = a_norm * EPS; + thr = a_norm; + + // Step 4 : rotations + while (thr > 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; + } + //_________________________________________________________ - } -} +} // MatrixUtil namespace + +} // OGF namespace diff --git a/source/blender/freestyle/intern/geometry/matrix_util.h b/source/blender/freestyle/intern/geometry/matrix_util.h index a990413c403..1cf58a8e1fd 100644 --- a/source/blender/freestyle/intern/geometry/matrix_util.h +++ b/source/blender/freestyle/intern/geometry/matrix_util.h @@ -1,69 +1,72 @@ /* - * 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 ***** */ #ifndef __MATRIX_UTIL__ #define __MATRIX_UTIL__ -# include "../system/FreestyleConfig.h" +/** \file blender/freestyle/intern/geometry/matrix_util.h + * \ingroup freestyle + * \author Bruno Levy + */ + +#include "../system/FreestyleConfig.h" namespace OGF { - namespace MatrixUtil { +namespace MatrixUtil { + + /** + * computes the eigen values and eigen vectors of a semi definite symmetric matrix + * + * @param matrix is stored in column symmetric storage, i.e. + * matrix = { m11, m12, m22, m13, m23, m33, m14, m24, m34, m44 ... } + * size = n(n+1)/2 + * + * @param eigen_vectors (return) = { v1, v2, v3, ..., vn } + * where vk = vk0, vk1, ..., vkn + * size = n^2, must be allocated by caller + * + * @param eigen_values (return) are in decreasing order + * size = n, must be allocated by caller + */ + LIB_GEOMETRY_EXPORT + void semi_definite_symmetric_eigen(const double *mat, int n, double *eigen_vec, double *eigen_val); + +} // MatrixUtil namespace - /** - * computes the eigen values and eigen vectors - * of a semi definite symmetric matrix - * - * @param matrix is stored in column symmetric storage, i.e. - * matrix = { m11, m12, m22, m13, m23, m33, m14, m24, m34, m44 ... } - * size = n(n+1)/2 - * - * @param eigen_vectors (return) = { v1, v2, v3, ..., vn } - * where vk = vk0, vk1, ..., vkn - * size = n^2, must be allocated by caller - * - * @param eigen_values (return) are in decreasing order - * size = n, must be allocated by caller - */ - LIB_GEOMETRY_EXPORT - void semi_definite_symmetric_eigen( - const double *mat, int n, double *eigen_vec, double *eigen_val - ) ; - - } -} +} // OGF namespace -#endif +#endif // __MATRIX_UTIL__ diff --git a/source/blender/freestyle/intern/geometry/normal_cycle.cpp b/source/blender/freestyle/intern/geometry/normal_cycle.cpp index 3a697d54731..2f0aa268c9f 100644 --- a/source/blender/freestyle/intern/geometry/normal_cycle.cpp +++ b/source/blender/freestyle/intern/geometry/normal_cycle.cpp @@ -1,87 +1,100 @@ +/* + * ***** 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. + * + * This Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * 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 + * + * 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. -// -/////////////////////////////////////////////////////////////////////////////// -#include "normal_cycle.h" -#include "matrix_util.h" +/** \file blender/freestyle/intern/geometry/normal_cycle.cpp + * \ingroup freestyle + * \author Bruno Levy + */ +#include "matrix_util.h" +#include "normal_cycle.h" namespace OGF { //_________________________________________________________ - - - NormalCycle::NormalCycle() { - } - - void NormalCycle::begin() { - M_[0] = M_[1] = M_[2] = M_[3] = M_[4] = M_[5] = 0 ; - } - - void NormalCycle::end() { - - double eigen_vectors[9] ; - MatrixUtil::semi_definite_symmetric_eigen(M_, 3, eigen_vectors, eigen_value_) ; - - 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]) ; - } - - } -//_________________________________________________________ +NormalCycle::NormalCycle() +{ } + +void NormalCycle::begin() +{ + M_[0] = M_[1] = M_[2] = M_[3] = M_[4] = M_[5] = 0; +} + +void NormalCycle::end() +{ + double eigen_vectors[9]; + MatrixUtil::semi_definite_symmetric_eigen(M_, 3, eigen_vectors, eigen_value_); + + 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 <class T> inline void ogf_swap(T& x, T& y) { - T z = x ; - x = y ; - y = z ; - } +template <class T> 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() ; - } - -//_________________________________________________________ +/** +* 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(); } -#endif +//_________________________________________________________ + +} // 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 <stdlib.h> -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 -// -/////////////////////////////////////////////////////////////////////////////// - - -// -// 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 GAUSSIANFILTER_H -# define GAUSSIANFILTER_H +/* + * ***** 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__ + +/** \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 + */ -#include <string.h> // for memcpy #include <cstdlib> // for abs +#include <string.h> // 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() ; - - /*! 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<class Map> - 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) ; - - /*! accessors */ - inline float sigma() const {return _sigma;} - inline int maskSize() const {return _maskSize;} - inline int getBound() {return _bound;} - - /*! modifiers */ - void setSigma(float sigma) ; - // void SetMaskSize(int size) {_maskSize = size;_storedMaskSize=(_maskSize+1)>>1;} - - + 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 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<class Map> + 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); + + /*! 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 + protected: - void computeMask(); + void computeMask(); }; /* @@ -106,41 +125,37 @@ protected: */ - #include <math.h> #ifdef __MACH__ -#define sqrtf(x) (sqrt(x)) +# define sqrtf(x) (sqrt(x)) #endif template<class Map> -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 - - // 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; + 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; } - -#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. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef IMAGE_H -# define IMAGE_H +/** \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 + */ -# include <string.h> // for memcpy +#include <string.h> // 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: - - /*! 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; - } - - /*! 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; - } - - /*! 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() {} - - /*! 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; - - /*! 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; - - protected: - - unsigned _width; - unsigned _height; - unsigned _storedWidth; - unsigned _storedHeight; - unsigned _Ox; // origin of the stored part - unsigned _Oy; // origin of the stored part +public: + /*! 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; + } + + /*! 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; + } + + /*! 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() {} + + /*! 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; + + /*! 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; + +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: - - 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(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)); - } - - /*! 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<FrsImage&>(*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; - } - - 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 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 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; - } - - /*! 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)); - } - - virtual float * getArray() {return _rgb;} - - protected: - - float* _rgb; +public: + 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(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)); + } + + /*! 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<FrsImage&>(*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; + } + + 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 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 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)); + } + + virtual float *getArray() + { + return _rgb; + } + +protected: + float *_rgb; }; @@ -298,92 +313,103 @@ class RGBImage : public FrsImage class GrayImage : public FrsImage { - public: - - GrayImage() : FrsImage() { - _lvl = 0; - } - - 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]; - } - - 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)); - } - - GrayImage& operator=(const GrayImage& brother) { - dynamic_cast<FrsImage&>(*this) = brother; - _lvl = new float[_storedWidth * _storedHeight]; - memcpy(_lvl, brother._lvl, _storedWidth * _storedHeight * sizeof(float)); - return *this; - } - - virtual ~GrayImage() { - if(_lvl) - delete[] _lvl; - } - - 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)]; - } - - /*! 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;} - - protected: - - float *_lvl; +public: + GrayImage() : FrsImage() + { + _lvl = 0; + } + + 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]; + } + + 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)); + } + + GrayImage& operator=(const GrayImage& brother) + { + dynamic_cast<FrsImage&>(*this) = brother; + _lvl = new float[_storedWidth * _storedHeight]; + memcpy(_lvl, brother._lvl, _storedWidth * _storedHeight * sizeof(float)); + return *this; + } + + virtual ~GrayImage() + { + if (_lvl) + delete[] _lvl; + } + + 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)]; + } + + /*! 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; + } + +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 <iostream> +#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<GrayImage*>::iterator im=_levels.begin(), imend=_levels.end(); - im!=imend; - ++im){ - _levels.push_back(new GrayImage(**im)); - } - } +#if 0 +ImagePyramid::ImagePyramid(const GrayImage& level0, unsigned nbLevels) +{ + BuildPyramid(level0,nbLevels); +} +#endif + +ImagePyramid::ImagePyramid(const ImagePyramid& iBrother) +{ + if (!_levels.empty()) { + for (vector<GrayImage*>::iterator im = _levels.begin(), imend = _levels.end(); im != imend; ++im) { + _levels.push_back(new GrayImage(**im)); + } + } } -ImagePyramid::~ImagePyramid(){ - if(!_levels.empty()){ - for(vector<GrayImage*>::iterator im=_levels.begin(), imend=_levels.end(); - im!=imend; - ++im){ - delete (*im); - } - _levels.clear(); - } + +ImagePyramid::~ImagePyramid() +{ + if (!_levels.empty()) { + for (vector<GrayImage*>::iterator im = _levels.begin(), imend = _levels.end(); im != imend; ++im) { + delete (*im); + } + _levels.clear(); + } } -GrayImage * ImagePyramid::getLevel(int l){ - return _levels[l]; +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.f/(float)(1<<2*level))*(C*P1 + D*P2); +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::width(int level) +{ + return _levels[level]->width(); } -int ImagePyramid::height(int level){ - return _levels[level]->height(); +int ImagePyramid::height(int level) +{ + return _levels[level]->height(); } -GaussianPyramid::GaussianPyramid(const GrayImage& level0, unsigned nbLevels, float iSigma) - : ImagePyramid() +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(GrayImage* level0, unsigned nbLevels, float iSigma) : ImagePyramid() { - _sigma = iSigma; - BuildPyramid(level0,nbLevels); + _sigma = iSigma; + BuildPyramid(level0, nbLevels); } -GaussianPyramid::GaussianPyramid(const GaussianPyramid& iBrother) -: ImagePyramid(iBrother){ - _sigma = iBrother._sigma; +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(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 i=0; i<nbLevels; ++i){ //soc - w = pLevel->width()>>1; - h = pLevel->height()>>1; - GrayImage *img = new GrayImage(w,h); - for(unsigned y=0; y<h; ++y){ - for(unsigned x=0; x<w; ++x){ - float v = gf.getSmoothedPixel<GrayImage>(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<h; ++y){ - for(unsigned x=0; x<w; ++x){ - float v = gf.getSmoothedPixel<GrayImage>(pLevel, 2*x,2*y); - img->setPixel(x,y,v); - } - } - _levels.push_back(img); - pLevel = img; - } - } +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<GrayImage>(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<GrayImage>(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 -// -/////////////////////////////////////////////////////////////////////////////// - - -// -// 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 IMAGEPYRAMID_H -# define IMAGEPYRAMID_H +/* + * ***** 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__ + +/** \file blender/freestyle/intern/image/ImagePyramid.h + * \ingroup freestyle + * \brief Class to represent a pyramid of images + * \author Stephane Grabli + * \date 25/12/2003 + */ -#include "../system/FreestyleConfig.h" #include <vector> +#include "../system/FreestyleConfig.h" + class GrayImage; -class LIB_IMAGE_EXPORT ImagePyramid{ + +class LIB_IMAGE_EXPORT ImagePyramid +{ protected: - std::vector<GrayImage*> _levels; - + std::vector<GrayImage*> _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();} -}; + 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(){} - - virtual void BuildPyramid(const GrayImage& level0, unsigned nbLevels); - virtual void BuildPyramid(GrayImage* level0, unsigned nbLevels); - /* accessors */ - inline float getSigma() const {return _sigma;} - /* modifiers */ + GaussianPyramid(float iSigma=1.f) : ImagePyramid() + { + _sigma = iSigma; + } + + 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__ |