| |
| |
| #include "tgl.h" |
| #include "toonz/strokegenerator.h" |
| |
| |
| #include "tstroke.h" |
| #include "toonz/preferences.h" |
| |
| using namespace std; |
| |
| |
| |
| void StrokeGenerator::clear() { |
| m_points.clear(); |
| m_modifiedRegion = TRectD(); |
| m_lastPointRect.empty(); |
| m_lastModifiedRegion.empty(); |
| 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_lastPointRect = 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; |
| m_lastPointRect = rect; |
| } else { |
| m_points.back().thick = std::max(m_points.back().thick, point.thick); |
| } |
| } |
| } |
| |
| |
| |
| void StrokeGenerator::filterPoints() { |
| if (m_points.size() < 10) return; |
| |
| |
| |
| int size1 = m_points.size(); |
| int kMin = 0; |
| int kMax = std::min( |
| 4, |
| size1 - |
| 2); |
| 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) |
| |
| |
| { |
| vector<TThickPoint>::iterator it1 = m_points.begin(); |
| vector<TThickPoint>::iterator it2 = it1 + k + 1; |
| m_points.erase(it1, it2); |
| assert((int)m_points.size() == size1 - k - 1); |
| break; |
| } |
| } |
| |
| |
| |
| int size2 = m_points.size(); |
| kMax = size2 - 1; |
| kMin = std::max( |
| kMax - 4, |
| 1); |
| 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) |
| |
| |
| { |
| int kTmp = k; |
| while (k <= kMax) |
| { |
| 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; |
| TThickPoint a; |
| TThickPoint b; |
| TThickPoint c; |
| TPointD v; |
| |
| |
| if (m_points.size() == 2) { |
| a = m_points[0]; |
| b = m_points[1]; |
| if (Preferences::instance()->getShow0ThickLines()) { |
| if (a.thick == 0) a.thick = 0.1; |
| if (b.thick == 0) b.thick = 0.1; |
| } |
| |
| v = a.thick * normalize(rotate90(b - a)); |
| m_p0 = a + v; |
| m_p1 = a - v; |
| v = b.thick * normalize(rotate90(b - 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; |
| glBegin(GL_LINE_STRIP); |
| tglVertex(a); |
| tglVertex(b); |
| glEnd(); |
| return; |
| } |
| |
| while (i < last) { |
| a = m_points[i - 1]; |
| b = m_points[i]; |
| c = m_points[i + 1]; |
| if (Preferences::instance()->getShow0ThickLines()) { |
| if (a.thick == 0) a.thick = 0.1; |
| if (b.thick == 0) b.thick = 0.1; |
| if (c.thick == 0) c.thick = 0.1; |
| } |
| if (i - 1 == 0) { |
| v = a.thick * normalize(rotate90(b - a)); |
| m_p0 = a + v; |
| m_p1 = a - v; |
| } |
| 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; |
| |
| glBegin(GL_LINE_STRIP); |
| tglVertex(a); |
| tglVertex(b); |
| glEnd(); |
| i++; |
| } |
| if (last < 2) return; |
| v = m_points[last].thick * |
| normalize(rotate90(m_points[last] - m_points[last - 1])); |
| TPointD p0 = m_points[last] + v; |
| TPointD p1 = m_points[last] - v; |
| glBegin(GL_POLYGON); |
| tglVertex(m_p0); |
| tglVertex(m_p1); |
| tglVertex(p1); |
| tglVertex(p0); |
| glEnd(); |
| glBegin(GL_LINE_STRIP); |
| tglVertex(m_points[last - 1]); |
| tglVertex(m_points[last]); |
| glEnd(); |
| } |
| |
| |
| |
| 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); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| a = m_points.back(); |
| if (a.thick >= h) tglDrawDisk(a, a.thick); |
| } |
| |
| |
| |
| TRectD StrokeGenerator::getModifiedRegion() const { return m_modifiedRegion; } |
| |
| |
| |
| void StrokeGenerator::removeMiddlePoints() { |
| int size = m_points.size(); |
| if (size > 2) { |
| m_points.erase(m_points.begin() + 1, m_points.begin() + (size - 1)); |
| } |
| } |
| |
| |
| |
| TRectD StrokeGenerator::getLastModifiedRegion() { |
| TRectD ret = m_lastModifiedRegion; |
| m_lastModifiedRegion = m_lastPointRect; |
| return ret; |
| } |
| |
| |
| |
| TPointD StrokeGenerator::getFirstPoint() { return m_points[0]; } |
| |
| |
| |
| 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); |
| } |
| |
| |
| |