void ControlPointEditorStroke::adjustChunkParity() {
  TStroke *stroke = getStroke();
  if (!stroke) return;
  int firstChunk;
  int secondChunk = stroke->getChunkCount();
  int i;
  for (i = stroke->getChunkCount() - 1; i > 0; i--) {
    if (tdistance(stroke->getChunk(i - 1)->getP0(),
                  stroke->getChunk(i)->getP2()) < 0.5)
      continue;
    TPointD p0 = stroke->getChunk(i - 1)->getP1();
    TPointD p1 = stroke->getChunk(i - 1)->getP2();
    TPointD p2 = stroke->getChunk(i)->getP1();
    if (isCuspPoint(p0, p1, p2) || isLinearPoint(p0, p1, p2)) {
      firstChunk = i;
      insertPoint(stroke, firstChunk, secondChunk);
      secondChunk = firstChunk;
    }
  }
  insertPoint(stroke, 0, secondChunk);
}
void ControlPointEditorStroke::setStroke(const TVectorImageP &vi,
                                         int strokeIndex) {
  m_strokeIndex = strokeIndex;
  m_vi          = vi;
  if (!vi || strokeIndex == -1) {
    m_controlPoints.clear();
    return;
  }
  TStroke *stroke              = getStroke();
  const TThickQuadratic *chunk = stroke->getChunk(0);
  if (stroke->getControlPointCount() == 3 && chunk->getP0() == chunk->getP1() &&
      chunk->getP0() == chunk->getP2()) {
    resetControlPoints();
    return;
  }
  adjustChunkParity();
  resetControlPoints();
}
void ControlPointEditorStroke::resetControlPoints() {
  TStroke *stroke = getStroke();
  if (!stroke) return;
  m_controlPoints.clear();
  int i;
  int cpCount = stroke->getControlPointCount();
  if (cpCount == 3) {
    const TThickQuadratic *chunk = stroke->getChunk(0);
    if (chunk->getP0() == chunk->getP1() &&
        chunk->getP0() == chunk->getP2())  // E' un punto
    {
      m_controlPoints.push_back(
          ControlPoint(0, TPointD(0.0, 0.0), TPointD(0.0, 0.0), true));
      return;
    }
  }
  for (i = 0; i < cpCount; i = i + 4) {
    TThickPoint speedIn, speedOut;
    bool isPickOut    = false;
    TThickPoint p     = stroke->getControlPoint(i);
    TThickPoint precP = stroke->getControlPoint(i - 1);
    TThickPoint nextP = stroke->getControlPoint(i + 1);
    if (0 < i && i < cpCount - 1)  // calcola speedIn e speedOut
    {
      speedIn  = p - precP;
      speedOut = nextP - p;
    }
    if (i == 0)  // calcola solo lo speedOut
    {
      speedOut                  = nextP - p;
      if (isSelfLoop()) speedIn = p - stroke->getControlPoint(cpCount - 2);
    }
    if (i == cpCount - 1)  // calcola solo lo speedIn
      speedIn = p - precP;
    if (i == cpCount - 1 && isSelfLoop())
      break;  // Se lo stroke e' selfLoop inserisco solo il primo dei due punti
              // coincidenti

    bool isCusp = ((i != 0 && i != cpCount - 1) || (isSelfLoop() && i == 0))
                      ? isCuspPoint(precP, p, nextP)
                      : true;
    m_controlPoints.push_back(ControlPoint(i, speedIn, speedOut, isCusp));
  }
}
Example #4
0
void TRegion::Imp::computeScanlineIntersections(double y, vector<double> &intersections) const
{
	TRectD bbox = getBBox();
	if (y <= bbox.y0 || y >= bbox.y1)
		return;

	assert(intersections.empty());

	UINT i, firstSide = 0;
	vector<int> sides;

	for (i = 0; i < m_edge.size(); i++) {
		TEdge *e = m_edge[i];

		TStroke *s = e->m_s;
		if (s->getBBox().y0 > y || s->getBBox().y1 < y)
			continue;
		int chunkIndex0, chunkIndex1;
		double t0, t1;
		s->getChunkAndT(e->m_w0, chunkIndex0, t0);
		s->getChunkAndT(e->m_w1, chunkIndex1, t1);

		if (chunkIndex0 > chunkIndex1) {
			findIntersections(y, *s->getChunk(chunkIndex0), t0, 0, intersections, sides);
			for (int j = chunkIndex0 - 1; j > chunkIndex1; j--)
				findIntersections(y, *s->getChunk(j), 1, 0, intersections, sides);
			findIntersections(y, *s->getChunk(chunkIndex1), 1, t1, intersections, sides);
		} else if (chunkIndex0 < chunkIndex1) {
			findIntersections(y, *s->getChunk(chunkIndex0), t0, 1, intersections, sides);
			for (int j = chunkIndex0 + 1; j < chunkIndex1; j++)
				findIntersections(y, *s->getChunk(j), 0, 1, intersections, sides);
			findIntersections(y, *s->getChunk(chunkIndex1), 0, t1, intersections, sides);
		} else {
			findIntersections(y, *s->getChunk(chunkIndex0), t0, t1, intersections, sides);
		}
	}

	if (intersections.size() > 0 && intersections.front() == intersections.back()) {
		intersections.pop_back();
		if (!sides.empty() && sides.front() == sides.back() && intersections.size() > 0)
			intersections.erase(intersections.begin());
	}

	std::sort(intersections.begin(), intersections.end());
	assert(intersections.size() % 2 == 0);
}
Example #5
0
void tglDraw(const TVectorRenderData &rd, TRegion *r, bool pushAttribs) {
  checkErrorsByGL;
  assert(r);
  checkErrorsByGL;
  if (!r) return;
  bool alphaChannel = rd.m_alphaChannel;
  checkErrorsByGL;

  int j          = 0;
  bool visible   = false;
  int colorCount = 0;

  TColorStyleP style;
  if (rd.m_paintCheckEnabled && r->getStyle() == rd.m_colorCheckIndex) {
    static TSolidColorStyle *redColor = new TSolidColorStyle();
    redColor->addRef();
    redColor->setMainColor(TPixel::Red);
    style = redColor;
  } else if (rd.m_tcheckEnabled) {
    static TSolidColorStyle *color = new TSolidColorStyle();
    color->addRef();
    color->setMainColor(rd.m_tCheckPaint);
    style = color;
  } else
    style = rd.m_palette->getStyle(r->getStyle());

  colorCount = style->getColorParamCount();
  if (colorCount == 0) {  // for example texture
    visible = true;
  } else {
    visible = false;
    for (j = 0; j < colorCount && !visible; j++) {
      TPixel32 color            = style->getColorParamValue(j);
      if (rd.m_cf) color        = (*(rd.m_cf))(color);
      if (color.m != 0) visible = true;
    }
  }
  if (visible) {
    TRegionProp *prop = r->getProp(/*rd.m_palette*/);
    /// questo codice satva dentro tregion::getprop/////
    int styleId = r->getStyle();
    if (styleId) {
      // TColorStyle * style = rd.m_palette->getStyle(styleId);
      if (!style->isRegionStyle() || style->isEnabled() == false) {
        prop = 0;
      } else {
        // Warning: The same remark of stroke props holds here.
        if (!prop || style.getPointer() != prop->getColorStyle()) {
          r->setProp(style->makeRegionProp(r));
          prop = r->getProp();
        }
      }
    }

    ////// draw
    if (prop) {
      if (pushAttribs) glPushAttrib(GL_ALL_ATTRIB_BITS);

      tglEnableLineSmooth(true);
//#define DRAW_EDGE_NUMBERS
#ifdef DRAW_EDGE_NUMBERS
      glPushMatrix();
      tglMultMatrix(rd.m_aff);
      switch (Index % 7) {
      case 0:
        tglColor(TPixel::Red);
        break;
      case 1:
        tglColor(TPixel::Green);
        break;
      case 2:
        tglColor(TPixel::Blue);
        break;
      case 3:
        tglColor(TPixel::Cyan);
        break;
      case 4:
        tglColor(TPixel::Magenta);
        break;
      case 5:
        tglColor(TPixel::Yellow);
        break;
      case 6:
        tglColor(TPixel::Black);
        break;
      default:
        tglColor(TPixel::Red);
        break;
      }

      Index++;
      if (rIndex == 2) {
        double y = r->getEdge(0)
                       ->m_s
                       ->getThickPoint(
                           (r->getEdge(0)->m_w0 + r->getEdge(0)->m_w1) / 2.0)
                       .y;
        tglDrawSegment(TPointD(-1000, y), TPointD(1000, y));
      }

      for (int i = 0; i < (int)r->getEdgeCount(); i++) {
        TEdge *e  = r->getEdge(i);
        TPointD p = e->m_s->getPoint(0.8 * e->m_w0 + 0.2 * e->m_w1);
        if (i == 0)
          tglDrawText(p,
                      (QString::number(rIndex) + QString("-0")).toStdString());
        else
          tglDrawText(p, QString::number(i).toStdString());
        if (e->m_index == 3) {
          tglColor(TPixel::Black);
          TStroke *s = e->m_s;
          drawPoint(s->getChunk(0)->getP0(), .3);
          tglColor(TPixel::Red);
          tglDrawText(s->getChunk(0)->getP0(),
                      QString::number(0).toStdString());
          for (int ii = 0; ii < s->getChunkCount(); ii++) {
            drawPoint(s->getChunk(ii)->getP2(), .3);
            if (ii < s->getChunkCount() - 1) {
              tglColor(TPixel::Red);
              tglDrawText(s->getChunk(ii)->getP2(),
                          QString::number(ii + 1).toStdString());
            }
          }
        }
      }
      glPopMatrix();
#endif

      if (alphaChannel) {
        GLboolean red, green, blue, alpha;
        tglGetColorMask(red, green, blue, alpha);

        // Draw RGB channels
        tglEnableBlending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glColorMask(red, green, blue, GL_FALSE);
        prop->draw(rd);

        // Draw Matte channel
        tglEnableBlending(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
        glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, alpha);
        prop->draw(rd);

        glColorMask(red, green, blue, alpha);
      } else {
        // pezza: in render, le aree fillate dei custom styles sparivano.
        if (!rd.m_isOfflineRender || !rd.m_isImagePattern)
          tglRgbOnlyColorMask();  // RGB components only

        prop->draw(rd);
      }

      if (pushAttribs) glPopAttrib();
    }
  }

  for (UINT i = 0; i < r->getSubregionCount(); i++)
    tglDraw(rd, r->getSubregion(i), pushAttribs);
  checkErrorsByGL;
}
Example #6
0
int TRegion::Imp::leftScanlineIntersections(
	const TPointD &p,
	double(TPointD::*h), double(TPointD::*v)) const
{
	struct Locals {
		const Imp *m_this;
		double m_x, m_y,
			m_tol;
		double TPointD::*m_h,
			TPointD::*m_v;

		inline double x(const TPointD &p) const { return p.*m_h; }
		inline double y(const TPointD &p) const { return p.*m_v; }

		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);
		}

		inline double getX(const TQuadratic &q, double t) const { return get(q, t, m_h); }
		inline double getY(const TQuadratic &q, double t) const { return get(q, t, m_v); }

		void getEdgeData(int e, TEdge *&ed, TStroke *&s,
						 int &chunk0, const TThickQuadratic *&q0, double &t0,
						 int &chunk1, const TThickQuadratic *&q1, double &t1) const
		{
			ed = m_this->m_edge[e];
			s = ed->m_s;

			s->getChunkAndT(ed->m_w0, chunk0, t0);
			s->getChunkAndT(ed->m_w1, chunk1, t1);

			q0 = s->getChunk(chunk0);
			q1 = s->getChunk(chunk1);
		}

		bool isInYRange(double y0, double y1) const
		{
			return (y0 <= m_y && m_y < y1)	 // Assuming the first endpoint is vertical-including,
				   || (y1 < m_y && m_y <= y0); // while the latter is not. Vertical conditions are EXACT.
		}

		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);
		}

		int leftScanlineIntersections(const TSegment &seg, bool &ascending)
		{
			const TPointD &p0 = seg.getP0(), &p1 = seg.getP1();
			bool wasAscending = ascending;

			ascending = (y(p1) > y(p0)) ? true
										: (y(p1) < y(p0)) ? false
														  : (wasAscending = !ascending, ascending); // Couples with the cusp check below

			if (!isInYRange(y(p0), y(p1)))
				return 0;

			if (m_y == y(p0))
				return int(x(p0) < m_x && ascending == wasAscending); // Cusps treated here

			double y1_y0 = y(p1) - y(p0), // (x, m_y) in (p0, p1) from here on
				poly[2] = {(m_y - y(p0)) * (x(p1) - x(p0)), -y1_y0},
				   sx_x0;

			return tcg::poly_ops::solve_1(poly, &sx_x0, m_tol) ? int(sx_x0 < m_x - x(p0))
															   : int(x(p0) < m_x && x(p1) < m_x); // Almost horizontal segments are
		}																						  // flattened along the axes

		int isAscending(const TThickQuadratic &q, double t, bool forward)
		{
			double y0 = y(q.getP0()), y1 = y(q.getP1()), y2 = y(q.getP2()),
				   y1_y0 = y1 - y0, y2_y1 = y2 - y1;

			double yspeed_2 = tcg::numeric_ops::lerp(y1_y0, y2_y1, t) * (2 * int(forward) - 1),
				   yaccel = y2_y1 - y1_y0;

			return (yspeed_2 > 0.0) ? 1
									: (yspeed_2 < 0.0) ? -1
													   : tcg::numeric_ops::sign(yaccel);
		}

		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.
		}

	} locals = {this, p.*h, p.*v, 1e-4, h, v};

	TEdge *ed;
	TStroke *s;
	int chunk0, chunk1;
	const TThickQuadratic *q0, *q1;
	double t0, t1;

	UINT e, eCount = m_edge.size();

	int leftInters = 0;
	bool ascending = (locals.getEdgeData(eCount - 1, ed, s, chunk0, q0, t0, chunk1, q1, t1),
					  locals.isAscending(*q1, t1, (t0 < t1)));

	for (e = 0; e != eCount; ++e) {
		// Explore current edge
		{
			// Retrieve edge data
			locals.getEdgeData(e, ed, s, chunk0, q0, t0, chunk1, q1, t1);

			// Compare edge against scanline segment
			if (chunk0 != chunk1) {
				if (chunk0 < chunk1) {
					leftInters += locals.leftScanlineIntersections(*q0, t0, 1.0, ascending);

					for (int c = chunk0 + 1; c != chunk1; ++c)
						leftInters += locals.leftScanlineIntersections(*s->getChunk(c), 0.0, 1.0, ascending);

					leftInters += locals.leftScanlineIntersections(*q1, 0.0, t1, ascending);
				} else {
					leftInters += locals.leftScanlineIntersections(*q0, t0, 0.0, ascending);

					for (int c = chunk0 - 1; c != chunk1; --c)
						leftInters += locals.leftScanlineIntersections(*s->getChunk(c), 1.0, 0.0, ascending);

					leftInters += locals.leftScanlineIntersections(*q1, 1.0, t1, ascending);
				}
			} else
				leftInters += locals.leftScanlineIntersections(*q0, t0, t1, ascending);
		}

		// Explore autoclose segment at the end of current edge
		{
			int nextE = (e + 1) % int(m_edge.size());

			const TPointD &p0 = m_edge[e]->m_s->getPoint(m_edge[e]->m_w1),
						  &p1 = m_edge[nextE]->m_s->getPoint(m_edge[nextE]->m_w0);

			leftInters += locals.leftScanlineIntersections(TSegment(p0, p1), ascending);
		}
	}

	return leftInters;
}
Example #7
0
//-----------------------------------------------------------------------------
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;
}