Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tcurveutil.h"
Toshihiro Shimizu 890ddd
#include "tcurves.h"
Toshihiro Shimizu 890ddd
#include "tmathutil.h"
Toshihiro Shimizu 890ddd
#include "tbezier.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Campbell Barton a6cacc
This function returns a vector of
Campbell Barton a6cacc
pairs of double (DoublePair) which identifies the parameters
Campbell Barton a6cacc
of the points of intersection.
Toshihiro Shimizu 890ddd
Campbell Barton a6cacc
  The integer returned is the number of intersections which
Campbell Barton a6cacc
  have been identified (for two segments).
Shinya Kitaoka 120a6e
Campbell Barton a6cacc
    If the segments are parallel to the parameter it is set to -1.
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int intersect(const TSegment &first, const TSegment &second,
Shinya Kitaoka 120a6e
              std::vector<doublepair> &intersections) {</doublepair>
Shinya Kitaoka 120a6e
  return intersect(first.getP0(), first.getP1(), second.getP0(), second.getP1(),
Shinya Kitaoka 120a6e
                   intersections);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int intersect(const TPointD &p1, const TPointD &p2, const TPointD &p3,
Shinya Kitaoka 120a6e
              const TPointD &p4, std::vector<doublepair> &intersections) {</doublepair>
Shinya Kitaoka 120a6e
  // This algorithm is presented in Graphics Geems III pag 199
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  static double Ax, Bx, Ay, By, Cx, Cy, d, f, e;
Shinya Kitaoka 120a6e
  static double x1lo, x1hi, y1lo, y1hi;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  Ax = p2.x - p1.x;
Shinya Kitaoka 120a6e
  Bx = p3.x - p4.x;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // test delle BBox
Shinya Kitaoka 120a6e
  if (Ax < 0.0) {
Shinya Kitaoka 120a6e
    x1lo = p2.x;
Shinya Kitaoka 120a6e
    x1hi = p1.x;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    x1lo = p1.x;
Shinya Kitaoka 120a6e
    x1hi = p2.x;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (Bx > 0.0) {
Shinya Kitaoka 120a6e
    if (x1hi < p4.x || x1lo > p3.x) return 0;
Shinya Kitaoka 120a6e
  } else if (x1hi < p3.x || x1lo > p4.x)
Shinya Kitaoka 120a6e
    return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  Ay = p2.y - p1.y;
Shinya Kitaoka 120a6e
  By = p3.y - p4.y;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (Ay < 0) {
Shinya Kitaoka 120a6e
    y1lo = p2.y;
Shinya Kitaoka 120a6e
    y1hi = p1.y;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    y1lo = p1.y;
Shinya Kitaoka 120a6e
    y1hi = p2.y;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (By > 0) {
Shinya Kitaoka 120a6e
    if (y1hi < p4.y || y1lo > p3.y) return 0;
Shinya Kitaoka 120a6e
  } else if (y1hi < p3.y || y1lo > p4.y)
Shinya Kitaoka 120a6e
    return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  Cx = p1.x - p3.x;
Shinya Kitaoka 120a6e
  Cy = p1.y - p3.y;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  d = By * Cx - Bx * Cy;
Shinya Kitaoka 120a6e
  f = Ay * Bx - Ax * By;
Shinya Kitaoka 120a6e
  e = Ax * Cy - Ay * Cx;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (f > 0) {
Shinya Kitaoka 120a6e
    if (d < 0) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!areAlmostEqual(d, f))
Shinya Kitaoka 120a6e
      if (d > f) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (e < 0) return 0;
Shinya Kitaoka 120a6e
    if (!areAlmostEqual(e, f))
Shinya Kitaoka 120a6e
      if (e > f) return 0;
Shinya Kitaoka 120a6e
  } else if (f < 0) {
Shinya Kitaoka 120a6e
    if (d > 0) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!areAlmostEqual(d, f))
Shinya Kitaoka 120a6e
      if (d < f) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (e > 0) return 0;
Shinya Kitaoka 120a6e
    if (!areAlmostEqual(e, f))
Shinya Kitaoka 120a6e
      if (e < f) return 0;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    if (d < 0 || d > 1 || e < 0 || e > 1) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (p1 == p2 && p3 == p4) {
Shinya Kitaoka 120a6e
      intersections.push_back(DoublePair(0, 0));
Shinya Kitaoka 120a6e
      return 1;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Campbell Barton a6cacc
    // Check that the segments are not on the same line.
Shinya Kitaoka 120a6e
    if (!cross(p2 - p1, p4 - p1)) {
Campbell Barton a6cacc
      // Calculation of Barycentric combinations.
Shinya Kitaoka 120a6e
      double distp2p1 = norm2(p2 - p1);
Shinya Kitaoka 120a6e
      double distp3p4 = norm2(p3 - p4);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      double dist2_p3p1 = norm2(p3 - p1);
Shinya Kitaoka 120a6e
      double dist2_p4p1 = norm2(p4 - p1);
Shinya Kitaoka 120a6e
      double dist2_p3p2 = norm2(p3 - p2);
Shinya Kitaoka 120a6e
      double dist2_p4p2 = norm2(p4 - p2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      int intersection = 0;
Shinya Kitaoka 120a6e
Campbell Barton a6cacc
      // Calculation of the first two solutions.
Shinya Kitaoka 120a6e
      double vol1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (distp3p4) {
Shinya Kitaoka 120a6e
        distp3p4 = sqrt(distp3p4);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        vol1 = (p1 - p3) * normalize(p4 - p3);
Shinya Kitaoka 120a6e
Campbell Barton a6cacc
        if (vol1 >= 0 && vol1 <= distp3p4)  // Barycentric combinations valid
Shinya Kitaoka 120a6e
        {
Shinya Kitaoka 120a6e
          intersections.push_back(DoublePair(0.0, vol1 / distp3p4));
Shinya Kitaoka 120a6e
          ++intersection;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        vol1 = (p2 - p3) * normalize(p4 - p3);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (vol1 >= 0 && vol1 <= distp3p4) {
Shinya Kitaoka 120a6e
          intersections.push_back(DoublePair(1.0, vol1 / distp3p4));
Shinya Kitaoka 120a6e
          ++intersection;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (distp2p1) {
Shinya Kitaoka 120a6e
        distp2p1 = sqrt(distp2p1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        vol1 = (p3 - p1) * normalize(p2 - p1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (dist2_p3p2 && dist2_p3p1)
Shinya Kitaoka 120a6e
          if (vol1 >= 0 && vol1 <= distp2p1) {
Shinya Kitaoka 120a6e
            intersections.push_back(DoublePair(vol1 / distp2p1, 0.0));
Shinya Kitaoka 120a6e
            ++intersection;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        vol1 = (p4 - p1) * normalize(p2 - p1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (dist2_p4p2 && dist2_p4p1)
Shinya Kitaoka 120a6e
          if (vol1 >= 0 && vol1 <= distp2p1) {
Shinya Kitaoka 120a6e
            intersections.push_back(DoublePair(vol1 / distp2p1, 1.0));
Shinya Kitaoka 120a6e
            ++intersection;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      return intersection;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return -1;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double par_s = d / f;
Shinya Kitaoka 120a6e
  double par_t = e / f;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  intersections.push_back(DoublePair(par_s, par_t));
Shinya Kitaoka 120a6e
  return 1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------------------------------------------
Shinya Kitaoka 120a6e
int intersectCloseControlPoints(const TQuadratic &c0, const TQuadratic &c1,
Shinya Kitaoka 120a6e
                                std::vector<doublepair> &intersections);</doublepair>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int intersect(const TQuadratic &c0, const TQuadratic &c1,
Shinya Kitaoka 120a6e
              std::vector<doublepair> &intersections, bool checksegments) {</doublepair>
Shinya Kitaoka 120a6e
  int ret;
Shinya Kitaoka 120a6e
Campbell Barton a6cacc
  // Works baddly, sometimes patch intersections...
Shinya Kitaoka 120a6e
  if (checksegments) {
Shinya Kitaoka 120a6e
    ret = intersectCloseControlPoints(c0, c1, intersections);
Shinya Kitaoka 120a6e
    if (ret != -2) return ret;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double a = c0.getP0().x - 2 * c0.getP1().x + c0.getP2().x;
Shinya Kitaoka 120a6e
  double b = 2 * (c0.getP1().x - c0.getP0().x);
Shinya Kitaoka 120a6e
  double d = c0.getP0().y - 2 * c0.getP1().y + c0.getP2().y;
Shinya Kitaoka 120a6e
  double e = 2 * (c0.getP1().y - c0.getP0().y);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double coeff = b * d - a * e;
Shinya Kitaoka 120a6e
  int i        = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (areAlmostEqual(coeff, 0.0))  // c0 is a Segment, or a single point!!!
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    TSegment s = TSegment(c0.getP0(), c0.getP2());
Shinya Kitaoka 120a6e
    ret        = intersect(s, c1, intersections);
Shinya Kitaoka 120a6e
    if (a == 0 && d == 0)  // values of t in s coincide with values of t in c0
Shinya Kitaoka 120a6e
      return ret;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = intersections.size() - ret; i < (int)intersections.size(); i++) {
Shinya Kitaoka 120a6e
      intersections[i].first = c0.getT(s.getPoint(intersections[i].first));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return ret;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double c = c0.getP0().x;
Shinya Kitaoka 120a6e
  double f = c0.getP0().y;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double g = c1.getP0().x - 2 * c1.getP1().x + c1.getP2().x;
Shinya Kitaoka 120a6e
  double h = 2 * (c1.getP1().x - c1.getP0().x);
Shinya Kitaoka 120a6e
  double k = c1.getP0().x;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double m = c1.getP0().y - 2 * c1.getP1().y + c1.getP2().y;
Shinya Kitaoka 120a6e
  double p = 2 * (c1.getP1().y - c1.getP0().y);
Shinya Kitaoka 120a6e
  double q = c1.getP0().y;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (areAlmostEqual(h * m - g * p,
Shinya Kitaoka 120a6e
                     0.0))  // c1 is a Segment, or a single point!!!
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    TSegment s = TSegment(c1.getP0(), c1.getP2());
Shinya Kitaoka 120a6e
    ret        = intersect(c0, s, intersections);
Shinya Kitaoka 120a6e
    if (g == 0 && m == 0)  // values of t in s coincide with values of t in c0
Shinya Kitaoka 120a6e
      return ret;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = intersections.size() - ret; i < (int)intersections.size(); i++) {
Shinya Kitaoka 120a6e
      intersections[i].second = c1.getT(s.getPoint(intersections[i].second));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return ret;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double a2 = (g * d - a * m);
Shinya Kitaoka 120a6e
  double b2 = (h * d - a * p);
Shinya Kitaoka 120a6e
  double c2 = ((k - c) * d + (f - q) * a);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  coeff = 1.0 / coeff;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double A   = (a * a + d * d) * coeff * coeff;
Shinya Kitaoka 120a6e
  double aux = A * c2 + (a * b + d * e) * coeff;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<double> t;</double>
Shinya Kitaoka 120a6e
  std::vector<double> solutions;</double>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  t.push_back(aux * c2 + a * c + d * f - k * a - d * q);
Shinya Kitaoka 120a6e
  aux += A * c2;
Shinya Kitaoka 120a6e
  t.push_back(aux * b2 - h * a - d * p);
Shinya Kitaoka 120a6e
  t.push_back(aux * a2 + A * b2 * b2 - g * a - d * m);
Shinya Kitaoka 120a6e
  t.push_back(2 * A * a2 * b2);
Shinya Kitaoka 120a6e
  t.push_back(A * a2 * a2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  rootFinding(t, solutions);
Shinya Kitaoka 120a6e
  //  solutions.push_back(0.0); //per convenzione; un valore vale l'altro....
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)solutions.size(); i++) {
Shinya Kitaoka 120a6e
    if (solutions[i] < 0) {
Shinya Kitaoka 120a6e
      if (areAlmostEqual(solutions[i], 0, 1e-6))
Shinya Kitaoka 120a6e
        solutions[i] = 0;
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        continue;
Shinya Kitaoka 120a6e
    } else if (solutions[i] > 1) {
Shinya Kitaoka 120a6e
      if (areAlmostEqual(solutions[i], 1, 1e-6))
Shinya Kitaoka 120a6e
        solutions[i] = 1;
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    DoublePair tt;
Shinya Kitaoka 120a6e
    tt.second = solutions[i];
Shinya Kitaoka 120a6e
    tt.first  = coeff * (tt.second * (a2 * tt.second + b2) + c2);
Shinya Kitaoka 120a6e
    if (tt.first < 0) {
Shinya Kitaoka 120a6e
      if (areAlmostEqual(tt.first, 0, 1e-6))
Shinya Kitaoka 120a6e
        tt.first = 0;
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        continue;
Shinya Kitaoka 120a6e
    } else if (tt.first > 1) {
Shinya Kitaoka 120a6e
      if (areAlmostEqual(tt.first, 1, 1e-6))
Shinya Kitaoka 120a6e
        tt.first = 1;
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    intersections.push_back(tt);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    assert(areAlmostEqual(c0.getPoint(tt.first), c1.getPoint(tt.second), 1e-1));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return intersections.size();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Campbell Barton a6cacc
// This function checks whether the control point
Campbell Barton a6cacc
// p1 is very close to p0 or p2.
Campbell Barton a6cacc
// In this case, we are approximated to the quadratic p0-p2 segment.
shun-iwasawa 7cd1ff
// If p1 is near p0, the relationship between the original and the quadratic
shun-iwasawa 7cd1ff
// segment:
Campbell Barton a6cacc
//     tq = sqrt(ts),
Campbell Barton a6cacc
// If p1 is near p2, instead it's:
Campbell Barton a6cacc
//     tq = 1-sqrt(1-ts).
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
int intersectCloseControlPoints(const TQuadratic &c0, const TQuadratic &c1,
Shinya Kitaoka 120a6e
                                std::vector<doublepair> &intersections) {</doublepair>
Shinya Kitaoka 120a6e
  int ret = -2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double dist1          = tdistance2(c0.getP0(), c0.getP1());
Shinya Kitaoka 120a6e
  if (dist1 == 0) dist1 = 1e-20;
Shinya Kitaoka 120a6e
  double dist2          = tdistance2(c0.getP1(), c0.getP2());
Shinya Kitaoka 120a6e
  if (dist2 == 0) dist2 = 1e-20;
Shinya Kitaoka 120a6e
  double val0           = std::max(dist1, dist2) / std::min(dist1, dist2);
Shinya Kitaoka 120a6e
  double dist3          = tdistance2(c1.getP0(), c1.getP1());
Shinya Kitaoka 120a6e
  if (dist3 == 0) dist3 = 1e-20;
Shinya Kitaoka 120a6e
  double dist4          = tdistance2(c1.getP1(), c1.getP2());
Shinya Kitaoka 120a6e
  if (dist4 == 0) dist4 = 1e-20;
Shinya Kitaoka 120a6e
  double val1           = std::max(dist3, dist4) / std::min(dist3, dist4);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (val0 > 1000000 &&
Campbell Barton a6cacc
      val1 > 1000000)  // both c0 and c1 approximated by segments
Toshihiro Shimizu 890ddd
  {
Shinya Kitaoka 120a6e
    TSegment s0 = TSegment(c0.getP0(), c0.getP2());
Shinya Kitaoka 120a6e
    TSegment s1 = TSegment(c1.getP0(), c1.getP2());
Shinya Kitaoka 120a6e
    ret         = intersect(s0, s1, intersections);
Shinya Kitaoka 120a6e
    for (UINT i = intersections.size() - ret; i < (int)intersections.size();
Shinya Kitaoka 120a6e
         i++) {
Shinya Kitaoka 120a6e
      intersections[i].first = (dist1 < dist2)
Shinya Kitaoka 120a6e
                                   ? sqrt(intersections[i].first)
Shinya Kitaoka 120a6e
                                   : 1 - sqrt(1 - intersections[i].first);
Shinya Kitaoka 120a6e
      intersections[i].second = (dist3 < dist4)
Shinya Kitaoka 120a6e
                                    ? sqrt(intersections[i].second)
Shinya Kitaoka 120a6e
                                    : 1 - sqrt(1 - intersections[i].second);
Toshihiro Shimizu 890ddd
    }
Shinya Kitaoka 120a6e
    // return ret;
Campbell Barton a6cacc
  } else if (val0 > 1000000)  // c0 only approximated segment
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    TSegment s0 = TSegment(c0.getP0(), c0.getP2());
Shinya Kitaoka 120a6e
    ret         = intersect(s0, c1, intersections);
Shinya Kitaoka 120a6e
    for (UINT i = intersections.size() - ret; i < (int)intersections.size();
Shinya Kitaoka 120a6e
         i++)
Shinya Kitaoka 120a6e
      intersections[i].first = (dist1 < dist2)
Shinya Kitaoka 120a6e
                                   ? sqrt(intersections[i].first)
Shinya Kitaoka 120a6e
                                   : 1 - sqrt(1 - intersections[i].first);
Shinya Kitaoka 120a6e
    // return ret;
Campbell Barton a6cacc
  } else if (val1 > 1000000)  // only c1 approximated segment
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    TSegment s1 = TSegment(c1.getP0(), c1.getP2());
Shinya Kitaoka 120a6e
    ret         = intersect(c0, s1, intersections);
Shinya Kitaoka 120a6e
    for (UINT i = intersections.size() - ret; i < (int)intersections.size();
Shinya Kitaoka 120a6e
         i++)
Shinya Kitaoka 120a6e
      intersections[i].second = (dist3 < dist4)
Shinya Kitaoka 120a6e
                                    ? sqrt(intersections[i].second)
Shinya Kitaoka 120a6e
                                    : 1 - sqrt(1 - intersections[i].second);
Shinya Kitaoka 120a6e
    // return ret;
Toshihiro Shimizu 890ddd
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
if (ret!=-2)
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
std::vector<doublepair> intersections1;</doublepair>
Shinya Kitaoka 120a6e
int ret1 = intersect(c0, c1, intersections1, false);
Shinya Kitaoka 120a6e
if (ret1>ret)
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
intersections = intersections1;
Shinya Kitaoka 120a6e
return ret1;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
}
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int intersect(const TQuadratic &q, const TSegment &s,
Shinya Kitaoka 120a6e
              std::vector<doublepair> &intersections, bool firstIsQuad) {</doublepair>
Shinya Kitaoka 120a6e
  int solutionNumber = 0;
Shinya Kitaoka 120a6e
Campbell Barton a6cacc
  // Note the line `a*x+b*y+c = 0` we search for solutions
Shinya Kitaoka 120a6e
  //  di a*x(t)+b*y(t)+c=0 in [0,1]
Shinya Kitaoka 120a6e
  double a = s.getP0().y - s.getP1().y, b = s.getP1().x - s.getP0().x,
Shinya Kitaoka 120a6e
         c = -(a * s.getP0().x + b * s.getP0().y);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // se il segmento e' un punto
Shinya Kitaoka 120a6e
  if (0.0 == a && 0.0 == b) {
Shinya Kitaoka 120a6e
    double outParForQuad = q.getT(s.getP0());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (areAlmostEqual(q.getPoint(outParForQuad), s.getP0())) {
Shinya Kitaoka 120a6e
      if (firstIsQuad)
Shinya Kitaoka 120a6e
        intersections.push_back(DoublePair(outParForQuad, 0));
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        intersections.push_back(DoublePair(0, outParForQuad));
Shinya Kitaoka 120a6e
      return 1;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (q.getP2() - q.getP1() ==
Campbell Barton a6cacc
      q.getP1() - q.getP0()) {  // the second is a segment....
Shinya Kitaoka 120a6e
    if (firstIsQuad)
Shinya Kitaoka 120a6e
      return intersect(TSegment(q.getP0(), q.getP2()), s, intersections);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return intersect(s, TSegment(q.getP0(), q.getP2()), intersections);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<tpointd> bez, pol;</tpointd>
Shinya Kitaoka 120a6e
  bez.push_back(q.getP0());
Shinya Kitaoka 120a6e
  bez.push_back(q.getP1());
Shinya Kitaoka 120a6e
  bez.push_back(q.getP2());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bezier2poly(bez, pol);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<double> poly_1(3, 0), sol;</double>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  poly_1[0] = a * pol[0].x + b * pol[0].y + c;
Shinya Kitaoka 120a6e
  poly_1[1] = a * pol[1].x + b * pol[1].y;
Shinya Kitaoka 120a6e
  poly_1[2] = a * pol[2].x + b * pol[2].y;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!(rootFinding(poly_1, sol))) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double segmentPar, solution;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPointD v10(s.getP1() - s.getP0());
Shinya Kitaoka 120a6e
  for (UINT i = 0; i < sol.size(); ++i) {
Shinya Kitaoka 120a6e
    solution = sol[i];
Shinya Kitaoka 120a6e
    if ((0.0 <= solution && solution <= 1.0) ||
Shinya Kitaoka 120a6e
        areAlmostEqual(solution, 0.0, 1e-6) ||
Shinya Kitaoka 120a6e
        areAlmostEqual(solution, 1.0, 1e-6)) {
Shinya Kitaoka 120a6e
      segmentPar = (q.getPoint(solution) - s.getP0()) * v10 / (v10 * v10);
Shinya Kitaoka 120a6e
      if ((0.0 <= segmentPar && segmentPar <= 1.0) ||
Shinya Kitaoka 120a6e
          areAlmostEqual(segmentPar, 0.0, 1e-6) ||
Shinya Kitaoka 120a6e
          areAlmostEqual(segmentPar, 1.0, 1e-6)) {
Shinya Kitaoka 120a6e
        TPointD p1 = q.getPoint(solution);
Shinya Kitaoka 120a6e
        TPointD p2 = s.getPoint(segmentPar);
Shinya Kitaoka 120a6e
        assert(areAlmostEqual(p1, p2, 1e-1));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (firstIsQuad)
Shinya Kitaoka 120a6e
          intersections.push_back(DoublePair(solution, segmentPar));
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          intersections.push_back(DoublePair(segmentPar, solution));
Shinya Kitaoka 120a6e
        solutionNumber++;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return solutionNumber;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool isCloseToSegment(const TPointD &point, const TSegment &segment,
Shinya Kitaoka 120a6e
                      double distance) {
Shinya Kitaoka 120a6e
  TPointD a      = segment.getP0();
Shinya Kitaoka 120a6e
  TPointD b      = segment.getP1();
MCCCS a0ce32
  double length2 = tdistance2(a, b);
MCCCS a0ce32
  if (length2 < tdistance2(a, point) || length2 < tdistance2(point, b))
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  if (a.x == b.x) return fabs(point.x - a.x) <= distance;
Shinya Kitaoka 120a6e
  if (a.y == b.y) return fabs(point.y - a.y) <= distance;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // y=mx+q
Shinya Kitaoka 120a6e
  double m = (a.y - b.y) / (a.x - b.x);
Shinya Kitaoka 120a6e
  double q = a.y - (m * a.x);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double d2 = pow(fabs(point.y - (m * point.x) - q), 2) / (1 + (m * m));
Shinya Kitaoka 120a6e
  return d2 <= distance * distance;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double tdistance(const TSegment &segment, const TPointD &point) {
Shinya Kitaoka 120a6e
  TPointD v1 = segment.getP1() - segment.getP0();
Shinya Kitaoka 120a6e
  TPointD v2 = point - segment.getP0();
Shinya Kitaoka 120a6e
  TPointD v3 = point - segment.getP1();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (v2 * v1 <= 0)
Shinya Kitaoka 120a6e
    return tdistance(point, segment.getP0());
Shinya Kitaoka 120a6e
  else if (v3 * v1 >= 0)
Shinya Kitaoka 120a6e
    return tdistance(point, segment.getP1());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return fabs(v2 * rotate90(normalize(v1)));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
This formule is derived from Graphic Gems pag. 600
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  e = h^2 |a|/8
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
    e = pixel size
Toshihiro Shimizu 890ddd
    h = step
Toshihiro Shimizu 890ddd
    a = acceleration of curve (for a quadratic is a costant value)
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double computeStep(const TQuadratic &quad, double pixelSize) {
Shinya Kitaoka 120a6e
  double step = 2;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD A = quad.getP0() - 2.0 * quad.getP1() +
Shinya Kitaoka 120a6e
              quad.getP2();  // 2*A is the acceleration of the curve
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double A_len = norm(A);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
A_len is equal to 2*norm(a)
Shinya Kitaoka 120a6e
pixelSize will be 0.5*pixelSize
Shinya Kitaoka 120a6e
now h is equal to sqrt( 8 * 0.5 * pixelSize / (2*norm(a)) ) = sqrt(2) * sqrt(
Shinya Kitaoka 120a6e
pixelSize/A_len )
Shinya Kitaoka 120a6e
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (A_len > 0) step = sqrt(2 * pixelSize / A_len);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return step;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double computeStep(const TThickQuadratic &quad, double pixelSize) {
Shinya Kitaoka 120a6e
  TThickPoint cp0 = quad.getThickP0(), cp1 = quad.getThickP1(),
Shinya Kitaoka 120a6e
              cp2 = quad.getThickP2();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TQuadratic q1(TPointD(cp0.x, cp0.y), TPointD(cp1.x, cp1.y),
Shinya Kitaoka 120a6e
                TPointD(cp2.x, cp2.y)),
Shinya Kitaoka 120a6e
      q2(TPointD(cp0.y, cp0.thick), TPointD(cp1.y, cp1.thick),
Shinya Kitaoka 120a6e
         TPointD(cp2.y, cp2.thick)),
Shinya Kitaoka 120a6e
      q3(TPointD(cp0.x, cp0.thick), TPointD(cp1.x, cp1.thick),
Shinya Kitaoka 120a6e
         TPointD(cp2.x, cp2.thick));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return std::min({computeStep(q1, pixelSize), computeStep(q2, pixelSize),
Shinya Kitaoka 120a6e
                   computeStep(q3, pixelSize)});
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
  Explanation: The length of a Bezier quadratic can be calculated explicitly.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  Let Q be the quadratic. The tricks to explicitly integrate | Q'(t) | are:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    - The integrand can be reformulated as:  | Q'(t) | = sqrt(at^2 + bt + c);
Toshihiro Shimizu 890ddd
    - Complete the square beneath the sqrt (add/subtract sq(b) / 4a)
Shinya Kitaoka 120a6e
      and perform a linear variable change. We reduce the integrand to:
Shinya Kitaoka 120a6e
  sqrt(kx^2 + k),
Toshihiro Shimizu 890ddd
      where k can be taken outside => sqrt(x^2 + 1)
Toshihiro Shimizu 890ddd
    - Use x = tan y. The integrand will yield sec^3 y.
Toshihiro Shimizu 890ddd
    - Integrate by parts. In short, the resulting primitive of sqrt(x^2 + 1) is:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
        F(x) = ( x * sqrt(x^2 + 1) + log(x + sqrt(x^2 + 1)) ) / 2;
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TQuadraticLengthEvaluator::setQuad(const TQuadratic &quad) {
Shinya Kitaoka 120a6e
  const TPointD &p0 = quad.getP0();
Shinya Kitaoka 120a6e
  const TPointD &p1 = quad.getP1();
Shinya Kitaoka 120a6e
  const TPointD &p2 = quad.getP2();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD speed0(2.0 * (p1 - p0));
Shinya Kitaoka 120a6e
  TPointD accel(2.0 * (p2 - p1) - speed0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double a = accel * accel;
Shinya Kitaoka 120a6e
  double b = 2.0 * accel * speed0;
Shinya Kitaoka 120a6e
  m_c      = speed0 * speed0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_constantSpeed = isAlmostZero(a);  // => b isAlmostZero, too
Shinya Kitaoka 120a6e
  if (m_constantSpeed) {
Shinya Kitaoka 120a6e
    m_c = sqrt(m_c);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_sqrt_a_div_2 = 0.5 * sqrt(a);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_noSpeed0 = isAlmostZero(m_c);  // => b isAlmostZero, too
Shinya Kitaoka 120a6e
  if (m_noSpeed0) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_tRef   = 0.5 * b / a;
Shinya Kitaoka 120a6e
  double d = m_c - 0.5 * b * m_tRef;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_squareIntegrand = (d < TConsts::epsilon);
Shinya Kitaoka 120a6e
  if (m_squareIntegrand) {
Shinya Kitaoka 120a6e
    m_f = (b > 0) ? -sq(m_tRef) : sq(m_tRef);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_e = d / a;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double sqrt_part = sqrt(sq(m_tRef) + m_e);
Shinya Kitaoka 120a6e
  double log_arg   = m_tRef + sqrt_part;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_squareIntegrand = (log_arg < TConsts::epsilon);
Shinya Kitaoka 120a6e
  if (m_squareIntegrand) {
Shinya Kitaoka 120a6e
    m_f = (b > 0) ? -sq(m_tRef) : sq(m_tRef);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_primitive_0 = m_sqrt_a_div_2 * (m_tRef * sqrt_part + m_e * log(log_arg));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double TQuadraticLengthEvaluator::getLengthAt(double t) const {
Shinya Kitaoka 120a6e
  if (m_constantSpeed) return m_c * t;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_noSpeed0) return m_sqrt_a_div_2 * sq(t);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_squareIntegrand) {
Shinya Kitaoka 120a6e
    double t_plus_tRef = t + m_tRef;
Shinya Kitaoka 120a6e
    return m_sqrt_a_div_2 *
Shinya Kitaoka 120a6e
           (m_f + ((t_plus_tRef > 0) ? sq(t_plus_tRef) : -sq(t_plus_tRef)));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double y         = t + m_tRef;
Shinya Kitaoka 120a6e
  double sqrt_part = sqrt(sq(y) + m_e);
Shinya Kitaoka 120a6e
  double log_arg =
Shinya Kitaoka 120a6e
      y + sqrt_part;  // NOTE: log_arg >= log_arg0 >= TConsts::epsilon
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return m_sqrt_a_div_2 * (y * sqrt_part + m_e * log(log_arg)) - m_primitive_0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//  End Of File
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------