#include "tgl.h"
#include "toonz/strokegenerator.h"
//#include "tofflinegl.h"
#include "tstroke.h"
using namespace std;
//-------------------------------------------------------------------
void StrokeGenerator::clear()
{
m_points.clear();
m_modifiedRegion = TRectD();
m_paintedPointCount = 0;
m_p0 = m_p1 = TPointD();
}
//-------------------------------------------------------------------
bool StrokeGenerator::isEmpty() const
{
return m_points.empty();
}
//-------------------------------------------------------------------
void StrokeGenerator::add(const TThickPoint &point, double pixelSize2)
{
if (m_points.empty()) {
double x = point.x, y = point.y, d = point.thick + 3;
m_points.push_back(point);
TRectD rect(x - d, y - d, x + d, y + d);
m_modifiedRegion = rect;
m_lastModifiedRegion = rect;
m_p0 = m_p1 = point;
} else {
TThickPoint lastPoint = m_points.back();
if (tdistance2(lastPoint, point) >= 4 * pixelSize2) {
m_points.push_back(point);
double d = std::max(point.thick, lastPoint.thick) + 3;
TRectD rect(TRectD(lastPoint, point).enlarge(d));
m_modifiedRegion += rect;
m_lastModifiedRegion += rect;
} else {
m_points.back().thick = std::max(m_points.back().thick, point.thick);
}
}
}
//-------------------------------------------------------------------
void StrokeGenerator::filterPoints()
{
if (m_points.size() < 10)
return;
// filtra m_points iniziali: generalmente elevate variazioni di thickness
// si hanno tra m_points[0] (al massimo m_points[1]) e i successivi)
int size1 = m_points.size();
int kMin = 0;
int kMax = std::min(4, size1 - 2); // confronta 5 m_points iniziali con i successivi corrispondenti
int k = kMax;
for (k = kMax; k >= kMin; --k) {
TThickPoint currPoint = m_points[k];
TThickPoint nextPoint = m_points[k + 1];
double dist = tdistance(currPoint, nextPoint);
double deltaThick = fabs(currPoint.thick - nextPoint.thick);
if (deltaThick > 0.6 * dist) // deltaThick <= dist (condizione approssimata di non-autocontenimento per TTQ)
{
vector<TThickPoint>::iterator it1 = m_points.begin();
vector<TThickPoint>::iterator it2 = it1 + k + 1;
m_points.erase(it1, it2); // cancella da m_points[0] a m_points[k]
assert((int)m_points.size() == size1 - k - 1);
break;
}
}
// filtra m_points finali: generalmente elevate variazioni di thickness
// si hanno tra m_points[size - 1] (al massimo m_points[size - 2]) e i predecessori)
int size2 = m_points.size();
kMax = size2 - 1;
kMin = std::max(kMax - 4, 1); // confronta 5 m_points finali con i predecessori corrispondenti
k = kMin;
for (k = kMin; k <= kMax; ++k) {
TThickPoint currPoint = m_points[k];
TThickPoint prevPoint = m_points[k - 1];
double dist = tdistance(currPoint, prevPoint);
double deltaThick = fabs(currPoint.thick - prevPoint.thick);
if (deltaThick > 0.6 * dist) // deltaThick <= dist (condizione approssimata di non-autocontenimento per TTQ)
{
int kTmp = k;
while (k <= kMax) // cancella da m_points[k] a m_points[size2 - 1]
{
m_points.pop_back();
++k;
}
assert((int)m_points.size() == size2 - (kMax - kTmp + 1));
break;
}
}
}
//-------------------------------------------------------------------
void StrokeGenerator::drawFragments(int first, int last)
{
if (m_points.empty())
return;
int i = first;
if (last >= (int)m_points.size())
last = m_points.size() - 1;
const double h = 0.01;
TThickPoint a;
TThickPoint b;
TThickPoint c;
TPointD v;
while (i < last) {
a = m_points[i - 1];
b = m_points[i];
c = m_points[i + 1];
if (a.thick >= h && b.thick >= h && tdistance2(b, a) >= h && tdistance2(a, c) >= h) {
if (i - 1 == 0) {
assert(tdistance(b, a) > h);
v = a.thick * normalize(rotate90(b - a));
m_p0 = a + v;
m_p1 = a - v;
}
assert(tdistance(c, a) > h);
v = b.thick * normalize(rotate90(c - a));
TPointD p0 = b + v;
TPointD p1 = b - v;
glBegin(GL_POLYGON);
tglVertex(m_p0);
tglVertex(m_p1);
tglVertex(p1);
tglVertex(p0);
glEnd();
m_p0 = p0;
m_p1 = p1;
} else {
m_p0 = m_p1 = b;
}
glBegin(GL_LINE_STRIP);
tglVertex(a);
tglVertex(b);
glEnd();
i++;
}
}
//-------------------------------------------------------------------
void StrokeGenerator::drawLastFragments()
{
if (m_points.empty())
return;
int n = m_points.size();
int i = m_paintedPointCount;
const double h = 0.01;
if (i == 0) {
TThickPoint a = m_points[0];
if (a.thick >= h)
tglDrawDisk(a, a.thick);
i++;
}
drawFragments(i, n - 1);
m_paintedPointCount = std::max(0, n - 2);
}
//-------------------------------------------------------------------
void StrokeGenerator::drawAllFragments()
{
if (m_points.empty())
return;
int n = m_points.size();
int i = 0;
const double h = 0.01;
TThickPoint a = m_points[0];
if (a.thick >= h)
tglDrawDisk(a, a.thick);
drawFragments(1, n - 1);
/*
//last fragment
TPointD p0 = c+v;
TPointD p1 = c-v;
glBegin(GL_POLYGON);
tglVertex(m_p0);
tglVertex(m_p1);
tglVertex(p1);
tglVertex(p0);
glEnd();
*/
a = m_points.back();
if (a.thick >= h)
tglDrawDisk(a, a.thick);
}
//-------------------------------------------------------------------
TRectD StrokeGenerator::getModifiedRegion() const { return m_modifiedRegion; }
//-------------------------------------------------------------------
TRectD StrokeGenerator::getLastModifiedRegion()
{
TRectD lastModifiedRegion = m_lastModifiedRegion;
m_lastModifiedRegion.empty();
return lastModifiedRegion;
}
//-------------------------------------------------------------------
TStroke *StrokeGenerator::makeStroke(double error, UINT onlyLastPoints) const
{
if (onlyLastPoints == 0 || onlyLastPoints > m_points.size())
return TStroke::interpolate(m_points, error);
vector<TThickPoint> lastPoints(onlyLastPoints);
vector<TThickPoint>::const_iterator first = m_points.begin() + (m_points.size() - onlyLastPoints);
copy(first, m_points.end(), lastPoints.begin());
return TStroke::interpolate(lastPoints, error);
}
//-------------------------------------------------------------------