Example #1
0
/*! \internal

    \a a, \a b and \a c are corner points of an equilateral triangle.
    (\a x,\a y) is an arbitrary point inside or outside this triangle.

    If (x,y) is inside the triangle, this function returns the double
    point (x,y).

    Otherwise, the intersection of the perpendicular projection of
    (x,y) onto the closest triangle edge is returned, unless this
    intersection is outside the triangle's bounds, in which case the
    corner closest to the intersection is returned instead.

    Yes, it's trigonometry.
*/
QPointF QtColorTriangle::movePointToTriangle(double x, double y, const Vertex &a,
					       const Vertex &b, const Vertex &c) const
{
    // Let v1A be the vector from (x,y) to a.
    // Let v2A be the vector from a to b.
    // Find the angle alphaA between v1A and v2A.
    double v1xA = x - a.point.x();
    double v1yA = y - a.point.y();
    double v2xA = b.point.x() - a.point.x();
    double v2yA = b.point.y() - a.point.y();
    double vpA = vprod(v1xA, v1yA, v2xA, v2yA);
    double cosA = vpA / (vlen(v1xA, v1yA) * vlen(v2xA, v2yA));
    double alphaA = acos(cosA);

    // Let v1B be the vector from x to b.
    // Let v2B be the vector from b to c.
    double v1xB = x - b.point.x();
    double v1yB = y - b.point.y();
    double v2xB = c.point.x() - b.point.x();
    double v2yB = c.point.y() - b.point.y();
    double vpB = vprod(v1xB, v1yB, v2xB, v2yB);
    double cosB = vpB / (vlen(v1xB, v1yB) * vlen(v2xB, v2yB));
    double alphaB = acos(cosB);

    // Let v1C be the vector from x to c.
    // Let v2C be the vector from c back to a.
    double v1xC = x - c.point.x();
    double v1yC = y - c.point.y();
    double v2xC = a.point.x() - c.point.x();
    double v2yC = a.point.y() - c.point.y();
    double vpC = vprod(v1xC, v1yC, v2xC, v2yC);
    double cosC = vpC / (vlen(v1xC, v1yC) * vlen(v2xC, v2yC));
    double alphaC = acos(cosC);

    // Find the radian angles between the (1,0) vector and the points
    // A, B, C and (x,y). Use this information to determine which of
    // the edges we should project (x,y) onto.
    double angleA = angleAt(a.point, contentsRect());
    double angleB = angleAt(b.point, contentsRect());
    double angleC = angleAt(c.point, contentsRect());
    double angleP = angleAt(QPointF(x, y), contentsRect());

    // If (x,y) is in the a-b area, project onto the a-b vector.
    if (angleBetweenAngles(angleP, angleA, angleB)) {
	// Find the distance from (x,y) to a. Then use the slope of
	// the a-b vector with this distance and the angle between a-b
	// and a-(x,y) to determine the point of intersection of the
	// perpendicular projection from (x,y) onto a-b.
	double pdist = sqrt(qsqr(x - a.point.x()) + qsqr(y - a.point.y()));

        // the length of all edges is always > 0
	double p0x = a.point.x() + ((b.point.x() - a.point.x()) / vlen(v2xB, v2yB)) * cos(alphaA) * pdist;
	double p0y = a.point.y() + ((b.point.y() - a.point.y()) / vlen(v2xB, v2yB)) * cos(alphaA) * pdist;

	// If (x,y) is above the a-b line, which basically means it's
	// outside the triangle, then return its projection onto a-b.
	if (pointAbovePoint(x, y, p0x, p0y, a.point.x(), a.point.y(), b.point.x(), b.point.y())) {
	    // If the projection is "outside" a, return a. If it is
	    // outside b, return b. Otherwise return the projection.
	    int n = pointInLine(p0x, p0y, a.point.x(), a.point.y(), b.point.x(), b.point.y());
	    if (n < 0)
		return a.point;
	    else if (n > 0)
		return b.point;

	    return QPointF(p0x, p0y);
	}
    } else if (angleBetweenAngles(angleP, angleB, angleC)) {
	// If (x,y) is in the b-c area, project onto the b-c vector.
	double pdist = sqrt(qsqr(x - b.point.x()) + qsqr(y - b.point.y()));

        // the length of all edges is always > 0
        double p0x = b.point.x() + ((c.point.x() - b.point.x()) / vlen(v2xC, v2yC)) * cos(alphaB) * pdist;
	double p0y = b.point.y() + ((c.point.y() - b.point.y()) / vlen(v2xC, v2yC)) * cos(alphaB) * pdist;

	if (pointAbovePoint(x, y, p0x, p0y, b.point.x(), b.point.y(), c.point.x(), c.point.y())) {
	    int n = pointInLine(p0x, p0y, b.point.x(), b.point.y(), c.point.x(), c.point.y());
	    if (n < 0)
		return b.point;
	    else if (n > 0)
		return c.point;
	    return QPointF(p0x, p0y);
	}
    } else if (angleBetweenAngles(angleP, angleC, angleA)) {
	// If (x,y) is in the c-a area, project onto the c-a vector.
	double pdist = sqrt(qsqr(x - c.point.x()) + qsqr(y - c.point.y()));

        // the length of all edges is always > 0
        double p0x = c.point.x() + ((a.point.x() - c.point.x()) / vlen(v2xA, v2yA)) * cos(alphaC) * pdist;
	double p0y = c.point.y() + ((a.point.y() - c.point.y()) / vlen(v2xA, v2yA)) * cos(alphaC) * pdist;

	if (pointAbovePoint(x, y, p0x, p0y, c.point.x(), c.point.y(), a.point.x(), a.point.y())) {
	    int n = pointInLine(p0x, p0y, c.point.x(), c.point.y(), a.point.x(), a.point.y());
	    if (n < 0)
		return c.point;
	    else if (n > 0)
		return a.point;
	    return QPointF(p0x, p0y);
	}
    }

    // (x,y) is inside the triangle (inside a-b, b-c and a-c).
    return QPointF(x, y);
}
  bool lineSegInTriangle(sf::Vector2f t1, sf::Vector2f t2, sf::Vector2f t3, sf::Vector2f l1, sf::Vector2f l2) {
    //the triangle is made by t1, t2 & t2; the line segment is made by l1 & l2
    //return true if the line segment lies or partially lies in the triangle
    int v1 = pointInLine(t1, l1, l2);
    int v2 = pointInLine(t2, l1, l2);
    int v3 = pointInLine(t3, l1, l2);
    sf::Vector2f inter1, inter2;
    bool isIntersectionSet = false;
    if (v1 == 0) {
      if (v2 == 0) {
        inter1 = t1;
        inter2 = t2;
        isIntersectionSet = true;
      } else if (v3 == 0){
        inter1 = t1;
        inter2 = t3;
        isIntersectionSet = true;
      } else{
        v1 = v2;
      }
    }

    if (v2 == 0) {
      if (v3 == 0){
        inter1 = t2;
        inter2 = t3;
        isIntersectionSet = true;
      } else{
        v2 = v1;
      }
    }

    if (v3 == 0) {
      v3 = v1;
    }


    if ( isIntersectionSet == false && v1 * v2 == -1 && v2 * v3 == 1 ) {
      inter1 = twoLineIntersection(t1, t2, l1, l2);
      inter2 = twoLineIntersection(t1, t3, l1, l2);
      isIntersectionSet = true;
    }
    if ( isIntersectionSet == false && v2 * v1 == -1 && v1 * v3 == 1 ) {
      inter1 = twoLineIntersection(t2, t1, l1, l2);
      inter2 = twoLineIntersection(t2, t3, l1, l2);
      isIntersectionSet = true;
    }
    if ( isIntersectionSet == false && v3 * v1 == -1 && v1 * v2 == 1 ) {
      inter1 = twoLineIntersection(t3, t1, l1, l2);
      inter2 = twoLineIntersection(t3, t2, l1, l2);
      isIntersectionSet = true;

    }

    if (isIntersectionSet) {
      if (l1.x == l2.x) {
        if ( ( (l1.y < inter1.y && l2.y < inter1.y) && (l1.y < inter2.y && l2.y < inter2.y ) )
          || ( (l1.y > inter1.y && l2.y > inter1.y) && (l1.y > inter2.y && l2.y > inter2.y ) ) )
          return false;
        else
          return true;
      }
      else {

        if ( ( (l1.x < inter1.x && l2.x < inter1.x) && (l1.x < inter2.x && l2.x < inter2.x ) )
          || ( (l1.x > inter1.x && l2.x > inter1.x) && (l1.x > inter2.x && l2.x > inter2.x ) ) )
          return false;
        else
          return true;
      }
    }
    else
      return false;
  }