コード例 #1
0
ファイル: tregion.cpp プロジェクト: AmEv7Fam/opentoonz
		bool areInYRange(const TQuadratic &q, double t0, double t1,
						 int(&solIdx)[2]) const
		{
			assert(0.0 <= t0 && t0 <= 1.0), assert(0.0 <= t1 && t1 <= 1.0);

			const TPointD &p0 = q.getP0(), &p1 = q.getP1(), &p2 = q.getP2();

			double der[2] = {y(p1) - y(p0), y(p0) - y(p1) + y(p2) - y(p1)},
				   s;

			double y0 = getY(q, t0), y1 = getY(q, t1);

			if (tcg::poly_ops::solve_1(der, &s, m_tol)) {
				if (t0 <= s && s < t1) {
					double ys = getY(q, s);

					solIdx[0] = (ys < m_y && m_y <= y0 || y0 <= m_y && m_y < ys) ? 0 : -1;
					solIdx[1] = (ys < m_y && m_y < y1 || y1 < m_y && m_y < ys) ? 1 : -1;
				} else if (t1 < s && s <= t0) {
					double ys = getY(q, s);

					solIdx[0] = (ys < m_y && m_y <= y0 || y0 <= m_y && m_y < ys) ? 1 : -1;
					solIdx[1] = (ys < m_y && m_y < y1 || y1 < m_y && m_y < ys) ? 0 : -1;
				} else {
					solIdx[0] = isInYRange(y0, y1) ? (t0 < s) ? 0 : 1
												   : -1;
					solIdx[1] = -1;
				}
			} else
				solIdx[1] = solIdx[0] = -1;

			return (solIdx[0] >= 0 || solIdx[1] >= 0);
		}
コード例 #2
0
ファイル: tregion.cpp プロジェクト: AmEv7Fam/opentoonz
		int leftScanlineIntersections(const TQuadratic &q, double t0, double t1,
									  bool &ascending)
		{
			const TPointD &p0 = q.getP0(), &p1 = q.getP1(), &p2 = q.getP2();

			double y1_y0 = y(p1) - y(p0),
				   accel = y(p2) - y(p1) - y1_y0;

			// Fallback to segment case whenever we have too flat quads
			if (std::fabs(accel) < m_tol)
				return leftScanlineIntersections(TSegment(q.getPoint(t0), q.getPoint(t1)), ascending);

			// Calculate new ascension
			int ascends = isAscending(q, t1, t0 < t1);
			bool wasAscending = ascending;

			ascending = (ascends > 0) ? true
									  : (ascends < 0) ? false
													  : (wasAscending = !ascending, ascending); // Couples with the cusps check below

			// In case the y coords are not in range, quit
			int solIdx[2];
			if (!areInYRange(q, t0, t1, solIdx))
				return 0;

			// Identify coordinates for which  q(t) == y
			double poly[3] = {y(p0) - m_y, 2.0 * y1_y0, accel},
				   s[2];

			int sCount = tcg::poly_ops::solve_2(poly, s); // Tolerance dealt at the first bailout above
			if (sCount == 2) {
				// Calculate result
				int result = 0;

				if (solIdx[0] >= 0) {
					result += int(getX(q, s[solIdx[0]]) < m_x && (getY(q, t0) != m_y || ascending == wasAscending)); // Cusp check
				}

				if (solIdx[1] >= 0)
					result += int(getX(q, s[solIdx[1]]) < m_x);

				return result;
			}

			return (assert(sCount == 0), 0); // Should never happen, since m_y is in range. If it ever happens,
											 // it must be close to the extremal - so quit with no intersections.
		}
コード例 #3
0
void TQuadraticLengthEvaluator::setQuad(const TQuadratic &quad) {
  const TPointD &p0 = quad.getP0();
  const TPointD &p1 = quad.getP1();
  const TPointD &p2 = quad.getP2();

  TPointD speed0(2.0 * (p1 - p0));
  TPointD accel(2.0 * (p2 - p1) - speed0);

  double a = accel * accel;
  double b = 2.0 * accel * speed0;
  m_c      = speed0 * speed0;

  m_constantSpeed = isAlmostZero(a);  // => b isAlmostZero, too
  if (m_constantSpeed) {
    m_c = sqrt(m_c);
    return;
  }

  m_sqrt_a_div_2 = 0.5 * sqrt(a);

  m_noSpeed0 = isAlmostZero(m_c);  // => b isAlmostZero, too
  if (m_noSpeed0) return;

  m_tRef   = 0.5 * b / a;
  double d = m_c - 0.5 * b * m_tRef;

  m_squareIntegrand = (d < TConsts::epsilon);
  if (m_squareIntegrand) {
    m_f = (b > 0) ? -sq(m_tRef) : sq(m_tRef);
    return;
  }

  m_e = d / a;

  double sqrt_part = sqrt(sq(m_tRef) + m_e);
  double log_arg   = m_tRef + sqrt_part;

  m_squareIntegrand = (log_arg < TConsts::epsilon);
  if (m_squareIntegrand) {
    m_f = (b > 0) ? -sq(m_tRef) : sq(m_tRef);
    return;
  }

  m_primitive_0 = m_sqrt_a_div_2 * (m_tRef * sqrt_part + m_e * log(log_arg));
}
コード例 #4
0
double computeStep(const TQuadratic &quad, double pixelSize) {
  double step = 2;

  TPointD A = quad.getP0() - 2.0 * quad.getP1() +
              quad.getP2();  // 2*A is the acceleration of the curve

  double A_len = norm(A);

  /*
A_len is equal to 2*norm(a)
pixelSize will be 0.5*pixelSize
now h is equal to sqrt( 8 * 0.5 * pixelSize / (2*norm(a)) ) = sqrt(2) * sqrt(
pixelSize/A_len )
*/

  if (A_len > 0) step = sqrt(2 * pixelSize / A_len);

  return step;
}
コード例 #5
0
void makeOutline(const TStroke *stroke, int startQuad, int endQuad,
				 outlineBoundary &ob, double error2)
{
	//std::ofstream cout("c:\\temp\\outline.txt");

	assert(stroke);
	assert(startQuad >= 0);
	assert(endQuad < stroke->getChunkCount());
	assert(startQuad <= endQuad);
	TThickQuadratic *tq;
	std::vector<TQuadratic *> arrayUp, arrayDown;
	TQuadratic arc;

	if (!stroke->getChunkCount())
		return;
	//if (startQuad==0)
	{
		const TThickQuadratic *tq = stroke->getChunk(startQuad);

		// trova i punti sul cerchio che corrispondono
		// a due fette di 90 gradi.
		// Ritorna una quadratica invece di tre singoli punti solo per compattezza.
		TQuadratic
			arc = getCircleQuarter(tq, QUARTER_BEGIN);

		// estrae le quadratiche che corrispondono ad i due archi...
		splitCircularArcIntoQuadraticCurves(tq->getP0(), arc.getP0(), arc.getP1(), arrayUp);
		// e le ordina in modo che l'outline sia composta sempre da
		// una curva superiore ed una inferiore corrispondente
		changeDirection(arrayUp);
		splitCircularArcIntoQuadraticCurves(tq->getP0(), arc.getP1(), arc.getP2(), arrayDown);
		changeDirection(arrayDown, true);
		// copia le curve nell'outline; se gli array non hanno la stessa dimensione
		//  quello con meno curve viene riempito con curve improprie
		//  che hanno i punti di controllo coincidente con l'ultimo estremo valido
		//cout<<"quads del semicerchio left:"<<std::endl;
		copy(/*cout,  */ arrayUp, arrayDown, ob);
	}

	for (int i = startQuad; i <= endQuad; ++i) {
		tq = (TThickQuadratic *)stroke->getChunk(i);
		TThickPoint p0 = tq->getThickP0();
		TThickPoint p1 = tq->getThickP1();
		TThickPoint p2 = tq->getThickP2();
		if (p0.x == p1.x) {
			if (p1.x == p2.x && ((p1.y > p0.y && p1.y > p2.y) || (p1.y < p0.y && p1.y < p2.y)))
				tq = new TThickQuadratic(p0, 0.5 * (p0 + p1), p1);
		} else if (p0.y == p1.y) {
			if (p0.y == p2.y && ((p1.x > p0.x && p1.x > p2.x) || (p1.x < p0.x && p1.x < p2.x)))
				tq = new TThickQuadratic(p0, 0.5 * (p0 + p1), p1);
		} else {
			double fac1 = 1.0 / (p0.x - p1.x);
			double fac2 = 1.0 / (p0.y - p1.y);

			double aux1 = fac1 * (p2.x - p1.x);
			double aux2 = fac2 * (p2.y - p1.y);
			double aux3 = fac1 * (p0.x - p2.x);
			double aux4 = fac2 * (p0.y - p2.y);

			if ((areAlmostEqual(aux1, aux2) && aux1 >= 0) ||
				(areAlmostEqual(aux3, aux4) && aux3 >= 0 && aux3 <= 1))
				tq = new TThickQuadratic(p0, 0.5 * (p0 + p1), p1);
		}

		//cout<<"quad# "<<i<<":" <<*tq<<std::endl;
		makeOutline(/*cout, */ ob, *tq, error2);
		if (tq != stroke->getChunk(i))
			delete tq;
	}

	arrayUp.clear();
	arrayDown.clear();

	// come sopra ultimo pezzo di arco
	//	if (endQuad==stroke->getChunkCount()-1)
	{
		arc = getCircleQuarter(tq, QUARTER_END);
		splitCircularArcIntoQuadraticCurves(tq->getP2(), arc.getP1(), arc.getP0(), arrayUp);
		changeDirection(arrayUp);
		splitCircularArcIntoQuadraticCurves(tq->getP2(), arc.getP2(), arc.getP1(), arrayDown);
		changeDirection(arrayDown, true);
		//cout<<"quads del semicerchio right:"<<std::endl;

		copy(/*cout,*/ arrayUp, arrayDown, ob);
	}
}
コード例 #6
0
int intersect(const TQuadratic &q, const TSegment &s,
              std::vector<DoublePair> &intersections, bool firstIsQuad) {
  int solutionNumber = 0;

  // Note the line `a*x+b*y+c = 0` we search for solutions
  //  di a*x(t)+b*y(t)+c=0 in [0,1]
  double a = s.getP0().y - s.getP1().y, b = s.getP1().x - s.getP0().x,
         c = -(a * s.getP0().x + b * s.getP0().y);

  // se il segmento e' un punto
  if (0.0 == a && 0.0 == b) {
    double outParForQuad = q.getT(s.getP0());

    if (areAlmostEqual(q.getPoint(outParForQuad), s.getP0())) {
      if (firstIsQuad)
        intersections.push_back(DoublePair(outParForQuad, 0));
      else
        intersections.push_back(DoublePair(0, outParForQuad));
      return 1;
    }
    return 0;
  }

  if (q.getP2() - q.getP1() ==
      q.getP1() - q.getP0()) {  // the second is a segment....
    if (firstIsQuad)
      return intersect(TSegment(q.getP0(), q.getP2()), s, intersections);
    else
      return intersect(s, TSegment(q.getP0(), q.getP2()), intersections);
  }

  std::vector<TPointD> bez, pol;
  bez.push_back(q.getP0());
  bez.push_back(q.getP1());
  bez.push_back(q.getP2());

  bezier2poly(bez, pol);

  std::vector<double> poly_1(3, 0), sol;

  poly_1[0] = a * pol[0].x + b * pol[0].y + c;
  poly_1[1] = a * pol[1].x + b * pol[1].y;
  poly_1[2] = a * pol[2].x + b * pol[2].y;

  if (!(rootFinding(poly_1, sol))) return 0;

  double segmentPar, solution;

  TPointD v10(s.getP1() - s.getP0());
  for (UINT i = 0; i < sol.size(); ++i) {
    solution = sol[i];
    if ((0.0 <= solution && solution <= 1.0) ||
        areAlmostEqual(solution, 0.0, 1e-6) ||
        areAlmostEqual(solution, 1.0, 1e-6)) {
      segmentPar = (q.getPoint(solution) - s.getP0()) * v10 / (v10 * v10);
      if ((0.0 <= segmentPar && segmentPar <= 1.0) ||
          areAlmostEqual(segmentPar, 0.0, 1e-6) ||
          areAlmostEqual(segmentPar, 1.0, 1e-6)) {
        TPointD p1 = q.getPoint(solution);
        TPointD p2 = s.getPoint(segmentPar);
        assert(areAlmostEqual(p1, p2, 1e-1));

        if (firstIsQuad)
          intersections.push_back(DoublePair(solution, segmentPar));
        else
          intersections.push_back(DoublePair(segmentPar, solution));
        solutionNumber++;
      }
    }
  }

  return solutionNumber;
}
コード例 #7
0
int intersectCloseControlPoints(const TQuadratic &c0, const TQuadratic &c1,
                                std::vector<DoublePair> &intersections) {
  int ret = -2;

  double dist1          = tdistance2(c0.getP0(), c0.getP1());
  if (dist1 == 0) dist1 = 1e-20;
  double dist2          = tdistance2(c0.getP1(), c0.getP2());
  if (dist2 == 0) dist2 = 1e-20;
  double val0           = std::max(dist1, dist2) / std::min(dist1, dist2);
  double dist3          = tdistance2(c1.getP0(), c1.getP1());
  if (dist3 == 0) dist3 = 1e-20;
  double dist4          = tdistance2(c1.getP1(), c1.getP2());
  if (dist4 == 0) dist4 = 1e-20;
  double val1           = std::max(dist3, dist4) / std::min(dist3, dist4);

  if (val0 > 1000000 &&
      val1 > 1000000)  // both c0 and c1 approximated by segments
  {
    TSegment s0 = TSegment(c0.getP0(), c0.getP2());
    TSegment s1 = TSegment(c1.getP0(), c1.getP2());
    ret         = intersect(s0, s1, intersections);
    for (UINT i = intersections.size() - ret; i < (int)intersections.size();
         i++) {
      intersections[i].first = (dist1 < dist2)
                                   ? sqrt(intersections[i].first)
                                   : 1 - sqrt(1 - intersections[i].first);
      intersections[i].second = (dist3 < dist4)
                                    ? sqrt(intersections[i].second)
                                    : 1 - sqrt(1 - intersections[i].second);
    }
    // return ret;
  } else if (val0 > 1000000)  // c0 only approximated segment
  {
    TSegment s0 = TSegment(c0.getP0(), c0.getP2());
    ret         = intersect(s0, c1, intersections);
    for (UINT i = intersections.size() - ret; i < (int)intersections.size();
         i++)
      intersections[i].first = (dist1 < dist2)
                                   ? sqrt(intersections[i].first)
                                   : 1 - sqrt(1 - intersections[i].first);
    // return ret;
  } else if (val1 > 1000000)  // only c1 approximated segment
  {
    TSegment s1 = TSegment(c1.getP0(), c1.getP2());
    ret         = intersect(c0, s1, intersections);
    for (UINT i = intersections.size() - ret; i < (int)intersections.size();
         i++)
      intersections[i].second = (dist3 < dist4)
                                    ? sqrt(intersections[i].second)
                                    : 1 - sqrt(1 - intersections[i].second);
    // return ret;
  }

  /*
if (ret!=-2)
{
std::vector<DoublePair> intersections1;
int ret1 = intersect(c0, c1, intersections1, false);
if (ret1>ret)
{
intersections = intersections1;
return ret1;
}
}
*/

  return ret;
}
コード例 #8
0
int intersect(const TQuadratic &c0, const TQuadratic &c1,
              std::vector<DoublePair> &intersections, bool checksegments) {
  int ret;

  // Works baddly, sometimes patch intersections...
  if (checksegments) {
    ret = intersectCloseControlPoints(c0, c1, intersections);
    if (ret != -2) return ret;
  }

  double a = c0.getP0().x - 2 * c0.getP1().x + c0.getP2().x;
  double b = 2 * (c0.getP1().x - c0.getP0().x);
  double d = c0.getP0().y - 2 * c0.getP1().y + c0.getP2().y;
  double e = 2 * (c0.getP1().y - c0.getP0().y);

  double coeff = b * d - a * e;
  int i        = 0;

  if (areAlmostEqual(coeff, 0.0))  // c0 is a Segment, or a single point!!!
  {
    TSegment s = TSegment(c0.getP0(), c0.getP2());
    ret        = intersect(s, c1, intersections);
    if (a == 0 && d == 0)  // values of t in s coincide with values of t in c0
      return ret;

    for (i = intersections.size() - ret; i < (int)intersections.size(); i++) {
      intersections[i].first = c0.getT(s.getPoint(intersections[i].first));
    }
    return ret;
  }

  double c = c0.getP0().x;
  double f = c0.getP0().y;

  double g = c1.getP0().x - 2 * c1.getP1().x + c1.getP2().x;
  double h = 2 * (c1.getP1().x - c1.getP0().x);
  double k = c1.getP0().x;

  double m = c1.getP0().y - 2 * c1.getP1().y + c1.getP2().y;
  double p = 2 * (c1.getP1().y - c1.getP0().y);
  double q = c1.getP0().y;

  if (areAlmostEqual(h * m - g * p,
                     0.0))  // c1 is a Segment, or a single point!!!
  {
    TSegment s = TSegment(c1.getP0(), c1.getP2());
    ret        = intersect(c0, s, intersections);
    if (g == 0 && m == 0)  // values of t in s coincide with values of t in c0
      return ret;

    for (i = intersections.size() - ret; i < (int)intersections.size(); i++) {
      intersections[i].second = c1.getT(s.getPoint(intersections[i].second));
    }
    return ret;
  }

  double a2 = (g * d - a * m);
  double b2 = (h * d - a * p);
  double c2 = ((k - c) * d + (f - q) * a);

  coeff = 1.0 / coeff;

  double A   = (a * a + d * d) * coeff * coeff;
  double aux = A * c2 + (a * b + d * e) * coeff;

  std::vector<double> t;
  std::vector<double> solutions;

  t.push_back(aux * c2 + a * c + d * f - k * a - d * q);
  aux += A * c2;
  t.push_back(aux * b2 - h * a - d * p);
  t.push_back(aux * a2 + A * b2 * b2 - g * a - d * m);
  t.push_back(2 * A * a2 * b2);
  t.push_back(A * a2 * a2);

  rootFinding(t, solutions);
  //  solutions.push_back(0.0); //per convenzione; un valore vale l'altro....

  for (i = 0; i < (int)solutions.size(); i++) {
    if (solutions[i] < 0) {
      if (areAlmostEqual(solutions[i], 0, 1e-6))
        solutions[i] = 0;
      else
        continue;
    } else if (solutions[i] > 1) {
      if (areAlmostEqual(solutions[i], 1, 1e-6))
        solutions[i] = 1;
      else
        continue;
    }

    DoublePair tt;
    tt.second = solutions[i];
    tt.first  = coeff * (tt.second * (a2 * tt.second + b2) + c2);
    if (tt.first < 0) {
      if (areAlmostEqual(tt.first, 0, 1e-6))
        tt.first = 0;
      else
        continue;
    } else if (tt.first > 1) {
      if (areAlmostEqual(tt.first, 1, 1e-6))
        tt.first = 1;
      else
        continue;
    }

    intersections.push_back(tt);

    assert(areAlmostEqual(c0.getPoint(tt.first), c1.getPoint(tt.second), 1e-1));
  }
  return intersections.size();
}
コード例 #9
0
ファイル: tregion.cpp プロジェクト: AmEv7Fam/opentoonz
		inline double get(const TQuadratic &q, double t, double(TPointD::*val)) const
		{
			double one_t = 1.0 - t;
			return one_t * (one_t * q.getP0().*val + t * q.getP1().*val) + t * (one_t * q.getP1().*val + t * q.getP2().*val);
		}