Annotation of micropolis/src/tk/tktrig.c, revision 1.1.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.