| |
| |
|
|
| #include "tcenterlinevectP.h" |
| |
| |
| #include "toonz/tcenterlinevectorizer.h" |
| #include "toonz/Naa2TlvConverter.h" |
| |
| |
| #include "tpalette.h" |
| #include "tcolorstyles.h" |
| #include "trastercm.h" |
| #include "ttoonzimage.h" |
| #include "trasterimage.h" |
| #include "tvectorimage.h" |
| #include "tgeometry.h" |
| #include "tstroke.h" |
| #include "tropcm.h" |
| |
| |
| #include <vector> |
| #include <list> |
| #include <queue> |
| #include <map> |
| #include <functional> |
| #include <algorithm> |
| #include <math.h> |
| #include <assert.h> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| inline void reduceThickness(TVectorImageP image, double thicknessRatio) |
| { |
| thicknessRatio *= 0.01; |
| |
| unsigned int i; |
| int j; |
| for (i = 0; i < image->getStrokeCount(); ++i) { |
| for (j = 0; j < image->getStroke(i)->getControlPointCount(); ++j) { |
| TThickPoint newCP = image->getStroke(i)->getControlPoint(j); |
| newCP.thick *= thicknessRatio; |
| image->getStroke(i)->setControlPoint(j, newCP); |
| } |
| } |
| } |
| |
| |
| |
| |
| inline void deleteSkeletonList(SkeletonList *skeleton) |
| { |
| unsigned int i; |
| for (i = 0; i < skeleton->size(); ++i) |
| delete (*skeleton)[i]; |
| |
| delete skeleton; |
| } |
| |
| |
| |
| TVectorImageP copyStrokes(std::vector<TStroke *> &strokes) |
| { |
| unsigned int i; |
| TVectorImageP result = new TVectorImage; |
| |
| for (i = 0; i < strokes.size(); ++i) |
| if (strokes[i]->getStyle() >= 0) |
| result->addStroke(strokes[i]); |
| |
| return result; |
| } |
| |
| |
| |
| inline TThickPoint randomized(const TThickPoint &P) |
| { |
| TThickPoint Q = P; |
| |
| Q.x += ((((double)rand()) / RAND_MAX) - 0.5) * 0.1; |
| Q.y += ((((double)rand()) / RAND_MAX) - 0.5) * 0.1; |
| |
| return Q; |
| } |
| |
| |
| |
| |
| void randomizeExtremities(TVectorImageP vi) |
| { |
| unsigned int i; |
| for (i = 0; i < vi->getStrokeCount(); ++i) { |
| TThickPoint P = vi->getStroke(i)->getControlPoint(0); |
| vi->getStroke(i)->setControlPoint(0, randomized(P)); |
| int n = vi->getStroke(i)->getControlPointCount(); |
| P = vi->getStroke(i)->getControlPoint(n - 1); |
| vi->getStroke(i)->setControlPoint(n - 1, randomized(P)); |
| } |
| } |
| |
| |
| |
| |
| inline void addFrameStrokes(TVectorImageP vi, TRasterP ras, TPalette *palette) |
| { |
| const double epsThick = 1.0; |
| TStroke *frameStroke; |
| std::vector<TThickPoint> CPs; |
| |
| CPs.push_back(TThickPoint(0, 0, epsThick)); |
| CPs.push_back(TThickPoint(ras->getLx() / 2.0, 0, epsThick)); |
| CPs.push_back(TThickPoint(ras->getLx(), 0, epsThick)); |
| CPs.push_back(TThickPoint(ras->getLx(), 0, epsThick)); |
| CPs.push_back(TThickPoint(ras->getLx(), 0, epsThick)); |
| CPs.push_back(TThickPoint(ras->getLx(), ras->getLy() / 2.0, epsThick)); |
| CPs.push_back(TThickPoint(ras->getLx(), ras->getLy(), epsThick)); |
| CPs.push_back(TThickPoint(ras->getLx(), ras->getLy(), epsThick)); |
| CPs.push_back(TThickPoint(ras->getLx(), ras->getLy(), epsThick)); |
| CPs.push_back(TThickPoint(ras->getLx() / 2.0, ras->getLy(), epsThick)); |
| CPs.push_back(TThickPoint(0, ras->getLy(), epsThick)); |
| CPs.push_back(TThickPoint(0, ras->getLy(), epsThick)); |
| CPs.push_back(TThickPoint(0, ras->getLy(), epsThick)); |
| CPs.push_back(TThickPoint(0, ras->getLy() / 2.0, epsThick)); |
| CPs.push_back(TThickPoint(0, 0, epsThick)); |
| |
| frameStroke = new TStroke(CPs); |
| frameStroke->setStyle(0); |
| frameStroke->setSelfLoop(true); |
| vi->addStroke(frameStroke); |
| } |
| |
| |
| |
| |
| bool VectorizerCore::isInkRegionEdge(TStroke *stroke) |
| { |
| return stroke->getFlag(SkeletonArc::SS_OUTLINE); |
| } |
| |
| |
| bool VectorizerCore::isInkRegionEdgeReversed(TStroke *stroke) |
| { |
| return stroke->getFlag(SkeletonArc::SS_OUTLINE_REVERSED); |
| } |
| |
| void VectorizerCore::clearInkRegionFlags(TVectorImageP vi) |
| { |
| int flag = SkeletonArc::SS_OUTLINE | SkeletonArc::SS_OUTLINE_REVERSED; |
| for (int i = 0; i < (int)vi->getStrokeCount(); i++) |
| vi->getStroke(i)->setFlag(flag, false); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| TVectorImageP VectorizerCore::centerlineVectorize( |
| TImageP &image, const CenterlineConfiguration &configuration, TPalette *palette) |
| { |
| TRasterImageP ri = image; |
| TToonzImageP ti = image; |
| |
| TRasterP ras; |
| if (ri) |
| ras = ri->getRaster(); |
| else { |
| ras = ti->getRaster()->clone(); |
| TRop::expandPaint(ras); |
| } |
| |
| if (configuration.m_naaSource) { |
| if (TRaster32P ras32 = ras) { |
| Naa2TlvConverter converter; |
| |
| converter.process(ras32); |
| converter.setPalette(palette); |
| |
| if (ti = converter.makeTlv(true)) |
| { |
| image = ti; |
| ras = ti->getRaster(); |
| |
| TRop::expandPaint(ras); |
| } |
| } |
| } |
| |
| VectorizerCoreGlobals globals; |
| globals.currConfig = &configuration; |
| |
| Contours polygons; |
| polygonize(ras, polygons, globals); |
| |
| |
| SkeletonList *skeletons = skeletonize(polygons, this, globals); |
| |
| if (isCanceled()) { |
| |
| deleteSkeletonList(skeletons); |
| |
| return TVectorImageP(); |
| } |
| |
| organizeGraphs(skeletons, globals); |
| |
| |
| |
| std::vector<TStroke *> sortibleResult; |
| TVectorImageP result; |
| |
| calculateSequenceColors(ras, globals); |
| conversionToStrokes(sortibleResult, globals); |
| applyStrokeColors(sortibleResult, ras, palette, globals); |
| result = copyStrokes(sortibleResult); |
| |
| |
| if (globals.currConfig->m_thicknessRatio < 100) |
| reduceThickness(result, configuration.m_thicknessRatio); |
| if (globals.currConfig->m_maxThickness == 0.0) |
| for (unsigned int i = 0; i < result->getStrokeCount(); ++i) |
| result->getStroke(i)->setSelfLoop(true); |
| if (globals.currConfig->m_makeFrame) |
| addFrameStrokes(result, ras, palette); |
| |
| |
| deleteSkeletonList(skeletons); |
| |
| return result; |
| } |
| |