Example #1
0
	/* ARGSUSED */
int
TkThickPolyLineToArea(
    double *coordPtr,		/* Points to an array of coordinates for the
				 * polyline: x0, y0, x1, y1, ... */
    int numPoints,		/* Total number of points at *coordPtr. */
    double width,		/* Width of each line segment. */
    int capStyle,		/* How are end-points of polyline drawn?
				 * CapRound, CapButt, or CapProjecting. */
    int joinStyle,		/* How are joints in polyline drawn?
				 * JoinMiter, JoinRound, or JoinBevel. */
    double *rectPtr)		/* Rectangular area to check against. */
{
    double radius, poly[10];
    int count;
    int changedMiterToBevel;	/* Non-zero means that a mitered corner had to
				 * be treated as beveled after all because the
				 * angle was < 11 degrees. */
    int inside;			/* Tentative guess about what to return, based
				 * on all points seen so far: one means
				 * everything seen so far was inside the area;
				 * -1 means everything was outside the area.
				 * 0 means overlap has been found. */

    radius = width/2.0;
    inside = -1;

    if ((coordPtr[0] >= rectPtr[0]) && (coordPtr[0] <= rectPtr[2])
	    && (coordPtr[1] >= rectPtr[1]) && (coordPtr[1] <= rectPtr[3])) {
	inside = 1;
    }

    /*
     * Iterate through all of the edges of the line, computing a polygon for
     * each edge and testing the area against that polygon. In addition, there
     * are additional tests to deal with rounded joints and caps.
     */

    changedMiterToBevel = 0;
    for (count = numPoints; count >= 2; count--, coordPtr += 2) {
	/*
	 * If rounding is done around the first point of the edge then test a
	 * circular region around the point with the area.
	 */

	if (((capStyle == CapRound) && (count == numPoints))
		|| ((joinStyle == JoinRound) && (count != numPoints))) {
	    poly[0] = coordPtr[0] - radius;
	    poly[1] = coordPtr[1] - radius;
	    poly[2] = coordPtr[0] + radius;
	    poly[3] = coordPtr[1] + radius;
	    if (TkOvalToArea(poly, rectPtr) != inside) {
		return 0;
	    }
	}

	/*
	 * Compute the polygonal shape corresponding to this edge, consisting
	 * of two points for the first point of the edge and two points for
	 * the last point of the edge.
	 */

	if (count == numPoints) {
	    TkGetButtPoints(coordPtr+2, coordPtr, width,
		    capStyle == CapProjecting, poly, poly+2);
	} else if ((joinStyle == JoinMiter) && !changedMiterToBevel) {
	    poly[0] = poly[6];
	    poly[1] = poly[7];
	    poly[2] = poly[4];
	    poly[3] = poly[5];
	} else {
	    TkGetButtPoints(coordPtr+2, coordPtr, width, 0, poly, poly+2);

	    /*
	     * If the last joint was beveled, then also check a polygon
	     * comprising the last two points of the previous polygon and the
	     * first two from this polygon; this checks the wedges that fill
	     * the beveled joint.
	     */

	    if ((joinStyle == JoinBevel) || changedMiterToBevel) {
		poly[8] = poly[0];
		poly[9] = poly[1];
		if (TkPolygonToArea(poly, 5, rectPtr) != inside) {
		    return 0;
		}
		changedMiterToBevel = 0;
	    }
	}
	if (count == 2) {
	    TkGetButtPoints(coordPtr, coordPtr+2, width,
		    capStyle == CapProjecting, poly+4, poly+6);
	} else if (joinStyle == JoinMiter) {
	    if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4,
		    (double) width, poly+4, poly+6) == 0) {
		changedMiterToBevel = 1;
		TkGetButtPoints(coordPtr, coordPtr+2, width, 0, poly+4,
			poly+6);
	    }
	} else {
	    TkGetButtPoints(coordPtr, coordPtr+2, width, 0, poly+4, poly+6);
	}
	poly[8] = poly[0];
	poly[9] = poly[1];
	if (TkPolygonToArea(poly, 5, rectPtr) != inside) {
	    return 0;
	}
    }

    /*
     * If caps are rounded, check the cap around the final point of the line.
     */

    if (capStyle == CapRound) {
	poly[0] = coordPtr[0] - radius;
	poly[1] = coordPtr[1] - radius;
	poly[2] = coordPtr[0] + radius;
	poly[3] = coordPtr[1] + radius;
	if (TkOvalToArea(poly, rectPtr) != inside) {
	    return 0;
	}
    }

    return inside;
}
Example #2
0
	/* ARGSUSED */
static double
BLineToPoint(Tk_Canvas canvas, Tk_Item *itemPtr, double *pointPtr)
{
  register BLineItem *linePtr = (BLineItem *) itemPtr;
  register double *coordPtr, *linePoints;
  double staticSpace[2*MAX_STATIC_POINTS];
  double poly[10];
  double bestDist, dist;
  int numPoints, count;
  int changedMiterToBevel;	/* Non-zero means that a mitered corner
       * had to be treated as beveled after all
       * because the angle was < 11 degrees. */

  bestDist = 1.0e40;

  /*
   * Handle smoothed lines by generating an expanded set of points
   * against which to do the check.
   */

  numPoints = linePtr->numPoints;
  linePoints = linePtr->coordPtr;

  /*
   * The overall idea is to iterate through all of the edges of
   * the line, computing a polygon for each edge and testing the
   * point against that polygon.  In addition, there are additional
   * tests to deal with rounded joints and caps.
   */

  changedMiterToBevel = 0;
  for (count = numPoints, coordPtr = linePoints; count >= 2;
    count--, coordPtr += 2) 
  {

    /*
     * If rounding is done around the first point then compute
     * the distance between the point and the point.
     */

    if (((linePtr->capStyle == CapRound) && (count == numPoints))
      || ((linePtr->joinStyle == JoinRound)
        && (count != numPoints))) 
    {
      dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1])
            - linePtr->width/2.0;
      if (dist <= 0.0) 
      {
        bestDist = 0.0;
        goto done;
      } 
      else if (dist < bestDist) 
      {
        bestDist = dist;
      }
    }

    /*
     * Compute the polygonal shape corresponding to this edge,
     * consisting of two points for the first point of the edge
     * and two points for the last point of the edge.
     */

    if (count == numPoints) 
    {
      TkGetButtPoints(coordPtr+2, coordPtr, (double) linePtr->width,
          linePtr->capStyle == CapProjecting, poly, poly+2);
    } 
    else if ((linePtr->joinStyle == JoinMiter) && !changedMiterToBevel) 
    {
      poly[0] = poly[6];
      poly[1] = poly[7];
      poly[2] = poly[4];
      poly[3] = poly[5];
    } 
    else 
    {
      TkGetButtPoints(coordPtr+2, coordPtr, (double) linePtr->width, 0,
        poly, poly+2);

	    /*
	     * If this line uses beveled joints, then check the distance
	     * to a polygon comprising the last two points of the previous
	     * polygon and the first two from this polygon;  this checks
	     * the wedges that fill the mitered joint.
	     */

	    if ((linePtr->joinStyle == JoinBevel) || changedMiterToBevel) 
      {
        poly[8] = poly[0];
        poly[9] = poly[1];
        dist = TkPolygonToPoint(poly, 5, pointPtr);
        if (dist <= 0.0) 
        {
          bestDist = 0.0;
          goto done;
        } 
        else if (dist < bestDist) 
        {
          bestDist = dist;
        }
        changedMiterToBevel = 0;
	    }
    }
    if (count == 2) 
    {
	    TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width,
		    linePtr->capStyle == CapProjecting, poly+4, poly+6);
    } 
    else if (linePtr->joinStyle == JoinMiter) 
    {
	    if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4,
		    (double) linePtr->width, poly+4, poly+6) == 0) 
      {
        changedMiterToBevel = 1;
        TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width,
          0, poly+4, poly+6);
	    }
    } 
    else 
    {
	    TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width, 0,
		    poly+4, poly+6);
    }
    poly[8] = poly[0];
    poly[9] = poly[1];
    dist = TkPolygonToPoint(poly, 5, pointPtr);
    if (dist <= 0.0) 
    {
      bestDist = 0.0;
      goto done;
    } 
    else if (dist < bestDist) 
    {
      bestDist = dist;
    }
  }

  /*
   * If caps are rounded, check the distance to the cap around the
   * final end point of the line.
   */

  if (linePtr->capStyle == CapRound) 
  {
    dist = hypot(coordPtr[0] - pointPtr[0], coordPtr[1] - pointPtr[1])
      - linePtr->width/2.0;
    if (dist <= 0.0) 
    {
	    bestDist = 0.0;
	    goto done;
    } 
    else if (dist < bestDist) 
    {
	    bestDist = dist;
    }
  }

  done:
  if ((linePoints != staticSpace) && (linePoints != linePtr->coordPtr)) 
  {
    ckfree((char *) linePoints);
  }
  return bestDist;
}
Example #3
0
	/* ARGSUSED */
static int
BLineToArea(Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr)
{
  register BLineItem *linePtr = (BLineItem *) itemPtr;
  register double *coordPtr;
  double staticSpace[2*MAX_STATIC_POINTS];
  double *linePoints, poly[10];
  double radius;
  int numPoints, count;
  int changedMiterToBevel;	/* Non-zero means that a mitered corner
       * had to be treated as beveled after all
       * because the angle was < 11 degrees. */
  int inside;			/* Tentative guess about what to return,
       * based on all points seen so far:  one
       * means everything seen so far was
       * inside the area;  -1 means everything
       * was outside the area.  0 means overlap
       * has been found. */ 

  radius = linePtr->width/2.0;
  inside = -1;

  numPoints = linePtr->numPoints;
  linePoints = linePtr->coordPtr;

  coordPtr = linePoints;
  if ((coordPtr[0] >= rectPtr[0]) && (coordPtr[0] <= rectPtr[2])
    && (coordPtr[1] >= rectPtr[1]) && (coordPtr[1] <= rectPtr[3])) 
  {
    inside = 1;
  }

  /*
   * Iterate through all of the edges of the line, computing a polygon
   * for each edge and testing the area against that polygon.  In
   * addition, there are additional tests to deal with rounded joints
   * and caps.
   */

  changedMiterToBevel = 0;
  for (count = numPoints; count >= 2; count--, coordPtr += 2) 
  {

    /*
     * If rounding is done around the first point of the edge
     * then test a circular region around the point with the
     * area.
     */

    if (((linePtr->capStyle == CapRound) && (count == numPoints))
      || ((linePtr->joinStyle == JoinRound)
      && (count != numPoints))) 
    {
      poly[0] = coordPtr[0] - radius;
      poly[1] = coordPtr[1] - radius;
      poly[2] = coordPtr[0] + radius;
      poly[3] = coordPtr[1] + radius;
      if (TkOvalToArea(poly, rectPtr) != inside) 
      {
        inside = 0;
        goto done;
	    }
    }

    /*
     * Compute the polygonal shape corresponding to this edge,
     * consisting of two points for the first point of the edge
     * and two points for the last point of the edge.
     */

    if (count == numPoints) 
    {
      TkGetButtPoints(coordPtr+2, coordPtr, (double) linePtr->width,
          linePtr->capStyle == CapProjecting, poly, poly+2);
    } 
    else if ((linePtr->joinStyle == JoinMiter) && !changedMiterToBevel) 
    {
      poly[0] = poly[6];
      poly[1] = poly[7];
      poly[2] = poly[4];
      poly[3] = poly[5];
    } 
    else 
    {
      TkGetButtPoints(coordPtr+2, coordPtr, (double) linePtr->width, 0,
          poly, poly+2);

	    /*
	     * If the last joint was beveled, then also check a
	     * polygon comprising the last two points of the previous
	     * polygon and the first two from this polygon;  this checks
	     * the wedges that fill the beveled joint.
	     */

	    if ((linePtr->joinStyle == JoinBevel) || changedMiterToBevel) 
      {
        poly[8] = poly[0];
        poly[9] = poly[1];
        if (TkPolygonToArea(poly, 5, rectPtr) != inside) 
        {
          inside = 0;
          goto done;
        }
        changedMiterToBevel = 0;
	    }
    }
    if (count == 2) 
    {
	    TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width,
		    linePtr->capStyle == CapProjecting, poly+4, poly+6);
    }
    else if (linePtr->joinStyle == JoinMiter) 
    {
	    if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4,
		    (double) linePtr->width, poly+4, poly+6) == 0) 
      {
        changedMiterToBevel = 1;
        TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width,
          0, poly+4, poly+6);
	    }
    } 
    else 
    {
	    TkGetButtPoints(coordPtr, coordPtr+2, (double) linePtr->width, 0,
		    poly+4, poly+6);
    }
    poly[8] = poly[0];
    poly[9] = poly[1];
    if (TkPolygonToArea(poly, 5, rectPtr) != inside) 
    {
      inside = 0;
      goto done;
    }
  }

  /*
   * If caps are rounded, check the cap around the final point
   * of the line.
   */

  if (linePtr->capStyle == CapRound) 
  {
    poly[0] = coordPtr[0] - radius;
    poly[1] = coordPtr[1] - radius;
    poly[2] = coordPtr[0] + radius;
    poly[3] = coordPtr[1] + radius;
    if (TkOvalToArea(poly, rectPtr) != inside) 
    {
	    inside = 0;
	    goto done;
    }
  }

done:
  if ((linePoints != staticSpace) && (linePoints != linePtr->coordPtr)) 
  {
    ckfree((char *) linePoints);
  }
  return inside;
}
Example #4
0
static void
ComputeBLineBbox(Tk_Canvas canvas, BLineItem *linePtr)
{
  register double *coordPtr;
  int i;

  coordPtr = linePtr->coordPtr;
  linePtr->header.x1 = linePtr->header.x2 = (int)coordPtr[0];
  linePtr->header.y1 = linePtr->header.y2 = (int)coordPtr[1];

  /*
   * Compute the bounding box of all the points in the line,
   * then expand in all directions by the line's width to take
   * care of butting or rounded corners and projecting or
   * rounded caps.  This expansion is an overestimate (worst-case
   * is square root of two over two) but it's simple.  Don't do
   * anything special for curves.  This causes an additional
   * overestimate in the bounding box, but is faster.
   */

  for (i = 1, coordPtr = linePtr->coordPtr+2; i < linePtr->numPoints;
    i++, coordPtr += 2) 
  {
    TkIncludePoint((Tk_Item *) linePtr, coordPtr);
  }
  linePtr->header.x1 -= linePtr->width;
  linePtr->header.x2 += linePtr->width;
  linePtr->header.y1 -= linePtr->width;
  linePtr->header.y2 += linePtr->width;

  /*
   * For mitered lines, make a second pass through all the points.
   * Compute the locations of the two miter vertex points and add
   * those into the bounding box.
   */

  if (linePtr->joinStyle == JoinMiter) 
  {
    for (i = linePtr->numPoints, coordPtr = linePtr->coordPtr; i >= 3;
      i--, coordPtr += 2) 
    {
      double miter[4];
      int j;
    
      if (TkGetMiterPoints(coordPtr, coordPtr+2, coordPtr+4,
        (double) linePtr->width, miter, miter+2)) 
      {
        for (j = 0; j < 4; j += 2) 
        {
          TkIncludePoint((Tk_Item *) linePtr, miter+j);
        }
      }
    }
  }

  /*
   * Add one more pixel of fudge factor just to be safe (e.g.
   * X may round differently than we do).
   */

  linePtr->header.x1 -= 3;
  linePtr->header.x2 += 3;
  linePtr->header.y1 -= 3;
  linePtr->header.y2 += 3;
}