tahoma2d/toonz/sources/toonzlib/tcenterlinevectorizer.cpp
Campbell Barton b3bd842e04 Make functions static, ensure declarations match headers (#610)
This patch used -Wmissing-declarations warning
to show functions and symbols that had no declarations, and either:

- Make static
- Add to header

This helps avoid possability that declarations and functions get out of sync.
And ensures all source files reference headers correctly.

It also makes sure functions defined with extern "C",
have this defined in the header. An error found in calligraph.h while writing this patch.

This has been applied to toonzlib, to avoid making very large global changes.
If accepted, -Wmissing-declarations warning could be added to CMake.
2016-07-13 21:05:06 +09:00

232 lines
6.9 KiB
C++

// The following contains classes and prototypes for most code of centerline
// vectorization.
#include "tcenterlinevectP.h"
// TnzLib includes
#include "toonz/tcenterlinevectorizer.h"
#include "toonz/Naa2TlvConverter.h"
// TnzCore includes
#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"
// STD includes
#include <vector>
#include <list>
#include <queue>
#include <map>
#include <functional>
#include <algorithm>
#include <math.h>
#include <assert.h>
//==========================================================================
//*********************************
//* Further miscellaneous *
//*********************************
//--------------------------------------------------------------------------
// Reduces strokes of image by currConfig->m_reduceThicknessRatio/100
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);
}
}
}
//========================================================================
// Delete Skeleton graphs and list
inline void deleteSkeletonList(SkeletonList *skeleton) {
unsigned int i;
for (i = 0; i < skeleton->size(); ++i) delete (*skeleton)[i];
delete skeleton;
}
//========================================================================
static 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;
}
//------------------------------------------------------------------------
// Give stroke extremities a random shake. May help for region computing.
static 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));
}
}
//========================================================================
// Looped frame
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);
}
//========================================================================
// Returns if input stroke is edge boundary of an ink-filled region
bool VectorizerCore::isInkRegionEdge(TStroke *stroke) {
return stroke->getFlag(SkeletonArc::SS_OUTLINE);
}
// Similar as above
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);
}
//==========================================================================
//************************
//* Vectorizer Main *
//************************
//--------------------------------------------------------------------------
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)) // Transparent synthetic inks
{
image = ti;
ras = ti->getRaster();
TRop::expandPaint(ras);
}
}
}
VectorizerCoreGlobals globals;
globals.currConfig = &configuration;
Contours polygons;
polygonize(ras, polygons, globals);
// Most time-consuming part of vectorization, 'this' is passed to inform of
// partial progresses
SkeletonList *skeletons = skeletonize(polygons, this, globals);
if (isCanceled()) {
// Clean and return 0 at cancel command
deleteSkeletonList(skeletons);
return TVectorImageP();
}
organizeGraphs(skeletons, globals);
// junctionRecovery(polygons); //Da' problemi per maxThickness<inf...
// sarebbe da rendere compatibile
std::vector<TStroke *> sortibleResult;
TVectorImageP result;
calculateSequenceColors(ras, globals); // Extract stroke colors here
conversionToStrokes(sortibleResult, globals);
applyStrokeColors(sortibleResult, ras, palette,
globals); // Strokes get sorted here
result = copyStrokes(sortibleResult);
// Further misc adjustments
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);
// randomizeExtremities(result); //Cuccio random - non serve...
deleteSkeletonList(skeletons);
return result;
}