This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/freestyle/intern/stroke/Operators.cpp
Campbell Barton 829a2cc1b0 remove blender foundation copyright from freestyle files.
this can be added back on case-by-case basis, but better not assume ownership of another projects work by default.
2013-03-31 01:11:07 +00:00

1275 lines
32 KiB
C++

/*
* ***** 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.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/freestyle/intern/stroke/Operators.cpp
* \ingroup freestyle
* \brief Class gathering stroke creation algorithms
* \author Stephane Grabli
* \author Emmanuel Turquin
* \date 01/07/2003
*/
#include <algorithm>
#include <stdexcept>
#include "Operators.h"
#include "Canvas.h"
#include "Stroke.h"
#include "BKE_global.h"
LIB_STROKE_EXPORT Operators::I1DContainer Operators::_current_view_edges_set;
LIB_STROKE_EXPORT Operators::I1DContainer Operators::_current_chains_set;
LIB_STROKE_EXPORT Operators::I1DContainer *Operators::_current_set = NULL;
LIB_STROKE_EXPORT Operators::StrokesContainer Operators::_current_strokes_set;
int Operators::select(UnaryPredicate1D& pred)
{
if (!_current_set)
return 0;
if (_current_set->empty())
return 0;
I1DContainer new_set;
I1DContainer rejected;
Functions1D::ChainingTimeStampF1D cts;
Functions1D::TimeStampF1D ts;
I1DContainer::iterator it = _current_set->begin();
I1DContainer::iterator itbegin = it;
while (it != _current_set->end()) {
Interface1D *i1d = *it;
cts(*i1d); // mark everyone's chaining time stamp anyway
if (pred(*i1d) < 0) {
new_set.clear();
rejected.clear();
return -1;
}
if (pred.result) {
new_set.push_back(i1d);
ts(*i1d);
}
else {
rejected.push_back(i1d);
}
++it;
}
if ((*itbegin)->getExactTypeName() != "ViewEdge") {
for (it = rejected.begin(); it != rejected.end(); ++it)
delete *it;
}
rejected.clear();
_current_set->clear();
*_current_set = new_set;
return 0;
}
int Operators::chain(ViewEdgeInternal::ViewEdgeIterator& it, UnaryPredicate1D& pred, UnaryFunction1D_void& modifier)
{
if (_current_view_edges_set.empty())
return 0;
unsigned id = 0;
ViewEdge *edge;
I1DContainer new_chains_set;
for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
it_edge != _current_view_edges_set.end();
++it_edge)
{
if (pred(**it_edge) < 0)
goto error;
if (pred.result)
continue;
edge = dynamic_cast<ViewEdge*>(*it_edge);
it.setBegin(edge);
it.setCurrentEdge(edge);
Chain *new_chain = new Chain(id);
++id;
while (TRUE) {
new_chain->push_viewedge_back(*it, it.getOrientation());
if (modifier(**it) < 0) {
delete new_chain;
goto error;
}
++it;
if (it.isEnd())
break;
if (pred(**it) < 0) {
delete new_chain;
goto error;
}
if (pred.result)
break;
}
new_chains_set.push_back(new_chain);
}
if (!new_chains_set.empty()) {
for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
_current_chains_set.push_back(*it);
}
new_chains_set.clear();
_current_set = &_current_chains_set;
}
return 0;
error:
for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
delete (*it);
}
new_chains_set.clear();
return -1;
}
int Operators::chain(ViewEdgeInternal::ViewEdgeIterator& it, UnaryPredicate1D& pred)
{
if (_current_view_edges_set.empty())
return 0;
unsigned id = 0;
Functions1D::IncrementChainingTimeStampF1D ts;
Predicates1D::EqualToChainingTimeStampUP1D pred_ts(TimeStamp::instance()->getTimeStamp() + 1);
ViewEdge *edge;
I1DContainer new_chains_set;
for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
it_edge != _current_view_edges_set.end();
++it_edge)
{
if (pred(**it_edge) < 0)
goto error;
if (pred.result)
continue;
if (pred_ts(**it_edge) < 0)
goto error;
if (pred_ts.result)
continue;
edge = dynamic_cast<ViewEdge*>(*it_edge);
it.setBegin(edge);
it.setCurrentEdge(edge);
Chain *new_chain = new Chain(id);
++id;
while (TRUE) {
new_chain->push_viewedge_back(*it, it.getOrientation());
ts(**it);
++it;
if (it.isEnd())
break;
if (pred(**it) < 0) {
delete new_chain;
goto error;
}
if (pred.result)
break;
if (pred_ts(**it) < 0) {
delete new_chain;
goto error;
}
if (pred_ts.result)
break;
}
new_chains_set.push_back(new_chain);
}
if (!new_chains_set.empty()) {
for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
_current_chains_set.push_back(*it);
}
new_chains_set.clear();
_current_set = &_current_chains_set;
}
return 0;
error:
for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
delete (*it);
}
new_chains_set.clear();
return -1;
}
#if 0
void Operators::bidirectionalChain(ViewEdgeIterator& it, UnaryPredicate1D& pred, UnaryFunction1D_void& modifier)
{
if (_current_view_edges_set.empty())
return;
unsigned id = 0;
ViewEdge *edge;
Chain *new_chain;
for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
it_edge != _current_view_edges_set.end();
++it_edge)
{
if (pred(**it_edge))
continue;
edge = dynamic_cast<ViewEdge*>(*it_edge);
it.setBegin(edge);
it.setCurrentEdge(edge);
Chain *new_chain = new Chain(id);
++id;
#if 0 // FIXME
ViewEdgeIterator it_back(it);
--it_back;
#endif
do {
new_chain->push_viewedge_back(*it, it.getOrientation());
modifier(**it);
++it;
} while (!it.isEnd() && !pred(**it));
it.setBegin(edge);
it.setCurrentEdge(edge);
--it;
while (!it.isEnd() && !pred(**it)) {
new_chain->push_viewedge_front(*it, it.getOrientation());
modifier(**it);
--it;
}
_current_chains_set.push_back(new_chain);
}
if (!_current_chains_set.empty())
_current_set = &_current_chains_set;
}
void Operators::bidirectionalChain(ViewEdgeIterator& it, UnaryPredicate1D& pred)
{
if (_current_view_edges_set.empty())
return;
unsigned id = 0;
Functions1D::IncrementChainingTimeStampF1D ts;
Predicates1D::EqualToChainingTimeStampUP1D pred_ts(TimeStamp::instance()->getTimeStamp() + 1);
ViewEdge *edge;
Chain *new_chain;
for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
it_edge != _current_view_edges_set.end();
++it_edge)
{
if (pred(**it_edge) || pred_ts(**it_edge))
continue;
edge = dynamic_cast<ViewEdge*>(*it_edge);
it.setBegin(edge);
it.setCurrentEdge(edge);
Chain *new_chain = new Chain(id);
++id;
#if 0 //FIXME
ViewEdgeIterator it_back(it);
--it_back;
#endif
do {
new_chain->push_viewedge_back(*it, it.getOrientation());
ts(**it);
++it;
} while (!it.isEnd() && !pred(**it) && !pred_ts(**it));
it.setBegin(edge);
it.setCurrentEdge(edge);
--it;
while (!it.isEnd() && !pred(**it) && !pred_ts(**it)) {
new_chain->push_viewedge_front(*it, it.getOrientation());
ts(**it);
--it;
}
_current_chains_set.push_back(new_chain);
}
if (!_current_chains_set.empty())
_current_set = &_current_chains_set;
}
#endif
int Operators::bidirectionalChain(ChainingIterator& it, UnaryPredicate1D& pred)
{
if (_current_view_edges_set.empty())
return 0;
unsigned id = 0;
Functions1D::IncrementChainingTimeStampF1D ts;
Predicates1D::EqualToChainingTimeStampUP1D pred_ts(TimeStamp::instance()->getTimeStamp() + 1);
ViewEdge *edge;
I1DContainer new_chains_set;
for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
it_edge != _current_view_edges_set.end();
++it_edge)
{
if (pred(**it_edge) < 0)
goto error;
if (pred.result)
continue;
if (pred_ts(**it_edge) < 0)
goto error;
if (pred_ts.result)
continue;
edge = dynamic_cast<ViewEdge*>(*it_edge);
// re-init iterator
it.setBegin(edge);
it.setCurrentEdge(edge);
it.setOrientation(true);
if (it.init() < 0)
goto error;
Chain *new_chain = new Chain(id);
++id;
#if 0 // FIXME
ViewEdgeIterator it_back(it);
--it_back;
#endif
while (TRUE) {
new_chain->push_viewedge_back(*it, it.getOrientation());
ts(**it);
if (it.increment() < 0) {
delete new_chain;
goto error;
}
if (it.isEnd())
break;
if (pred(**it) < 0) {
delete new_chain;
goto error;
}
if (pred.result)
break;
}
it.setBegin(edge);
it.setCurrentEdge(edge);
it.setOrientation(true);
if (it.decrement() < 0) {
delete new_chain;
goto error;
}
while (!it.isEnd()) {
if (pred(**it) < 0) {
delete new_chain;
goto error;
}
if (pred.result)
break;
new_chain->push_viewedge_front(*it, it.getOrientation());
ts(**it);
if (it.decrement() < 0) {
delete new_chain;
goto error;
}
}
new_chains_set.push_back(new_chain);
}
if (!new_chains_set.empty()) {
for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
_current_chains_set.push_back(*it);
}
new_chains_set.clear();
_current_set = &_current_chains_set;
}
return 0;
error:
for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
delete (*it);
}
new_chains_set.clear();
return -1;
}
int Operators::bidirectionalChain(ChainingIterator& it)
{
if (_current_view_edges_set.empty())
return 0;
unsigned id = 0;
Functions1D::IncrementChainingTimeStampF1D ts;
Predicates1D::EqualToChainingTimeStampUP1D pred_ts(TimeStamp::instance()->getTimeStamp() + 1);
ViewEdge *edge;
I1DContainer new_chains_set;
for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
it_edge != _current_view_edges_set.end();
++it_edge)
{
if (pred_ts(**it_edge) < 0)
goto error;
if (pred_ts.result)
continue;
edge = dynamic_cast<ViewEdge*>(*it_edge);
// re-init iterator
it.setBegin(edge);
it.setCurrentEdge(edge);
it.setOrientation(true);
if (it.init() < 0)
goto error;
Chain *new_chain = new Chain(id);
++id;
#if 0 // FIXME
ViewEdgeIterator it_back(it);
--it_back;
#endif
do {
new_chain->push_viewedge_back(*it, it.getOrientation());
ts(**it);
if (it.increment() < 0) { // FIXME
delete new_chain;
goto error;
}
} while (!it.isEnd());
it.setBegin(edge);
it.setCurrentEdge(edge);
it.setOrientation(true);
if (it.decrement() < 0) { // FIXME
delete new_chain;
goto error;
}
while (!it.isEnd()) {
new_chain->push_viewedge_front(*it, it.getOrientation());
ts(**it);
if (it.decrement() < 0) { // FIXME
delete new_chain;
goto error;
}
}
new_chains_set.push_back(new_chain);
}
if (!new_chains_set.empty()) {
for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
_current_chains_set.push_back(*it);
}
new_chains_set.clear();
_current_set = &_current_chains_set;
}
return 0;
error:
for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
delete (*it);
}
new_chains_set.clear();
return -1;
}
int Operators::sequentialSplit(UnaryPredicate0D& pred, float sampling)
{
if (_current_chains_set.empty()) {
cerr << "Warning: current set empty" << endl;
return 0;
}
CurvePoint *point;
Chain *new_curve;
I1DContainer splitted_chains;
Interface0DIterator first;
Interface0DIterator end;
Interface0DIterator last;
Interface0DIterator it;
I1DContainer::iterator cit = _current_chains_set.begin(), citend = _current_chains_set.end();
for (; cit != citend; ++cit) {
Id currentId = (*cit)->getId();
new_curve = new Chain(currentId);
first = (*cit)->pointsBegin(sampling);
end = (*cit)->pointsEnd(sampling);
last = end;
--last;
it = first;
point = dynamic_cast<CurvePoint*>(&(*it));
new_curve->push_vertex_back(point);
++it;
for (; it != end; ++it) {
point = dynamic_cast<CurvePoint*>(&(*it));
new_curve->push_vertex_back(point);
if (pred(it) < 0) {
delete new_curve;
goto error;
}
if (pred.result && (it != last)) {
splitted_chains.push_back(new_curve);
currentId.setSecond(currentId.getSecond() + 1);
new_curve = new Chain(currentId);
new_curve->push_vertex_back(point);
}
}
if (new_curve->nSegments() == 0) {
delete new_curve;
return 0;
}
splitted_chains.push_back(new_curve);
}
// Update the current set of chains:
cit = _current_chains_set.begin();
for (; cit != citend; ++cit) {
delete (*cit);
}
_current_chains_set.clear();
#if 0
_current_chains_set = splitted_chains;
#else
for (cit = splitted_chains.begin(), citend = splitted_chains.end(); cit != citend; ++cit) {
if ((*cit)->getLength2D() < M_EPSILON) {
delete (*cit);
continue;
}
_current_chains_set.push_back(*cit);
}
#endif
splitted_chains.clear();
if (!_current_chains_set.empty())
_current_set = &_current_chains_set;
return 0;
error:
cit = splitted_chains.begin();
citend = splitted_chains.end();
for (; cit != citend; ++cit) {
delete (*cit);
}
splitted_chains.clear();
return -1;
}
int Operators::sequentialSplit(UnaryPredicate0D& startingPred, UnaryPredicate0D& stoppingPred, float sampling)
{
if (_current_chains_set.empty()) {
cerr << "Warning: current set empty" << endl;
return 0;
}
CurvePoint *point;
Chain *new_curve;
I1DContainer splitted_chains;
Interface0DIterator first;
Interface0DIterator end;
Interface0DIterator last;
Interface0DIterator itStart;
Interface0DIterator itStop;
I1DContainer::iterator cit = _current_chains_set.begin(), citend = _current_chains_set.end();
for (; cit != citend; ++cit) {
Id currentId = (*cit)->getId();
first = (*cit)->pointsBegin(sampling);
end = (*cit)->pointsEnd(sampling);
last = end;
--last;
itStart = first;
do {
itStop = itStart;
++itStop;
new_curve = new Chain(currentId);
currentId.setSecond(currentId.getSecond() + 1);
point = dynamic_cast<CurvePoint*>(&(*itStart));
new_curve->push_vertex_back(point);
do {
point = dynamic_cast<CurvePoint*>(&(*itStop));
new_curve->push_vertex_back(point);
++itStop;
if (itStop == end)
break;
if (stoppingPred(itStop) < 0) {
delete new_curve;
goto error;
}
} while (!stoppingPred.result);
if (itStop != end) {
point = dynamic_cast<CurvePoint*>(&(*itStop));
new_curve->push_vertex_back(point);
}
if (new_curve->nSegments() == 0) {
delete new_curve;
}
else {
splitted_chains.push_back(new_curve);
}
// find next start
do {
++itStart;
if (itStart == end)
break;
if (startingPred(itStart) < 0)
goto error;
} while (!startingPred.result);
} while ((itStart != end) && (itStart != last));
}
// Update the current set of chains:
cit = _current_chains_set.begin();
for (; cit != citend; ++cit) {
delete (*cit);
}
_current_chains_set.clear();
#if 0
_current_chains_set = splitted_chains;
#else
for (cit = splitted_chains.begin(), citend = splitted_chains.end(); cit != citend; ++cit) {
if ((*cit)->getLength2D() < M_EPSILON) {
delete (*cit);
continue;
}
_current_chains_set.push_back(*cit);
}
#endif
splitted_chains.clear();
if (!_current_chains_set.empty())
_current_set = &_current_chains_set;
return 0;
error:
cit = splitted_chains.begin();
citend = splitted_chains.end();
for (; cit != citend; ++cit) {
delete (*cit);
}
splitted_chains.clear();
return -1;
}
#include "CurveIterators.h"
// Internal function
static int __recursiveSplit(Chain *_curve, UnaryFunction0D<double>& func, UnaryPredicate1D& pred, float sampling,
Operators::I1DContainer& newChains, Operators::I1DContainer& splitted_chains)
{
if (((_curve->nSegments() == 1) && (sampling == 0)) || (_curve->getLength2D() <= sampling)) {
newChains.push_back(_curve);
return 0;
}
CurveInternal::CurvePointIterator first = _curve->curvePointsBegin(sampling);
CurveInternal::CurvePointIterator second = first;
++second;
CurveInternal::CurvePointIterator end = _curve->curvePointsEnd(sampling);
CurveInternal::CurvePointIterator it = second;
CurveInternal::CurvePointIterator split = second;
Interface0DIterator it0d = it.castToInterface0DIterator();
real _min = FLT_MAX; // func(it0d);
++it;
CurveInternal::CurvePointIterator next = it;
++next;
bool bsplit = false;
for (; ((it != end) && (next != end)); ++it, ++next) {
it0d = it.castToInterface0DIterator();
if (func(it0d) < 0)
return -1;
if (func.result < _min) {
_min = func.result;
split = it;
bsplit = true;
}
}
if (!bsplit) { // we didn't find any minimum
newChains.push_back(_curve);
return 0;
}
// retrieves the current splitting id
Id *newId = _curve->getSplittingId();
if (newId == 0) {
newId = new Id(_curve->getId());
_curve->setSplittingId(newId);
}
Chain *new_curve_a = new Chain(*newId);
newId->setSecond(newId->getSecond() + 1);
new_curve_a->setSplittingId(newId);
Chain *new_curve_b = new Chain(*newId);
newId->setSecond(newId->getSecond() + 1);
new_curve_b->setSplittingId(newId);
CurveInternal::CurvePointIterator vit = _curve->curveVerticesBegin(), vitend = _curve->curveVerticesEnd();
CurveInternal::CurvePointIterator vnext = vit;
++vnext;
for (; (vit != vitend) && (vnext != vitend) && (vnext._CurvilinearLength < split._CurvilinearLength);
++vit, ++vnext)
{
new_curve_a->push_vertex_back(&(*vit));
}
if ((vit == vitend) || (vnext == vitend)) {
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "The split takes place in bad location" << endl;
}
newChains.push_back(_curve);
delete new_curve_a;
delete new_curve_b;
return 0;
}
// build the two resulting chains
new_curve_a->push_vertex_back(&(*vit));
new_curve_a->push_vertex_back(&(*split));
new_curve_b->push_vertex_back(&(*split));
for (vit = vnext; vit != vitend; ++vit)
new_curve_b->push_vertex_back(&(*vit));
// let's check whether one or two of the two new curves satisfy the stopping condition or not.
// (if one of them satisfies it, we don't split)
if (pred(*new_curve_a) < 0 || (!pred.result && pred(*new_curve_b) < 0)) {
delete new_curve_a;
delete new_curve_b;
return -1;
}
if (pred.result) {
// we don't actually create these two chains
newChains.push_back(_curve);
delete new_curve_a;
delete new_curve_b;
return 0;
}
// here we know we'll split _curve:
splitted_chains.push_back(_curve);
__recursiveSplit(new_curve_a, func, pred, sampling, newChains, splitted_chains);
__recursiveSplit(new_curve_b, func, pred, sampling, newChains, splitted_chains);
return 0;
}
int Operators::recursiveSplit(UnaryFunction0D<double>& func, UnaryPredicate1D& pred, float sampling)
{
if (_current_chains_set.empty()) {
cerr << "Warning: current set empty" << endl;
return 0;
}
Chain *currentChain = 0;
I1DContainer splitted_chains;
I1DContainer newChains;
I1DContainer::iterator cit = _current_chains_set.begin(), citend = _current_chains_set.end();
for (; cit != citend; ++cit) {
currentChain = dynamic_cast<Chain*>(*cit);
if (!currentChain)
continue;
// let's check the first one:
if (pred(*currentChain) < 0)
return -1;
if (!pred.result) {
__recursiveSplit(currentChain, func, pred, sampling, newChains, splitted_chains);
}
else {
newChains.push_back(currentChain);
}
}
// Update the current set of chains:
if (!splitted_chains.empty()) {
for (cit = splitted_chains.begin(), citend = splitted_chains.end(); cit != citend; ++cit) {
delete (*cit);
}
splitted_chains.clear();
}
_current_chains_set.clear();
#if 0
_current_chains_set = newChains;
#else
for (cit = newChains.begin(), citend = newChains.end(); cit != citend; ++cit) {
if ((*cit)->getLength2D() < M_EPSILON) {
delete (*cit);
continue;
}
_current_chains_set.push_back(*cit);
}
#endif
newChains.clear();
if (!_current_chains_set.empty())
_current_set = &_current_chains_set;
return 0;
}
// recursive split with pred 0D
static int __recursiveSplit(Chain *_curve, UnaryFunction0D<double>& func, UnaryPredicate0D& pred0d,
UnaryPredicate1D& pred, float sampling,
Operators::I1DContainer& newChains, Operators::I1DContainer& splitted_chains)
{
if (((_curve->nSegments() == 1) && (sampling == 0)) || (_curve->getLength2D() <= sampling)) {
newChains.push_back(_curve);
return 0;
}
CurveInternal::CurvePointIterator first = _curve->curvePointsBegin(sampling);
CurveInternal::CurvePointIterator second = first;
++second;
CurveInternal::CurvePointIterator end = _curve->curvePointsEnd(sampling);
CurveInternal::CurvePointIterator it = second;
CurveInternal::CurvePointIterator split = second;
Interface0DIterator it0d = it.castToInterface0DIterator();
#if 0
real _min = func(it0d);
++it;
#endif
real _min = FLT_MAX;
++it;
real mean = 0.f;
//soc unused - real variance = 0.0f;
unsigned count = 0;
CurveInternal::CurvePointIterator next = it;
++next;
bool bsplit = false;
for (; ((it != end) && (next != end)); ++it, ++next) {
++count;
it0d = it.castToInterface0DIterator();
if (pred0d(it0d) < 0)
return -1;
if (!pred0d.result)
continue;
if (func(it0d) < 0)
return -1;
mean += func.result;
if (func.result < _min) {
_min = func.result;
split = it;
bsplit = true;
}
}
mean /= (float)count;
//if ((!bsplit) || (mean - _min > mean)) { // we didn't find any minimum
if (!bsplit) { // we didn't find any minimum
newChains.push_back(_curve);
return 0;
}
// retrieves the current splitting id
Id *newId = _curve->getSplittingId();
if (newId == NULL) {
newId = new Id(_curve->getId());
_curve->setSplittingId(newId);
}
Chain *new_curve_a = new Chain(*newId);
newId->setSecond(newId->getSecond() + 1);
new_curve_a->setSplittingId(newId);
Chain *new_curve_b = new Chain(*newId);
newId->setSecond(newId->getSecond() + 1);
new_curve_b->setSplittingId(newId);
CurveInternal::CurvePointIterator vit = _curve->curveVerticesBegin(), vitend = _curve->curveVerticesEnd();
CurveInternal::CurvePointIterator vnext = vit;
++vnext;
for (;
(vit != vitend) && (vnext != vitend) && (vnext._CurvilinearLength < split._CurvilinearLength);
++vit, ++vnext)
{
new_curve_a->push_vertex_back(&(*vit));
}
if ((vit == vitend) || (vnext == vitend)) {
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "The split takes place in bad location" << endl;
}
newChains.push_back(_curve);
delete new_curve_a;
delete new_curve_b;
return 0;
}
// build the two resulting chains
new_curve_a->push_vertex_back(&(*vit));
new_curve_a->push_vertex_back(&(*split));
new_curve_b->push_vertex_back(&(*split));
for (vit = vnext; vit != vitend; ++vit)
new_curve_b->push_vertex_back(&(*vit));
// let's check whether one or two of the two new curves satisfy the stopping condition or not.
// (if one of them satisfies it, we don't split)
if (pred(*new_curve_a) < 0 || (!pred.result && pred(*new_curve_b) < 0)) {
delete new_curve_a;
delete new_curve_b;
return -1;
}
if (pred.result) {
// we don't actually create these two chains
newChains.push_back(_curve);
delete new_curve_a;
delete new_curve_b;
return 0;
}
// here we know we'll split _curve:
splitted_chains.push_back(_curve);
__recursiveSplit(new_curve_a, func, pred0d, pred, sampling, newChains, splitted_chains);
__recursiveSplit(new_curve_b, func, pred0d, pred, sampling, newChains, splitted_chains);
return 0;
}
int Operators::recursiveSplit(UnaryFunction0D<double>& func, UnaryPredicate0D& pred0d, UnaryPredicate1D& pred,
float sampling)
{
if (_current_chains_set.empty()) {
cerr << "Warning: current set empty" << endl;
return 0;
}
Chain *currentChain = 0;
I1DContainer splitted_chains;
I1DContainer newChains;
I1DContainer::iterator cit = _current_chains_set.begin(), citend = _current_chains_set.end();
for (; cit != citend; ++cit) {
currentChain = dynamic_cast<Chain*>(*cit);
if (!currentChain)
continue;
// let's check the first one:
if (pred(*currentChain) < 0)
return -1;
if (!pred.result) {
__recursiveSplit(currentChain, func, pred0d, pred, sampling, newChains, splitted_chains);
}
else {
newChains.push_back(currentChain);
}
}
// Update the current set of chains:
if (!splitted_chains.empty()) {
for (cit = splitted_chains.begin(), citend = splitted_chains.end(); cit != citend; ++cit) {
delete (*cit);
}
splitted_chains.clear();
}
_current_chains_set.clear();
#if 0
_current_chains_set = newChains;
#else
for (cit = newChains.begin(), citend = newChains.end(); cit != citend; ++cit) {
if ((*cit)->getLength2D() < M_EPSILON) {
delete (*cit);
continue;
}
_current_chains_set.push_back(*cit);
}
#endif
newChains.clear();
if (!_current_chains_set.empty())
_current_set = &_current_chains_set;
return 0;
}
// Internal class
class PredicateWrapper
{
public:
inline PredicateWrapper(BinaryPredicate1D& pred)
{
_pred = &pred;
}
inline bool operator()(Interface1D *i1, Interface1D *i2)
{
if ((*_pred)(*i1, *i2) < 0)
throw std::runtime_error("comparison failed");
return _pred->result;
}
private:
BinaryPredicate1D *_pred;
};
int Operators::sort(BinaryPredicate1D& pred)
{
if (!_current_set)
return 0;
PredicateWrapper wrapper(pred);
try {
std::sort(_current_set->begin(), _current_set->end(), wrapper);
}
catch (std::runtime_error &e) {
cerr << "Warning: Operator.sort(): " << e.what() << endl;
return -1;
}
return 0;
}
static Stroke *createStroke(Interface1D& inter)
{
Stroke *stroke = new Stroke;
stroke->setId(inter.getId());
float currentCurvilignAbscissa = 0.0f;
Interface0DIterator it = inter.verticesBegin(), itend = inter.verticesEnd();
Interface0DIterator itfirst = it;
Vec2r current(it->getPoint2D());
Vec2r previous = current;
SVertex *sv;
CurvePoint *cp;
StrokeVertex *stroke_vertex = NULL;
bool hasSingularity = false;
do {
cp = dynamic_cast<CurvePoint*>(&(*it));
if (!cp) {
sv = dynamic_cast<SVertex*>(&(*it));
if (!sv) {
cerr << "Warning: unexpected Vertex type" << endl;
continue;
}
stroke_vertex = new StrokeVertex(sv);
}
else {
stroke_vertex = new StrokeVertex(cp);
}
current = stroke_vertex->getPoint2D();
Vec2r vec_tmp(current - previous);
real dist = vec_tmp.norm();
if (dist < 1.0e-6)
hasSingularity = true;
currentCurvilignAbscissa += dist;
stroke_vertex->setCurvilinearAbscissa(currentCurvilignAbscissa);
stroke->push_back(stroke_vertex);
previous = current;
++it;
} while ((it != itend) && (it != itfirst));
if (it == itfirst) {
// Add last vertex:
cp = dynamic_cast<CurvePoint*>(&(*it));
if (!cp) {
sv = dynamic_cast<SVertex*>(&(*it));
if (!sv)
cerr << "Warning: unexpected Vertex type" << endl;
else
stroke_vertex = new StrokeVertex(sv);
}
else {
stroke_vertex = new StrokeVertex(cp);
}
current = stroke_vertex->getPoint2D();
Vec2r vec_tmp(current - previous);
real dist = vec_tmp.norm();
if (dist < 1.0e-6)
hasSingularity = true;
currentCurvilignAbscissa += dist;
stroke_vertex->setCurvilinearAbscissa(currentCurvilignAbscissa);
stroke->push_back(stroke_vertex);
}
// Discard the stroke if the number of stroke vertices is less than two
if (stroke->strokeVerticesSize() < 2) {
delete stroke;
return NULL;
}
stroke->setLength(currentCurvilignAbscissa);
if (hasSingularity) {
// Try to address singular points such that the distance between two subsequent vertices
// are smaller than epsilon.
Interface0DIterator v = stroke->verticesBegin();
Interface0DIterator vnext = v;
++vnext;
Vec2r next((*v).getPoint2D());
while (!vnext.isEnd()) {
current = next;
next = (*vnext).getPoint2D();
if ((next - current).norm() < 1.0e-6) {
Interface0DIterator vprevious = v;
if (!vprevious.isBegin())
--vprevious;
// collect a set of overlapping vertices
std::vector<Interface0D *> overlapping_vertices;
overlapping_vertices.push_back(&(*v));
do {
overlapping_vertices.push_back(&(*vnext));
current = next;
++v;
++vnext;
if (vnext.isEnd())
break;
next = (*vnext).getPoint2D();
} while ((next - current).norm() < 1.0e-6);
Vec2r target;
bool reverse;
if (!vnext.isEnd()) {
target = (*vnext).getPoint2D();
reverse = false;
}
else if (!vprevious.isBegin()) {
target = (*vprevious).getPoint2D();
reverse = true;
}
else {
// Discard the stroke because all stroke vertices are overlapping
delete stroke;
return NULL;
}
current = overlapping_vertices.front()->getPoint2D();
Vec2r dir(target - current);
real dist = dir.norm();
real len = 1.0e-3; // default offset length
int nvert = overlapping_vertices.size();
if (dist < len * nvert) {
len = dist / nvert;
}
dir.normalize();
Vec2r offset(dir * len);
// add the offset to the overlapping vertices
StrokeVertex *sv;
std::vector<Interface0D *>::iterator it = overlapping_vertices.begin();
if (!reverse) {
for (int n = 1; n < nvert; n++) {
sv = dynamic_cast<StrokeVertex*>(*it);
sv->setPoint(sv->getPoint() + offset * n);
++it;
}
}
else {
int last = nvert - 1;
for (int n = 0; n < last; n++) {
sv = dynamic_cast<StrokeVertex*>(*it);
sv->setPoint(sv->getPoint() + offset * (last - n));
++it;
}
}
if (vnext.isEnd())
break;
}
++v;
++vnext;
}
}
{
// Check if the stroke no longer contains singular points
Interface0DIterator v = stroke->verticesBegin();
Interface0DIterator vnext = v;
++vnext;
Vec2r next((*v).getPoint2D());
bool warning = false;
while (!vnext.isEnd()) {
current = next;
next = (*vnext).getPoint2D();
if ((next - current).norm() < 1.0e-6) {
warning = true;
break;
}
++v;
++vnext;
}
if (warning && G.debug & G_DEBUG_FREESTYLE) {
printf("Warning: stroke contains singular points.\n");
}
}
return stroke;
}
inline int applyShading(Stroke& stroke, vector<StrokeShader*>& shaders)
{
for (vector<StrokeShader*>::iterator it = shaders.begin(); it != shaders.end(); ++it) {
if ((*it)->shade(stroke) < 0) {
return -1;
}
}
return 0;
}
int Operators::create(UnaryPredicate1D& pred, vector<StrokeShader*> shaders)
{
//Canvas* canvas = Canvas::getInstance();
if (!_current_set) {
cerr << "Warning: current set empty" << endl;
return 0;
}
StrokesContainer new_strokes_set;
for (Operators::I1DContainer::iterator it = _current_set->begin(); it != _current_set->end(); ++it) {
if (pred(**it) < 0)
goto error;
if (!pred.result)
continue;
Stroke *stroke = createStroke(**it);
if (stroke) {
if (applyShading(*stroke, shaders) < 0) {
delete stroke;
goto error;
}
//canvas->RenderStroke(stroke);
new_strokes_set.push_back(stroke);
}
}
for (StrokesContainer::iterator it = new_strokes_set.begin(); it != new_strokes_set.end(); ++it) {
_current_strokes_set.push_back(*it);
}
new_strokes_set.clear();
return 0;
error:
for (StrokesContainer::iterator it = new_strokes_set.begin(); it != new_strokes_set.end(); ++it) {
delete (*it);
}
new_strokes_set.clear();
return -1;
}
void Operators::reset()
{
ViewMap *vm = ViewMap::getInstance();
if (!vm) {
cerr << "Error: no ViewMap computed yet" << endl;
return;
}
_current_view_edges_set.clear();
for (I1DContainer::iterator it = _current_chains_set.begin(); it != _current_chains_set.end(); ++it)
delete *it;
_current_chains_set.clear();
#if 0
_current_view_edges_set.insert(_current_view_edges_set.begin(),
vm->ViewEdges().begin(),
vm->ViewEdges().end());
#else
ViewMap::viewedges_container& vedges = vm->ViewEdges();
ViewMap::viewedges_container::iterator ve = vedges.begin(), veend = vedges.end();
for (; ve != veend; ++ve) {
if ((*ve)->getLength2D() < M_EPSILON)
continue;
_current_view_edges_set.push_back(*ve);
}
#endif
_current_set = &_current_view_edges_set;
_current_strokes_set.clear();
}