/*
* tkCanvArc.c --
*
* This file implements arc items for canvas widgets.
*
* Copyright (c) 1992-1994 The Regents of the University of California.
* Copyright (c) 1994-1995 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* SCCS: @(#) tkCanvArc.c 1.32 96/02/17 16:59:09
*/
#include "tkInt.h"
/*
* The structure below defines the record for each arc item.
*/
typedef struct ArcItem {
* types. MUST BE FIRST IN STRUCTURE. */
* box for oval of which arc is a piece. */
* between 0 and 360. */
* start to end of arc) in degrees between
* -360 and 360. */
* that define one or two closed polygons
* representing the portion of the outline
* that isn't part of the arc (the V-shape
* for a pie slice or a line-like segment
* for a chord). Malloc'ed. */
* means no space allocated. */
* draw outline. */
* outline too when style is "arc"). NULL
* means don't fill arc. */
* start (see ComputeArcOutline). */
* start+extent (see ComputeArcOutline). */
} ArcItem;
/*
* The definitions below define the sizes of the polygons used to
* display outline information for various styles of arcs:
*/
/*
* Information used for parsing configuration specs:
*/
};
(char *) NULL, 0, 0}
};
/*
* Prototypes for procedures defined in this file:
*/
char **argv));
static int AngleInRange _ANSI_ARGS_((double x, double y,
/*
* The structures below defines the arc item types by means of procedures
* that can be invoked by generic item code.
*/
"arc", /* name */
sizeof(ArcItem), /* itemSize */
CreateArc, /* createProc */
configSpecs, /* configSpecs */
ConfigureArc, /* configureProc */
ArcCoords, /* coordProc */
DeleteArc, /* deleteProc */
DisplayArc, /* displayProc */
0, /* alwaysRedraw */
ArcToPoint, /* pointProc */
ArcToArea, /* areaProc */
ArcToPostscript, /* postscriptProc */
ScaleArc, /* scaleProc */
TranslateArc, /* translateProc */
};
#ifndef PI
#endif
/*
* The uid's below comprise the legal values for the "-style"
* option for arcs.
*/
/*
*--------------------------------------------------------------
*
* CreateArc --
*
* This procedure is invoked to create a new arc item in
* a canvas.
*
* Results:
* A standard Tcl return value. If an error occurred in
* creating the item, then an error message is left in
* interp->result; in this case itemPtr is
* left uninitialized, so it can be safely freed by the
* caller.
*
* Side effects:
* A new arc item is created.
*
*--------------------------------------------------------------
*/
static int
* has been initialized by caller. */
int argc; /* Number of arguments in argv. */
char **argv; /* Arguments describing arc. */
{
if (argc < 4) {
(char *) NULL);
return TCL_ERROR;
}
/*
* Carry out once-only initialization.
*/
}
/*
* Carry out initialization that is needed in order to clean
* up after errors during the the remainder of this procedure.
*/
arcPtr->numOutlinePoints = 0;
/*
* Process the arguments to fill in the item record.
*/
return TCL_ERROR;
}
return TCL_ERROR;
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* ArcCoords --
*
* This procedure is invoked to process the "coords" widget
* command on arcs. See the user documentation for details
* on what it does.
*
* Results:
* Returns TCL_OK or TCL_ERROR, and sets interp->result.
*
* Side effects:
* The coordinates for the given item may be changed.
*
*--------------------------------------------------------------
*/
static int
* read or modified. */
int argc; /* Number of coordinates supplied in
* argv. */
char **argv; /* Array of coordinates: x1, y1,
* x2, y2, ... */
{
if (argc == 0) {
(char *) NULL);
} else if (argc == 4) {
return TCL_ERROR;
}
} else {
"wrong # coordinates: expected 0 or 4, got %d",
argc);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* ConfigureArc --
*
* This procedure is invoked to configure various aspects
* of a arc item, such as its outline and fill colors.
*
* Results:
* A standard Tcl result code. If an error occurs, then
* an error message is left in interp->result.
*
* Side effects:
* Configuration information, such as colors and stipple
* patterns, may be set for itemPtr.
*
*--------------------------------------------------------------
*/
static int
int argc; /* Number of elements in argv. */
char **argv; /* Arguments describing things to configure. */
int flags; /* Flags to pass to Tk_ConfigureWidget. */
{
unsigned long mask;
int i;
return TCL_ERROR;
}
/*
* A few of the options require additional processing, such as
* style and graphics contexts.
*/
}
(char *) NULL);
return TCL_ERROR;
}
}
} else {
}
}
}
} else {
} else {
}
}
}
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* DeleteArc --
*
* This procedure is called to clean up the data structure
* associated with a arc item.
*
* Results:
* None.
*
* Side effects:
* Resources associated with itemPtr are released.
*
*--------------------------------------------------------------
*/
static void
* canvas. */
{
if (arcPtr->numOutlinePoints != 0) {
}
}
}
}
}
}
}
}
/*
*--------------------------------------------------------------
*
* ComputeArcBbox --
*
* This procedure is invoked to compute the bounding box of
* all the pixels that may be drawn as part of an arc.
*
* Results:
* None.
*
* Side effects:
* The fields x1, y1, x2, and y2 are updated in the header
* for itemPtr.
*
*--------------------------------------------------------------
*/
/* ARGSUSED */
static void
* recomputed. */
{
/*
* Make sure that the first coordinates are the lowest ones.
*/
double tmp;
}
double tmp;
}
/*
* To compute the bounding box, start with the the bbox formed
* by the two endpoints of the arc. Then add in the center of
* the arc's oval (if relevant) and the 3-o'clock, 6-o'clock,
* 9-o'clock, and 12-o'clock positions, if they are relevant.
*/
}
if (tmp < 0) {
tmp += 360.0;
}
}
if (tmp < 0) {
tmp += 360.0;
}
}
if (tmp < 0) {
tmp += 360.0;
}
}
if (tmp < 0) {
tmp += 360.0;
}
}
/*
* Lastly, expand by the width of the arc (if the arc's outline is
* being drawn) and add one extra pixel just for safety.
*/
tmp = 1;
} else {
}
}
/*
*--------------------------------------------------------------
*
* DisplayArc --
*
* This procedure is invoked to draw an arc item in a given
* drawable.
*
* Results:
* None.
*
* Side effects:
* ItemPtr is drawn in drawable using the transformation
* information in canvas.
*
*--------------------------------------------------------------
*/
static void
* item. */
* must be redisplayed (not used). */
{
/*
* Compute the screen coordinates of the bounding box for the item,
* plus integer values for the angles.
*/
}
}
/*
* Display filled arc first (if wanted), then outline. If the extent
* is zero then don't invoke XFillArc or XDrawArc, since this causes
* some window servers to crash and should be a no-op anyway.
*/
}
}
}
}
if (extent != 0) {
}
/*
* If the outline width is very thin, don't use polygons to draw
* the linear parts of the outline (this often results in nothing
* being displayed); just draw lines instead.
*/
}
} else {
None);
}
}
}
}
}
/*
*--------------------------------------------------------------
*
* ArcToPoint --
*
* Computes the distance from a given point to a given
* arc, in canvas units.
*
* Results:
* The return value is 0 if the point whose x and y coordinates
* are coordPtr[0] and coordPtr[1] is inside the arc. If the
* point isn't inside the arc then the return value is the
* distance from the point to the arc. If itemPtr is filled,
* then anywhere in the interior is considered "inside"; if
* itemPtr isn't filled, then "inside" means only the area
* occupied by the outline.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
/* ARGSUSED */
static double
double *pointPtr; /* Pointer to x and y coordinates. */
{
filled = 1;
} else {
filled = 0;
}
/*
* See if the point is within the angular range of the arc.
* Remember, X angles are backwards from the way we'd normally
* think of them. Also, compensate for any eccentricity of
* the oval.
*/
pointAngle = 0;
} else {
}
if (diff < 0) {
diff += 360.0;
}
/*
* Now perform different tests depending on what kind of arc
* we're dealing with.
*/
if (angleInRange) {
0, pointPtr);
}
return newDist;
}
return dist;
}
filled = 1;
} else {
filled = 0;
}
width = 0.0;
} else {
}
if (width > 1.0) {
pointPtr);
} else {
}
}
if (angleInRange) {
}
}
return dist;
}
/*
* This is a chord-style arc. We have to deal specially with the
* triangular piece that represents the difference between a
* chord-style arc and a pie-slice arc (for small angles this piece
* is excluded here where it would be included for pie slices;
* for large angles the piece is included here but would be
* excluded for pie slices).
*/
if (width > 1.0) {
pointPtr);
} else {
}
if (angleInRange) {
|| (polyDist > 0.0)) {
}
}
} else {
}
}
}
return dist;
}
/*
*--------------------------------------------------------------
*
* ArcToArea --
*
* This procedure is called to determine whether an item
* lies entirely inside, entirely outside, or overlapping
* a given area.
*
* Results:
* -1 is returned if the item is entirely outside the area
* given by rectPtr, 0 if it overlaps, and 1 if it is entirely
* inside the given area.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
/* ARGSUSED */
static int
double *rectPtr; /* Pointer to array of four coordinates
* (x1, y1, x2, y2) describing rectangular
* area. */
{
* an oval centered at the origin. */
* for coord. system where arc is centered
* on the origin. */
* that arc is inside rectangle. 0 means
* every test so far shows arc to be outside
* of rectangle. */
int newInside;
filled = 1;
} else {
filled = 0;
}
width = 0.0;
} else {
}
/*
* Transform both the arc and the rectangle so that the arc's oval
* is centered on the origin.
*/
/*
* Find the extreme points of the arc and see whether these are all
* inside the rectangle (in which case we're done), partly in and
* partly out (in which case we're done), or all outside (in which
* case we have more work to do). The extreme points include the
* following, which are checked in order:
*
* 1. The outside points of the arc, corresponding to start and
* extent.
* 2. The center of the arc (but only in pie-slice mode).
* 3. The 12, 3, 6, and 9-o'clock positions (but only if the arc
* includes those angles).
*/
numPoints = 0;
numPoints = 2;
pointPtr += 4;
pointPtr[0] = 0.0;
numPoints++;
pointPtr += 2;
}
if (tmp < 0) {
tmp += 360.0;
}
numPoints++;
pointPtr += 2;
}
if (tmp < 0) {
tmp += 360.0;
}
pointPtr[0] = 0.0;
numPoints++;
pointPtr += 2;
}
if (tmp < 0) {
tmp += 360.0;
}
numPoints++;
pointPtr += 2;
}
if (tmp < 0) {
tmp += 360.0;
}
pointPtr[0] = 0.0;
numPoints++;
pointPtr += 2;
}
/*
* Now that we've located the extreme points, loop through them all
* to see which are inside the rectangle.
*/
return 0;
}
}
if (inside) {
return 1;
}
/*
* So far, oval appears to be outside rectangle, but can't yet tell
* for sure. Next, test each of the four sides of the rectangle
* against the bounding region for the arc. If any intersections
* are found, then return "overlapping". First, test against the
* polygon(s) forming the sides of a chord or pie-slice.
*/
if (width >= 1.0) {
rectPtr) != -1) {
return 0;
}
return 0;
}
} else {
return 0;
}
}
if (width >= 1.0) {
rectPtr) != -1) {
return 0;
}
} else {
rectPtr) != -1) {
return 0;
}
}
}
/*
* Next check for overlap between each of the four sides and the
* outer perimiter of the arc. If the arc isn't filled, then also
* check the inner perimeter of the arc.
*/
return 0;
}
return 0;
}
}
/*
* The arc still appears to be totally disjoint from the rectangle,
* but it's also possible that the rectangle is totally inside the arc.
* Do one last check, which is to check one point of the rectangle
* to see if it's inside the arc. If it is, we've got overlap. If
* it isn't, the arc's really outside the rectangle.
*/
return 0;
}
return -1;
}
/*
*--------------------------------------------------------------
*
* ScaleArc --
*
* This procedure is invoked to rescale an arc item.
*
* Results:
* None.
*
* Side effects:
* The arc referred to by itemPtr is rescaled so that the
* following transformation is applied to all point
* coordinates:
* x' = originX + scaleX*(x-originX)
* y' = originY + scaleY*(y-originY)
*
*--------------------------------------------------------------
*/
static void
double scaleX; /* Amount to scale in X direction. */
double scaleY; /* Amount to scale in Y direction. */
{
}
/*
*--------------------------------------------------------------
*
* TranslateArc --
*
* This procedure is called to move an arc by a given amount.
*
* Results:
* None.
*
* Side effects:
* The position of the arc is offset by (xDelta, yDelta), and
* the bounding box is updated in the generic part of the item
* structure.
*
*--------------------------------------------------------------
*/
static void
* moved. */
{
}
/*
*--------------------------------------------------------------
*
* ComputeArcOutline --
*
* This procedure creates a polygon describing everything in
* the outline for an arc except what's in the curved part.
* For a "pie slice" arc this is a V-shaped chunk, and for
* a "chord" arc this is a linear chunk (with cutaway corners).
* For "arc" arcs, this stuff isn't relevant.
*
* Results:
* None.
*
* Side effects:
* The information at arcPtr->outlinePtr gets modified, and
* storage for arcPtr->outlinePtr may be allocated or freed.
*
*--------------------------------------------------------------
*/
static void
{
double *outlinePtr;
/*
* Make sure that the outlinePtr array is large enough to hold
* either a chord or pie-slice outline.
*/
if (arcPtr->numOutlinePoints == 0) {
(26 * sizeof(double)));
}
/*
* First compute the two points that lie at the centers of
* the ends of the curved arc segment, which are marked with
* X's in the figure below:
*
*
* * * *
* * *
* * * * *
* * * * *
* * * * *
* X * * X
*
* The code is tricky because the arc can be ovular in shape.
* It computes the position for a unit circle, and then
* scales to fit the shape of the arc's bounding box.
*
* Also, watch out because angles go counter-clockwise like you
* might expect, but the y-coordinate system is inverted. To
* handle this, just negate the angles in all the computations.
*/
/*
* Next compute the "outermost corners" of the arc, which are
* marked with X's in the figure below:
*
* * * *
* * *
* * * * *
* * * * *
* X * * X
* * *
*
* The code below is tricky because it has to handle eccentricity
* in the shape of the oval. The key in the code below is to
* realize that the slope of the line from arcPtr->center1 to corner1
* is (boxWidth*sin1)/(boxHeight*cos1), and similarly for arcPtr->center2
* and corner2. These formulas can be computed from the formula for
* the oval.
*/
angle = 0.0;
} else {
}
angle = 0.0;
} else {
}
/*
* For a chord outline, generate a six-sided polygon with three
* points for each end of the chord. The first and third points
* for each end are butt points generated on either side of the
* center point. The second point is the corner point.
*/
/*
* For pie slices, generate two polygons, one for each side
* of the pie slice. The first arm has a shape like this,
* where the center of the oval is X, arcPtr->center1 is at Y, and
* corner1 is at Z:
*
* _____________________
* | \
* | \
* X Y Z
* | /
* |_____________________/
*
*/
/*
* The second arm has a shape like this:
*
*
* ______________________
* / \
* / \
* Z Y X /
* \ /
* \______________________/
*
* arcPtr->center2, and Z is corner2. The extra jog out to the left
* of X is needed in or to produce a butted joint with the
* first arm; the corner to the right of X is one of the
* first two points of the first arm, depending on extent.
*/
} else {
}
}
}
/*
*--------------------------------------------------------------
*
* HorizLineToArc --
*
* Determines whether a horizontal line segment intersects
* a given arc.
*
* Results:
* The return value is 1 if the given line intersects the
* infinitely-thin arc section defined by rx, ry, start,
* and extent, and 0 otherwise. Only the perimeter of the
* arc is checked: interior areas (e.g. pie-slice or chord)
* are not checked.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static int
* X1 must be <= x2. */
double y; /* Y-coordinate of line segment. */
* centered at the origin. */
* the standard fashion for this module. */
{
double tmp;
* transformed coordinate system. */
double x;
/*
* Compute the x-coordinate of one possible intersection point
* between the arc and the line. Use a transformed coordinate
* system where the oval is a unit circle centered at the origin.
* Then scale back to get actual x-coordinate.
*/
if (tmp < 0) {
return 0;
}
/*
* Test both intersection points.
*/
return 1;
}
return 1;
}
return 0;
}
/*
*--------------------------------------------------------------
*
* VertLineToArc --
*
* Determines whether a vertical line segment intersects
* a given arc.
*
* Results:
* The return value is 1 if the given line intersects the
* infinitely-thin arc section defined by rx, ry, start,
* and extent, and 0 otherwise. Only the perimeter of the
* arc is checked: interior areas (e.g. pie-slice or chord)
* are not checked.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static int
double x; /* X-coordinate of line segment. */
* Y1 must be <= y2. */
* centered at the origin. */
* the standard fashion for this module. */
{
double tmp;
* transformed coordinate system. */
double y;
/*
* Compute the y-coordinate of one possible intersection point
* between the arc and the line. Use a transformed coordinate
* system where the oval is a unit circle centered at the origin.
* Then scale back to get actual y-coordinate.
*/
if (tmp < 0) {
return 0;
}
/*
* Test both intersection points.
*/
return 1;
}
return 1;
}
return 0;
}
/*
*--------------------------------------------------------------
*
* AngleInRange --
*
* Determine whether the angle from the origin to a given
* point is within a given range.
*
* Results:
* The return value is 1 if the angle from (0,0) to (x,y)
* is in the range given by start and extent, where angles
* are interpreted in the standard way for ovals (meaning
* backwards from normal interpretation). Otherwise the
* return value is 0.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static int
double x, y; /* Coordinate of point; angle measured
* from origin to here, relative to x-axis. */
double start; /* First angle, degrees, >=0, <=360. */
double extent; /* Size of arc in degrees >=-360, <=360. */
{
double diff;
if ((x == 0.0) && (y == 0.0)) {
return 1;
}
while (diff > 360.0) {
diff -= 360.0;
}
while (diff < 0.0) {
diff += 360.0;
}
if (extent >= 0) {
}
}
/*
*--------------------------------------------------------------
*
* ArcToPostscript --
*
* This procedure is called to generate Postscript for
* arc items.
*
* Results:
* The return value is a standard Tcl result. If an error
* occurs in generating Postscript then an error message is
* left in interp->result, replacing whatever used
* to be there. If no error occurs, then Postscript for the
* item is appended to the result.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static int
* here. */
* wanted. */
int prepass; /* 1 means this is a prepass to
* collect font information; 0 means
* final Postscript is being created. */
{
}
/*
* If the arc is filled, output Postscript for the interior region
* of the arc.
*/
} else {
"0 0 moveto 0 0 1 %.15g %.15g arc closepath\nsetmatrix\n",
}
return TCL_ERROR;
};
!= TCL_OK) {
return TCL_ERROR;
}
}
} else {
}
}
/*
* If there's an outline for the arc, draw it.
*/
!= TCL_OK) {
return TCL_ERROR;
}
return TCL_ERROR;
}
} else {
}
} else {
!= TCL_OK) {
return TCL_ERROR;
}
return TCL_ERROR;
}
} else {
}
}
!= TCL_OK) {
return TCL_ERROR;
}
return TCL_ERROR;
}
} else {
}
}
}
return TCL_OK;
}