Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// The following contains classes and prototypes for most code of centerline
Shinya Kitaoka 120a6e
// vectorization.
Toshihiro Shimizu 890ddd
#include "tcenterlinevectP.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/tcenterlinevectorizer.h"
Toshihiro Shimizu 890ddd
#include "toonz/Naa2TlvConverter.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tpalette.h"
Toshihiro Shimizu 890ddd
#include "tcolorstyles.h"
Toshihiro Shimizu 890ddd
#include "trastercm.h"
Toshihiro Shimizu 890ddd
#include "ttoonzimage.h"
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "tgeometry.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "tropcm.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// STD includes
Toshihiro Shimizu 890ddd
#include <vector></vector>
Toshihiro Shimizu 890ddd
#include <list></list>
Toshihiro Shimizu 890ddd
#include <queue></queue>
Toshihiro Shimizu 890ddd
#include <map></map>
Toshihiro Shimizu 890ddd
#include <functional></functional>
Toshihiro Shimizu 890ddd
#include <algorithm></algorithm>
Toshihiro Shimizu 890ddd
#include <math.h></math.h>
Toshihiro Shimizu 890ddd
#include <assert.h></assert.h>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*********************************
Toshihiro Shimizu 890ddd
//*     Further miscellaneous     *
Toshihiro Shimizu 890ddd
//*********************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Reduces strokes of image by currConfig->m_reduceThicknessRatio/100
Shinya Kitaoka 120a6e
inline void reduceThickness(TVectorImageP image, double thicknessRatio) {
Shinya Kitaoka 120a6e
  thicknessRatio *= 0.01;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
  int j;
Shinya Kitaoka 120a6e
  for (i = 0; i < image->getStrokeCount(); ++i) {
Shinya Kitaoka 120a6e
    for (j = 0; j < image->getStroke(i)->getControlPointCount(); ++j) {
Shinya Kitaoka 120a6e
      TThickPoint newCP = image->getStroke(i)->getControlPoint(j);
Shinya Kitaoka 120a6e
      newCP.thick *= thicknessRatio;
Shinya Kitaoka 120a6e
      image->getStroke(i)->setControlPoint(j, newCP);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Delete Skeleton graphs and list
Shinya Kitaoka 120a6e
inline void deleteSkeletonList(SkeletonList *skeleton) {
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < skeleton->size(); ++i) delete (*skeleton)[i];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  delete skeleton;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Campbell Barton b3bd84
static TVectorImageP copyStrokes(std::vector<tstroke *=""> &strokes) {</tstroke>
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
  TVectorImageP result = new TVectorImage;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (i = 0; i < strokes.size(); ++i)
Shinya Kitaoka 120a6e
    if (strokes[i]->getStyle() >= 0) result->addStroke(strokes[i]);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return result;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline TThickPoint randomized(const TThickPoint &P) {
Shinya Kitaoka 120a6e
  TThickPoint Q = P;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  Q.x += ((((double)rand()) / RAND_MAX) - 0.5) * 0.1;
Shinya Kitaoka 120a6e
  Q.y += ((((double)rand()) / RAND_MAX) - 0.5) * 0.1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return Q;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Give stroke extremities a random shake. May help for region computing.
Campbell Barton b3bd84
static void randomizeExtremities(TVectorImageP vi) {
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < vi->getStrokeCount(); ++i) {
Shinya Kitaoka 120a6e
    TThickPoint P = vi->getStroke(i)->getControlPoint(0);
Shinya Kitaoka 120a6e
    vi->getStroke(i)->setControlPoint(0, randomized(P));
Shinya Kitaoka 120a6e
    int n = vi->getStroke(i)->getControlPointCount();
Shinya Kitaoka 120a6e
    P     = vi->getStroke(i)->getControlPoint(n - 1);
Shinya Kitaoka 120a6e
    vi->getStroke(i)->setControlPoint(n - 1, randomized(P));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Looped frame
Shinya Kitaoka 120a6e
inline void addFrameStrokes(TVectorImageP vi, TRasterP ras, TPalette *palette) {
Shinya Kitaoka 120a6e
  const double epsThick = 1.0;
Shinya Kitaoka 120a6e
  TStroke *frameStroke;
Shinya Kitaoka 120a6e
  std::vector<tthickpoint> CPs;</tthickpoint>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  CPs.push_back(TThickPoint(0, 0, epsThick));
Shinya Kitaoka 120a6e
  CPs.push_back(TThickPoint(ras->getLx() / 2.0, 0, epsThick));
Shinya Kitaoka 120a6e
  CPs.push_back(TThickPoint(ras->getLx(), 0, epsThick));
Shinya Kitaoka 120a6e
  CPs.push_back(TThickPoint(ras->getLx(), 0, epsThick));
Shinya Kitaoka 120a6e
  CPs.push_back(TThickPoint(ras->getLx(), 0, epsThick));
Shinya Kitaoka 120a6e
  CPs.push_back(TThickPoint(ras->getLx(), ras->getLy() / 2.0, epsThick));
Shinya Kitaoka 120a6e
  CPs.push_back(TThickPoint(ras->getLx(), ras->getLy(), epsThick));
Shinya Kitaoka 120a6e
  CPs.push_back(TThickPoint(ras->getLx(), ras->getLy(), epsThick));
Shinya Kitaoka 120a6e
  CPs.push_back(TThickPoint(ras->getLx(), ras->getLy(), epsThick));
Shinya Kitaoka 120a6e
  CPs.push_back(TThickPoint(ras->getLx() / 2.0, ras->getLy(), epsThick));
Shinya Kitaoka 120a6e
  CPs.push_back(TThickPoint(0, ras->getLy(), epsThick));
Shinya Kitaoka 120a6e
  CPs.push_back(TThickPoint(0, ras->getLy(), epsThick));
Shinya Kitaoka 120a6e
  CPs.push_back(TThickPoint(0, ras->getLy(), epsThick));
Shinya Kitaoka 120a6e
  CPs.push_back(TThickPoint(0, ras->getLy() / 2.0, epsThick));
Shinya Kitaoka 120a6e
  CPs.push_back(TThickPoint(0, 0, epsThick));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  frameStroke = new TStroke(CPs);
Shinya Kitaoka 120a6e
  frameStroke->setStyle(0);
Shinya Kitaoka 120a6e
  frameStroke->setSelfLoop(true);
Shinya Kitaoka 120a6e
  vi->addStroke(frameStroke);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Returns if input stroke is edge boundary of an ink-filled region
Shinya Kitaoka 120a6e
bool VectorizerCore::isInkRegionEdge(TStroke *stroke) {
Shinya Kitaoka 120a6e
  return stroke->getFlag(SkeletonArc::SS_OUTLINE);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Similar as above
Shinya Kitaoka 120a6e
bool VectorizerCore::isInkRegionEdgeReversed(TStroke *stroke) {
Shinya Kitaoka 120a6e
  return stroke->getFlag(SkeletonArc::SS_OUTLINE_REVERSED);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void VectorizerCore::clearInkRegionFlags(TVectorImageP vi) {
Shinya Kitaoka 120a6e
  int flag = SkeletonArc::SS_OUTLINE | SkeletonArc::SS_OUTLINE_REVERSED;
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)vi->getStrokeCount(); i++)
Shinya Kitaoka 120a6e
    vi->getStroke(i)->setFlag(flag, false);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************
Toshihiro Shimizu 890ddd
//*    Vectorizer Main   *
Toshihiro Shimizu 890ddd
//************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TVectorImageP VectorizerCore::centerlineVectorize(
Shinya Kitaoka 120a6e
    TImageP &image, const CenterlineConfiguration &configuration,
Shinya Kitaoka 120a6e
    TPalette *palette) {
Shinya Kitaoka 120a6e
  TRasterImageP ri = image;
Shinya Kitaoka 120a6e
  TToonzImageP ti  = image;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterP ras;
Shinya Kitaoka 120a6e
  if (ri)
Shinya Kitaoka 120a6e
    ras = ri->getRaster();
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    ras = ti->getRaster()->clone();
Shinya Kitaoka 120a6e
    TRop::expandPaint(ras);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (configuration.m_naaSource) {
Shinya Kitaoka 120a6e
    if (TRaster32P ras32 = ras) {
Shinya Kitaoka 120a6e
      Naa2TlvConverter converter;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      converter.process(ras32);
Shinya Kitaoka 120a6e
      converter.setPalette(palette);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (ti = converter.makeTlv(true))  // Transparent synthetic inks
Shinya Kitaoka 120a6e
      {
Shinya Kitaoka 120a6e
        image = ti;
Shinya Kitaoka 120a6e
        ras   = ti->getRaster();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        TRop::expandPaint(ras);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  VectorizerCoreGlobals globals;
Shinya Kitaoka 120a6e
  globals.currConfig = &configuration;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  Contours polygons;
Shinya Kitaoka 120a6e
  polygonize(ras, polygons, globals);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Most time-consuming part of vectorization, 'this' is passed to inform of
Shinya Kitaoka 120a6e
  // partial progresses
Shinya Kitaoka 120a6e
  SkeletonList *skeletons = skeletonize(polygons, this, globals);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (isCanceled()) {
Shinya Kitaoka 120a6e
    // Clean and return 0 at cancel command
Shinya Kitaoka 120a6e
    deleteSkeletonList(skeletons);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    return TVectorImageP();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  organizeGraphs(skeletons, globals);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // junctionRecovery(polygons);   //Da' problemi per maxThickness
Shinya Kitaoka 120a6e
  // sarebbe da rendere compatibile
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<tstroke *=""> sortibleResult;</tstroke>
Shinya Kitaoka 120a6e
  TVectorImageP result;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  calculateSequenceColors(ras, globals);  // Extract stroke colors here
Shinya Kitaoka 120a6e
  conversionToStrokes(sortibleResult, globals);
Shinya Kitaoka 120a6e
  applyStrokeColors(sortibleResult, ras, palette,
Shinya Kitaoka 120a6e
                    globals);  // Strokes get sorted here
Shinya Kitaoka 120a6e
  result = copyStrokes(sortibleResult);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Further misc adjustments
Shinya Kitaoka 120a6e
  if (globals.currConfig->m_thicknessRatio < 100)
Shinya Kitaoka 120a6e
    reduceThickness(result, configuration.m_thicknessRatio);
Shinya Kitaoka 120a6e
  if (globals.currConfig->m_maxThickness == 0.0)
Shinya Kitaoka 120a6e
    for (unsigned int i = 0; i < result->getStrokeCount(); ++i)
Shinya Kitaoka 120a6e
      result->getStroke(i)->setSelfLoop(true);
Shinya Kitaoka 120a6e
  if (globals.currConfig->m_makeFrame) addFrameStrokes(result, ras, palette);
Shinya Kitaoka 120a6e
  // randomizeExtremities(result);   //Cuccio random - non serve...
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  deleteSkeletonList(skeletons);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return result;
Toshihiro Shimizu 890ddd
}