Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Toonz includes
Toshihiro Shimizu 890ddd
#include "tgeometry.h"
Toshihiro Shimizu 890ddd
#include "tpalette.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "tregion.h"
Toshihiro Shimizu 890ddd
#include "tcolorutils.h"
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
#include "ttoonzimage.h"
Toshihiro Shimizu 890ddd
#include "trop.h"
Toshihiro Shimizu 890ddd
#include "trop_borders.h"
Toshihiro Shimizu 890ddd
#include "tstrokeutil.h"
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// template includes
Toshihiro Shimizu 890ddd
#define INCLUDE_HPP
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// tcg includes
Toshihiro Shimizu 890ddd
#include "tcg_wrap.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_vertex.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_edge.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_face.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_mesh.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_hash.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_polylineops.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_sequence_ops.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_cyclic.h"
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Toonz includes
Shinya Kitaoka 810553
#include "../common/trop/raster_edge_evaluator.hpp"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#undef INCLUDE_HPP
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// STL includes
Toshihiro Shimizu 890ddd
#include <set></set>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/tcenterlinevectorizer.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace stuff
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
//    Colors stuff
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix=""></typename>
Toshihiro Shimizu 890ddd
Pix transparent();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <>
Shinya Kitaoka 120a6e
inline TPixel32 transparent<tpixel32>() {</tpixel32>
Shinya Kitaoka 120a6e
  return TPixel32::Transparent;
Shinya Kitaoka 120a6e
}
Toshihiro Shimizu 890ddd
template <>
Shinya Kitaoka 120a6e
inline TPixelGR16 transparent<tpixelgr16>() {</tpixelgr16>
Shinya Kitaoka 120a6e
  return TPixelGR16::Black;
Shinya Kitaoka 120a6e
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
//    Mesh stuff
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class Edge final : public tcg::Edge {
Shinya Kitaoka 120a6e
  TPoint m_dirs[2];
Shinya Kitaoka 120a6e
  TStroke *m_s;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  Edge() : tcg::Edge(), m_s(0) {}
Shinya Kitaoka 120a6e
  Edge(int v1, const TPoint &dir1, int v2, const TPoint &dir2)
Shinya Kitaoka 120a6e
      : tcg::Edge(v1, v2), m_s(0) {
Shinya Kitaoka 120a6e
    m_dirs[0] = dir1, m_dirs[1] = dir2;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TPoint &direction(int i) const { return m_dirs[i]; }
Shinya Kitaoka 120a6e
  TPoint &direction(int i) { return m_dirs[i]; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TStroke *stroke() const { return m_s; }
Shinya Kitaoka 120a6e
  void setStroke(TStroke *s) { m_s = s; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef tcg::Mesh<tcg::vertex<tpoint>, Edge, tcg::Face> LocalMesh;</tcg::vertex<tpoint>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int hashPoint(const TPoint &point) { return point.x ^ point.y; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef int (*PointHashType)(const TPoint &);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
size_t hashStroke(const TStroke *stroke) { return (size_t)stroke; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef size_t (*StrokeHashType)(const TStroke *);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
//    Vertex Adjustment
Toshihiro Shimizu 890ddd
//===========================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct Sums {
Shinya Kitaoka 120a6e
  double m_sums_x, m_sums_y;
Shinya Kitaoka 120a6e
  double m_sums2_x, m_sums2_y;
Shinya Kitaoka 120a6e
  double m_sums_xy;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct SumsBuilder {
Shinya Kitaoka 120a6e
  const std::vector<double> &m_sums_x, &m_sums_y, &m_sums2_x, &m_sums2_y,</double>
Shinya Kitaoka 120a6e
      &m_sums_xy;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  SumsBuilder(const std::vector<double> &sums_x,</double>
Shinya Kitaoka 120a6e
              const std::vector<double> &sums_y,</double>
Shinya Kitaoka 120a6e
              const std::vector<double> &sums2_x,</double>
Shinya Kitaoka 120a6e
              const std::vector<double> &sums2_y,</double>
Shinya Kitaoka 120a6e
              const std::vector<double> &sums_xy)</double>
Shinya Kitaoka 120a6e
      : m_sums_x(sums_x)
Shinya Kitaoka 120a6e
      , m_sums_y(sums_y)
Shinya Kitaoka 120a6e
      , m_sums2_x(sums2_x)
Shinya Kitaoka 120a6e
      , m_sums2_y(sums2_y)
Shinya Kitaoka 120a6e
      , m_sums_xy(sums_xy) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void build(Sums &sums, int idx0, int idx1) const {
Shinya Kitaoka 120a6e
    sums.m_sums_x  = m_sums_x[idx1] - m_sums_x[idx0];
Shinya Kitaoka 120a6e
    sums.m_sums_y  = m_sums_y[idx1] - m_sums_y[idx0];
Shinya Kitaoka 120a6e
    sums.m_sums2_x = m_sums2_x[idx1] - m_sums2_x[idx0];
Shinya Kitaoka 120a6e
    sums.m_sums2_y = m_sums2_y[idx1] - m_sums2_y[idx0];
Shinya Kitaoka 120a6e
    sums.m_sums_xy = m_sums_xy[idx1] - m_sums_xy[idx0];
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename p1_type,="" p2_type="" typename=""></typename>
Shinya Kitaoka 120a6e
void adjustVertex(const TPointD &origin, TPointD &point, P1_type p0,
Shinya Kitaoka 120a6e
                  Sums &sums0, int n0, P2_type p1, Sums &sums1, int n1) {
Shinya Kitaoka 120a6e
  // Find the 2 best-fit lines
Shinya Kitaoka 120a6e
  TPointD v0, v1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  tcg::point_ops::bestFit(p0, v0, sums0.m_sums_x, sums0.m_sums_y,
Shinya Kitaoka 120a6e
                          sums0.m_sums2_x, sums0.m_sums2_y, sums0.m_sums_xy,
Shinya Kitaoka 120a6e
                          n0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  tcg::point_ops::bestFit(p1, v1, sums1.m_sums_x, sums1.m_sums_y,
Shinya Kitaoka 120a6e
                          sums1.m_sums2_x, sums1.m_sums2_y, sums1.m_sums_xy,
Shinya Kitaoka 120a6e
                          n1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Get the intersecting point
Shinya Kitaoka 120a6e
  double s, t;
Shinya Kitaoka 120a6e
  tcg::point_ops::intersectionCoords(p0, v0, p1, v1, s, t, 1e-3);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (s == tcg::numeric_ops::NaN<double>()) return;</double>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Adjust vertex - inside a 0.5 radius disc
Shinya Kitaoka 120a6e
  TPointD newPoint(origin + p0 + s * v0), diff(newPoint - point);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double distance = norm(diff);
Shinya Kitaoka 120a6e
  if (distance < 0.5)
Shinya Kitaoka 120a6e
    point = newPoint;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    point += (0.5 / distance) * diff;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void adjustVertices(const TPointD &origin, std::vector<tpointd> &points,</tpointd>
Shinya Kitaoka 120a6e
                    const std::vector<int> &indices,</int>
Shinya Kitaoka 120a6e
                    const std::vector<double> &sums_x,</double>
Shinya Kitaoka 120a6e
                    const std::vector<double> &sums_y,</double>
Shinya Kitaoka 120a6e
                    const std::vector<double> &sums2_x,</double>
Shinya Kitaoka 120a6e
                    const std::vector<double> &sums2_y,</double>
Shinya Kitaoka 120a6e
                    const std::vector<double> &sums_xy) {</double>
Shinya Kitaoka 120a6e
  int i, last = points.size() - 1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  SumsBuilder sumsBuilder(sums_x, sums_y, sums2_x, sums2_y, sums_xy);
Shinya Kitaoka 120a6e
  Sums sums0, sums1;
Shinya Kitaoka 120a6e
  int prev0, prev1, next0, next1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD a0, a1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (points.front() == points.back()) {
Shinya Kitaoka 120a6e
    prev0 = indices[last - 1] - 1, prev1 = indices[last],
Shinya Kitaoka 120a6e
    next0 = indices[0] - 1, next1 = indices[1];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    sumsBuilder.build(sums0, prev0, prev1);
Shinya Kitaoka 120a6e
    sumsBuilder.build(sums1, next0, next1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    adjustVertex<tpointd &="" &,="" tpointd="">(origin, points[0], a0, sums0,</tpointd>
Shinya Kitaoka 120a6e
                                       prev1 - prev0, a1, sums1, next1 - next0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    points[last] = points[0];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    for (i = 1; i < last; ++i) {
Shinya Kitaoka 120a6e
      prev0 = indices[i - 1] - 1, prev1 = indices[i], next0 = indices[i] - 1,
Shinya Kitaoka 120a6e
      next1 = indices[i + 1];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      sumsBuilder.build(sums0, prev0, prev1);
Shinya Kitaoka 120a6e
      sumsBuilder.build(sums1, next0, next1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      adjustVertex<tpointd &="" &,="" tpointd="">(origin, points[i], a0, sums0,</tpointd>
Shinya Kitaoka 120a6e
                                         prev1 - prev0, a1, sums1,
Shinya Kitaoka 120a6e
                                         next1 - next0);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    prev0 = indices[0], prev1 = indices[1], next0 = indices[1] - 1,
Shinya Kitaoka 120a6e
    next1 = indices[2];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    sumsBuilder.build(sums0, prev0, prev1);
Shinya Kitaoka 120a6e
    sumsBuilder.build(sums1, next0, next1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    a0 = points[0];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    adjustVertex<const &="" &,="" tpointd="">(origin, points[1], a0, sums0,</const>
Shinya Kitaoka 120a6e
                                             prev1 - prev0 + 1, a1, sums1,
Shinya Kitaoka 120a6e
                                             next1 - next0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    int end = last - 1;
Shinya Kitaoka 120a6e
    for (i = 2; i < end; ++i) {
Shinya Kitaoka 120a6e
      prev0 = indices[i - 1] - 1, prev1 = indices[i], next0 = indices[i] - 1,
Shinya Kitaoka 120a6e
      next1 = indices[i + 1];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      sumsBuilder.build(sums0, prev0, prev1);
Shinya Kitaoka 120a6e
      sumsBuilder.build(sums1, next0, next1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      adjustVertex<tpointd &="" &,="" tpointd="">(origin, points[i], a0, sums0,</tpointd>
Shinya Kitaoka 120a6e
                                         prev1 - prev0, a1, sums1,
Shinya Kitaoka 120a6e
                                         next1 - next0);
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    prev0 = indices[end - 1], prev1 = indices[end], next0 = indices[end] - 1,
Shinya Kitaoka 120a6e
    next1 = indices[last];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    sumsBuilder.build(sums0, prev0, prev1);
Shinya Kitaoka 120a6e
    sumsBuilder.build(sums1, next0, next1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    a1 = points[last];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    adjustVertex<const &="" &,="" tpointd="">(</const>
Shinya Kitaoka 120a6e
        origin, points[1], a1, sums1, next1 - next0, a0, sums0, prev1 - prev0);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    Borders Reader declaration
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename ranit=""></typename>
Shinya Kitaoka 120a6e
class PolylineReader {
Shinya Kitaoka 120a6e
  const NewOutlineConfiguration &m_conf;
Shinya Kitaoka 120a6e
  double m_adherenceTol, m_angleTol, m_relativeTol, m_mergeTol;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TVectorImageP m_vi;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<tpointd> m_points;</tpointd>
Shinya Kitaoka 120a6e
  std::vector<int> m_indices;</int>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const RasterEdgeEvaluator<ranit> *m_eval;</ranit>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  PolylineReader(TVectorImageP vi, const NewOutlineConfiguration &conf)
Shinya Kitaoka 120a6e
      : m_vi(vi)
Shinya Kitaoka 120a6e
      , m_conf(conf)
Shinya Kitaoka 120a6e
      , m_adherenceTol(2.0 * (1.0 - m_conf.m_adherenceTol))
Shinya Kitaoka 120a6e
      , m_angleTol(cos(M_PI * m_conf.m_angleTol))
Shinya Kitaoka 120a6e
      , m_relativeTol(conf.m_relativeTol)
Shinya Kitaoka 120a6e
      , m_mergeTol(m_conf.m_mergeTol) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void setEvaluator(const RasterEdgeEvaluator<ranit> *eval) { m_eval = eval; }</ranit>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void openContainer(const RanIt &it);
Shinya Kitaoka 120a6e
  void addElement(const RanIt &it);
Shinya Kitaoka 120a6e
  void openContainer(const TPoint &p) { addElement(p); }
Shinya Kitaoka 120a6e
  void addElement(const TPoint &p) { m_points.push_back(TPointD(p.x, p.y)); }
Shinya Kitaoka 120a6e
  void closeContainer();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    Borders Reader declaration
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix=""></typename>
Shinya Kitaoka d1f6c4
class BordersReader final : public TRop::borders::BordersReader {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  typedef Pix pixel_type;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  typedef TPoint point_type;
Shinya Kitaoka 120a6e
  typedef tcg::hash<tpoint, int,="" pointhashtype=""> points_hash;</tpoint,>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  typedef typename std::pair<pixel_type, pixel_type=""> stroke_colors_type;</pixel_type,>
Shinya Kitaoka 120a6e
  typedef
Shinya Kitaoka 120a6e
      typename tcg::hash<const *,="" stroke_colors_type,="" strokehashtype="" tstroke=""></const>
Shinya Kitaoka 120a6e
          stroke_colors_hash;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  typedef typename std::vector<tpoint>::iterator point_iterator;</tpoint>
Shinya Kitaoka 120a6e
  typedef typename tcg::cyclic_iterator<point_iterator> cyclic_point_iterator;</point_iterator>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  const TRasterPT<pixel_type> &m_ras;</pixel_type>
Shinya Kitaoka 120a6e
  int m_lx, m_ly, m_wrap;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  LocalMesh *m_mesh;
Shinya Kitaoka 120a6e
  PolylineReader<point_iterator> m_polylineReader;</point_iterator>
Shinya Kitaoka 120a6e
  PolylineReader<cyclic_point_iterator> m_loopReader;</cyclic_point_iterator>
Shinya Kitaoka 120a6e
  TVectorImageP m_vi;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  points_hash m_vHash;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  pixel_type m_innerColor, m_outerColor;
Shinya Kitaoka 120a6e
  stroke_colors_hash m_scHash;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Current data
Shinya Kitaoka 120a6e
  TPoint m_pos;
Shinya Kitaoka 120a6e
  pixel_type *m_pix;
Shinya Kitaoka 120a6e
  std::vector<tpoint> m_points;</tpoint>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Last vertex data
Shinya Kitaoka 120a6e
  TPoint m_dir;
Shinya Kitaoka 120a6e
  int m_vIdx;
Shinya Kitaoka 120a6e
  int m_nDirections;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // First vertex data
Shinya Kitaoka 120a6e
  TPoint m_firstPos, m_firstDir, m_firstOppDir;
Shinya Kitaoka 120a6e
  int m_firstVIdx;
Shinya Kitaoka 120a6e
  int m_firstNDirections;
Shinya Kitaoka 120a6e
  std::vector<tpoint> m_firstPoints;</tpoint>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  BordersReader(const TRasterPT<pixel_type> &ras, LocalMesh *mesh,</pixel_type>
Shinya Kitaoka 120a6e
                TVectorImageP vi, const NewOutlineConfiguration &conf)
Shinya Kitaoka 120a6e
      : m_mesh(mesh)
Shinya Kitaoka 120a6e
      , m_polylineReader(vi, conf)
Shinya Kitaoka 120a6e
      , m_loopReader(vi, conf)
Shinya Kitaoka 120a6e
      , m_vi(vi)
Shinya Kitaoka 120a6e
      , m_vHash(&hashPoint)
Shinya Kitaoka 120a6e
      , m_scHash(&hashStroke)
Shinya Kitaoka 120a6e
      , m_ras(ras)
Shinya Kitaoka 120a6e
      , m_lx(ras->getLx())
Shinya Kitaoka 120a6e
      , m_ly(ras->getLy())
Shinya Kitaoka 120a6e
      , m_wrap(ras->getWrap()) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void openContainer(const TPoint &pos, const TPoint &dir,
Shinya Kitaoka 120a6e
                     const pixel_type &innerColor,
Shinya Kitaoka 473e70
                     const pixel_type &outerColor) override;
Shinya Kitaoka 120a6e
  void addElement(const TPoint &pos, const TPoint &dir,
Shinya Kitaoka 473e70
                  const pixel_type &outerColor) override;
Shinya Kitaoka 473e70
  void closeContainer() override;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int surroundingEdges();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int touchVertex(const TPoint &pos);
Shinya Kitaoka 120a6e
  void touchEdge(int v0, const TPoint &d0, int nd0, int v1, const TPoint &d1,
Shinya Kitaoka 120a6e
                 int nd1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const stroke_colors_hash &scHash() const { return m_scHash; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    BordersReader implementation
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix=""></typename>
Shinya Kitaoka 120a6e
int ::BordersReader<pix>::surroundingEdges() {</pix>
Shinya Kitaoka 120a6e
  static const Pix transp(transparent<pix>());</pix>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  Pix ll((m_pos.x > 0 && m_pos.y > 0) ? *(m_pix - m_wrap - 1) : transp);
Shinya Kitaoka 120a6e
  Pix lr((m_pos.x < m_lx && m_pos.y > 0) ? *(m_pix - m_wrap) : transp);
Shinya Kitaoka 120a6e
  Pix ul((m_pos.x > 0 && m_pos.y < m_ly) ? *(m_pix - 1) : transp);
Shinya Kitaoka 120a6e
  Pix ur((m_pos.x < m_lx && m_pos.y < m_ly) ? *(m_pix) : transp);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (ll == ur || lr == ul) return 2;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int nEquals =
Shinya Kitaoka 120a6e
      (int)(ll == lr) + (int)(lr == ur) + (int)(ur == ul) + (int)(ul == ll);
Shinya Kitaoka 120a6e
  return 4 - nEquals;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix=""></typename>
Shinya Kitaoka 120a6e
int ::BordersReader<pix>::touchVertex(const TPoint &pos) {</pix>
Shinya Kitaoka 120a6e
  points_hash::iterator it = m_vHash.find(pos);
Shinya Kitaoka 120a6e
  if (it == m_vHash.end())
Shinya Kitaoka 120a6e
    // No vertex found, add it now.
Shinya Kitaoka 120a6e
    it = m_vHash.insert(m_pos, m_mesh->addVertex(LocalMesh::vertex_type(pos)));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return it->m_val;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix=""></typename>
Shinya Kitaoka 120a6e
void ::BordersReader<pix>::touchEdge(int v0, const TPoint &d0, int nd0, int v1,</pix>
Shinya Kitaoka 120a6e
                                     const TPoint &d1, int nd1) {
Shinya Kitaoka 120a6e
  typedef tcg::vertex_traits<localmesh::vertex_type>::edges_const_iterator</localmesh::vertex_type>
Shinya Kitaoka 120a6e
      edge_const_it;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Ensure that an associated edge is present, in case it should
Shinya Kitaoka 120a6e
  const LocalMesh::vertex_type &vx0 = m_mesh->vertex(v0);
Shinya Kitaoka 120a6e
  const LocalMesh::vertex_type &vx1 = m_mesh->vertex(v1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Peek each vertex edge, for the one with the right direction
Shinya Kitaoka 120a6e
  int e;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  edge_const_it it, end = vx1.edgesEnd();
Shinya Kitaoka 120a6e
  for (it = vx1.edgesBegin(); it != end; ++it) {
Shinya Kitaoka 120a6e
    Edge &ed = m_mesh->edge(*it);
Shinya Kitaoka 120a6e
    int side = (int)(ed.vertex(1) == v1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (ed.direction(side) == d1) {
Shinya Kitaoka 120a6e
      e = ed.getIndex();
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // If none was found, the edge must be added
Shinya Kitaoka 120a6e
  if (it == end) {
Shinya Kitaoka 120a6e
    e = m_mesh->addEdge(Edge(v0, d0, v1, d1));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Also, insert it in the output vector image
Shinya Kitaoka 120a6e
    if (m_points.size() == 2) {
Shinya Kitaoka 120a6e
      m_polylineReader.openContainer(m_points[0]);
Shinya Kitaoka 120a6e
      m_polylineReader.addElement(m_points[1]);
Shinya Kitaoka 120a6e
      m_polylineReader.closeContainer();
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      if (m_points.front() == m_points.back()) {
Shinya Kitaoka 120a6e
        point_iterator b = m_points.begin(), e = m_points.end() - 1;
Shinya Kitaoka 120a6e
        cyclic_point_iterator beginC(b, b, e, 0), endC(b + 1, b, e, 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        RasterEdgeEvaluator<cyclic_point_iterator> eval(</cyclic_point_iterator>
Shinya Kitaoka 120a6e
            beginC - 1, endC + 1, 1.0, (std::numeric_limits<double>::max)());</double>
Shinya Kitaoka 120a6e
        m_loopReader.setEvaluator(&eval);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        tcg::sequence_ops::minimalPath(beginC, endC, eval, m_loopReader);
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        RasterEdgeEvaluator<point_iterator> eval(</point_iterator>
Shinya Kitaoka 120a6e
            m_points.begin(), m_points.end(), 1.0,
Shinya Kitaoka 120a6e
            (std::numeric_limits<double>::max)());</double>
Shinya Kitaoka 120a6e
        m_polylineReader.setEvaluator(&eval);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        tcg::sequence_ops::minimalPath(m_points.begin(), m_points.end(), eval,
Shinya Kitaoka 120a6e
                                       m_polylineReader);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    Edge &ed = m_mesh->edge(e);
Shinya Kitaoka 120a6e
    ed.setStroke(m_vi->getStroke(m_vi->getStrokeCount() - 1));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Also, associate the extracted colors to the built stroke.
Shinya Kitaoka 120a6e
    stroke_colors_type &colors = m_scHash[ed.stroke()];
Shinya Kitaoka 120a6e
    colors.first               = m_outerColor;
Shinya Kitaoka 120a6e
    colors.second              = m_innerColor;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Finally, if the number of each vertex's incident edges has been reached,
Shinya Kitaoka 120a6e
  // erase the corresponding hash entry.
Shinya Kitaoka 120a6e
  /*{
Shinya Kitaoka 120a6e
if(nd0 == vx0.edgesCount())
Shinya Kitaoka 120a6e
m_vHash.erase(vx0.P());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
if(nd1 == vx1.edgesCount())
Shinya Kitaoka 120a6e
m_vHash.erase(vx1.P());
Shinya Kitaoka 120a6e
}*/
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix=""></typename>
Toshihiro Shimizu 890ddd
void ::BordersReader<pix>::openContainer(const TPoint &pos, const TPoint &dir,</pix>
Shinya Kitaoka 120a6e
                                         const pixel_type &innerColor,
Shinya Kitaoka 120a6e
                                         const pixel_type &outerColor) {
Shinya Kitaoka 120a6e
  // Store the associated color if not already present
Shinya Kitaoka 120a6e
  m_innerColor = innerColor;
Shinya Kitaoka 120a6e
  m_outerColor = outerColor;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build the initial pixel
Shinya Kitaoka 120a6e
  m_pos = pos;
Shinya Kitaoka 120a6e
  m_pix = m_ras->pixels(0) + m_ras->getWrap() * m_pos.y + m_pos.x;
Shinya Kitaoka 120a6e
  m_points.push_back(m_pos);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_dir         = dir;
Shinya Kitaoka 120a6e
  m_vIdx        = -1;
Shinya Kitaoka 120a6e
  m_nDirections = surroundingEdges();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_firstPos         = m_pos;
Shinya Kitaoka 120a6e
  m_firstDir         = m_dir;
Shinya Kitaoka 120a6e
  m_firstVIdx        = -1;
Shinya Kitaoka 120a6e
  m_firstNDirections = m_nDirections;
Shinya Kitaoka 120a6e
  m_firstOppDir      = TPoint(1, 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_nDirections > 2) {
Shinya Kitaoka 120a6e
    // Found mesh vertex. Retrieve the associated vertex
Shinya Kitaoka 120a6e
    m_vIdx        = touchVertex(m_pos);
Shinya Kitaoka 120a6e
    m_firstVIdx   = m_vIdx;
Shinya Kitaoka 120a6e
    m_firstPoints = m_points;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix=""></typename>
Shinya Kitaoka 120a6e
void ::BordersReader<pix>::addElement(const TPoint &pos, const TPoint &dir,</pix>
Shinya Kitaoka 120a6e
                                      const Pix &outerColor) {
Shinya Kitaoka 120a6e
  // Build opposite direction
Shinya Kitaoka 120a6e
  bool horizontal = (pos.y == m_pos.y);
Shinya Kitaoka 120a6e
  TPoint oppDir   = horizontal ? TPoint((pos.x > m_pos.x) ? -1 : 1, 0)
Shinya Kitaoka 120a6e
                             : TPoint(0, (pos.y > m_pos.y) ? -1 : 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Update position
Shinya Kitaoka 120a6e
  m_pix += horizontal ? (pos.x - m_pos.x) : (pos.y - m_pos.y) * m_wrap;
Shinya Kitaoka 120a6e
  m_pos = pos;
Shinya Kitaoka 120a6e
  m_points.push_back(m_pos);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Check the new pos
Shinya Kitaoka 120a6e
  int nDirections = surroundingEdges();
Shinya Kitaoka 120a6e
  if (nDirections > 2) {
Shinya Kitaoka 120a6e
    // Found mesh vertex. First, check the hash for an associated vertex
Shinya Kitaoka 120a6e
    int vIdx = touchVertex(m_pos);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Ensure that an associated edge is present, in case it should
Shinya Kitaoka 120a6e
    if (m_vIdx >= 0)
Shinya Kitaoka 120a6e
      touchEdge(m_vIdx, m_dir, m_nDirections, vIdx, oppDir, nDirections);
Shinya Kitaoka 120a6e
    else {
Shinya Kitaoka 120a6e
      m_firstPos         = m_pos;
Shinya Kitaoka 120a6e
      m_firstDir         = dir;
Shinya Kitaoka 120a6e
      m_firstOppDir      = oppDir;
Shinya Kitaoka 120a6e
      m_firstVIdx        = vIdx;
Shinya Kitaoka 120a6e
      m_firstNDirections = nDirections;
Shinya Kitaoka 120a6e
      m_firstPoints      = m_points;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_dir         = dir;
Shinya Kitaoka 120a6e
    m_vIdx        = vIdx;
Shinya Kitaoka 120a6e
    m_nDirections = nDirections;
Shinya Kitaoka 120a6e
    m_outerColor  = outerColor;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_points.clear();
Shinya Kitaoka 120a6e
    m_points.push_back(m_pos);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix=""></typename>
Shinya Kitaoka 120a6e
void ::BordersReader<pix>::closeContainer() {</pix>
Shinya Kitaoka 120a6e
  // If no vertex was found, build one on the first position.
Shinya Kitaoka 120a6e
  if (m_firstVIdx < 0) {
Shinya Kitaoka 120a6e
    // Add a vertex at the first position.
Shinya Kitaoka 120a6e
    m_firstVIdx = m_vIdx = touchVertex(m_firstPos);
Shinya Kitaoka 120a6e
    m_dir                = m_firstDir;
Shinya Kitaoka 120a6e
    m_nDirections        = m_firstNDirections;
Shinya Kitaoka 120a6e
    m_firstPoints.push_back(m_firstPos);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Connect the last vertex to the first.
Shinya Kitaoka 120a6e
  m_points.insert(m_points.end(), m_firstPoints.begin(), m_firstPoints.end());
Shinya Kitaoka 120a6e
  touchEdge(m_vIdx, m_dir, m_nDirections, m_firstVIdx, m_firstOppDir,
Shinya Kitaoka 120a6e
            m_firstNDirections);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_points.clear();
Shinya Kitaoka 120a6e
  m_firstPoints.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename ranit=""></typename>
Shinya Kitaoka 120a6e
void ::PolylineReader<ranit>::openContainer(const RanIt &it) {</ranit>
Shinya Kitaoka 120a6e
  const TPoint &p = *it;
Shinya Kitaoka 120a6e
  m_points.push_back(TPointD(p.x, p.y));
Shinya Kitaoka 120a6e
  m_indices.push_back(it - m_eval->begin());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename ranit=""></typename>
Shinya Kitaoka 120a6e
void ::PolylineReader<ranit>::addElement(const RanIt &it) {</ranit>
Shinya Kitaoka 120a6e
  const TPoint &p = *it;
Shinya Kitaoka 120a6e
  m_points.push_back(TPointD(p.x, p.y));
Shinya Kitaoka 120a6e
  m_indices.push_back(it - m_eval->begin());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename ranit=""></typename>
Shinya Kitaoka 120a6e
void ::PolylineReader<ranit>::closeContainer() {</ranit>
Shinya Kitaoka 120a6e
  if (!m_indices.empty()) {
Shinya Kitaoka 120a6e
    const TPoint &origI(*m_eval->begin());
Shinya Kitaoka 120a6e
    TPointD origin(origI.x, origI.y);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ::adjustVertices(origin, m_points, m_indices, m_eval->sums_x(),
Shinya Kitaoka 120a6e
                     m_eval->sums_y(), m_eval->sums2_x(), m_eval->sums2_y(),
Shinya Kitaoka 120a6e
                     m_eval->sums_xy());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<tthickpoint> cps;</tthickpoint>
Shinya Kitaoka 120a6e
  polylineToQuadratics(m_points, cps, m_adherenceTol, m_angleTol, m_relativeTol,
Shinya Kitaoka 120a6e
                       0.75, m_mergeTol);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_vi->addStroke(new TStroke(cps));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_points.clear();
Shinya Kitaoka 120a6e
  m_indices.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    Palette functions
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void discretizeColors(TRaster32P &ras, TPalette *palette, int nColors,
Shinya Kitaoka 120a6e
                      TPixel32 transparentColor) {
Shinya Kitaoka 120a6e
  // Extract the palette
Shinya Kitaoka 120a6e
  std::set<tpixel32> colors;</tpixel32>
Shinya Kitaoka 120a6e
  TColorUtils::buildPalette(colors, ras, nColors);
Shinya Kitaoka 120a6e
  colors.erase(TPixel::Black);  // Black is automatically inserted by TPalette's
Shinya Kitaoka 120a6e
                                // constructor
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::set<tpixel32>::const_iterator it = colors.begin();</tpixel32>
Shinya Kitaoka 120a6e
  for (; it != colors.end(); ++it) palette->getPage(0)->addStyle(*it);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Flatten ras to the specified palette
Shinya Kitaoka 120a6e
  TPixel32 *pix, *line, *lineEnd;
Shinya Kitaoka 120a6e
  int y, lx = ras->getLx(), ly = ras->getLy();
Shinya Kitaoka 120a6e
  for (y = 0; y < ly; ++y) {
Shinya Kitaoka 120a6e
    line = ras->pixels(y), lineEnd = line + lx;
Shinya Kitaoka 120a6e
    for (pix = line; pix < lineEnd; ++pix)
Shinya Kitaoka 120a6e
      *pix = (*pix == transparentColor)
Shinya Kitaoka 120a6e
                 ? TPixel32::Transparent
Shinya Kitaoka 120a6e
                 : palette->getStyle(palette->getClosestStyle(*pix))
Shinya Kitaoka 120a6e
                       ->getMainColor();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void copyCM(TRasterGR16P &dst, const TRasterCM32P &src, int toneTol) {
Shinya Kitaoka 120a6e
  assert(dst->getLx() == src->getLx() && dst->getLy() == src->getLy());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int y, lx = src->getLx(), ly = src->getLy();
Shinya Kitaoka 120a6e
  TPixelCM32 *pixIn, *lineInEnd;
Shinya Kitaoka 120a6e
  TPixelGR16 *pixOut;
Shinya Kitaoka 120a6e
  for (y = 0; y < ly; ++y) {
Shinya Kitaoka 120a6e
    pixIn = src->pixels(y), lineInEnd = pixIn + lx;
Shinya Kitaoka 120a6e
    pixOut = dst->pixels(y);
Shinya Kitaoka 120a6e
    for (; pixIn < lineInEnd; ++pixIn, ++pixOut)
Shinya Kitaoka 120a6e
      pixOut->value =
Shinya Kitaoka 120a6e
          (pixIn->getTone() < toneTol) ? pixIn->getInk() : pixIn->getPaint();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef BordersReader<tpixel32>::stroke_colors_type stroke_colors_typeRGBM;</tpixel32>
Toshihiro Shimizu 890ddd
typedef BordersReader<tpixel32>::stroke_colors_hash stroke_colors_hashRGBM;</tpixel32>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef BordersReader<tpixelgr16>::stroke_colors_type stroke_colors_typeCM;</tpixelgr16>
Toshihiro Shimizu 890ddd
typedef BordersReader<tpixelgr16>::stroke_colors_hash stroke_colors_hashCM;</tpixelgr16>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void buildColorsRGBM(TRegion *r, const stroke_colors_hashRGBM &scHash,
Shinya Kitaoka 120a6e
                     const TPaletteP palette) {
Shinya Kitaoka 120a6e
  // Build r's color
Shinya Kitaoka 120a6e
  UINT i, edgeCount = r->getEdgeCount();
Shinya Kitaoka 120a6e
  for (i = 0; i < edgeCount; ++i) {
Shinya Kitaoka 120a6e
    TEdge *ed = r->getEdge(i);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    stroke_colors_hashRGBM::const_iterator it = scHash.find(ed->m_s);
Shinya Kitaoka 120a6e
    if (it == scHash.end()) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    const stroke_colors_typeRGBM &colors = it->m_val;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int style;
Shinya Kitaoka 120a6e
    if (ed->m_w0 < ed->m_w1) {
Shinya Kitaoka 120a6e
      style = palette->getClosestStyle(colors.first);
Shinya Kitaoka 120a6e
      ed->setStyle(style);
Shinya Kitaoka 120a6e
      ed->m_s->setStyle(style ? style
Shinya Kitaoka 120a6e
                              : palette->getClosestStyle(colors.second));
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      style = palette->getClosestStyle(colors.second);
Shinya Kitaoka 120a6e
      ed->setStyle(style);
Shinya Kitaoka 120a6e
      ed->m_s->setStyle(style ? style : palette->getClosestStyle(colors.first));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build the color for its sub-regions
Shinya Kitaoka 120a6e
  int j, rCount = r->getSubregionCount();
Shinya Kitaoka 120a6e
  for (j = 0; j < rCount; ++j)
Shinya Kitaoka 120a6e
    buildColorsRGBM(r->getSubregion(j), scHash, palette);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void buildColorsRGBM(TVectorImageP vi, const stroke_colors_hashRGBM &scHash) {
Shinya Kitaoka 120a6e
  // For every region, find its color
Shinya Kitaoka 120a6e
  int i, rCount = vi->getRegionCount();
Shinya Kitaoka 120a6e
  for (i = 0; i < rCount; ++i)
Shinya Kitaoka 120a6e
    buildColorsRGBM(vi->getRegion(i), scHash, vi->getPalette());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void buildColorsCM(TRegion *r, const stroke_colors_hashCM &scHash) {
Shinya Kitaoka 120a6e
  // Build r's color
Shinya Kitaoka 120a6e
  UINT i, edgeCount = r->getEdgeCount();
Shinya Kitaoka 120a6e
  for (i = 0; i < edgeCount; ++i) {
Shinya Kitaoka 120a6e
    TEdge *ed = r->getEdge(i);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    stroke_colors_hashCM::const_iterator it = scHash.find(ed->m_s);
Shinya Kitaoka 120a6e
    if (it == scHash.end()) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    const stroke_colors_typeCM &colors = it->m_val;
Shinya Kitaoka 120a6e
    if (ed->m_w0 < ed->m_w1)
Shinya Kitaoka 120a6e
      ed->setStyle(colors.first.value);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      ed->setStyle(colors.second.value);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ed->m_s->setStyle(colors.first.value ? colors.first.value
Shinya Kitaoka 120a6e
                                         : colors.second.value);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build the color for its sub-regions
Shinya Kitaoka 120a6e
  int j, rCount = r->getSubregionCount();
Shinya Kitaoka 120a6e
  for (j = 0; j < rCount; ++j) buildColorsCM(r->getSubregion(j), scHash);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void buildColorsCM(TVectorImageP vi, const stroke_colors_hashCM &scHash) {
Shinya Kitaoka 120a6e
  // For every region, find its color
Shinya Kitaoka 120a6e
  int i, rCount = vi->getRegionCount();
Shinya Kitaoka 120a6e
  for (i = 0; i < rCount; ++i) buildColorsCM(vi->getRegion(i), scHash);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
//    Main functions
Toshihiro Shimizu 890ddd
//************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void outlineVectorize(TVectorImageP &vi, const TRasterImageP &ri,
Shinya Kitaoka 120a6e
                      const NewOutlineConfiguration &conf, TPalette *palette) {
Shinya Kitaoka 120a6e
  // Make a copy of ri's raster - a 32-bit raster
Shinya Kitaoka 120a6e
  TRasterP ras(ri->getRaster());
Shinya Kitaoka 120a6e
  TRaster32P ras32(ras->getSize());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRop::copy(ras32, ras);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build palette color and discretize the raster
Shinya Kitaoka 120a6e
  discretizeColors(ras32, palette, conf.m_maxColors, conf.m_transparentColor);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Perform despeckling
Shinya Kitaoka 120a6e
  if (conf.m_despeckling > 0)
Shinya Kitaoka 120a6e
    TRop::majorityDespeckle(ras32, conf.m_despeckling);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Examinate the discretized raster. Build a mesh structure representing the
Shinya Kitaoka 120a6e
  // image's
Shinya Kitaoka 120a6e
  // colors geometry. Build strokes as mesh edges are extracted.
Shinya Kitaoka 120a6e
  LocalMesh mesh;
Shinya Kitaoka 120a6e
  BordersReader<tpixel32> reader(ras32, &mesh, vi, conf);</tpixel32>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRop::borders::readBorders_simple(ras32, reader, false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build regions
Shinya Kitaoka 120a6e
  vi->transform(conf.m_affine);
Shinya Kitaoka 120a6e
  vi->findRegions();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!conf.m_leaveUnpainted)
Shinya Kitaoka 120a6e
    // Finally, build region colors.
Shinya Kitaoka 120a6e
    buildColorsRGBM(vi, reader.scHash());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void outlineVectorize(TVectorImageP &vi, const TToonzImageP &ti,
Shinya Kitaoka 120a6e
                      const NewOutlineConfiguration &conf, TPalette *palette) {
Shinya Kitaoka 120a6e
  TRasterCM32P ras(ti->getRaster());
Shinya Kitaoka 120a6e
  TRasterGR16P rasGR16(ras->getSize());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ::copyCM(rasGR16, ras, conf.m_toneTol);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Perform despeckling
Shinya Kitaoka 120a6e
  if (conf.m_despeckling > 0)
Shinya Kitaoka 120a6e
    TRop::majorityDespeckle(rasGR16, conf.m_despeckling);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  LocalMesh mesh;
Shinya Kitaoka 120a6e
  BordersReader<tpixelgr16> reader(rasGR16, &mesh, vi, conf);</tpixelgr16>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRop::borders::readBorders_simple(rasGR16, reader, TPixelGR16::Black, false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  vi->transform(conf.m_affine);
Shinya Kitaoka 120a6e
  vi->findRegions();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!conf.m_leaveUnpainted) buildColorsCM(vi, reader.scHash());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TVectorImageP VectorizerCore::newOutlineVectorize(
Shinya Kitaoka 120a6e
    const TImageP &image, const NewOutlineConfiguration &conf,
Shinya Kitaoka 120a6e
    TPalette *palette) {
Shinya Kitaoka 120a6e
  TVectorImageP output(new TVectorImage);
Shinya Kitaoka 120a6e
  output->setPalette(palette);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterImageP ri(image);
Shinya Kitaoka 120a6e
  TToonzImageP ti(image);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Deal with palette (observe that if image is colormap, the input palette is
Shinya Kitaoka 120a6e
  // directly copied to output)
Shinya Kitaoka 120a6e
  if (ri)
Shinya Kitaoka 120a6e
    ::outlineVectorize(output, ri, conf, palette);
Shinya Kitaoka 120a6e
  else if (ti)
Shinya Kitaoka 120a6e
    ::outlineVectorize(output, ti, conf, palette);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    assert(false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return output;
Toshihiro Shimizu 890ddd
}