コード例 #1
0
ファイル: tregion.cpp プロジェクト: AmEv7Fam/opentoonz
bool TRegion::Imp::isSubRegionOf(const TRegion::Imp &r) const
{
	if (!r.getBBox().contains(getBBox()))
		return false;

	for (UINT i = 0; i < m_edge.size(); i++) {
		for (UINT j = 0; j < r.m_edge.size(); j++) {
			TEdge *e = r.m_edge[j];
			TEdge *subE = m_edge[i];
			if (subE->m_index == e->m_index &&
				(subE->m_w0 < m_edge[i]->m_w1) == (e->m_w0 < e->m_w1)) {
				bool forward = (e->m_w0 < e->m_w1);

				if (forward && (subE->m_w0 >= e->m_w0 || areAlmostEqual(subE->m_w0, e->m_w0, 1e-3)) &&
					(subE->m_w1 <= e->m_w1 || areAlmostEqual(subE->m_w1, e->m_w1, 1e-3)))
					return true;

				if (!forward && (subE->m_w0 <= e->m_w0 || areAlmostEqual(subE->m_w0, e->m_w0, 1e-3)) &&
					(subE->m_w1 >= e->m_w1 || areAlmostEqual(subE->m_w1, e->m_w1, 1e-3)))
					return true;
			}
		}
	}
	return false;
}
コード例 #2
0
ファイル: tregion.cpp プロジェクト: AmEv7Fam/opentoonz
void checkPolyline(const vector<T3DPointD> &p)
{
	int ret;

	if (p.size() < 3)
		return;

	TPointD p1;
	TPointD p2;

	int pointSize = (int)p.size() - 1;

	for (int i = 0; i < pointSize; i++) {
		for (int j = i + 1; j < pointSize; j++) {
			vector<DoublePair> res;

			p1 = TPointD(p[i].x, p[i].y);
			p2 = TPointD(p[i + 1].x, p[i + 1].y);

			TSegment s0(p1, p2);

			p1 = TPointD(p[j].x, p[j].y);
			p2 = TPointD(p[j + 1].x, p[j + 1].y);

			TSegment s1(p1, p2);

			ret = intersect(s0, s1, res);
			if (ret)
				assert(
					(ret == 1) &&
					(areAlmostEqual(res[0].first, 1) ||
					 areAlmostEqual(res[0].first, 0)) &&
					(areAlmostEqual(res[0].second, 1) ||
					 areAlmostEqual(res[0].second, 0)));
		}
	}

	p1 = TPointD(p.back().x, p.back().y);
	p2 = TPointD(p[0].x, p[0].y);

	TSegment s0(p1, p2);

	for (int j = 0; j < pointSize; j++) {
		vector<DoublePair> res;

		p1 = TPointD(p[j].x, p[j].y);
		p2 = TPointD(p[j + 1].x, p[j + 1].y);
		TSegment s1(p1, p2);

		ret = intersect(s0, s1, res);
		if (ret)
			assert(
				(ret == 1) &&
				(areAlmostEqual(res[0].first, 1) ||
				 areAlmostEqual(res[0].first, 0)) &&
				(areAlmostEqual(res[0].second, 1) ||
				 areAlmostEqual(res[0].second, 0)));
	}
}
コード例 #3
0
ファイル: cleanuppreview.cpp プロジェクト: walkerka/opentoonz
void CameraTestTool::drawClosestFieldCamera(double pixelSize) {
  CleanupParameters *cp =
      CleanupSettingsModel::instance()->getCurrentParameters();

  double zoom = cp->m_closestField / cp->m_camera.getSize().lx;
  if (areAlmostEqual(zoom, 1.0, 1e-2)) return;

  TRectD rect(cp->m_camera.getStageRect());
  rect = rect.enlarge((zoom - 1) * (rect.x1 - rect.x0 + 1) / 2.0,
                      (zoom - 1) * (rect.y1 - rect.y0 + 1) / 2.0);

  glColor3d(0.0, 0.0, 1.0);
  glLineStipple(1, 0xFFFF);
  glEnable(GL_LINE_STIPPLE);

  // box
  glBegin(GL_LINE_STRIP);
  glVertex2d(rect.x0, rect.y0);
  glVertex2d(rect.x0, rect.y1 - pixelSize);
  glVertex2d(rect.x1 - pixelSize, rect.y1 - pixelSize);
  glVertex2d(rect.x1 - pixelSize, rect.y0);
  glVertex2d(rect.x0, rect.y0);
  glEnd();

  glDisable(GL_LINE_STIPPLE);

  // camera name
  TPointD pos = rect.getP01() + TPointD(0, 4);
  glPushMatrix();
  glTranslated(pos.x, pos.y, 0);
  glScaled(2, 2, 2);
  tglDrawText(TPointD(), "Closest Field");
  glPopMatrix();
}
コード例 #4
0
ファイル: ForecastDisplay.cpp プロジェクト: crsdrw/patterns
 void
 ForecastDisplay::display() {
   std::cout << "Forecast: ";
   if (current_pressure_ > last_pressure_)
     std::cout << "Improving weather on the way!\n";
   else if (areAlmostEqual(current_pressure_, last_pressure_, 1e-20f))
     std::cout << "More of the same\n";
   else if (current_pressure_ < last_pressure_)
     std::cout << "Watch out for cooler, rainy weather\n";
 }
コード例 #5
0
ファイル: unaryFx.cpp プロジェクト: Makoto-Sasahara/opentoonz
std::string TGeometryFx::getAlias(double frame,
                                  const TRenderSettings &info) const {
  TGeometryFx *tthis = const_cast<TGeometryFx *>(this);
  TAffine affine     = tthis->getPlacement(frame);

  std::string alias = getFxType();
  alias += "[";

  // alias degli effetti connessi alle porte di input separati da virgole
  // una porta non connessa da luogo a un alias vuoto (stringa vuota)

  for (int i = 0; i < getInputPortCount(); ++i) {
    TFxPort *port = getInputPort(i);
    if (port->isConnected()) {
      TRasterFxP ifx = port->getFx();
      assert(ifx);
      alias += ifx->getAlias(frame, info);
    }
    alias += ",";
  }

  return alias +
         (areAlmostEqual(affine.a11, 0) ? "0" : ::to_string(affine.a11, 5)) +
         "," +
         (areAlmostEqual(affine.a12, 0) ? "0" : ::to_string(affine.a12, 5)) +
         "," +
         (areAlmostEqual(affine.a13, 0) ? "0" : ::to_string(affine.a13, 5)) +
         "," +
         (areAlmostEqual(affine.a21, 0) ? "0" : ::to_string(affine.a21, 5)) +
         "," +
         (areAlmostEqual(affine.a22, 0) ? "0" : ::to_string(affine.a22, 5)) +
         "," +
         (areAlmostEqual(affine.a23, 0) ? "0" : ::to_string(affine.a23, 5)) +
         "]";
}
コード例 #6
0
	void expectAlmostEqual(ValueType actual, ValueType expected, const double& precision=0.0001, String failureMessage = String())
	{
		const bool result = areAlmostEqual(actual, expected, precision);

		if (!result)
		{
			if (failureMessage.isNotEmpty())
				failureMessage << " -- ";

			failureMessage << "Expected value: " << expected << ", Actual value: " << actual;
		}

		expect(result, failureMessage);
	}
コード例 #7
0
ファイル: tregion.cpp プロジェクト: AmEv7Fam/opentoonz
void TRegion::addEdge(TEdge *e, bool minimizeEdges)
{

	if (minimizeEdges &&
		e->m_s->getMaxThickness() > 0.0 && //outline strokes ignore this
		!m_imp->m_edge.empty() &&
		m_imp->m_edge.back()->m_index == e->m_index &&
		areAlmostEqual(m_imp->m_edge.back()->m_w1, e->m_w0, 1e-5))
		m_imp->m_edge.back()->m_w1 = e->m_w1;
	else
		m_imp->m_edge.push_back(e);
	m_imp->m_isValidBBox = false;
	//if (e->m_s->isSelfLoop())
	//  assert(m_imp->m_edge.size()==1);
}
コード例 #8
0
ファイル: tregion.cpp プロジェクト: AmEv7Fam/opentoonz
TRegion *TRegion::findRegion(const TRegion &r) const
{
	if (areAlmostEqual(r.getBBox(), getBBox(), 1e-3))
		return (TRegion *)this;

	if (!getBBox().contains(r.getBBox()))
		return 0;
	TRegion *ret;

	for (UINT i = 0; i < m_imp->m_includedRegionArray.size(); i++)
		if ((ret = m_imp->m_includedRegionArray[i]->findRegion(r)) != 0)
			return ret;

	return 0;
}
コード例 #9
0
ファイル: tregion.cpp プロジェクト: AmEv7Fam/opentoonz
bool TRegion::Imp::getInternalPoint(TPointD &p, double left, double right, double y)
{
	assert(left < right);

	if (areAlmostEqual(left, right, 1e-2))
		return false;

	double mid = 0.5 * (left + right);

	p = TPointD(mid, y);

	if (noSubregionContains(p))
		return true;

	if (!getInternalPoint(p, left, mid, y))
		return getInternalPoint(p, mid, right, y);
	else
		return true;
}
コード例 #10
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);
	}
}
コード例 #11
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;
}
コード例 #12
0
int intersect(const TPointD &p1, const TPointD &p2, const TPointD &p3,
              const TPointD &p4, std::vector<DoublePair> &intersections) {
  // This algorithm is presented in Graphics Geems III pag 199

  static double Ax, Bx, Ay, By, Cx, Cy, d, f, e;
  static double x1lo, x1hi, y1lo, y1hi;

  Ax = p2.x - p1.x;
  Bx = p3.x - p4.x;

  // test delle BBox
  if (Ax < 0.0) {
    x1lo = p2.x;
    x1hi = p1.x;
  } else {
    x1lo = p1.x;
    x1hi = p2.x;
  }

  if (Bx > 0.0) {
    if (x1hi < p4.x || x1lo > p3.x) return 0;
  } else if (x1hi < p3.x || x1lo > p4.x)
    return 0;

  Ay = p2.y - p1.y;
  By = p3.y - p4.y;

  if (Ay < 0) {
    y1lo = p2.y;
    y1hi = p1.y;
  } else {
    y1lo = p1.y;
    y1hi = p2.y;
  }

  if (By > 0) {
    if (y1hi < p4.y || y1lo > p3.y) return 0;
  } else if (y1hi < p3.y || y1lo > p4.y)
    return 0;

  Cx = p1.x - p3.x;
  Cy = p1.y - p3.y;

  d = By * Cx - Bx * Cy;
  f = Ay * Bx - Ax * By;
  e = Ax * Cy - Ay * Cx;

  if (f > 0) {
    if (d < 0) return 0;

    if (!areAlmostEqual(d, f))
      if (d > f) return 0;

    if (e < 0) return 0;
    if (!areAlmostEqual(e, f))
      if (e > f) return 0;
  } else if (f < 0) {
    if (d > 0) return 0;

    if (!areAlmostEqual(d, f))
      if (d < f) return 0;

    if (e > 0) return 0;
    if (!areAlmostEqual(e, f))
      if (e < f) return 0;
  } else {
    if (d < 0 || d > 1 || e < 0 || e > 1) return 0;

    if (p1 == p2 && p3 == p4) {
      intersections.push_back(DoublePair(0, 0));
      return 1;
    }

    // Check that the segments are not on the same line.
    if (!cross(p2 - p1, p4 - p1)) {
      // Calculation of Barycentric combinations.
      double distp2p1 = norm2(p2 - p1);
      double distp3p4 = norm2(p3 - p4);

      double dist2_p3p1 = norm2(p3 - p1);
      double dist2_p4p1 = norm2(p4 - p1);
      double dist2_p3p2 = norm2(p3 - p2);
      double dist2_p4p2 = norm2(p4 - p2);

      int intersection = 0;

      // Calculation of the first two solutions.
      double vol1;

      if (distp3p4) {
        distp3p4 = sqrt(distp3p4);

        vol1 = (p1 - p3) * normalize(p4 - p3);

        if (vol1 >= 0 && vol1 <= distp3p4)  // Barycentric combinations valid
        {
          intersections.push_back(DoublePair(0.0, vol1 / distp3p4));
          ++intersection;
        }

        vol1 = (p2 - p3) * normalize(p4 - p3);

        if (vol1 >= 0 && vol1 <= distp3p4) {
          intersections.push_back(DoublePair(1.0, vol1 / distp3p4));
          ++intersection;
        }
      }

      if (distp2p1) {
        distp2p1 = sqrt(distp2p1);

        vol1 = (p3 - p1) * normalize(p2 - p1);

        if (dist2_p3p2 && dist2_p3p1)
          if (vol1 >= 0 && vol1 <= distp2p1) {
            intersections.push_back(DoublePair(vol1 / distp2p1, 0.0));
            ++intersection;
          }

        vol1 = (p4 - p1) * normalize(p2 - p1);

        if (dist2_p4p2 && dist2_p4p1)
          if (vol1 >= 0 && vol1 <= distp2p1) {
            intersections.push_back(DoublePair(vol1 / distp2p1, 1.0));
            ++intersection;
          }
      }
      return intersection;
    }
    return -1;
  }

  double par_s = d / f;
  double par_t = e / f;

  intersections.push_back(DoublePair(par_s, par_t));
  return 1;
}
コード例 #13
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();
}
コード例 #14
0
ファイル: tregion.cpp プロジェクト: AmEv7Fam/opentoonz
//-----------------------------------------------------------------------------
bool TRegion::Imp::contains(const TPointD &p) const
{
	bool leftAreOdd = false;

	if (!getBBox().contains(p))
		return false;

	//printContains(p);

	UINT i;

	int side = 0;

	for (i = 0; i < m_edge.size() * 2; i++) //i pari, esplora gli edge,
											//i dispari esplora i segmenti di autoclose tra un edge e il successivo
	{
		if (i & 0x1) {
			TPointD p0 = m_edge[i / 2]->m_s->getPoint(m_edge[i / 2]->m_w1);
			TPointD p1;
			if (i / 2 < m_edge.size() - 1)
				p1 = m_edge[i / 2 + 1]->m_s->getPoint(m_edge[i / 2 + 1]->m_w0);
			else
				p1 = m_edge[0]->m_s->getPoint(m_edge[0]->m_w0);

			if (tmin(p0.y, p1.y) > p.y || tmax(p0.y, p1.y) < p.y)
				continue;

			if (!areAlmostEqual(p0, p1, 1e-2))
				side = findSides(p, TQuadratic(p0, 0.5 * (p0 + p1), p1), 0.0, 1.0, leftAreOdd, side);

			continue;
		}

		TEdge *e = m_edge[i / 2];

		TStroke *s = e->m_s;
		if (s->getBBox().y0 > p.y || s->getBBox().y1 < p.y)
			continue;

		double t0, t1;
		int chunkIndex0, chunkIndex1;
		const TThickQuadratic *q0, *q1;

		s->getChunkAndT(e->m_w0, chunkIndex0, t0);
		s->getChunkAndT(e->m_w1, chunkIndex1, t1);
		q0 = s->getChunk(chunkIndex0);
		q1 = s->getChunk(chunkIndex1);

		if (i == 0 && areAlmostEqual(q0->getPoint(t0).y, p.y)) {
			double tEnd;
			int chunkIndexEnd;
			TEdge *edgeEnd = m_edge.back();
			edgeEnd->m_s->getChunkAndT(edgeEnd->m_w1, chunkIndexEnd, tEnd);
			assert(areAlmostEqual(edgeEnd->m_s->getChunk(chunkIndexEnd)->getPoint(tEnd).y, p.y));
			side = edgeEnd->m_s->getChunk(chunkIndexEnd)->getSpeed(tEnd).y > 0 ? 1 : -1;
		}

		if (chunkIndex0 != chunkIndex1) {
			/*if (chunkIndex0>chunkIndex1)
		  {
		  tswap(chunkIndex0, chunkIndex1);
		  tswap(t0, t1);
      }*/
			if (chunkIndex0 > chunkIndex1) {
				side = findSides(p, *q0, t0, 0, leftAreOdd, side);
				for (int j = chunkIndex0 - 1; j > chunkIndex1; j--)
					side = findSides(p, *s->getChunk(j), 1, 0, leftAreOdd, side);
				side = findSides(p, *q1, 1, t1, leftAreOdd, side);
			} else {
				side = findSides(p, *q0, t0, 1, leftAreOdd, side);
				for (int j = chunkIndex0 + 1; j < chunkIndex1; j++)
					side = findSides(p, *s->getChunk(j), 0, 1, leftAreOdd, side);
				side = findSides(p, *q1, 0, t1, leftAreOdd, side);
			}

		} else
			side = findSides(p, *q0, t0, t1, leftAreOdd, side);

		if (i & 0x1)
			delete q0;
	}

	return leftAreOdd;
}