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
/*
Toshihiro Shimizu 890ddd
Questa funzione ritorna un vettore di
Shinya Kitaoka 120a6e
coppie di double (DoublePair) che individua i parametri
Toshihiro Shimizu 890ddd
dei punti d'intersezione.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  L'intero restituito indica il numero d'intersezioni che
Toshihiro Shimizu 890ddd
  sono state individuate (per due segmenti una).
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
    Se i segmenti sono paralleli il parametro viene posto a -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
Shinya Kitaoka 120a6e
    // controllo che i segmenti non siano sulla stessa retta
Shinya Kitaoka 120a6e
    if (!cross(p2 - p1, p4 - p1)) {
Shinya Kitaoka 120a6e
      // calcolo delle combinazioni baricentriche
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
Shinya Kitaoka 120a6e
      // calcolo delle prime due soluzioni
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
Shinya Kitaoka 120a6e
        if (vol1 >= 0 && vol1 <= distp3p4)  // combinazione baricentrica valida
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
Shinya Kitaoka 120a6e
  // funziona male, a volte toppa le intersezioni...
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
//=============================================================================
Shinya Kitaoka 120a6e
// questa funzione verifica se il punto di controllo p1 e' molto vicino a p0 o a
Shinya Kitaoka 120a6e
// p2:
Shinya Kitaoka 120a6e
// in tal caso, si approssima la quadratica al segmento p0-p2.
Shinya Kitaoka 120a6e
// se p1 e' vicino a p0, la relazione che lega il t del segmento al t della
Shinya Kitaoka 120a6e
// quadratica originaria e' tq = sqrt(ts),
Shinya Kitaoka 120a6e
// se p1 e' vicino a p2, invece e' 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 &&
Shinya Kitaoka 120a6e
      val1 > 1000000)  // entrambe c0 e c1  approssimate a segmenti
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;
Shinya Kitaoka 120a6e
  } else if (val0 > 1000000)  // solo c0 approssimata  a segmento
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;
Shinya Kitaoka 120a6e
  } else if (val1 > 1000000)  // solo c1 approssimata  a segmento
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
Shinya Kitaoka 120a6e
  // nota la retta a*x+b*y+c = 0 andiamo alla ricerca delle soluzioni
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() ==
Shinya Kitaoka 120a6e
      q.getP1() - q.getP0()) {  // pure il secondo e' unsegmento....
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
//-----------------------------------------------------------------------------