Annotation of micropolis/src/tk/tktrig.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * tkTrig.c --
        !             3:  *
        !             4:  *     This file contains a collection of trigonometry utility
        !             5:  *     routines that are used by Tk and in particular by the
        !             6:  *     canvas code.  It also has miscellaneous geometry functions
        !             7:  *     used by canvases.
        !             8:  *
        !             9:  * Copyright 1992 Regents of the University of California.
        !            10:  * Permission to use, copy, modify, and distribute this
        !            11:  * software and its documentation for any purpose and without
        !            12:  * fee is hereby granted, provided that the above copyright
        !            13:  * notice appear in all copies.  The University of California
        !            14:  * makes no representations about the suitability of this
        !            15:  * software for any purpose.  It is provided "as is" without
        !            16:  * express or implied warranty.
        !            17:  */
        !            18: 
        !            19: #ifndef lint
        !            20: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkTrig.c,v 1.8 92/08/24 09:24:14 ouster Exp $ SPRITE (Berkeley)";
        !            21: #endif
        !            22: 
        !            23: #include <stdio.h>
        !            24: #include <math.h>
        !            25: #include "tkconfig.h"
        !            26: #include "tkcanvas.h"
        !            27: 
        !            28: #undef MIN
        !            29: #define MIN(a,b) (((a) < (b)) ? (a) : (b))
        !            30: #undef MAX
        !            31: #define MAX(a,b) (((a) > (b)) ? (a) : (b))
        !            32: #define PI 3.14159265358979323846
        !            33: 
        !            34: /*
        !            35:  *--------------------------------------------------------------
        !            36:  *
        !            37:  * TkLineToPoint --
        !            38:  *
        !            39:  *     Compute the distance from a point to a finite line segment.
        !            40:  *
        !            41:  * Results:
        !            42:  *     The return value is the distance from the line segment
        !            43:  *     whose end-points are *end1Ptr and *end2Ptr to the point
        !            44:  *     given by *pointPtr.
        !            45:  *
        !            46:  * Side effects:
        !            47:  *     None.
        !            48:  *
        !            49:  *--------------------------------------------------------------
        !            50:  */
        !            51: 
        !            52: double
        !            53: TkLineToPoint(end1Ptr, end2Ptr, pointPtr)
        !            54:     double end1Ptr[2];         /* Coordinates of first end-point of line. */
        !            55:     double end2Ptr[2];         /* Coordinates of second end-point of line. */
        !            56:     double pointPtr[2];                /* Points to coords for point. */
        !            57: {
        !            58:     double x, y;
        !            59: 
        !            60:     /*
        !            61:      * Compute the point on the line that is closest to the
        !            62:      * point.  This must be done separately for vertical edges,
        !            63:      * horizontal edges, and other edges.
        !            64:      */
        !            65: 
        !            66:     if (end1Ptr[0] == end2Ptr[0]) {
        !            67: 
        !            68:        /*
        !            69:         * Vertical edge.
        !            70:         */
        !            71: 
        !            72:        x = end1Ptr[0];
        !            73:        if (end1Ptr[1] >= end2Ptr[1]) {
        !            74:            y = MIN(end1Ptr[1], pointPtr[1]);
        !            75:            y = MAX(y, end2Ptr[1]);
        !            76:        } else {
        !            77:            y = MIN(end2Ptr[1], pointPtr[1]);
        !            78:            y = MAX(y, end1Ptr[1]);
        !            79:        }
        !            80:     } else if (end1Ptr[1] == end2Ptr[1]) {
        !            81: 
        !            82:        /*
        !            83:         * Horizontal edge.
        !            84:         */
        !            85: 
        !            86:        y = end1Ptr[1];
        !            87:        if (end1Ptr[0] >= end2Ptr[0]) {
        !            88:            x = MIN(end1Ptr[0], pointPtr[0]);
        !            89:            x = MAX(x, end2Ptr[0]);
        !            90:        } else {
        !            91:            x = MIN(end2Ptr[0], pointPtr[0]);
        !            92:            x = MAX(x, end1Ptr[0]);
        !            93:        }
        !            94:     } else {
        !            95:        double m1, b1, m2, b2;
        !            96: 
        !            97:        /*
        !            98:         * The edge is neither horizontal nor vertical.  Convert the
        !            99:         * edge to a line equation of the form y = m1*x + b1.  Then
        !           100:         * compute a line perpendicular to this edge but passing
        !           101:         * through the point, also in the form y = m2*x + b2.
        !           102:         */
        !           103: 
        !           104:        m1 = (end2Ptr[1] - end1Ptr[1])/(end2Ptr[0] - end1Ptr[0]);
        !           105:        b1 = end1Ptr[1] - m1*end1Ptr[0];
        !           106:        m2 = -1.0/m1;
        !           107:        b2 = pointPtr[1] - m2*pointPtr[0];
        !           108:        x = (b2 - b1)/(m1 - m2);
        !           109:        y = m1*x + b1;
        !           110:        if (end1Ptr[0] > end2Ptr[0]) {
        !           111:            if (x > end1Ptr[0]) {
        !           112:                x = end1Ptr[0];
        !           113:                y = end1Ptr[1];
        !           114:            } else if (x < end2Ptr[0]) {
        !           115:                x = end2Ptr[0];
        !           116:                y = end2Ptr[1];
        !           117:            }
        !           118:        } else {
        !           119:            if (x > end2Ptr[0]) {
        !           120:                x = end2Ptr[0];
        !           121:                y = end2Ptr[1];
        !           122:            } else if (x < end1Ptr[0]) {
        !           123:                x = end1Ptr[0];
        !           124:                y = end1Ptr[1];
        !           125:            }
        !           126:        }
        !           127:     }
        !           128: 
        !           129:     /*
        !           130:      * Compute the distance to the closest point.
        !           131:      */
        !           132: 
        !           133:     return hypot(pointPtr[0] - x, pointPtr[1] - y);
        !           134: }
        !           135: 
        !           136: /*
        !           137:  *--------------------------------------------------------------
        !           138:  *
        !           139:  * TkLineToArea --
        !           140:  *
        !           141:  *     Determine whether a line lies entirely inside, entirely
        !           142:  *     outside, or overlapping a given rectangular area.
        !           143:  *
        !           144:  * Results:
        !           145:  *     -1 is returned if the line given by end1Ptr and end2Ptr
        !           146:  *     is entirely outside the rectangle given by rectPtr.  0 is
        !           147:  *     returned if the polygon overlaps the rectangle, and 1 is
        !           148:  *     returned if the polygon is entirely inside the rectangle.
        !           149:  *
        !           150:  * Side effects:
        !           151:  *     None.
        !           152:  *
        !           153:  *--------------------------------------------------------------
        !           154:  */
        !           155: 
        !           156: int
        !           157: TkLineToArea(end1Ptr, end2Ptr, rectPtr)
        !           158:     double end1Ptr[2];         /* X and y coordinates for one endpoint
        !           159:                                 * of line. */
        !           160:     double end2Ptr[2];         /* X and y coordinates for other endpoint
        !           161:                                 * of line. */
        !           162:     double rectPtr[4];         /* Points to coords for rectangle, in the
        !           163:                                 * order x1, y1, x2, y2.  X1 must be no
        !           164:                                 * larger than x2, and y1 no larger than y2. */
        !           165: {
        !           166:     int inside1, inside2;
        !           167: 
        !           168:     /*
        !           169:      * First check the two points individually to see whether they
        !           170:      * are inside the rectangle or not.
        !           171:      */
        !           172: 
        !           173:     inside1 = (end1Ptr[0] >= rectPtr[0]) && (end1Ptr[0] <= rectPtr[2])
        !           174:            && (end1Ptr[1] >= rectPtr[1]) && (end1Ptr[1] <= rectPtr[3]);
        !           175:     inside2 = (end2Ptr[0] >= rectPtr[0]) && (end2Ptr[0] <= rectPtr[2])
        !           176:            && (end2Ptr[1] >= rectPtr[1]) && (end2Ptr[1] <= rectPtr[3]);
        !           177:     if (inside1 != inside2) {
        !           178:        return 0;
        !           179:     }
        !           180:     if (inside1 & inside2) {
        !           181:        return 1;
        !           182:     }
        !           183: 
        !           184:     /*
        !           185:      * Both points are outside the rectangle, but still need to check
        !           186:      * for intersections between the line and the rectangle.  Horizontal
        !           187:      * and vertical lines are particularly easy, so handle them
        !           188:      * separately.
        !           189:      */
        !           190: 
        !           191:     if (end1Ptr[0] == end2Ptr[0]) {
        !           192:        /*
        !           193:         * Vertical line.
        !           194:         */
        !           195:     
        !           196:        if (((end1Ptr[1] >= rectPtr[1]) ^ (end2Ptr[1] >= rectPtr[1]))
        !           197:                && (end1Ptr[0] >= rectPtr[0])
        !           198:                && (end1Ptr[0] <= rectPtr[2])) {
        !           199:            return 0;
        !           200:        }
        !           201:     } else if (end1Ptr[1] == end2Ptr[1]) {
        !           202:        /*
        !           203:         * Horizontal line.
        !           204:         */
        !           205:     
        !           206:        if (((end1Ptr[0] >= rectPtr[0]) ^ (end2Ptr[0] >= rectPtr[0]))
        !           207:                && (end1Ptr[1] >= rectPtr[1])
        !           208:                && (end1Ptr[1] <= rectPtr[3])) {
        !           209:            return 0;
        !           210:        }
        !           211:     } else {
        !           212:        double m, x, y, low, high;
        !           213:     
        !           214:        /*
        !           215:         * Diagonal line.  Compute slope of line and use
        !           216:         * for intersection checks against each of the
        !           217:         * sides of the rectangle: left, right, bottom, top.
        !           218:         */
        !           219:     
        !           220:        m = (end2Ptr[1] - end1Ptr[1])/(end2Ptr[0] - end1Ptr[0]);
        !           221:        if (end1Ptr[0] < end2Ptr[0]) {
        !           222:            low = end1Ptr[0];  high = end2Ptr[0];
        !           223:        } else {
        !           224:            low = end2Ptr[0]; high = end1Ptr[0];
        !           225:        }
        !           226:     
        !           227:        /*
        !           228:         * Left edge.
        !           229:         */
        !           230:     
        !           231:        y = end1Ptr[1] + (rectPtr[0] - end1Ptr[0])*m;
        !           232:        if ((rectPtr[0] >= low) && (rectPtr[0] <= high)
        !           233:                && (y >= rectPtr[1]) && (y <= rectPtr[3])) {
        !           234:            return 0;
        !           235:        }
        !           236:     
        !           237:        /*
        !           238:         * Right edge.
        !           239:         */
        !           240:     
        !           241:        y += (rectPtr[2] - rectPtr[0])*m;
        !           242:        if ((y >= rectPtr[1]) && (y <= rectPtr[3])
        !           243:                && (rectPtr[2] >= low) && (rectPtr[2] <= high)) {
        !           244:            return 0;
        !           245:        }
        !           246:     
        !           247:        /*
        !           248:         * Bottom edge.
        !           249:         */
        !           250:     
        !           251:        if (end1Ptr[1] < end2Ptr[1]) {
        !           252:            low = end1Ptr[1];  high = end2Ptr[1];
        !           253:        } else {
        !           254:            low = end2Ptr[1]; high = end1Ptr[1];
        !           255:        }
        !           256:        x = end1Ptr[0] + (rectPtr[1] - end1Ptr[1])/m;
        !           257:        if ((x >= rectPtr[0]) && (x <= rectPtr[2])
        !           258:                && (rectPtr[1] >= low) && (rectPtr[1] <= high)) {
        !           259:            return 0;
        !           260:        }
        !           261:     
        !           262:        /*
        !           263:         * Top edge.
        !           264:         */
        !           265:     
        !           266:        x += (rectPtr[3] - rectPtr[1])/m;
        !           267:        if ((x >= rectPtr[0]) && (x <= rectPtr[2])
        !           268:                && (rectPtr[3] >= low) && (rectPtr[3] <= high)) {
        !           269:            return 0;
        !           270:        }
        !           271:     }
        !           272:     return -1;
        !           273: }
        !           274: 
        !           275: /*
        !           276:  *--------------------------------------------------------------
        !           277:  *
        !           278:  * TkPolygonToPoint --
        !           279:  *
        !           280:  *     Compute the distance from a point to a polygon.
        !           281:  *
        !           282:  * Results:
        !           283:  *     The return value is 0.0 if the point referred to by
        !           284:  *     pointPtr is within the polygon referred to by polyPtr
        !           285:  *     and numPoints.  Otherwise the return value is the
        !           286:  *     distance of the point from the polygon.
        !           287:  *
        !           288:  * Side effects:
        !           289:  *     None.
        !           290:  *
        !           291:  *--------------------------------------------------------------
        !           292:  */
        !           293: 
        !           294: double
        !           295: TkPolygonToPoint(polyPtr, numPoints, pointPtr)
        !           296:     double *polyPtr;           /* Points to an array coordinates for
        !           297:                                 * closed polygon:  x0, y0, x1, y1, ...
        !           298:                                 * The polygon may be self-intersecting. */
        !           299:     int numPoints;             /* Total number of points at *polyPtr. */
        !           300:     double *pointPtr;          /* Points to coords for point. */
        !           301: {
        !           302:     double bestDist;           /* Closest distance between point and
        !           303:                                 * any edge in polygon. */
        !           304:     int intersections;         /* Number of edges in the polygon that
        !           305:                                 * intersect a ray extending vertically
        !           306:                                 * upwards from the point to infinity. */
        !           307:     int count;
        !           308:     register double *pPtr;
        !           309: 
        !           310:     /*
        !           311:      * Iterate through all of the edges in the polygon, updating
        !           312:      * bestDist and intersections.
        !           313:      *
        !           314:      * TRICKY POINT:  when computing intersections, include left
        !           315:      * x-coordinate of line within its range, but not y-coordinate.
        !           316:      * Otherwise if the point lies exactly below a vertex we'll
        !           317:      * count it as two intersections.
        !           318:      */
        !           319: 
        !           320:     bestDist = 1.0e40;
        !           321:     intersections = 0;
        !           322: 
        !           323:     for (count = numPoints, pPtr = polyPtr; count > 1; count--, pPtr += 2) {
        !           324:        double x, y, dist;
        !           325: 
        !           326:        /*
        !           327:         * Compute the point on the current edge closest to the point
        !           328:         * and update the intersection count.  This must be done
        !           329:         * separately for vertical edges, horizontal edges, and
        !           330:         * other edges.
        !           331:         */
        !           332: 
        !           333:        if (pPtr[2] == pPtr[0]) {
        !           334: 
        !           335:            /*
        !           336:             * Vertical edge.
        !           337:             */
        !           338: 
        !           339:            x = pPtr[0];
        !           340:            if (pPtr[1] >= pPtr[3]) {
        !           341:                y = MIN(pPtr[1], pointPtr[1]);
        !           342:                y = MAX(y, pPtr[3]);
        !           343:            } else {
        !           344:                y = MIN(pPtr[3], pointPtr[1]);
        !           345:                y = MAX(y, pPtr[1]);
        !           346:            }
        !           347:        } else if (pPtr[3] == pPtr[1]) {
        !           348: 
        !           349:            /*
        !           350:             * Horizontal edge.
        !           351:             */
        !           352: 
        !           353:            y = pPtr[1];
        !           354:            if (pPtr[0] >= pPtr[2]) {
        !           355:                x = MIN(pPtr[0], pointPtr[0]);
        !           356:                x = MAX(x, pPtr[2]);
        !           357:                if ((pointPtr[1] < y) && (pointPtr[0] < pPtr[0])
        !           358:                        && (pointPtr[0] >= pPtr[2])) {
        !           359:                    intersections++;
        !           360:                }
        !           361:            } else {
        !           362:                x = MIN(pPtr[2], pointPtr[0]);
        !           363:                x = MAX(x, pPtr[0]);
        !           364:                if ((pointPtr[1] < y) && (pointPtr[0] < pPtr[2])
        !           365:                        && (pointPtr[0] >= pPtr[0])) {
        !           366:                    intersections++;
        !           367:                }
        !           368:            }
        !           369:        } else {
        !           370:            double m1, b1, m2, b2;
        !           371:            int lower;                  /* Non-zero means point below line. */
        !           372: 
        !           373:            /*
        !           374:             * The edge is neither horizontal nor vertical.  Convert the
        !           375:             * edge to a line equation of the form y = m1*x + b1.  Then
        !           376:             * compute a line perpendicular to this edge but passing
        !           377:             * through the point, also in the form y = m2*x + b2.
        !           378:             */
        !           379: 
        !           380:            m1 = (pPtr[3] - pPtr[1])/(pPtr[2] - pPtr[0]);
        !           381:            b1 = pPtr[1] - m1*pPtr[0];
        !           382:            m2 = -1.0/m1;
        !           383:            b2 = pointPtr[1] - m2*pointPtr[0];
        !           384:            x = (b2 - b1)/(m1 - m2);
        !           385:            y = m1*x + b1;
        !           386:            if (pPtr[0] > pPtr[2]) {
        !           387:                if (x > pPtr[0]) {
        !           388:                    x = pPtr[0];
        !           389:                    y = pPtr[1];
        !           390:                } else if (x < pPtr[2]) {
        !           391:                    x = pPtr[2];
        !           392:                    y = pPtr[3];
        !           393:                }
        !           394:            } else {
        !           395:                if (x > pPtr[2]) {
        !           396:                    x = pPtr[2];
        !           397:                    y = pPtr[3];
        !           398:                } else if (x < pPtr[0]) {
        !           399:                    x = pPtr[0];
        !           400:                    y = pPtr[1];
        !           401:                }
        !           402:            }
        !           403:            lower = (m1*pointPtr[0] + b1) > pointPtr[1];
        !           404:            if (lower && (pointPtr[0] >= MIN(pPtr[0], pPtr[2]))
        !           405:                    && (pointPtr[0] < MAX(pPtr[0], pPtr[2]))) {
        !           406:                intersections++;
        !           407:            }
        !           408:        }
        !           409: 
        !           410:        /*
        !           411:         * Compute the distance to the closest point, and see if that
        !           412:         * is the best distance seen so far.
        !           413:         */
        !           414: 
        !           415:        dist = hypot(pointPtr[0] - x, pointPtr[1] - y);
        !           416:        if (dist < bestDist) {
        !           417:            bestDist = dist;
        !           418:        }
        !           419:     }
        !           420: 
        !           421:     /*
        !           422:      * We've processed all of the points.  If the number of intersections
        !           423:      * is odd, the point is inside the polygon.
        !           424:      */
        !           425: 
        !           426:     if (intersections & 0x1) {
        !           427:        return 0.0;
        !           428:     }
        !           429:     return bestDist;
        !           430: }
        !           431: 
        !           432: /*
        !           433:  *--------------------------------------------------------------
        !           434:  *
        !           435:  * TkPolygonToArea --
        !           436:  *
        !           437:  *     Determine whether a polygon lies entirely inside, entirely
        !           438:  *     outside, or overlapping a given rectangular area.
        !           439:  *
        !           440:  * Results:
        !           441:  *     -1 is returned if the polygon given by polyPtr and numPoints
        !           442:  *     is entirely outside the rectangle given by rectPtr.  0 is
        !           443:  *     returned if the polygon overlaps the rectangle, and 1 is
        !           444:  *     returned if the polygon is entirely inside the rectangle.
        !           445:  *
        !           446:  * Side effects:
        !           447:  *     None.
        !           448:  *
        !           449:  *--------------------------------------------------------------
        !           450:  */
        !           451: 
        !           452: int
        !           453: TkPolygonToArea(polyPtr, numPoints, rectPtr)
        !           454:     double *polyPtr;           /* Points to an array coordinates for
        !           455:                                 * closed polygon:  x0, y0, x1, y1, ...
        !           456:                                 * The polygon may be self-intersecting. */
        !           457:     int numPoints;             /* Total number of points at *polyPtr. */
        !           458:     register double *rectPtr;  /* Points to coords for rectangle, in the
        !           459:                                 * order x1, y1, x2, y2.  X1 and y1 must
        !           460:                                 * be lower-left corner. */
        !           461: {
        !           462:     int state;                 /* State of all edges seen so far (-1 means
        !           463:                                 * outside, 1 means inside, won't ever be
        !           464:                                 * 0). */
        !           465:     int count;
        !           466:     register double *pPtr;
        !           467: 
        !           468:     /*
        !           469:      * Iterate over all of the edges of the polygon and test them
        !           470:      * against the rectangle.  Can quit as soon as the state becomes
        !           471:      * "intersecting".
        !           472:      */
        !           473: 
        !           474:     state = TkLineToArea(polyPtr, polyPtr+2, rectPtr);
        !           475:     if (state == 0) {
        !           476:        return 0;
        !           477:     }
        !           478:     for (pPtr = polyPtr+2, count = numPoints-1; count >= 2;
        !           479:            pPtr += 2, count--) {
        !           480:        if (TkLineToArea(pPtr, pPtr+2, rectPtr) != state) {
        !           481:            return 0;
        !           482:        }
        !           483:     }
        !           484: 
        !           485:     /*
        !           486:      * If all of the edges were inside the rectangle we're done.
        !           487:      * If all of the edges were outside, then the rectangle could
        !           488:      * still intersect the polygon (if it's entirely enclosed).
        !           489:      * Call TkPolygonToPoint to figure this out.
        !           490:      */
        !           491: 
        !           492:     if (state == 1) {
        !           493:        return 1;
        !           494:     }
        !           495:     if (TkPolygonToPoint(polyPtr, numPoints, rectPtr) == 0.0) {
        !           496:        return 0;
        !           497:     }
        !           498:     return -1;
        !           499: }
        !           500: 
        !           501: /*
        !           502:  *--------------------------------------------------------------
        !           503:  *
        !           504:  * TkOvalToPoint --
        !           505:  *
        !           506:  *     Computes the distance from a given point to a given
        !           507:  *     oval, in canvas units.
        !           508:  *
        !           509:  * Results:
        !           510:  *     The return value is 0 if the point given by *pointPtr is
        !           511:  *     inside the oval.  If the point isn't inside the
        !           512:  *     oval then the return value is approximately the distance
        !           513:  *     from the point to the oval.  If the oval is filled, then
        !           514:  *     anywhere in the interior is considered "inside";  if
        !           515:  *     the oval isn't filled, then "inside" means only the area
        !           516:  *     occupied by the outline.
        !           517:  *
        !           518:  * Side effects:
        !           519:  *     None.
        !           520:  *
        !           521:  *--------------------------------------------------------------
        !           522:  */
        !           523: 
        !           524:        /* ARGSUSED */
        !           525: double
        !           526: TkOvalToPoint(ovalPtr, width, filled, pointPtr)
        !           527:     double ovalPtr[4];         /* Pointer to array of four coordinates
        !           528:                                 * (x1, y1, x2, y2) defining oval's bounding
        !           529:                                 * box. */
        !           530:     double width;              /* Width of outline for oval. */
        !           531:     int filled;                        /* Non-zero means oval should be treated as
        !           532:                                 * filled;  zero means only consider outline. */
        !           533:     double pointPtr[2];                /* Coordinates of point. */
        !           534: {
        !           535:     double xDelta, yDelta, scaledDistance, distToOutline, distToCenter;
        !           536: 
        !           537:     /*
        !           538:      * Compute the distance between the center of the oval and the
        !           539:      * point in question, using a coordinate system where the oval
        !           540:      * has been transformed to a circle with unit radius.
        !           541:      */
        !           542: 
        !           543:     xDelta = (pointPtr[0] - (ovalPtr[0] + ovalPtr[2])/2.0);
        !           544:     yDelta = (pointPtr[1] - (ovalPtr[1] + ovalPtr[3])/2.0);
        !           545:     distToCenter = hypot(xDelta, yDelta);
        !           546:     scaledDistance = hypot(xDelta / ((ovalPtr[2] + width - ovalPtr[0])/2.0),
        !           547:            yDelta / ((ovalPtr[3] + width - ovalPtr[1])/2.0));
        !           548: 
        !           549: 
        !           550:     /*
        !           551:      * If the scaled distance is greater than 1 then it means no
        !           552:      * hit.  Compute the distance from the point to the edge of
        !           553:      * the circle, then scale this distance back to the original
        !           554:      * coordinate system.
        !           555:      *
        !           556:      * Note: this distance isn't completely accurate.  It's only
        !           557:      * an approximation, and it can overestimate the correct
        !           558:      * distance when the oval is eccentric.
        !           559:      */
        !           560: 
        !           561:     if (scaledDistance > 1.0) {
        !           562:        return (distToCenter/scaledDistance) * (scaledDistance - 1.0);
        !           563:     }
        !           564: 
        !           565:     /*
        !           566:      * Scaled distance less than 1 means the point is inside the
        !           567:      * outer edge of the oval.  If this is a filled oval, then we
        !           568:      * have a hit.  Otherwise, do the same computation as above
        !           569:      * (scale back to original coordinate system), but also check
        !           570:      * to see if the point is within the width of the outline.
        !           571:      */
        !           572: 
        !           573:     if (filled) {
        !           574:        return 0.0;
        !           575:     }
        !           576:     distToOutline = (distToCenter/scaledDistance) * (1.0 - scaledDistance)
        !           577:            - width;
        !           578:     if (distToOutline < 0.0) {
        !           579:        return 0.0;
        !           580:     }
        !           581:     return distToOutline;
        !           582: }
        !           583: 
        !           584: /*
        !           585:  *--------------------------------------------------------------
        !           586:  *
        !           587:  * TkOvalToArea --
        !           588:  *
        !           589:  *     Determine whether an oval lies entirely inside, entirely
        !           590:  *     outside, or overlapping a given rectangular area.
        !           591:  *
        !           592:  * Results:
        !           593:  *     -1 is returned if the oval described by ovalPtr is entirely
        !           594:  *     outside the rectangle given by rectPtr.  0 is returned if the
        !           595:  *     oval overlaps the rectangle, and 1 is returned if the oval
        !           596:  *     is entirely inside the rectangle.
        !           597:  *
        !           598:  * Side effects:
        !           599:  *     None.
        !           600:  *
        !           601:  *--------------------------------------------------------------
        !           602:  */
        !           603: 
        !           604: int
        !           605: TkOvalToArea(ovalPtr, rectPtr)
        !           606:     register double *ovalPtr;  /* Points to coordinates definining the
        !           607:                                 * bounding rectangle for the oval: x1, y1,
        !           608:                                 * x2, y2.  X1 must be less than x2 and y1
        !           609:                                 * less than y2. */
        !           610:     register double *rectPtr;  /* Points to coords for rectangle, in the
        !           611:                                 * order x1, y1, x2, y2.  X1 and y1 must
        !           612:                                 * be lower-left corner. */
        !           613: {
        !           614:     double centerX, centerY, radX, radY, deltaX, deltaY;
        !           615: 
        !           616:     /*
        !           617:      * First, see if oval is entirely inside rectangle or entirely
        !           618:      * outside rectangle.
        !           619:      */
        !           620: 
        !           621:     if ((rectPtr[0] <= ovalPtr[0]) && (rectPtr[2] >= ovalPtr[2])
        !           622:            && (rectPtr[1] <= ovalPtr[1]) && (rectPtr[3] >= ovalPtr[3])) {
        !           623:        return 1;
        !           624:     }
        !           625:     if ((rectPtr[2] < ovalPtr[0]) || (rectPtr[0] > ovalPtr[2])
        !           626:            || (rectPtr[3] < ovalPtr[1]) || (rectPtr[1] > ovalPtr[3])) {
        !           627:        return -1;
        !           628:     }
        !           629: 
        !           630:     /*
        !           631:      * Next, go through the rectangle side by side.  For each side
        !           632:      * of the rectangle, find the point on the side that is closest
        !           633:      * to the oval's center, and see if that point is inside the
        !           634:      * oval.  If at least one such point is inside the oval, then
        !           635:      * the rectangle intersects the oval.
        !           636:      */
        !           637: 
        !           638:     centerX = (ovalPtr[0] + ovalPtr[2])/2;
        !           639:     centerY = (ovalPtr[1] + ovalPtr[3])/2;
        !           640:     radX = (ovalPtr[2] - ovalPtr[0])/2;
        !           641:     radY = (ovalPtr[3] - ovalPtr[1])/2;
        !           642: 
        !           643:     deltaY = rectPtr[1] - centerY;
        !           644:     if (deltaY < 0.0) {
        !           645:        deltaY = centerY - rectPtr[3];
        !           646:        if (deltaY < 0.0) {
        !           647:            deltaY = 0;
        !           648:        }
        !           649:     }
        !           650:     deltaY /= radY;
        !           651:     deltaY *= deltaY;
        !           652: 
        !           653:     /*
        !           654:      * Left side:
        !           655:      */
        !           656: 
        !           657:     deltaX = (rectPtr[0] - centerX)/radX;
        !           658:     deltaX *= deltaX;
        !           659:     if ((deltaX + deltaY) <= 1.0) {
        !           660:        return 0;
        !           661:     }
        !           662: 
        !           663:     /*
        !           664:      * Right side:
        !           665:      */
        !           666: 
        !           667:     deltaX = (rectPtr[2] - centerX)/radX;
        !           668:     deltaX *= deltaX;
        !           669:     if ((deltaX + deltaY) <= 1.0) {
        !           670:        return 0;
        !           671:     }
        !           672: 
        !           673:     deltaX = rectPtr[0] - centerX;
        !           674:     if (deltaX < 0.0) {
        !           675:        deltaX = centerX - rectPtr[2];
        !           676:        if (deltaX < 0.0) {
        !           677:            deltaX = 0;
        !           678:        }
        !           679:     }
        !           680:     deltaX /= radX;
        !           681:     deltaX *= deltaX;
        !           682: 
        !           683:     /*
        !           684:      * Bottom side:
        !           685:      */
        !           686: 
        !           687:     deltaY = (rectPtr[1] - centerY)/radY;
        !           688:     deltaY *= deltaY;
        !           689:     if ((deltaX + deltaY) < 1.0) {
        !           690:        return 0;
        !           691:     }
        !           692: 
        !           693:     /*
        !           694:      * Top side:
        !           695:      */
        !           696: 
        !           697:     deltaY = (rectPtr[3] - centerY)/radY;
        !           698:     deltaY *= deltaY;
        !           699:     if ((deltaX + deltaY) < 1.0) {
        !           700:        return 0;
        !           701:     }
        !           702: 
        !           703:     return -1;
        !           704: }
        !           705: 
        !           706: /*
        !           707:  *--------------------------------------------------------------
        !           708:  *
        !           709:  * TkIncludePoint --
        !           710:  *
        !           711:  *     Given a point and a generic canvas item header, expand
        !           712:  *     the item's bounding box if needed to include the point.
        !           713:  *
        !           714:  * Results:
        !           715:  *     None.
        !           716:  *
        !           717:  * Side effects:
        !           718:  *     The boudn.
        !           719:  *
        !           720:  *--------------------------------------------------------------
        !           721:  */
        !           722: 
        !           723:        /* ARGSUSED */
        !           724: void
        !           725: TkIncludePoint(canvasPtr, itemPtr, pointPtr)
        !           726:     Tk_Canvas *canvasPtr;              /* Canvas containing item. */
        !           727:     register Tk_Item *itemPtr;         /* Item whose bounding box is
        !           728:                                         * being calculated. */
        !           729:     double *pointPtr;                  /* Address of two doubles giving
        !           730:                                         * x and y coordinates of point. */
        !           731: {
        !           732:     int tmp;
        !           733: 
        !           734:     tmp = pointPtr[0] + 0.5;
        !           735:     if (tmp < itemPtr->x1) {
        !           736:        itemPtr->x1 = tmp;
        !           737:     }
        !           738:     if (tmp > itemPtr->x2) {
        !           739:        itemPtr->x2 = tmp;
        !           740:     }
        !           741:     tmp = pointPtr[1] + 0.5;
        !           742:     if (tmp < itemPtr->y1) {
        !           743:        itemPtr->y1 = tmp;
        !           744:     }
        !           745:     if (tmp > itemPtr->y2) {
        !           746:        itemPtr->y2 = tmp;
        !           747:     }
        !           748: }
        !           749: 
        !           750: /*
        !           751:  *--------------------------------------------------------------
        !           752:  *
        !           753:  * TkBezierScreenPoints --
        !           754:  *
        !           755:  *     Given four control points, create a larger set of XPoints
        !           756:  *     for a Bezier spline based on the points.
        !           757:  *
        !           758:  * Results:
        !           759:  *     The array at *xPointPtr gets filled in with numSteps XPoints
        !           760:  *     corresponding to the Bezier spline defined by the four 
        !           761:  *     control points.  Note:  no output point is generated for the
        !           762:  *     first input point, but an output point *is* generated for
        !           763:  *     the last input point.
        !           764:  *
        !           765:  * Side effects:
        !           766:  *     None.
        !           767:  *
        !           768:  *--------------------------------------------------------------
        !           769:  */
        !           770: 
        !           771: void
        !           772: TkBezierScreenPoints(canvasPtr, control, numSteps, xPointPtr)
        !           773:     Tk_Canvas *canvasPtr;              /* Canvas in which curve is to be
        !           774:                                         * drawn. */
        !           775:     double control[];                  /* Array of coordinates for four
        !           776:                                         * control points:  x0, y0, x1, y1,
        !           777:                                         * ... x3 y3. */
        !           778:     int numSteps;                      /* Number of curve points to
        !           779:                                         * generate.  */
        !           780:     register XPoint *xPointPtr;                /* Where to put new points. */
        !           781: {
        !           782:     int i;
        !           783:     double u, u2, u3, t, t2, t3;
        !           784: 
        !           785:     for (i = 1; i <= numSteps; i++, xPointPtr++) {
        !           786:        t = ((double) i)/((double) numSteps);
        !           787:        t2 = t*t;
        !           788:        t3 = t2*t;
        !           789:        u = 1.0 - t;
        !           790:        u2 = u*u;
        !           791:        u3 = u2*u;
        !           792:        xPointPtr->x = SCREEN_X(canvasPtr, (control[0]*u3
        !           793:                + 3.0 * (control[2]*t*u2 + control[4]*t2*u) + control[6]*t3));
        !           794:        xPointPtr->y = SCREEN_Y(canvasPtr, (control[1]*u3
        !           795:                + 3.0 * (control[3]*t*u2 + control[5]*t2*u) + control[7]*t3));
        !           796:     }
        !           797: }
        !           798: 
        !           799: /*
        !           800:  *--------------------------------------------------------------
        !           801:  *
        !           802:  * TkBezierPoints --
        !           803:  *
        !           804:  *     Given four control points, create a larger set of points
        !           805:  *     for a Bezier spline based on the points.
        !           806:  *
        !           807:  * Results:
        !           808:  *     The array at *coordPtr gets filled in with 2*numSteps
        !           809:  *     coordinates, which correspond to the Bezier spline defined
        !           810:  *     by the four control points.  Note:  no output point is
        !           811:  *     generated for the first input point, but an output point
        !           812:  *     *is* generated for the last input point.
        !           813:  *
        !           814:  * Side effects:
        !           815:  *     None.
        !           816:  *
        !           817:  *--------------------------------------------------------------
        !           818:  */
        !           819: 
        !           820: void
        !           821: TkBezierPoints(control, numSteps, coordPtr)
        !           822:     double control[];                  /* Array of coordinates for four
        !           823:                                         * control points:  x0, y0, x1, y1,
        !           824:                                         * ... x3 y3. */
        !           825:     int numSteps;                      /* Number of curve points to
        !           826:                                         * generate.  */
        !           827:     register double *coordPtr;         /* Where to put new points. */
        !           828: {
        !           829:     int i;
        !           830:     double u, u2, u3, t, t2, t3;
        !           831: 
        !           832:     for (i = 1; i <= numSteps; i++, coordPtr += 2) {
        !           833:        t = ((double) i)/((double) numSteps);
        !           834:        t2 = t*t;
        !           835:        t3 = t2*t;
        !           836:        u = 1.0 - t;
        !           837:        u2 = u*u;
        !           838:        u3 = u2*u;
        !           839:        coordPtr[0] = control[0]*u3
        !           840:                + 3.0 * (control[2]*t*u2 + control[4]*t2*u) + control[6]*t3;
        !           841:        coordPtr[1] = control[1]*u3
        !           842:                + 3.0 * (control[3]*t*u2 + control[5]*t2*u) + control[7]*t3;
        !           843:     }
        !           844: }
        !           845: 
        !           846: /*
        !           847:  *--------------------------------------------------------------
        !           848:  *
        !           849:  * TkMakeBezierCurve --
        !           850:  *
        !           851:  *     Given a set of points, create a new set of points that
        !           852:  *     fit Bezier splines to the line segments connecting the
        !           853:  *     original points.  Produces output points in either of two
        !           854:  *     forms.
        !           855:  *
        !           856:  * Results:
        !           857:  *     Either or both of the xPoints or dblPoints arrays are filled
        !           858:  *     in.  The return value is the number of points placed in the
        !           859:  *     arrays.  Note:  if the first and last points are the same, then
        !           860:  *     a closed curve is generated.
        !           861:  *
        !           862:  * Side effects:
        !           863:  *     None.
        !           864:  *
        !           865:  *--------------------------------------------------------------
        !           866:  */
        !           867: 
        !           868: int
        !           869: TkMakeBezierCurve(canvasPtr, pointPtr, numPoints, numSteps, xPoints, dblPoints)
        !           870:     Tk_Canvas *canvasPtr;              /* Canvas in which curve is to be
        !           871:                                         * drawn. */
        !           872:     double *pointPtr;                  /* Array of input coordinates:  x0,
        !           873:                                         * y0, x1, y1, etc.. */
        !           874:     int numPoints;                     /* Number of points at pointPtr. */
        !           875:     int numSteps;                      /* Number of steps to use for each
        !           876:                                         * spline segments (determines
        !           877:                                         * smoothness of curve). */
        !           878:     XPoint xPoints[];                  /* Array of XPoints to fill in (e.g.
        !           879:                                         * for display.  NULL means don't
        !           880:                                         * fill in any XPoints. */
        !           881:     double dblPoints[];                        /* Array of points to fill in as
        !           882:                                         * doubles, in the form x0, y0,
        !           883:                                         * x1, y1, ....  NULL means don't
        !           884:                                         * fill in anything in this form. 
        !           885:                                         * Caller must make sure that this
        !           886:                                         * array has enough space. */
        !           887: {
        !           888:     int closed, outputPoints, i;
        !           889:     int numCoords = numPoints*2;
        !           890:     double control[8];
        !           891: 
        !           892:     /*
        !           893:      * If the curve is a closed one then generate a special spline
        !           894:      * that spans the last points and the first ones.  Otherwise
        !           895:      * just put the first point into the output.
        !           896:      */
        !           897: 
        !           898:     outputPoints = 0;
        !           899:     if ((pointPtr[0] == pointPtr[numCoords-2])
        !           900:            && (pointPtr[1] == pointPtr[numCoords-1])) {
        !           901:        closed = 1;
        !           902:        control[0] = 0.5*pointPtr[numCoords-4] + 0.5*pointPtr[0];
        !           903:        control[1] = 0.5*pointPtr[numCoords-3] + 0.5*pointPtr[1];
        !           904:        control[2] = 0.167*pointPtr[numCoords-4] + 0.833*pointPtr[0];
        !           905:        control[3] = 0.167*pointPtr[numCoords-3] + 0.833*pointPtr[1];
        !           906:        control[4] = 0.833*pointPtr[0] + 0.167*pointPtr[2];
        !           907:        control[5] = 0.833*pointPtr[1] + 0.167*pointPtr[3];
        !           908:        control[6] = 0.5*pointPtr[0] + 0.5*pointPtr[2];
        !           909:        control[7] = 0.5*pointPtr[1] + 0.5*pointPtr[3];
        !           910:        if (xPoints != NULL) {
        !           911:            xPoints->x = SCREEN_X(canvasPtr, control[0]);
        !           912:            xPoints->y = SCREEN_Y(canvasPtr, control[1]);
        !           913:            TkBezierScreenPoints(canvasPtr, control, numSteps, xPoints+1);
        !           914:            xPoints += numSteps+1;
        !           915:        }
        !           916:        if (dblPoints != NULL) {
        !           917:            dblPoints[0] = control[0];
        !           918:            dblPoints[1] = control[1];
        !           919:            TkBezierPoints(control, numSteps, dblPoints+2);
        !           920:            dblPoints += 2*(numSteps+1);
        !           921:        }
        !           922:        outputPoints += numSteps+1;
        !           923:     } else {
        !           924:        closed = 0;
        !           925:        if (xPoints != NULL) {
        !           926:            xPoints->x = SCREEN_X(canvasPtr, pointPtr[0]);
        !           927:            xPoints->y = SCREEN_Y(canvasPtr, pointPtr[1]);
        !           928:            xPoints += 1;
        !           929:        }
        !           930:        if (dblPoints != NULL) {
        !           931:            dblPoints[0] = pointPtr[0];
        !           932:            dblPoints[1] = pointPtr[1];
        !           933:            dblPoints += 2;
        !           934:        }
        !           935:        outputPoints += 1;
        !           936:     }
        !           937: 
        !           938:     for (i = 2; i < numPoints; i++, pointPtr += 2) {
        !           939:        /*
        !           940:         * Set up the first two control points.  This is done
        !           941:         * differently for the first spline of an open curve
        !           942:         * than for other cases.
        !           943:         */
        !           944: 
        !           945:        if ((i == 2) && !closed) {
        !           946:            control[0] = pointPtr[0];
        !           947:            control[1] = pointPtr[1];
        !           948:            control[2] = 0.333*pointPtr[0] + 0.667*pointPtr[2];
        !           949:            control[3] = 0.333*pointPtr[1] + 0.667*pointPtr[3];
        !           950:        } else {
        !           951:            control[0] = 0.5*pointPtr[0] + 0.5*pointPtr[2];
        !           952:            control[1] = 0.5*pointPtr[1] + 0.5*pointPtr[3];
        !           953:            control[2] = 0.167*pointPtr[0] + 0.833*pointPtr[2];
        !           954:            control[3] = 0.167*pointPtr[1] + 0.833*pointPtr[3];
        !           955:        }
        !           956: 
        !           957:        /*
        !           958:         * Set up the last two control points.  This is done
        !           959:         * differently for the last spline of an open curve
        !           960:         * than for other cases.
        !           961:         */
        !           962: 
        !           963:        if ((i == (numPoints-1)) && !closed) {
        !           964:            control[4] = .667*pointPtr[2] + .333*pointPtr[4];
        !           965:            control[5] = .667*pointPtr[3] + .333*pointPtr[5];
        !           966:            control[6] = pointPtr[4];
        !           967:            control[7] = pointPtr[5];
        !           968:        } else {
        !           969:            control[4] = .833*pointPtr[2] + .167*pointPtr[4];
        !           970:            control[5] = .833*pointPtr[3] + .167*pointPtr[5];
        !           971:            control[6] = 0.5*pointPtr[2] + 0.5*pointPtr[4];
        !           972:            control[7] = 0.5*pointPtr[3] + 0.5*pointPtr[5];
        !           973:        }
        !           974: 
        !           975:        /*
        !           976:         * If the first two points coincide, or if the last
        !           977:         * two points coincide, then generate a single
        !           978:         * straight-line segment by outputting the last control
        !           979:         * point.
        !           980:         */
        !           981: 
        !           982:        if (((pointPtr[0] == pointPtr[2]) && (pointPtr[1] == pointPtr[3]))
        !           983:                || ((pointPtr[2] == pointPtr[4])
        !           984:                && (pointPtr[3] == pointPtr[5]))) {
        !           985:            if (xPoints != NULL) {
        !           986:                xPoints[0].x = SCREEN_X(canvasPtr, control[6]);
        !           987:                xPoints[0].y = SCREEN_Y(canvasPtr, control[7]);
        !           988:                xPoints++;
        !           989:            }
        !           990:            if (dblPoints != NULL) {
        !           991:                dblPoints[0] = control[6];
        !           992:                dblPoints[1] = control[7];
        !           993:                dblPoints += 2;
        !           994:            }
        !           995:            outputPoints += 1;
        !           996:            continue;
        !           997:        }
        !           998: 
        !           999:        /*
        !          1000:         * Generate a Bezier spline using the control points.
        !          1001:         */
        !          1002: 
        !          1003: 
        !          1004:        if (xPoints != NULL) {
        !          1005:            TkBezierScreenPoints(canvasPtr, control, numSteps, xPoints);
        !          1006:            xPoints += numSteps;
        !          1007:        }
        !          1008:        if (dblPoints != NULL) {
        !          1009:            TkBezierPoints(control, numSteps, dblPoints);
        !          1010:            dblPoints += 2*numSteps;
        !          1011:        }
        !          1012:        outputPoints += numSteps;
        !          1013:     }
        !          1014:     return outputPoints;
        !          1015: }
        !          1016: 
        !          1017: /*
        !          1018:  *--------------------------------------------------------------
        !          1019:  *
        !          1020:  * TkGetMiterPoints --
        !          1021:  *
        !          1022:  *     Given three points forming an angle, compute the
        !          1023:  *     coordinates of the inside and outside points of
        !          1024:  *     the mitered corner formed by a line of a given
        !          1025:  *     width at that angle.
        !          1026:  *
        !          1027:  * Results:
        !          1028:  *     If the angle formed by the three points is less than
        !          1029:  *     11 degrees then 0 is returned and m1 and m2 aren't
        !          1030:  *     modified.  Otherwise 1 is returned and the points at
        !          1031:  *     m1 and m2 are filled in with the positions of the points
        !          1032:  *     of the mitered corner.
        !          1033:  *
        !          1034:  * Side effects:
        !          1035:  *     None.
        !          1036:  *
        !          1037:  *--------------------------------------------------------------
        !          1038:  */
        !          1039: 
        !          1040: int
        !          1041: TkGetMiterPoints(p1, p2, p3, width, m1, m2)
        !          1042:     double p1[];               /* Points to x- and y-coordinates of point
        !          1043:                                 * before vertex. */
        !          1044:     double p2[];               /* Points to x- and y-coordinates of vertex
        !          1045:                                 * for mitered joint. */
        !          1046:     double p3[];               /* Points to x- and y-coordinates of point
        !          1047:                                 * after vertex. */
        !          1048:     double width;              /* Width of line.  */
        !          1049:     double m1[];               /* Points to place to put "left" vertex
        !          1050:                                 * point (see as you face from p1 to p2). */
        !          1051:     double m2[];               /* Points to place to put "right" vertex
        !          1052:                                 * point. */
        !          1053: {
        !          1054:     double theta1;             /* Angle of segment p2-p1. */
        !          1055:     double theta2;             /* Angle of segment p2-p3. */
        !          1056:     double theta;              /* Angle between line segments (angle
        !          1057:                                 * of joint). */
        !          1058:     double theta3;             /* Angle that bisects theta1 and
        !          1059:                                 * theta2 and points to m1. */
        !          1060:     double dist;               /* Distance of miter points from p2. */
        !          1061:     double deltaX, deltaY;     /* X and y offsets cooresponding to
        !          1062:                                 * dist (fudge factors for bounding
        !          1063:                                 * box). */
        !          1064:     static float elevenDegrees = (11.0*2.0*PI)/360.0;
        !          1065: 
        !          1066:     if (p2[1] == p1[1]) {
        !          1067:        theta1 = (p2[0] < p1[0]) ? 0 : PI;
        !          1068:     } else if (p2[0] == p1[0]) {
        !          1069:        theta1 = (p2[1] < p1[1]) ? PI/2.0 : -PI/2.0;
        !          1070:     } else {
        !          1071:        theta1 = atan2(p1[1] - p2[1], p1[0] - p2[0]);
        !          1072:     }
        !          1073:     if (p3[1] == p2[1]) {
        !          1074:        theta2 = (p3[0] > p2[0]) ? 0 : PI;
        !          1075:     } else if (p3[0] == p2[0]) {
        !          1076:        theta2 = (p3[1] > p2[1]) ? PI/2.0 : -PI/2.0;
        !          1077:     } else {
        !          1078:        theta2 = atan2(p3[1] - p2[1], p3[0] - p2[0]);
        !          1079:     }
        !          1080:     theta = theta1 - theta2;
        !          1081:     if (theta > PI) {
        !          1082:        theta -= 2*PI;
        !          1083:     } else if (theta < -PI) {
        !          1084:        theta += 2*PI;
        !          1085:     }
        !          1086:     if ((theta < elevenDegrees) && (theta > -elevenDegrees)) {
        !          1087:        return 0;
        !          1088:     }
        !          1089:     dist = 0.5*width/sin(0.5*theta);
        !          1090:     if (dist < 0.0) {
        !          1091:        dist = -dist;
        !          1092:     }
        !          1093: 
        !          1094:     /*
        !          1095:      * Compute theta3 (make sure that it points to the left when
        !          1096:      * looking from p1 to p2).
        !          1097:      */
        !          1098: 
        !          1099:     theta3 = (theta1 + theta2)/2.0;
        !          1100:     if (sin(theta3 - (theta1 + PI)) < 0.0) {
        !          1101:        theta3 += PI;
        !          1102:     }
        !          1103:     deltaX = dist*cos(theta3);
        !          1104:     m1[0] = p2[0] + deltaX;
        !          1105:     m2[0] = p2[0] - deltaX;
        !          1106:     deltaY = dist*sin(theta3);
        !          1107:     m1[1] = p2[1] + deltaY;
        !          1108:     m2[1] = p2[1] - deltaY;
        !          1109:     return 1;
        !          1110: }
        !          1111: 
        !          1112: /*
        !          1113:  *--------------------------------------------------------------
        !          1114:  *
        !          1115:  * TkGetButtPoints --
        !          1116:  *
        !          1117:  *     Given two points forming a line segment, compute the
        !          1118:  *     coordinates of two endpoints of a rectangle formed by
        !          1119:  *     bloating the line segment until it is width units wide.
        !          1120:  *
        !          1121:  * Results:
        !          1122:  *     There is no return value.  M1 and m2 are filled in to
        !          1123:  *     correspond to m1 and m2 in the diagram below:
        !          1124:  *
        !          1125:  *                ----------------* m1
        !          1126:  *                                |
        !          1127:  *             p1 *---------------* p2
        !          1128:  *                                |
        !          1129:  *                ----------------* m2
        !          1130:  *
        !          1131:  *     M1 and m2 will be W units apart, with p2 centered between
        !          1132:  *     them and m1-m2 perpendicular to p1-p2.  However, if
        !          1133:  *     "project" is true then m1 and m2 will be as follows:
        !          1134:  *
        !          1135:  *                -------------------* m1
        !          1136:  *                               p2  |
        !          1137:  *             p1 *---------------*  |
        !          1138:  *                                   |
        !          1139:  *                -------------------* m2
        !          1140:  *
        !          1141:  *     In this case p2 will be width/2 units from the segment m1-m2.
        !          1142:  *
        !          1143:  * Side effects:
        !          1144:  *     None.
        !          1145:  *
        !          1146:  *--------------------------------------------------------------
        !          1147:  */
        !          1148: 
        !          1149: void
        !          1150: TkGetButtPoints(p1, p2, width, project, m1, m2)
        !          1151:     double p1[];               /* Points to x- and y-coordinates of point
        !          1152:                                 * before vertex. */
        !          1153:     double p2[];               /* Points to x- and y-coordinates of vertex
        !          1154:                                 * for mitered joint. */
        !          1155:     double width;              /* Width of line.  */
        !          1156:     int project;               /* Non-zero means project p2 by an additional
        !          1157:                                 * width/2 before computing m1 and m2. */
        !          1158:     double m1[];               /* Points to place to put "left" result
        !          1159:                                 * point, as you face from p1 to p2. */
        !          1160:     double m2[];               /* Points to place to put "right" result
        !          1161:                                 * point. */
        !          1162: {
        !          1163:     double length;             /* Length of p1-p2 segment. */
        !          1164:     double deltaX, deltaY;     /* Increments in coords. */
        !          1165: 
        !          1166:     width *= 0.5;
        !          1167:     length = hypot(p2[0] - p1[0], p2[1] - p1[1]);
        !          1168:     if (length == 0.0) {
        !          1169:        m1[0] = m2[0] = p2[0];
        !          1170:        m1[1] = m2[1] = p2[1];
        !          1171:     } else {
        !          1172:        deltaX = -width * (p2[1] - p1[1]) / length;
        !          1173:        deltaY = width * (p2[0] - p1[0]) / length;
        !          1174:        m1[0] = p2[0] + deltaX;
        !          1175:        m2[0] = p2[0] - deltaX;
        !          1176:        m1[1] = p2[1] + deltaY;
        !          1177:        m2[1] = p2[1] - deltaY;
        !          1178:        if (project) {
        !          1179:            m1[0] += deltaY;
        !          1180:            m2[0] += deltaY;
        !          1181:            m1[1] -= deltaX;
        !          1182:            m2[1] -= deltaX;
        !          1183:        }
        !          1184:     }
        !          1185: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.