Another "insanely" big code clean-up patch by Bastien Montagne, many thanks!

This commit is contained in:
Tamito Kajiyama 2012-12-22 18:25:01 +00:00
parent 8b57a67f3e
commit fa0211df26
32 changed files with 6234 additions and 5853 deletions

@ -1,141 +1,154 @@
// /*
// Filename : BBox.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Stephane Grabli *
// Purpose : A class to hold a bounding box * This program is free software; you can redistribute it and/or
// Date of creation : 22/05/2003 * 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
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief A class to hold a bounding box
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 22/05/2003
// 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
template <class Point> template <class Point>
class BBox class BBox
{ {
public: public:
inline BBox()
{
_empty = true;
}
inline BBox() { template <class T>
_empty = true; inline BBox(const T& min_in, const T& max_in) : _min(min_in), _max(max_in)
} {
_empty = false;
}
template <class T> template <class T>
inline BBox(const T& min_in, const T& max_in) : _min(min_in), _max(max_in) { inline BBox(const BBox<T>& b) : _min(b.getMin()), _max(b.getMax())
_empty = false; {
} _empty = false;
}
template <class T> template <class T>
inline BBox(const BBox<T>& b) : _min(b.getMin()), _max(b.getMax()) { inline void extendToContain(const T& p)
_empty = false; {
} if (_empty) {
_min = p;
_max = p;
_empty = false;
return;
}
for (unsigned int i = 0; i < Point::dim(); i++) {
if (p[i] < _min[i])
_min[i] = p[i];
else if (p[i] > _max[i])
_max[i] = p[i];
}
_empty = false;
}
template <class T> inline void clear()
inline void extendToContain(const T& p) { {
if (_empty) { _empty = true;
_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() { inline bool empty() const
_empty = true; {
} return _empty;
}
inline bool empty() const { inline const Point& getMin() const
return _empty; {
} return _min;
}
inline const Point& getMin() const { inline const Point& getMax() const
return _min; {
} return _max;
}
inline const Point& getMax() const { inline BBox<Point>& operator=(const BBox<Point>& b)
return _max; {
} _min = b.getMin();
_max = b.getMax();
_empty = false;
return *this;
}
inline BBox<Point>& operator=(const BBox<Point>& b) { inline BBox<Point>& operator+=(const BBox<Point>& b)
_min = b.getMin(); {
_max = b.getMax(); if (_empty) {
_empty = false; _min = b.getMin();
return *this; _max = b.getMax();
} _empty = false;
}
else {
for (unsigned int i = 0; i < Point::dim(); i++) {
if (b.getMin()[i] < _min[i])
_min[i] = b.getMin()[i];
if (b.getMax()[i] > _max[i])
_max[i] = b.getMax()[i];
}
}
return *this;
}
inline BBox<Point>& operator+=(const BBox<Point>& b) { inline bool inside(const Point& p)
if (_empty) { {
_min = b.getMin(); if (empty())
_max = b.getMax(); return false;
_empty = false; for (unsigned int i = 0; i < Point::dim(); i++) {
} if ((_min[i]>p[i]) || (_max[i]<p[i]))
else { return false;
for (unsigned i = 0; i < Point::dim(); i++) { }
if (b.getMin()[i] < _min[i]) return true;
_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;
}
private: private:
Point _min;
Point _min; Point _max;
Point _max; bool _empty;
bool _empty;
}; };
template <class Point> template <class Point>
BBox<Point>& operator+(const BBox<Point> &b1, const BBox<Point> &b2) BBox<Point>& operator+(const BBox<Point> &b1, const BBox<Point> &b2)
{ {
Point new_min; Point new_min;
Point new_max; Point new_max;
for (unsigned i = 0; i < Point::dim(); 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_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]; 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__

@ -1,23 +1,36 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2010 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
// /** \file blender/freestyle/intern/geometry/Bezier.cpp
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to define a Bezier curve of order 4.
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 04/06/2003
// 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 "Bezier.h" #include "Bezier.h"
#include "FitCurve.h" #include "FitCurve.h"
@ -34,85 +47,81 @@ BezierCurveSegment::~BezierCurveSegment()
void BezierCurveSegment::AddControlPoint(const Vec2d& iPoint) void BezierCurveSegment::AddControlPoint(const Vec2d& iPoint)
{ {
_ControlPolygon.push_back(iPoint); _ControlPolygon.push_back(iPoint);
if(_ControlPolygon.size() == 4) if (_ControlPolygon.size() == 4)
Build(); Build();
} }
void BezierCurveSegment::Build() void BezierCurveSegment::Build()
{ {
if(_ControlPolygon.size() != 4) if (_ControlPolygon.size() != 4)
return; return;
// Compute the rightmost part of the matrix: // Compute the rightmost part of the matrix:
vector<Vec2d>::const_iterator p0,p1,p2,p3; vector<Vec2d>::const_iterator p0,p1,p2,p3;
p0 = _ControlPolygon.begin(); p0 = _ControlPolygon.begin();
p1 = p0;++p1; p1 = p0;
p2 = p1;++p2; ++p1;
p3 = p2;++p3; p2 = p1;
float x[4], y[4]; ++p2;
p3 = p2;
x[0] = -p0->x()+3*p1->x()-3*p2->x()+p3->x(); ++p3;
x[1] = 3*p0->x()-6*p1->x()+3*p2->x(); float x[4], y[4];
x[2] = -3*p0->x()+3*p1->x();
x[3] = p0->x();
y[0] = -p0->y()+3*p1->y()-3*p2->y()+p3->y(); x[0] = -p0->x() + 3 * p1->x() - 3 * p2->x() + p3->x();
y[1] = 3*p0->y()-6*p1->y()+3*p2->y(); x[1] = 3 * p0->x() - 6 * p1->x() + 3 * p2->x();
y[2] = -3*p0->y()+3*p1->y(); x[2] = -3 * p0->x() + 3 * p1->x();
y[3] = p0->y(); x[3] = p0->x();
int nvertices = 12; y[0] = -p0->y() + 3 * p1->y() - 3 * p2->y() + p3->y();
float increment = 1.0/(float)nvertices; y[1] = 3 * p0->y() - 6 * p1->y() + 3 * p2->y();
float t = 0.f; y[2] = -3 * p0->y() + 3 * p1->y();
for(int i=0; i<=nvertices; ++i) y[3] = p0->y();
{
_Vertices.push_back(Vec2d((x[3] + t*(x[2] + t*(x[1] + t*x[0]))), int nvertices = 12;
(y[3] + t*(y[2] + t*(y[1] + t*y[0]))))); float increment = 1.0 / (float)nvertices;
t+=increment; 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() BezierCurve::BezierCurve()
{ {
_currentSegment = new BezierCurveSegment; _currentSegment = new BezierCurveSegment;
} }
BezierCurve::BezierCurve(vector<Vec2d>& iPoints, double error) BezierCurve::BezierCurve(vector<Vec2d>& iPoints, double error)
{ {
FitCurveWrapper fitcurve; FitCurveWrapper fitcurve;
_currentSegment = new BezierCurveSegment; _currentSegment = new BezierCurveSegment;
vector<Vec2d> curve; vector<Vec2d> curve;
fitcurve.FitCurve(iPoints, curve, error); fitcurve.FitCurve(iPoints, curve, error);
int i=0; int i = 0;
vector<Vec2d>::iterator v,vend; vector<Vec2d>::iterator v,vend;
for(v=curve.begin(),vend=curve.end(); for (v = curve.begin(), vend = curve.end(); v != vend; ++v) {
v!=vend; if ((i == 0) || (i % 4 != 0))
++v) AddControlPoint(*v);
{ ++i;
if((i == 0) || (i%4 != 0)) }
AddControlPoint(*v);
++i;
}
} }
BezierCurve::~BezierCurve() BezierCurve::~BezierCurve()
{ {
if(_currentSegment) if(_currentSegment)
delete _currentSegment; delete _currentSegment;
} }
void BezierCurve::AddControlPoint(const Vec2d& iPoint) void BezierCurve::AddControlPoint(const Vec2d& iPoint)
{ {
_ControlPolygon.push_back(iPoint); _ControlPolygon.push_back(iPoint);
_currentSegment->AddControlPoint(iPoint); _currentSegment->AddControlPoint(iPoint);
if(_currentSegment->size() == 4) if (_currentSegment->size() == 4) {
{ _Segments.push_back(_currentSegment);
_Segments.push_back(_currentSegment); _currentSegment = new BezierCurveSegment;
_currentSegment = new BezierCurveSegment; _currentSegment->AddControlPoint(iPoint);
_currentSegment->AddControlPoint(iPoint); }
}
} }

@ -1,73 +1,96 @@
// /*
// Filename : Bezier.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Stephane Grabli *
// Purpose : Class to define a Bezier curve of order 4. * This program is free software; you can redistribute it and/or
// Date of creation : 04/06/2003 * 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
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to define a Bezier curve of order 4.
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 04/06/2003
// 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
#include <vector> #include <vector>
#include "../system/FreestyleConfig.h"
#include "Geom.h" #include "Geom.h"
#include "../system/FreestyleConfig.h"
using namespace Geometry; using namespace Geometry;
class LIB_GEOMETRY_EXPORT BezierCurveSegment class LIB_GEOMETRY_EXPORT BezierCurveSegment
{ {
private: private:
std::vector<Vec2d> _ControlPolygon; std::vector<Vec2d> _ControlPolygon;
std::vector<Vec2d> _Vertices; std::vector<Vec2d> _Vertices;
public: public:
BezierCurveSegment(); BezierCurveSegment();
virtual ~BezierCurveSegment(); virtual ~BezierCurveSegment();
void AddControlPoint(const Vec2d& iPoint); void AddControlPoint(const Vec2d& iPoint);
void Build(); void Build();
inline int size() const {return _ControlPolygon.size();}
inline std::vector<Vec2d>& vertices() {return _Vertices;} inline int size() const
{
return _ControlPolygon.size();
}
inline std::vector<Vec2d>& vertices()
{
return _Vertices;
}
}; };
class LIB_GEOMETRY_EXPORT BezierCurve class LIB_GEOMETRY_EXPORT BezierCurve
{ {
private: private:
std::vector<Vec2d> _ControlPolygon; std::vector<Vec2d> _ControlPolygon;
std::vector<BezierCurveSegment*> _Segments; std::vector<BezierCurveSegment*> _Segments;
BezierCurveSegment *_currentSegment; BezierCurveSegment *_currentSegment;
public: public:
BezierCurve(); BezierCurve();
BezierCurve(std::vector<Vec2d>& iPoints, double error=4.0); BezierCurve(std::vector<Vec2d>& iPoints, double error=4.0);
virtual ~BezierCurve(); virtual ~BezierCurve();
void AddControlPoint(const Vec2d& iPoint); void AddControlPoint(const Vec2d& iPoint);
std::vector<Vec2d>& controlPolygon() {return _ControlPolygon;}
std::vector<BezierCurveSegment*>& segments() {return _Segments;} std::vector<Vec2d>& controlPolygon()
{
return _ControlPolygon;
}
std::vector<BezierCurveSegment*>& segments()
{
return _Segments;
}
}; };
#endif // BEZIER_H #endif // __BEZIER_H__

@ -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 *****
*/
// /** \file blender/freestyle/intern/geometry/FastGrid.h
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to define a cell grid surrounding the bounding box of the scene
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 30/07/2002
// 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 "FastGrid.h" #include "FastGrid.h"
void FastGrid::clear() { void FastGrid::clear()
if(!_cells) {
return; if (!_cells)
return;
for(unsigned i = 0; i < _cells_size; i++) for (unsigned int i = 0; i < _cells_size; i++) {
if (_cells[i]) if (_cells[i])
delete _cells[i]; delete _cells[i];
delete[] _cells; }
_cells = NULL; delete[] _cells;
_cells_size = 0; _cells = NULL;
_cells_size = 0;
Grid::clear(); Grid::clear();
} }
void FastGrid::configure(const Vec3r& orig, const Vec3r& size, unsigned nb) { 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]; Grid::configure(orig, size, nb);
_cells = new Cell*[_cells_size]; _cells_size = _cells_nb[0] * _cells_nb[1] * _cells_nb[2];
memset(_cells, 0, _cells_size * sizeof(*_cells)); _cells = new Cell*[_cells_size];
memset(_cells, 0, _cells_size * sizeof(*_cells));
} }
Cell* FastGrid::getCell(const Vec3u& p) { 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")); #if 0
assert((_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0])<_cells_size); cout << _cells << " " << p << " " << _cells_nb[0] << "-" << _cells_nb[1] << "-" << _cells_nb[2]
assert(p[0]<_cells_nb[0]); << " " << _cells_size << endl;
assert(p[1]<_cells_nb[1]); #endif
assert(p[2]<_cells_nb[2]); assert(_cells || ("_cells is a null pointer"));
return _cells[_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]]; 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) { 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(_cells || ("_cells is a null pointer"));
assert(p[0]<_cells_nb[0]); assert((_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]) < _cells_size);
assert(p[1]<_cells_nb[1]); assert(p[0] < _cells_nb[0]);
assert(p[2]<_cells_nb[2]); assert(p[1] < _cells_nb[1]);
_cells[_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]] = &cell; assert(p[2] < _cells_nb[2]);
_cells[_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]] = &cell;
} }

@ -1,85 +1,86 @@
// /*
// Filename : FastGrid.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Stephane Grabli *
// Purpose : Class to define a cell grid surrounding the * This program is free software; you can redistribute it and/or
// bounding box of the scene * modify it under the terms of the GNU General Public License
// Date of creation : 30/07/2002 * 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
// Copyright (C) : Please refer to the COPYRIGHT file distributed * GNU General Public License for more details.
// with this source distribution. *
// * You should have received a copy of the GNU General Public License
// This program is free software; you can redistribute it and/or * along with this program; if not, write to the Free Software Foundation,
// modify it under the terms of the GNU General Public License * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
// as published by the Free Software Foundation; either version 2 *
// of the License, or (at your option) any later version. * The Original Code is Copyright (C) 2010 Blender Foundation.
// * All rights reserved.
// This program is distributed in the hope that it will be useful, *
// but WITHOUT ANY WARRANTY; without even the implied warranty of * The Original Code is: all of this file.
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
// GNU General Public License for more details. * Contributor(s): none yet.
// *
// You should have received a copy of the GNU General Public License * ***** END GPL LICENSE BLOCK *****
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef FASTGRID_H
# define FASTGRID_H
# include "Grid.h"
# include <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)
*/ */
#ifndef __FASTGRID_H__
#define __FASTGRID_H__
/** \file blender/freestyle/intern/geometry/FastGrid.h
* \ingroup freestyle
* \brief Class to define a cell grid surrounding the bounding box of the scene
* \author Stephane Grabli
* \date 30/07/2002
*/
#include <cassert>
#include "Grid.h"
/*! Class to define a regular grid used for ray casting computations
* We don't use a hashtable here. The grid is explicitly stored for faster computations.
* However, this might result in significant increase in memory usage (compared to the regular grid)
*/
class LIB_GEOMETRY_EXPORT FastGrid : public Grid class LIB_GEOMETRY_EXPORT FastGrid : public Grid
{ {
public: public:
FastGrid() : Grid()
{
_cells = NULL;
_cells_size = 0;
}
FastGrid() : Grid() { virtual ~FastGrid()
_cells = NULL; {
_cells_size = 0; clear();
} }
virtual ~FastGrid() {
clear();
}
/*! clears the grid /*! clears the grid
* Deletes all the cells, clears the hashtable, * Deletes all the cells, clears the hashtable, resets size, size of cell, number of cells.
* resets size, size of cell, number of cells. */
*/ virtual void clear();
virtual void clear();
/*! Sets the different parameters of the grid
/*! Sets the different parameters of the grid * orig
* orig * The grid origin
* The grid origin * size
* size * The grid's dimensions
* The grid's dimensions * nb
* nb * The number of cells of the grid
* The number of cells of the grid */
*/ virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb);
virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb);
/*! returns the cell whose coordinates are pased as argument */
/*! returns the cell whose coordinates are pased as argument */ Cell* getCell(const Vec3u& p);
Cell* getCell(const Vec3u& p) ;
/*! Fills the case p with the cell iCell */
/*! Fills the case p with the cell iCell */ virtual void fillCell(const Vec3u& p, Cell& cell);
virtual void fillCell(const Vec3u& p, Cell& cell);
protected: protected:
Cell **_cells;
Cell** _cells; unsigned _cells_size;
unsigned _cells_size;
}; };
#endif // FASTGRID_H #endif // __FASTGRID_H__

@ -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 *****
*/
// /** \file blender/freestyle/intern/geometry/FitCurve.cpp
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief An Algorithm for Automatically Fitting Digitized Curves by Philip J. Schneider,
// * \brief from "Graphics Gems", Academic Press, 1990
// This program is free software; you can redistribute it and/or * \author Stephane Grabli
// modify it under the terms of the GNU General Public License * \date 06/06/2003
// 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 <cstdlib> // for malloc and free #include <cstdlib> // for malloc and free
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h>
#include "FitCurve.h" #include "FitCurve.h"
using namespace std; using namespace std;
typedef Vector2 *BezierCurve; typedef Vector2 *BezierCurve;
// XXX Do we need "#ifdef __cplusplus" at all here???
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
{ {
@ -46,379 +62,367 @@ static Vector2 ComputeLeftTangent(Vector2 *d, int end);
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 ComputeMaxError(Vector2 *d, int first, int last, BezierCurve bezCurve, double *u, int *splitPoint);
static double *ChordLengthParameterize(Vector2 *d, int first, int last); 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 V2AddII(Vector2 a, Vector2 b);
static Vector2 V2ScaleIII(Vector2 v, double s); static Vector2 V2ScaleIII(Vector2 v, double s);
static Vector2 V2SubII(Vector2 a, Vector2 b); 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)
/* returns squared length of input vector */ {
static double V2SquaredLength(Vector2 *a) return (((*a)[0] * (*a)[0]) + ((*a)[1] * (*a)[1]));
{ return(((*a)[0] * (*a)[0])+((*a)[1] * (*a)[1]));
} }
/* returns length of input vector */ /* returns length of input vector */
static double V2Length(Vector2 *a) 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); double len = V2Length(v);
if (len != 0.0) { (*v)[0] *= newlen/len; (*v)[1] *= newlen/len; } if (len != 0.0) {
return(v); (*v)[0] *= newlen / len;
(*v)[1] *= newlen / len;
}
return v;
} }
/* return the dot product of vectors a and b */ /* 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 */ /* return the distance between two points */
static double V2DistanceBetween2Points(Vector2 *a, Vector2 *b) static double V2DistanceBetween2Points(Vector2 *a, Vector2 *b)
{ {
double dx = (*a)[0] - (*b)[0]; double dx = (*a)[0] - (*b)[0];
double dy = (*a)[1] - (*b)[1]; double dy = (*a)[1] - (*b)[1];
return(sqrt((dx*dx)+(dy*dy))); return (sqrt((dx * dx) + (dy * dy)));
} }
/* return vector sum c = a+b */ /* return vector sum c = a+b */
static Vector2 *V2Add(Vector2 *a, Vector2 *b, Vector2 *c) static Vector2 *V2Add(Vector2 *a, Vector2 *b, Vector2 *c)
{ {
(*c)[0] = (*a)[0]+(*b)[0]; (*c)[1] = (*a)[1]+(*b)[1]; (*c)[0] = (*a)[0] + (*b)[0];
return(c); (*c)[1] = (*a)[1] + (*b)[1];
return c;
} }
/* normalizes the input vector and returns it */ /* normalizes the input vector and returns it */
static Vector2 *V2Normalize(Vector2 *v) static Vector2 *V2Normalize(Vector2 *v)
{ {
double len = V2Length(v); double len = V2Length(v);
if (len != 0.0) { (*v)[0] /= len; (*v)[1] /= len; } if (len != 0.0) {
return(v); (*v)[0] /= len;
(*v)[1] /= len;
}
return v;
} }
/* negates the input vector and returns it */ /* 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]; (*v)[0] = -(*v)[0];
return(v); (*v)[1] = -(*v)[1];
return v;
} }
/* GenerateBezier:
/*
* GenerateBezier :
* Use least-squares method to find Bezier control points for region. * 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) 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; int i;
Vector2 A[MAXPOINTS][2]; /* Precomputed rhs for eqn */ Vector2 A[MAXPOINTS][2]; /* Precomputed rhs for eqn */
int nPts; /* Number of pts in sub-curve */ int nPts; /* Number of pts in sub-curve */
double C[2][2]; /* Matrix C */ double C[2][2]; /* Matrix C */
double X[2]; /* Matrix X */ double X[2]; /* Matrix X */
double det_C0_C1, /* Determinants of matrices */ double det_C0_C1; /* Determinants of matrices */
det_C0_X, double det_C0_X;
det_X_C1; double det_X_C1;
double alpha_l, /* Alpha values, left and right */ double alpha_l; /* Alpha values, left and right */
alpha_r; double alpha_r;
Vector2 tmp; /* Utility variable */ Vector2 tmp; /* Utility variable */
BezierCurve bezCurve; /* RETURN bezier curve ctl pts */ BezierCurve bezCurve; /* RETURN bezier curve ctl pts */
bezCurve = (Vector2 *)malloc(4 * sizeof(Vector2)); bezCurve = (Vector2*)malloc(4 * sizeof(Vector2));
nPts = last - first + 1; nPts = last - first + 1;
/* Compute the A's */
/* Compute the A's */ for (i = 0; i < nPts; i++) {
for (i = 0; i < nPts; i++) { Vector2 v1, v2;
Vector2 v1, v2;
v1 = tHat1; v1 = tHat1;
v2 = tHat2; v2 = tHat2;
V2Scale(&v1, B1(uPrime[i])); V2Scale(&v1, B1(uPrime[i]));
V2Scale(&v2, B2(uPrime[i])); V2Scale(&v2, B2(uPrime[i]));
A[i][0] = v1; A[i][0] = v1;
A[i][1] = v2; A[i][1] = v2;
} }
/* Create the C and X matrices */ /* Create the C and X matrices */
C[0][0] = 0.0; C[0][0] = 0.0;
C[0][1] = 0.0; C[0][1] = 0.0;
C[1][0] = 0.0; C[1][0] = 0.0;
C[1][1] = 0.0; C[1][1] = 0.0;
X[0] = 0.0; X[0] = 0.0;
X[1] = 0.0; X[1] = 0.0;
for (i = 0; i < nPts; i++) {
for (i = 0; i < nPts; i++) { C[0][0] += V2Dot(&A[i][0], &A[i][0]);
C[0][0] += V2Dot(&A[i][0], &A[i][0]);
C[0][1] += V2Dot(&A[i][0], &A[i][1]); 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][0] = C[0][1];
C[1][1] += V2Dot(&A[i][1], &A[i][1]); C[1][1] += V2Dot(&A[i][1], &A[i][1]);
tmp = V2SubII(d[first + i], tmp = V2SubII(d[first + i],
V2AddII( V2AddII(V2ScaleIII(d[first], B0(uPrime[i])),
V2ScaleIII(d[first], B0(uPrime[i])), V2AddII(V2ScaleIII(d[first], B1(uPrime[i])),
V2AddII( V2AddII(V2ScaleIII(d[last], B2(uPrime[i])),
V2ScaleIII(d[first], B1(uPrime[i])), V2ScaleIII(d[last], B3(uPrime[i]))
V2AddII( )
V2ScaleIII(d[last], B2(uPrime[i])), )
V2ScaleIII(d[last], B3(uPrime[i])))))); )
);
X[0] += V2Dot(&((A[i])[0]), &tmp); X[0] += V2Dot(&((A[i])[0]), &tmp);
X[1] += V2Dot(&((A[i])[1]), &tmp); X[1] += V2Dot(&((A[i])[1]), &tmp);
} }
/* Compute the determinants of C and X */ /* Compute the determinants of C and X */
det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1]; 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_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]; det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1];
/* Finally, derive alpha values */ /* Finally, derive alpha values */
if (det_C0_C1 == 0.0) { if (det_C0_C1 == 0.0) {
det_C0_C1 = (C[0][0] * C[1][1]) * 10e-12; det_C0_C1 = (C[0][0] * C[1][1]) * 10.0e-12;
} }
alpha_l = det_X_C1 / det_C0_C1; alpha_l = det_X_C1 / det_C0_C1;
alpha_r = det_C0_X / det_C0_C1; alpha_r = det_C0_X / det_C0_C1;
/* If alpha negative, use the Wu/Barsky heuristic (see text) */ /* If alpha negative, use the Wu/Barsky heuristic (see text) (if alpha is 0, you get coincident control points
/* (if alpha is 0, you get coincident control points that lead to * that lead to divide by zero in any subsequent NewtonRaphsonRootFind() call).
* divide by zero in any subsequent NewtonRaphsonRootFind() call. */ */
if (alpha_l < 1.0e-6 || alpha_r < 1.0e-6) { if (alpha_l < 1.0e-6 || alpha_r < 1.0e-6) {
double dist = V2DistanceBetween2Points(&d[last], &d[first]) / double dist = V2DistanceBetween2Points(&d[last], &d[first]) / 3.0;
3.0;
bezCurve[0] = d[first]; bezCurve[0] = d[first];
bezCurve[3] = d[last]; bezCurve[3] = d[last];
V2Add(&(bezCurve[0]), V2Scale(&(tHat1), dist), &(bezCurve[1])); V2Add(&(bezCurve[0]), V2Scale(&(tHat1), dist), &(bezCurve[1]));
V2Add(&(bezCurve[3]), V2Scale(&(tHat2), dist), &(bezCurve[2])); V2Add(&(bezCurve[3]), V2Scale(&(tHat2), dist), &(bezCurve[2]));
return (bezCurve); return bezCurve;
} }
/* First and last control points of the Bezier curve are */ /* First and last control points of the Bezier curve are positioned exactly at the first and last data points
/* 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
/* Control points 1 and 2 are positioned an alpha distance out */ */
/* on the tangent vectors, left and right, respectively */ bezCurve[0] = d[first];
bezCurve[0] = d[first]; bezCurve[3] = d[last];
bezCurve[3] = d[last]; V2Add(&bezCurve[0], V2Scale(&tHat1, alpha_l), &bezCurve[1]);
V2Add(&bezCurve[0], V2Scale(&tHat1, alpha_l), &bezCurve[1]); V2Add(&bezCurve[3], V2Scale(&tHat2, alpha_r), &bezCurve[2]);
V2Add(&bezCurve[3], V2Scale(&tHat2, alpha_r), &bezCurve[2]); return (bezCurve);
return (bezCurve);
} }
/* /*
* Reparameterize: * Reparameterize:
* Given set of points and their parameterization, try to find * Given set of points and their parameterization, try to find a better parameterization.
* 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) 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 nPts = last - first + 1;
int i; int i;
double *uPrime; /* New parameter values */ double *uPrime; /* New parameter values */
uPrime = (double *)malloc(nPts * sizeof(double)); uPrime = (double*)malloc(nPts * sizeof(double));
for (i = first; i <= last; i++) { for (i = first; i <= last; i++) {
uPrime[i-first] = NewtonRaphsonRootFind(bezCurve, d[i], u[i- uPrime[i-first] = NewtonRaphsonRootFind(bezCurve, d[i], u[i - first]);
first]); }
} return (uPrime);
return (uPrime);
} }
/* /*
* NewtonRaphsonRootFind : * NewtonRaphsonRootFind:
* Use Newton-Raphson iteration to find better root. * 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) 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; double numerator, denominator;
Vector2 Q1[3], Q2[2]; /* Q' and Q'' */ Vector2 Q1[3], Q2[2]; /* Q' and Q'' */
Vector2 Q_u, Q1_u, Q2_u; /*u evaluated at Q, Q', & Q'' */ Vector2 Q_u, Q1_u, Q2_u; /* u evaluated at Q, Q', & Q'' */
double uPrime; /* Improved u */ double uPrime; /* Improved u */
int i; int i;
/* Compute Q(u) */ /* Compute Q(u) */
Q_u = BezierII(3, Q, u); Q_u = BezierII(3, Q, u);
/* Generate control vertices for Q' */ /* Generate control vertices for Q' */
for (i = 0; i <= 2; i++) { for (i = 0; i <= 2; i++) {
Q1[i][0] = (Q[i+1][0] - Q[i][0]) * 3.0; Q1[i][0] = (Q[i + 1][0] - Q[i][0]) * 3.0;
Q1[i][1] = (Q[i+1][1] - Q[i][1]) * 3.0; Q1[i][1] = (Q[i + 1][1] - Q[i][1]) * 3.0;
} }
/* Generate control vertices for Q'' */ /* Generate control vertices for Q'' */
for (i = 0; i <= 1; i++) { for (i = 0; i <= 1; i++) {
Q2[i][0] = (Q1[i+1][0] - Q1[i][0]) * 2.0; Q2[i][0] = (Q1[i + 1][0] - Q1[i][0]) * 2.0;
Q2[i][1] = (Q1[i+1][1] - Q1[i][1]) * 2.0; Q2[i][1] = (Q1[i + 1][1] - Q1[i][1]) * 2.0;
} }
/* Compute Q'(u) and Q''(u) */ /* Compute Q'(u) and Q''(u) */
Q1_u = BezierII(2, Q1, u); Q1_u = BezierII(2, Q1, u);
Q2_u = BezierII(1, Q2, u); Q2_u = BezierII(1, Q2, u);
/* Compute f(u)/f'(u) */ /* Compute f(u)/f'(u) */
numerator = (Q_u[0] - P[0]) * (Q1_u[0]) + (Q_u[1] - P[1]) * (Q1_u[1]); 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]) + 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]); (Q_u[0] - P[0]) * (Q2_u[0]) + (Q_u[1] - P[1]) * (Q2_u[1]);
/* u = u - f(u)/f'(u) */ /* u = u - f(u)/f'(u) */
if(denominator == 0) // FIXME if (denominator == 0) // FIXME
return u; return u;
uPrime = u - (numerator/denominator); uPrime = u - (numerator / denominator);
return (uPrime); return uPrime;
} }
/* /*
* Bezier : * Bezier:
* Evaluate a Bezier curve at a particular parameter value * 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) 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; int i, j;
Vector2 Q; /* Point on curve at parameter t */ Vector2 Q; /* Point on curve at parameter t */
Vector2 *Vtemp; /* Local copy of control points */ Vector2 *Vtemp; /* Local copy of control points */
/* Copy array */ /* Copy array */
Vtemp = (Vector2 *)malloc((unsigned)((degree+1) Vtemp = (Vector2*)malloc((unsigned)((degree + 1) * sizeof (Vector2)));
* sizeof (Vector2))); for (i = 0; i <= degree; i++) {
for (i = 0; i <= degree; i++) {
Vtemp[i] = V[i]; Vtemp[i] = V[i];
} }
/* Triangle computation */ /* Triangle computation */
for (i = 1; i <= degree; i++) { for (i = 1; i <= degree; i++) {
for (j = 0; j <= degree-i; j++) { for (j = 0; j <= degree-i; j++) {
Vtemp[j][0] = (1.0 - t) * Vtemp[j][0] + t * Vtemp[j+1][0]; 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][1] = (1.0 - t) * Vtemp[j][1] + t * Vtemp[j + 1][1];
} }
} }
Q = Vtemp[0]; Q = Vtemp[0];
free((void *)Vtemp); free((void*)Vtemp);
return Q; return Q;
} }
/* /*
* B0, B1, B2, B3 : * B0, B1, B2, B3:
* Bezier multipliers * Bezier multipliers
*/ */
static double B0(double u) static double B0(double u)
{ {
double tmp = 1.0 - u; double tmp = 1.0 - u;
return (tmp * tmp * tmp); return (tmp * tmp * tmp);
} }
static double B1(double u) static double B1(double u)
{ {
double tmp = 1.0 - u; double tmp = 1.0 - u;
return (3 * u * (tmp * tmp)); return (3 * u * (tmp * tmp));
} }
static double B2(double u) static double B2(double u)
{ {
double tmp = 1.0 - u; double tmp = 1.0 - u;
return (3 * u * u * tmp); return (3 * u * u * tmp);
} }
static double B3(double u) static double B3(double u)
{ {
return (u * u * u); return (u * u * u);
} }
/* /*
* ComputeLeftTangent, ComputeRightTangent, ComputeCenterTangent : * ComputeLeftTangent, ComputeRightTangent, ComputeCenterTangent:
*Approximate unit tangents at endpoints and "center" of digitized curve * 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) static Vector2 ComputeLeftTangent(Vector2 *d, int end)
// Vector2 *d; /* Digitized points*/
// int end; /* Index to "left" end of region */
{ {
Vector2 tHat1; Vector2 tHat1;
tHat1 = V2SubII(d[end+1], d[end]); tHat1 = V2SubII(d[end + 1], d[end]);
tHat1 = *V2Normalize(&tHat1); tHat1 = *V2Normalize(&tHat1);
return tHat1; return tHat1;
} }
/* Vector2 *d; Digitized points
* int end; Index to "right" end of region
*/
static Vector2 ComputeRightTangent(Vector2 *d, int end) static Vector2 ComputeRightTangent(Vector2 *d, int end)
// Vector2 *d; /* Digitized points */
// int end; /* Index to "right" end of region */
{ {
Vector2 tHat2; Vector2 tHat2;
tHat2 = V2SubII(d[end-1], d[end]); tHat2 = V2SubII(d[end - 1], d[end]);
tHat2 = *V2Normalize(&tHat2); tHat2 = *V2Normalize(&tHat2);
return tHat2; return tHat2;
} }
/* Vector2 *d; Digitized points
* int end; Index to point inside region
*/
static Vector2 ComputeCenterTangent(Vector2 *d, int center) static Vector2 ComputeCenterTangent(Vector2 *d, int center)
// Vector2 *d; /* Digitized points */
// int center; /* Index to point inside region */
{ {
Vector2 V1, V2, tHatCenter; Vector2 V1, V2, tHatCenter;
V1 = V2SubII(d[center-1], d[center]); V1 = V2SubII(d[center - 1], d[center]);
V2 = V2SubII(d[center], d[center+1]); V2 = V2SubII(d[center], d[center + 1]);
tHatCenter[0] = (V1[0] + V2[0])/2.0; tHatCenter[0] = (V1[0] + V2[0]) / 2.0;
tHatCenter[1] = (V1[1] + V2[1])/2.0; tHatCenter[1] = (V1[1] + V2[1]) / 2.0;
tHatCenter = *V2Normalize(&tHatCenter); tHatCenter = *V2Normalize(&tHatCenter);
return tHatCenter; return tHatCenter;
} }
/* /*
* ChordLengthParameterize : * ChordLengthParameterize:
* Assign parameter values to digitized points * Assign parameter values to digitized points using relative distances between 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) static double *ChordLengthParameterize(Vector2 *d, int first, int last)
// Vector2 *d; /* Array of digitized points */
// int first, last; /* Indices defining region */
{ {
int i; int i;
double *u; /* Parameterization */ 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; u[0] = 0.0;
for (i = first+1; i <= last; i++) { for (i = first + 1; i <= last; i++) {
u[i-first] = u[i-first-1] + u[i - first] = u[i - first - 1] + V2DistanceBetween2Points(&d[i], &d[i - 1]);
V2DistanceBetween2Points(&d[i], &d[i-1]); }
}
for (i = first + 1; i <= last; i++) { for (i = first + 1; i <= last; i++) {
u[i-first] = u[i-first] / u[last-first]; 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 : * ComputeMaxError :
* Find the maximum squared distance of digitized points * Find the maximum squared distance of digitized points to fitted curve.
* 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) 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; int i;
double maxDist; /* Maximum error */ double maxDist; /* Maximum error */
double dist; /* Current error */ double dist; /* Current error */
Vector2 P; /* Point on curve */ Vector2 P; /* Point on curve */
Vector2 v; /* Vector from point to curve */ Vector2 v; /* Vector from point to curve */
*splitPoint = (last - first + 1)/2; *splitPoint = (last - first + 1) / 2;
maxDist = 0.0; maxDist = 0.0;
for (i = first + 1; i < last; i++) { for (i = first + 1; i < last; i++) {
P = BezierII(3, bezCurve, u[i-first]); P = BezierII(3, bezCurve, u[i - first]);
v = V2SubII(P, d[i]); v = V2SubII(P, d[i]);
dist = V2SquaredLength(&v); dist = V2SquaredLength(&v);
if (dist >= maxDist) { if (dist >= maxDist) {
maxDist = dist; maxDist = dist;
*splitPoint = i; *splitPoint = i;
} }
} }
return (maxDist); return maxDist;
} }
static Vector2 V2AddII(Vector2 a, Vector2 b) static Vector2 V2AddII(Vector2 a, Vector2 b)
{ {
Vector2 c; Vector2 c;
c[0] = a[0] + b[0]; c[1] = a[1] + b[1]; c[0] = a[0] + b[0];
return (c); c[1] = a[1] + b[1];
return c;
} }
static Vector2 V2ScaleIII(Vector2 v, double s) static Vector2 V2ScaleIII(Vector2 v, double s)
{ {
Vector2 result; Vector2 result;
result[0] = v[0] * s; result[1] = v[1] * s; result[0] = v[0] * s;
return (result); result[1] = v[1] * s;
return result;
} }
static Vector2 V2SubII(Vector2 a, Vector2 b) static Vector2 V2SubII(Vector2 a, Vector2 b)
{ {
Vector2 c; Vector2 c;
c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; c[0] = a[0] - b[0];
return (c); c[1] = a[1] - b[1];
return c;
} }
#ifdef __cplusplus #ifdef __cplusplus
@ -488,116 +496,107 @@ FitCurveWrapper::FitCurveWrapper()
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) for (int i = 0; i < n + 1; ++i)
_vertices.push_back(curve[i]); _vertices.push_back(curve[i]);
} }
void FitCurveWrapper::FitCurve(vector<Vec2d>& data, vector<Vec2d>& oCurve, double error) void FitCurveWrapper::FitCurve(vector<Vec2d>& data, vector<Vec2d>& oCurve, double error)
{ {
int size = data.size(); int size = data.size();
Vector2 *d = new Vector2[size]; Vector2 *d = new Vector2[size];
for(int i=0; i<size; ++i) for (int i = 0; i < size; ++i) {
{ d[i][0] = data[i][0];
d[i][0] = data[i][0]; d[i][1] = data[i][1];
d[i][1] = data[i][1]; }
}
FitCurve(d,size,error); FitCurve(d, size, error);
// copy results // copy results
for(vector<Vector2>::iterator v=_vertices.begin(), vend=_vertices.end(); for (vector<Vector2>::iterator v = _vertices.begin(), vend = _vertices.end(); v != vend; ++v) {
v!=vend; oCurve.push_back(Vec2d(v->x(), v->y())) ;
++v) }
{
oCurve.push_back(Vec2d(v->x(), v->y())) ;
}
} }
void FitCurveWrapper::FitCurve(Vector2 *d, int nPts, double error) 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); tHat1 = ComputeLeftTangent(d, 0);
tHat2 = ComputeRightTangent(d, nPts - 1); tHat2 = ComputeRightTangent(d, nPts - 1);
FitCubic(d, 0, nPts - 1, tHat1, tHat2, error); FitCubic(d, 0, nPts - 1, tHat1, tHat2, error);
} }
void FitCurveWrapper::FitCubic(Vector2 *d, int first, int last, Vector2 tHat1, Vector2 tHat2, double error) void FitCurveWrapper::FitCubic(Vector2 *d, int first, int last, Vector2 tHat1, Vector2 tHat2, double error)
{ {
BezierCurve bezCurve; /*Control points of fitted Bezier curve*/ BezierCurve bezCurve; /* Control points of fitted Bezier curve */
double *u; /* Parameter values for point */ double *u; /* Parameter values for point */
double *uPrime; /* Improved parameter values */ double *uPrime; /* Improved parameter values */
double maxError; /* Maximum fitting error */ double maxError; /* Maximum fitting error */
int splitPoint; /* Point to split point set at */ int splitPoint; /* Point to split point set at */
int nPts; /* Number of points in subset */ int nPts; /* Number of points in subset */
double iterationError; /*Error below which you try iterating */ double iterationError; /* Error below which you try iterating */
int maxIterations = 4; /* Max times to try iterating */ int maxIterations = 4; /* Max times to try iterating */
Vector2 tHatCenter; /* Unit tangent vector at splitPoint */ Vector2 tHatCenter; /* Unit tangent vector at splitPoint */
int i; int i;
iterationError = error * error; iterationError = error * error;
nPts = last - first + 1; nPts = last - first + 1;
/* Use heuristic if region only has two points in it */ /* Use heuristic if region only has two points in it */
if (nPts == 2) { if (nPts == 2) {
double dist = V2DistanceBetween2Points(&d[last], &d[first]) / 3.0; double dist = V2DistanceBetween2Points(&d[last], &d[first]) / 3.0;
bezCurve = (Vector2 *)malloc(4 * sizeof(Vector2)); bezCurve = (Vector2*)malloc(4 * sizeof(Vector2));
bezCurve[0] = d[first]; bezCurve[0] = d[first];
bezCurve[3] = d[last]; bezCurve[3] = d[last];
V2Add(&bezCurve[0], V2Scale(&tHat1, dist), &bezCurve[1]); V2Add(&bezCurve[0], V2Scale(&tHat1, dist), &bezCurve[1]);
V2Add(&bezCurve[3], V2Scale(&tHat2, dist), &bezCurve[2]); V2Add(&bezCurve[3], V2Scale(&tHat2, dist), &bezCurve[2]);
DrawBezierCurve(3, bezCurve); DrawBezierCurve(3, bezCurve);
free((void *)bezCurve); free((void*)bezCurve);
return; return;
}
/* Parameterize points, and attempt to fit curve */
u = ChordLengthParameterize(d, first, last);
bezCurve = GenerateBezier(d, first, last, u, tHat1, tHat2);
/* Find max deviation of points to fitted curve */
maxError = ComputeMaxError(d, first, last, bezCurve, u, &splitPoint);
if (maxError < error) {
DrawBezierCurve(3, bezCurve);
free((void *)u);
free((void *)bezCurve);
return;
}
/* If error not too large, try some reparameterization */
/* and iteration */
if (maxError < iterationError) {
for (i = 0; i < maxIterations; i++) {
uPrime = Reparameterize(d, first, last, u, bezCurve);
bezCurve = GenerateBezier(d, first, last, uPrime, tHat1, tHat2);
maxError = ComputeMaxError(d, first, last,
bezCurve, uPrime, &splitPoint);
if (maxError < error) {
DrawBezierCurve(3, bezCurve);
free((void *)u);
free((void *)bezCurve);
return;
}
free((void *)u);
u = uPrime;
} }
}
/* Fitting failed -- split at max error point and fit recursively */ /* Parameterize points, and attempt to fit curve */
free((void *)u); u = ChordLengthParameterize(d, first, last);
free((void *)bezCurve); bezCurve = GenerateBezier(d, first, last, u, tHat1, tHat2);
tHatCenter = ComputeCenterTangent(d, splitPoint);
FitCubic(d, first, splitPoint, tHat1, tHatCenter, error);
V2Negate(&tHatCenter);
FitCubic(d, splitPoint, last, tHatCenter, tHat2, 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);
return;
}
/* If error not too large, try some reparameterization and iteration */
if (maxError < iterationError) {
for (i = 0; i < maxIterations; i++) {
uPrime = Reparameterize(d, first, last, u, bezCurve);
bezCurve = GenerateBezier(d, first, last, uPrime, tHat1, tHat2);
maxError = ComputeMaxError(d, first, last,
bezCurve, uPrime, &splitPoint);
if (maxError < error) {
DrawBezierCurve(3, bezCurve);
free((void*)u);
free((void*)bezCurve);
return;
}
free((void*)u);
u = uPrime;
}
}
/* Fitting failed -- split at max error point and fit recursively */
free((void*)u);
free((void*)bezCurve);
tHatCenter = ComputeCenterTangent(d, splitPoint);
FitCubic(d, first, splitPoint, tHat1, tHatCenter, error);
V2Negate(&tHatCenter);
FitCubic(d, splitPoint, last, tHatCenter, tHat2, error);
} }

@ -1,101 +1,125 @@
// /*
// Filename : FitCurve.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Stephane Grabli *
// Purpose : An Algorithm for Automatically Fitting Digitized Curves * This program is free software; you can redistribute it and/or
// by Philip J. Schneider * modify it under the terms of the GNU General Public License
// from "Graphics Gems", Academic Press, 1990 * as published by the Free Software Foundation; either version 2
// Date of creation : 06/06/2003 * 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
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief An Algorithm for Automatically Fitting Digitized Curves by Philip J. Schneider,
// * \brief from "Graphics Gems", Academic Press, 1990
// This program is free software; you can redistribute it and/or * \author Stephane Grabli
// modify it under the terms of the GNU General Public License * \date 06/06/2003
// 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
#include <vector> #include <vector>
#include "../system/FreestyleConfig.h"
#include "Geom.h" #include "Geom.h"
#include "../system/FreestyleConfig.h"
using namespace Geometry; using namespace Geometry;
typedef struct Point2Struct { /* 2d point */ /* 2d point */
typedef struct Point2Struct
{
double coordinates[2]; double coordinates[2];
Point2Struct() {coordinates[0]=0;coordinates[1]=0;}
inline double operator[](const int i) const Point2Struct()
{ {
return coordinates[i]; coordinates[0] = 0;
} coordinates[1] = 0;
inline double& operator[](const int i) }
{
return coordinates[i]; inline double operator[](const int i) const
} {
inline double x() const {return coordinates[0];} return coordinates[i];
inline double y() const {return coordinates[1];} }
} Point2;
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; typedef Point2 Vector2;
class LIB_GEOMETRY_EXPORT FitCurveWrapper class LIB_GEOMETRY_EXPORT FitCurveWrapper
{ {
private: private:
std::vector<Vector2> _vertices; std::vector<Vector2> _vertices;
public: public:
FitCurveWrapper(); FitCurveWrapper();
~FitCurveWrapper(); ~FitCurveWrapper();
/*! Fits a set of 2D data points to a set of Bezier Curve segments
* data
* Input data points
* oCurve
* Control points of the sets of bezier curve segments.
* Each segment is made of 4 points (polynomial degree of curve = 3)
* error
* max error tolerance between resulting curve and input data
*/
void FitCurve(std::vector<Vec2d>& data, std::vector<Vec2d>& oCurve, double error);
/*! Fits a set of 2D data points to a set of Bezier Curve segments
* data
* Input data points
* oCurve
* Control points of the sets of bezier curve segments.
* Each segment is made of 4 points (polynomial degree of curve = 3)
* error
* max error tolerance between resulting curve and input data
*/
void FitCurve(std::vector<Vec2d>& data, std::vector<Vec2d>& oCurve, double error);
protected: protected:
/* Vec2d *d; Array of digitized points */ /* Vec2d *d; Array of digitized points
/* int nPts; Number of digitized points */ * int nPts; Number of digitized points
/* double error; User-defined error squared */ * double error; User-defined error squared
void FitCurve(Vector2 *d, int nPts, double error); */
void FitCurve(Vector2 *d, int nPts, double error);
/*! Draws a Bezier curve segment
* n /*! Draws a Bezier curve segment
* degree of curve (=3) * n
* curve * degree of curve (=3)
* bezier segments control points * curve
*/ * bezier segments control points
void DrawBezierCurve(int n, Vector2 *curve); */
void DrawBezierCurve(int n, Vector2 *curve);
/* Vec2d *d; Array of digitized points */
/* int first, last; Indices of first and last pts in region */ /* Vec2d *d; Array of digitized points
/* Vec2d tHat1, tHat2; Unit tangent vectors at endpoints */ * int first, last; Indices of first and last pts in region
/* double error; User-defined error squared */ * Vec2d tHat1, tHat2; Unit tangent vectors at endpoints
void FitCubic(Vector2 *d, int first, int last, Vector2 tHat1, Vector2 tHat2, double error); * 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__

@ -1,78 +1,84 @@
// /*
// Filename : Geom.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Sylvain Paris *
// Emmanuel Turquin * This program is free software; you can redistribute it and/or
// Stephane Grabli * modify it under the terms of the GNU General Public License
// Purpose : Vectors and Matrices (useful type definitions) * as published by the Free Software Foundation; either version 2
// Date of creation : 20/05/2003 * 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__
// /** \file blender/freestyle/intern/geometry/Geom.h
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Vectors and Matrices (useful type definitions)
// * \author Sylvain Paris
// This program is free software; you can redistribute it and/or * \author Emmanuel Turquin
// modify it under the terms of the GNU General Public License * \author Stephane Grabli
// as published by the Free Software Foundation; either version 2 * \date 20/05/2003
// 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 GEOM_H #include "VecMat.h"
# define GEOM_H
# include "VecMat.h" #include "../system/Precision.h"
# include "../system/Precision.h"
namespace Geometry { namespace Geometry {
typedef VecMat::Vec2<unsigned> Vec2u; typedef VecMat::Vec2<unsigned> Vec2u;
typedef VecMat::Vec2<int> Vec2i; typedef VecMat::Vec2<int> Vec2i;
typedef VecMat::Vec2<float> Vec2f; typedef VecMat::Vec2<float> Vec2f;
typedef VecMat::Vec2<double> Vec2d; typedef VecMat::Vec2<double> Vec2d;
typedef VecMat::Vec2<real> Vec2r; typedef VecMat::Vec2<real> Vec2r;
typedef VecMat::Vec3<unsigned> Vec3u; typedef VecMat::Vec3<unsigned> Vec3u;
typedef VecMat::Vec3<int> Vec3i; typedef VecMat::Vec3<int> Vec3i;
typedef VecMat::Vec3<float> Vec3f; typedef VecMat::Vec3<float> Vec3f;
typedef VecMat::Vec3<double> Vec3d; typedef VecMat::Vec3<double> Vec3d;
typedef VecMat::Vec3<real> Vec3r; typedef VecMat::Vec3<real> Vec3r;
typedef VecMat::HVec3<unsigned> HVec3u; typedef VecMat::HVec3<unsigned> HVec3u;
typedef VecMat::HVec3<int> HVec3i; typedef VecMat::HVec3<int> HVec3i;
typedef VecMat::HVec3<float> HVec3f; typedef VecMat::HVec3<float> HVec3f;
typedef VecMat::HVec3<double> HVec3d; typedef VecMat::HVec3<double> HVec3d;
typedef VecMat::HVec3<real> HVec3r; typedef VecMat::HVec3<real> HVec3r;
typedef VecMat::SquareMatrix<unsigned, 2> Matrix22u; typedef VecMat::SquareMatrix<unsigned, 2> Matrix22u;
typedef VecMat::SquareMatrix<int, 2> Matrix22i; typedef VecMat::SquareMatrix<int, 2> Matrix22i;
typedef VecMat::SquareMatrix<float, 2> Matrix22f; typedef VecMat::SquareMatrix<float, 2> Matrix22f;
typedef VecMat::SquareMatrix<double, 2> Matrix22d; typedef VecMat::SquareMatrix<double, 2> Matrix22d;
typedef VecMat::SquareMatrix<real, 2> Matrix22r; typedef VecMat::SquareMatrix<real, 2> Matrix22r;
typedef VecMat::SquareMatrix<unsigned, 3> Matrix33u; typedef VecMat::SquareMatrix<unsigned, 3> Matrix33u;
typedef VecMat::SquareMatrix<int, 3> Matrix33i; typedef VecMat::SquareMatrix<int, 3> Matrix33i;
typedef VecMat::SquareMatrix<float, 3> Matrix33f; typedef VecMat::SquareMatrix<float, 3> Matrix33f;
typedef VecMat::SquareMatrix<double, 3> Matrix33d; typedef VecMat::SquareMatrix<double, 3> Matrix33d;
typedef VecMat::SquareMatrix<real, 3> Matrix33r; typedef VecMat::SquareMatrix<real, 3> Matrix33r;
typedef VecMat::SquareMatrix<unsigned, 4> Matrix44u; typedef VecMat::SquareMatrix<unsigned, 4> Matrix44u;
typedef VecMat::SquareMatrix<int, 4> Matrix44i; typedef VecMat::SquareMatrix<int, 4> Matrix44i;
typedef VecMat::SquareMatrix<float, 4> Matrix44f; typedef VecMat::SquareMatrix<float, 4> Matrix44f;
typedef VecMat::SquareMatrix<double, 4> Matrix44d; typedef VecMat::SquareMatrix<double, 4> Matrix44d;
typedef VecMat::SquareMatrix<real, 4> Matrix44r; typedef VecMat::SquareMatrix<real, 4> Matrix44r;
} // end of namespace Geometry } // end of namespace Geometry
#endif // GEOM_H #endif // __GEOM_H__

@ -1,240 +1,233 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2010 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
// /** \file blender/freestyle/intern/geometry/GeomCleaner.cpp
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to define a cleaner of geometry providing a set of useful tools
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 04/03/2002
// 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) #if 0
//// hash_map is not part of the C++ standard anymore; #if defined(__GNUC__) && (__GNUC__ >= 3)
//// hash_map.h has been kept though for backward compatibility // hash_map is not part of the C++ standard anymore;
//# include <hash_map.h> // hash_map.h has been kept though for backward compatibility
//#else # include <hash_map.h>
//# include <hash_map> #else
//#endif # include <hash_map>
#endif
#endif
#include <stdio.h> #include <stdio.h>
#include <list> #include <list>
#include <map> #include <map>
#include "../system/TimeUtils.h"
#include "GeomCleaner.h" #include "GeomCleaner.h"
#include "../system/TimeUtils.h"
using namespace std; using namespace std;
void GeomCleaner::SortIndexedVertexArray( const float *iVertices, unsigned iVSize, void GeomCleaner::SortIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices,
const unsigned *iIndices, unsigned iISize, unsigned iISize, real **oVertices, unsigned **oIndices)
real **oVertices,
unsigned **oIndices)
{ {
// First, we build a list of IndexVertex: // First, we build a list of IndexVertex:
list<IndexedVertex> indexedVertices; list<IndexedVertex> indexedVertices;
unsigned i; unsigned i;
for(i=0; i<iVSize; i+= 3) for (i = 0; i < iVSize; i += 3) {
{ indexedVertices.push_back(IndexedVertex(Vec3r(iVertices[i], iVertices[i + 1], iVertices[i + 2]), i / 3));
indexedVertices.push_back(IndexedVertex(Vec3r(iVertices[i], iVertices[i+1], iVertices[i+2]), i/3)); }
}
// q-sort // q-sort
indexedVertices.sort(); indexedVertices.sort();
// build the indices mapping array: // build the indices mapping array:
unsigned *mapIndices = new unsigned[iVSize/3]; unsigned *mapIndices = new unsigned[iVSize / 3];
*oVertices = new real[iVSize]; *oVertices = new real[iVSize];
list<IndexedVertex>::iterator iv; list<IndexedVertex>::iterator iv;
unsigned newIndex = 0; unsigned newIndex = 0;
unsigned vIndex = 0; unsigned vIndex = 0;
for(iv=indexedVertices.begin(); iv!=indexedVertices.end(); iv++) for (iv = indexedVertices.begin(); iv != indexedVertices.end(); iv++) {
{ // Build the final results:
// Build the final results: (*oVertices)[vIndex] = iv->x();
(*oVertices)[vIndex] = iv->x(); (*oVertices)[vIndex + 1] = iv->y();
(*oVertices)[vIndex+1] = iv->y(); (*oVertices)[vIndex + 2] = iv->z();
(*oVertices)[vIndex+2] = iv->z();
mapIndices[iv->index()] = newIndex; mapIndices[iv->index()] = newIndex;
newIndex++; newIndex++;
vIndex+=3; vIndex += 3;
} }
// Build the final index array:
// Build the final index array: *oIndices = new unsigned[iISize];
*oIndices = new unsigned[iISize]; for (i = 0; i < iISize; i++) {
for(i=0; i<iISize; i++) (*oIndices)[i] = 3 * mapIndices[iIndices[i] / 3];
{ }
(*oIndices)[i] = 3*mapIndices[iIndices[i]/3];
}
delete [] mapIndices; delete [] mapIndices;
} }
void GeomCleaner::CompressIndexedVertexArray(const real *iVertices, unsigned iVSize, void GeomCleaner::CompressIndexedVertexArray(const real *iVertices, unsigned iVSize, const unsigned *iIndices,
const unsigned *iIndices, unsigned iISize, unsigned iISize, real **oVertices, unsigned *oVSize, unsigned **oIndices)
real **oVertices, unsigned *oVSize,
unsigned **oIndices)
{ {
// First, we build a list of IndexVertex: // First, we build a list of IndexVertex:
vector<Vec3r> vertices; vector<Vec3r> vertices;
unsigned i; unsigned i;
for(i=0; i<iVSize; i+= 3) for (i = 0; i < iVSize; i += 3) {
{ vertices.push_back(Vec3r(iVertices[i], iVertices[i + 1], iVertices[i + 2]));
vertices.push_back(Vec3r(iVertices[i], iVertices[i+1], iVertices[i+2])); }
}
unsigned *mapVertex = new unsigned[iVSize]; unsigned *mapVertex = new unsigned[iVSize];
vector<Vec3r>::iterator v = vertices.begin(); vector<Vec3r>::iterator v = vertices.begin();
vector<Vec3r> compressedVertices;
Vec3r previous = *v;
mapVertex[0] = 0;
compressedVertices.push_back(vertices.front());
v++; vector<Vec3r> compressedVertices;
Vec3r current; Vec3r previous = *v;
i=1; mapVertex[0] = 0;
for(; v!=vertices.end(); v++) compressedVertices.push_back(vertices.front());
{
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: v++;
*oVSize = 3*compressedVertices.size(); Vec3r current;
*oVertices = new real [*oVSize]; i = 1;
i=0; for (; v != vertices.end(); v++) {
for(v=compressedVertices.begin(); v!=compressedVertices.end(); v++) current = *v;
{ if (current == previous)
(*oVertices)[i] = (*v)[0]; mapVertex[i] = compressedVertices.size() - 1;
(*oVertices)[i+1] = (*v)[1]; else {
(*oVertices)[i+2] = (*v)[2]; compressedVertices.push_back(current);
i += 3; mapVertex[i] = compressedVertices.size() - 1;
} }
previous = current;
i++;
}
// Map the index array: // Builds the resulting vertex array:
*oIndices = new unsigned[iISize]; *oVSize = 3 * compressedVertices.size();
for(i=0; i<iISize; i++) *oVertices = new real[*oVSize];
{ i = 0;
(*oIndices)[i] = 3*mapVertex[iIndices[i]/3]; for (v = compressedVertices.begin(); v != compressedVertices.end(); v++) {
} (*oVertices)[i] = (*v)[0];
(*oVertices)[i + 1] = (*v)[1];
(*oVertices)[i + 2] = (*v)[2];
i += 3;
}
delete [] mapVertex; // 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, void GeomCleaner::SortAndCompressIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices,
const unsigned *iIndices, unsigned iISize, unsigned iISize, real **oVertices, unsigned *oVSize,
real **oVertices, unsigned *oVSize,
unsigned **oIndices) unsigned **oIndices)
{ {
// tmp arrays used to store the sorted data:
real *tmpVertices;
unsigned *tmpIndices;
// tmp arrays used to store the sorted data: Chronometer chrono;
real *tmpVertices; // Sort data
unsigned *tmpIndices; chrono.start();
GeomCleaner::SortIndexedVertexArray(iVertices, iVSize, iIndices, iISize, &tmpVertices, &tmpIndices);
printf("Sorting: %lf\n", chrono.stop());
Chronometer chrono; // compress data
// Sort data chrono.start();
chrono.start(); GeomCleaner::CompressIndexedVertexArray(tmpVertices, iVSize, tmpIndices, iISize, oVertices, oVSize, oIndices);
GeomCleaner::SortIndexedVertexArray(iVertices, iVSize, printf("Merging: %lf\n", chrono.stop());
iIndices, iISize,
&tmpVertices, &tmpIndices
);
printf("Sorting: %lf\n", chrono.stop());
// compress data // deallocates memory:
chrono.start(); delete [] tmpVertices;
GeomCleaner::CompressIndexedVertexArray(tmpVertices, iVSize, delete [] tmpIndices;
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 */ /*! Defines a hash table used for searching the Cells */
struct GeomCleanerHasher{ struct GeomCleanerHasher{
#define _MUL 950706376UL #define _MUL 950706376UL
#define _MOD 2147483647UL #define _MOD 2147483647UL
inline size_t operator() (const Vec3r& p) const { 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; size_t res = ((unsigned long) (p[0] * _MUL)) % _MOD;
return ((res +(unsigned long) (p[2]) * _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, void GeomCleaner::CleanIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices,
const unsigned *iIndices, unsigned iISize, unsigned iISize, real **oVertices, unsigned *oVSize, unsigned **oIndices)
real **oVertices, unsigned *oVSize,
unsigned **oIndices)
{ {
typedef map<Vec3r, unsigned> cleanHashTable; typedef map<Vec3r, unsigned> cleanHashTable;
vector<Vec3r> vertices; vector<Vec3r> vertices;
unsigned i; unsigned i;
for(i=0; i<iVSize; i+= 3) for (i = 0; i < iVSize; i += 3)
vertices.push_back(Vec3r(iVertices[i], iVertices[i+1], iVertices[i+2])); 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: cleanHashTable ht;
*oVSize = 3*newVertices.size(); vector<unsigned> newIndices;
*oVertices = new real[*oVSize]; vector<Vec3r> newVertices;
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: // elimination of needless points
*oIndices = new unsigned[iISize]; unsigned currentIndex = 0;
for(i=0; i<iISize; i++) vector<Vec3r>::const_iterator v = vertices.begin();
(*oIndices)[i] = 3*newIndices[iIndices[i]/3]; 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];
} }

@ -1,219 +1,227 @@
// /*
// Filename : GeomCleaner.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author : Stephane Grabli *
// Purpose : Class to define a cleaner of geometry providing * This program is free software; you can redistribute it and/or
// a set of useful tools * modify it under the terms of the GNU General Public License
// Date of creation : 04/03/2002 * 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
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to define a cleaner of geometry providing a set of useful tools
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 04/03/2002
// 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 #include "Geom.h"
# define GEOMCLEANER_H
# include "../system/FreestyleConfig.h" #include "../system/FreestyleConfig.h"
# include "Geom.h"
using namespace Geometry; using namespace Geometry;
class LIB_GEOMETRY_EXPORT GeomCleaner class LIB_GEOMETRY_EXPORT GeomCleaner
{ {
public: public:
inline GeomCleaner() {}
inline ~GeomCleaner() {}
inline GeomCleaner() {} /*! Sorts an array of Indexed vertices
inline ~GeomCleaner() {} * 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);
/*! Sorts an array of Indexed vertices /*! Compress a SORTED indexed vertex array by eliminating multiple appearing occurences of a single vertex.
* iVertices * iVertices
* Array of vertices to sort. It is organized as a * The SORTED vertex array to compress. It is organized as a float series of vertex coordinates: XYZXYZXYZ...
* float series of vertex coordinates: XYZXYZXYZ... * iVSize
* iVSize * The size of iVertices array.
* The size of iVertices array. * iIndices
* iIndices * The array containing the vertex indices (used to refer to the vertex coordinates in an indexed face).
* The array containing the vertex indices (used to refer * Each element is an unsignedeger multiple of 3.
* to the vertex coordinates in an indexed face). Each * iISize
* element is an unsignedeger multiple of 3. * The size of iIndices array
* iISize * oVertices
* The size of iIndices array * The vertex array, result of the compression.
* oVertices * The array is organized as a 3-float serie giving the vertices coordinates: XYZXYZXYZ...
* Output of sorted vertices. A vertex v1 precedes another one * oVSize
* v2 in this array if v1.x<v2.x, or v1.x=v2.x && v1.y < v2.y * The size of oVertices.
* or v1.x=v2.y && v1.y=v2.y && v1.z < v2.z. * oIndices
* The array is organized as a 3-float serie giving * The indices array, reorganized to match the compressed oVertices array.
* the vertices coordinates: XYZXYZXYZ... */
* oIndices static void CompressIndexedVertexArray(const real *iVertices, unsigned iVSize, const unsigned *iIndices,
* Output corresponding to the iIndices array but unsigned iISize, real **oVertices, unsigned *oVSize, unsigned **oIndices);
* reorganized in order to match the sorted vertex array.
*/
static void SortIndexedVertexArray(const float *iVertices, unsigned iVSize, /*! Sorts and compress an array of indexed vertices.
const unsigned *iIndices, unsigned iISize, * iVertices
real **oVertices, * The vertex array to sort then compress. It is organized as a float series of
unsigned **oIndices); * 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);
/*! Compress a SORTED indexed vertex array by eliminating /*! Cleans an indexed vertex array. (Identical to SortAndCompress except that we use here a hash table
* multiple appearing occurences of a single vertex. * to create the new array.)
* iVertices * iVertices
* The SORTED vertex array to compress. It is organized as a * The vertex array to sort then compress. It is organized as a float series of
* float series of vertex coordinates: XYZXYZXYZ... * vertex coordinates: XYZXYZXYZ...
* iVSize * iVSize
* The size of iVertices array. * The size of iVertices array.
* iIndices * iIndices
* The array containing the vertex indices (used to refer * The array containing the vertex indices (used to refer to the vertex coordinates in an indexed face).
* to the vertex coordinates in an indexed face). Each * Each element is an unsignedeger multiple of 3.
* element is an unsignedeger multiple of 3. * iISize
* iISize * The size of iIndices array
* The size of iIndices array * oVertices
* oVertices * The vertex array, result of the sorting-compression.
* The vertex array, result of the compression. * The array is organized as a 3-float serie giving the vertices coordinates: XYZXYZXYZ...
* The array is organized as a 3-float serie giving * oVSize
* the vertices coordinates: XYZXYZXYZ... * The size of oVertices.
* oVSize * oIndices
* The size of oVertices. * The indices array, reorganized to match the sorted and compressed oVertices array.
* oIndices */
* The indices array, reorganized to match the compressed static void CleanIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices,
* oVertices array. unsigned iISize, real **oVertices, unsigned *oVSize, unsigned **oIndices);
*/
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 */ /*! Binary operators */
//inline bool operator<(const IndexedVertex& iv1, const IndexedVertex& iv2); //inline bool operator<(const IndexedVertex& iv1, const IndexedVertex& iv2);
/*! Class Indexed Vertex. Used to represent /*! Class Indexed Vertex. Used to represent an indexed vertex by storing the vertex coordinates as well as its index */
* an indexed vertex by storing the vertex
* coordinates as well as its index
*/
class IndexedVertex class IndexedVertex
{ {
public:
private: private:
Vec3r _Vector; Vec3r _Vector;
unsigned _index; 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 */ public:
IndexedVertex& operator=(const IndexedVertex& iv) inline IndexedVertex() {}
{
_Vector = iv._Vector; inline IndexedVertex(Vec3r iVector, unsigned iIndex)
_index = iv._index; {
return *this; _Vector = iVector;
} _index = iIndex;
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 /*! accessors */
{ inline const Vec3r& vector() const
return (_Vector < v._Vector); {
} return _Vector;
inline bool operator==(const IndexedVertex& v) }
{
return (_Vector == v._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) #if 0
//{ bool operator<(const IndexedVertex& iv1, const IndexedVertex& iv2)
// return iv1.operator<(iv2); {
//} return iv1.operator<(iv2);
}
#endif
#endif // GEOMCLEANER_H #endif // __GEOMCLEANER_H__

File diff suppressed because it is too large Load Diff

@ -1,310 +1,277 @@
// /*
// Filename : GeomUtils.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Stephane Grabli *
// Purpose : Various tools for geometry * This program is free software; you can redistribute it and/or
// Date of creation : 12/04/2002 * 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
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Various tools for geometry
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 12/04/2002
// 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 GEOMUTILS_H #include <vector>
# define GEOMUTILS_H
# include <vector> #include "Geom.h"
# include "../system/FreestyleConfig.h"
# include "Geom.h" #include "../system/FreestyleConfig.h"
using namespace std; using namespace std;
using namespace Geometry; using namespace Geometry;
namespace GeomUtils { namespace GeomUtils {
// //
// Templated procedures // Templated procedures
// //
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/*! Computes the distance from a point P to a segment AB */ /*! Computes the distance from a point P to a segment AB */
template<class T> template<class T>
real distPointSegment( const T& P, const T& A , const T& B) { real distPointSegment( const T& P, const T& A , const T& B)
T AB, AP, BP; {
AB = B - A; T AB, AP, BP;
AP = P - A; AB = B - A;
BP = P - B; AP = P - A;
BP = P - B;
real c1(AB * AP); real c1(AB * AP);
if (c1 <= 0) if (c1 <= 0)
return AP.norm(); return AP.norm();
real c2(AB * AB); real c2(AB * AB);
if (c2 <= c1) if (c2 <= c1)
return BP.norm(); return BP.norm();
real b = c1 / c2; real b = c1 / c2;
T Pb, PPb; T Pb, PPb;
Pb = A + b * AB; Pb = A + b * AB;
PPb = P - Pb; PPb = P - Pb;
return PPb.norm(); return PPb.norm();
} }
// //
// Non-templated procedures // Non-templated procedures
// //
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
typedef enum {
DONT_INTERSECT,
DO_INTERSECT,
COLINEAR,
COINCIDENT,
} intersection_test;
typedef enum { LIB_GEOMETRY_EXPORT
DONT_INTERSECT, intersection_test intersect2dSeg2dSeg(const Vec2r& p1, const Vec2r& p2, // first segment
DO_INTERSECT, const Vec2r& p3, const Vec2r& p4, // second segment
COLINEAR, Vec2r& res); // found intersection point
COINCIDENT
} intersection_test;
LIB_GEOMETRY_EXPORT LIB_GEOMETRY_EXPORT
intersection_test intersect2dSeg2dSeg(const Vec2r& p1, const Vec2r& p2, // first segment intersection_test intersect2dLine2dLine(const Vec2r& p1, const Vec2r& p2, // first segment
const Vec2r& p3, const Vec2r& p4, // second segment const Vec2r& p3, const Vec2r& p4, // second segment
Vec2r& res); // found intersection point Vec2r& res); // found intersection point
LIB_GEOMETRY_EXPORT LIB_GEOMETRY_EXPORT
intersection_test intersect2dLine2dLine(const Vec2r& p1, const Vec2r& p2, // first segment intersection_test intersect2dSeg2dSegParametric(const Vec2r& p1, const Vec2r& p2, // first segment
const Vec2r& p3, const Vec2r& p4, // second segment const Vec2r& p3, const Vec2r& p4, // second segment
Vec2r& res); // found intersection point real& t, // I = P1 + t * P1P2)
real& u, // I = P3 + u * P3P4
real epsilon = M_EPSILON);
LIB_GEOMETRY_EXPORT /*! check whether a 2D segment intersect a 2D region or not */
intersection_test intersect2dSeg2dSegParametric(const Vec2r& p1, const Vec2r& p2, // first segment LIB_GEOMETRY_EXPORT
const Vec2r& p3, const Vec2r& p4, // second segment bool intersect2dSeg2dArea(const Vec2r& min, const Vec2r& max, const Vec2r& A, const Vec2r& B);
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 */ /*! check whether a 2D segment is included in a 2D region or not */
LIB_GEOMETRY_EXPORT LIB_GEOMETRY_EXPORT
bool intersect2dSeg2dArea(const Vec2r& min, bool include2dSeg2dArea(const Vec2r& min, const Vec2r& max, const Vec2r& A, const Vec2r& B);
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 */ /*! Box-triangle overlap test, adapted from Tomas Akenine-Möller code */
LIB_GEOMETRY_EXPORT LIB_GEOMETRY_EXPORT
bool overlapTriangleBox(Vec3r& boxcenter, bool overlapTriangleBox(Vec3r& boxcenter, Vec3r& boxhalfsize, Vec3r triverts[3]);
Vec3r& boxhalfsize,
Vec3r triverts[3]);
/*! Fast, Minimum Storage Ray-Triangle Intersection, /*! Fast, Minimum Storage Ray-Triangle Intersection, adapted from Tomas Möller and Ben Trumbore code. */
* 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,
LIB_GEOMETRY_EXPORT real& t, // I = orig + t * dir
bool intersectRayTriangle(const Vec3r& orig, const Vec3r& dir, real& u, real& v, // I = (1 - u - v) * v0 + u * v1 + v * v2
const Vec3r& v0, const Vec3r& v1, const Vec3r& v2, const real epsilon = M_EPSILON); // the epsilon to use
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 /*! Intersection between plane and ray adapted from Graphics Gems, Didier Badouel */
* adapted from Graphics Gems, Didier Badouel LIB_GEOMETRY_EXPORT
*/ intersection_test intersectRayPlane(const Vec3r& orig, const Vec3r& dir, // ray origin and direction
LIB_GEOMETRY_EXPORT // plane's normal and offset (plane = { P / P.N + d = 0 })
intersection_test intersectRayPlane(const Vec3r& orig, const Vec3r& dir, // ray origin and direction const Vec3r& norm, const real d,
const Vec3r& norm, const real d, // plane's normal and offset (plane = { P / P.N + d = 0 }) real& t, // I = orig + t * dir
real& t, // I = orig + t * dir const real epsilon = M_EPSILON); // the epsilon to use
const real epsilon = M_EPSILON); // the epsilon to use
/*! Intersection Ray-Bounding box (axis aligned). /*! Intersection Ray-Bounding box (axis aligned).
* Adapted from Williams et al, "An Efficient Robust Ray-Box Intersection Algorithm", * Adapted from Williams et al, "An Efficient Robust Ray-Box Intersection Algorithm", JGT 10:1 (2005), pp. 49-54.
* JGT 10:1 (2005), pp. 49-54. */
* Returns LIB_GEOMETRY_EXPORT
*/ bool intersectRayBBox(const Vec3r& orig, const Vec3r& dir, // ray origin and direction
LIB_GEOMETRY_EXPORT const Vec3r& boxMin, const Vec3r& boxMax, // the bbox
bool intersectRayBBox(const Vec3r& orig, const Vec3r& dir, // ray origin and direction // the interval in which at least on of the intersections must happen
const Vec3r& boxMin, const Vec3r& boxMax, // the bbox real t0, real t1,
real t0, real t1, // the interval in which at least on of the intersections must happen real& tmin, // Imin = orig + tmin * dir is the first intersection
real& tmin, real& tmax, // Imin=orig+tmin*dir is the first intersection, Imax=orig+tmax*dir is the second intersection real& tmax, // Imax = orig + tmax * dir is the second intersection
real epsilon = M_EPSILON); // the epsilon to use real epsilon = M_EPSILON); // the epsilon to use
/*! Checks whether 3D point P lies inside or outside of the triangle ABC */
LIB_GEOMETRY_EXPORT
bool includePointTriangle(const Vec3r& P, const Vec3r& A, const Vec3r& B, const Vec3r& C);
/*! Checks whether 3D point P lies inside or outside of the triangle ABC */ LIB_GEOMETRY_EXPORT
LIB_GEOMETRY_EXPORT void transformVertex(const Vec3r& vert, const Matrix44r& matrix, Vec3r& res);
bool includePointTriangle(const Vec3r& P,
const Vec3r& A,
const Vec3r& B,
const Vec3r& C);
LIB_GEOMETRY_EXPORT LIB_GEOMETRY_EXPORT
void transformVertex(const Vec3r& vert, void transformVertices(const vector<Vec3r>& vertices, const Matrix44r& trans, vector<Vec3r>& res);
const Matrix44r& matrix,
Vec3r& res);
LIB_GEOMETRY_EXPORT
void transformVertices(const vector<Vec3r>& vertices,
const Matrix44r& trans,
vector<Vec3r>& res);
LIB_GEOMETRY_EXPORT LIB_GEOMETRY_EXPORT
Vec3r rotateVector(const Matrix44r& mat, const Vec3r& v); Vec3r rotateVector(const Matrix44r& mat, const Vec3r& v);
// //
// Coordinates systems changing procedures // Coordinates systems changing procedures
// //
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/*! From world to image /*! From world to image
* p * p
* point's coordinates expressed in world coordinates system * point's coordinates expressed in world coordinates system
* q * q
* vector in which the result will be stored * vector in which the result will be stored
* model_view_matrix * model_view_matrix
* The model view matrix expressed in line major order (OpenGL * The model view matrix expressed in line major order (OpenGL
* matrices are column major ordered) * matrices are column major ordered)
* projection_matrix * projection_matrix
* The projection matrix expressed in line major order (OpenGL * The projection matrix expressed in line major order (OpenGL
* matrices are column major ordered) * matrices are column major ordered)
* viewport * viewport
* The viewport: x,y coordinates followed by width and height (OpenGL like viewport) * The viewport: x,y coordinates followed by width and height (OpenGL like viewport)
*/ */
LIB_GEOMETRY_EXPORT LIB_GEOMETRY_EXPORT
void fromWorldToImage(const Vec3r& p, void fromWorldToImage(const Vec3r& p, Vec3r& q, const real model_view_matrix[4][4], const real projection_matrix[4][4],
Vec3r& q, const int viewport[4]);
const real model_view_matrix[4][4],
const real projection_matrix[4][4],
const int viewport[4]);
/*! From world to image /*! From world to image
* p * p
* point's coordinates expressed in world coordinates system * point's coordinates expressed in world coordinates system
* q * q
* vector in which the result will be stored * vector in which the result will be stored
* transform * transform
* The transformation matrix (gathering model view and projection), * The transformation matrix (gathering model view and projection),
* expressed in line major order (OpenGL matrices are column major ordered) * expressed in line major order (OpenGL matrices are column major ordered)
* viewport * viewport
* The viewport: x,y coordinates followed by width and height (OpenGL like viewport) * The viewport: x,y coordinates followed by width and height (OpenGL like viewport)
*/ */
LIB_GEOMETRY_EXPORT LIB_GEOMETRY_EXPORT
void fromWorldToImage(const Vec3r& p, void fromWorldToImage(const Vec3r& p, Vec3r& q, const real transform[4][4], const int viewport[4]);
Vec3r& q,
const real transform[4][4],
const int viewport[4]);
/*! Projects from world coordinates to camera coordinates /*! Projects from world coordinates to camera coordinates
* Returns the point's coordinates expressed in the camera's * Returns the point's coordinates expressed in the camera's
* coordinates system. * coordinates system.
* p * p
* point's coordinates expressed in world coordinates system * point's coordinates expressed in world coordinates system
* q * q
* vector in which the result will be stored * vector in which the result will be stored
* model_view_matrix * model_view_matrix
* The model view matrix expressed in line major order (OpenGL * The model view matrix expressed in line major order (OpenGL
* matrices are column major ordered) * matrices are column major ordered)
*/ */
LIB_GEOMETRY_EXPORT LIB_GEOMETRY_EXPORT
void fromWorldToCamera(const Vec3r& p, void fromWorldToCamera(const Vec3r& p, Vec3r& q, const real model_view_matrix[4][4]);
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 /*! Projects from World Coordinates to retina coordinates
* Returns the point's coordinates expressed in the world's * Returns the point's coordinates expressed in Retina system.
* coordinates system. * p
* p * point's coordinates expressed in camera system
* point's coordinates expressed in the camera coordinates system * q
* q * vector in which the result will be stored
* vector in which the result will be stored * projection_matrix
* model_view_matrix * The projection matrix expressed in line major order (OpenGL
* The model view matrix expressed in line major order (OpenGL * matrices are column major ordered)
* matrices are column major ordered) */
*/ LIB_GEOMETRY_EXPORT
LIB_GEOMETRY_EXPORT void fromCameraToRetina(const Vec3r& p, Vec3r& q, const real projection_matrix[4][4]);
void fromCameraToWorld(const Vec3r& p,
Vec3r& q, /*! From retina to image.
const real model_view_matrix[4][4]); * 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 } // end of namespace GeomUtils
#endif // GEOMUTILS_H #endif // __GEOMUTILS_H__

@ -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
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Base class to define a cell grid surrounding the bounding box of the scene
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 30/07/2002
// 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 <cassert>
#include <stdexcept> #include <stdexcept>
#include "BBox.h"
#include "Grid.h"
// Grid Visitors // Grid Visitors
///////////////// /////////////////
void allOccludersGridVisitor::examineOccluder(Polygon3r *occ){ void allOccludersGridVisitor::examineOccluder(Polygon3r *occ)
occluders_.push_back(occ); {
occluders_.push_back(occ);
} }
static bool inBox(const Vec3r& inter, const Vec3r& box_min, const Vec3r& box_max){ 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())) if (((inter.x() >= box_min.x()) && (inter.x() < box_max.x())) &&
&& ((inter.z()>=box_min.z()) && (inter.z() <box_max.z())) ((inter.y() >= box_min.y()) && (inter.y() < box_max.y())) &&
){ ((inter.z() >= box_min.z()) && (inter.z() < box_max.z())))
return true; {
} return true;
return false; }
} 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;
}
}
}
} }
bool firstIntersectionGridVisitor::stop(){ void firstIntersectionGridVisitor::examineOccluder(Polygon3r *occ)
if(occluder_) {
return true; // check whether the edge and the polygon plane are coincident:
return false; //-------------------------------------------------------------
//first let us compute the plane equation.
Vec3r v1(((occ)->getVertices())[0]);
Vec3d normal((occ)->getNormal());
//soc unused - double d = -(v1 * normal);
double tmp_u, tmp_v, tmp_t;
if ((occ)->rayIntersect(ray_org_, ray_dir_, tmp_t, tmp_u, tmp_v)) {
if (fabs(ray_dir_ * normal) > 0.0001) {
// Check whether the intersection is in the cell:
if (inBox(ray_org_ + tmp_t * ray_dir_ / ray_dir_.norm(), current_cell_->getOrigin(),
current_cell_->getOrigin() + cell_size_))
{
#if 0
Vec3d bboxdiag(_scene3d->bbox().getMax() - _scene3d->bbox().getMin());
if ((t > 1.0e-06 * (min(min(bboxdiag.x(), bboxdiag.y()), bboxdiag.z()))) && (t < raylength)) {
#else
if (tmp_t < t_) {
#endif
occluder_ = occ;
u_ = tmp_u;
v_ = tmp_v;
t_ = tmp_t;
}
}
else {
occ->userdata2 = 0;
}
}
}
}
bool firstIntersectionGridVisitor::stop()
{
if (occluder_)
return true;
return false;
} }
// Grid // Grid
///////////////// /////////////////
void Grid::clear()
void Grid::clear() { {
if (_occluders.size() != 0) { if (_occluders.size() != 0) {
for(OccludersSet::iterator it = _occluders.begin(); for (OccludersSet::iterator it = _occluders.begin(); it != _occluders.end(); it++) {
it != _occluders.end(); delete (*it);
it++) { }
delete (*it); _occluders.clear();
}
_occluders.clear();
}
_size = Vec3r(0, 0, 0);
_cell_size = Vec3r(0, 0, 0);
_orig = Vec3r(0, 0, 0);
_cells_nb = Vec3u(0, 0, 0);
//_ray_occluders.clear();
}
void Grid::configure(const Vec3r& orig,
const Vec3r& size,
unsigned nb) {
_orig = orig;
Vec3r tmpSize=size;
// Compute the volume of the desired grid
real grid_vol = size[0] * size[1] * size[2];
if(grid_vol == 0){
double min=DBL_MAX;
int index=0;
int nzeros=0;
for(int i=0;i<3;++i){
if(size[i] == 0){
++nzeros;
index=i;
}
if((size[i]!=0) && (min>size[i])){
min=size[i];
}
}
if(nzeros>1){
throw std::runtime_error("Warning: the 3D grid has more than one null dimension");
}
tmpSize[index]=min;
_orig[index] = _orig[index]-min/2;
}
// Compute the desired volume of a single cell
real cell_vol = grid_vol / nb;
// The edge of such a cubic cell is cubic root of cellVolume
real edge = pow(cell_vol, 1.0 / 3.0);
// We compute the number of cells par edge
// such as we cover at least the whole box.
unsigned i;
for (i = 0; i < 3; i++)
_cells_nb[i] = (unsigned)floor(tmpSize[i] / edge) + 1;
_size = tmpSize;
for(i = 0; i < 3; i++)
_cell_size[i] = _size[i] / _cells_nb[i];
}
void Grid::insertOccluder(Polygon3r* occluder) {
const vector<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. _size = Vec3r(0, 0, 0);
for (z = imin[2]; z <= imax[2]; z++) _cell_size = Vec3r(0, 0, 0);
for (y = imin[1]; y <= imax[1]; y++) _orig = Vec3r(0, 0, 0);
for (x = imin[0]; x <= imax[0]; x++) { _cells_nb = Vec3u(0, 0, 0);
coord[0] = x; //_ray_occluders.clear();
coord[1] = y; }
coord[2] = z;
Cell* cell = getCell(coord); void Grid::configure(const Vec3r& orig, const Vec3r& size, unsigned nb)
if (!cell) { {
Vec3r orig; _orig = orig;
getCellOrigin(coord, orig); Vec3r tmpSize = size;
cell = new Cell(orig); // Compute the volume of the desired grid
fillCell(coord, *cell); real grid_vol = size[0] * size[1] * size[2];
}
cell->addOccluder(occluder); if (grid_vol == 0) {
double min = DBL_MAX;
int index = 0;
int nzeros = 0;
for (int i = 0; i < 3; ++i) {
if (size[i] == 0) {
++nzeros;
index = i;
}
if ((size[i] != 0) && (min > size[i])) {
min = size[i];
}
}
if (nzeros > 1) {
throw std::runtime_error("Warning: the 3D grid has more than one null dimension");
}
tmpSize[index] = min;
_orig[index] = _orig[index] - min / 2;
} }
} // Compute the desired volume of a single cell
real cell_vol = grid_vol / nb;
// The edge of such a cubic cell is cubic root of cellVolume
real edge = pow(cell_vol, 1.0 / 3.0);
// We compute the number of cells par edge such as we cover at least the whole box.
unsigned i;
for (i = 0; i < 3; i++)
_cells_nb[i] = (unsigned)floor(tmpSize[i] / edge) + 1;
_size = tmpSize;
for (i = 0; i < 3; i++)
_cell_size[i] = _size[i] / _cells_nb[i];
} }
bool Grid::nextRayCell(Vec3u& current_cell, Vec3u& next_cell) { void Grid::insertOccluder(Polygon3r* occluder)
next_cell = current_cell; {
real t_min, t; const vector<Vec3r> vertices = occluder->getVertices();
unsigned i; if (vertices.size() == 0)
return;
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)
// add this occluder to the grid's occluders list
addOccluder(occluder);
// using a parametric equation of // find the bbox associated to this polygon
// a line : B = A + t u, we find Vec3r min, max;
// the tx, ty and tz respectively coresponding occluder->getBBox(min, max);
// 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 // Retrieve the cell x, y, z cordinates associated with these min and max
// the found t (tamx) to compute the Vec3u imax, imin;
// B coordinates: getCellCoordinates(max, imax);
Vec3r pt_tmp(_pt); getCellCoordinates(min, imin);
_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; // We are now going to fill in the cells overlapping with the polygon bbox.
if (_t >= _t_end) // If the polygon is a triangle (most of cases), we also check for each of these cells if it is overlapping with
return false; // the triangle in order to only fill in the ones really overlapping the triangle.
return true; 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);
}
}
}
}
} }
void Grid::castRay(const Vec3r& orig, bool Grid::nextRayCell(Vec3u& current_cell, Vec3u& next_cell)
const Vec3r& end, {
OccludersSet& occluders, next_cell = current_cell;
unsigned timestamp) { real t_min, t;
initRay(orig, end, timestamp); unsigned i;
allOccludersGridVisitor visitor(occluders);
castRayInternal(visitor); t_min = FLT_MAX; // init tmin with handle of the case where one or 2 _u[i] = 0.
unsigned coord = 0; // predominant coord(0=x, 1=y, 2=z)
// using a parametric equation of a line : B = A + t u, we find the tx, ty and tz respectively coresponding
// to the intersections with the plans:
// x = _cell_size[0], y = _cell_size[1], z = _cell_size[2]
for (i = 0; i < 3; i++) {
if (_ray_dir[i] == 0)
continue;
if (_ray_dir[i] > 0)
t = (_cell_size[i] - _pt[i]) / _ray_dir[i];
else
t = -_pt[i] / _ray_dir[i];
if (t < t_min) {
t_min = t;
coord = i;
}
}
// We use the parametric line equation and the found t (tamx) to compute the B coordinates:
Vec3r pt_tmp(_pt);
_pt = pt_tmp + t_min * _ray_dir;
// We express B coordinates in the next cell coordinates system. We just have to
// set the coordinate coord of B to 0 of _CellSize[coord] depending on the sign of _u[coord]
if (_ray_dir[coord] > 0) {
next_cell[coord]++;
_pt[coord] -= _cell_size[coord];
// if we are out of the grid, we must stop
if (next_cell[coord] >= _cells_nb[coord])
return false;
}
else {
int tmp = next_cell[coord] - 1;
_pt[coord] = _cell_size[coord];
if (tmp < 0)
return false;
next_cell[coord]--;
}
_t += t_min;
if (_t >= _t_end)
return false;
return true;
} }
void Grid::castInfiniteRay(const Vec3r& orig, void Grid::castRay(const Vec3r& orig, const Vec3r& end, OccludersSet& occluders, unsigned timestamp)
const Vec3r& dir, {
OccludersSet& occluders, initRay(orig, end, timestamp);
unsigned timestamp) { allOccludersGridVisitor visitor(occluders);
Vec3r end = Vec3r(orig + FLT_MAX * dir / dir.norm()); castRayInternal(visitor);
bool inter = initInfiniteRay(orig, dir, timestamp);
if(!inter)
return;
allOccludersGridVisitor visitor(occluders);
castRayInternal(visitor);
} }
Polygon3r* Grid::castRayToFindFirstIntersection(const Vec3r& orig, void Grid::castInfiniteRay(const Vec3r& orig, const Vec3r& dir, OccludersSet& occluders, unsigned timestamp)
const Vec3r& dir, {
double& t, Vec3r end = Vec3r(orig + FLT_MAX * dir / dir.norm());
double& u, bool inter = initInfiniteRay(orig, dir, timestamp);
double& v, if (!inter)
unsigned timestamp){ return;
Polygon3r *occluder = 0; allOccludersGridVisitor visitor(occluders);
Vec3r end = Vec3r(orig + FLT_MAX * dir / dir.norm()); castRayInternal(visitor);
bool inter = initInfiniteRay(orig, dir, timestamp); }
if(!inter){
return 0; Polygon3r* Grid::castRayToFindFirstIntersection(const Vec3r& orig, const Vec3r& dir, double& t,
} double& u, double& v, unsigned timestamp)
firstIntersectionGridVisitor visitor(orig,dir,_cell_size); {
castRayInternal(visitor); 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 // ARB: This doesn't work, because occluders are unordered within any cell
// visitor.occluder() will be an occluder, but we have no guarantee // visitor.occluder() will be an occluder, but we have no guarantee it will be the *first* occluder.
// it will be the *first* occluder.
// I assume that is the reason this code is not actually used for FindOccludee. // I assume that is the reason this code is not actually used for FindOccludee.
occluder = visitor.occluder(); occluder = visitor.occluder();
t = visitor.t_; t = visitor.t_;
u = visitor.u_; u = visitor.u_;
v = visitor.v_; v = visitor.v_;
return occluder; return occluder;
} }
void Grid::initRay (const Vec3r &orig, void Grid::initRay (const Vec3r &orig, const Vec3r& end, unsigned timestamp)
const Vec3r& end, {
unsigned timestamp) { _ray_dir = end - orig;
_ray_dir = end - orig; _t_end = _ray_dir.norm();
_t_end = _ray_dir.norm(); _t = 0;
_t = 0; _ray_dir.normalize();
_ray_dir.normalize(); _timestamp = timestamp;
_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();
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, bool Grid::initInfiniteRay (const Vec3r &orig, const Vec3r& dir, unsigned timestamp) {
const Vec3r& dir, _ray_dir = dir;
unsigned timestamp) { _t_end = FLT_MAX;
_ray_dir = dir; _t = 0;
_t_end = FLT_MAX; _ray_dir.normalize();
_t = 0; _timestamp = timestamp;
_ray_dir.normalize();
_timestamp = timestamp;
// check whether the origin is in or out the box: // check whether the origin is in or out the box:
Vec3r boxMin(_orig); Vec3r boxMin(_orig);
Vec3r boxMax(_orig+_size); Vec3r boxMax(_orig + _size);
BBox<Vec3r> box(boxMin, boxMax); BBox<Vec3r> box(boxMin, boxMax);
if(box.inside(orig)){ if (box.inside(orig)) {
for(unsigned i = 0; i < 3; i++) { for (unsigned int i = 0; i < 3; i++) {
_current_cell[i] = (unsigned)floor((orig[i] - _orig[i]) / _cell_size[i]); _current_cell[i] = (unsigned int)floor((orig[i] - _orig[i]) / _cell_size[i]);
//soc unused - unsigned u = _current_cell[i]; //soc unused - unsigned u = _current_cell[i];
_pt[i] = orig[i] - _orig[i] - _current_cell[i] * _cell_size[i]; _pt[i] = orig[i] - _orig[i] - _current_cell[i] * _cell_size[i];
} }
}else{ }
// is the ray intersecting the box? else {
real tmin(-1.0), tmax(-1.0); // is the ray intersecting the box?
if(GeomUtils::intersectRayBBox(orig, _ray_dir, boxMin, boxMax, 0, _t_end, tmin, tmax)){ real tmin(-1.0), tmax(-1.0);
assert(tmin != -1.0); if (GeomUtils::intersectRayBBox(orig, _ray_dir, boxMin, boxMax, 0, _t_end, tmin, tmax)) {
Vec3r newOrig = orig + tmin*_ray_dir; assert(tmin != -1.0);
for(unsigned i = 0; i < 3; i++) { Vec3r newOrig = orig + tmin * _ray_dir;
_current_cell[i] = (unsigned)floor((newOrig[i] - _orig[i]) / _cell_size[i]); for (unsigned int i = 0; i < 3; i++) {
if(_current_cell[i] == _cells_nb[i]) _current_cell[i] = (unsigned)floor((newOrig[i] - _orig[i]) / _cell_size[i]);
_current_cell[i] = _cells_nb[i] - 1; if (_current_cell[i] == _cells_nb[i])
//soc unused - unsigned u = _current_cell[i]; _current_cell[i] = _cells_nb[i] - 1;
_pt[i] = newOrig[i] - _orig[i] - _current_cell[i] * _cell_size[i]; //soc unused - unsigned u = _current_cell[i];
} _pt[i] = newOrig[i] - _orig[i] - _current_cell[i] * _cell_size[i];
}
}else{ }
return false; else {
} return false;
} }
//_ray_occluders.clear(); }
//_ray_occluders.clear();
return true;
return true;
} }

@ -1,49 +1,54 @@
// /*
// Filename : Grid.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Stephane Grabli *
// Purpose : Base class to define a cell grid surrounding * This program is free software; you can redistribute it and/or
// the bounding box of the scene * modify it under the terms of the GNU General Public License
// Date of creation : 30/07/2002 * 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__
// /** \file blender/freestyle/intern/geometry/Grid.h
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Base class to define a cell grid surrounding the bounding box of the scene
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 30/07/2002
// 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 GRID_H #include <cstring> // for memset
# define GRID_H #include <float.h>
#include <vector>
# include <cstring> // for memset #include "Geom.h"
# include <float.h> #include "GeomUtils.h"
# include <vector> #include "Polygon.h"
# include "../system/FreestyleConfig.h"
# include "GeomUtils.h" #include "../system/FreestyleConfig.h"
# include "Geom.h"
# include "Polygon.h"
using namespace std; using namespace std;
using namespace Geometry; using namespace Geometry;
typedef vector<Polygon3r*> OccludersSet; typedef vector<Polygon3r*> OccludersSet;
// //
// Class to define cells used by the regular grid // Class to define cells used by the regular grid
@ -52,84 +57,102 @@ typedef vector<Polygon3r*> OccludersSet;
class LIB_GEOMETRY_EXPORT Cell class LIB_GEOMETRY_EXPORT Cell
{ {
public: public:
Cell(Vec3r& orig) {
Cell(Vec3r& orig) { _orig = orig;
_orig = orig; }
}
virtual ~Cell() {} virtual ~Cell() {}
inline void addOccluder(Polygon3r* o) { inline void addOccluder(Polygon3r* o) {
if (o) if (o)
_occluders.push_back(o); _occluders.push_back(o);
} }
inline const Vec3r& getOrigin() { inline const Vec3r& getOrigin() {
return _orig; return _orig;
} }
inline OccludersSet& getOccluders() { inline OccludersSet& getOccluders() {
return _occluders; return _occluders;
} }
private:
Vec3r _orig; private:
OccludersSet _occluders; Vec3r _orig;
OccludersSet _occluders;
}; };
class GridVisitor{ class GridVisitor
{
public: public:
virtual ~GridVisitor() {}; //soc virtual ~GridVisitor() {}; //soc
virtual void discoverCell(Cell *cell) {}
virtual void examineOccluder(Polygon3r *occ) {} virtual void discoverCell(Cell *cell) {}
virtual void finishCell(Cell *cell) {}
virtual bool stop() {return false;} virtual void examineOccluder(Polygon3r *occ) {}
virtual void finishCell(Cell *cell) {}
virtual bool stop() {
return false;
}
}; };
/*! Gathers all the occluders belonging to the cells /*! Gathers all the occluders belonging to the cells traversed by the ray */
* traversed by the ray */ class allOccludersGridVisitor : public GridVisitor
class allOccludersGridVisitor : public GridVisitor{ {
public: public:
allOccludersGridVisitor(OccludersSet& occluders) allOccludersGridVisitor(OccludersSet& occluders) : GridVisitor(), occluders_(occluders) {}
:GridVisitor(), occluders_(occluders){}
virtual void examineOccluder(Polygon3r *occ);
OccludersSet& occluders() {return occluders_;} virtual void examineOccluder(Polygon3r *occ);
void clear() {occluders_.clear();}
OccludersSet& occluders() {
return occluders_;
}
void clear() {
occluders_.clear();
}
private: private:
OccludersSet& occluders_; OccludersSet& occluders_;
}; };
/*! Finds the first intersection and breaks. The occluder and /*! Finds the first intersection and breaks.
* the intersection information are stored and accessible. * The occluder and the intersection information are stored and accessible.
*/ */
class firstIntersectionGridVisitor : public GridVisitor { class firstIntersectionGridVisitor : public GridVisitor
{
//soc - changed order to remove warnings //soc - changed order to remove warnings
public: public:
double u_, v_, t_; double u_, v_, t_;
private: private:
Polygon3r *occluder_; Polygon3r *occluder_;
Vec3r ray_org_, ray_dir_, cell_size_; Vec3r ray_org_, ray_dir_, cell_size_;
Cell * current_cell_; Cell *current_cell_;
public: public:
firstIntersectionGridVisitor(const Vec3r& ray_org, const Vec3r& ray_dir, const Vec3r& cell_size) : firstIntersectionGridVisitor(const Vec3r& ray_org, const Vec3r& ray_dir, const Vec3r& cell_size) :
GridVisitor(), u_(0),v_(0),t_(DBL_MAX), GridVisitor(), u_(0),v_(0),t_(DBL_MAX), occluder_(0), ray_org_(ray_org), ray_dir_(ray_dir),
occluder_(0), cell_size_(cell_size), current_cell_(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 ~firstIntersectionGridVisitor() {}
virtual void examineOccluder(Polygon3r *occ);
virtual bool stop();
Polygon3r * occluder() {return occluder_;} virtual void discoverCell(Cell *cell) {
current_cell_ = cell;
}
virtual void examineOccluder(Polygon3r *occ);
virtual bool stop();
Polygon3r *occluder() {
return occluder_;
}
}; };
// //
@ -140,236 +163,197 @@ public:
class LIB_GEOMETRY_EXPORT Grid class LIB_GEOMETRY_EXPORT Grid
{ {
public: public:
/*! Builds a Grid. Must be followed by a call to configure() */
Grid() {}
/*! Builds a Grid virtual ~Grid() {
* Must be followed by a call to configure() clear();
*/ }
Grid() {}
virtual ~Grid() { /*! clears the grid
clear(); * Deletes all the cells, clears the hashtable, resets size, size of cell, number of cells.
} */
virtual void clear();
/*! clears the grid /*! Sets the different parameters of the grid
* Deletes all the cells, clears the hashtable, * orig
* resets size, size of cell, number of cells. * The grid origin
*/ * size
virtual void clear(); * The grid's dimensions
* nb
* The number of cells of the grid
*/
virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb);
/*! Sets the different parameters of the grid /*! returns a vector of integer containing the coordinates of the cell containing the point passed as argument
* orig * p
* The grid origin * The point for which we're looking the cell
* size */
* The grid's dimensions inline void getCellCoordinates(const Vec3r& p, Vec3u& res) {
* nb int tmp;
* The number of cells of the grid for (int i = 0; i < 3; i++) {
*/ tmp = (int)((p[i] - _orig[i]) / _cell_size[i]);
virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb); if (tmp < 0)
res[i] = 0;
/*! returns a vector of integer containing the else if ((unsigned int)tmp >= _cells_nb[i])
* coordinates of the cell containing the point res[i] = _cells_nb[i] - 1;
* passed as argument else
* p res[i] = tmp;
* 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 */ /*! Fills the case corresponding to coord with the cell */
virtual void fillCell(const Vec3u& coord, Cell& cell) = 0; virtual void fillCell(const Vec3u& coord, Cell& cell) = 0;
/*! returns the cell whose coordinates /*! returns the cell whose coordinates are pased as argument */
* are pased as argument virtual Cell* getCell(const Vec3u& coord) = 0;
*/
virtual Cell* getCell(const Vec3u& coord) = 0;
/*! returns the cell containing the point /*! returns the cell containing the point passed as argument. If the cell is empty (contains no occluder),
* passed as argument. If the cell is empty * NULL is returned
* (contains no occluder), NULL is returned * p
* p * The point for which we're looking the cell
* The point for which we're looking the cell */
*/ inline Cell* getCell(const Vec3r& p) {
inline Cell* getCell(const Vec3r& p) { Vec3u coord;
Vec3u coord; getCellCoordinates(p, coord);
getCellCoordinates(p, coord); return getCell(coord);
return getCell(coord); }
}
/*! Retrieves the x,y,z coordinates of the origin of the cell whose coordinates (i,j,k) /*! Retrieves the x,y,z coordinates of the origin of the cell whose coordinates (i,j,k) is passed as argument
* is passed as argument * cell_coord
* cell_coord * i,j,k integer coordinates for the cell
* i,j,k integer coordinates for the cell * orig
* orig * x,y,x vector to be filled in with the cell origin's coordinates
* x,y,x vector to be filled in with the cell origin's coordinates */
*/ inline void getCellOrigin(const Vec3u& cell_coord, Vec3r& orig) {
inline void getCellOrigin(const Vec3u& cell_coord, Vec3r& orig) { for (unsigned int i = 0; i < 3; i++)
for (unsigned i = 0; i < 3; i++) orig[i] = _orig[i] + cell_coord[i] * _cell_size[i];
orig[i] = _orig[i] + cell_coord[i] * _cell_size[i]; }
}
/*! Retrieves the box corresponding to the cell whose coordinates /*! Retrieves the box corresponding to the cell whose coordinates are passed as argument.
* are passed as argument. * cell_coord
* cell_coord * i,j,k integer coordinates for the cell
* i,j,k integer coordinates for the cell * min_out
* min_out * The min x,y,x vector of the box. Filled in by the method.
* The min x,y,x vector of the box. Filled in by the method. * max_out
* max_out * The max x,y,z coordinates of the box. Filled in by the method.
* 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) {
inline void getCellBox(const Vec3u& cell_coord, Vec3r& min_out, Vec3r& max_out) { getCellOrigin(cell_coord, min_out);
getCellOrigin(cell_coord, min_out); max_out = min_out + _cell_size;
max_out = min_out + _cell_size; }
}
/*! inserts a convex polygon occluder /*! inserts a convex polygon occluder
* This method is quite coarse insofar as it * This method is quite coarse insofar as it adds all cells intersecting the polygon bounding box
* adds all cells intersecting the polygon bounding box * convex_poly
* convex_poly * The list of 3D points constituing a convex polygon
* The list of 3D points constituing a convex polygon */
*/ void insertOccluder(Polygon3r * convex_poly);
void insertOccluder(Polygon3r * convex_poly);
/*! Adds an occluder to the list of occluders */ /*! Adds an occluder to the list of occluders */
void addOccluder(Polygon3r* occluder) { void addOccluder(Polygon3r* occluder) {
_occluders.push_back(occluder); _occluders.push_back(occluder);
} }
/*! Casts a ray between a starting point and an ending point /*! Casts a ray between a starting point and an ending point
* Returns the list of occluders contained * Returns the list of occluders contained in the cells intersected by this ray
* in the cells intersected by this ray * Starts with a call to InitRay.
* Starts with a call to InitRay. */
*/ void castRay(const Vec3r& orig, const Vec3r& end, OccludersSet& occluders, unsigned timestamp);
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. // Prepares to cast ray without generating OccludersSet
* Returns the list of occluders contained void initAcceleratedRay(const Vec3r& orig, const Vec3r& end, unsigned timestamp);
* 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. /*! 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. * Returns the list of occluders contained in the cells intersected by this ray
* Starts with a call to InitRay. * Starts with a call to InitRay.
*/ */
Polygon3r * castRayToFindFirstIntersection(const Vec3r& orig, void castInfiniteRay(const Vec3r& orig, const Vec3r& dir, OccludersSet& occluders, unsigned timestamp);
const Vec3r& dir,
double& t, // Prepares to cast ray without generating OccludersSet.
double& u, bool initAcceleratedInfiniteRay(const Vec3r& orig, const Vec3r& dir, unsigned timestamp);
double& v,
unsigned timestamp); /*! Casts an infinite ray (still finishing at the end of the grid) from a starting point and in a given direction.
* Returns the 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 /*! Init all structures and values for computing the cells intersected by this new ray */
* the cells intersected by this new ray void initRay(const Vec3r &orig, const Vec3r& end, unsigned timestamp);
*/
void initRay (const Vec3r &orig,
const Vec3r& end,
unsigned timestamp);
/*! Init all structures and values for computing /*! Init all structures and values for computing the cells intersected by this infinite ray.
* the cells intersected by this infinite ray. * Returns false if the ray doesn't intersect the grid.
* Returns false if the ray doesn't intersect the */
* grid. bool initInfiniteRay(const Vec3r &orig, const Vec3r& dir, unsigned timestamp);
*/
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() { /*! Accessors */
cerr << "Cells nb : " << _cells_nb << endl; inline const Vec3r& getOrigin() const {
cerr << "Cell size : " << _cell_size << endl; return _orig;
cerr << "Origin : " << _orig << endl; }
cerr << "Occluders nb : " << _occluders.size() << endl;
}
protected: inline Vec3r gridSize() const {
return _size;
}
/*! Core of castRay and castInfiniteRay, find occluders inline Vec3r getCellSize() const {
* along the given ray return _cell_size;
*/ }
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)));
}
//ARB profiling only:
/*! returns the cell next to the cell inline OccludersSet* getOccluders() {
* passed as argument. return &_occluders;
*/ }
bool nextRayCell(Vec3u& current_cell, Vec3u& next_cell);
unsigned _timestamp; void displayDebug() {
cerr << "Cells nb : " << _cells_nb << endl;
cerr << "Cell size : " << _cell_size << endl;
cerr << "Origin : " << _orig << endl;
cerr << "Occluders nb : " << _occluders.size() << endl;
}
Vec3u _cells_nb; // number of cells for x,y,z axis protected:
Vec3r _cell_size; // cell x,y,z dimensions /*! Core of castRay and castInfiniteRay, find occluders along the given ray */
Vec3r _size; // grid x,y,x dimensions inline void castRayInternal(GridVisitor& visitor) {
Vec3r _orig; // grid origin Cell *current_cell = NULL;
do {
current_cell = getCell(_current_cell);
if (current_cell) {
visitor.discoverCell(current_cell);
OccludersSet& occluders = current_cell->getOccluders(); // FIXME: I had forgotten the ref &
for (OccludersSet::iterator it = occluders.begin(); it != occluders.end(); it++) {
if ((unsigned long)(*it)->userdata2 != _timestamp) {
(*it)->userdata2 = (void*)_timestamp;
visitor.examineOccluder(*it);
}
}
visitor.finishCell(current_cell);
}
} while ((!visitor.stop()) && (nextRayCell(_current_cell, _current_cell)));
}
Vec3r _ray_dir; // direction vector for the ray
Vec3u _current_cell; // The current cell being processed (designated by its 3 coordinates)
Vec3r _pt; // Points corresponding to the incoming and outgoing intersections
// of one cell with the ray
real _t_end; // To know when we are at the end of the ray
real _t;
//OccludersSet _ray_occluders; // Set storing the occluders contained in the cells traversed by a ray /*! returns the cell next to the cell passed as argument. */
OccludersSet _occluders; // List of all occluders inserted in the grid 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 { class VirtualOccludersSet {
public: public:
VirtualOccludersSet(Grid& _grid) : grid (_grid) {}; VirtualOccludersSet(Grid& _grid) : grid (_grid) {};
Polygon3r* begin(); Polygon3r* begin();
Polygon3r* next(); Polygon3r* next();
Polygon3r* next(bool stopOnNewCell); Polygon3r* next(bool stopOnNewCell);
private:
Polygon3r* firstOccluderFromNextCell(); private:
Grid& grid; Polygon3r* firstOccluderFromNextCell();
OccludersSet::iterator it, end; Grid& grid;
OccludersSet::iterator it, end;
}; };
#endif // GRID_H #endif // __GRID_H__

@ -1,49 +1,52 @@
// /*
// Filename : GridHelpers.cpp * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Alexander Beels *
// Purpose : Class to define a cell grid surrounding * This program is free software; you can redistribute it and/or
// the projected image of a scene * modify it under the terms of the GNU General Public License
// Date of creation : 2010-12-21 * 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/GridHelpers.cpp
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to define a cell grid surrounding the projected image of a scene
// * \author Alexander Beels
// This program is free software; you can redistribute it and/or * \date 2010-12-21
// 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 <math.h> #include <math.h>
#include "GridHelpers.h" #include "GridHelpers.h"
void GridHelpers::getDefaultViewProscenium(real viewProscenium[4]) { void GridHelpers::getDefaultViewProscenium(real viewProscenium[4])
{
// Get proscenium boundary for culling // Get proscenium boundary for culling
// bufferZone determines the amount by which the area processed // bufferZone determines the amount by which the area processed should exceed the actual image area.
// should exceed the actual image area. This is intended to // This is intended to avoid visible artifacts generated along the proscenium edge.
// 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
// Perhaps this is no longer needed now that entire view edges // should eliminate visible artifacts.
// are culled at once, since that theoretically should eliminate // To the extent it is still useful, bufferZone should be put into the UI as configurable percentage value
// 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; const real bufferZone = 0.05;
// borderZone describes a blank border outside the proscenium, but // borderZone describes a blank border outside the proscenium, but still inside the image area.
// still inside the image area. Only intended for exposing possible // Only intended for exposing possible artifacts along or outside the proscenium edge during debugging.
// artifacts along or outside the proscenium edge during debugging.
const real borderZone = 0.0; const real borderZone = 0.0;
viewProscenium[0] = freestyle_viewport[2] * (borderZone - bufferZone); viewProscenium[0] = freestyle_viewport[2] * (borderZone - bufferZone);
viewProscenium[1] = freestyle_viewport[2] * (1.0f - 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); viewProscenium[3] = freestyle_viewport[3] * (1.0f - borderZone + bufferZone);
} }
GridHelpers::Transform::~Transform () {} GridHelpers::Transform::~Transform ()
{
}

@ -1,47 +1,55 @@
// /*
// Filename : GridHelpers.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Alexander Beels *
// Purpose : Class to define a cell grid surrounding * This program is free software; you can redistribute it and/or
// the projected image of a scene * modify it under the terms of the GNU General Public License
// Date of creation : 2010-12-13 * 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
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to define a cell grid surrounding the projected image of a scene
// * \author Alexander Beels
// This program is free software; you can redistribute it and/or * \date 2010-12-13
// 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
#include <vector> #include <vector>
#include "Polygon.h"
#include "../winged_edge/WEdge.h"
#include "FRS_freestyle.h" #include "FRS_freestyle.h"
#include "GeomUtils.h" #include "GeomUtils.h"
#include "Polygon.h"
#include "../winged_edge/WEdge.h"
namespace GridHelpers { namespace GridHelpers {
/*! Computes the distance from a point P to a segment AB */ /*! Computes the distance from a point P to a segment AB */
template<class T> 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; T AB, AP, BP;
AB = B - A; AB = B - A;
AP = P - 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 return B; // B is closest point
} }
real b = c1 / c2; real b = c1 / c2;
T Pb, PPb; T Pb, PPb;
Pb = A + b * AB; Pb = A + b * AB;
PPb = P - Pb; PPb = P - Pb;
distance = PPb.norm(); distance = PPb.norm();
return Pb; // closest point lies on AB 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 // First cast a ray from the point onto the polygon plane
// If the ray intersects the polygon, then the intersection point // If the ray intersects the polygon, then the intersection point
// is the closest point on the polygon // is the closest point on the polygon
real t, u, v; 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; return point + poly.getNormal() * t;
} }
// Otherwise, get the nearest point on each edge, and take the closest // Otherwise, get the nearest point on each edge, and take the closest
real distance; real distance;
Vec3r closest = closestPointToSegment(point, poly.getVertices()[2], poly.getVertices()[0], 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; real t;
Vec3r p = closestPointToSegment(point, poly.getVertices()[i], poly.getVertices()[i + 1], t); Vec3r p = closestPointToSegment(point, poly.getVertices()[i], poly.getVertices()[i + 1], t);
if ( t < distance ) { if (t < distance) {
distance = t; distance = t;
closest = p; closest = p;
} }
@ -91,57 +100,63 @@ inline Vec3r closestPointOnPolygon(const Vec3r& point, const Polygon3r& poly) {
return closest; 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 // First cast a ray from the point onto the polygon plane
// If the ray intersects the polygon, then the intersection point // If the ray intersects the polygon, then the intersection point
// is the closest point on the polygon // is the closest point on the polygon
real t, u, v; real t, u, v;
if ( poly.rayIntersect(point, poly.getNormal(), t, u, v) ) { if (poly.rayIntersect(point, poly.getNormal(), t, u, v)) {
return t > 0.0 ? t : -t; return (t > 0.0) ? t : -t;
} }
// Otherwise, get the nearest point on each edge, and take the closest // Otherwise, get the nearest point on each edge, and take the closest
real distance = GeomUtils::distPointSegment(point, poly.getVertices()[2], poly.getVertices()[0]); 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]); real t = GeomUtils::distPointSegment(point, poly.getVertices()[i], poly.getVertices()[i + 1]);
if ( t < distance ) { if (t < distance) {
distance = t; distance = t;
} }
} }
return distance; return distance;
} }
class Transform { class Transform
{
public: public:
virtual ~Transform () =0; virtual ~Transform () = 0;
virtual Vec3r operator()(const Vec3r& point) const =0; virtual Vec3r operator()(const Vec3r& point) const = 0;
}; };
inline bool insideProscenium (const real proscenium[4], const Polygon3r& polygon) { 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 // N.B. The bounding box check is redundant for inserting occluders into cells, because the cell selection code
// guaranteed that the bounding boxes will overlap. // in insertOccluders has already guaranteed that the bounding boxes will overlap.
// First check the viewport edges, since they are the easiest case // First check the viewport edges, since they are the easiest case
// Check if the bounding box is entirely outside the proscenium // Check if the bounding box is entirely outside the proscenium
Vec3r bbMin, bbMax; Vec3r bbMin, bbMax;
polygon.getBBox(bbMin, bbMax); polygon.getBBox(bbMin, bbMax);
if ( bbMax[0] < proscenium[0] if (bbMax[0] < proscenium[0] || bbMin[0] > proscenium[1] || bbMax[1] < proscenium[2] || bbMin[1] > proscenium[3]) {
|| bbMin[0] > proscenium[1]
|| bbMax[1] < proscenium[2]
|| bbMin[1] > proscenium[3] ) {
return false; return false;
} }
Vec3r boxCenter(proscenium[0] + (proscenium[1] - proscenium[0]) / 2.0, proscenium[2] + (proscenium[3] - proscenium[2]) / 2.0, 0.0); Vec3r boxCenter(proscenium[0] + (proscenium[1] - proscenium[0]) / 2.0,
Vec3r boxHalfSize((proscenium[1] - proscenium[0]) / 2.0, (proscenium[3] - proscenium[2]) / 2.0, 1.0); proscenium[2] + (proscenium[3] - proscenium[2]) / 2.0, 0.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 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); 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; vector<Vec3r> points;
// Iterate over vertices, storing projections in 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()); points.push_back((*woe)->GetaVertex()->GetVertex());
} }
@ -150,50 +165,51 @@ inline vector<Vec3r> enumerateVertices(const vector<WOEdge*>& fedges) {
void getDefaultViewProscenium(real viewProscenium[4]); 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; Vec3r bbMin, bbMax;
polygon.getBBox(bbMin, bbMax); polygon.getBBox(bbMin, bbMax);
const real epsilon = 1.0e-6; const real epsilon = 1.0e-6;
if ( bbMin[0] <= proscenium[0] ) { if (bbMin[0] <= proscenium[0]) {
proscenium[0] = bbMin[0] - epsilon; proscenium[0] = bbMin[0] - epsilon;
} }
if ( bbMin[1] <= proscenium[2] ) { if (bbMin[1] <= proscenium[2]) {
proscenium[2] = bbMin[1] - epsilon; proscenium[2] = bbMin[1] - epsilon;
} }
if ( bbMax[0] >= proscenium[1] ) { if (bbMax[0] >= proscenium[1]) {
proscenium[1] = bbMax[0] + epsilon; proscenium[1] = bbMax[0] + epsilon;
} }
if ( bbMax[1] >= proscenium[3] ) { if (bbMax[1] >= proscenium[3]) {
proscenium[3] = bbMax[1] + epsilon; 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; const real epsilon = 1.0e-6;
if ( point[0] <= proscenium[0] ) { if (point[0] <= proscenium[0]) {
proscenium[0] = point[0] - epsilon; proscenium[0] = point[0] - epsilon;
} }
if ( point[1] <= proscenium[2] ) { if (point[1] <= proscenium[2]) {
proscenium[2] = point[1] - epsilon; proscenium[2] = point[1] - epsilon;
} }
if ( point[0] >= proscenium[1] ) { if (point[0] >= proscenium[1]) {
proscenium[1] = point[0] + epsilon; proscenium[1] = point[0] + epsilon;
} }
if ( point[1] >= proscenium[3] ) { if (point[1] >= proscenium[3]) {
proscenium[3] = point[1] + epsilon; proscenium[3] = point[1] + epsilon;
} }
} }
}; }; // GridHelpers namespace
#endif // GRIDHELPERS_H
#endif // __GRIDHELPERS_H__

@ -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 *****
*/
// /** \file blender/freestyle/intern/geometry/HashGrid.cpp
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to define a cell grid surrounding the bounding box of the scene
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 30/07/2002
// 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 "HashGrid.h" #include "HashGrid.h"
void HashGrid::clear() void HashGrid::clear()
{ {
if(!_cells.empty()) { if (!_cells.empty()) {
for(GridHashTable::iterator it = _cells.begin(); for (GridHashTable::iterator it = _cells.begin(); it !=_cells.end(); it++) {
it !=_cells.end(); Cell* cell = (*it).second;
it++) { delete cell;
Cell* cell = (*it).second; }
delete cell; _cells.clear();
} }
_cells.clear();
}
Grid::clear(); Grid::clear();
} }
void HashGrid::configure(const Vec3r& orig, const Vec3r& size, unsigned nb) { void HashGrid::configure(const Vec3r& orig, const Vec3r& size, unsigned nb)
Grid::configure(orig, size, nb); {
Grid::configure(orig, size, nb);
} }

@ -1,109 +1,116 @@
// /*
// Filename : HashGrid.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Stephane Grabli *
// Purpose : Class to define a cell grid surrounding the * This program is free software; you can redistribute it and/or
// bounding box of the scene * modify it under the terms of the GNU General Public License
// Date of creation : 30/07/2002 * 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
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to define a cell grid surrounding the bounding box of the scene
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 30/07/2002
// 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 #if 0
# define HASHGRID_H # if defined(__GNUC__) && (__GNUC__ >= 3)
//# if defined(__GNUC__) && (__GNUC__ >= 3)
// hash_map is not part of the C++ standard anymore; // hash_map is not part of the C++ standard anymore;
// hash_map.h has been kept though for backward compatibility // hash_map.h has been kept though for backward compatibility
//# include <hash_map.h> # include <hash_map.h>
//# else # else
//# include <hash_map> # include <hash_map>
//# endif # endif
#endif
#include <map>
#include "Grid.h"
# include "Grid.h"
# include <map>
/*! Defines a hash table used for searching the Cells */ /*! Defines a hash table used for searching the Cells */
struct GridHasher{ struct GridHasher
{
#define _MUL 950706376UL #define _MUL 950706376UL
#define _MOD 2147483647UL #define _MOD 2147483647UL
inline size_t operator() (const Vec3u& p) const inline size_t operator() (const Vec3u& p) const
{ {
size_t res = ((unsigned long) (p[0] * _MUL)) % _MOD; size_t res = ((unsigned long) (p[0] * _MUL)) % _MOD;
res = ((res + (unsigned long) (p[1]) * _MUL)) % _MOD; res = ((res + (unsigned long) (p[1]) * _MUL)) % _MOD;
return ((res +(unsigned long) (p[2]) * _MUL)) % _MOD; return ((res +(unsigned long) (p[2]) * _MUL)) % _MOD;
} }
#undef _MUL
#undef _MOD
}; };
/*! Class to define a regular grid used for ray /*! Class to define a regular grid used for ray casting computations */
casting computations */
class LIB_GEOMETRY_EXPORT HashGrid : public Grid class LIB_GEOMETRY_EXPORT HashGrid : public Grid
{ {
public: public:
typedef map<Vec3u, Cell*> GridHashTable;
typedef map<Vec3u, Cell*> GridHashTable; HashGrid() : Grid() {}
HashGrid() : Grid() {}
virtual ~HashGrid() { virtual ~HashGrid()
clear(); {
} clear();
}
/*! clears the grid /*! clears the grid
* Deletes all the cells, clears the hashtable, * Deletes all the cells, clears the hashtable, resets size, size of cell, number of cells.
* resets size, size of cell, number of cells. */
*/ virtual void clear();
virtual void clear();
/*! Sets the different parameters of the grid /*! Sets the different parameters of the grid
* orig * orig
* The grid origin * The grid origin
* size * size
* The grid's dimensions * The grid's dimensions
* nb * nb
* The number of cells of the grid * The number of cells of the grid
*/ */
virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb); virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb);
/*! returns the cell whose coordinates /*! returns the cell whose coordinates are pased as argument */
* are pased as argument virtual Cell* getCell(const Vec3u& p)
*/ {
virtual Cell* getCell(const Vec3u& p) { Cell* found_cell = NULL;
Cell* found_cell = NULL;
GridHashTable::const_iterator found = _cells.find(p);
GridHashTable::const_iterator found = _cells.find(p); if (found != _cells.end())
if (found != _cells.end()) found_cell = (*found).second;
found_cell = (*found).second; return found_cell;
return found_cell; }
}
/*! Fills the case p with the cell iCell */
/*! Fills the case p with the cell iCell */ virtual void fillCell(const Vec3u& p, Cell& cell)
virtual void fillCell(const Vec3u& p, Cell& cell) { {
_cells[p] = &cell; _cells[p] = &cell;
} }
protected: protected:
GridHashTable _cells;
GridHashTable _cells;
}; };
#endif // HASHGRID_H #endif // __HASHGRID_H__

@ -1,264 +1,285 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2010 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
// /** \file blender/freestyle/intern/geometry/Noise.cpp
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to define Perlin noise
// * \author Emmanuel Turquin
// This program is free software; you can redistribute it and/or * \date 12/01/2004
// 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 "Noise.h" #include <math.h>
# include <stdlib.h> #include <stdio.h>
# include <stdio.h> #include <stdlib.h>
# include <math.h>
#include <time.h> #include <time.h>
#define MINX -1000000 #include "Noise.h"
#define MINY MINX
#define MINZ MINX #define MINX -1000000
#define SCURVE(a) ((a)*(a)*(3.0-2.0*(a))) #define MINY MINX
#define REALSCALE ( 2.0 / 65536.0 ) #define MINZ MINX
#define NREALSCALE ( 2.0 / 4096.0 )
#define HASH3D(a,b,c) hashTable[hashTable[hashTable[(a) & 0xfff] ^ ((b) & 0xfff)] ^ ((c) & 0xfff)] #define SCURVE(a) ((a) * (a) * (3.0 - 2.0 * (a)))
#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 \ #define REALSCALE (2.0 / 65536.0)
+ RTable[m+1]*(x) \ #define NREALSCALE (2.0 / 4096.0)
+ RTable[m+2]*(y) \
+ RTable[m+3]*(z))) #define HASH3D(a, b, c) hashTable[hashTable[hashTable[(a) & 0xfff] ^ ((b) & 0xfff)] ^ ((c) & 0xfff)]
#define MAXSIZE 500 #define HASH(a, b, c) (xtab[(xtab[(xtab[(a) & 0xff] ^ (b)) & 0xff] ^ (c)) & 0xff] & 0xff)
#define nrand() ((float)rand()/(float)RAND_MAX)
#define seednrand(x) srand(x*RAND_MAX) #define INCRSUM(m, s, x, y, z) \
((s) * (RTable[m] * 0.5 + RTable[m + 1] * (x) + RTable[m + 2] * (y) + RTable[m + 3] * (z)))
#define MAXSIZE 500
#if 0 // XXX Unused
#define NRAND() ((float)rand() / (float)RAND_MAX)
#endif
#define SEEDNRAND(x) (srand(x * RAND_MAX))
#define BM 0xff #define BM 0xff
#define N 0x1000
#define N 0x1000 #define NP 12 /* 2^N */
#define NP 12 /* 2^N */
#define NM 0xfff #define NM 0xfff
#define s_curve(t) ( t * t * (3. - 2. * t) ) #define LERP(t, a, b) ((a) + (t) * ((b) - (a)))
#define lerp(t, a, b) ( a + t * (b - a) ) #define SETUP(i, b0, b1, r0, r1) \
{ \
#define setup(i,b0,b1,r0,r1)\ (t) = (i) + (N); \
t = i + N;\ (b0) = ((int)(t)) & BM; \
b0 = ((int)t) & BM;\ (b1) = ((b0) + 1) & BM; \
b1 = (b0+1) & BM;\ (r0) = (t) - (int)(t); \
r0 = t - (int)t;\ (r1) = (r0) - 1.0; \
r1 = r0 - 1.; } (void)0
static void normalize2(float v[2]) static void normalize2(float v[2])
{ {
float s; float s;
s = sqrt(v[0] * v[0] + v[1] * v[1]); s = sqrt(v[0] * v[0] + v[1] * v[1]);
v[0] = v[0] / s; v[0] = v[0] / s;
v[1] = v[1] / s; v[1] = v[1] / s;
} }
static void normalize3(float v[3]) static void normalize3(float v[3])
{ {
float s; float s;
s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] = v[0] / s; v[0] = v[0] / s;
v[1] = v[1] / s; v[1] = v[1] / s;
v[2] = v[2] / s; v[2] = v[2] / s;
} }
float Noise::turbulence1(float arg, float freq, float amp, unsigned oct) float Noise::turbulence1(float arg, float freq, float amp, unsigned oct)
{ {
float t; float t;
float vec; float vec;
for (t = 0; oct > 0 && freq > 0; freq *= 2, amp /= 2, --oct) for (t = 0; oct > 0 && freq > 0; freq *= 2, amp /= 2, --oct) {
{ vec = freq * arg;
vec = freq * arg; t += smoothNoise1(vec) * amp;
t += smoothNoise1(vec) * amp; }
} return t;
return t;
} }
float Noise::turbulence2(Vec2f& v, float freq, float amp, unsigned oct) float Noise::turbulence2(Vec2f& v, float freq, float amp, unsigned oct)
{ {
float t; float t;
Vec2f vec; Vec2f vec;
for (t = 0; oct > 0 && freq > 0; freq *= 2, amp /= 2, --oct) for (t = 0; oct > 0 && freq > 0; freq *= 2, amp /= 2, --oct) {
{ vec.x() = freq * v.x();
vec.x() = freq * v.x(); vec.y() = freq * v.y();
vec.y() = freq * v.y(); t += smoothNoise2(vec) * amp;
t += smoothNoise2(vec) * amp; }
} return t;
return t;
} }
float Noise::turbulence3(Vec3f& v, float freq, float amp, unsigned oct) float Noise::turbulence3(Vec3f& v, float freq, float amp, unsigned oct)
{ {
float t; float t;
Vec3f vec; Vec3f vec;
for (t = 0; oct > 0 && freq > 0; freq *= 2, amp /= 2, --oct) for (t = 0; oct > 0 && freq > 0; freq *= 2, amp /= 2, --oct) {
{ vec.x() = freq * v.x();
vec.x() = freq * v.x(); vec.y() = freq * v.y();
vec.y() = freq * v.y(); vec.z() = freq * v.z();
vec.z() = freq * v.z(); t += smoothNoise3(vec) * amp;
t += smoothNoise3(vec) * amp; }
} return t;
return t;
} }
// Noise functions over 1, 2, and 3 dimensions // Noise functions over 1, 2, and 3 dimensions
float Noise::smoothNoise1(float arg) float Noise::smoothNoise1(float arg)
{ {
int bx0, bx1; int bx0, bx1;
float rx0, rx1, sx, t, u, v, vec; float rx0, rx1, sx, t, u, v, vec;
vec = arg; vec = arg;
setup(vec, bx0,bx1, rx0,rx1); SETUP(vec, bx0, bx1, rx0, rx1);
sx = s_curve(rx0); sx = SCURVE(rx0);
u = rx0 * g1[ p[ bx0 ] ]; u = rx0 * g1[p[bx0]];
v = rx1 * g1[ p[ bx1 ] ]; v = rx1 * g1[p[bx1]];
return lerp(sx, u, v); return LERP(sx, u, v);
} }
float Noise::smoothNoise2(Vec2f& vec) float Noise::smoothNoise2(Vec2f& vec)
{ {
int bx0, bx1, by0, by1, b00, b10, b01, b11; int bx0, bx1, by0, by1, b00, b10, b01, b11;
float rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v; float rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
register int i, j; register int i, j;
setup(vec.x(), bx0,bx1, rx0,rx1); SETUP(vec.x(), bx0, bx1, rx0, rx1);
setup(vec.y(), by0,by1, ry0,ry1); SETUP(vec.y(), by0, by1, ry0, ry1);
i = p[ bx0 ]; i = p[bx0];
j = p[ bx1 ]; j = p[bx1];
b00 = p[ i + by0 ]; b00 = p[i + by0];
b10 = p[ j + by0 ]; b10 = p[j + by0];
b01 = p[ i + by1 ]; b01 = p[i + by1];
b11 = p[ j + by1 ]; b11 = p[j + by1];
sx = s_curve(rx0); sx = SCURVE(rx0);
sy = s_curve(ry0); sy = SCURVE(ry0);
#define at2(rx,ry) ( rx * q[0] + ry * q[1] ) #define AT2(rx, ry) ((rx) * q[0] + (ry) * q[1])
q = g2[ b00 ] ; u = at2(rx0,ry0); q = g2[b00];
q = g2[ b10 ] ; v = at2(rx1,ry0); u = AT2(rx0, ry0);
a = lerp(sx, u, v); q = g2[b10];
v = AT2(rx1, ry0);
a = LERP(sx, u, v);
q = g2[ b01 ] ; u = at2(rx0,ry1); q = g2[b01];
q = g2[ b11 ] ; v = at2(rx1,ry1); u = AT2(rx0, ry1);
b = lerp(sx, u, v); q = g2[b11];
v = AT2(rx1, ry1);
b = LERP(sx, u, v);
return lerp(sy, a, b); #undef AT2
return LERP(sy, a, b);
} }
float Noise::smoothNoise3(Vec3f& vec) float Noise::smoothNoise3(Vec3f& vec)
{ {
int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; 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; float rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v;
register int i, j; register int i, j;
setup(vec.x(), bx0,bx1, rx0,rx1); SETUP(vec.x(), bx0, bx1, rx0, rx1);
setup(vec.y(), by0,by1, ry0,ry1); SETUP(vec.y(), by0, by1, ry0, ry1);
setup(vec.z(), bz0,bz1, rz0,rz1); SETUP(vec.z(), bz0, bz1, rz0, rz1);
i = p[ bx0 ]; i = p[bx0];
j = p[ bx1 ]; j = p[bx1];
b00 = p[ i + by0 ]; b00 = p[i + by0];
b10 = p[ j + by0 ]; b10 = p[j + by0];
b01 = p[ i + by1 ]; b01 = p[i + by1];
b11 = p[ j + by1 ]; b11 = p[j + by1];
t = s_curve(rx0); t = SCURVE(rx0);
sy = s_curve(ry0); sy = SCURVE(ry0);
sz = s_curve(rz0); sz = SCURVE(rz0);
#define at3(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] ) #define AT3(rx, ry, rz) ((rx) * q[0] + (ry) * q[1] + (rz) * q[2])
q = g3[ b00 + bz0 ] ; q = g3[b00 + bz0];
u = at3(rx0,ry0,rz0); u = AT3(rx0, ry0, rz0);
q = g3[ b10 + bz0 ] ; q = g3[b10 + bz0];
v = at3(rx1,ry0,rz0); v = AT3(rx1, ry0, rz0);
a = lerp(t, u, v); a = LERP(t, u, v);
q = g3[ b01 + bz0 ] ; q = g3[b01 + bz0];
u = at3(rx0,ry1,rz0); u = AT3(rx0, ry1, rz0);
q = g3[ b11 + bz0 ] ; q = g3[b11 + bz0];
v = at3(rx1,ry1,rz0); v = AT3(rx1, ry1, rz0);
b = lerp(t, u, v); b = LERP(t, u, v);
c = lerp(sy, a, b); c = LERP(sy, a, b);
q = g3[ b00 + bz1 ] ; q = g3[b00 + bz1];
u = at3(rx0,ry0,rz1); u = AT3(rx0, ry0, rz1);
q = g3[ b10 + bz1 ] ; q = g3[b10 + bz1];
v = at3(rx1,ry0,rz1); v = AT3(rx1, ry0, rz1);
a = lerp(t, u, v); a = LERP(t, u, v);
q = g3[ b01 + bz1 ] ; q = g3[b01 + bz1];
u = at3(rx0,ry1,rz1); u = AT3(rx0, ry1, rz1);
q = g3[ b11 + bz1 ] ; q = g3[b11 + bz1];
v = at3(rx1,ry1,rz1); v = AT3(rx1, ry1, rz1);
b = lerp(t, u, v); b = LERP(t, u, v);
d = lerp(sy, a, b); d = LERP(sy, a, b);
return lerp(sz, c, d); #undef AT3
return LERP(sz, c, d);
} }
Noise::Noise(long seed) Noise::Noise(long seed)
{ {
int i, j, k; 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_; 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++) for (j = 0 ; j < 2 ; j++)
g2[i][j] = (float)((rand() % (_Noise_B_ + _Noise_B_)) - _Noise_B_) / _Noise_B_; g2[i][j] = (float)((rand() % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B;
normalize2(g2[i]); normalize2(g2[i]);
for (j = 0 ; j < 3 ; j++) for (j = 0 ; j < 3 ; j++)
g3[i][j] = (float)((rand() % (_Noise_B_ + _Noise_B_)) - _Noise_B_) / _Noise_B_; g3[i][j] = (float)((rand() % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B;
normalize3(g3[i]); normalize3(g3[i]);
} }
while (--i) while (--i) {
{ k = p[i];
k = p[i]; p[i] = p[j = rand() % _NOISE_B];
p[i] = p[j = rand() % _Noise_B_]; p[j] = k;
p[j] = k; }
}
for (i = 0 ; i < _Noise_B_ + 2 ; i++) for (i = 0 ; i < _NOISE_B + 2 ; i++) {
{ p[_NOISE_B + i] = p[i];
p[_Noise_B_ + i] = p[i]; g1[_NOISE_B + i] = g1[i];
g1[_Noise_B_ + i] = g1[i];
for (j = 0 ; j < 2 ; j++) for (j = 0 ; j < 2 ; j++)
g2[_Noise_B_ + i][j] = g2[i][j]; g2[_NOISE_B + i][j] = g2[i][j];
for (j = 0 ; j < 3 ; j++)
g3[_Noise_B_ + i][j] = g3[i][j]; for (j = 0 ; j < 3 ; j++)
} g3[_NOISE_B + i][j] = g3[i][j];
}
} }

@ -1,40 +1,45 @@
// /*
// Filename : Noise.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Emmanuel Turquin *
// Purpose : Class to define Perlin noise * This program is free software; you can redistribute it and/or
// Date of creation : 12/01/2004 * 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
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to define Perlin noise
// * \author Emmanuel Turquin
// This program is free software; you can redistribute it and/or * \date 12/01/2004
// 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 #include "Geom.h"
# define NOISE_H
#include "../system/FreestyleConfig.h"
# include "../system/FreestyleConfig.h" #define _NOISE_B 0x100
# include "Geom.h"
#define _Noise_B_ 0x100
using namespace Geometry; using namespace Geometry;
using namespace std; using namespace std;
@ -42,36 +47,37 @@ using namespace std;
/*! Class to provide Perlin Noise functionalities */ /*! Class to provide Perlin Noise functionalities */
class LIB_GEOMETRY_EXPORT Noise class LIB_GEOMETRY_EXPORT Noise
{ {
public: public:
/*! Builds a Noise object */
Noise(long seed = -1);
/*! Builds a Noise object */ /*! Destructor */
Noise(long seed = -1); ~Noise() {}
/*! Destructor */
~Noise() {}
/*! Returns a noise value for a 1D element */ /*! Returns a noise value for a 1D element */
float turbulence1(float arg, float freq, float amp, unsigned oct = 4); float turbulence1(float arg, float freq, float amp, unsigned oct = 4);
/*! Returns a noise value for a 2D element */ /*! Returns a noise value for a 2D element */
float turbulence2(Vec2f& v, float freq, float amp, unsigned oct = 4); float turbulence2(Vec2f& v, float freq, float amp, unsigned oct = 4);
/*! Returns a noise value for a 3D element */ /*! Returns a noise value for a 3D element */
float turbulence3(Vec3f& v, float freq, float amp, unsigned oct = 4); float turbulence3(Vec3f& v, float freq, float amp, unsigned oct = 4);
/*! Returns a smooth noise value for a 1D element */ /*! Returns a smooth noise value for a 1D element */
float smoothNoise1(float arg); 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);
private: /*! Returns a smooth noise value for a 2D element */
float smoothNoise2(Vec2f& vec);
int p[ _Noise_B_ + _Noise_B_ + 2]; /*! Returns a smooth noise value for a 3D element */
float g3[ _Noise_B_ + _Noise_B_ + 2][3]; float smoothNoise3(Vec3f& vec);
float g2[ _Noise_B_ + _Noise_B_ + 2][2];
float g1[ _Noise_B_ + _Noise_B_ + 2]; private:
int start; 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__

@ -1,38 +1,44 @@
// /*
// Filename : Polygon.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Stephane Grabli *
// Purpose : Class to define a polygon * This program is free software; you can redistribute it and/or
// Date of creation : 30/07/2002 * 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
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to define a polygon
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 30/07/2002
// 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 #include <vector>
# define POLYGON_H
# include <vector> #include "Geom.h"
# include "Geom.h" #include "GeomUtils.h"
# include "GeomUtils.h"
using namespace std; using namespace std;
@ -41,129 +47,129 @@ namespace Geometry {
template <class Point> template <class Point>
class Polygon class Polygon
{ {
public: public:
inline Polygon()
{
_id = 0;
userdata = 0;
userdata2 = 0;
}
inline Polygon() { inline Polygon(const vector<Point>& vertices)
_id = 0; {
userdata = 0; _vertices = vertices;
userdata2 = 0; computeBBox();
} _id = 0;
userdata = 0;
userdata2 = 0;
}
inline Polygon(const vector<Point>& vertices) { inline Polygon(const Polygon<Point>& poly)
_vertices = vertices; {
computeBBox(); Point p;
_id = 0; for (typename vector<Point>::const_iterator it = poly.getVertices().begin();
userdata = 0; it != poly.getVertices().end();
userdata2 = 0; it++)
} {
p = *it;
_vertices.push_back(p);
}
inline Polygon(const Polygon<Point>& poly) { _id = poly.getId();
Point p; poly.getBBox(_min, _max);
for(typename vector<Point>::const_iterator it = poly.getVertices().begin(); userdata = 0;
it != poly.getVertices().end(); userdata2 = 0;
it++) { }
p = *it;
_vertices.push_back(p);
}
_id = poly.getId(); virtual ~Polygon() {}
poly.getBBox(_min, _max);
userdata = 0;
userdata2 = 0;
}
virtual ~Polygon() {}
// //
// Accessors // Accessors
// //
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
inline const vector<Point>& getVertices() const
{
return _vertices;
}
inline const vector<Point>& getVertices() const { inline void getBBox(Point& min, Point& max) const
return _vertices; {
} min = _min;
max = _max;
}
inline void getBBox(Point& min, Point& max) const { inline Point& getBBoxCenter()
min = _min; {
max = _max; Point result;
} result = (_min + _max) / 2;
return result;
}
inline Point& getBBoxCenter() inline Point& getCenter()
{ {
Point result; Point result;
result = (_min + _max) / 2; for (typename vector<Point>::iterator it = _vertices.begin(); it != _vertices.end(); it++)
return result; result += *it;
} result /= _vertices.size();
return result;
}
inline Point& getCenter() { inline unsigned getId() const
Point result; {
for (typename vector<Point>::iterator it = _vertices.begin(); return _id;
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)
// Modifiers {
// _id = id;
///////////////////////////////////////////////////////////////////////////// }
inline void setVertices(const vector<Point>& vertices) { //
_vertices.clear(); // Other methods
Point p; //
for (typename vector<Point>::const_iterator it = vertices.begin(); /////////////////////////////////////////////////////////////////////////////
it != vertices.end(); inline void computeBBox()
it++) { {
p = *it; if (_vertices.empty())
_vertices.push_back(p); return;
}
computeBBox();
}
inline void setId(unsigned id) { _max = _vertices[0];
_id = id; _min = _vertices[0];
}
// for (typename vector<Point>::iterator it = _vertices.begin(); it != _vertices.end(); it++) {
// Other methods for (unsigned int i = 0; i < Point::dim(); i++) {
// if ((*it)[i] > _max[i])
///////////////////////////////////////////////////////////////////////////// _max[i] = (*it)[i];
if ((*it)[i] < _min[i])
_min[i] = (*it)[i];
}
}
}
inline void computeBBox() { // FIXME Is it possible to get rid of userdatas ?
if(_vertices.empty()) void* userdata;
return; void* userdata2; // Used during ray casting
_max = _vertices[0];
_min = _vertices[0];
for(typename vector<Point>::iterator it = _vertices.begin(); protected:
it != _vertices.end(); vector<Point> _vertices;
it++) { Point _min;
for(unsigned i = 0; i < Point::dim(); i++) { Point _max;
if((*it)[i] > _max[i]) unsigned _id;
_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 // Polygon3r class
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
class Polygon3r : public Polygon<Vec3r> class Polygon3r : public Polygon<Vec3r>
{ {
public: public:
inline Polygon3r() : Polygon<Vec3r>() {} inline Polygon3r() : Polygon<Vec3r>() {}
inline Polygon3r(const vector<Vec3r>& vertices, inline Polygon3r(const vector<Vec3r>& vertices, const Vec3r& normal) : Polygon<Vec3r>(vertices)
const Vec3r& normal) : Polygon<Vec3r>(vertices) { {
setNormal(normal); setNormal(normal);
} }
inline Polygon3r(const Polygon3r& poly) : Polygon<Vec3r>(poly), _normal(poly._normal) {} inline Polygon3r(const Polygon3r& poly) : Polygon<Vec3r>(poly), _normal(poly._normal) {}
virtual ~Polygon3r() {}
void setNormal(const Vec3r& normal) { virtual ~Polygon3r() {}
_normal = normal;
}
inline Vec3r getNormal() const { void setNormal(const Vec3r& normal)
return _normal; {
} _normal = normal;
}
/*! Check whether the Polygon intersects with the ray or not */ inline Vec3r getNormal() const
inline bool rayIntersect(const Vec3r& orig, const Vec3r& dir, {
real& t, real& u, real& v, real epsilon = M_EPSILON) const { return _normal;
// if (_vertices.size() < 3) }
// return false;
return GeomUtils::intersectRayTriangle(orig, dir,
_vertices[0], _vertices[1], _vertices[2],
t, u, v, epsilon);
}
private: /*! Check whether the Polygon intersects with the ray or not */
inline bool rayIntersect(const Vec3r& orig, const Vec3r& dir, real& t, real& u, real& v,
real epsilon = M_EPSILON) const
{
#if 0
if (_vertices.size() < 3)
return false;
#endif
return GeomUtils::intersectRayTriangle(orig, dir, _vertices[0], _vertices[1], _vertices[2], t, u, v, epsilon);
}
Vec3r _normal; private:
Vec3r _normal;
}; };
} // end of namespace Geometry } // end of namespace Geometry
#endif // POLYGON_H #endif // __POLYGON_H__

@ -1,198 +1,202 @@
// /*
// Filename : SweepLine.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Stephane Grabli *
// Purpose : Class to define a Sweep Line * This program is free software; you can redistribute it and/or
// Date of creation : 29/08/2002 * 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
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to define a Sweep Line
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 29/08/2002
// 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 #include <list>
# define SWEEPLINE_H #include <vector>
# include <list>
# include <vector>
/*! Class to define the intersection berween two segments*/ /*! Class to define the intersection berween two segments*/
template<class Edge> template<class Edge>
class Intersection class Intersection
{ {
public: public:
template<class EdgeClass>
Intersection(EdgeClass* eA, real ta, EdgeClass* eB, real tb)
{
EdgeA = eA;
EdgeB = eB;
tA = ta;
tB = tb;
userdata = 0;
}
template<class EdgeClass> Intersection(const Intersection& iBrother)
Intersection(EdgeClass* eA, real ta, EdgeClass* eB, real tb) {
{ EdgeA = iBrother.EdgeA;
EdgeA = eA; EdgeB = iBrother.EdgeB;
EdgeB = eB; tA = iBrother.tA;
tA = ta; tB = iBrother.tB;
tB = tb; userdata = 0;
userdata = 0; }
}
Intersection(const Intersection& iBrother) /*! returns the parameter giving the intersection, for the edge iEdge */
{ real getParameter(Edge *iEdge)
EdgeA = iBrother.EdgeA; {
EdgeB = iBrother.EdgeB; if (iEdge == EdgeA)
tA = iBrother.tA; return tA;
tB = iBrother.tB; if (iEdge == EdgeB)
userdata = 0; return tB;
} return 0;
}
/*! returns the parameter giving the
* intersection, for the edge iEdge
*/
real getParameter(Edge *iEdge)
{
if(iEdge == EdgeA)
return tA;
if(iEdge == EdgeB)
return tB;
return 0;
}
public: public:
void * userdata; // FIXME void * userdata; // FIXME
Edge *EdgeA; // first segment Edge *EdgeA; // first segment
Edge *EdgeB; // second segment Edge *EdgeB; // second segment
real tA; // parameter defining the intersection point with respect to the segment EdgeA. 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. real tB; // parameter defining the intersection point with respect to the segment EdgeB.
}; };
template<class T, class Point> template<class T, class Point>
class Segment class Segment
{ {
public: public:
Segment() 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) Segment(T& s, const Point& iA, const Point& iB)
{ {
_edge = iBrother.edge(); _edge = s;
A = iBrother.A; if (iA < iB) {
B = iBrother.B; A = iA;
_Intersections = iBrother._Intersections; B = iB;
_order = iBrother._order; _order = true;
} }
else {
A = iB;
B = iA;
_order = false;
}
}
Segment(const Segment<T,Point>& iBrother) Segment(Segment<T,Point>& iBrother)
{ {
_edge = iBrother._edge; _edge = iBrother.edge();
A = iBrother.A; A = iBrother.A;
B = iBrother.B; B = iBrother.B;
_Intersections = iBrother._Intersections; _Intersections = iBrother._Intersections;
_order = iBrother._order; _order = iBrother._order;
} }
~Segment() { Segment(const Segment<T,Point>& iBrother)
_Intersections.clear(); {
} _edge = iBrother._edge;
A = iBrother.A;
B = iBrother.B;
_Intersections = iBrother._Intersections;
_order = iBrother._order;
}
inline Point operator[](const unsigned short int& i) const ~Segment()
{ {
return i%2==0 ? A : B; _Intersections.clear();
} }
inline bool operator==(const Segment<T,Point>& iBrother) inline Point operator[](const unsigned short int& i) const
{ {
if(_edge == iBrother._edge) return (i % 2 == 0) ? A : B;
return true; }
return false; inline bool operator==(const Segment<T,Point>& iBrother)
} {
if (_edge == iBrother._edge)
/* Adds an intersection for this segment */ return true;
inline void AddIntersection(Intersection<Segment<T,Point> > *i) {_Intersections.push_back(i);} return false;
}
/*! Checks for a common vertex with another edge */ /* Adds an intersection for this segment */
inline bool CommonVertex(const Segment<T,Point>& S, Point& CP) inline void AddIntersection(Intersection<Segment<T,Point> > *i)
{ {
if((A == S[0]) || (A == S[1])) _Intersections.push_back(i);
{ }
CP = A;
return true;
}
if((B == S[0]) || (B == S[1]))
{
CP = B;
return true;
}
return false; /*! 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 vector<Intersection<Segment<T,Point> >*>& intersections()
inline bool order() {return _order;} {
inline T& edge() {return _edge;} return _Intersections;
}
private: inline bool order()
T _edge; {
Point A; return _order;
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. 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 /*! defines a binary function that can be overload by the user to specify at each condition the intersection
* by the user to specify at each condition * between 2 edges must be computed
* the intersection between 2 edges must be computed
*/ */
template<class T1, class T2> template<class T1, class T2>
struct binary_rule struct binary_rule
{ {
binary_rule() {} binary_rule() {}
template<class T3,class T4> template<class T3,class T4> binary_rule(const binary_rule<T3,T4>& brother) {}
binary_rule(const binary_rule<T3,T4>& brother) {} virtual ~binary_rule() {}
virtual ~binary_rule() {}
virtual bool operator()(T1&, T2&) virtual bool operator()(T1&, T2&)
{ {
return true; return true;
} }
}; };
@ -200,126 +204,121 @@ template<class T,class Point>
class SweepLine class SweepLine
{ {
public: public:
SweepLine() {}
~SweepLine()
{
for (typename vector<Intersection<Segment<T,Point> >*>::iterator i = _Intersections.begin(),
iend = _Intersections.end();
i != iend;
i++)
{
delete (*i);
}
}
SweepLine() {} inline void process(Point& p, vector<Segment<T,Point>*>& segments,
~SweepLine() #if 0
{ binary_rule<Segment<T,Point>,Segment<T,Point> >& binrule = \
for(typename vector<Intersection<Segment<T,Point> >*>::iterator i=_Intersections.begin(),iend=_Intersections.end(); binary_rule<Segment<T,Point>,Segment<T,Point> >(),
i!=iend; #else
i++) binary_rule<Segment<T,Point>,Segment<T,Point> >& binrule,
{ #endif
delete (*i); 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,
inline void process(Point& p, #if 0
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> >(),
//binary_rule<Segment<T,Point>,Segment<T,Point> >& binrule = binary_rule<Segment<T,Point>,Segment<T,Point> >(), #else
real epsilon = M_EPSILON binary_rule<Segment<T,Point>,Segment<T,Point> >& binrule,
) #endif
{ real epsilon)
// first we remove the segments that need to be removed and then {
// we add the segments to add real t,u;
vector<Segment<T,Point>*> toadd; Point CP;
typename vector<Segment<T,Point>*>::iterator s, send; Vec2r v0, v1, v2, v3;
for(s=segments.begin(), send=segments.end(); if (true == S->order()) {
s!=send; v0[0] = ((*S)[0])[0];
s++) v0[1] = ((*S)[0])[1];
{ v1[0] = ((*S)[1])[0];
if(p == (*(*s))[0]) v1[1] = ((*S)[1])[1];
toadd.push_back((*s)); }
else else {
remove((*s)); v1[0] = ((*S)[0])[0];
} v1[1] = ((*S)[0])[1];
for(s=toadd.begin(), send=toadd.end(); v0[0] = ((*S)[1])[0];
s!=send; v0[1] = ((*S)[1])[1];
s++) }
{ for (typename std::list<Segment<T,Point>* >::iterator s = _set.begin(), send = _set.end(); s != send; s++) {
add((*s), binrule, epsilon); Segment<T,Point>* currentS = (*s);
} if (true != binrule(*S, *currentS))
} continue;
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()) if (true == currentS->order()) {
{ v2[0] = ((*currentS)[0])[0];
v2[0] = ((*currentS)[0])[0]; v2[1] = ((*currentS)[0])[1];
v2[1] = ((*currentS)[0])[1]; v3[0] = ((*currentS)[1])[0];
v3[0] = ((*currentS)[1])[0]; v3[1] = ((*currentS)[1])[1];
v3[1] = ((*currentS)[1])[1]; }
} else {
else v3[0] = ((*currentS)[0])[0];
{ v3[1] = ((*currentS)[0])[1];
v3[0] = ((*currentS)[0])[0]; v2[0] = ((*currentS)[1])[0];
v3[1] = ((*currentS)[0])[1]; v2[1] = ((*currentS)[1])[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(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;} if (GeomUtils::intersect2dSeg2dSegParametric(v0, v1, v2, v3, t, u, epsilon) == GeomUtils::DO_INTERSECT) {
vector<Intersection<Segment<T,Point> >*>& intersections() {return _Intersections;} // 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: private:
std::list<Segment<T,Point>* > _set; // set of active edges for a given position of the sweep line 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<Segment<T,Point>* > _IntersectedEdges; // the list of intersected edges
std::vector<Intersection<Segment<T,Point> >*> _Intersections; // the list of all intersections. std::vector<Intersection<Segment<T,Point> >*> _Intersections; // the list of all intersections.
}; };
#endif // SWEEPLINE_H #endif // __SWEEPLINE_H__

File diff suppressed because it is too large Load Diff

@ -1,265 +1,266 @@
/* /*
* GXML/Graphite: Geometry and Graphics Programming Library + Utilities * ***** BEGIN GPL LICENSE BLOCK *****
* Copyright (C) 2000 Bruno Levy
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or
* it under the terms of the GNU General Public License as published by * modify it under the terms of the GNU General Public License
* the Free Software Foundation; either version 2 of the License, or * as published by the Free Software Foundation; either version 2
* (at your option) any later version. * of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software Foundation,
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* *
* If you modify this software, you should include a notice giving the * This Code is Copyright (C) 2010 Blender Foundation.
* name of the person performing the modification, the date of modification, * All rights reserved.
* and the reason for such modification.
* *
* 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 * ***** END GPL LICENSE BLOCK *****
* 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.
*/ */
/** \file blender/freestyle/intern/geometry/matrix_util.cpp
* \ingroup freestyle
* \author Bruno Levy
*/
#include "matrix_util.h"
#include <math.h> #include <math.h>
#include "matrix_util.h"
namespace OGF { namespace OGF {
namespace MatrixUtil {
static const double EPS = 0.00001 ; namespace MatrixUtil {
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) ; static const double EPS = 0.00001;
cosx = cos(x) ; static int MAX_ITER = 100;
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;
}
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;
}
// 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;
}
//_________________________________________________________ //_________________________________________________________
} } // MatrixUtil namespace
}
} // OGF namespace

@ -1,69 +1,72 @@
/* /*
* GXML/Graphite: Geometry and Graphics Programming Library + Utilities * ***** BEGIN GPL LICENSE BLOCK *****
* Copyright (C) 2000 Bruno Levy
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or
* it under the terms of the GNU General Public License as published by * modify it under the terms of the GNU General Public License
* the Free Software Foundation; either version 2 of the License, or * as published by the Free Software Foundation; either version 2
* (at your option) any later version. * of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software Foundation,
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* *
* If you modify this software, you should include a notice giving the * This Code is Copyright (C) 2010 Blender Foundation.
* name of the person performing the modification, the date of modification, * All rights reserved.
* and the reason for such modification.
* *
* 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 * ***** END GPL LICENSE BLOCK *****
* 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.
*/ */
#ifndef __MATRIX_UTIL__ #ifndef __MATRIX_UTIL__
#define __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 OGF {
namespace MatrixUtil { namespace MatrixUtil {
/** /**
* computes the eigen values and eigen vectors * computes the eigen values and eigen vectors of a semi definite symmetric matrix
* of a semi definite symmetric matrix *
* * @param matrix is stored in column symmetric storage, i.e.
* @param matrix is stored in column symmetric storage, i.e. * matrix = { m11, m12, m22, m13, m23, m33, m14, m24, m34, m44 ... }
* matrix = { m11, m12, m22, m13, m23, m33, m14, m24, m34, m44 ... } * size = n(n+1)/2
* size = n(n+1)/2 *
* * @param eigen_vectors (return) = { v1, v2, v3, ..., vn }
* @param eigen_vectors (return) = { v1, v2, v3, ..., vn } * where vk = vk0, vk1, ..., vkn
* where vk = vk0, vk1, ..., vkn * size = n^2, must be allocated by caller
* size = n^2, must be allocated by caller *
* * @param eigen_values (return) are in decreasing order
* @param eigen_values (return) are in decreasing order * size = n, must be allocated by caller
* size = n, must be allocated by caller */
*/ LIB_GEOMETRY_EXPORT
LIB_GEOMETRY_EXPORT void semi_definite_symmetric_eigen(const double *mat, int n, double *eigen_vec, double *eigen_val);
void semi_definite_symmetric_eigen(
const double *mat, int n, double *eigen_vec, double *eigen_val
) ;
}
}
#endif } // MatrixUtil namespace
} // OGF namespace
#endif // __MATRIX_UTIL__

@ -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 *****
*/
/** \file blender/freestyle/intern/geometry/normal_cycle.cpp
* \ingroup freestyle
* \author Bruno Levy
*/
//
// 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" #include "matrix_util.h"
#include "normal_cycle.h"
namespace OGF { namespace OGF {
//_________________________________________________________ //_________________________________________________________
NormalCycle::NormalCycle() {
}
void NormalCycle::begin() { NormalCycle::NormalCycle()
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 void NormalCycle::begin()
{
M_[0] = M_[1] = M_[2] = M_[3] = M_[4] = M_[5] = 0;
}
i_[0] = 0 ; void NormalCycle::end()
i_[1] = 1 ; {
i_[2] = 2 ; double eigen_vectors[9];
MatrixUtil::semi_definite_symmetric_eigen(M_, 3, eigen_vectors, eigen_value_);
double l0 = ::fabs(eigen_value_[0]) ; axis_[0] = Vec3r(eigen_vectors[0], eigen_vectors[1], eigen_vectors[2]);
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]) ;
}
} 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

@ -1,110 +1,144 @@
/* /*
* OGF/Graphite: Geometry and Graphics Programming Library + Utilities * ***** BEGIN GPL LICENSE BLOCK *****
* Copyright (C) 2000 Bruno Levy
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or
* it under the terms of the GNU General Public License as published by * modify it under the terms of the GNU General Public License
* the Free Software Foundation; either version 2 of the License, or * as published by the Free Software Foundation; either version 2
* (at your option) any later version. * of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software Foundation,
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* *
* If you modify this software, you should include a notice giving the * This Code is Copyright (C) 2010 Blender Foundation.
* name of the person performing the modification, the date of modification, * All rights reserved.
* and the reason for such modification.
* *
* 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 * ***** END GPL LICENSE BLOCK *****
* 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.
*/ */
#ifndef __MESH_TOOLS_MATH_NORMAL_CYCLE__ #ifndef __MESH_TOOLS_MATH_NORMAL_CYCLE__
#define __MESH_TOOLS_MATH_NORMAL_CYCLE__ #define __MESH_TOOLS_MATH_NORMAL_CYCLE__
# include "../system/FreestyleConfig.h" /** \file blender/freestyle/intern/geometry/normal_cycle.h
# include "Geom.h" * \ingroup freestyle
* \author Bruno Levy
*/
#include "Geom.h"
#include "../system/FreestyleConfig.h"
using namespace Geometry; using namespace Geometry;
namespace OGF { namespace OGF {
template <class T> inline void ogf_swap(T& x, T& y) { template <class T> inline void ogf_swap(T& x, T& y)
T z = x ; {
x = y ; T z = x ;
y = z ; 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() ;
}
//_________________________________________________________
} }
#endif //_________________________________________________________
/**
* NormalCycle evaluates the curvature tensor in function
* of a set of dihedral angles and associated vectors.
* Reference:
* Restricted Delaunay Triangulation and Normal Cycle,
* D. Cohen-Steiner and J.M. Morvan,
* SOCG 2003
*/
class LIB_GEOMETRY_EXPORT NormalCycle {
public:
NormalCycle();
void begin();
void end();
/**
* Note: the specified edge vector needs to be pre-clipped by the neighborhood.
*/
void accumulate_dihedral_angle(const Vec3r& edge, real angle, real neigh_area = 1.0);
const Vec3r& eigen_vector(int i) const
{
return axis_[i_[i]];
}
real eigen_value(int i) const
{
return eigen_value_[i_[i]];
}
const Vec3r& N() const
{
return eigen_vector(2);
}
const Vec3r& Kmax() const
{
return eigen_vector(1);
}
const Vec3r& Kmin() const
{
return eigen_vector(0);
}
real n() const
{
return eigen_value(2);
}
real kmax() const
{
return eigen_value(1);
}
real kmin() const
{
return eigen_value(0);
}
private:
real center_[3];
Vec3r axis_[3];
real eigen_value_[3];
real M_[6];
int i_[3];
};
inline void NormalCycle::accumulate_dihedral_angle(const Vec3r& edge, const double beta, double neigh_area)
{
double s = beta * neigh_area / edge.norm();
M_[0] += s * edge.x() * edge.x();
M_[1] += s * edge.x() * edge.y();
M_[2] += s * edge.y() * edge.y();
M_[3] += s * edge.x() * edge.z();
M_[4] += s * edge.y() * edge.z();
M_[5] += s * edge.z() * edge.z();
}
//_________________________________________________________
} // OGF namespace
#endif // __MESH_TOOLS_MATH_NORMAL_CYCLE__

@ -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 *****
*/
// /** \file blender/freestyle/intern/image/GaussianFilter.cpp
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to perform gaussian filtering operations on an image
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 20/05/2003
// 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 "GaussianFilter.h"
#include <stdlib.h> #include <stdlib.h>
GaussianFilter::GaussianFilter(float iSigma ) #include "GaussianFilter.h"
GaussianFilter::GaussianFilter(float iSigma)
{ {
_sigma = iSigma; _sigma = iSigma;
_mask = 0; _mask = 0;
computeMask(); computeMask();
} }
GaussianFilter::GaussianFilter(const GaussianFilter& iBrother) GaussianFilter::GaussianFilter(const GaussianFilter& iBrother)
{ {
_sigma = iBrother._sigma; _sigma = iBrother._sigma;
_maskSize = iBrother._maskSize; _maskSize = iBrother._maskSize;
_bound = iBrother._bound; _bound = iBrother._bound;
_storedMaskSize = iBrother._storedMaskSize; _storedMaskSize = iBrother._storedMaskSize;
_mask = new float[_maskSize*_maskSize]; _mask = new float[_maskSize * _maskSize];
memcpy(_mask, iBrother._mask, _maskSize*_maskSize*sizeof(float)); memcpy(_mask, iBrother._mask, _maskSize * _maskSize * sizeof(float));
} }
GaussianFilter& GaussianFilter::operator=(const GaussianFilter& iBrother)
GaussianFilter& GaussianFilter::operator= (const GaussianFilter& iBrother)
{ {
_sigma = iBrother._sigma; _sigma = iBrother._sigma;
_maskSize = iBrother._maskSize; _maskSize = iBrother._maskSize;
_bound = iBrother._bound; _bound = iBrother._bound;
_storedMaskSize = iBrother._storedMaskSize; _storedMaskSize = iBrother._storedMaskSize;
_mask = new float[_storedMaskSize*_storedMaskSize]; _mask = new float[_storedMaskSize * _storedMaskSize];
memcpy(_mask, iBrother._mask, _storedMaskSize*_storedMaskSize*sizeof(float)); memcpy(_mask, iBrother._mask, _storedMaskSize * _storedMaskSize * sizeof(float));
return *this; return *this;
} }
GaussianFilter::~GaussianFilter() GaussianFilter::~GaussianFilter()
{ {
if(0!=_mask) if (0 != _mask) {
{ delete[] _mask;
delete [] _mask; }
}
} }
int GaussianFilter::computeMaskSize(float sigma) int GaussianFilter::computeMaskSize(float sigma)
{ {
int maskSize = (int)floor(4*sigma)+1; int maskSize = (int)floor(4 * sigma) + 1;
if(0 == maskSize%2) if (0 == (maskSize % 2))
++maskSize; ++maskSize;
return maskSize; return maskSize;
} }
void GaussianFilter::setSigma(float sigma) void GaussianFilter::setSigma(float sigma)
{ {
_sigma = sigma; _sigma = sigma;
computeMask(); computeMask();
} }
void GaussianFilter::computeMask() void GaussianFilter::computeMask()
{ {
if(0 != _mask){ if (0 != _mask) {
delete [] _mask; delete[] _mask;
} }
_maskSize = computeMaskSize(_sigma); _maskSize = computeMaskSize(_sigma);
_storedMaskSize = (_maskSize+1)>>1; _storedMaskSize = (_maskSize + 1) >> 1;
_bound = _storedMaskSize-1; _bound = _storedMaskSize - 1;
float norm = _sigma*_sigma*2.f*M_PI; float norm = _sigma * _sigma * 2.0f * M_PI;
float invNorm = 1.0/norm; float invNorm = 1.0f / norm;
_mask = new float[_storedMaskSize*_storedMaskSize*sizeof(float)]; _mask = new float[_storedMaskSize * _storedMaskSize * sizeof(float)];
for(int i=0; i<_storedMaskSize; ++i) for (int i = 0; i < _storedMaskSize; ++i) {
for(int j=0; j<_storedMaskSize; ++j) for (int j = 0; j < _storedMaskSize; ++j) {
_mask[i*_storedMaskSize+j] = invNorm*exp(-(i*i + j*j)/(2.0*_sigma*_sigma)); #if 0
//_mask[i*_storedMaskSize+j] = exp(-(i*i + j*j)/(2.0*_sigma*_sigma)); _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
}
}
} }

@ -1,95 +1,114 @@
// /*
// Filename : Image.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Stephane Grabli *
// Purpose : Class to perform gaussian filtering operations on an image * This program is free software; you can redistribute it and/or
// Date of creation : 20/05/2003 * 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
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to perform gaussian filtering operations on an image
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 20/05/2003
// 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
#include <string.h> // for memcpy
#include <cstdlib> // for abs #include <cstdlib> // for abs
#include <string.h> // for memcpy
#include "../system/FreestyleConfig.h" #include "../system/FreestyleConfig.h"
class LIB_IMAGE_EXPORT GaussianFilter{ class LIB_IMAGE_EXPORT GaussianFilter
{
protected: protected:
/* the mask is a symetrical 2d array (with respect /* The mask is a symetrical 2d array (with respect to the middle point).
to the middle point). * Thus, M(i,j) = M(-i,j) = M(i,-j) = M(-i,-j).
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.
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;
float _sigma; int _bound;
float *_mask; int _maskSize; // the real mask size (must be odd)(the size of the mask we store is ((_maskSize+1)/2)*((_maskSize+1)/2))
int _bound; int _storedMaskSize; // (_maskSize+1)/2)
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: public:
GaussianFilter(float iSigma = 1.f) ; GaussianFilter(float iSigma = 1.0f);
GaussianFilter(const GaussianFilter&) ; GaussianFilter(const GaussianFilter&);
GaussianFilter& operator= (const GaussianFilter&) ; GaussianFilter& operator=(const GaussianFilter&);
virtual ~GaussianFilter() ; virtual ~GaussianFilter();
/*! Returns the value for pixel x,y of image "map" after a gaussian blur, /*! Returns the value for pixel x,y of image "map" after a gaussian blur, made using the sigma value.
* made using the sigma value. * The sigma value determines the mask size (~ 2 x sigma).
* The sigma value determines the mask size (~ 2 x sigma). * \param map
* \param map * The image we wish to work on. The Map template must implement the following methods:
* The image we wish to work on. The Map template must implement the * - float pixel(unsigned int x,unsigned int y) const;
* foloowing methods: * - unsigned width() const;
* - float pixel(unsigned int x,unsigned int y) const; * - unsigned height() const;
* - unsigned width() const; * \param x
* - unsigned height() const; * The abscissa of the pixel where we want to evaluate the gaussian blur.
* \param x * \param y
* The abscissa of the pixel where we want to evaluate the gaussian blur. * The ordinate of the pixel where we want to evaluate the gaussian blur.
* \param y * \param sigma
* The ordinate of the pixel where we want to evaluate the gaussian blur. * The sigma value of the gaussian function.
* \param sigma */
* The sigma value of the gaussian function. template<class Map>
*/ float getSmoothedPixel(Map *map, int x, int y);
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 */ /*! Compute the mask size and returns the REAL mask size ((2*_maskSize)-1)
inline float sigma() const {return _sigma;} * This method is provided for convenience.
inline int maskSize() const {return _maskSize;} */
inline int getBound() {return _bound;} static int computeMaskSize(float sigma);
/*! accessors */
inline float sigma() const
{
return _sigma;
}
inline int maskSize() const
{
return _maskSize;
}
inline int getBound()
{
return _bound;
}
/*! modifiers */
void setSigma(float sigma);
#if 0
void SetMaskSize(int size)
{
_maskSize = size;
_storedMaskSize = (_maskSize + 1) >> 1;
}
#endif
/*! modifiers */
void setSigma(float sigma) ;
// void SetMaskSize(int size) {_maskSize = size;_storedMaskSize=(_maskSize+1)>>1;}
protected: protected:
void computeMask(); void computeMask();
}; };
/* /*
@ -106,41 +125,37 @@ protected:
*/ */
#include <math.h> #include <math.h>
#ifdef __MACH__ #ifdef __MACH__
#define sqrtf(x) (sqrt(x)) # define sqrtf(x) (sqrt(x))
#endif #endif
template<class Map> 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 sum = 0.0f;
float L=0.f; float L = 0.0f;
int w = (int)map->width(); //soc int w = (int)map->width(); //soc
int h = (int)map->height(); //soc int h = (int)map->height(); //soc
// Current pixel is x,y // Current pixel is x,y
// Sum surrounding pixels L value: // Sum surrounding pixels L value:
for(int i=-_bound; i<=_bound; ++i) for (int i = -_bound; i <= _bound; ++i) {
{ if ((y + i < 0) || (y + i >= h))
if((y+i < 0) || (y+i >= h)) continue;
continue; for (int j = -_bound; j <= _bound; ++j) {
for(int j=-_bound; j<=_bound; ++j) if ((x + j < 0) || (x + j >= w))
{ continue;
if((x+j < 0) || (x+j >= w))
continue; float tmpL = map->pixel(x + j, y + i);
float m = _mask[abs(i) * _storedMaskSize + abs(j)];
float tmpL = map->pixel(x+j,y+i); L += m * tmpL;
float m = _mask[abs(i)*_storedMaskSize+abs(j)]; sum += m;
L += m*tmpL; }
sum += m; }
} //L /= sum;
} return L;
//L /= sum;
return L;
} }
#endif // __GAUSSIANFILTER_H__
#endif // GAUSSIANFILTER

@ -1,178 +1,177 @@
// /*
// Filename : Image.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Stephane Grabli *
// Purpose : Class to encapsulate an array of RGB or Gray level values * This program is free software; you can redistribute it and/or
// Date of creation : 20/05/2003 * 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__
// /** \file blender/freestyle/intern/image/Image.h
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to encapsulate an array of RGB or Gray level values
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 20/05/2003
// 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 #include <string.h> // for memcpy
# define IMAGE_H
# include <string.h> // for memcpy
// //
// Image base class, for all types of images // Image base class, for all types of images
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/*! This class allows the storing of part of an image, /*! This class allows the storing of part of an image, while allowing a normal access to its pixel values.
* 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
* You can for example only a rectangle of sw*sh, whose * size w*h, and access these pixels using x,y coordinates specified in the whole image coordinate system.
* 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 class FrsImage
{ {
public: public:
/*! Default constructor */
FrsImage()
{
_storedWidth = 0;
_storedHeight = 0;
_width = 0;
_height = 0;
_Ox = 0;
_Oy = 0;
}
/*! Default constructor */ /*! Copy constructor */
FrsImage() { FrsImage(const FrsImage& brother)
_storedWidth = 0; {
_storedHeight = 0; _storedWidth = brother._storedWidth;
_width = 0; _storedHeight = brother._storedHeight;
_height = 0; _width = brother._width;
_Ox = 0; _height = brother._height;
_Oy = 0; _Ox = brother._Ox;
} _Oy = brother._Oy;
}
/*! Copy constructor */ /*! Builds an FrsImage from its width and height.
FrsImage(const FrsImage& brother) { * The memory is allocated consequently.
_storedWidth = brother._storedWidth; */
_storedHeight = brother._storedHeight; FrsImage(unsigned w, unsigned h)
_width = brother._width; {
_height = brother._height; _width = w;
_Ox = brother._Ox; _height = h;
_Oy = brother._Oy; _storedWidth = w;
} _storedHeight = h;
_Ox = 0;
_Oy = 0;
}
/*! Builds an FrsImage from its width and height. /*! Builds a partial-storing image.
* The memory is allocated consequently. * \param w
*/ * The width of the complete image
FrsImage(unsigned w, unsigned h) { * \param h
_width = w; * The height of the complete image
_height = h; * \param sw
_storedWidth = w; * The width of the rectangle that will actually be stored.
_storedHeight = h; * \param sh
_Ox = 0; * The height of the rectangle that will actually be stored.
_Oy = 0; * \param ox
} * The x-abscissa of the origin of the rectangle that will actually be stored.
* \param oy
* The x-abscissa of the origin of the rectangle that will actually be stored.
*/
FrsImage(unsigned w, unsigned h, unsigned sw, unsigned sh, unsigned ox, unsigned oy)
{
_width = w;
_height = h;
_storedWidth = sw;
_storedHeight = sh;
_Ox = ox;
_Oy = oy;
}
/*! Builds a partial-storing image. /*! Operator= */
* \param w FrsImage& operator=(const FrsImage& brother)
* The width of the complete image {
* \param h _width = brother._width;
* The height of the complete image _height = brother._height;
* \param sw _storedWidth = brother._storedWidth;
* The width of the rectangle that will actually _storedHeight = brother._storedHeight;
* be stored. _Ox = brother._Ox;
* \param sh _Oy = brother._Oy;
* The height of the rectangle that will actually return *this;
* 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= */ /*! Destructor */
FrsImage& operator=(const FrsImage& brother) { virtual ~FrsImage() {}
_width = brother._width;
_height = brother._height;
_storedWidth = brother._storedWidth;
_storedHeight = brother._storedHeight;
_Ox = brother._Ox;
_Oy = brother._Oy;
return* this;
}
/*! Destructor */ /*! Returns the width of the complete image */
virtual ~FrsImage() {} inline unsigned width() const
{
return _width;
}
/*! Returns the width of the complete image */ /*! Returns the height of the complete image */
inline unsigned width() const { inline unsigned height() const
return _width; {
} return _height;
/*! 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. /*! Returns the grey value for pixel x,y */
* \param array virtual float pixel(unsigned x, unsigned y) const = 0;
* 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: /*! Sets the array.
* \param array
* The array containing the values we wish to store.
* Its size is sw*sh.
* \param width
* The width of the complete image
* \param height
* The height of the complete image
* \param sw
* The width of the rectangle that will actually be stored.
* \param sh
* The height of the rectangle that will actually be stored.
* \param ox
* The x-abscissa of the origin of the rectangle that will actually be stored.
* \param oy
* The x-abscissa of the origin of the rectangle that will actually be stored.
* \param copy
* If true, the array is copied, otherwise the pointer is copied
*/
virtual void setArray(float *array, unsigned width, unsigned height, unsigned sw, unsigned sh,
unsigned x, unsigned y, bool copy = true) = 0;
unsigned _width; /*! Returns the array containing the pixels values.
unsigned _height; * Its size is sw*sh, i.e. potentially a smaller rectangular part of the complete image.
unsigned _storedWidth; */
unsigned _storedHeight; virtual float *getArray() = 0;
unsigned _Ox; // origin of the stored part
unsigned _Oy; // origin of the stored part 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 // RGBImage
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
class RGBImage : public FrsImage class RGBImage : public FrsImage
{ {
public: public:
RGBImage() : FrsImage()
{
_rgb = 0;
}
RGBImage() : FrsImage() { RGBImage(const RGBImage& brother) : FrsImage(brother)
_rgb = 0; {
} _rgb = new float[3 * _storedWidth * _storedHeight];
memcpy(_rgb, brother._rgb, 3 * _storedWidth * _storedHeight * sizeof(float));
}
RGBImage(const RGBImage& brother) : FrsImage(brother) { RGBImage(unsigned w, unsigned h) : FrsImage(w, h)
_rgb = new float[3 * _storedWidth * _storedHeight]; {
memcpy(_rgb, brother._rgb, 3 * _storedWidth * _storedHeight * sizeof(float)); _rgb = new float[3 * _width * _height];
} }
RGBImage(unsigned w, unsigned h) : FrsImage(w, h) { RGBImage(float *rgb, unsigned w, unsigned h) : FrsImage(w, h)
_rgb = new float[3 * _width * _height]; {
} _rgb = new float[3 * _width * _height];
memcpy(_rgb, rgb, 3 * _width * _height * sizeof(float));
}
RGBImage(float* rgb, unsigned w, unsigned h) : FrsImage(w, h) { /*! Builds an RGB partial image from the useful part buffer.
_rgb = new float[3 * _width * _height]; * \param rgb
memcpy(_rgb, rgb, 3 * _width * _height * sizeof(float)); * 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
/*! Builds an RGB partial image from the useful part buffer. * The width of the complete image
* \param rgb * \param h
* The array of size 3*sw*sh containing the RGB values * The height of the complete image
* of the sw*sh pixels we need to stored. * \param sw
* These sw*sh pixels constitute a rectangular part of * The width of the part of the image we want to store and work on
* a bigger RGB image containing w*h pixels. * \param sh
* \param w * The height of the part of the image we want to store and work on
* The width of the complete image */
* \param h RGBImage(float *rgb, unsigned w, unsigned h, unsigned sw, unsigned sh, unsigned ox, unsigned oy)
* The height of the complete image : FrsImage(w, h, sw, sh, ox, oy)
* \param sw {
* The width of the part of the image we want to store and work on _rgb = new float[3 * _storedWidth * _storedHeight];
* \param sh memcpy(_rgb, rgb, 3 * _storedWidth * _storedHeight * sizeof(float));
* 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) { RGBImage& operator=(const RGBImage& brother)
dynamic_cast<FrsImage&>(*this) = brother; {
_rgb = new float[3 * _storedWidth * _storedHeight]; dynamic_cast<FrsImage&>(*this) = brother;
memcpy(_rgb, brother._rgb, 3 * _storedWidth * _storedHeight * sizeof(float)); _rgb = new float[3 * _storedWidth * _storedHeight];
return* this; memcpy(_rgb, brother._rgb, 3 * _storedWidth * _storedHeight * sizeof(float));
} return *this;
}
virtual ~RGBImage() { virtual ~RGBImage()
if(_rgb) {
delete[] _rgb; if(_rgb)
} delete[] _rgb;
}
inline float getR(unsigned x, unsigned y) const { inline float getR(unsigned x, unsigned y) const
return _rgb[3 * (y-_Oy) * _storedWidth + (x-_Ox) * 3]; {
} return _rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3];
}
inline float getG(unsigned x, unsigned y) const { inline float getG(unsigned x, unsigned y) const
return _rgb[3 * (y-_Oy) * _storedWidth + (x-_Ox) * 3 + 1]; {
} return _rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3 + 1];
}
inline float getB(unsigned x, unsigned y) const { inline float getB(unsigned x, unsigned y) const
return _rgb[3 * (y-_Oy) * _storedWidth + (x-_Ox) * 3 + 2]; {
} return _rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3 + 2];
}
virtual void setPixel(unsigned x, unsigned y, float r, float g, float b){ virtual void setPixel(unsigned x, unsigned y, float r, float g, float b)
float * tmp = &(_rgb[3 * (y-_Oy) * _storedWidth + (x-_Ox) * 3]); {
*tmp = r;++tmp; float *tmp = &(_rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3]);
*tmp = g;++tmp; *tmp = r;
*tmp = b; tmp++;
} *tmp = g;
tmp++;
*tmp = b;
}
virtual float pixel(unsigned x, unsigned y) const { virtual float pixel(unsigned x, unsigned y) const
float res = 0; {
float* tmp = &(_rgb[3 * (y-_Oy) * _storedWidth + (x-_Ox) * 3]); float res = 0.0f;
res += 11 * (*tmp++); float *tmp = &(_rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3]);
res += 16 * (*tmp++); res += 11.0f * (*tmp);
res += 5 * (*tmp); tmp++;
return res / 32; res += 16.0f * (*tmp);
} tmp++;
res += 5.0f * (*tmp);
return res / 32.0f;
}
/*! Sets the RGB array. /*! Sets the RGB array.
* copy * copy
* If true, the array is copied, otherwise the pointer is * If true, the array is copied, otherwise the pointer is copied
* copied */
*/ virtual void setArray(float *rgb, unsigned width, unsigned height, unsigned sw, unsigned sh,
virtual void setArray(float* rgb, unsigned width, unsigned height, unsigned sw, unsigned sh, unsigned x, unsigned y, bool copy = true) { unsigned x, unsigned y, bool copy = true)
_width = width; {
_height = height; _width = width;
_storedWidth = sw; _height = height;
_storedHeight = sh; _storedWidth = sw;
_Ox = x; _storedHeight = sh;
_Oy = y; _Ox = x;
if(!copy) { _Oy = y;
_rgb = rgb; if (!copy) {
return; _rgb = rgb;
} return;
}
memcpy(_rgb, rgb, 3 * _storedWidth * _storedHeight* sizeof(float));
}
virtual float * getArray() {return _rgb;} memcpy(_rgb, rgb, 3 * _storedWidth * _storedHeight * sizeof(float));
}
protected: virtual float *getArray()
{
return _rgb;
}
float* _rgb; protected:
float *_rgb;
}; };
@ -298,92 +313,103 @@ class RGBImage : public FrsImage
class GrayImage : public FrsImage class GrayImage : public FrsImage
{ {
public: public:
GrayImage() : FrsImage()
{
_lvl = 0;
}
GrayImage() : FrsImage() { GrayImage(const GrayImage& brother) : FrsImage(brother)
_lvl = 0; {
} _lvl = new float[_storedWidth * _storedHeight];
memcpy(_lvl, brother._lvl, _storedWidth * _storedHeight * sizeof(*_lvl));
}
GrayImage(const GrayImage& brother) : FrsImage(brother) { /*! Builds an empty gray image */
_lvl = new float[_storedWidth*_storedHeight]; GrayImage(unsigned w, unsigned h) : FrsImage(w, h)
memcpy(_lvl, brother._lvl, _storedWidth*_storedHeight*sizeof(*_lvl)); {
} _lvl = new float[_width * _height];
}
/*! Builds an empty gray image */ GrayImage(float *lvl, unsigned w, unsigned h) : FrsImage(w, h)
GrayImage(unsigned w, unsigned h) : FrsImage(w, h) { {
_lvl = new float[_width*_height]; _lvl = new float[_width * _height];
} memcpy(_lvl, lvl, _width * _height * sizeof(*_lvl));
}
GrayImage(float* lvl, unsigned w, unsigned h) : FrsImage(w, h) { /*! Builds a partial image from the useful part buffer.
_lvl = new float[_width*_height]; * \param lvl
memcpy(_lvl, lvl, _width*_height*sizeof(*_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
/*! Builds a partial image from the useful part buffer. * The width of the complete image
* \param lvl * \param h
* The array of size sw*sh containing the gray values * The height of the complete image
* of the sw*sh pixels we need to stored. * \param sw
* These sw*sh pixels constitute a rectangular part of * The width of the part of the image we want to store and work on
* a bigger gray image containing w*h pixels. * \param sh
* \param w * The height of the part of the image we want to store and work on
* The width of the complete image */
* \param h GrayImage(float *lvl, unsigned w, unsigned h, unsigned sw, unsigned sh, unsigned ox, unsigned oy)
* The height of the complete image : FrsImage(w, h, sw, sh, ox, oy)
* \param sw {
* The width of the part of the image we want to store and work on _lvl = new float[_storedWidth * _storedHeight];
* \param sh memcpy(_lvl, lvl, _storedWidth * _storedHeight * sizeof(float));
* 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) { GrayImage& operator=(const GrayImage& brother)
dynamic_cast<FrsImage&>(*this) = brother; {
_lvl = new float[_storedWidth * _storedHeight]; dynamic_cast<FrsImage&>(*this) = brother;
memcpy(_lvl, brother._lvl, _storedWidth * _storedHeight * sizeof(float)); _lvl = new float[_storedWidth * _storedHeight];
return *this; memcpy(_lvl, brother._lvl, _storedWidth * _storedHeight * sizeof(float));
} return *this;
}
virtual ~GrayImage() { virtual ~GrayImage()
if(_lvl) {
delete[] _lvl; if (_lvl)
} delete[] _lvl;
}
inline void setPixel(unsigned x, unsigned y, float v){ inline void setPixel(unsigned x, unsigned y, float v)
_lvl[(y-_Oy) * _storedWidth+ (x-_Ox)] = v; {
} _lvl[(y - _Oy) * _storedWidth + (x - _Ox)] = v;
}
inline float pixel(unsigned x, unsigned y) const { inline float pixel(unsigned x, unsigned y) const
return _lvl[(y-_Oy) * _storedWidth+ (x-_Ox)]; {
} return _lvl[(y - _Oy) * _storedWidth + (x - _Ox)];
}
/*! Sets the array. /*! Sets the array.
* copy * copy
* If true, the array is copie, otherwise the pounsigneder is * If true, the array is copie, otherwise the pounsigneder is copied
* copied */
*/ void setArray(float *lvl, unsigned width, unsigned height, unsigned sw, unsigned sh,
void setArray(float *lvl, unsigned width, unsigned height, unsigned sw, unsigned sh, unsigned x, unsigned y, bool copy = true) { unsigned x, unsigned y, bool copy = true)
_width = width; {
_height = height; _width = width;
_storedWidth = sw; _height = height;
_storedHeight = sh; _storedWidth = sw;
_Ox = x; _storedHeight = sh;
_Oy = y; _Ox = x;
if(!copy) { _Oy = y;
_lvl = lvl; if (!copy) {
return; _lvl = lvl;
} return;
}
memcpy(_lvl, lvl, _storedWidth * _storedHeight * sizeof(float));
}
/*! Returns the array containing the gray values. */
virtual float * getArray() {return _lvl;}
protected: memcpy(_lvl, lvl, _storedWidth * _storedHeight * sizeof(float));
}
float *_lvl; /*! Returns the array containing the gray values. */
virtual float *getArray()
{
return _lvl;
}
protected:
float *_lvl;
}; };
#endif // IMAGE_H #endif // __IMAGE_H__

@ -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 <iostream>
#include "GaussianFilter.h"
#include "Image.h"
#include "ImagePyramid.h"
using namespace std; using namespace std;
//ImagePyramid::ImagePyramid(const GrayImage& level0, unsigned nbLevels){ #if 0
// //BuildPyramid(level0,nbLevels); ImagePyramid::ImagePyramid(const GrayImage& level0, unsigned 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));
}
}
}
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];
}
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);
}
int ImagePyramid::width(int level){
return _levels[level]->width();
}
int ImagePyramid::height(int level){
return _levels[level]->height();
}
GaussianPyramid::GaussianPyramid(const GrayImage& level0, unsigned nbLevels, float iSigma)
: ImagePyramid()
{ {
_sigma = iSigma; BuildPyramid(level0,nbLevels);
BuildPyramid(level0,nbLevels); }
} #endif
GaussianPyramid::GaussianPyramid(GrayImage* level0, unsigned nbLevels, float iSigma)
: ImagePyramid() ImagePyramid::ImagePyramid(const ImagePyramid& iBrother)
{ {
_sigma = iSigma; if (!_levels.empty()) {
BuildPyramid(level0,nbLevels); for (vector<GrayImage*>::iterator im = _levels.begin(), imend = _levels.end(); im != imend; ++im) {
_levels.push_back(new GrayImage(**im));
}
}
} }
GaussianPyramid::GaussianPyramid(const GaussianPyramid& iBrother) ImagePyramid::~ImagePyramid()
: ImagePyramid(iBrother){ {
_sigma = iBrother._sigma; if (!_levels.empty()) {
} for (vector<GrayImage*>::iterator im = _levels.begin(), imend = _levels.end(); im != imend; ++im) {
void GaussianPyramid::BuildPyramid(const GrayImage& level0, unsigned nbLevels){ delete (*im);
GrayImage *pLevel = new GrayImage(level0); }
BuildPyramid(pLevel, nbLevels); _levels.clear();
}
} }
void GaussianPyramid::BuildPyramid(GrayImage* level0, unsigned nbLevels){ GrayImage * ImagePyramid::getLevel(int l)
GrayImage *pLevel = level0; {
_levels.push_back(pLevel); return _levels[l];
GaussianFilter gf(_sigma); }
// build the nbLevels:
unsigned w = pLevel->width(); float ImagePyramid::pixel(int x, int y, int level)
unsigned h = pLevel->height(); {
if(nbLevels!=0) GrayImage *img = _levels[level];
{ if (0 == level) {
for(unsigned i=0; i<nbLevels; ++i){ //soc return img->pixel(x, y);
w = pLevel->width()>>1; }
h = pLevel->height()>>1; unsigned int i = 1 << level;
GrayImage *img = new GrayImage(w,h); unsigned int sx = x >> level;
for(unsigned y=0; y<h; ++y){ unsigned int sy = y >> level;
for(unsigned x=0; x<w; ++x){ if (sx >= img->width())
float v = gf.getSmoothedPixel<GrayImage>(pLevel, 2*x,2*y); sx = img->width() - 1;
img->setPixel(x,y,v); if (sy >= img->height())
} sy = img->height() - 1;
}
_levels.push_back(img); // bilinear interpolation
pLevel = img; float A = i * (sx + 1) - x;
} float B = x - i * sx;
}else{ float C = i * (sy + 1) - y;
while((w>1) && (h>1)){ float D = y - i * sy;
w = pLevel->width()>>1;
h = pLevel->height()>>1; float P1(0), P2(0);
GrayImage *img = new GrayImage(w,h); P1 = A * img->pixel(sx, sy);
for(unsigned y=0; y<h; ++y){ if (sx < img->width() - 1) {
for(unsigned x=0; x<w; ++x){ if (x % i != 0)
float v = gf.getSmoothedPixel<GrayImage>(pLevel, 2*x,2*y); P1 += B * img->pixel(sx + 1, sy);
img->setPixel(x,y,v); }
} else {
} P1 += B * img->pixel(sx, sy);
_levels.push_back(img); }
pLevel = img; if (sy < img->height() - 1) {
} if (y % i != 0) {
} P2 = A * img->pixel(sx, sy + 1);
if (sx < img->width() - 1) {
if (x % i != 0)
P2 += B * img->pixel(sx + 1, sy + 1);
}
else {
P2 += B * img->pixel(sx, sy + 1);
}
}
}
else {
P2 = P1;
}
return (1.0f / (float)(1 << (2 * level))) * (C * P1 + D * P2);
}
int ImagePyramid::width(int level)
{
return _levels[level]->width();
}
int ImagePyramid::height(int level)
{
return _levels[level]->height();
}
GaussianPyramid::GaussianPyramid(const GrayImage& level0, unsigned nbLevels, float iSigma) : ImagePyramid()
{
_sigma = iSigma;
BuildPyramid(level0, nbLevels);
}
GaussianPyramid::GaussianPyramid(GrayImage* level0, unsigned nbLevels, float iSigma) : ImagePyramid()
{
_sigma = iSigma;
BuildPyramid(level0, nbLevels);
}
GaussianPyramid::GaussianPyramid(const GaussianPyramid& iBrother) : ImagePyramid(iBrother)
{
_sigma = iBrother._sigma;
}
void GaussianPyramid::BuildPyramid(const GrayImage& level0, unsigned nbLevels)
{
GrayImage *pLevel = new GrayImage(level0);
BuildPyramid(pLevel, nbLevels);
}
void GaussianPyramid::BuildPyramid(GrayImage* level0, unsigned nbLevels)
{
GrayImage *pLevel = level0;
_levels.push_back(pLevel);
GaussianFilter gf(_sigma);
// build the nbLevels:
unsigned w = pLevel->width();
unsigned h = pLevel->height();
if (nbLevels != 0) {
for (unsigned int i = 0; i < nbLevels; ++i) { //soc
w = pLevel->width() >> 1;
h = pLevel->height() >> 1;
GrayImage *img = new GrayImage(w, h);
for (unsigned int y = 0; y < h; ++y) {
for (unsigned int x = 0; x < w; ++x) {
float v = gf.getSmoothedPixel<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;
}
}
} }

@ -1,92 +1,116 @@
// /*
// Filename : ImagePyramid.h * ***** BEGIN GPL LICENSE BLOCK *****
// Author(s) : Stephane Grabli *
// Purpose : Class to represent a pyramid of images * This program is free software; you can redistribute it and/or
// Date of creation : 25/12/2003 * 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
// Copyright (C) : Please refer to the COPYRIGHT file distributed * \ingroup freestyle
// with this source distribution. * \brief Class to represent a pyramid of images
// * \author Stephane Grabli
// This program is free software; you can redistribute it and/or * \date 25/12/2003
// 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
#include "../system/FreestyleConfig.h"
#include <vector> #include <vector>
class GrayImage; #include "../system/FreestyleConfig.h"
class LIB_IMAGE_EXPORT ImagePyramid{
protected:
std::vector<GrayImage*> _levels;
public:
ImagePyramid(){}
ImagePyramid(const ImagePyramid& iBrother);
//ImagePyramid(const GrayImage& level0, unsigned nbLevels);
virtual ~ImagePyramid();
/*! Builds the pyramid. class GrayImage;
* must be overloaded by inherited classes.
* if nbLevels==0, the complete pyramid is built class LIB_IMAGE_EXPORT ImagePyramid
*/ {
virtual void BuildPyramid(const GrayImage& level0, unsigned nbLevels) = 0; protected:
std::vector<GrayImage*> _levels;
/*! Builds a pyramid without copying the base level */
virtual void BuildPyramid(GrayImage* level0, unsigned nbLevels) = 0; public:
ImagePyramid(){}
virtual GrayImage * getLevel(int l); ImagePyramid(const ImagePyramid& iBrother);
/*! Returns the pixel x,y using bilinear interpolation. //ImagePyramid(const GrayImage& level0, unsigned nbLevels);
* \param x virtual ~ImagePyramid();
* the abscissa specified in the finest level coordinate system
* \param y /*! Builds the pyramid.
* the ordinate specified in the finest level coordinate system * must be overloaded by inherited classes.
* \param level * if nbLevels==0, the complete pyramid is built
* the level from which we want the pixel to be evaluated */
*/ virtual void BuildPyramid(const GrayImage& level0, unsigned nbLevels) = 0;
virtual float pixel(int x, int y, int level=0);
/*! Returns the width of the level-th level image */ /*! Builds a pyramid without copying the base level */
virtual int width(int level=0); virtual void BuildPyramid(GrayImage* level0, unsigned nbLevels) = 0;
/*! Returns the height of the level-th level image */
virtual int height(int level=0); virtual GrayImage * getLevel(int l);
/*! Returns the number of levels in the pyramid */ /*! Returns the pixel x,y using bilinear interpolation.
inline int getNumberOfLevels() const { return _levels.size();} * \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 class LIB_IMAGE_EXPORT GaussianPyramid : public ImagePyramid
{ {
protected: protected:
float _sigma; float _sigma;
public: public:
GaussianPyramid(float iSigma=1.f) : ImagePyramid() {_sigma=iSigma;} GaussianPyramid(float iSigma=1.f) : ImagePyramid()
GaussianPyramid(const GrayImage& level0, unsigned nbLevels, float iSigma=1.f); {
GaussianPyramid(GrayImage* level0, unsigned nbLevels, float iSigma=1.f); _sigma = iSigma;
GaussianPyramid(const GaussianPyramid& iBrother); }
virtual ~GaussianPyramid(){}
virtual void BuildPyramid(const GrayImage& level0, unsigned nbLevels); GaussianPyramid(const GrayImage& level0, unsigned nbLevels, float iSigma=1.0f);
virtual void BuildPyramid(GrayImage* level0, unsigned nbLevels); GaussianPyramid(GrayImage* level0, unsigned nbLevels, float iSigma=1.0f);
/* accessors */ GaussianPyramid(const GaussianPyramid& iBrother);
inline float getSigma() const {return _sigma;} virtual ~GaussianPyramid() {}
/* modifiers */
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__