shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
#include "flowlinestrokestyle.h"
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
#include "tcolorfunctions.h"
shun-iwasawa 13c4cf
#include "tcurves.h"
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
#define BUFFER_OFFSET(bytes) ((GLubyte *)NULL + (bytes))
shun-iwasawa 13c4cf
#define V_BUFFER_SIZE 1000
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
namespace {
shun-iwasawa 13c4cf
double getMaxThickness(const TStroke *s) {
shun-iwasawa 13c4cf
  int count           = s->getControlPointCount();
shun-iwasawa 13c4cf
  double maxThickness = -1;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  for (int i = 0; i < s->getControlPointCount(); i++) {
shun-iwasawa 13c4cf
    double thick = s->getControlPoint(i).thick;
shun-iwasawa 13c4cf
    if (thick > maxThickness) maxThickness = thick;
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
  return maxThickness;
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
struct float2 {
shun-iwasawa 13c4cf
  float x;
shun-iwasawa 13c4cf
  float y;
shun-iwasawa 13c4cf
};
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
inline double dot(const TPointD &v1, const TPointD &v2) {
shun-iwasawa 13c4cf
  return v1.x * v2.x + v1.y * v2.y;
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
inline bool isLinearPoint(const TPointD &p0, const TPointD &p1,
shun-iwasawa 13c4cf
                          const TPointD &p2) {
shun-iwasawa 13c4cf
  return (tdistance(p0, p1) < 0.02) && (tdistance(p1, p2) < 0.02);
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//! Ritorna \b true se il punto \b p1 e' una cuspide.
shun-iwasawa 13c4cf
bool isCuspPoint(const TPointD &p0, const TPointD &p1, const TPointD &p2) {
shun-iwasawa 13c4cf
  TPointD p0_p1(p0 - p1), p2_p1(p2 - p1);
shun-iwasawa 13c4cf
  double n1 = norm(p0_p1), n2 = norm(p2_p1);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  // Partial linear points are ALWAYS cusps (since directions from them are
shun-iwasawa 13c4cf
  // determined by neighbours, not by the points themselves)
shun-iwasawa 13c4cf
  if ((n1 < 0.02) || (n2 < 0.02)) return true;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  p0_p1 = p0_p1 * (1.0 / n1);
shun-iwasawa 13c4cf
  p2_p1 = p2_p1 * (1.0 / n2);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  return (p0_p1 * p2_p1 > 0) ||
shun-iwasawa 13c4cf
         (fabs(cross(p0_p1, p2_p1)) > 0.09);  // more than 5° is yes
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  // Distance-based check. Unscalable...
shun-iwasawa 13c4cf
  // return
shun-iwasawa 13c4cf
  // !areAlmostEqual(tdistance(p0,p2),tdistance(p0,p1)+tdistance(p1,p2),2);
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------
shun-iwasawa 13c4cf
/*! Insert a point in the most long chunk between chunk \b indexA and chunk \b
shun-iwasawa 13c4cf
 * indexB. */
shun-iwasawa 13c4cf
void insertPoint(TStroke *stroke, int indexA, int indexB) {
shun-iwasawa 13c4cf
  assert(stroke);
shun-iwasawa 13c4cf
  int j          = 0;
shun-iwasawa 13c4cf
  int chunkCount = indexB - indexA;
shun-iwasawa 13c4cf
  if (chunkCount % 2 == 0) return;
shun-iwasawa 13c4cf
  double length = 0;
shun-iwasawa 13c4cf
  double firstW, lastW;
shun-iwasawa 13c4cf
  for (j = indexA; j < indexB; j++) {
shun-iwasawa 13c4cf
    // cerco il chunk piu' lungo
shun-iwasawa 13c4cf
    double w0 = stroke->getW(stroke->getChunk(j)->getP0());
shun-iwasawa 13c4cf
    double w1;
shun-iwasawa 13c4cf
    if (j == stroke->getChunkCount() - 1)
shun-iwasawa 13c4cf
      w1 = 1;
shun-iwasawa 13c4cf
    else
shun-iwasawa 13c4cf
      w1 = stroke->getW(stroke->getChunk(j)->getP2());
shun-iwasawa 13c4cf
    double length0 = stroke->getLength(w0);
shun-iwasawa 13c4cf
    double length1 = stroke->getLength(w1);
shun-iwasawa 13c4cf
    if (length < length1 - length0) {
shun-iwasawa 13c4cf
      firstW = w0;
shun-iwasawa 13c4cf
      lastW  = w1;
shun-iwasawa 13c4cf
      length = length1 - length0;
shun-iwasawa 13c4cf
    }
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
  stroke->insertControlPoints((firstW + lastW) * 0.5);
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
};  // namespace
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
FlowLineStrokeStyle::FlowLineStrokeStyle()
shun-iwasawa 13c4cf
    : m_color(TPixel32(100, 200, 200, 255))
shun-iwasawa 13c4cf
    , m_density(0.25)
shun-iwasawa 13c4cf
    , m_extension(5.0)
shun-iwasawa 13c4cf
    , m_widthScale(5.0)
shun-iwasawa 13c4cf
    , m_straightenEnds(true) {}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
TColorStyle *FlowLineStrokeStyle::clone() const {
shun-iwasawa 13c4cf
  return new FlowLineStrokeStyle(*this);
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
int FlowLineStrokeStyle::getParamCount() const { return ParamCount; }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
TColorStyle::ParamType FlowLineStrokeStyle::getParamType(int index) const {
shun-iwasawa 13c4cf
  assert(0 <= index && index < getParamCount());
shun-iwasawa 13c4cf
  switch (index) {
shun-iwasawa 13c4cf
  case Density:
shun-iwasawa 13c4cf
  case Extension:
shun-iwasawa 13c4cf
  case WidthScale:
shun-iwasawa 13c4cf
    return TColorStyle::DOUBLE;
shun-iwasawa 13c4cf
  case StraightenEnds:
shun-iwasawa 13c4cf
    return TColorStyle::BOOL;
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
  return TColorStyle::DOUBLE;
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
QString FlowLineStrokeStyle::getParamNames(int index) const {
shun-iwasawa 13c4cf
  assert(0 <= index && index < ParamCount);
shun-iwasawa 13c4cf
  switch (index) {
shun-iwasawa 13c4cf
  case Density:
shun-iwasawa 13c4cf
    return QCoreApplication::translate("FlowLineStrokeStyle", "Density");
shun-iwasawa 13c4cf
  case Extension:
shun-iwasawa 13c4cf
    return QCoreApplication::translate("FlowLineStrokeStyle", "Extension");
shun-iwasawa 13c4cf
  case WidthScale:
shun-iwasawa 13c4cf
    return QCoreApplication::translate("FlowLineStrokeStyle", "Width Scale");
shun-iwasawa 13c4cf
  case StraightenEnds:
shun-iwasawa 13c4cf
    return QCoreApplication::translate("FlowLineStrokeStyle",
shun-iwasawa 13c4cf
                                       "Straighten Ends");
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
  return QString();
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
void FlowLineStrokeStyle::getParamRange(int index, double &min,
shun-iwasawa 13c4cf
                                        double &max) const {
shun-iwasawa 13c4cf
  assert(0 <= index && index < ParamCount);
shun-iwasawa 13c4cf
  switch (index) {
shun-iwasawa 13c4cf
  case Density:
shun-iwasawa 13c4cf
    min = 0.2;
shun-iwasawa 13c4cf
    max = 5.0;
shun-iwasawa 13c4cf
    break;
shun-iwasawa 13c4cf
  case Extension:
shun-iwasawa 13c4cf
    min = 0.0;
shun-iwasawa 13c4cf
    max = 20.0;
shun-iwasawa 13c4cf
    break;
shun-iwasawa 13c4cf
  case WidthScale:
shun-iwasawa 13c4cf
    min = 1.0;
shun-iwasawa 13c4cf
    max = 50.0;
shun-iwasawa 13c4cf
    break;
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
double FlowLineStrokeStyle::getParamValue(TColorStyle::double_tag,
shun-iwasawa 13c4cf
                                          int index) const {
shun-iwasawa 13c4cf
  assert(0 <= index && index < ParamCount);
shun-iwasawa 13c4cf
  switch (index) {
shun-iwasawa 13c4cf
  case Density:
shun-iwasawa 13c4cf
    return m_density;
shun-iwasawa 13c4cf
  case Extension:
shun-iwasawa 13c4cf
    return m_extension;
shun-iwasawa 13c4cf
  case WidthScale:
shun-iwasawa 13c4cf
    return m_widthScale;
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
  return 0.0;
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
void FlowLineStrokeStyle::setParamValue(int index, double value) {
shun-iwasawa 13c4cf
  assert(0 <= index && index < ParamCount);
shun-iwasawa 13c4cf
  switch (index) {
shun-iwasawa 13c4cf
  case Density:
shun-iwasawa 13c4cf
    m_density = value;
shun-iwasawa 13c4cf
    break;
shun-iwasawa 13c4cf
  case Extension:
shun-iwasawa 13c4cf
    m_extension = value;
shun-iwasawa 13c4cf
    break;
shun-iwasawa 13c4cf
  case WidthScale:
shun-iwasawa 13c4cf
    m_widthScale = value;
shun-iwasawa 13c4cf
    break;
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
  updateVersionNumber();
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
bool FlowLineStrokeStyle::getParamValue(TColorStyle::bool_tag,
shun-iwasawa 13c4cf
                                        int index) const {
shun-iwasawa 13c4cf
  assert(index == StraightenEnds);
shun-iwasawa 13c4cf
  return m_straightenEnds;
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
void FlowLineStrokeStyle::setParamValue(int index, bool value) {
shun-iwasawa 13c4cf
  assert(index == StraightenEnds);
shun-iwasawa 13c4cf
  m_straightenEnds = value;
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
void FlowLineStrokeStyle::drawStroke(const TColorFunction *cf,
shun-iwasawa 13c4cf
                                     const TStroke *stroke) const {
shun-iwasawa 13c4cf
  auto lerp = [](float val1, float val2, float ratio) {
shun-iwasawa 13c4cf
    return val1 * (1.0 - ratio) + val2 * ratio;
shun-iwasawa 13c4cf
  };
shun-iwasawa 13c4cf
  auto length2 = [](TPointD p) { return p.x * p.x + p.y * p.y; };
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  // Length and position of the stroke is in "actual size" (i.e. not in pixels).
shun-iwasawa 13c4cf
  // 1unit = 1/53.3333inches
shun-iwasawa 13c4cf
  // Strokeの長さや座標は実寸(1単位=1/53.3333インチ)
shun-iwasawa 13c4cf
  double length = stroke->getLength();
shun-iwasawa 13c4cf
  if (length <= 0) return;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  double maxThickness = getMaxThickness(stroke) * m_widthScale;
shun-iwasawa 13c4cf
  if (maxThickness <= 0) return;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  TStroke *tmpStroke = new TStroke(*stroke);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  // straighten ends. replace the control point only if the new handle will
shun-iwasawa 13c4cf
  // become longer
shun-iwasawa 13c4cf
  if (m_straightenEnds && stroke->getControlPointCount() >= 5 &&
shun-iwasawa 13c4cf
      !stroke->isSelfLoop()) {
shun-iwasawa 13c4cf
    TPointD newPos = tmpStroke->getControlPoint(0) * 0.75 +
shun-iwasawa 13c4cf
                     tmpStroke->getControlPoint(3) * 0.25;
shun-iwasawa 13c4cf
    TPointD oldVec =
shun-iwasawa 13c4cf
        tmpStroke->getControlPoint(1) - tmpStroke->getControlPoint(0);
shun-iwasawa 13c4cf
    TPointD newVec = newPos - tmpStroke->getControlPoint(0);
shun-iwasawa 13c4cf
    if (length2(oldVec) < length2(newVec))
shun-iwasawa 13c4cf
      tmpStroke->setControlPoint(1, newPos);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
    int lastId = stroke->getControlPointCount() - 1;
shun-iwasawa 13c4cf
    newPos     = tmpStroke->getControlPoint(lastId) * 0.75 +
shun-iwasawa 13c4cf
             tmpStroke->getControlPoint(lastId - 3) * 0.25;
shun-iwasawa 13c4cf
    oldVec = tmpStroke->getControlPoint(lastId - 1) -
shun-iwasawa 13c4cf
             tmpStroke->getControlPoint(lastId);
shun-iwasawa 13c4cf
    newVec = newPos - tmpStroke->getControlPoint(lastId);
shun-iwasawa 13c4cf
    if (length2(oldVec) < length2(newVec))
shun-iwasawa 13c4cf
      tmpStroke->setControlPoint(lastId - 1, newPos);
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  // see ControlPointEditorStroke::adjustChunkParity() in
shun-iwasawa 13c4cf
  // controlpointselection.cpp
shun-iwasawa 13c4cf
  int firstChunk;
shun-iwasawa 13c4cf
  int secondChunk = tmpStroke->getChunkCount();
shun-iwasawa 13c4cf
  int i;
shun-iwasawa 13c4cf
  for (i = tmpStroke->getChunkCount() - 1; i > 0; i--) {
shun-iwasawa 13c4cf
    if (tdistance(tmpStroke->getChunk(i - 1)->getP0(),
shun-iwasawa 13c4cf
                  tmpStroke->getChunk(i)->getP2()) < 0.5)
shun-iwasawa 13c4cf
      continue;
shun-iwasawa 13c4cf
    TPointD p0 = tmpStroke->getChunk(i - 1)->getP1();
shun-iwasawa 13c4cf
    TPointD p1 = tmpStroke->getChunk(i - 1)->getP2();
shun-iwasawa 13c4cf
    TPointD p2 = tmpStroke->getChunk(i)->getP1();
shun-iwasawa 13c4cf
    if (isCuspPoint(p0, p1, p2) || isLinearPoint(p0, p1, p2)) {
shun-iwasawa 13c4cf
      firstChunk = i;
shun-iwasawa 13c4cf
      insertPoint(tmpStroke, firstChunk, secondChunk);
shun-iwasawa 13c4cf
      secondChunk = firstChunk;
shun-iwasawa 13c4cf
    }
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
  insertPoint(tmpStroke, 0, secondChunk);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  // thin lines amount 細線の本数
shun-iwasawa 13c4cf
  int count = 2 * (int)std::ceil(maxThickness * m_density) - 1;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  TPixel32 color;
shun-iwasawa 13c4cf
  if (cf)
shun-iwasawa 13c4cf
    color = (*(cf))(m_color);
shun-iwasawa 13c4cf
  else
shun-iwasawa 13c4cf
    color = m_color;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  float2 *vertBuf  = new float2[V_BUFFER_SIZE];
shun-iwasawa 13c4cf
  int maxVertCount = 0;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  glEnableClientState(GL_VERTEX_ARRAY);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  int centerId = (count - 1) / 2;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  TThickPoint p0 = tmpStroke->getThickPoint(0);
shun-iwasawa 13c4cf
  TThickPoint p1 = tmpStroke->getThickPoint(1);
shun-iwasawa 13c4cf
  double d01     = tdistance(p0, p1);
shun-iwasawa 13c4cf
  if (d01 == 0) return;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  int len = (int)(d01);
shun-iwasawa 13c4cf
  if (len == 0) return;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  TPointD v0 = tmpStroke->getSpeed(0);
shun-iwasawa 13c4cf
  TPointD v1 = tmpStroke->getSpeed(1);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  if (norm2(v0) == 0 || norm2(v1) == 0) return;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  TPointD startVec = -normalize(v0);
shun-iwasawa 13c4cf
  TPointD endVec   = normalize(v1);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
  for (int i = 0; i < count; i++) {
shun-iwasawa 13c4cf
    double widthRatio =
shun-iwasawa 13c4cf
        (count == 1) ? 0.0 : (double)(i - centerId) / (double)centerId;
shun-iwasawa 13c4cf
    double extensionLength =
shun-iwasawa 13c4cf
        (1.0 - std::abs(widthRatio)) * maxThickness * m_extension;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
    glColor4ub(color.r, color.g, color.b, color.m);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
    int divAmount = len * 5;
shun-iwasawa 13c4cf
    if (divAmount + 3 > V_BUFFER_SIZE) divAmount = V_BUFFER_SIZE - 3;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
    float2 *vp = vertBuf;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
    for (int j = 0; j <= divAmount; j++, vp++) {
shun-iwasawa 13c4cf
      // current position ratio  今の座標の割合位置
shun-iwasawa 13c4cf
      double t = double(j) / double(divAmount);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
      // position ratio on the stroke ストローク上のratio位置
shun-iwasawa 13c4cf
      double w = t;
shun-iwasawa 13c4cf
      // unit vector perpendicular to the stroke 鉛直方向の単位ベクトル
shun-iwasawa 13c4cf
      TPointD v = rotate90(normalize(tmpStroke->getSpeed(w)));
shun-iwasawa 13c4cf
      assert(0 <= w && w <= 1);
shun-iwasawa 13c4cf
      // position on the stroke ストローク上の位置
shun-iwasawa 13c4cf
      TPointD p = tmpStroke->getPoint(w);
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
      TPointD pos = p + v * maxThickness * widthRatio;
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
      if (j == 0) {
shun-iwasawa 13c4cf
        TPointD sPos = pos + startVec * extensionLength;
shun-iwasawa 13c4cf
        *vp          = {float(sPos.x), float(sPos.y)};
shun-iwasawa 13c4cf
        vp++;
shun-iwasawa 13c4cf
      }
shun-iwasawa 13c4cf
      *vp = {float(pos.x), float(pos.y)};
shun-iwasawa 13c4cf
      if (j == divAmount) {
shun-iwasawa 13c4cf
        vp++;
shun-iwasawa 13c4cf
        TPointD ePos = pos + endVec * extensionLength;
shun-iwasawa 13c4cf
        *vp          = {float(ePos.x), float(ePos.y)};
shun-iwasawa 13c4cf
      }
shun-iwasawa 13c4cf
    }
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
    glVertexPointer(2, GL_FLOAT, 0, vertBuf);
shun-iwasawa 13c4cf
    // draw
shun-iwasawa 13c4cf
    glDrawArrays(GL_LINE_STRIP, 0, divAmount + 3);
shun-iwasawa 13c4cf
  }
shun-iwasawa 13c4cf
  glColor4d(0, 0, 0, 1);
shun-iwasawa 13c4cf
  glDisableClientState(GL_VERTEX_ARRAY);
shun-iwasawa 13c4cf
  delete[] vertBuf;
shun-iwasawa 13c4cf
  delete tmpStroke;
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
TRectD FlowLineStrokeStyle::getStrokeBBox(const TStroke *stroke) const {
shun-iwasawa 13c4cf
  TRectD rect = TColorStyle::getStrokeBBox(stroke);
shun-iwasawa 13c4cf
  double margin =
shun-iwasawa 13c4cf
      getMaxThickness(stroke) * m_widthScale * std::max(1.0, m_extension);
shun-iwasawa 13c4cf
  return rect.enlarge(margin);
shun-iwasawa 13c4cf
}
shun-iwasawa 13c4cf
shun-iwasawa 13c4cf
//-----------------------------------------------------------------------------