Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/tcenterlinevectorizer.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tsystem.h"
Toshihiro Shimizu 890ddd
#include "tstopwatch.h"
Toshihiro Shimizu 890ddd
#include "tpalette.h"
Toshihiro Shimizu 890ddd
#include "trastercm.h"
Toshihiro Shimizu 890ddd
#include "ttoonzimage.h"
Toshihiro Shimizu 890ddd
#include "tregion.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
#include "tmathutil.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// tcg includes
Toshihiro Shimizu 890ddd
#include "tcg/tcg_numeric_ops.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// STD includes
Shinya Kitaoka ec43d4
#include <cmath></cmath>
Toshihiro Shimizu 890ddd
#include <functional></functional>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#undef DEBUG
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct ControlPoint {
Shinya Kitaoka 120a6e
  TStroke *m_stroke;
Shinya Kitaoka 120a6e
  int m_index;
Shinya Kitaoka 120a6e
  ControlPoint(TStroke *stroke, int index) : m_stroke(stroke), m_index(index) {}
Shinya Kitaoka 120a6e
  TPointD getPoint() const { return m_stroke->getControlPoint(m_index); }
Shinya Kitaoka 120a6e
  void setPoint(const TPointD &p) {
Shinya Kitaoka 120a6e
    TThickPoint point = m_stroke->getControlPoint(m_index);
Shinya Kitaoka 120a6e
    point.x           = p.x;
Shinya Kitaoka 120a6e
    point.y           = p.y;
Shinya Kitaoka 120a6e
    m_stroke->setControlPoint(m_index, point);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class Node;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class DataPixel {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TPoint m_pos;
Shinya Kitaoka 120a6e
  int m_value;
Shinya Kitaoka 120a6e
  bool m_ink;
Shinya Kitaoka 120a6e
  Node *m_node;
Shinya Kitaoka 120a6e
  DataPixel() : m_value(0), m_ink(false), m_node(0) {}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Shinya Kitaoka 9f5a1b
#ifdef _WIN32
Toshihiro Shimizu 890ddd
template class DV_EXPORT_API TSmartPointerT<trastert<datapixel>>;</trastert<datapixel>
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
typedef TRasterPT<datapixel> DataRasterP;</datapixel>
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class Junction;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class Node {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  Node *m_other;
Shinya Kitaoka 120a6e
  DataPixel *m_pixel;
Shinya Kitaoka 120a6e
  Node *m_prev, *m_next;
Shinya Kitaoka 120a6e
  Junction *m_junction;
Toshihiro Shimizu 890ddd
#ifdef DEBUG
Shinya Kitaoka 120a6e
  bool m_flag;
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  bool m_visited;
Shinya Kitaoka 120a6e
  Node()
Shinya Kitaoka 120a6e
      : m_pixel(0)
Shinya Kitaoka 120a6e
      , m_prev(0)
Shinya Kitaoka 120a6e
      , m_next(0)
Shinya Kitaoka 120a6e
      , m_junction(0)
Shinya Kitaoka 120a6e
      ,
Toshihiro Shimizu 890ddd
#ifdef DEBUG
Shinya Kitaoka 120a6e
      m_flag(false)
Shinya Kitaoka 120a6e
      ,
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
      m_visited(false) {
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class ProtoStroke;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class Junction {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TThickPoint m_center;
Shinya Kitaoka 120a6e
  std::deque<node *=""> m_nodes;</node>
Shinya Kitaoka 120a6e
  int m_junctionOrder;
Shinya Kitaoka 120a6e
  std::vector<protostroke *=""> m_protoStrokes;</protostroke>
Shinya Kitaoka 120a6e
  bool m_locked;
Shinya Kitaoka 120a6e
  Junction()
Shinya Kitaoka 120a6e
      : m_center()
Shinya Kitaoka 120a6e
      , m_nodes()
Shinya Kitaoka 120a6e
      , m_junctionOrder(0)
Shinya Kitaoka 120a6e
      , m_protoStrokes()
Shinya Kitaoka 120a6e
      , m_locked(false) {}
Shinya Kitaoka 120a6e
  bool isConvex();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class ProtoStroke {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TPointD m_startDirection, m_endDirection;
Shinya Kitaoka 120a6e
  Junction *m_startJunction, *m_endJunction;
Shinya Kitaoka 120a6e
  std::deque<tthickpoint> m_points;</tthickpoint>
Shinya Kitaoka 120a6e
  ProtoStroke()
Shinya Kitaoka 120a6e
      : m_points()
Shinya Kitaoka 120a6e
      , m_startDirection()
Shinya Kitaoka 120a6e
      , m_endDirection()
Shinya Kitaoka 120a6e
      , m_startJunction(0)
Shinya Kitaoka 120a6e
      , m_endJunction(0) {}
Shinya Kitaoka 120a6e
  ProtoStroke(std::deque<tthickpoint>::iterator it_b,</tthickpoint>
Shinya Kitaoka 120a6e
              std::deque<tthickpoint>::iterator it_e)</tthickpoint>
Shinya Kitaoka 120a6e
      : m_points(it_b, it_e)
Shinya Kitaoka 120a6e
      , m_startDirection()
Shinya Kitaoka 120a6e
      , m_endDirection()
Shinya Kitaoka 120a6e
      , m_startJunction(0)
Shinya Kitaoka 120a6e
      , m_endJunction(0) {}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Campbell Barton b3bd84
static double computeDistance2(Node *na, Node *nb) {
Shinya Kitaoka 120a6e
  assert(na->m_pixel);
Shinya Kitaoka 120a6e
  assert(nb->m_pixel);
Shinya Kitaoka 120a6e
  TPointD d = convert(na->m_pixel->m_pos - nb->m_pixel->m_pos);
Shinya Kitaoka 120a6e
  return d * d;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Campbell Barton b3bd84
static void renormalizeImage(TVectorImage *vi) {
Shinya Kitaoka 120a6e
  int i, j;
Shinya Kitaoka 120a6e
  int n = vi->getStrokeCount();
Shinya Kitaoka 120a6e
  std::vector<controlpoint> points;</controlpoint>
Shinya Kitaoka 120a6e
  points.reserve(n * 2);
Shinya Kitaoka 120a6e
  for (i = 0; i < n; i++) {
Shinya Kitaoka 120a6e
    TStroke *stroke = vi->getStroke(i);
Shinya Kitaoka 120a6e
    int m           = stroke->getControlPointCount();
Shinya Kitaoka 120a6e
    if (m > 0) {
Shinya Kitaoka 120a6e
      if (m == 1)
Shinya Kitaoka 120a6e
        points.push_back(ControlPoint(stroke, 0));
Shinya Kitaoka 120a6e
      else {
Shinya Kitaoka 120a6e
        points.push_back(ControlPoint(stroke, 0));
Shinya Kitaoka 120a6e
        points.push_back(ControlPoint(stroke, m - 1));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int count = points.size();
Shinya Kitaoka 120a6e
  for (i = 0; i < count; i++) {
Shinya Kitaoka 120a6e
    ControlPoint &pi = points[i];
Shinya Kitaoka 120a6e
    TPointD posi     = pi.getPoint();
Shinya Kitaoka 120a6e
    TPointD center   = posi;
Shinya Kitaoka 120a6e
    std::vector<int> neighbours;</int>
Shinya Kitaoka 120a6e
    neighbours.push_back(i);
Shinya Kitaoka 120a6e
    for (j = i + 1; j < count; j++) {
Shinya Kitaoka 120a6e
      TPointD posj = points[j].getPoint();
Shinya Kitaoka 120a6e
      double d     = tdistance(posj, posi);
Shinya Kitaoka 120a6e
      if (d < 0.01) {
Shinya Kitaoka 120a6e
        neighbours.push_back(j);
Shinya Kitaoka 120a6e
        center += posj;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    int m = neighbours.size();
Shinya Kitaoka 120a6e
    if (m == 1) continue;
Shinya Kitaoka 120a6e
    center = center * (1.0 / m);
Shinya Kitaoka 120a6e
    for (j = 0; j < m; j++) points[neighbours[j]].setPoint(center);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class OutlineVectorizer {
Shinya Kitaoka 120a6e
  TPalette *m_palette;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TRasterP m_src;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  OutlineConfiguration m_configuration;
Shinya Kitaoka 120a6e
  DataRasterP m_dataRaster;
Shinya Kitaoka 120a6e
  std::vector<std::pair<int, datarasterp="">> m_dataRasterArray;</std::pair<int,>
Shinya Kitaoka 120a6e
  TVectorImageP m_vimage;
Shinya Kitaoka 120a6e
  std::vector<node *=""> m_nodes;</node>
Shinya Kitaoka 120a6e
  std::list<std::vector<tthickpoint>> m_protoOutlines;</std::vector<tthickpoint>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<junction *=""> m_junctions;</junction>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  OutlineVectorizer(const OutlineConfiguration &configuration,
Shinya Kitaoka 120a6e
                    TPalette *palette)
Shinya Kitaoka 120a6e
      : m_configuration(configuration), m_palette(palette) {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ~OutlineVectorizer();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void traceOutline(Node *initialNode);
Shinya Kitaoka 120a6e
  void createOutlineStrokes();
Shinya Kitaoka 120a6e
  void makeDataRaster(const TRasterP &src);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  Node *findOtherSide(Node *node);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void clearNodes();
Shinya Kitaoka 120a6e
  Node *createNode(DataPixel *pix);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void clearJunctions();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void init();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void link(DataPixel *pix, DataPixel *from, DataPixel *to);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPoint computeGradient(DataPixel *pix) {
Shinya Kitaoka 120a6e
    assert(m_dataRaster);
Shinya Kitaoka 120a6e
    const int wrap = m_dataRaster->getWrap();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TPoint g(0, 0);
Shinya Kitaoka 120a6e
    int n, s, w, e, nw, sw, ne, se;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    w  = pix[-1].m_value;
Shinya Kitaoka 120a6e
    nw = pix[-1 + wrap].m_value;
Shinya Kitaoka 120a6e
    sw = pix[-1 - wrap].m_value;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    e  = pix[+1].m_value;
Shinya Kitaoka 120a6e
    ne = pix[+1 + wrap].m_value;
Shinya Kitaoka 120a6e
    se = pix[+1 - wrap].m_value;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    n = pix[+wrap].m_value;
Shinya Kitaoka 120a6e
    s = pix[-wrap].m_value;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    g.y = -sw + ne - se + nw + 2 * (n - s);
Shinya Kitaoka 120a6e
    g.x = -sw + ne + se - nw + 2 * (e - w);
Shinya Kitaoka 120a6e
    return g;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  // not implemented
Shinya Kitaoka 120a6e
  OutlineVectorizer(const OutlineVectorizer &);
Shinya Kitaoka 120a6e
  OutlineVectorizer &operator=(const OutlineVectorizer &);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
OutlineVectorizer::~OutlineVectorizer() {
Shinya Kitaoka 120a6e
  m_protoOutlines.clear();
Shinya Kitaoka 120a6e
  clearNodes();
Shinya Kitaoka 120a6e
  clearJunctions();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void OutlineVectorizer::init() {
Shinya Kitaoka 120a6e
  int y;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  DataRasterP dataRaster = m_dataRaster;
Shinya Kitaoka 120a6e
  const int wrap         = dataRaster->getWrap();
Shinya Kitaoka 120a6e
  const int delta[]      = {-wrap - 1, -wrap, -wrap + 1, 1,
Shinya Kitaoka 120a6e
                       wrap + 1,  wrap,  wrap - 1,  -1};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (y = 1; y < dataRaster->getLy() - 1; y++) {
Shinya Kitaoka 120a6e
    DataPixel *pix    = dataRaster->pixels(y);
Shinya Kitaoka 120a6e
    DataPixel *endPix = pix + dataRaster->getLx() - 1;
Shinya Kitaoka 120a6e
    pix++;
Shinya Kitaoka 120a6e
    for (pix++; pix < endPix; ++pix) {
Shinya Kitaoka 120a6e
      if ((pix->m_ink == false) || (pix[-wrap].m_ink && pix[wrap].m_ink &&
Shinya Kitaoka 120a6e
                                    pix[-1].m_ink && pix[1].m_ink))
Shinya Kitaoka 120a6e
        continue;
Shinya Kitaoka 120a6e
      int i;
Shinya Kitaoka 120a6e
      for (i = 0; i < 8; i++)
Shinya Kitaoka 120a6e
        if (pix[delta[i]].m_ink && pix[delta[(i + 1) & 0x7]].m_ink == false)
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
      int start = i;
Shinya Kitaoka 120a6e
      if (i == 8) continue;  // punto isolato
Shinya Kitaoka 120a6e
      for (;;) {
Shinya Kitaoka 120a6e
        int j = (i + 1) & 0x7;
Shinya Kitaoka 120a6e
        assert(i < 8 && pix[delta[i]].m_ink);
Shinya Kitaoka 120a6e
        assert(j < 8 && pix[delta[j]].m_ink == false);
Shinya Kitaoka 120a6e
        do
Shinya Kitaoka 120a6e
          j = (j + 1) & 0x7;
Shinya Kitaoka 120a6e
        while (pix[delta[j]].m_ink == false);
Shinya Kitaoka 120a6e
        assert(j < 8 && pix[delta[j]].m_ink);
Shinya Kitaoka 120a6e
        if (((i + 2) & 0x7) != j || (i & 1) == 0) {
Shinya Kitaoka 120a6e
          // il bianco comprende anche un fianco
Shinya Kitaoka 120a6e
          link(pix, pix + delta[i], pix + delta[j]);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        i = j;
Shinya Kitaoka 120a6e
        assert(i < 8);
Shinya Kitaoka 120a6e
        while (pix[delta[(i + 1) & 0x7]].m_ink) i = (i + 1) & 0x7;
Shinya Kitaoka 120a6e
        assert(i < 8 && pix[delta[i]].m_ink);
Shinya Kitaoka 120a6e
        assert(pix[delta[(i + 1) & 0x7]].m_ink == false);
Shinya Kitaoka 120a6e
        if (i == start) break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
Node *OutlineVectorizer::createNode(DataPixel *pix) {
Shinya Kitaoka 120a6e
  Node *node    = new Node();
Shinya Kitaoka 120a6e
  node->m_pixel = pix;
Shinya Kitaoka 120a6e
  node->m_other = pix->m_node;
Shinya Kitaoka 120a6e
  pix->m_node   = node;
Shinya Kitaoka 120a6e
  m_nodes.push_back(node);
Shinya Kitaoka 120a6e
  return node;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void OutlineVectorizer::clearNodes() {
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)m_nodes.size(); i++) delete m_nodes[i];
Shinya Kitaoka 120a6e
  m_nodes.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void OutlineVectorizer::clearJunctions() {
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)m_junctions.size(); i++) delete m_junctions[i];
Shinya Kitaoka 120a6e
  m_junctions.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void OutlineVectorizer::link(DataPixel *pix, DataPixel *srcPix,
Shinya Kitaoka 120a6e
                             DataPixel *dstPix) {
Shinya Kitaoka 120a6e
  Node *srcNode = 0, *dstNode = 0, *node = 0;
Shinya Kitaoka 120a6e
  Node *tmp;
Shinya Kitaoka 120a6e
  for (tmp = pix->m_node; tmp; tmp = tmp->m_other) {
Shinya Kitaoka 120a6e
    if (tmp->m_pixel == 0) continue;
Shinya Kitaoka 120a6e
    if (tmp->m_prev && tmp->m_prev->m_pixel == srcPix) {
Shinya Kitaoka 120a6e
      assert(srcNode == 0);
Shinya Kitaoka 120a6e
      if (node) {
Shinya Kitaoka 120a6e
        assert(node->m_next->m_pixel == dstPix);
Shinya Kitaoka 120a6e
        assert(node->m_prev == 0);
Shinya Kitaoka 120a6e
        node->m_prev        = tmp->m_prev;
Shinya Kitaoka 120a6e
        tmp->m_prev->m_next = node;
Shinya Kitaoka 120a6e
        tmp->m_next = tmp->m_prev = 0;
Shinya Kitaoka 120a6e
        tmp->m_pixel              = 0;
Shinya Kitaoka 120a6e
        return;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      assert(tmp->m_next == 0);
Shinya Kitaoka 120a6e
      srcNode = tmp->m_prev;
Shinya Kitaoka 120a6e
      node    = tmp;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (tmp->m_next && tmp->m_next->m_pixel == dstPix) {
Shinya Kitaoka 120a6e
      assert(dstNode == 0);
Shinya Kitaoka 120a6e
      if (node) {
Shinya Kitaoka 120a6e
        assert(node->m_prev->m_pixel == srcPix);
Shinya Kitaoka 120a6e
        assert(node->m_next == 0);
Shinya Kitaoka 120a6e
        node->m_next        = tmp->m_next;
Shinya Kitaoka 120a6e
        tmp->m_next->m_prev = node;
Shinya Kitaoka 120a6e
        tmp->m_next = tmp->m_prev = 0;
Shinya Kitaoka 120a6e
        tmp->m_pixel              = 0;
Shinya Kitaoka 120a6e
        return;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      assert(tmp->m_prev == 0);
Shinya Kitaoka 120a6e
      dstNode = tmp->m_next;
Shinya Kitaoka 120a6e
      node    = tmp;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
shun-iwasawa 21f942
  if (!node) node = createNode(pix);
Shinya Kitaoka 120a6e
  if (!srcNode) srcNode = createNode(srcPix);
Shinya Kitaoka 120a6e
  if (!dstNode) dstNode = createNode(dstPix);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!node->m_next) {
Shinya Kitaoka 120a6e
    node->m_next = dstNode;
Shinya Kitaoka 120a6e
    assert(dstNode->m_prev == 0);
Shinya Kitaoka 120a6e
    dstNode->m_prev = node;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (!node->m_prev) {
Shinya Kitaoka 120a6e
    node->m_prev = srcNode;
Shinya Kitaoka 120a6e
    assert(srcNode->m_next == 0);
Shinya Kitaoka 120a6e
    srcNode->m_next = node;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(node->m_next == dstNode);
Shinya Kitaoka 120a6e
  assert(node->m_prev == srcNode);
Shinya Kitaoka 120a6e
  assert(dstNode->m_prev == node);
Shinya Kitaoka 120a6e
  assert(srcNode->m_next == node);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void OutlineVectorizer::traceOutline(Node *initialNode) {
Shinya Kitaoka 120a6e
  Node *startNode = initialNode;
Shinya Kitaoka 120a6e
  Node *node;
Shinya Kitaoka 120a6e
  do {
Shinya Kitaoka 120a6e
    if (!startNode) break;
Shinya Kitaoka 120a6e
    node = findOtherSide(startNode);
Shinya Kitaoka 120a6e
    if (!node) break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double startDist2 = computeDistance2(startNode, node);
Shinya Kitaoka 120a6e
    if (startDist2 > 0.1) break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    startNode = startNode->m_next;
Shinya Kitaoka 120a6e
  } while (startNode != initialNode);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!startNode) return;
Shinya Kitaoka 120a6e
  node = startNode;
Shinya Kitaoka 120a6e
  std::vector<tthickpoint> points;</tthickpoint>
Shinya Kitaoka 120a6e
  do {
Shinya Kitaoka 120a6e
    node = node->m_next;
Shinya Kitaoka 120a6e
    if (!node) break;
Shinya Kitaoka 120a6e
    node->m_visited = true;
Shinya Kitaoka 120a6e
    points.push_back(TThickPoint(convert(node->m_pixel->m_pos), 0));
Shinya Kitaoka 120a6e
  } while (node != startNode);
Shinya Kitaoka 120a6e
  m_protoOutlines.push_back(points);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
Node *OutlineVectorizer::findOtherSide(Node *node) {
Shinya Kitaoka 120a6e
  DataPixel *pix = node->m_pixel;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPoint dir = -computeGradient(pix);
Shinya Kitaoka 120a6e
  if (dir == TPoint(0, 0)) return 0;
Shinya Kitaoka 120a6e
  TPoint d1(tsign(dir.x), 0), d2(0, tsign(dir.y));
Shinya Kitaoka 120a6e
  int num = abs(dir.y), den = abs(dir.x);
Shinya Kitaoka 120a6e
  if (num > den) {
otakuto ed7dcd
    std::swap(d1, d2);
otakuto ed7dcd
    std::swap(num, den);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TPoint pos = pix->m_pos;
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0;; i++) {
Shinya Kitaoka 120a6e
    TPoint q(pos.x + d1.x * i + d2.x * num * i / den,
Shinya Kitaoka 120a6e
             pos.y + d1.y * i + d2.y * num * i / den);
Shinya Kitaoka 120a6e
    DataPixel *nextPix = m_dataRaster->pixels(q.y) + q.x;
Shinya Kitaoka 120a6e
    if (nextPix->m_ink == false) break;
Shinya Kitaoka 120a6e
    pix = nextPix;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  assert(pix);
Shinya Kitaoka 120a6e
  if (!pix->m_node) {
Shinya Kitaoka 120a6e
    const int wrap = m_dataRaster->getWrap();
Shinya Kitaoka 120a6e
    if (pix[-1].m_node)
Shinya Kitaoka 120a6e
      pix--;
Shinya Kitaoka 120a6e
    else if (pix[1].m_node)
Shinya Kitaoka 120a6e
      pix++;
Shinya Kitaoka 120a6e
    else if (pix[wrap].m_node)
Shinya Kitaoka 120a6e
      pix += wrap;
Shinya Kitaoka 120a6e
    else if (pix[-wrap].m_node)
Shinya Kitaoka 120a6e
      pix -= wrap;
Shinya Kitaoka 120a6e
    else {
Shinya Kitaoka 120a6e
      assert(0);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (!pix->m_node) return 0;
shun-iwasawa 21f942
  Node *q = pix->m_node;
Shinya Kitaoka 120a6e
  while (q->m_pixel == 0 && q->m_other) q = q->m_other;
Shinya Kitaoka 120a6e
  assert(q && q->m_pixel == pix);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i < 5; i++) {
Shinya Kitaoka 120a6e
    if (!q->m_prev) break;
Shinya Kitaoka 120a6e
    q = q->m_prev;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  Node *best       = q;
Shinya Kitaoka 120a6e
  double bestDist2 = computeDistance2(q, node);
Shinya Kitaoka 120a6e
  for (i = 0; i < 10; i++) {
Shinya Kitaoka 120a6e
    q = q->m_next;
Shinya Kitaoka 120a6e
    if (!q) break;
Shinya Kitaoka 120a6e
    double dist2 = computeDistance2(q, node);
Shinya Kitaoka 120a6e
    if (dist2 < bestDist2) {
Shinya Kitaoka 120a6e
      bestDist2 = dist2;
Shinya Kitaoka 120a6e
      best      = q;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return best;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void OutlineVectorizer::createOutlineStrokes() {
Shinya Kitaoka 120a6e
  m_vimage->enableRegionComputing(true, false);
Shinya Kitaoka 120a6e
  int j;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (j = 0; j < (int)m_nodes.size(); j++) {
Shinya Kitaoka 120a6e
    Node *node = m_nodes[j];
Shinya Kitaoka 120a6e
    if (node->m_pixel == 0 || node->m_visited) continue;
Shinya Kitaoka 120a6e
    traceOutline(node);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef DEBUG
Shinya Kitaoka 120a6e
  for (j = 0; j < (int)m_nodes.size(); j++) {
Shinya Kitaoka 120a6e
    Node *node = m_nodes[j];
Shinya Kitaoka 120a6e
    if (node->m_pixel == 0 || node->m_flag) continue;
Shinya Kitaoka 120a6e
    outputNodes(node);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::list<std::vector<tthickpoint>>::iterator it_outlines =</std::vector<tthickpoint>
Shinya Kitaoka 120a6e
      m_protoOutlines.begin();
Rozhuk Ivan 823a31
  for (; it_outlines != m_protoOutlines.end(); it_outlines++) {
Shinya Kitaoka 120a6e
    if (it_outlines->size() > 3) {
Shinya Kitaoka 120a6e
      std::vector<tthickpoint> points;</tthickpoint>
Shinya Kitaoka 120a6e
      std::vector<tthickpoint>::iterator it;</tthickpoint>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (it_outlines->size() > 10) {
Shinya Kitaoka 120a6e
        it = it_outlines->begin() + 1;
Shinya Kitaoka 120a6e
        for (;;) {
Shinya Kitaoka 120a6e
          // Baco: Ricontrolla l'if seguente - in alcuni casi va fuori bounds...
Shinya Kitaoka 120a6e
          if ((int)it_outlines->size() <= m_configuration.m_smoothness + 1)
Shinya Kitaoka 120a6e
            break;
Shinya Kitaoka 120a6e
          if (it >= it_outlines->end() - (m_configuration.m_smoothness + 1))
Shinya Kitaoka 120a6e
            break;
Shinya Kitaoka 120a6e
          for (j = 0; j < m_configuration.m_smoothness; j++)
Shinya Kitaoka 120a6e
            it = it_outlines->erase(it);
Shinya Kitaoka 120a6e
          ++it;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      points.push_back(it_outlines->front());
Shinya Kitaoka 120a6e
      it              = it_outlines->begin();
Shinya Kitaoka 120a6e
      TThickPoint old = *it;
Shinya Kitaoka 120a6e
      ++it;
Shinya Kitaoka 120a6e
      for (; it != it_outlines->end(); ++it) {
Shinya Kitaoka 120a6e
        TThickPoint point((1 / 2.0) * (*it + old));
Shinya Kitaoka 120a6e
        points.push_back(point);
Shinya Kitaoka 120a6e
        old = *it;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      points.push_back(it_outlines->back());
Shinya Kitaoka 120a6e
      points.push_back(it_outlines->front());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TStroke *stroke =
Shinya Kitaoka 120a6e
          TStroke::interpolate(points, m_configuration.m_interpolationError);
Shinya Kitaoka 120a6e
      stroke->setStyle(m_configuration.m_strokeStyleId);
Shinya Kitaoka 120a6e
      stroke->setSelfLoop();
Shinya Kitaoka 120a6e
      m_vimage->addStroke(stroke);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline int colorDistance2(const TPixel32 &c0, const TPixel32 &c1) {
Shinya Kitaoka 120a6e
  return ((c0.r - c1.r) * (c0.r - c1.r) + (c0.g - c1.g) * (c0.g - c1.g) +
Shinya Kitaoka 120a6e
          (c0.b - c1.b) * (c0.b - c1.b));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
#define MAX_TOLERANCE 20
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tcolorstyles.h"
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void OutlineVectorizer::makeDataRaster(const TRasterP &src) {
Shinya Kitaoka 120a6e
  m_vimage = new TVectorImage();
Shinya Kitaoka 120a6e
  if (!src) return;
Shinya Kitaoka 120a6e
  m_src = src;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  clearNodes();
Shinya Kitaoka 120a6e
  clearJunctions();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int x, y, ii = 0;
Shinya Kitaoka 120a6e
  TRaster32P srcRGBM = (TRaster32P)m_src;
Shinya Kitaoka 120a6e
  TRasterCM32P srcCM = (TRasterCM32P)m_src;
Shinya Kitaoka 120a6e
  TRasterGR8P srcGR  = (TRasterGR8P)m_src;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Inizializzo DataRasterP per i casi in cui si ha un TRaster32P, un
Shinya Kitaoka 120a6e
  // TRasterGR8P o un TRasterCM32P molto grande
Shinya Kitaoka 120a6e
  DataRasterP dataRaster(m_src->getSize().lx + 2, m_src->getSize().ly + 2);
Shinya Kitaoka 120a6e
  if (srcRGBM || srcGR ||
Shinya Kitaoka 120a6e
      (srcCM && srcCM->getLx() * srcCM->getLy() > 5000000)) {
Shinya Kitaoka 120a6e
    int ly              = dataRaster->getLy();
Shinya Kitaoka 120a6e
    int lx              = dataRaster->getLx();
Shinya Kitaoka 120a6e
    int wrap            = dataRaster->getWrap();
Shinya Kitaoka 120a6e
    DataPixel *dataPix0 = dataRaster->pixels(0);
Shinya Kitaoka 120a6e
    DataPixel *dataPix1 = dataRaster->pixels(0) + m_src->getLx() + 1;
Shinya Kitaoka 120a6e
    for (y = 0; y < ly; y++, dataPix0 += wrap, dataPix1 += wrap) {
Shinya Kitaoka 120a6e
      dataPix0->m_pos.x = 0;
Shinya Kitaoka 120a6e
      dataPix1->m_pos.x = lx - 1;
Shinya Kitaoka 120a6e
      dataPix0->m_pos.y = dataPix1->m_pos.y = y;
Shinya Kitaoka 120a6e
      dataPix0->m_value = dataPix1->m_value = 0;
Shinya Kitaoka 120a6e
      dataPix0->m_ink = dataPix1->m_ink = false;
Shinya Kitaoka 120a6e
      dataPix0->m_node = dataPix1->m_node = 0;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    dataPix0 = dataRaster->pixels(0);
Shinya Kitaoka 120a6e
    dataPix1 = dataRaster->pixels(ly - 1);
Shinya Kitaoka 120a6e
    for (x = 0; x < lx; x++, dataPix0++, dataPix1++) {
Shinya Kitaoka 120a6e
      dataPix0->m_pos.x = dataPix1->m_pos.x = x;
Shinya Kitaoka 120a6e
      dataPix0->m_pos.y                     = 0;
Shinya Kitaoka 120a6e
      dataPix1->m_pos.y                     = ly - 1;
Shinya Kitaoka 120a6e
      dataPix0->m_value = dataPix1->m_value = 0;
Shinya Kitaoka 120a6e
      dataPix0->m_ink = dataPix1->m_ink = false;
Shinya Kitaoka 120a6e
      dataPix0->m_node = dataPix1->m_node = 0;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (srcRGBM) {
Shinya Kitaoka 120a6e
    assert(m_palette);
Shinya Kitaoka 120a6e
    int inkId = m_palette->getClosestStyle(m_configuration.m_inkColor);
shun-iwasawa 21f942
    if (!inkId || m_configuration.m_inkColor !=
shun-iwasawa 21f942
                      m_palette->getStyle(inkId)->getMainColor()) {
Shinya Kitaoka 120a6e
      inkId = m_palette->getStyleCount();
Shinya Kitaoka 120a6e
      m_palette->getStylePage(1)->insertStyle(1, m_configuration.m_inkColor);
Shinya Kitaoka 120a6e
      m_palette->setStyle(inkId, m_configuration.m_inkColor);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    assert(inkId);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_dataRasterArray.push_back(std::pair<int, datarasterp="">(inkId, dataRaster));</int,>
Shinya Kitaoka 120a6e
    int maxDistance2 =
Shinya Kitaoka 120a6e
        m_configuration.m_threshold * m_configuration.m_threshold;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (y = 0; y < m_src->getLy(); y++) {
Shinya Kitaoka 120a6e
      TPixel32 *inPix    = srcRGBM->pixels(y);
Shinya Kitaoka 120a6e
      TPixel32 *inEndPix = inPix + srcRGBM->getLx();
Shinya Kitaoka 120a6e
      DataPixel *dataPix = dataRaster->pixels(y + 1) + 1;
Shinya Kitaoka 120a6e
      x                  = 0;
Shinya Kitaoka 120a6e
      while (inPix < inEndPix) {
Shinya Kitaoka 120a6e
        *dataPix      = DataPixel();
Shinya Kitaoka 120a6e
        int distance2 = colorDistance2(m_configuration.m_inkColor, *inPix);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (y == 0 || y == m_src->getLy() - 1 || x == 0 ||
Shinya Kitaoka 120a6e
            x == m_src->getLx() - 1 || inPix->m == 0) {
Shinya Kitaoka 120a6e
          dataPix->m_value = 255;
Shinya Kitaoka 120a6e
          dataPix->m_ink   = false;
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          dataPix->m_value = (inPix->r + 2 * inPix->g + inPix->b) >> 2;
Shinya Kitaoka 120a6e
          dataPix->m_ink   = (distance2 < maxDistance2);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        dataPix->m_pos.x = x++;
Shinya Kitaoka 120a6e
        dataPix->m_pos.y = y;
Shinya Kitaoka 120a6e
        dataPix->m_node  = 0;
Shinya Kitaoka 120a6e
        inPix++;
Shinya Kitaoka 120a6e
        dataPix++;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else if (srcGR) {
Shinya Kitaoka 120a6e
    assert(m_palette);
Shinya Kitaoka 120a6e
    int inkId = m_palette->getClosestStyle(m_configuration.m_inkColor);
shun-iwasawa 21f942
    if (!inkId || m_configuration.m_inkColor !=
shun-iwasawa 21f942
                      m_palette->getStyle(inkId)->getMainColor()) {
Shinya Kitaoka 120a6e
      inkId = m_palette->getStyleCount();
Shinya Kitaoka 120a6e
      m_palette->getStylePage(1)->insertStyle(1, m_configuration.m_inkColor);
Shinya Kitaoka 120a6e
      m_palette->setStyle(inkId, m_configuration.m_inkColor);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    assert(inkId);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_dataRasterArray.push_back(std::pair<int, datarasterp="">(inkId, dataRaster));</int,>
Shinya Kitaoka 120a6e
    int threshold = m_configuration.m_threshold;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (y = 0; y < m_src->getLy(); y++) {
Shinya Kitaoka 120a6e
      TPixelGR8 *inPix    = srcGR->pixels(y);
Shinya Kitaoka 120a6e
      TPixelGR8 *inEndPix = inPix + srcGR->getLx();
Shinya Kitaoka 120a6e
      DataPixel *dataPix  = dataRaster->pixels(y + 1) + 1;
Shinya Kitaoka 120a6e
      x                   = 0;
Shinya Kitaoka 120a6e
      while (inPix < inEndPix) {
Shinya Kitaoka 120a6e
        *dataPix = DataPixel();
Shinya Kitaoka 120a6e
        if (y == 0 || y == m_src->getLy() - 1 || x == 0 ||
Shinya Kitaoka 120a6e
            x == m_src->getLx() - 1) {
Shinya Kitaoka 120a6e
          dataPix->m_value = 255;
Shinya Kitaoka 120a6e
          dataPix->m_ink   = false;
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          dataPix->m_value = inPix->value;
Shinya Kitaoka 120a6e
          dataPix->m_ink   = (inPix->value < threshold);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        dataPix->m_pos.x = x++;
Shinya Kitaoka 120a6e
        dataPix->m_pos.y = y;
Shinya Kitaoka 120a6e
        dataPix->m_node  = 0;
Shinya Kitaoka 120a6e
        inPix++;
Shinya Kitaoka 120a6e
        dataPix++;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  else if (srcCM) {
Shinya Kitaoka 120a6e
    int currInk, nextInk = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (srcCM->getLx() * srcCM->getLy() > 5000000) {
Shinya Kitaoka 120a6e
      int threshold = m_configuration.m_threshold;
Shinya Kitaoka 120a6e
      int inkId     = m_palette->getClosestStyle(TPixel::Black);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (TPixel::Black != m_palette->getStyle(inkId)->getMainColor()) {
Shinya Kitaoka 120a6e
        inkId = m_palette->getStyleCount();
Shinya Kitaoka 120a6e
        m_palette->getStylePage(1)->insertStyle(1, m_configuration.m_inkColor);
Shinya Kitaoka 120a6e
        m_palette->setStyle(inkId, m_configuration.m_inkColor);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      assert(inkId);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_dataRasterArray.push_back(
Shinya Kitaoka 120a6e
          std::pair<int, datarasterp="">(inkId, dataRaster));</int,>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // inizializza la parte centrale
Shinya Kitaoka 120a6e
      for (y = 0; y < m_src->getLy(); y++) {
Shinya Kitaoka 120a6e
        TPixelCM32 *inPix    = srcCM->pixels(y);
Shinya Kitaoka 120a6e
        TPixelCM32 *inEndPix = inPix + m_src->getLx();
Shinya Kitaoka 120a6e
        DataPixel *dataPix   = dataRaster->pixels(y + 1) + 1;
Shinya Kitaoka 120a6e
        x                    = 0;
Shinya Kitaoka 120a6e
        while (inPix < inEndPix) {
shun-iwasawa 21f942
          *dataPix  = DataPixel();
shun-iwasawa 21f942
          int value = inPix->getTone();
Shinya Kitaoka 120a6e
          if (m_configuration.m_ignoreInkColors) inkId = 1;
Shinya Kitaoka 120a6e
          if (y == 0 || y == m_src->getLy() - 1 || x == 0 ||
Shinya Kitaoka 120a6e
              x == m_src->getLx() - 1) {
Shinya Kitaoka 120a6e
            dataPix->m_value = 255;
Shinya Kitaoka 120a6e
            dataPix->m_ink   = false;
Shinya Kitaoka 120a6e
          } else {
Shinya Kitaoka 120a6e
            dataPix->m_value = value;
Shinya Kitaoka 120a6e
            dataPix->m_ink   = (value < threshold);
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
          dataPix->m_pos.x = x++;
Shinya Kitaoka 120a6e
          dataPix->m_pos.y = y;
Shinya Kitaoka 120a6e
          dataPix->m_node  = 0;
Shinya Kitaoka 120a6e
          inPix++;
Shinya Kitaoka 120a6e
          dataPix++;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      do {
Shinya Kitaoka 120a6e
        // Inizializzo DataRasterP
Shinya Kitaoka 120a6e
        DataRasterP dataRaster(m_src->getSize().lx + 2,
Shinya Kitaoka 120a6e
                               m_src->getSize().ly + 2);
Shinya Kitaoka 120a6e
        int ly              = dataRaster->getLy();
Shinya Kitaoka 120a6e
        int lx              = dataRaster->getLx();
Shinya Kitaoka 120a6e
        int wrap            = dataRaster->getWrap();
Shinya Kitaoka 120a6e
        DataPixel *dataPix0 = dataRaster->pixels(0);
Shinya Kitaoka 120a6e
        DataPixel *dataPix1 = dataRaster->pixels(0) + m_src->getLx() + 1;
Shinya Kitaoka 120a6e
        for (y = 0; y < ly; y++, dataPix0 += wrap, dataPix1 += wrap) {
Shinya Kitaoka 120a6e
          dataPix0->m_pos.x = 0;
Shinya Kitaoka 120a6e
          dataPix1->m_pos.x = lx - 1;
Shinya Kitaoka 120a6e
          dataPix0->m_pos.y = dataPix1->m_pos.y = y;
Shinya Kitaoka 120a6e
          dataPix0->m_value = dataPix1->m_value = 0;
Shinya Kitaoka 120a6e
          dataPix0->m_ink = dataPix1->m_ink = false;
Shinya Kitaoka 120a6e
          dataPix0->m_node = dataPix1->m_node = 0;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        dataPix0 = dataRaster->pixels(0);
Shinya Kitaoka 120a6e
        dataPix1 = dataRaster->pixels(ly - 1);
Shinya Kitaoka 120a6e
        for (x = 0; x < lx; x++, dataPix0++, dataPix1++) {
Shinya Kitaoka 120a6e
          dataPix0->m_pos.x = dataPix1->m_pos.x = x;
Shinya Kitaoka 120a6e
          dataPix0->m_pos.y                     = 0;
Shinya Kitaoka 120a6e
          dataPix1->m_pos.y                     = ly - 1;
Shinya Kitaoka 120a6e
          dataPix0->m_value = dataPix1->m_value = 0;
Shinya Kitaoka 120a6e
          dataPix0->m_ink = dataPix1->m_ink = false;
Shinya Kitaoka 120a6e
          dataPix0->m_node = dataPix1->m_node = 0;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        int threshold =
Shinya Kitaoka 120a6e
            m_configuration.m_threshold;  // tolerance: 1->MAX thresh: 1-255
Shinya Kitaoka 120a6e
        currInk = nextInk;
Shinya Kitaoka 120a6e
        nextInk = 0;
Shinya Kitaoka 120a6e
        m_dataRasterArray.push_back(
Shinya Kitaoka 120a6e
            std::pair<int, datarasterp="">(currInk, dataRaster));</int,>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // inizializza la parte centrale
Shinya Kitaoka 120a6e
        for (y = 0; y < m_src->getLy(); y++) {
Shinya Kitaoka 120a6e
          TPixelCM32 *inPix    = srcCM->pixels(y);
Shinya Kitaoka 120a6e
          TPixelCM32 *inEndPix = inPix + m_src->getLx();
Shinya Kitaoka 120a6e
          DataPixel *dataPix   = dataRaster->pixels(y + 1) + 1;
Shinya Kitaoka 120a6e
          x                    = 0;
Shinya Kitaoka 120a6e
          while (inPix < inEndPix) {
Shinya Kitaoka 120a6e
            *dataPix  = DataPixel();
Shinya Kitaoka 120a6e
            int value = inPix->getTone();
Shinya Kitaoka 120a6e
            if (value < 255 && !m_configuration.m_ignoreInkColors) {
Shinya Kitaoka 120a6e
              int ink = inPix->getInk();
Shinya Kitaoka 120a6e
              if (currInk == 0) {
Shinya Kitaoka 120a6e
                currInk                        = ink;
Shinya Kitaoka 120a6e
                m_dataRasterArray.back().first = ink;
Shinya Kitaoka 120a6e
              } else if (ink != currInk) {
Shinya Kitaoka 120a6e
                value = 255;
Shinya Kitaoka 120a6e
                if (nextInk == 0) {
Shinya Kitaoka 120a6e
                  for (ii = 0; ii < (int)m_dataRasterArray.size() - 1; ii++)
Shinya Kitaoka 120a6e
                    if (m_dataRasterArray[ii].first == ink) break;
Shinya Kitaoka 120a6e
                  if (ii == (int)m_dataRasterArray.size() - 1) nextInk = ink;
Shinya Kitaoka 120a6e
                }
Shinya Kitaoka 120a6e
              }
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
            dataPix->m_pos.x = x++;
Shinya Kitaoka 120a6e
            dataPix->m_pos.y = y;
Shinya Kitaoka 120a6e
            dataPix->m_value = value;
Shinya Kitaoka 120a6e
            dataPix->m_ink   = (value < threshold);
Shinya Kitaoka 120a6e
            dataPix->m_node  = 0;
Shinya Kitaoka 120a6e
            inPix++;
Shinya Kitaoka 120a6e
            dataPix++;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      } while (nextInk != 0);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (m_configuration.m_ignoreInkColors) {
Shinya Kitaoka 120a6e
      assert(m_dataRasterArray.size() == 1);
Shinya Kitaoka 120a6e
      m_dataRasterArray.back().first = 1;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    assert(false);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TVectorImageP VectorizerCore::outlineVectorize(
Shinya Kitaoka 120a6e
    const TImageP &image, const OutlineConfiguration &configuration,
Shinya Kitaoka 120a6e
    TPalette *palette) {
Shinya Kitaoka 120a6e
  TVectorImageP out;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  OutlineVectorizer vectorizer(configuration, palette);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterImageP ri = image;
Shinya Kitaoka 120a6e
  TToonzImageP vi  = image;
Shinya Kitaoka 120a6e
  if (ri)
Shinya Kitaoka 120a6e
    vectorizer.makeDataRaster(ri->getRaster());
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    vectorizer.makeDataRaster(vi->getRaster());
Shinya Kitaoka 120a6e
  int layersCount = vectorizer.m_dataRasterArray.size();
Shinya Kitaoka 120a6e
  if (layersCount > 1) {
Shinya Kitaoka 120a6e
    out = new TVectorImage();
Shinya Kitaoka 120a6e
    out->setPalette(palette);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)layersCount; i++) {
Shinya Kitaoka 120a6e
    vectorizer.m_dataRaster = vectorizer.m_dataRasterArray[i].second;
Shinya Kitaoka 120a6e
    vectorizer.m_configuration.m_strokeStyleId =
Shinya Kitaoka 120a6e
        vectorizer.m_dataRasterArray[i].first;
Shinya Kitaoka 120a6e
    vectorizer.m_protoOutlines.clear();
Shinya Kitaoka 120a6e
    vectorizer.init();
Shinya Kitaoka 120a6e
    vectorizer.createOutlineStrokes();
Shinya Kitaoka 120a6e
    renormalizeImage(vectorizer.m_vimage.getPointer());
Shinya Kitaoka 120a6e
    vectorizer.m_vimage->setPalette(palette);
Shinya Kitaoka 120a6e
    if (layersCount > 1) out->mergeImage(vectorizer.m_vimage, TAffine());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (i != (int)layersCount - 1) vectorizer.m_vimage = new TVectorImage();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return (layersCount == 1) ? vectorizer.m_vimage : out;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================
Toshihiro Shimizu 890ddd
Campbell Barton b3bd84
static bool isPointInRegion(TPointD p, TRegion *r) {
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < 5; i++) {
Shinya Kitaoka 120a6e
    double stepX = i * 0.2;
Shinya Kitaoka 120a6e
    int j;
Shinya Kitaoka 120a6e
    for (j = 0; j < 5; j++) {
Shinya Kitaoka 120a6e
      double stepY = j * 0.2;
Shinya Kitaoka 120a6e
      if (r->contains(TPointD(p.x + stepX, p.y + stepY))) return true;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Se findInk == true :
Shinya Kitaoka 120a6e
//    trova il punto piu' vicino a p con ink puro e restituisce true se e'
Shinya Kitaoka 120a6e
//    contenuto nella regione
Toshihiro Shimizu 890ddd
// Se findInk == false :
Shinya Kitaoka 120a6e
//    Trova il punto piu' vicino a p con paint puro e restituisce true se e'
Shinya Kitaoka 120a6e
//    contenuto nella regione
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//(Daniele) Aggiunti controlli per evitare uscite dai bounds
Toshihiro Shimizu 890ddd
Campbell Barton b3bd84
static bool isNearestInkOrPaintInRegion(bool findInk, const TRasterCM32P &ras,
Campbell Barton b3bd84
                                        TRegion *r, const TAffine &aff,
Campbell Barton b3bd84
                                        const TPoint &p) {
Shinya Kitaoka 120a6e
  bool isTheLastSquare = false;
Shinya Kitaoka 120a6e
  int mx, my, Mx, My;
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 1; i <= 100; i++) {
Shinya Kitaoka 120a6e
    int j, t, s, e;
Shinya Kitaoka 120a6e
    if (p.x - i >= 0) {
Shinya Kitaoka 120a6e
      my = std::max(p.y - i, 0);
Shinya Kitaoka 120a6e
      My = std::min(p.y + i, ras->getLy() - 1);
Shinya Kitaoka 120a6e
      for (j = my; j <= My; j++) {
Shinya Kitaoka 120a6e
        TPixelCM32 col = ras->pixels(j)[p.x - i];
Shinya Kitaoka 120a6e
        int tone       = col.getTone();
Shinya Kitaoka 120a6e
        if ((findInk && tone == 0) || (!findInk && tone == 255)) {
Shinya Kitaoka 120a6e
          if (isPointInRegion(aff * TPointD(double(p.x - i), double(j)), r))
Shinya Kitaoka 120a6e
            return true;
Shinya Kitaoka 120a6e
          else
Shinya Kitaoka 120a6e
            isTheLastSquare = true;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (p.y + i < ras->getLy()) {
Shinya Kitaoka 120a6e
      mx = std::max(p.x - i + 1, 0);
Shinya Kitaoka 120a6e
      Mx = std::min(p.x + i, ras->getLx() - 1);
Shinya Kitaoka 120a6e
      for (t = mx; t <= Mx; t++) {
Shinya Kitaoka 120a6e
        TPixelCM32 col = ras->pixels(p.y + i)[t];
Shinya Kitaoka 120a6e
        int tone       = col.getTone();
Shinya Kitaoka 120a6e
        if ((findInk && tone == 0) || (!findInk && tone == 255)) {
Shinya Kitaoka 120a6e
          if (isPointInRegion(aff * TPointD(double(t), double(p.y + i)), r))
Shinya Kitaoka 120a6e
            return true;
Shinya Kitaoka 120a6e
          else
Shinya Kitaoka 120a6e
            isTheLastSquare = true;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (p.x + i < ras->getLx()) {
Shinya Kitaoka 120a6e
      my = std::max(p.y - i, 0);
Shinya Kitaoka 120a6e
      My = std::min(p.y + i - 1, ras->getLy() - 1);
Shinya Kitaoka 120a6e
      for (s = my; s <= My; s++) {
Shinya Kitaoka 120a6e
        TPixelCM32 col = ras->pixels(s)[p.x + i];
Shinya Kitaoka 120a6e
        int tone       = col.getTone();
Shinya Kitaoka 120a6e
        if ((findInk && tone == 0) || (!findInk && tone == 255)) {
Shinya Kitaoka 120a6e
          if (isPointInRegion(aff * TPointD(double(p.x + i), double(s)), r))
Shinya Kitaoka 120a6e
            return true;
Shinya Kitaoka 120a6e
          else
Shinya Kitaoka 120a6e
            isTheLastSquare = true;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (p.y - i >= 0) {
Shinya Kitaoka 120a6e
      mx = std::max(p.x - i + 1, 0);
Shinya Kitaoka 120a6e
      Mx = std::min(p.x + i - 1, ras->getLx() - 1);
Shinya Kitaoka 120a6e
      for (e = mx; e <= Mx; e++) {
Shinya Kitaoka 120a6e
        TPixelCM32 col = ras->pixels(p.y - i)[e];
Shinya Kitaoka 120a6e
        int tone       = col.getTone();
Shinya Kitaoka 120a6e
        if ((findInk && tone == 0) || (!findInk && tone == 255)) {
Shinya Kitaoka 120a6e
          if (isPointInRegion(aff * TPointD(double(e), double(p.y - i)), r))
Shinya Kitaoka 120a6e
            return true;
Shinya Kitaoka 120a6e
          else
Shinya Kitaoka 120a6e
            isTheLastSquare = true;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (isTheLastSquare) return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline bool isBright(const TPixelCM32 &pix, int threshold) {
Shinya Kitaoka 120a6e
  return pix.getTone() >= threshold;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline bool isBright(const TPixelGR8 &pix, int threshold) {
Shinya Kitaoka 120a6e
  return pix.value >= threshold;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline bool isBright(const TPixel32 &pix, int threshold) {
Shinya Kitaoka 120a6e
  // Using Value in HSV color model
Shinya Kitaoka 120a6e
  return std::max(pix.r, std::max(pix.g, pix.b)) >= threshold * (pix.m / 255.0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Using Lightness in HSL color model
Shinya Kitaoka 120a6e
  // return (max(pix.r,max(pix.g,pix.b)) + min(pix.r,min(pix.g,pix.b))) / 2.0
Shinya Kitaoka 120a6e
  //  >= threshold * (pix.m / 255.0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Using (relative) Luminance
Shinya Kitaoka 120a6e
  // return 0.2126 * pix.r + 0.7152 * pix.g + 0.0722 * pix.b >= threshold *
Shinya Kitaoka 120a6e
  // (pix.m / 255.0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline bool isDark(const TPixelCM32 &pix, int threshold) {
Shinya Kitaoka 120a6e
  return !isBright(pix, threshold);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline bool isDark(const TPixelGR8 &pix, int threshold) {
Shinya Kitaoka 120a6e
  return !isBright(pix, threshold);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline bool isDark(const TPixelRGBM32 &pix, int threshold) {
Shinya Kitaoka 120a6e
  return !isBright(pix, threshold);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix,="" selector="" typename=""></typename>
Toshihiro Shimizu 890ddd
bool getInternalPoint(const TRasterPT<pix> &ras, const Selector &sel,</pix>
Shinya Kitaoka 120a6e
                      const TAffine &inverse, const VectorizerConfiguration &c,
Shinya Kitaoka 120a6e
                      const TRegion *region, TPointD &p) {
Shinya Kitaoka 120a6e
  struct Locals {
Shinya Kitaoka 120a6e
    const TRasterPT<pix> &m_ras;</pix>
Shinya Kitaoka 120a6e
    const Selector &m_sel;
Shinya Kitaoka 120a6e
    const TAffine &m_inverse;
Shinya Kitaoka 120a6e
    double m_pixelSize;
Shinya Kitaoka 120a6e
    const TRegion &m_region;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    static bool contains(const TRegion ®ion, const TPointD &p) {
Shinya Kitaoka 120a6e
      return region.getBBox().contains(p) &&
Shinya Kitaoka 120a6e
             (region.leftScanlineIntersections(p.x, p.y) % 2);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    bool contains(const TPointD &p) {
Shinya Kitaoka 120a6e
      if (!contains(m_region, p)) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      UINT sr, srCount = m_region.getSubregionCount();
Shinya Kitaoka 120a6e
      for (sr = 0; sr != srCount; ++sr) {
Shinya Kitaoka 120a6e
        if (contains(*m_region.getSubregion(sr), p)) return false;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      return true;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Subdivide the output scanline in even intervals, and sample each's
Shinya Kitaoka 120a6e
    // midpoint
Shinya Kitaoka 120a6e
    bool sampleMidpoints(TPointD &p, double x0, double x1, double y,
Shinya Kitaoka 120a6e
                         int intervalsCount) {
Shinya Kitaoka 120a6e
      const double iCountD = intervalsCount;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      for (int i = 0; i != intervalsCount; ++i) {
Shinya Kitaoka 120a6e
        double i_x0 = tcg::numeric_ops::lerp(x0, x1, i / iCountD),
Shinya Kitaoka 120a6e
               i_x1 = tcg::numeric_ops::lerp(x0, x1, (i + 1) / iCountD);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (sample(p = TPointD(0.5 * (i_x0 + i_x1), y))) return true;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Sample the output scanline's midpoint
Shinya Kitaoka 120a6e
    bool sample(TPointD &point) {
Shinya Kitaoka 120a6e
      return (contains(point) &&
Shinya Kitaoka 120a6e
              adjustPoint(point)  // Ensures that point is inRaster()
Shinya Kitaoka 120a6e
              && selected(point));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TPoint toRaster(const TPointD &p) {
Shinya Kitaoka 120a6e
      const TPointD &pRasD = m_inverse * p;
Shinya Kitaoka 120a6e
      return TPoint(pRasD.x, pRasD.y);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    bool inRaster(const TPointD &point) {
Shinya Kitaoka 120a6e
      const TPoint &pRas = toRaster(point);
Shinya Kitaoka 120a6e
      return (pRas.x >= 0 && pRas.x < m_ras->getLx() && pRas.y >= 0 &&
Shinya Kitaoka 120a6e
              pRas.y < m_ras->getLy());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    bool selected(const TPointD &point) {
Shinya Kitaoka 120a6e
      assert(inRaster(point));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      const TPoint &pRas = toRaster(point);
Shinya Kitaoka 120a6e
      return m_sel(m_ras->pixels(pRas.y)[pRas.x]);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    bool adjustPoint(TPointD &p) {
Shinya Kitaoka 120a6e
      const TRectD &bbox = m_region.getBBox();
Shinya Kitaoka 120a6e
      const double tol   = std::max(1e-1 * m_pixelSize, 1e-4);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TPointD newP = p;
Shinya Kitaoka 120a6e
      {
Shinya Kitaoka 120a6e
        // Adjust along x axis
Shinya Kitaoka 120a6e
        int iCount = scanlineIntersectionsBefore(newP.x, newP.y, true);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        double in0 = newP.x, out0 = bbox.x0, in1 = newP.x, out1 = bbox.x1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        isolateBorderX(in0, out0, newP.y, iCount, tol);
Shinya Kitaoka 120a6e
        isolateBorderX(in1, out1, newP.y, iCount, tol);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        newP = TPointD(0.5 * (in0 + in1), newP.y);
Shinya Kitaoka 120a6e
        assert(scanlineIntersectionsBefore(newP.x, newP.y, true) == iCount);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      {
Shinya Kitaoka 120a6e
        // Adjust along y axis
Shinya Kitaoka 120a6e
        int iCount = scanlineIntersectionsBefore(newP.x, newP.y, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        double in0 = newP.y, out0 = bbox.y0, in1 = newP.y, out1 = bbox.y1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        isolateBorderY(newP.x, in0, out0, iCount, tol);
Shinya Kitaoka 120a6e
        isolateBorderY(newP.x, in1, out1, iCount, tol);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        newP = TPointD(newP.x, 0.5 * (in0 + in1));
Shinya Kitaoka 120a6e
        assert(scanlineIntersectionsBefore(newP.x, newP.y, false) == iCount);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      return inRaster(newP) ? (p = newP, true) : false;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    void isolateBorderX(double &xIn, double &xOut, double y, int iCount,
Shinya Kitaoka 120a6e
                        const double tol) {
Shinya Kitaoka 120a6e
      assert(scanlineIntersectionsBefore(xIn, y, true) == iCount);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      while (true) {
Shinya Kitaoka 120a6e
        // Subdivide current interval
Shinya Kitaoka 120a6e
        double mid = 0.5 * (xIn + xOut);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (scanlineIntersectionsBefore(mid, y, true) == iCount)
Shinya Kitaoka 120a6e
          xIn = mid;
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          xOut = mid;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (std::abs(xOut - xIn) < tol) break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    void isolateBorderY(double x, double &yIn, double &yOut, int iCount,
Shinya Kitaoka 120a6e
                        const double tol) {
Shinya Kitaoka 120a6e
      assert(scanlineIntersectionsBefore(x, yIn, false) == iCount);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      while (true) {
Shinya Kitaoka 120a6e
        // Subdivide current interval
Shinya Kitaoka 120a6e
        double mid = 0.5 * (yIn + yOut);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (scanlineIntersectionsBefore(x, mid, false) == iCount)
Shinya Kitaoka 120a6e
          yIn = mid;
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          yOut = mid;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (std::abs(yOut - yIn) < tol) break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int scanlineIntersectionsBefore(double x, double y, bool hor) {
Shinya Kitaoka 120a6e
      int result = m_region.scanlineIntersectionsBefore(x, y, hor);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      UINT sr, srCount = m_region.getSubregionCount();
Shinya Kitaoka 120a6e
      for (sr = 0; sr != srCount; ++sr)
Shinya Kitaoka 120a6e
        result +=
Shinya Kitaoka 120a6e
            m_region.getSubregion(sr)->scanlineIntersectionsBefore(x, y, hor);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      return result;
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  } locals = {ras, sel, inverse, c.m_thickScale, *region};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(region);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const TRectD ®ionBBox = region->getBBox();
Shinya Kitaoka 120a6e
  double regionMidY        = 0.5 * (regionBBox.y0 + regionBBox.y1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int ic, icEnd = tceil((regionBBox.x1 - regionBBox.x0) / c.m_thickScale) +
Shinya Kitaoka 120a6e
                  1;  // Say you have 4 pixels, in [0, 4]. We want to
Shinya Kitaoka 120a6e
                      // have at least 4 intervals where midpoints are
Shinya Kitaoka 120a6e
                      // taken - so end intervals count is 5.
Shinya Kitaoka 120a6e
  for (ic = 1; ic < icEnd; ic *= 2) {
Shinya Kitaoka 120a6e
    if (locals.sampleMidpoints(p, regionBBox.x0, regionBBox.x1, regionMidY, ic))
Shinya Kitaoka 120a6e
      return true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//(Daniele)
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Taking lone, unchecked points is dangerous - they could lie inside
Shinya Kitaoka 120a6e
// region r and still have a wrong color (for example, if they lie
Toshihiro Shimizu 890ddd
//*on* a boundary stroke).
Shinya Kitaoka 120a6e
// Plus, over-threshold regions should always be considered black.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// In order to improve this, we search a 4way-local-brightest
Shinya Kitaoka 120a6e
// neighbour of p. Observe that, however, it may still lie outside r;
Shinya Kitaoka 120a6e
// would that happen, p was not significative in the first place.
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline TPixel32 takeLocalBrightest(const TRaster32P rr, TRegion *r,
Shinya Kitaoka 120a6e
                                   const VectorizerConfiguration &c,
Shinya Kitaoka 120a6e
                                   TPoint &p) {
Shinya Kitaoka 120a6e
  TPoint pMax;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  while (r->contains(c.m_affine * convert(p))) {
Shinya Kitaoka 120a6e
    pMax = p;
Shinya Kitaoka 120a6e
    if (p.x > 0 && rr->pixels(p.y)[p.x - 1] > rr->pixels(pMax.y)[pMax.x])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x - 1, p.y);
Shinya Kitaoka 120a6e
    if (p.x < rr->getLx() - 1 &&
Shinya Kitaoka 120a6e
        rr->pixels(p.y)[p.x + 1] > rr->pixels(pMax.y)[pMax.x])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x + 1, p.y);
Shinya Kitaoka 120a6e
    if (p.y > 0 && rr->pixels(p.y - 1)[p.x] > rr->pixels(pMax.y)[pMax.x])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x, p.y - 1);
Shinya Kitaoka 120a6e
    if (p.y < rr->getLy() - 1 &&
Shinya Kitaoka 120a6e
        rr->pixels(p.y + 1)[p.x] > rr->pixels(pMax.y)[pMax.x])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x, p.y + 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (p == pMax) break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    p = pMax;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!isBright(rr->pixels(p.y)[p.x], c.m_threshold))
Shinya Kitaoka 120a6e
    return TPixel32::Black;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return rr->pixels(p.y)[p.x];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline TPixel32 takeLocalBrightest(const TRasterGR8P rgr, TRegion *r,
Shinya Kitaoka 120a6e
                                   const VectorizerConfiguration &c,
Shinya Kitaoka 120a6e
                                   TPoint &p) {
Shinya Kitaoka 120a6e
  TPoint pMax;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  while (r->contains(c.m_affine * convert(p))) {
Shinya Kitaoka 120a6e
    pMax = p;
Shinya Kitaoka 120a6e
    if (p.x > 0 && rgr->pixels(pMax.y)[pMax.x] < rgr->pixels(p.y)[p.x - 1])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x - 1, p.y);
Shinya Kitaoka 120a6e
    if (p.x < rgr->getLx() - 1 &&
Shinya Kitaoka 120a6e
        rgr->pixels(pMax.y)[pMax.x] < rgr->pixels(p.y)[p.x + 1])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x + 1, p.y);
Shinya Kitaoka 120a6e
    if (p.y > 0 && rgr->pixels(pMax.y)[pMax.x] < rgr->pixels(p.y - 1)[p.x])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x, p.y - 1);
Shinya Kitaoka 120a6e
    if (p.y < rgr->getLy() - 1 &&
Shinya Kitaoka 120a6e
        rgr->pixels(pMax.y)[pMax.x] < rgr->pixels(p.y + 1)[p.x])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x, p.y + 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (p == pMax) break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    p = pMax;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!isBright(rgr->pixels(p.y)[p.x], c.m_threshold))
Shinya Kitaoka 120a6e
    return TPixel32::Black;
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    int val = rgr->pixels(p.y)[p.x].value;
Shinya Kitaoka 120a6e
    return TPixel32(val, val, val, 255);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline TPixel32 takeLocalDarkest(const TRaster32P rr, TRegion *r,
Shinya Kitaoka 120a6e
                                 const VectorizerConfiguration &c, TPoint &p) {
Shinya Kitaoka 120a6e
  TPoint pMax;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  while (r->contains(c.m_affine * convert(p)))  // 1
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    pMax = p;
Shinya Kitaoka 120a6e
    if (p.x > 0 && rr->pixels(p.y)[p.x - 1] < rr->pixels(pMax.y)[pMax.x])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x - 1, p.y);
Shinya Kitaoka 120a6e
    if (p.x < rr->getLx() - 1 &&
Shinya Kitaoka 120a6e
        rr->pixels(p.y)[p.x + 1] < rr->pixels(pMax.y)[pMax.x])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x + 1, p.y);
Shinya Kitaoka 120a6e
    if (p.y > 0 && rr->pixels(p.y - 1)[p.x] < rr->pixels(pMax.y)[pMax.x])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x, p.y - 1);
Shinya Kitaoka 120a6e
    if (p.y < rr->getLy() - 1 &&
Shinya Kitaoka 120a6e
        rr->pixels(p.y + 1)[p.x] < rr->pixels(pMax.y)[pMax.x])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x, p.y + 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (p == pMax) break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    p = pMax;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return rr->pixels(p.y)[p.x];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline TPixel32 takeLocalDarkest(const TRasterGR8P rgr, TRegion *r,
Shinya Kitaoka 120a6e
                                 const VectorizerConfiguration &c, TPoint &p) {
Shinya Kitaoka 120a6e
  TPoint pMax;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  while (r->contains(c.m_affine * convert(p))) {
Shinya Kitaoka 120a6e
    pMax = p;
Shinya Kitaoka 120a6e
    if (p.x > 0 && rgr->pixels(p.y)[p.x - 1] < rgr->pixels(pMax.y)[pMax.x])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x - 1, p.y);
Shinya Kitaoka 120a6e
    if (p.x < rgr->getLx() - 1 &&
Shinya Kitaoka 120a6e
        rgr->pixels(p.y)[p.x + 1] < rgr->pixels(pMax.y)[pMax.x])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x + 1, p.y);
Shinya Kitaoka 120a6e
    if (p.y > 0 && rgr->pixels(p.y - 1)[p.x] < rgr->pixels(pMax.y)[pMax.x])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x, p.y - 1);
Shinya Kitaoka 120a6e
    if (p.y < rgr->getLy() - 1 &&
Shinya Kitaoka 120a6e
        rgr->pixels(p.y + 1)[p.x] < rgr->pixels(pMax.y)[pMax.x])
Shinya Kitaoka 120a6e
      pMax = TPoint(p.x, p.y + 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (p == pMax) break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    p = pMax;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int val = rgr->pixels(p.y)[p.x].value;
Shinya Kitaoka 120a6e
  return TPixel32(val, val, val, 255);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=================================================================
Toshihiro Shimizu 890ddd
//  Vectorizer Core
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void VectorizerCore::applyFillColors(TRegion *r, const TRasterP &ras,
Shinya Kitaoka 120a6e
                                     TPalette *palette,
Shinya Kitaoka 120a6e
                                     const CenterlineConfiguration &c,
Shinya Kitaoka 120a6e
                                     int regionCount) {
otakuto 91a93e
  auto const alwaysTrue = [](const TPixelCM32 &) { return true; };
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterCM32P rt = ras;
Shinya Kitaoka 120a6e
  TRaster32P rr   = ras;
Shinya Kitaoka 120a6e
  TRasterGR8P rgr = ras;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(rt || rr || rgr);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool isBrightRegion = true;
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    unsigned int e, edgesCount = r->getEdgeCount();
Shinya Kitaoka 120a6e
    for (e = 0; e < edgesCount; ++e) {
Shinya Kitaoka 120a6e
      if (isInkRegionEdge(r->getEdge(e)->m_s)) {
Shinya Kitaoka 120a6e
        if (r->getEdge(e)->m_w0 > r->getEdge(e)->m_w1) isBrightRegion = false;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (isInkRegionEdgeReversed(r->getEdge(e)->m_s)) {
Shinya Kitaoka 120a6e
        if (r->getEdge(e)->m_w0 < r->getEdge(e)->m_w1) isBrightRegion = false;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TAffine inverse = c.m_affine.inv();
Shinya Kitaoka 120a6e
  TPointD pd;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  typedef bool (*cm_func)(const TPixelCM32 &, int);
Shinya Kitaoka 120a6e
  typedef bool (*rgbm_func)(const TPixelRGBM32 &, int);
Shinya Kitaoka 120a6e
  typedef bool (*gr_func)(const TPixelGR8 &, int);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool tookPoint =
Shinya Kitaoka 120a6e
      isBrightRegion
otakuto 91a93e
          ? rt ? getInternalPoint(
otakuto 91a93e
                     rt,
otakuto 91a93e
                     std::bind(cm_func(isBright), std::placeholders::_1,
otakuto 91a93e
                               c.m_threshold),
otakuto 91a93e
                     inverse, c, r, pd) ||
otakuto 91a93e
                     // If no bright pixel could be found,
otakuto 91a93e
                     getInternalPoint(rt, alwaysTrue, inverse, c, r,
otakuto 91a93e
                                      pd)
otakuto 91a93e
               :  // then any pixel inside the region
Shinya Kitaoka 120a6e
                rr ? getInternalPoint(
otakuto 91a93e
                         rr,
otakuto 91a93e
                         std::bind(rgbm_func(isBright), std::placeholders::_1,
otakuto 91a93e
                                   c.m_threshold),
Shinya Kitaoka 120a6e
                         inverse, c, r, pd)
Shinya Kitaoka 120a6e
                   :  // must suffice.
Shinya Kitaoka 120a6e
                    getInternalPoint(
otakuto 91a93e
                        rgr,
otakuto 91a93e
                        std::bind(gr_func(isBright), std::placeholders::_1,
otakuto 91a93e
                                  c.m_threshold),
Shinya Kitaoka 120a6e
                        inverse, c, r, pd)
otakuto 91a93e
          : rt ? getInternalPoint(
otakuto 91a93e
                     rt,
otakuto 91a93e
                     std::bind(cm_func(isDark), std::placeholders::_1,
otakuto 91a93e
                               c.m_threshold),
otakuto 91a93e
                     inverse, c, r, pd)
Shinya Kitaoka 120a6e
               : rr ? getInternalPoint(
otakuto 91a93e
                          rr,
otakuto 91a93e
                          std::bind(rgbm_func(isDark), std::placeholders::_1,
otakuto 91a93e
                                    c.m_threshold),
Shinya Kitaoka 120a6e
                          inverse, c, r, pd)
Shinya Kitaoka 120a6e
                    : getInternalPoint(
otakuto 91a93e
                          rgr,
otakuto 91a93e
                          std::bind(gr_func(isDark), std::placeholders::_1,
otakuto 91a93e
                                    c.m_threshold),
Shinya Kitaoka 120a6e
                          inverse, c, r, pd);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (tookPoint) {
Shinya Kitaoka 120a6e
    pd = inverse * pd;
Shinya Kitaoka 120a6e
    TPoint p(pd.x, pd.y);  // The same thing that happened inside
Shinya Kitaoka 120a6e
                           // getInternalPoint()
Shinya Kitaoka 120a6e
    if (ras->getBounds().contains(p)) {
Shinya Kitaoka 120a6e
      int styleId = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (rt) {
Shinya Kitaoka 120a6e
        TPixelCM32 col = rt->pixels(p.y)[p.x];
Shinya Kitaoka 120a6e
        styleId        = isBrightRegion
Shinya Kitaoka 120a6e
                      ? col.getPaint()
Shinya Kitaoka 120a6e
                      : col.getInk();  // Only paint colors with centerline
Shinya Kitaoka 120a6e
      }                                // vectorization
Shinya Kitaoka 120a6e
      else {
Shinya Kitaoka 120a6e
        TPixel32 color;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // Update color found to local brightness-extremals
Shinya Kitaoka 120a6e
        if (rr) {
Shinya Kitaoka 120a6e
          color = isBrightRegion ? takeLocalBrightest(rr, r, c, p)
Shinya Kitaoka 120a6e
                                 : takeLocalDarkest(rr, r, c, p);
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          color = isBrightRegion ? takeLocalBrightest(rgr, r, c, p)
Shinya Kitaoka 120a6e
                                 : takeLocalDarkest(rgr, r, c, p);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (color.m != 0) {
Shinya Kitaoka 120a6e
          styleId           = palette->getClosestStyle(color);
Shinya Kitaoka 120a6e
          TPixel32 oldColor = palette->getStyle(styleId)->getMainColor();
Shinya Kitaoka 120a6e
          if (!(isAlmostZero(double(oldColor.r - color.r), 15.0) &&
Shinya Kitaoka 120a6e
                isAlmostZero(double(oldColor.g - color.g), 15.0) &&
Shinya Kitaoka 120a6e
                isAlmostZero(double(oldColor.b - color.b), 15.0))) {
Shinya Kitaoka 120a6e
            styleId = palette->getStyleCount();
Shinya Kitaoka 120a6e
            palette->getStylePage(1)->insertStyle(1, color);
Shinya Kitaoka 120a6e
            palette->setStyle(styleId, color);
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      ++regionCount;
Shinya Kitaoka 120a6e
      r->setStyle(styleId);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)r->getSubregionCount(); ++i)
Shinya Kitaoka 120a6e
    applyFillColors(r->getSubregion(i), ras, palette, c, regionCount);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------
shun-iwasawa 21f942
/*
Shinya Kitaoka 120a6e
void VectorizerCore::applyFillColors(TRegion *r, const TRasterP &ras,
Shinya Kitaoka 120a6e
                                     TPalette *palette,
Shinya Kitaoka 120a6e
                                     const OutlineConfiguration &c,
Shinya Kitaoka 120a6e
                                     int regionCount) {
Shinya Kitaoka 120a6e
  TRasterCM32P rt = ras;
Shinya Kitaoka 120a6e
  TRaster32P rr   = ras;
Shinya Kitaoka 120a6e
  TRasterGR8P rgr = ras;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(rt || rr || rgr);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TAffine inverse = c.m_affine.inv();
Shinya Kitaoka 120a6e
  bool doInks = !c.m_ignoreInkColors, doPaints = !c.m_leaveUnpainted;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Retrieve a point inside the specified region
Shinya Kitaoka 120a6e
  TPointD pd;
Shinya Kitaoka 120a6e
  if (r->getInternalPoint(pd)) {
Shinya Kitaoka 120a6e
    pd = inverse * pd;     // Convert point to raster coordinates
Shinya Kitaoka 120a6e
    TPoint p(pd.x, pd.y);  //
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Retrieve the corresponding pixel in the raster image
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (ras->getBounds().contains(p)) {
Shinya Kitaoka 120a6e
      int styleId = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (rt) {
Shinya Kitaoka 120a6e
        // Toonz colormap case
Shinya Kitaoka 120a6e
        TPixelCM32 col =
Shinya Kitaoka 120a6e
            rt->pixels(p.y)[p.x];  // In the outline vectorization case, color
Shinya Kitaoka 120a6e
        int tone = col.getTone();  // can be either ink or paint
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (tone == 0)  // Full ink case
Shinya Kitaoka 120a6e
          styleId = doInks ? col.getInk() : 1;
Shinya Kitaoka 120a6e
        else if (tone == 255 && doPaints)  // Full paint case
Shinya Kitaoka 120a6e
          styleId = col.getPaint();
Shinya Kitaoka 120a6e
        else if (tone != 255) {
Shinya Kitaoka 120a6e
          if (regionCount % 2 == 1) {
Shinya Kitaoka 120a6e
            // Whenever regionCount is odd, ink is checked first
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
            if (isNearestInkOrPaintInRegion(true, rt, r, c.m_affine, p))
Shinya Kitaoka 120a6e
              styleId = doInks ? col.getInk() : 1;
Shinya Kitaoka 120a6e
            else if (doPaints &&
Shinya Kitaoka 120a6e
                     isNearestInkOrPaintInRegion(false, rt, r, c.m_affine, p))
Shinya Kitaoka 120a6e
              styleId = col.getPaint();
Shinya Kitaoka 120a6e
          } else {
Shinya Kitaoka 120a6e
            // Whenever regionCount is even, paint is checked first
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
            if (doPaints &&
Shinya Kitaoka 120a6e
                isNearestInkOrPaintInRegion(false, rt, r, c.m_affine, p))
Shinya Kitaoka 120a6e
              styleId = col.getPaint();
Shinya Kitaoka 120a6e
            else if (isNearestInkOrPaintInRegion(true, rt, r, c.m_affine, p))
Shinya Kitaoka 120a6e
              styleId = doInks ? col.getInk() : 1;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        TPixel32 color;
Shinya Kitaoka 120a6e
        if (rr)
Shinya Kitaoka 120a6e
          color = rr->pixels(p.y)[p.x];
Shinya Kitaoka 120a6e
        else {
Shinya Kitaoka 120a6e
          int val = rgr->pixels(p.y)[p.x].value;
Shinya Kitaoka 120a6e
          color   = (val < 80) ? TPixel32::Black : TPixel32::White;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if ((color.m != 0) && ((!c.m_leaveUnpainted) ||
Shinya Kitaoka 120a6e
                               (c.m_leaveUnpainted && color == c.m_inkColor))) {
Shinya Kitaoka 120a6e
          styleId           = palette->getClosestStyle(color);
Shinya Kitaoka 120a6e
          TPixel32 oldColor = palette->getStyle(styleId)->getMainColor();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (!(isAlmostZero(double(oldColor.r - color.r), 15.0) &&
Shinya Kitaoka 120a6e
                isAlmostZero(double(oldColor.g - color.g), 15.0) &&
Shinya Kitaoka 120a6e
                isAlmostZero(double(oldColor.b - color.b), 15.0))) {
Shinya Kitaoka 120a6e
            styleId = palette->getStyleCount();
Shinya Kitaoka 120a6e
            palette->getStylePage(1)->insertStyle(1, color);
Shinya Kitaoka 120a6e
            palette->setStyle(styleId, color);
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      ++regionCount;
Shinya Kitaoka 120a6e
      r->setStyle(styleId);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)r->getSubregionCount(); ++i)
Shinya Kitaoka 120a6e
    applyFillColors(r->getSubregion(i), ras, palette, c, regionCount);
Toshihiro Shimizu 890ddd
}
shun-iwasawa 21f942
*/
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void VectorizerCore::applyFillColors(TVectorImageP vi, const TImageP &img,
Shinya Kitaoka 120a6e
                                     TPalette *palette,
Shinya Kitaoka 120a6e
                                     const VectorizerConfiguration &c) {
Shinya Kitaoka 120a6e
  const CenterlineConfiguration ¢Conf =
Shinya Kitaoka 120a6e
      static_cast<const &="" centerlineconfiguration="">(c);</const>
shun-iwasawa 21f942
  // const OutlineConfiguration &outConf =
shun-iwasawa 21f942
  //    static_cast<const &="" outlineconfiguration="">(c);</const>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // If configuration is not set for color fill at all, quit.
shun-iwasawa 21f942
  if (c.m_leaveUnpainted && !c.m_outline && !c.m_alignBoundaryStrokesDirection)
shun-iwasawa 21f942
    return;
shun-iwasawa 21f942
  // if (c.m_leaveUnpainted && (!c.m_outline || outConf.m_ignoreInkColors))
shun-iwasawa 21f942
  // return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TToonzImageP ti  = img;
Shinya Kitaoka 120a6e
  TRasterImageP ri = img;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(ti || ri);
Shinya Kitaoka 120a6e
  TRasterP ras = ti ? TRasterP(ti->getRaster()) : TRasterP(ri->getRaster());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  vi->findRegions();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int r, regionsCount = vi->getRegionCount();
shun-iwasawa 21f942
  // filling colors in outline mode is done in tnewoutlinevectorize.cpp
shun-iwasawa 21f942
  // if (c.m_outline) {
shun-iwasawa 21f942
  //  for (r = 0; r < regionsCount; ++r)
shun-iwasawa 21f942
  //    applyFillColors(vi->getRegion(r), ras, palette, outConf, 1);
shun-iwasawa 21f942
  //} else {
shun-iwasawa 21f942
  for (r = 0; r < regionsCount; ++r)
shun-iwasawa 21f942
    applyFillColors(vi->getRegion(r), ras, palette, centConf,
shun-iwasawa 21f942
                    1);  // 1 - c.m_makeFrame;
shun-iwasawa 21f942
shun-iwasawa 21f942
  clearInkRegionFlags(vi);
shun-iwasawa 21f942
  //}
shun-iwasawa 21f942
}
shun-iwasawa 21f942
shun-iwasawa 21f942
namespace {
shun-iwasawa 21f942
struct StrokeData {
shun-iwasawa 21f942
  UCHAR m_hasColor, m_hasRegion;
shun-iwasawa 21f942
};
shun-iwasawa 21f942
shun-iwasawa 21f942
// found the shape boundaries and recognize their stroke direction.
shun-iwasawa 21f942
// based on the function getBoundaries() in levelselection.cpp
shun-iwasawa 21f942
void alignBoundariesDirection(TVectorImageP vi) {
shun-iwasawa 21f942
  enum { FORWARD = 0x1, BACKWARD = 0x2, INTERNAL = FORWARD | BACKWARD };
shun-iwasawa 21f942
shun-iwasawa 21f942
  struct locals {
shun-iwasawa 21f942
    static void markEdges(const TRegion ®ion, std::vector<strokedata> &sData,</strokedata>
shun-iwasawa 21f942
                          bool parentRegionHasColor) {
shun-iwasawa 21f942
      bool regionHasColor = (region.getStyle() != 0);
shun-iwasawa 21f942
shun-iwasawa 21f942
      // Traverse region edges, marking associated strokes accordingly
shun-iwasawa 21f942
      UINT e, eCount = region.getEdgeCount();
shun-iwasawa 21f942
      for (e = 0; e != eCount; ++e) {
shun-iwasawa 21f942
        const TEdge &ed = *region.getEdge(e);
shun-iwasawa 21f942
        assert(ed.m_s);
shun-iwasawa 21f942
shun-iwasawa 21f942
        int strokeIdx = ed.m_index;
shun-iwasawa 21f942
        if (strokeIdx >= 0)  // Could be <0 in case the corresponding
shun-iwasawa 21f942
        {                    // stroke is a region 'closure' (autoclose)
shun-iwasawa 21f942
          assert(0 <= strokeIdx && strokeIdx < sData.size());
shun-iwasawa 21f942
shun-iwasawa 21f942
          StrokeData &sd = sData[strokeIdx];
shun-iwasawa 21f942
shun-iwasawa 21f942
          UCHAR side = (ed.m_w1 > ed.m_w0) ? FORWARD : BACKWARD;
shun-iwasawa 21f942
shun-iwasawa 21f942
          sd.m_hasRegion |= side;
shun-iwasawa 21f942
          if (regionHasColor) sd.m_hasColor |= side;
shun-iwasawa 21f942
        }
shun-iwasawa 21f942
      }
shun-iwasawa 21f942
shun-iwasawa 21f942
      if (parentRegionHasColor) {
shun-iwasawa 21f942
        // Mark non-region edge sides with color
shun-iwasawa 21f942
        for (e = 0; e != eCount; ++e) {
shun-iwasawa 21f942
          const TEdge &ed = *region.getEdge(e);
shun-iwasawa 21f942
          assert(ed.m_s);
shun-iwasawa 21f942
shun-iwasawa 21f942
          int strokeIdx = ed.m_index;
shun-iwasawa 21f942
          if (strokeIdx >= 0) {
shun-iwasawa 21f942
            StrokeData &sd = sData[strokeIdx];
shun-iwasawa 21f942
            sd.m_hasColor |= (INTERNAL & ~sd.m_hasRegion);
shun-iwasawa 21f942
          }
shun-iwasawa 21f942
        }
shun-iwasawa 21f942
      }
shun-iwasawa 21f942
shun-iwasawa 21f942
      // Mark recursively on sub-regions
shun-iwasawa 21f942
      UINT sr, srCount = region.getSubregionCount();
shun-iwasawa 21f942
      for (sr = 0; sr != srCount; ++sr)
shun-iwasawa 21f942
        markEdges(*region.getSubregion(sr), sData, regionHasColor);
shun-iwasawa 21f942
    }
shun-iwasawa 21f942
  };  // locals
shun-iwasawa 21f942
shun-iwasawa 21f942
  std::vector<strokedata> sData(vi->getStrokeCount());</strokedata>
shun-iwasawa 21f942
shun-iwasawa 21f942
  // Traverse regions, mark each stroke edge with the side a COLORED region is
shun-iwasawa 21f942
  // on
shun-iwasawa 21f942
  UINT r, rCount = vi->getRegionCount();
shun-iwasawa 21f942
  for (r = 0; r != rCount; ++r)
shun-iwasawa 21f942
    locals::markEdges(*vi->getRegion(r), sData, false);
shun-iwasawa 21f942
shun-iwasawa 21f942
  UINT s, sCount = vi->getStrokeCount();
shun-iwasawa 21f942
  for (s = 0; s != sCount; ++s) {
shun-iwasawa 21f942
    // Strokes not appearing as region edges must be checked for region
shun-iwasawa 21f942
    // inclusion separately
shun-iwasawa 21f942
    if (!sData[s].m_hasRegion) {
shun-iwasawa 21f942
      TRegion *parentRegion = vi->getRegion(vi->getStroke(s)->getPoint(0.5));
shun-iwasawa 21f942
shun-iwasawa 21f942
      if (parentRegion && parentRegion->getStyle())
shun-iwasawa 21f942
        sData[s].m_hasColor = INTERNAL;
shun-iwasawa 21f942
    }
shun-iwasawa 21f942
shun-iwasawa 21f942
    // flip the stroke here
shun-iwasawa 21f942
    if (sData[s].m_hasColor == FORWARD) vi->getStroke(s)->changeDirection();
shun-iwasawa 21f942
  }
shun-iwasawa 21f942
}
shun-iwasawa 21f942
void removeFillColors(TRegion *r) {
shun-iwasawa 21f942
  UINT i, edgeCount = r->getEdgeCount();
shun-iwasawa 21f942
  for (i = 0; i < edgeCount; ++i) {
shun-iwasawa 21f942
    r->getEdge(i)->setStyle(0);
Shinya Kitaoka 120a6e
  }
shun-iwasawa 21f942
  // Build the color for its sub-regions
shun-iwasawa 21f942
  int j, rCount = r->getSubregionCount();
shun-iwasawa 21f942
  for (j = 0; j < rCount; ++j) removeFillColors(r->getSubregion(j));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
shun-iwasawa 21f942
void removeFillColors(TVectorImageP vi) {
shun-iwasawa 21f942
  int i, rCount = vi->getRegionCount();
shun-iwasawa 21f942
  for (i = 0; i < rCount; ++i) {
shun-iwasawa 21f942
    removeFillColors(vi->getRegion(i));
shun-iwasawa 21f942
  }
shun-iwasawa 21f942
}
shun-iwasawa 21f942
}  // namespace
shun-iwasawa 21f942
Toshihiro Shimizu 890ddd
//=================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TVectorImageP VectorizerCore::vectorize(const TImageP &img,
Shinya Kitaoka 120a6e
                                        const VectorizerConfiguration &c,
Shinya Kitaoka 120a6e
                                        TPalette *plt) {
Shinya Kitaoka 120a6e
  TVectorImageP vi;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (c.m_outline)
Shinya Kitaoka 120a6e
    vi = newOutlineVectorize(
Shinya Kitaoka 120a6e
        img, static_cast<const &="" newoutlineconfiguration="">(c), plt);</const>
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    TImageP img2(img);
Shinya Kitaoka 120a6e
    vi = centerlineVectorize(
Shinya Kitaoka 120a6e
        img2, static_cast<const &="" centerlineconfiguration="">(c), plt);</const>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (vi) {
Shinya Kitaoka 120a6e
      for (int i = 0; i < (int)vi->getStrokeCount(); ++i) {
Shinya Kitaoka 120a6e
        TStroke *stroke = vi->getStroke(i);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        for (int j = 0; j < stroke->getControlPointCount(); ++j) {
Shinya Kitaoka 120a6e
          TThickPoint p = stroke->getControlPoint(j);
Shinya Kitaoka 120a6e
          p             = TThickPoint(c.m_affine * p, c.m_thickScale * p.thick);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
          stroke->setControlPoint(j, p);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      applyFillColors(vi, img2, plt, c);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
shun-iwasawa 21f942
  // align boundary strokes direction
shun-iwasawa 21f942
  if (c.m_alignBoundaryStrokesDirection) {
shun-iwasawa 21f942
    alignBoundariesDirection(vi);
shun-iwasawa 21f942
    vi->validateRegions(false);
shun-iwasawa 21f942
    vi->findRegions();
shun-iwasawa 21f942
    if (c.m_leaveUnpainted) removeFillColors(vi);
shun-iwasawa 21f942
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return vi;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void VectorizerCore::emitPartialDone(void) {
Shinya Kitaoka 120a6e
  emit partialDone(m_currPartial++, m_totalPartials);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
void VectorizerCore::emitPartialDone(int current)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
  m_currPartial= current;
Toshihiro Shimizu 890ddd
  emit partialDone(current, m_totalPartials);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
*/