[BACK]Return to util3d.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gnuplot

Annotation of OpenXM_contrib/gnuplot/util3d.c, Revision 1.1

1.1     ! maekawa     1: #ifndef lint
        !             2: static char *RCSid = "$Id: util3d.c,v 1.17 1998/06/18 14:55:20 ddenholm Exp $";
        !             3: #endif
        !             4:
        !             5:
        !             6: /* GNUPLOT - util3d.c */
        !             7:
        !             8: /*[
        !             9:  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
        !            10:  *
        !            11:  * Permission to use, copy, and distribute this software and its
        !            12:  * documentation for any purpose with or without fee is hereby granted,
        !            13:  * provided that the above copyright notice appear in all copies and
        !            14:  * that both that copyright notice and this permission notice appear
        !            15:  * in supporting documentation.
        !            16:  *
        !            17:  * Permission to modify the software is granted, but not the right to
        !            18:  * distribute the complete modified source code.  Modifications are to
        !            19:  * be distributed as patches to the released version.  Permission to
        !            20:  * distribute binaries produced by compiling modified sources is granted,
        !            21:  * provided you
        !            22:  *   1. distribute the corresponding source modifications from the
        !            23:  *    released version in the form of a patch file along with the binaries,
        !            24:  *   2. add special version identification to distinguish your version
        !            25:  *    in addition to the base release version number,
        !            26:  *   3. provide your name and address as the primary contact for the
        !            27:  *    support of your modified version, and
        !            28:  *   4. retain our contact information in regard to use of the base
        !            29:  *    software.
        !            30:  * Permission to distribute the released version of the source code along
        !            31:  * with corresponding source modifications in the form of a patch file is
        !            32:  * granted with same provisions 2 through 4 for binary distributions.
        !            33:  *
        !            34:  * This software is provided "as is" without express or implied warranty
        !            35:  * to the extent permitted by applicable law.
        !            36: ]*/
        !            37:
        !            38:
        !            39: /*
        !            40:  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
        !            41:  * Added user-specified bases for log scaling.
        !            42:  *
        !            43:  * 3.6 - split graph3d.c into graph3d.c (graph),
        !            44:  *                            util3d.c (intersections, etc)
        !            45:  *                            hidden3d.c (hidden-line removal code)
        !            46:  *
        !            47:  */
        !            48:
        !            49: #include "plot.h"
        !            50: #include "setshow.h"
        !            51:
        !            52: extern int xleft,xright,ybot,ytop;
        !            53: extern int hidden_active; /* HBB 980324: hidden_no_update was unused here */
        !            54:
        !            55: /* ACCESS THINGS THAT OUGHT TO BE HIDDEN IN hidden3d.c - perhaps we
        !            56:  * can move the relevant code into hidden3d.c sometime
        !            57:  */
        !            58:
        !            59: /* Bitmap of the screen.  The array for each x value is malloc-ed as needed */
        !            60:
        !            61: extern int suppressMove;
        !            62:
        !            63: extern double min_array[], max_array[];
        !            64: extern int auto_array[], log_array[];
        !            65: extern double base_array[], log_base_array[];
        !            66:
        !            67: /* for convenience while converting to use these arrays */
        !            68: #define x_min3d min_array[FIRST_X_AXIS]
        !            69: #define x_max3d max_array[FIRST_X_AXIS]
        !            70: #define y_min3d min_array[FIRST_Y_AXIS]
        !            71: #define y_max3d max_array[FIRST_Y_AXIS]
        !            72: #define z_min3d min_array[FIRST_Z_AXIS]
        !            73: #define z_max3d max_array[FIRST_Z_AXIS]
        !            74: #define min3d_z min_array[FIRST_Z_AXIS]
        !            75: #define max3d_z max_array[FIRST_Z_AXIS]
        !            76:
        !            77: typedef double transform_matrix[4][4];
        !            78:
        !            79: void mat_unit(mat)
        !            80: transform_matrix mat;
        !            81: {
        !            82:     int i, j;
        !            83:
        !            84:     for (i = 0; i < 4; i++) for (j = 0; j < 4; j++)
        !            85:        if (i == j)
        !            86:            mat[i][j] = 1.0;
        !            87:        else
        !            88:            mat[i][j] = 0.0;
        !            89: }
        !            90:
        !            91: void mat_trans(tx, ty, tz, mat)
        !            92: double tx, ty, tz;
        !            93: transform_matrix mat;
        !            94: {
        !            95:      mat_unit(mat);                                 /* Make it unit matrix. */
        !            96:      mat[3][0] = tx;
        !            97:      mat[3][1] = ty;
        !            98:      mat[3][2] = tz;
        !            99: }
        !           100:
        !           101: void mat_scale(sx, sy, sz, mat)
        !           102: double sx, sy, sz;
        !           103: transform_matrix mat;
        !           104: {
        !           105:      mat_unit(mat);                                 /* Make it unit matrix. */
        !           106:      mat[0][0] = sx;
        !           107:      mat[1][1] = sy;
        !           108:      mat[2][2] = sz;
        !           109: }
        !           110:
        !           111: void mat_rot_x(teta, mat)
        !           112: double teta;
        !           113: transform_matrix mat;
        !           114: {
        !           115:     double cos_teta, sin_teta;
        !           116:
        !           117:     teta *= Pi / 180.0;
        !           118:     cos_teta = cos(teta);
        !           119:     sin_teta = sin(teta);
        !           120:
        !           121:     mat_unit(mat);                                  /* Make it unit matrix. */
        !           122:     mat[1][1] = cos_teta;
        !           123:     mat[1][2] = -sin_teta;
        !           124:     mat[2][1] = sin_teta;
        !           125:     mat[2][2] = cos_teta;
        !           126: }
        !           127:
        !           128: void mat_rot_y(teta, mat)
        !           129: double teta;
        !           130: transform_matrix mat;
        !           131: {
        !           132:     double cos_teta, sin_teta;
        !           133:
        !           134:     teta *= Pi / 180.0;
        !           135:     cos_teta = cos(teta);
        !           136:     sin_teta = sin(teta);
        !           137:
        !           138:     mat_unit(mat);                                  /* Make it unit matrix. */
        !           139:     mat[0][0] = cos_teta;
        !           140:     mat[0][2] = -sin_teta;
        !           141:     mat[2][0] = sin_teta;
        !           142:     mat[2][2] = cos_teta;
        !           143: }
        !           144:
        !           145: void mat_rot_z(teta, mat)
        !           146: double teta;
        !           147: transform_matrix mat;
        !           148: {
        !           149:     double cos_teta, sin_teta;
        !           150:
        !           151:     teta *= Pi / 180.0;
        !           152:     cos_teta = cos(teta);
        !           153:     sin_teta = sin(teta);
        !           154:
        !           155:     mat_unit(mat);                                  /* Make it unit matrix. */
        !           156:     mat[0][0] = cos_teta;
        !           157:     mat[0][1] = -sin_teta;
        !           158:     mat[1][0] = sin_teta;
        !           159:     mat[1][1] = cos_teta;
        !           160: }
        !           161:
        !           162: /* Multiply two transform_matrix. Result can be one of two operands. */
        !           163: void mat_mult(mat_res, mat1, mat2)
        !           164: transform_matrix mat_res, mat1, mat2;
        !           165: {
        !           166:     int i, j, k;
        !           167:     transform_matrix mat_res_temp;
        !           168:
        !           169:     for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) {
        !           170:         mat_res_temp[i][j] = 0;
        !           171:         for (k = 0; k < 4; k++) mat_res_temp[i][j] += mat1[i][k] * mat2[k][j];
        !           172:     }
        !           173:     for (i = 0; i < 4; i++) for (j = 0; j < 4; j++)
        !           174:        mat_res[i][j] = mat_res_temp[i][j];
        !           175: }
        !           176:
        !           177:
        !           178: /* Test a single point to be within the xleft,xright,ybot,ytop bbox.
        !           179:  * Sets the returned integers 4 l.s.b. as follows:
        !           180:  * bit 0 if to the left of xleft.
        !           181:  * bit 1 if to the right of xright.
        !           182:  * bit 2 if above of ytop.
        !           183:  * bit 3 if below of ybot.
        !           184:  * 0 is returned if inside.
        !           185:  */
        !           186: int clip_point(x, y)
        !           187: unsigned int x, y;
        !           188: {
        !           189:     int ret_val = 0;
        !           190:
        !           191:     if (x < xleft) ret_val |= 0x01;
        !           192:     if (x > xright) ret_val |= 0x02;
        !           193:     if (y < ybot) ret_val |= 0x04;
        !           194:     if (y > ytop) ret_val |= 0x08;
        !           195:
        !           196:     return ret_val;
        !           197: }
        !           198:
        !           199: /* Clip the given line to drawing coords defined as xleft,xright,ybot,ytop.
        !           200:  *   This routine uses the cohen & sutherland bit mapping for fast clipping -
        !           201:  * see "Principles of Interactive Computer Graphics" Newman & Sproull page 65.
        !           202:  */
        !           203: void draw_clip_line(x1, y1, x2, y2)
        !           204: unsigned int x1, y1, x2, y2;
        !           205: {
        !           206:     int x, y, dx, dy, x_intr[4], y_intr[4], count, pos1, pos2;
        !           207:     register struct termentry *t = term;
        !           208:
        !           209: #if defined(ATARI) || defined(MTOS)
        !           210:     if(x1<0||x2<0||y1<0||y2<0) return; /* temp bug fix */
        !           211: #endif
        !           212:
        !           213:     pos1 = clip_point(x1, y1);
        !           214:     pos2 = clip_point(x2, y2);
        !           215:     if (pos1 || pos2) {
        !           216:        if (pos1 & pos2) return;                 /* segment is totally out. */
        !           217:
        !           218:        /* Here part of the segment MAY be inside. test the intersection
        !           219:         * of this segment with the 4 boundaries for hopefully 2 intersections
        !           220:         * in. If none are found segment is totaly out.
        !           221:         * Under rare circumstances there may be up to 4 intersections (e.g.
        !           222:         * when the line passes directly through at least one corner). In
        !           223:         * this case it is sufficient to take any 2 intersections (e.g. the
        !           224:         * first two found).
        !           225:         */
        !           226:        count = 0;
        !           227:        dx = x2 - x1;
        !           228:        dy = y2 - y1;
        !           229:
        !           230:        /* Find intersections with the x parallel bbox lines: */
        !           231:        if (dy != 0) {
        !           232:            x = (ybot - y2) * dx / dy + x2;      /* Test for ybot boundary. */
        !           233:            if (x >= xleft && x <= xright) {
        !           234:                x_intr[count] = x;
        !           235:                y_intr[count++] = ybot;
        !           236:            }
        !           237:            x = (ytop - y2) * dx / dy + x2;      /* Test for ytop boundary. */
        !           238:            if (x >= xleft && x <= xright) {
        !           239:                x_intr[count] = x;
        !           240:                y_intr[count++] = ytop;
        !           241:            }
        !           242:        }
        !           243:
        !           244:        /* Find intersections with the y parallel bbox lines: */
        !           245:        if (dx != 0) {
        !           246:            y = (xleft - x2) * dy / dx + y2;    /* Test for xleft boundary. */
        !           247:            if (y >= ybot && y <= ytop) {
        !           248:                x_intr[count] = xleft;
        !           249:                y_intr[count++] = y;
        !           250:            }
        !           251:            y = (xright - x2) * dy / dx + y2;  /* Test for xright boundary. */
        !           252:            if (y >= ybot && y <= ytop) {
        !           253:                x_intr[count] = xright;
        !           254:                y_intr[count++] = y;
        !           255:            }
        !           256:        }
        !           257:
        !           258:        if (count >= 2) {
        !           259:            int x_max, x_min, y_max, y_min;
        !           260:
        !           261:            x_min = GPMIN(x1, x2);
        !           262:            x_max = GPMAX(x1, x2);
        !           263:            y_min = GPMIN(y1, y2);
        !           264:            y_max = GPMAX(y1, y2);
        !           265:
        !           266:            if (pos1 && pos2) {              /* Both were out - update both */
        !           267:                x1 = x_intr[0];
        !           268:                y1 = y_intr[0];
        !           269:                x2 = x_intr[1];
        !           270:                y2 = y_intr[1];
        !           271:            }
        !           272:            else if (pos1) {         /* Only x1/y1 was out - update only it */
        !           273:                if (dx * (x2 - x_intr[0]) + dy * (y2 - y_intr[0]) > 0) {
        !           274:                    x1 = x_intr[0];
        !           275:                    y1 = y_intr[0];
        !           276:                }
        !           277:                else {
        !           278:                    x1 = x_intr[1];
        !           279:                    y1 = y_intr[1];
        !           280:                }
        !           281:            }
        !           282:            else {                   /* Only x2/y2 was out - update only it */
        !           283:                if (dx * (x_intr[0] - x1) + dy * (y_intr[0] - y1) > 0) {
        !           284:                    x2 = x_intr[0];
        !           285:                    y2 = y_intr[0];
        !           286:                }
        !           287:                else {
        !           288:                    x2 = x_intr[1];
        !           289:                    y2 = y_intr[1];
        !           290:                }
        !           291:            }
        !           292:
        !           293:            if (x1 < x_min || x1 > x_max ||
        !           294:                x2 < x_min || x2 > x_max ||
        !           295:                y1 < y_min || y1 > y_max ||
        !           296:                y2 < y_min || y2 > y_max) return;
        !           297:        }
        !           298:        else
        !           299:            return;
        !           300:     }
        !           301:
        !           302:
        !           303: #ifndef LITE
        !           304:     if(hidden3d && hidden_active && draw_surface)
        !           305:       {
        !           306:         draw_line_hidden(x1, y1, x2, y2);
        !           307:         return;
        !           308:       };
        !           309: #endif /* not LITE */
        !           310:     if(!suppressMove) (*t->move)(x1,y1);
        !           311:     (*t->vector)(x2,y2);
        !           312: }
        !           313:
        !           314:
        !           315:
        !           316: /* And text clipping routine. */
        !           317: void clip_put_text(x, y, str)
        !           318: unsigned int x,y;
        !           319: char *str;
        !           320: {
        !           321:     register struct termentry *t = term;
        !           322:
        !           323:     if (clip_point(x, y)) return;
        !           324:
        !           325:     (*t->put_text)(x,y,str);
        !           326: }
        !           327:
        !           328: /* seems sensible to put the justification in here too..? */
        !           329: void clip_put_text_just(x,y,str,just)
        !           330: unsigned int x,y;
        !           331: char *str;
        !           332: enum JUSTIFY just;
        !           333: {
        !           334:         register struct termentry *t = term;
        !           335:        if (clip_point(x,y)) return;
        !           336:        if (!(*t->justify_text)(just)) {
        !           337:                assert(CENTRE == 1 && RIGHT == 2);
        !           338:                x -= (t->h_char * strlen(str) * just)/2;
        !           339:        }
        !           340:        (*t->put_text)(x,y,str);
        !           341: }
        !           342:
        !           343:
        !           344:
        !           345: /* Clip the given line to drawing coords defined as xleft,xright,ybot,ytop.
        !           346:  *   This routine uses the cohen & sutherland bit mapping for fast clipping -
        !           347:  * see "Principles of Interactive Computer Graphics" Newman & Sproull page 65.
        !           348:  */
        !           349:
        !           350: int clip_line(x1, y1, x2, y2)
        !           351:      int *x1, *y1, *x2, *y2;
        !           352: {
        !           353:   int x, y, dx, dy, x_intr[4], y_intr[4], count, pos1, pos2;
        !           354:   int x_max, x_min, y_max, y_min;
        !           355:   pos1 = clip_point(*x1, *y1);
        !           356:   pos2 = clip_point(*x2, *y2);
        !           357:   if (!pos1 && !pos2) return 1; /* segment is totally in */
        !           358:   if (pos1 & pos2) return 0;   /* segment is totally out. */
        !           359:   /* Here part of the segment MAY be inside. test the intersection
        !           360:    * of this segment with the 4 boundaries for hopefully 2 intersections
        !           361:    * in. If non found segment is totaly out.
        !           362:    */
        !           363:   count = 0;
        !           364:   dx = *x2 - *x1;
        !           365:   dy = *y2 - *y1;
        !           366:   /* Find intersections with the x parallel bbox lines: */
        !           367:   if (dy != 0) {
        !           368:     x = (ybot - *y2) * dx / dy + *x2; /* Test for ybot boundary. */
        !           369:     if (x >= xleft && x <= xright) {
        !           370:       x_intr[count] = x;
        !           371:       y_intr[count++] = ybot;
        !           372:     }
        !           373:     x = (ytop - *y2) * dx / dy + *x2; /* Test for ytop boundary. */
        !           374:     if (x >= xleft && x <= xright) {
        !           375:       x_intr[count] = x;
        !           376:       y_intr[count++] = ytop;
        !           377:     }
        !           378:   }
        !           379:   /* Find intersections with the y parallel bbox lines: */
        !           380:   if (dx != 0) {
        !           381:     y = (xleft - *x2) * dy / dx + *y2; /* Test for xleft boundary. */
        !           382:     if (y >= ybot && y <= ytop) {
        !           383:       x_intr[count] = xleft;
        !           384:       y_intr[count++] = y;
        !           385:     }
        !           386:     y = (xright - *x2) * dy / dx + *y2; /* Test for xright boundary. */
        !           387:     if (y >= ybot && y <= ytop) {
        !           388:       x_intr[count] = xright;
        !           389:       y_intr[count++] = y;
        !           390:     }
        !           391:   }
        !           392:   if (count < 2) return 0;
        !           393:   if (*x1 < *x2)
        !           394:     x_min = *x1, x_max = *x2;
        !           395:   else
        !           396:     x_min = *x2, x_max = *x1;
        !           397:   if (*y1 < *y2)
        !           398:     y_min = *y1, y_max = *y2;
        !           399:   else
        !           400:     y_min = *y2, y_max = *y1;
        !           401:   if (pos1 && pos2) {          /* Both were out - update both */
        !           402:     *x1 = x_intr[0];
        !           403:     *y1 = y_intr[0];
        !           404:     *x2 = x_intr[1];
        !           405:     *y2 = y_intr[1];
        !           406:   }
        !           407:   else if (pos1)
        !           408:     {                          /* Only x1/y1 was out - update only it */
        !           409:       if (dx * (*x2 - x_intr[0]) + dy * (*y2 - y_intr[0]) >= 0)
        !           410:        {
        !           411:          *x1 = x_intr[0];
        !           412:          *y1 = y_intr[0];
        !           413:        }
        !           414:       else
        !           415:        {
        !           416:          *x1 = x_intr[1];
        !           417:          *y1 = y_intr[1];
        !           418:        }
        !           419:     }
        !           420:   else
        !           421:     {                          /* Only x2/y2 was out - update only it */
        !           422:       if (dx * (x_intr[0] - *x1) + dy * (y_intr[0] - *y1) >= 0)
        !           423:        {
        !           424:          *x2 = x_intr[0];
        !           425:          *y2 = y_intr[0];
        !           426:        }
        !           427:       else
        !           428:        {
        !           429:          *x2 = x_intr[1];
        !           430:          *y2 = y_intr[1];
        !           431:        }
        !           432:     }
        !           433:
        !           434:   if (*x1 < x_min || *x1 > x_max ||
        !           435:       *x2 < x_min || *x2 > x_max ||
        !           436:       *y1 < y_min || *y1 > y_max ||
        !           437:       *y2 < y_min || *y2 > y_max)
        !           438:     return 0;
        !           439:   return 1;
        !           440: }
        !           441:
        !           442:
        !           443: /* single edge intersection algorithm */
        !           444: /* Given two points, one inside and one outside the plot, return
        !           445:  * the point where an edge of the plot intersects the line segment defined
        !           446:  * by the two points.
        !           447:  */
        !           448: void edge3d_intersect(points, i, ex, ey, ez)
        !           449:        struct coordinate GPHUGE *points; /* the points array */
        !           450:        int i;                          /* line segment from point i-1 to point i */
        !           451:        double *ex, *ey, *ez;           /* the point where it crosses an edge */
        !           452: {
        !           453:     /* global x_min3d, x_max3d, y_min3d, y_max3d, min3d_z, max3d_z */
        !           454:     int count;
        !           455:     double ix = points[i-1].x;
        !           456:     double iy = points[i-1].y;
        !           457:     double iz = points[i-1].z;
        !           458:     double ox = points[i].x;
        !           459:     double oy = points[i].y;
        !           460:     double oz = points[i].z;
        !           461:     double x, y, z;                    /* possible intersection point */
        !           462:
        !           463:     if(points[i].type == INRANGE)
        !           464:       {
        !           465:        /* swap points around so that ix/ix/iz are INRANGE and ox/oy/oz are OUTRANGE */
        !           466:        x = ix;ix = ox;ox = x;
        !           467:        y = iy;iy = oy;oy = y;
        !           468:        z = iz;iz = oz;oz = z;
        !           469:       }
        !           470:
        !           471:     /* nasty degenerate cases, effectively drawing to an infinity point (?)
        !           472:        cope with them here, so don't process them as a "real" OUTRANGE point
        !           473:
        !           474:        If more than one coord is -VERYLARGE, then can't ratio the "infinities"
        !           475:        so drop out by returning the INRANGE point.
        !           476:
        !           477:        Obviously, only need to test the OUTRANGE point (coordinates) */
        !           478:
        !           479:     /* nasty degenerate cases, effectively drawing to an infinity point (?)
        !           480:        cope with them here, so don't process them as a "real" OUTRANGE point
        !           481:
        !           482:        If more than one coord is -VERYLARGE, then can't ratio the "infinities"
        !           483:        so drop out by returning FALSE */
        !           484:
        !           485:     count = 0;
        !           486:     if(ox == -VERYLARGE) count++;
        !           487:     if(oy == -VERYLARGE) count++;
        !           488:     if(oz == -VERYLARGE) count++;
        !           489:
        !           490:     /* either doesn't pass through 3D volume *or*
        !           491:        can't ratio infinities to get a direction to draw line, so return the INRANGE point */
        !           492:     if(count > 1){
        !           493:       *ex = ix;
        !           494:       *ey = iy;
        !           495:       *ez = iz;
        !           496:
        !           497:       return;
        !           498:     }
        !           499:
        !           500:     if(count == 1)
        !           501:       {
        !           502:        *ex = ix;
        !           503:        *ey = iy;
        !           504:        *ez = iz;
        !           505:
        !           506:        if(ox == -VERYLARGE)
        !           507:          {
        !           508:            *ex = x_min3d;
        !           509:            return;
        !           510:          }
        !           511:
        !           512:        if(oy == -VERYLARGE)
        !           513:          {
        !           514:            *ey = y_min3d;
        !           515:            return;
        !           516:          }
        !           517:
        !           518:        /* obviously oz is -VERYLARGE and (ox != -VERYLARGE && oy != -VERYLARGE) */
        !           519:        *ez = min3d_z;
        !           520:        return;
        !           521:       }
        !           522:
        !           523:     /*
        !           524:      * Can't have case (ix == ox && iy == oy && iz == oz) as one point
        !           525:      * is INRANGE and one point is OUTRANGE.
        !           526:      */
        !           527:     if(ix == ox) {
        !           528:       if(iy == oy) {
        !           529:        /* line parallel to z axis */
        !           530:
        !           531:        /* assume inrange(iy, y_min3d, y_max3d) && inrange(ix, x_min3d, x_max3d) */
        !           532:        *ex = ix;               /* == ox */
        !           533:        *ey = iy;               /* == oy */
        !           534:
        !           535:        if (inrange(max3d_z, iz, oz))
        !           536:          *ez = max3d_z;
        !           537:        else if (inrange(min3d_z, iz, oz))
        !           538:          *ez = min3d_z;
        !           539:        else {
        !           540:          graph_error("error in edge3d_intersect");
        !           541:         }
        !           542:
        !           543:        return;
        !           544:       }
        !           545:
        !           546:       if(iz == oz) {
        !           547:        /* line parallel to y axis */
        !           548:
        !           549:        /* assume inrange(iz, min3d_z, max3d_z) && inrange(ix, x_min3d, x_max3d) */
        !           550:        *ex = ix;               /* == ox */
        !           551:        *ez = iz;               /* == oz */
        !           552:
        !           553:        if (inrange(y_max3d, iy, oy))
        !           554:          *ey = y_max3d;
        !           555:        else if (inrange(y_min3d, iy, oy))
        !           556:          *ey = y_min3d;
        !           557:        else {
        !           558:          graph_error("error in edge3d_intersect");
        !           559:        }
        !           560:
        !           561:        return;
        !           562:       }
        !           563:
        !           564:       /* nasty 2D slanted line in a yz plane */
        !           565:
        !           566:       /* does it intersect y_min3d edge */
        !           567:       if (inrange(y_min3d, iy, oy) && y_min3d != iy && y_min3d != oy) {
        !           568:        z = iz + (y_min3d-iy) * ((oz-iz) / (oy-iy));
        !           569:        if (inrange(z, min3d_z, max3d_z)) {
        !           570:          *ex = ix;
        !           571:          *ey = y_min3d;
        !           572:          *ez = z;
        !           573:          return;
        !           574:        }
        !           575:       }
        !           576:
        !           577:       /* does it intersect y_max3d edge */
        !           578:       if (inrange(y_max3d, iy, oy) && y_max3d != iy && y_max3d != oy) {
        !           579:        z = iz + (y_max3d-iy) * ((oz-iz) / (oy-iy));
        !           580:        if (inrange(z, min3d_z, max3d_z)) {
        !           581:          *ex = ix;
        !           582:          *ey = y_max3d;
        !           583:          *ez = z;
        !           584:          return;
        !           585:        }
        !           586:       }
        !           587:
        !           588:       /* does it intersect min3d_z edge */
        !           589:       if (inrange(min3d_z, iz, oz) && min3d_z != iz && min3d_z != oz) {
        !           590:        y = iy + (min3d_z-iz) * ((oy-iy) / (oz-iz));
        !           591:        if (inrange(y, y_min3d, y_max3d)) {
        !           592:          *ex = ix;
        !           593:          *ey = y;
        !           594:          *ez = min3d_z;
        !           595:          return;
        !           596:        }
        !           597:       }
        !           598:
        !           599:       /* does it intersect max3d_z edge */
        !           600:       if (inrange(max3d_z, iz, oz) && max3d_z != iz && max3d_z != oz) {
        !           601:        y = iy + (max3d_z-iz) * ((oy-iy) / (oz-iz));
        !           602:        if (inrange(y, y_min3d, y_max3d)) {
        !           603:          *ex = ix;
        !           604:          *ey = y;
        !           605:          *ez = max3d_z;
        !           606:          return;
        !           607:        }
        !           608:       }
        !           609:     }
        !           610:
        !           611:     if(iy == oy) {
        !           612:       /* already checked case (ix == ox && iy == oy) */
        !           613:       if(oz ==  iz) {
        !           614:          /* line parallel to x axis */
        !           615:
        !           616:          /* assume inrange(iz, min3d_z, max3d_z) && inrange(iy, y_min3d, y_max3d) */
        !           617:          *ey = iy;             /* == oy */
        !           618:          *ez = iz;             /* == oz */
        !           619:
        !           620:          if (inrange(x_max3d, ix, ox))
        !           621:            *ex = x_max3d;
        !           622:          else if (inrange(x_min3d, ix, ox))
        !           623:            *ex = x_min3d;
        !           624:          else {
        !           625:            graph_error("error in edge3d_intersect");
        !           626:          }
        !           627:
        !           628:          return;
        !           629:       }
        !           630:
        !           631:       /* nasty 2D slanted line in an xz plane */
        !           632:
        !           633:       /* does it intersect x_min3d edge */
        !           634:       if (inrange(x_min3d, ix, ox) && x_min3d != ix && x_min3d != ox) {
        !           635:        z = iz + (x_min3d-ix) * ((oz-iz) / (ox-ix));
        !           636:        if (inrange(z, min3d_z, max3d_z)) {
        !           637:          *ex = x_min3d;
        !           638:          *ey = iy;
        !           639:          *ez = z;
        !           640:          return;
        !           641:        }
        !           642:       }
        !           643:
        !           644:       /* does it intersect x_max3d edge */
        !           645:       if (inrange(x_max3d, ix, ox) && x_max3d != ix && x_max3d != ox) {
        !           646:        z = iz + (x_max3d-ix) * ((oz-iz) / (ox-ix));
        !           647:        if (inrange(z, min3d_z, max3d_z)) {
        !           648:          *ex = x_max3d;
        !           649:          *ey = iy;
        !           650:          *ez = z;
        !           651:          return;
        !           652:        }
        !           653:       }
        !           654:
        !           655:       /* does it intersect min3d_z edge */
        !           656:       if (inrange(min3d_z, iz, oz) && min3d_z != iz && min3d_z != oz) {
        !           657:        x = ix + (min3d_z-iz) * ((ox-ix) / (oz-iz));
        !           658:        if (inrange(x, x_min3d, x_max3d)) {
        !           659:          *ex = x;
        !           660:          *ey = iy;
        !           661:          *ez = min3d_z;
        !           662:          return;
        !           663:        }
        !           664:       }
        !           665:
        !           666:       /* does it intersect max3d_z edge */
        !           667:       if (inrange(max3d_z, iz, oz) && max3d_z != iz && max3d_z != oz) {
        !           668:        x = ix + (max3d_z-iz) * ((ox-ix) / (oz-iz));
        !           669:        if (inrange(x, x_min3d, x_max3d)) {
        !           670:          *ex = x;
        !           671:          *ey = iy;
        !           672:          *ez = max3d_z;
        !           673:          return;
        !           674:        }
        !           675:       }
        !           676:     }
        !           677:
        !           678:     if(iz == oz) {
        !           679:       /* already checked cases (ix == ox && iz == oz) and (iy == oy && iz == oz) */
        !           680:
        !           681:       /* nasty 2D slanted line in an xy plane */
        !           682:
        !           683:       /* assume inrange(oz, min3d_z, max3d_z) */
        !           684:
        !           685:       /* does it intersect x_min3d edge */
        !           686:       if (inrange(x_min3d, ix, ox) && x_min3d != ix && x_min3d != ox) {
        !           687:        y = iy + (x_min3d-ix) * ((oy-iy) / (ox-ix));
        !           688:        if (inrange(y, y_min3d, y_max3d)) {
        !           689:          *ex = x_min3d;
        !           690:          *ey = y;
        !           691:          *ez = iz;
        !           692:          return;
        !           693:        }
        !           694:       }
        !           695:
        !           696:       /* does it intersect x_max3d edge */
        !           697:       if (inrange(x_max3d, ix, ox) && x_max3d != ix && x_max3d != ox) {
        !           698:        y = iy + (x_max3d-ix) * ((oy-iy) / (ox-ix));
        !           699:        if (inrange(y, y_min3d, y_max3d)) {
        !           700:          *ex = x_max3d;
        !           701:          *ey = y;
        !           702:          *ez = iz;
        !           703:          return;
        !           704:        }
        !           705:       }
        !           706:
        !           707:       /* does it intersect y_min3d edge */
        !           708:       if (inrange(y_min3d, iy, oy) && y_min3d != iy && y_min3d != oy) {
        !           709:        x = ix + (y_min3d-iy) * ((ox-ix) / (oy-iy));
        !           710:        if (inrange(x, x_min3d, x_max3d)) {
        !           711:          *ex = x;
        !           712:          *ey = y_min3d;
        !           713:          *ez = iz;
        !           714:          return;
        !           715:        }
        !           716:       }
        !           717:
        !           718:       /* does it intersect y_max3d edge */
        !           719:       if (inrange(y_max3d, iy, oy) && y_max3d != iy && y_max3d != oy) {
        !           720:        x = ix + (y_max3d-iy) * ((ox-ix) / (oy-iy));
        !           721:        if (inrange(x, x_min3d, x_max3d)) {
        !           722:          *ex = x;
        !           723:          *ey = y_max3d;
        !           724:          *ez = iz;
        !           725:          return;
        !           726:        }
        !           727:       }
        !           728:     }
        !           729:
        !           730:     /* really nasty general slanted 3D case */
        !           731:
        !           732:     /* does it intersect x_min3d edge */
        !           733:     if (inrange(x_min3d, ix, ox) && x_min3d != ix && x_min3d != ox) {
        !           734:       y = iy + (x_min3d-ix) * ((oy-iy) / (ox-ix));
        !           735:       z = iz + (x_min3d-ix) * ((oz-iz) / (ox-ix));
        !           736:       if (inrange(y, y_min3d, y_max3d) && inrange(z, min3d_z, max3d_z)) {
        !           737:        *ex = x_min3d;
        !           738:        *ey = y;
        !           739:        *ez = z;
        !           740:        return;
        !           741:       }
        !           742:     }
        !           743:
        !           744:     /* does it intersect x_max3d edge */
        !           745:     if (inrange(x_max3d, ix, ox) && x_max3d != ix && x_max3d != ox) {
        !           746:       y = iy + (x_max3d-ix) * ((oy-iy) / (ox-ix));
        !           747:       z = iz + (x_max3d-ix) * ((oz-iz) / (ox-ix));
        !           748:       if (inrange(y, y_min3d, y_max3d) && inrange(z, min3d_z, max3d_z)) {
        !           749:        *ex = x_max3d;
        !           750:        *ey = y;
        !           751:        *ez = z;
        !           752:        return;
        !           753:       }
        !           754:     }
        !           755:
        !           756:     /* does it intersect y_min3d edge */
        !           757:     if (inrange(y_min3d, iy, oy) && y_min3d != iy && y_min3d != oy) {
        !           758:       x = ix + (y_min3d-iy) * ((ox-ix) / (oy-iy));
        !           759:       z = iz + (y_min3d-iy) * ((oz-iz) / (oy-iy));
        !           760:       if (inrange(x, x_min3d, x_max3d) && inrange(z, min3d_z, max3d_z)) {
        !           761:        *ex = x;
        !           762:        *ey = y_min3d;
        !           763:        *ez = z;
        !           764:        return;
        !           765:       }
        !           766:     }
        !           767:
        !           768:     /* does it intersect y_max3d edge */
        !           769:     if (inrange(y_max3d, iy, oy) && y_max3d != iy && y_max3d != oy) {
        !           770:       x = ix + (y_max3d-iy) * ((ox-ix) / (oy-iy));
        !           771:       z = iz + (y_max3d-iy) * ((oz-iz) / (oy-iy));
        !           772:       if (inrange(x, x_min3d, x_max3d) && inrange(z, min3d_z, max3d_z)) {
        !           773:        *ex = x;
        !           774:        *ey = y_max3d;
        !           775:        *ez = z;
        !           776:        return;
        !           777:       }
        !           778:     }
        !           779:
        !           780:     /* does it intersect min3d_z edge */
        !           781:     if (inrange(min3d_z, iz, oz) && min3d_z != iz && min3d_z != oz) {
        !           782:       x = ix + (min3d_z-iz) * ((ox-ix) / (oz-iz));
        !           783:       y = iy + (min3d_z-iz) * ((oy-iy) / (oz-iz));
        !           784:       if (inrange(x, x_min3d, x_max3d) && inrange(y, y_min3d, y_max3d)) {
        !           785:        *ex = x;
        !           786:        *ey = y;
        !           787:        *ez = min3d_z;
        !           788:        return;
        !           789:       }
        !           790:     }
        !           791:
        !           792:     /* does it intersect max3d_z edge */
        !           793:     if (inrange(max3d_z, iz, oz) && max3d_z != iz && max3d_z != oz) {
        !           794:       x = ix + (max3d_z-iz) * ((ox-ix) / (oz-iz));
        !           795:       y = iy + (max3d_z-iz) * ((oy-iy) / (oz-iz));
        !           796:       if (inrange(x, x_min3d, x_max3d) && inrange(y, y_min3d, y_max3d)) {
        !           797:        *ex = x;
        !           798:        *ey = y;
        !           799:        *ez = max3d_z;
        !           800:        return;
        !           801:       }
        !           802:     }
        !           803:
        !           804:     /* If we reach here, the inrange point is on the edge, and
        !           805:      * the line segment from the outrange point does not cross any
        !           806:      * other edges to get there. In this case, we return the inrange
        !           807:      * point as the 'edge' intersection point. This will basically draw
        !           808:      * line.
        !           809:      */
        !           810:     *ex = ix;
        !           811:     *ey = iy;
        !           812:     *ez = iz;
        !           813:     return;
        !           814: }
        !           815:
        !           816: /* double edge intersection algorithm */
        !           817: /* Given two points, both outside the plot, return
        !           818:  * the points where an edge of the plot intersects the line segment defined
        !           819:  * by the two points. There may be zero, one, two, or an infinite number
        !           820:  * of intersection points. (One means an intersection at a corner, infinite
        !           821:  * means overlaying the edge itself). We return FALSE when there is nothing
        !           822:  * to draw (zero intersections), and TRUE when there is something to
        !           823:  * draw (the one-point case is a degenerate of the two-point case and we do
        !           824:  * not distinguish it - we draw it anyway).
        !           825:  */
        !           826: TBOOLEAN                                /* any intersection? */
        !           827: two_edge3d_intersect(points, i, lx, ly, lz)
        !           828:        struct coordinate GPHUGE *points; /* the points array */
        !           829:        int i;                          /* line segment from point i-1 to point i */
        !           830:        double *lx, *ly, *lz;           /* lx[2], ly[2], lz[2]: points where it crosses edges */
        !           831: {
        !           832:     int count;
        !           833:     /* global x_min3d, x_max3d, y_min3d, y_max3d, min3d_z, max3d_z */
        !           834:     double ix = points[i-1].x;
        !           835:     double iy = points[i-1].y;
        !           836:     double iz = points[i-1].z;
        !           837:     double ox = points[i].x;
        !           838:     double oy = points[i].y;
        !           839:     double oz = points[i].z;
        !           840:     double t[6];
        !           841:     double swap;
        !           842:     double x, y, z;                    /* possible intersection point */
        !           843:     double t_min, t_max;
        !           844:
        !           845:     /* nasty degenerate cases, effectively drawing to an infinity point (?)
        !           846:        cope with them here, so don't process them as a "real" OUTRANGE point
        !           847:
        !           848:        If more than one coord is -VERYLARGE, then can't ratio the "infinities"
        !           849:        so drop out by returning FALSE */
        !           850:
        !           851:     count = 0;
        !           852:     if(ix == -VERYLARGE) count++;
        !           853:     if(ox == -VERYLARGE) count++;
        !           854:     if(iy == -VERYLARGE) count++;
        !           855:     if(oy == -VERYLARGE) count++;
        !           856:     if(iz == -VERYLARGE) count++;
        !           857:     if(oz == -VERYLARGE) count++;
        !           858:
        !           859:     /* either doesn't pass through 3D volume *or*
        !           860:        can't ratio infinities to get a direction to draw line, so simply return(FALSE) */
        !           861:     if(count > 1){
        !           862:       return(FALSE);
        !           863:     }
        !           864:
        !           865:     if(ox == -VERYLARGE || ix == -VERYLARGE)
        !           866:       {
        !           867:        if(ix == -VERYLARGE)
        !           868:          {
        !           869:            /* swap points so ix/iy/iz don't have a -VERYLARGE component */
        !           870:            x = ix;ix = ox;ox = x;
        !           871:            y = iy;iy = oy;oy = y;
        !           872:            z = iz;iz = oz;oz = z;
        !           873:          }
        !           874:
        !           875:        /* check actually passes through the 3D graph volume */
        !           876:        if(ix > x_max3d && inrange(iy, y_min3d, y_max3d) && inrange(iz, min3d_z, max3d_z))
        !           877:          {
        !           878:            lx[0] = x_min3d;
        !           879:            ly[0] = iy;
        !           880:            lz[0] = iz;
        !           881:
        !           882:            lx[1] = x_max3d;
        !           883:            ly[1] = iy;
        !           884:            lz[1] = iz;
        !           885:
        !           886:            return(TRUE);
        !           887:          }
        !           888:        else {
        !           889:          return(FALSE);
        !           890:        }
        !           891:       }
        !           892:
        !           893:     if(oy == -VERYLARGE || iy == -VERYLARGE)
        !           894:       {
        !           895:        if(iy == -VERYLARGE)
        !           896:          {
        !           897:            /* swap points so ix/iy/iz don't have a -VERYLARGE component */
        !           898:            x = ix; ix = ox; ox = x;
        !           899:            y = iy; iy = oy; oy = y;
        !           900:            z = iz; iz = oz; oz = z;
        !           901:          }
        !           902:
        !           903:        /* check actually passes through the 3D graph volume */
        !           904:        if(iy > y_max3d && inrange(ix, x_min3d, x_max3d) && inrange(iz, min3d_z, max3d_z))
        !           905:          {
        !           906:            lx[0] = ix;
        !           907:            ly[0] = y_min3d;
        !           908:            lz[0] = iz;
        !           909:
        !           910:            lx[1] = ix;
        !           911:            ly[1] = y_max3d;
        !           912:            lz[1] = iz;
        !           913:
        !           914:            return(TRUE);
        !           915:          }
        !           916:        else {
        !           917:          return(FALSE);
        !           918:        }
        !           919:       }
        !           920:
        !           921:     if(oz == -VERYLARGE || iz == -VERYLARGE)
        !           922:       {
        !           923:        if(iz == -VERYLARGE)
        !           924:          {
        !           925:            /* swap points so ix/iy/iz don't have a -VERYLARGE component */
        !           926:            x = ix; ix = ox; ox = x;
        !           927:            y = iy; iy = oy; oy = y;
        !           928:            z = iz; iz = oz; oz = z;
        !           929:          }
        !           930:
        !           931:        /* check actually passes through the 3D graph volume */
        !           932:        if(iz > max3d_z && inrange(ix, x_min3d, x_max3d) && inrange(iy, y_min3d, y_max3d))
        !           933:          {
        !           934:            lx[0] = ix;
        !           935:            ly[0] = iy;
        !           936:            lz[0] = min3d_z;
        !           937:
        !           938:            lx[1] = ix;
        !           939:            ly[1] = iy;
        !           940:            lz[1] = max3d_z;
        !           941:
        !           942:            return(TRUE);
        !           943:          }
        !           944:        else {
        !           945:          return(FALSE);
        !           946:        }
        !           947:       }
        !           948:
        !           949:     /*
        !           950:      * Quick outcode tests on the 3d graph volume
        !           951:      */
        !           952:
        !           953:     /*
        !           954:      * test z coord first --- most surface OUTRANGE points generated between
        !           955:      * min3d_z and z_min3d (i.e. when ticslevel is non-zero)
        !           956:      */
        !           957:     if(GPMAX(iz,oz) < min3d_z || GPMIN(iz,oz) > max3d_z)
        !           958:       return(FALSE);
        !           959:
        !           960:     if(GPMAX(ix,ox) < x_min3d || GPMIN(ix,ox) > x_max3d)
        !           961:       return(FALSE);
        !           962:
        !           963:     if(GPMAX(iy,oy) < y_min3d || GPMIN(iy,oy) > y_max3d)
        !           964:       return(FALSE);
        !           965:
        !           966:     /*
        !           967:      * Special horizontal/vertical, etc. cases are checked and remaining
        !           968:      * slant lines are checked separately.
        !           969:      *
        !           970:      * The slant line intersections are solved using the parametric form
        !           971:      * of the equation for a line, since if we test x/y/z min/max planes explicitly
        !           972:      * then e.g. a  line passing through a corner point (x_min,y_min,z_min)
        !           973:      * actually intersects all 3 planes and hence further tests would be required
        !           974:      * to anticipate this and similar situations.
        !           975:      */
        !           976:
        !           977:     /*
        !           978:      * Can have case (ix == ox && iy == oy && iz == oz) as both points OUTRANGE
        !           979:      */
        !           980:     if(ix == ox && iy == oy && iz == oz)
        !           981:       {
        !           982:        /* but as only define single outrange point, can't intersect 3D graph volume */
        !           983:        return(FALSE);
        !           984:       }
        !           985:
        !           986:     if(ix == ox) {
        !           987:       if(iy == oy) {
        !           988:        /* line parallel to z axis */
        !           989:
        !           990:        /* x and y coords must be in range, and line must span both min3d_z and max3d_z */
        !           991:        /* note that spanning min3d_z implies spanning max3d_z as both points OUTRANGE */
        !           992:        if(!inrange(ix, x_min3d, x_max3d) || !inrange(iy, y_min3d, y_max3d))
        !           993:          {
        !           994:            return(FALSE);
        !           995:          }
        !           996:
        !           997:        if (inrange(min3d_z, iz, oz)) {
        !           998:          lx[0] = ix;
        !           999:          ly[0] = iy;
        !          1000:          lz[0] = min3d_z;
        !          1001:
        !          1002:          lx[1] = ix;
        !          1003:          ly[1] = iy;
        !          1004:          lz[1] = max3d_z;
        !          1005:
        !          1006:          return(TRUE);
        !          1007:        } else
        !          1008:          return(FALSE);
        !          1009:       }
        !          1010:
        !          1011:       if(iz == oz) {
        !          1012:        /* line parallel to y axis */
        !          1013:
        !          1014:        /* x and z coords must be in range, and line must span both y_min3d and y_max3d */
        !          1015:        /* note that spanning y_min3d implies spanning y_max3d, as both points OUTRANGE */
        !          1016:        if(!inrange(ix, x_min3d, x_max3d) || !inrange(iz, min3d_z, max3d_z))
        !          1017:          {
        !          1018:            return(FALSE);
        !          1019:          }
        !          1020:
        !          1021:        if (inrange(y_min3d, iy, oy)) {
        !          1022:          lx[0] = ix;
        !          1023:          ly[0] = y_min3d;
        !          1024:          lz[0] = iz;
        !          1025:
        !          1026:          lx[1] = ix;
        !          1027:          ly[1] = y_max3d;
        !          1028:          lz[1] = iz;
        !          1029:
        !          1030:          return(TRUE);
        !          1031:        } else
        !          1032:          return(FALSE);
        !          1033:       }
        !          1034:
        !          1035:       /* nasty 2D slanted line in a yz plane */
        !          1036:
        !          1037:       if(!inrange(ox, x_min3d, x_max3d))
        !          1038:        return(FALSE);
        !          1039:
        !          1040:       t[0] = (y_min3d - iy)/(oy - iy);
        !          1041:       t[1] = (y_max3d - iy)/(oy - iy);
        !          1042:
        !          1043:       if(t[0] > t[1]) {
        !          1044:        swap = t[0];t[0] = t[1];t[1] = swap;
        !          1045:       }
        !          1046:
        !          1047:       t[2] = (min3d_z - iz)/(oz - iz);
        !          1048:       t[3] = (max3d_z - iz)/(oz - iz);
        !          1049:
        !          1050:       if(t[2] > t[3]) {
        !          1051:        swap = t[2];t[2] = t[3];t[3] = swap;
        !          1052:       }
        !          1053:
        !          1054:       t_min = GPMAX(GPMAX(t[0],t[2]),0.0);
        !          1055:       t_max = GPMIN(GPMIN(t[1],t[3]),1.0);
        !          1056:
        !          1057:       if(t_min > t_max)
        !          1058:        return(FALSE);
        !          1059:
        !          1060:       lx[0] = ix;
        !          1061:       ly[0] = iy + t_min * (oy - iy);
        !          1062:       lz[0] = iz + t_min * (oz - iz);
        !          1063:
        !          1064:       lx[1] = ix;
        !          1065:       ly[1] = iy + t_max * (oy - iy);
        !          1066:       lz[1] = iz + t_max * (oz - iz);
        !          1067:
        !          1068:       /*
        !          1069:        * Can only have 0 or 2 intersection points -- only need test one coord
        !          1070:        */
        !          1071:       if(inrange(ly[0], y_min3d, y_max3d) &&
        !          1072:         inrange(lz[0], min3d_z, max3d_z))
        !          1073:        {
        !          1074:          return(TRUE);
        !          1075:        }
        !          1076:
        !          1077:       return(FALSE);
        !          1078:     }
        !          1079:
        !          1080:     if(iy == oy) {
        !          1081:       /* already checked case (ix == ox && iy == oy) */
        !          1082:       if(oz ==  iz) {
        !          1083:        /* line parallel to x axis */
        !          1084:
        !          1085:        /* y and z coords must be in range, and line must span both x_min3d and x_max3d */
        !          1086:        /* note that spanning x_min3d implies spanning x_max3d, as both points OUTRANGE */
        !          1087:        if(!inrange(iy, y_min3d, y_max3d) || !inrange(iz, min3d_z, max3d_z))
        !          1088:          {
        !          1089:            return(FALSE);
        !          1090:          }
        !          1091:
        !          1092:        if (inrange(x_min3d, ix, ox)) {
        !          1093:          lx[0] = x_min3d;
        !          1094:          ly[0] = iy;
        !          1095:          lz[0] = iz;
        !          1096:
        !          1097:          lx[1] = x_max3d;
        !          1098:          ly[1] = iy;
        !          1099:          lz[1] = iz;
        !          1100:
        !          1101:          return(TRUE);
        !          1102:        } else
        !          1103:          return(FALSE);
        !          1104:       }
        !          1105:
        !          1106:       /* nasty 2D slanted line in an xz plane */
        !          1107:
        !          1108:       if(!inrange(oy, y_min3d, y_max3d))
        !          1109:        return(FALSE);
        !          1110:
        !          1111:       t[0] = (x_min3d - ix)/(ox - ix);
        !          1112:       t[1] = (x_max3d - ix)/(ox - ix);
        !          1113:
        !          1114:       if(t[0] > t[1]) {
        !          1115:        swap = t[0];t[0] = t[1];t[1] = swap;
        !          1116:       }
        !          1117:
        !          1118:       t[2] = (min3d_z - iz)/(oz - iz);
        !          1119:       t[3] = (max3d_z - iz)/(oz - iz);
        !          1120:
        !          1121:       if(t[2] > t[3]) {
        !          1122:        swap = t[2];t[2] = t[3];t[3] = swap;
        !          1123:       }
        !          1124:
        !          1125:       t_min = GPMAX(GPMAX(t[0],t[2]),0.0);
        !          1126:       t_max = GPMIN(GPMIN(t[1],t[3]),1.0);
        !          1127:
        !          1128:       if(t_min > t_max)
        !          1129:        return(FALSE);
        !          1130:
        !          1131:       lx[0] = ix + t_min * (ox - ix);
        !          1132:       ly[0] = iy;
        !          1133:       lz[0] = iz + t_min * (oz - iz);
        !          1134:
        !          1135:       lx[1] = ix + t_max * (ox - ix);
        !          1136:       ly[1] = iy;
        !          1137:       lz[1] = iz + t_max * (oz - iz);
        !          1138:
        !          1139:       /*
        !          1140:        * Can only have 0 or 2 intersection points -- only need test one coord
        !          1141:        */
        !          1142:       if(inrange(lx[0], x_min3d, x_max3d) &&
        !          1143:         inrange(lz[0], min3d_z, max3d_z))
        !          1144:        {
        !          1145:          return(TRUE);
        !          1146:        }
        !          1147:
        !          1148:       return(FALSE);
        !          1149:     }
        !          1150:
        !          1151:     if(iz == oz) {
        !          1152:       /* already checked cases (ix == ox && iz == oz) and (iy == oy && iz == oz) */
        !          1153:
        !          1154:       /* nasty 2D slanted line in an xy plane */
        !          1155:
        !          1156:       if(!inrange(oz, min3d_z, max3d_z))
        !          1157:        return(FALSE);
        !          1158:
        !          1159:       t[0] = (x_min3d - ix)/(ox - ix);
        !          1160:       t[1] = (x_max3d - ix)/(ox - ix);
        !          1161:
        !          1162:       if(t[0] > t[1]) {
        !          1163:        swap = t[0];t[0] = t[1];t[1] = swap;
        !          1164:       }
        !          1165:
        !          1166:       t[2] = (y_min3d - iy)/(oy - iy);
        !          1167:       t[3] = (y_max3d - iy)/(oy - iy);
        !          1168:
        !          1169:       if(t[2] > t[3]) {
        !          1170:        swap = t[2];t[2] = t[3];t[3] = swap;
        !          1171:       }
        !          1172:
        !          1173:       t_min = GPMAX(GPMAX(t[0],t[2]),0.0);
        !          1174:       t_max = GPMIN(GPMIN(t[1],t[3]),1.0);
        !          1175:
        !          1176:       if(t_min > t_max)
        !          1177:        return(FALSE);
        !          1178:
        !          1179:       lx[0] = ix + t_min * (ox - ix);
        !          1180:       ly[0] = iy + t_min * (oy - iy);
        !          1181:       lz[0] = iz;
        !          1182:
        !          1183:       lx[1] = ix + t_max * (ox - ix);
        !          1184:       ly[1] = iy + t_max * (oy - iy);
        !          1185:       lz[1] = iz;
        !          1186:
        !          1187:       /*
        !          1188:        * Can only have 0 or 2 intersection points -- only need test one coord
        !          1189:        */
        !          1190:       if(inrange(lx[0], x_min3d, x_max3d) &&
        !          1191:         inrange(ly[0], y_min3d, y_max3d))
        !          1192:        {
        !          1193:          return(TRUE);
        !          1194:        }
        !          1195:
        !          1196:       return(FALSE);
        !          1197:     }
        !          1198:
        !          1199:     /* really nasty general slanted 3D case */
        !          1200:
        !          1201:     /*
        !          1202:       Solve parametric equation
        !          1203:
        !          1204:       (ix, iy, iz) + t (diff_x, diff_y, diff_z)
        !          1205:
        !          1206:       where 0.0 <= t <= 1.0 and
        !          1207:
        !          1208:       diff_x = (ox - ix);
        !          1209:       diff_y = (oy - iy);
        !          1210:       diff_z = (oz - iz);
        !          1211:      */
        !          1212:
        !          1213:     t[0] = (x_min3d - ix)/(ox - ix);
        !          1214:     t[1] = (x_max3d - ix)/(ox - ix);
        !          1215:
        !          1216:     if(t[0] > t[1]) {
        !          1217:       swap = t[0];t[0] = t[1];t[1] = swap;
        !          1218:     }
        !          1219:
        !          1220:     t[2] = (y_min3d - iy)/(oy - iy);
        !          1221:     t[3] = (y_max3d - iy)/(oy - iy);
        !          1222:
        !          1223:     if(t[2] > t[3]) {
        !          1224:       swap = t[2];t[2] = t[3];t[3] = swap;
        !          1225:     }
        !          1226:
        !          1227:     t[4] = (iz == oz) ? 0.0 : (min3d_z - iz)/(oz - iz);
        !          1228:     t[5] = (iz == oz) ? 1.0 : (max3d_z - iz)/(oz - iz);
        !          1229:
        !          1230:     if(t[4] > t[5]) {
        !          1231:       swap = t[4];t[4] = t[5];t[5] = swap;
        !          1232:     }
        !          1233:
        !          1234:     t_min = GPMAX(GPMAX(t[0],t[2]),GPMAX(t[4],0.0));
        !          1235:     t_max = GPMIN(GPMIN(t[1],t[3]),GPMIN(t[5],1.0));
        !          1236:
        !          1237:     if(t_min > t_max)
        !          1238:       return(FALSE);
        !          1239:
        !          1240:     lx[0] = ix + t_min * (ox - ix);
        !          1241:     ly[0] = iy + t_min * (oy - iy);
        !          1242:     lz[0] = iz + t_min * (oz - iz);
        !          1243:
        !          1244:     lx[1] = ix + t_max * (ox - ix);
        !          1245:     ly[1] = iy + t_max * (oy - iy);
        !          1246:     lz[1] = iz + t_max * (oz - iz);
        !          1247:
        !          1248:     /*
        !          1249:      * Can only have 0 or 2 intersection points -- only need test one coord
        !          1250:      */
        !          1251:     if(inrange(lx[0], x_min3d, x_max3d) &&
        !          1252:        inrange(ly[0], y_min3d, y_max3d) &&
        !          1253:        inrange(lz[0], min3d_z, max3d_z))
        !          1254:       {
        !          1255:        return(TRUE);
        !          1256:       }
        !          1257:
        !          1258:     return(FALSE);
        !          1259:   }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>