Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tcenterlinevectP.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// tcg includes
Toshihiro Shimizu 890ddd
#include "tcg/tcg_numeric_ops.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Boost includes
Toshihiro Shimizu 890ddd
#include <boost container="" flat_map.hpp=""></boost>
Toshihiro Shimizu 890ddd
#include <boost algorithm="" minmax_element.hpp=""></boost>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace boost_c = boost::container;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*************************
Toshihiro Shimizu 890ddd
//*    Colors handling    *
Toshihiro Shimizu 890ddd
//*************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Riassunto: Nel caso di normali raster, i tratti di penna sono colorati con
Shinya Kitaoka 120a6e
// l'elemento della palette data maggiormente tendente al nero.
Shinya Kitaoka 120a6e
// Per le Toonz colormap abilitiamo una gestione piu' complessa, che tiene
Shinya Kitaoka 120a6e
// conto del colore dell'inchiostro specificato direttamente nell'immagine.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Nello specifico:
Toshihiro Shimizu 890ddd
//  a) I tratti di penna vengono rilevati in base al valore del campo *tone*
Toshihiro Shimizu 890ddd
//     di un TPixleCM32, non in base alla luminosita' del colore.
Toshihiro Shimizu 890ddd
//     (vv. Poligonizzazione)
Toshihiro Shimizu 890ddd
//  b) Sulle centerline grezze viene costruito un insieme di 'punti di assaggio'
Toshihiro Shimizu 890ddd
//     dell'immagine; gli id di inchiostro rilevati vengono assegnati
Toshihiro Shimizu 890ddd
//     direttamente alla stroke: se si verifica un cambio nell'id del colore,
Toshihiro Shimizu 890ddd
//     il punto di cambio del colore viene identificato e la centerline viene
Toshihiro Shimizu 890ddd
//     spezzata li'.
Toshihiro Shimizu 890ddd
//  c) Una volta identificati i colori delle stroke, le si ordina *prima*
Shinya Kitaoka 120a6e
//     di inserirle nella vector image di output, in base al colore
Shinya Kitaoka 120a6e
//     dell'immagine
Toshihiro Shimizu 890ddd
//     ai loro estremi (attualmente ordinamento solo parziale).
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TPixelCM32 pixel(const TRasterCM32 &ras, int x, int y) {
Shinya Kitaoka 120a6e
  // Seems that raster access was not very much double-checked at the time
Shinya Kitaoka 120a6e
  // I wrote this. Too bad. Enforcing it now.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return ras.pixels(tcrop(y, 0, ras.getLy() - 1))[tcrop(x, 0, ras.getLx() - 1)];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
T3DPointD firstInkChangePosition(const TRasterCM32P &ras,
Shinya Kitaoka 120a6e
                                 const T3DPointD &start, const T3DPointD &end,
Shinya Kitaoka 120a6e
                                 int threshold) {
Shinya Kitaoka 120a6e
  double dist = norm(end - start);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int sampleMax = tceil(dist), sampleCount = sampleMax + 1;
Shinya Kitaoka 120a6e
  double sampleMaxD = double(sampleMax);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Get first ink color
Shinya Kitaoka 120a6e
  int s, color = -1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (s = 0; s != sampleCount; ++s) {
Shinya Kitaoka 120a6e
    T3DPointD p           = tcg::numeric_ops::lerp(start, end, s / sampleMaxD);
Shinya Kitaoka 120a6e
    const TPixelCM32 &pix = pixel(*ras, p.x, p.y);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (pix.getTone() < threshold) {
Shinya Kitaoka 120a6e
      color = pix.getInk();
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Get second color
Shinya Kitaoka 120a6e
  for (; s != sampleCount; ++s) {
Shinya Kitaoka 120a6e
    T3DPointD p           = tcg::numeric_ops::lerp(start, end, s / sampleMaxD);
Shinya Kitaoka 120a6e
    const TPixelCM32 &pix = pixel(*ras, p.x, p.y);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (pix.getTone() < threshold && pix.getInk() != color) break;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Return middle position between s-1 and s
Shinya Kitaoka 120a6e
  if (s < sampleCount)
Shinya Kitaoka 120a6e
    return tcg::numeric_ops::lerp(start, end, (s - 0.5) / sampleMaxD);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return TConsts::nap3d;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Find color of input sequence. Will be copied to its equivalent stroke.
Shinya Kitaoka 120a6e
// Currently in use only on colormaps
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
// Riassunto: Per saggiare il colore da assegnare alle strokes e' meglio
Shinya Kitaoka 120a6e
// controllare
Shinya Kitaoka 120a6e
// le sequenze *prima* di convertirle in TStroke (visto che si perde parte
Shinya Kitaoka 120a6e
// dell'aderenza originale
Shinya Kitaoka 120a6e
// al tratto). Si specifica un numero di 'punti di assaggio' della spezzata
Shinya Kitaoka 120a6e
// equidistanti tra loro,
Shinya Kitaoka 120a6e
// su cui viene prelevato il valore dell'ink del pixel corrispondente. Se si
Shinya Kitaoka 120a6e
// identifica un cambio
Shinya Kitaoka 120a6e
// di colore, viene lanciata la procedura di spezzamento della sequenza: si
Shinya Kitaoka 120a6e
// identifica il punto
Shinya Kitaoka 120a6e
// di spezzamento, e la sequenza s viene bloccata li'; si costruisce una nuova
Shinya Kitaoka 120a6e
// sequenza newSeq e
Shinya Kitaoka 120a6e
// viene rilanciata sampleColor(ras,newSeq,sOpposite). Le sequenze tra due punti
Shinya Kitaoka 120a6e
// di spezzamento
Shinya Kitaoka 120a6e
// vengono inserite nel vector 'globals->singleSequences'.
Shinya Kitaoka 120a6e
// Nel caso di sequenze circolari c'e' una piccola modifica: il primo punto di
Shinya Kitaoka 120a6e
// spezzamento
Toshihiro Shimizu 890ddd
//*ridefinisce solo* il nodo-raccordo di s, senza introdurre nuove sequenze.
Shinya Kitaoka 120a6e
// La sequenza sOpposite, 'inversa' di s, rimane e diventa 'forward-oriented'
Shinya Kitaoka 120a6e
// previo aggiornamento
Shinya Kitaoka 120a6e
// della coda.
Shinya Kitaoka 120a6e
// Osservare che i nodi di spezzamento vengono inseriti con la signature
Shinya Kitaoka 120a6e
// 'SAMPLECOLOR_SIGN'.
Shinya Kitaoka 120a6e
// NOTA: La struttura a grafo J-S 'superiore' non viene alterata qui dentro.
Shinya Kitaoka 120a6e
// Eventualm. da fare fuori.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void sampleColor(const TRasterCM32P &ras, int threshold, Sequence &seq,
Shinya Kitaoka 120a6e
                 Sequence &seqOpposite, SequenceList &singleSequences) {
Shinya Kitaoka 120a6e
  SkeletonGraph *currGraph = seq.m_graphHolder;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Calculate sequence parametrization
Shinya Kitaoka 120a6e
  std::vector<unsigned int=""> nodes;</unsigned>
Shinya Kitaoka 120a6e
  std::vector<double> params;</double>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Meanwhile, ensure each point belong to ras. Otherwise, typically an error
Shinya Kitaoka 120a6e
  // occured
Shinya Kitaoka 120a6e
  // in the thinning process and it's better avoid sampling procedure. Only
Shinya Kitaoka 120a6e
  // exception, when
Shinya Kitaoka 120a6e
  // a point has x==ras->getLx() || y==ras->getLy(); that is accepted.
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    const T3DPointD &headPos = *currGraph->getNode(seq.m_head);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!ras->getBounds().contains(TPoint(headPos.x, headPos.y))) {
Shinya Kitaoka 120a6e
      if (headPos.x < 0 || ras->getLx() < headPos.x || headPos.y < 0 ||
Shinya Kitaoka 120a6e
          ras->getLy() < headPos.y)
Shinya Kitaoka 120a6e
        return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  unsigned int curr, currLink, next;
Shinya Kitaoka 120a6e
  double meanThickness = currGraph->getNode(seq.m_head)->z;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  params.push_back(0);
Shinya Kitaoka 120a6e
  nodes.push_back(seq.m_head);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (curr = seq.m_head, currLink = seq.m_headLink;
Shinya Kitaoka 120a6e
       curr != seq.m_tail || params.size() == 1; seq.next(curr, currLink)) {
Shinya Kitaoka 120a6e
    next = currGraph->getNode(curr).getLink(currLink).getNext();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    const T3DPointD &nextPos = *currGraph->getNode(next);
Shinya Kitaoka 120a6e
    if (!ras->getBounds().contains(TPoint(nextPos.x, nextPos.y))) {
Shinya Kitaoka 120a6e
      if (nextPos.x < 0 || ras->getLx() < nextPos.x || nextPos.y < 0 ||
Shinya Kitaoka 120a6e
          ras->getLy() < nextPos.y)
Shinya Kitaoka 120a6e
        return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    params.push_back(params.back() + tdistance(*currGraph->getNode(next),
Shinya Kitaoka 120a6e
                                               *currGraph->getNode(curr)));
Shinya Kitaoka 120a6e
    nodes.push_back(next);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    meanThickness += currGraph->getNode(next)->z;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  meanThickness /= params.size();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Exclude 0-length sequences
Shinya Kitaoka 120a6e
  if (params.back() < 0.01) {
Shinya Kitaoka 120a6e
    seq.m_color = pixel(*ras, currGraph->getNode(seq.m_head)->x,
Shinya Kitaoka 120a6e
                        currGraph->getNode(seq.m_head)->y)
Shinya Kitaoka 120a6e
                      .getInk();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Prepare sampling procedure
Shinya Kitaoka 120a6e
  int paramCount = params.size(), paramMax = paramCount - 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int sampleMax = std::max(params.back() / std::max(meanThickness, 1.0),
Shinya Kitaoka 120a6e
                           3.0),    // Number of color samples depends on
Shinya Kitaoka 120a6e
      sampleCount = sampleMax + 1;  // the ratio params.back() / meanThickness
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<double> sampleParams(sampleCount);  // Sampling lengths</double>
Shinya Kitaoka 120a6e
  std::vector<tpoint> samplePoints(</tpoint>
Shinya Kitaoka 120a6e
      sampleCount);  // Image points for color sampling
Shinya Kitaoka 120a6e
  std::vector<int> sampleSegments(</int>
Shinya Kitaoka 120a6e
      sampleCount);  // Sequence segment index for the above
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Sample colors
Shinya Kitaoka 120a6e
  for (int s = 0, j = 0; s != sampleCount; ++s) {
Shinya Kitaoka 120a6e
    double samplePar = params.back() * (s / double(sampleMax));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    while (j != paramMax &&
Shinya Kitaoka 120a6e
           params[j + 1] < samplePar)  // params[j] < samplePar <= params[j+1]
Shinya Kitaoka 120a6e
      ++j;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double t = (samplePar - params[j]) / (params[j + 1] - params[j]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    T3DPointD samplePoint(*currGraph->getNode(nodes[j]) * (1 - t) +
Shinya Kitaoka 120a6e
                          *currGraph->getNode(nodes[j + 1]) * t);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    sampleParams[s] = samplePar;
Shinya Kitaoka 120a6e
    samplePoints[s] = TPoint(
Shinya Kitaoka 120a6e
        std::min(samplePoint.x,
Shinya Kitaoka 120a6e
                 double(ras->getLx() - 1)),  // This deals with sample points at
Shinya Kitaoka 120a6e
        std::min(samplePoint.y,
Shinya Kitaoka 120a6e
                 double(ras->getLy() - 1)));  // the top/right raster border
Shinya Kitaoka 120a6e
    sampleSegments[s] = j;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // NOTE: Extremities of a sequence are considered unreliable: they typically
Shinya Kitaoka 120a6e
  // happen
Shinya Kitaoka 120a6e
  //       to be junction points shared between possibly different-colored
Shinya Kitaoka 120a6e
  //       strokes.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Find first and last extremity-free sampled points
Shinya Kitaoka 120a6e
  T3DPointD first(*currGraph->getNode(seq.m_head));
Shinya Kitaoka 120a6e
  T3DPointD last(*currGraph->getNode(seq.m_tail));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int i, k;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 1;
Shinya Kitaoka 120a6e
       params.back() * i / double(sampleMax) <= first.z && i < sampleCount; ++i)
Shinya Kitaoka 120a6e
    ;
Shinya Kitaoka 120a6e
  for (k = sampleMax - 1;
Shinya Kitaoka 120a6e
       params.back() * (sampleMax - k) / double(sampleMax) <= last.z && k >= 0;
Shinya Kitaoka 120a6e
       --k)
Shinya Kitaoka 120a6e
    ;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Give s the first sampled ink color found
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Initialize with a last-resort reasonable color - not just 0
Shinya Kitaoka 120a6e
  seq.m_color = seqOpposite.m_color =
Shinya Kitaoka 120a6e
      ras->pixels(samplePoints[0].y)[samplePoints[0].x].getInk();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int l;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (l = i - 1; l >= 0; --l) {
Shinya Kitaoka 120a6e
    if (ras->pixels(samplePoints[l].y)[samplePoints[l].x].getTone() <
Shinya Kitaoka 120a6e
        threshold) {
Shinya Kitaoka 120a6e
      seq.m_color = seqOpposite.m_color =
Shinya Kitaoka 120a6e
          ras->pixels(samplePoints[l].y)[samplePoints[l].x].getInk();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Then, look for the first reliable ink
Shinya Kitaoka 120a6e
  for (l = i; l <= k; ++l) {
Shinya Kitaoka 120a6e
    if (ras->pixels(samplePoints[l].y)[samplePoints[l].x].getTone() <
Shinya Kitaoka 120a6e
        threshold) {
Shinya Kitaoka 120a6e
      seq.m_color = seqOpposite.m_color =
Shinya Kitaoka 120a6e
          ras->pixels(samplePoints[l].y)[samplePoints[l].x].getInk();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (i >= k) goto _getOut;  // No admissible segment found for splitting
Shinya Kitaoka 120a6e
                             // check.
Shinya Kitaoka 120a6e
  // Find color changes between sampled colors
Shinya Kitaoka 120a6e
  for (l = i; l < k; ++l) {
Shinya Kitaoka 120a6e
    const TPixelCM32
Shinya Kitaoka 120a6e
        &nextSample = ras->pixels(samplePoints[l + 1].y)[samplePoints[l + 1].x],
Shinya Kitaoka 120a6e
        &nextSample2 = ras->pixels(
Shinya Kitaoka 120a6e
            samplePoints[l + 2]
Shinya Kitaoka 120a6e
                .y)[samplePoints[l + 2].x];  // l < k < sampleMax - so +2 is ok
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (nextSample.getTone() < threshold &&
Shinya Kitaoka 120a6e
        nextSample.getInk() != seq.m_color &&
Shinya Kitaoka 120a6e
        nextSample2.getTone() < threshold &&
Shinya Kitaoka 120a6e
        nextSample2.getInk() ==
Shinya Kitaoka 120a6e
            nextSample.getInk())  // Ignore single-sample color changes
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      // Found a color change - apply splitting procedure
Shinya Kitaoka 120a6e
      // NOTE: The function RETURNS BEFORE THE FOR IS CONTINUED!
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      int nextColor = nextSample.getInk();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Identify split segment
Shinya Kitaoka 120a6e
      int u;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      for (u = sampleSegments[l]; u < sampleSegments[l + 1]; ++u) {
Shinya Kitaoka 120a6e
        const TPixelCM32 &pix = pixel(*ras, currGraph->getNode(nodes[u + 1])->x,
Shinya Kitaoka 120a6e
                                      currGraph->getNode(nodes[u + 1])->y);
Shinya Kitaoka 120a6e
        if (pix.getTone() < threshold && pix.getInk() != seq.m_color) break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Now u indicates the splitting segment. Search for splitting point by
Shinya Kitaoka 120a6e
      // binary subdivision.
Shinya Kitaoka 120a6e
      const T3DPointD &nodeStartPos = *currGraph->getNode(nodes[u]),
Shinya Kitaoka 120a6e
                      &nodeEndPos   = *currGraph->getNode(nodes[u + 1]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      T3DPointD splitPoint =
Shinya Kitaoka 120a6e
          firstInkChangePosition(ras, nodeStartPos, nodeEndPos, threshold);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (splitPoint == TConsts::nap3d)
Shinya Kitaoka 120a6e
        splitPoint = 0.5 * (nodeStartPos +
Shinya Kitaoka 120a6e
                            nodeEndPos);  // A color change was found, but could
Shinya Kitaoka 120a6e
                                          // not be precisely located. Just take
Shinya Kitaoka 120a6e
                                          // a reasonable representant.
Shinya Kitaoka 120a6e
      // Insert a corresponding new node in basic graph structure.
Shinya Kitaoka 120a6e
      unsigned int splitNode = currGraph->newNode(splitPoint);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      unsigned int nodesLink =
Shinya Kitaoka 120a6e
          currGraph->getNode(nodes[u]).linkOfNode(nodes[u + 1]);
Shinya Kitaoka 120a6e
      currGraph->insert(splitNode, nodes[u], nodesLink);
Shinya Kitaoka 120a6e
      *currGraph->node(splitNode).link(0) =
Shinya Kitaoka 120a6e
          *currGraph->getNode(nodes[u]).getLink(nodesLink);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      nodesLink = currGraph->getNode(nodes[u + 1]).linkOfNode(nodes[u]);
Shinya Kitaoka 120a6e
      currGraph->insert(splitNode, nodes[u + 1], nodesLink);
Shinya Kitaoka 120a6e
      *currGraph->node(splitNode).link(1) =
Shinya Kitaoka 120a6e
          *currGraph->getNode(nodes[u + 1]).getLink(nodesLink);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      currGraph->node(splitNode).setAttribute(
Shinya Kitaoka 120a6e
          SAMPLECOLOR_SIGN);  // Sign all split-inserted nodes
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (seq.m_head == seq.m_tail &&
Shinya Kitaoka 120a6e
          currGraph->getNode(seq.m_head).getLinksCount() == 2 &&
Shinya Kitaoka 120a6e
          !currGraph->getNode(seq.m_head).hasAttribute(SAMPLECOLOR_SIGN)) {
Shinya Kitaoka 120a6e
        // Circular case: we update s to splitNode and relaunch this very
Shinya Kitaoka 120a6e
        // procedure on it.
Shinya Kitaoka 120a6e
        seq.m_head = seq.m_tail = splitNode;
Shinya Kitaoka 120a6e
        sampleColor(ras, threshold, seq, seqOpposite, singleSequences);
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        // Update upper (Joint-Sequence) graph data
Shinya Kitaoka 120a6e
        Sequence newSeq;
Shinya Kitaoka 120a6e
        newSeq.m_graphHolder = currGraph;
Shinya Kitaoka 120a6e
        newSeq.m_head        = splitNode;
Shinya Kitaoka 120a6e
        newSeq.m_headLink    = 0;
Shinya Kitaoka 120a6e
        newSeq.m_tail        = seq.m_tail;
Shinya Kitaoka 120a6e
        newSeq.m_tailLink    = seq.m_tailLink;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        seq.m_tail     = splitNode;
Shinya Kitaoka 120a6e
        seq.m_tailLink = 1;  // (link from splitNode to nodes[u] inserted for
Shinya Kitaoka 120a6e
                             // second by 'insert')
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        seqOpposite.m_graphHolder =
Shinya Kitaoka 120a6e
            seq.m_graphHolder;  // Inform that a split was found
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // NOTE: access on s terminates at newSeq's push_back, due to possible
Shinya Kitaoka 120a6e
        // reallocation of globals->singleSequences
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if ((!(seq.m_head == newSeq.m_tail &&
Shinya Kitaoka 120a6e
               currGraph->getNode(seq.m_head).getLinksCount() == 2)) &&
Shinya Kitaoka 120a6e
            currGraph->getNode(seq.m_head).hasAttribute(SAMPLECOLOR_SIGN))
Shinya Kitaoka 120a6e
          singleSequences.push_back(seq);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        sampleColor(ras, threshold, newSeq, seqOpposite, singleSequences);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
_getOut:
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Color changes not found (and therefore no newSeq got pushed back); if a
Shinya Kitaoka 120a6e
  // split happened, update sOpposite.
Shinya Kitaoka 120a6e
  if (currGraph->getNode(seq.m_head).hasAttribute(SAMPLECOLOR_SIGN)) {
Shinya Kitaoka 120a6e
    seqOpposite.m_color    = seq.m_color;
Shinya Kitaoka 120a6e
    seqOpposite.m_head     = seq.m_tail;
Shinya Kitaoka 120a6e
    seqOpposite.m_headLink = seq.m_tailLink;
Shinya Kitaoka 120a6e
    seqOpposite.m_tail     = seq.m_head;
Shinya Kitaoka 120a6e
    seqOpposite.m_tailLink = seq.m_headLink;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Take samples of image colors to associate each sequence to its corresponding
Shinya Kitaoka 120a6e
// palette color. Currently working on colormaps.
Shinya Kitaoka 120a6e
// void calculateSequenceColors(const TRasterP &ras)
Shinya Kitaoka 120a6e
void calculateSequenceColors(const TRasterP &ras, VectorizerCoreGlobals &g) {
Shinya Kitaoka 120a6e
  int threshold                           = g.currConfig->m_threshold;
Shinya Kitaoka 120a6e
  SequenceList &singleSequences           = g.singleSequences;
Shinya Kitaoka 120a6e
  JointSequenceGraphList &organizedGraphs = g.organizedGraphs;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterCM32P cm = ras;
Shinya Kitaoka 120a6e
  unsigned int i, j, k;
Shinya Kitaoka 120a6e
  int l;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (cm && g.currConfig->m_maxThickness > 0.0) {
Shinya Kitaoka 120a6e
    // singleSequence is traversed back-to-front because new, possibly splitted
Shinya Kitaoka 120a6e
    // sequences
Shinya Kitaoka 120a6e
    // are inserted at back - and don't have to be re-sampled.
Shinya Kitaoka 120a6e
    for (l = singleSequences.size() - 1; l >= 0; --l) {
Shinya Kitaoka 120a6e
      Sequence rear;
Shinya Kitaoka 120a6e
      sampleColor(ras, threshold, singleSequences[l], rear, singleSequences);
Shinya Kitaoka 120a6e
      // If rear is built, a split occurred and the rear of this
Shinya Kitaoka 120a6e
      // single sequence has to be pushed back.
Shinya Kitaoka 120a6e
      if (rear.m_graphHolder) singleSequences.push_back(rear);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = 0; i < organizedGraphs.size(); ++i)
Shinya Kitaoka 120a6e
      for (j = 0; j < organizedGraphs[i].getNodesCount(); ++j)
Shinya Kitaoka 120a6e
        if (!organizedGraphs[i].getNode(j).hasAttribute(
Shinya Kitaoka 120a6e
                JointSequenceGraph::ELIMINATED))  // due to junction recovery
Shinya Kitaoka 120a6e
          for (k = 0; k < organizedGraphs[i].getNode(j).getLinksCount(); ++k) {
Shinya Kitaoka 120a6e
            Sequence &s = *organizedGraphs[i].node(j).link(k);
Shinya Kitaoka 120a6e
            if (s.isForward() &&
Shinya Kitaoka 120a6e
                !s.m_graphHolder->getNode(s.m_tail).hasAttribute(
Shinya Kitaoka 120a6e
                    SAMPLECOLOR_SIGN)) {
Shinya Kitaoka 120a6e
              unsigned int next = organizedGraphs[i].node(j).link(k).getNext();
Shinya Kitaoka 120a6e
              unsigned int nextLink = organizedGraphs[i].tailLinkOf(j, k);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
              Sequence &sOpposite =
Shinya Kitaoka 120a6e
                  *organizedGraphs[i].node(next).link(nextLink);
Shinya Kitaoka 120a6e
              sampleColor(cm, threshold, s, sOpposite, singleSequences);
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline void applyStrokeIndices(VectorizerCoreGlobals *globals) {
Shinya Kitaoka 120a6e
  unsigned int i, j, k, n;
Shinya Kitaoka 120a6e
  unsigned int next, nextLink;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i < globals->singleSequences.size(); ++i)
Shinya Kitaoka 120a6e
    globals->singleSequences[i].m_strokeIndex = i;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  n = i;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i < globals->organizedGraphs.size(); ++i) {
Shinya Kitaoka 120a6e
    JointSequenceGraph *currJSGraph = &globals->organizedGraphs[i];
Shinya Kitaoka 120a6e
    for (j = 0; j < currJSGraph->getNodesCount(); ++j)
Shinya Kitaoka 120a6e
      if (!currJSGraph->getNode(j).hasAttribute(JointSequenceGraph::ELIMINATED))
Shinya Kitaoka 120a6e
        for (k = 0; k < currJSGraph->getNode(j).getLinksCount(); ++k) {
Shinya Kitaoka 120a6e
          Sequence &s = *currJSGraph->node(j).link(k);
Shinya Kitaoka 120a6e
          if (s.isForward()) {
Shinya Kitaoka 120a6e
            s.m_strokeIndex = n;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
            if (!s.m_graphHolder->getNode(s.m_tail).hasAttribute(
Shinya Kitaoka 120a6e
                    SAMPLECOLOR_SIGN)) {
Shinya Kitaoka 120a6e
              next     = currJSGraph->getNode(j).getLink(k).getNext();
Shinya Kitaoka 120a6e
              nextLink = currJSGraph->tailLinkOf(j, k);
Shinya Kitaoka 120a6e
              currJSGraph->node(next).link(nextLink)->m_strokeIndex = n;
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
            ++n;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Riassunto: Dato un grafo superiore, possiamo associare ad ogni nodo il colore
Shinya Kitaoka 120a6e
// del pixel associato a quel punto; se una sequenza e' nascosta, ha entrambi
Toshihiro Shimizu 890ddd
// i nodi agli estremi di colore diverso, viceversa per sequenze esposte.
Shinya Kitaoka 120a6e
// Data una sequenza, a partire dai nodi superiori adiacenti possiamo stabilire
Shinya Kitaoka 120a6e
// un
Shinya Kitaoka 120a6e
// insieme di sequenze che gli stanno sotto, ed uno di seq. che gli stanno
Shinya Kitaoka 120a6e
// sopra.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
// NOTA: Questo problema e' un caso particolare di 'graph labeling', di cui non
Shinya Kitaoka 120a6e
// ho ancora trovato soluzione. In rete qualcosa si trova...
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
// La seguente funzione fa qualcosa di piu' debole: ad ogni joint ed ogni
Shinya Kitaoka 120a6e
// Sequence
Shinya Kitaoka 120a6e
// viene assegnata una altezza (intero). Dato un Joint, le sequenze che lo hanno
Shinya Kitaoka 120a6e
// per estremo e che hanno lo stesso colore dell'immagine in quella posizione
Shinya Kitaoka 120a6e
// hanno
Shinya Kitaoka 120a6e
// un'altezza +1 rispetto al giunto, e viceversa altezza -1. Partendo da
Shinya Kitaoka 120a6e
// un giunto iniziale, quest'informazione viene propagata sul grafo; il problema
Shinya Kitaoka 120a6e
// sta ritornando ai giunti gia' percorsi...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Find predominant ink color in a circle of given radius and center
Shinya Kitaoka 120a6e
int getInkPredominance(const TRasterCM32P &ras, TPalette *palette, int x, int y,
Shinya Kitaoka 120a6e
                       int radius, int threshold) {
Shinya Kitaoka 120a6e
  int i, j;
Shinya Kitaoka 120a6e
  int mx, my, Mx, My;
Shinya Kitaoka 120a6e
  std::vector<int> inksFound(palette->getStyleCount());</int>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  radius = std::min(
Shinya Kitaoka 120a6e
      radius, 7);  // Restrict radius for a minimum significative neighbour
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  mx = std::max(x - radius, 0);
Shinya Kitaoka 120a6e
  my = std::max(y - radius, 0);
Shinya Kitaoka 120a6e
  Mx = std::min(x + radius, ras->getLx() - 1);
Shinya Kitaoka 120a6e
  My = std::min(y + radius, ras->getLy() - 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Check square grid around (x,y)
Shinya Kitaoka 120a6e
  for (i = mx; i <= Mx; ++i)
Shinya Kitaoka 120a6e
    for (j = my; j <= My; ++j)
Shinya Kitaoka 120a6e
      if (sq(i) + sq(j) <= sq(radius) &&
Shinya Kitaoka 120a6e
          ras->pixels(j)[i].getTone() < threshold) {
Shinya Kitaoka 120a6e
        // Update color table
Shinya Kitaoka 120a6e
        inksFound[ras->pixels(j)[i].getInk()] +=
Shinya Kitaoka 120a6e
            255 - ras->pixels(j)[i].getTone();
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // return the most found ink
Shinya Kitaoka 120a6e
  int maxCount = 0, mostFound = 0;
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)inksFound.size(); ++i)
Shinya Kitaoka 120a6e
    if (inksFound[i] > maxCount) {
Shinya Kitaoka 120a6e
      maxCount  = inksFound[i];
Shinya Kitaoka 120a6e
      mostFound = i;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return mostFound;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*!
Toshihiro Shimizu 890ddd
  \brief    Find the predominant color in sequences adjacent to the
Toshihiro Shimizu 890ddd
            input graph node.
Toshihiro Shimizu 890ddd
  \return   The predominant branch color if found, \p -1 otherwise.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
int getBranchPredominance(const TRasterCM32P &ras, TPalette *palette,
Shinya Kitaoka 120a6e
                          JointSequenceGraph::Node &node) {
Shinya Kitaoka 120a6e
  struct locals {
Shinya Kitaoka 120a6e
    static inline bool valueLess(const std::pair<int, int=""> &a,</int,>
Shinya Kitaoka 120a6e
                                 const std::pair<int, int=""> &b) {</int,>
Shinya Kitaoka 120a6e
      return (a.second < b.second);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  boost_c::flat_map<int, int=""> branchInksHistogram;</int,>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  UINT l, lCount = node.getLinksCount();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (l = 0; l != lCount; ++l) {
Shinya Kitaoka 120a6e
    int color = node.getLink(l)->m_color;
Shinya Kitaoka 120a6e
    if (color >= 0 && color <= palette->getStyleCount())
Shinya Kitaoka 120a6e
      ++branchInksHistogram[color];
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Return the most found ink, or -1 if a predominance color could not be found
Shinya Kitaoka 120a6e
  if (branchInksHistogram.empty()) return -1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  typedef boost_c::flat_map<int, int="">::iterator histo_it;</int,>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const std::pair<histo_it, histo_it=""> &histoRange =</histo_it,>
Shinya Kitaoka 120a6e
      boost::minmax_element(branchInksHistogram.begin(),
Shinya Kitaoka 120a6e
                            branchInksHistogram.end(), locals::valueLess);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return (histoRange.first->second == histoRange.second->second)
Shinya Kitaoka 120a6e
             ? -1
Shinya Kitaoka 120a6e
             : histoRange.second->first;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// NOTA: Da implementare una versione in grado di ordinare *pienamente* la
Shinya Kitaoka 120a6e
// vector image.
Shinya Kitaoka 120a6e
void sortJS(JointSequenceGraph *js,
Shinya Kitaoka 120a6e
            std::vector<std::pair<int, *="" tstroke="">> &toOrder,</std::pair<int,>
Shinya Kitaoka 120a6e
            const TRasterCM32P &ras, TPalette *palette) {
Shinya Kitaoka 120a6e
  enum { SORTED = 0x10 };
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<std::pair<unsigned int="" int,="">> nodesToDo;</std::pair<unsigned>
Shinya Kitaoka 120a6e
  unsigned int currNodeIdx, nextNodeIdx;
Shinya Kitaoka 120a6e
  int currColor, currHeight, nextColor, nextHeight;
Shinya Kitaoka 120a6e
  T3DPointD pD;
Shinya Kitaoka 120a6e
  TPoint p;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  SkeletonGraph *currGraph = js->getNode(0).getLink(0)->m_graphHolder;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  unsigned int n, nCount = js->getNodesCount();
Shinya Kitaoka 120a6e
  for (n = 0; n != nCount; ++n) {
Shinya Kitaoka 120a6e
    // Get the first non-ELIMINATED and non-already treated JS node
Shinya Kitaoka 120a6e
    if (!js->getNode(n).hasAttribute(JointSequenceGraph::ELIMINATED | SORTED)) {
Shinya Kitaoka 120a6e
      nodesToDo.push_back(std::make_pair(n, 0));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      while (!nodesToDo.empty()) {
Shinya Kitaoka 120a6e
        currNodeIdx = nodesToDo.back().first;
Shinya Kitaoka 120a6e
        currHeight  = nodesToDo.back().second;
Shinya Kitaoka 120a6e
        nodesToDo.pop_back();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        JointSequenceGraph::Node &currNode = js->node(currNodeIdx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // Sign current node
Shinya Kitaoka 120a6e
        currNode.setAttribute(SORTED);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // Initialize this node infos
Shinya Kitaoka 120a6e
        pD = *currGraph->getNode(currNode.getLink(0)->m_head);
Shinya Kitaoka 120a6e
        p  = TPoint(pD.x, pD.y);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (!ras->getBounds().contains(p)) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // currColor = getInkPredominance(ras, palette, p.x, p.y, (int) pD.z);
Shinya Kitaoka 120a6e
        // //ras->pixels(p.y)[p.x].getInk();
Shinya Kitaoka 120a6e
        currColor = getBranchPredominance(ras, palette, currNode);
Shinya Kitaoka 120a6e
        if (currColor < 0) currColor = ras->pixels(p.y)[p.x].getInk();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        int l, lCount = currNode.getLinksCount();
Shinya Kitaoka 120a6e
        for (l = 0; l != lCount; ++l) {
Shinya Kitaoka 120a6e
          nextNodeIdx = currNode.getLink(l).getNext();
Shinya Kitaoka 120a6e
          Sequence &s = *currNode.link(l);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          // Check if outgoing sequence has current color (front) or not (back)
Shinya Kitaoka 120a6e
          toOrder[s.m_strokeIndex].first =
Shinya Kitaoka 120a6e
              (s.m_color == currColor) ? currHeight : currHeight - 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (!(currNode.getLink(l).getAccess() == SORTED)) {
Shinya Kitaoka 120a6e
            // Deal with this unchecked branch
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
            // If sequence was not split (due to color change)
Shinya Kitaoka 120a6e
            if (!currGraph->getNode(s.m_tail).hasAttribute(SAMPLECOLOR_SIGN)) {
Shinya Kitaoka 120a6e
              JointSequenceGraph::Node &nextNode = js->node(nextNodeIdx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
              // Then check nextNode
Shinya Kitaoka 120a6e
              pD = *currGraph->getNode(nextNode.getLink(0)->m_head);
Shinya Kitaoka 120a6e
              p  = TPoint(pD.x, pD.y);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
              if (!ras->getBounds().contains(p)) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
              // If nextNode was not already inserted in ToDo vector, do it now.
Shinya Kitaoka 120a6e
              if (!nextNode.hasAttribute(SORTED)) {
Shinya Kitaoka 120a6e
                // nextColor = getInkPredominance(ras, palette, p.x, p.y, (int)
Shinya Kitaoka 120a6e
                // pD.z);
Shinya Kitaoka 120a6e
                nextColor = getBranchPredominance(ras, palette, nextNode);
Shinya Kitaoka 120a6e
                if (nextColor < 0) nextColor = ras->pixels(p.y)[p.x].getInk();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
                nextHeight = (s.m_color == nextColor)
Shinya Kitaoka 120a6e
                                 ? toOrder[s.m_strokeIndex].first
Shinya Kitaoka 120a6e
                                 : toOrder[s.m_strokeIndex].first + 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
                nodesToDo.push_back(std::make_pair(nextNodeIdx, nextHeight));
Shinya Kitaoka 120a6e
              }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
              // Deny access to its inverse (already processed now)
Shinya Kitaoka 120a6e
              nextNode.link(js->tailLinkOf(currNodeIdx, l)).setAccess(SORTED);
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline void orderColoredStrokes(JointSequenceGraphList &organizedGraphs,
Shinya Kitaoka 120a6e
                                std::vector<tstroke *=""> &strokes,</tstroke>
Shinya Kitaoka 120a6e
                                const TRasterCM32P &ras, TPalette *palette) {
Shinya Kitaoka 120a6e
  // Initialize ordering
Shinya Kitaoka 120a6e
  std::vector<std::pair<int, *="" tstroke="">> strokesByHeight(</std::pair<int,>
Shinya Kitaoka 120a6e
      strokes.size(),
Shinya Kitaoka 120a6e
      std::make_pair(-(std::numeric_limits<int>::max)(), (TStroke *)0));</int>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  size_t s, sCount = strokes.size();
Shinya Kitaoka 120a6e
  for (s = 0; s != sCount; ++s) strokesByHeight[s].second = strokes[s];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  size_t og, ogCount = organizedGraphs.size();
Shinya Kitaoka 120a6e
  for (og = 0; og != ogCount; ++og)
Shinya Kitaoka 120a6e
    sortJS(&organizedGraphs[og], strokesByHeight, ras, palette);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Now, we have the order vector filled, apply sorting algorithm.
Shinya Kitaoka 120a6e
  std::sort(strokesByHeight.begin(), strokesByHeight.end());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (s = 0; s != sCount; ++s) strokes[s] = strokesByHeight[s].second;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Take samples of image colors to associate each stroke to its corresponding
Shinya Kitaoka 120a6e
// palette color. Currently working on colormaps, closest-to-black strokes
Shinya Kitaoka 120a6e
// otherwise.
Shinya Kitaoka 120a6e
void applyStrokeColors(std::vector<tstroke *=""> &strokes, const TRasterP &ras,</tstroke>
Shinya Kitaoka 120a6e
                       TPalette *palette, VectorizerCoreGlobals &g) {
Shinya Kitaoka 120a6e
  JointSequenceGraphList &organizedGraphs = g.organizedGraphs;
Shinya Kitaoka 120a6e
  SequenceList &singleSequences           = g.singleSequences;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterCM32P cm = ras;
Shinya Kitaoka 120a6e
  unsigned int i, j, k, n;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (cm && g.currConfig->m_maxThickness > 0.0) {
Shinya Kitaoka 120a6e
    applyStrokeIndices(&g);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Treat single sequences before, like conversionToStrokes(..)
Shinya Kitaoka 120a6e
    for (i = 0; i < singleSequences.size(); ++i)
Shinya Kitaoka 120a6e
      strokes[i]->setStyle(singleSequences[i].m_color);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Then, treat remaining graph-strokes
Shinya Kitaoka 120a6e
    n = i;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = 0; i < organizedGraphs.size(); ++i)
Shinya Kitaoka 120a6e
      for (j = 0; j < organizedGraphs[i].getNodesCount(); ++j)
Shinya Kitaoka 120a6e
        if (!organizedGraphs[i].getNode(j).hasAttribute(
Shinya Kitaoka 120a6e
                JointSequenceGraph::ELIMINATED))  // due to junction recovery
Shinya Kitaoka 120a6e
          for (k = 0; k < organizedGraphs[i].getNode(j).getLinksCount(); ++k) {
Shinya Kitaoka 120a6e
            Sequence &s = *organizedGraphs[i].node(j).link(k);
Shinya Kitaoka 120a6e
            if (s.isForward()) {
Shinya Kitaoka 120a6e
              // vi->getStroke(n)->setStyle(s.m_color);
Shinya Kitaoka 120a6e
              strokes[n]->setStyle(s.m_color);
Shinya Kitaoka 120a6e
              ++n;
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Order vector image according to actual color-coverings at junctions.
Shinya Kitaoka 120a6e
    orderColoredStrokes(organizedGraphs, strokes, cm, palette);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // Choose closest-to-black palette color
Shinya Kitaoka 120a6e
    int blackStyleId = palette->getClosestStyle(TPixel32::Black);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    unsigned int i;
Shinya Kitaoka 120a6e
    for (i = 0; i < strokes.size(); ++i) strokes[i]->setStyle(blackStyleId);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}