intersect.h
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:14k
源码类别:

GIS编程

开发平台:

Visual C++

  1. /*
  2.  * FUNCTION:
  3.  * This file contains a number of utilities useful to 3D graphics in
  4.  * general, and to the generation of tubing and extrusions in particular
  5.  * 
  6.  * HISTORY:
  7.  * Written by Linas Vepstas, August 1991
  8.  * Updated to correctly handle degenerate cases, Linas,  February 1993 
  9.  */
  10. #include <math.h>
  11. #include "port.h"
  12. #include "vvector.h"
  13. #define BACKWARDS_INTERSECT (2)
  14. /* ========================================================== */
  15. /*
  16.  * the Degenerate_Tolerance token represents the greatest amount by
  17.  * which different scales in a graphics environment can differ before
  18.  * they should be considered "degenerate".   That is, when one vector is
  19.  * a million times longer than another, changces are that the second will
  20.  * be less than a pixel long, and therefore was probably meant to be
  21.  * degenerate (by the CAD package, etc.)  But what should this tolerance
  22.  * be?  At least 1 in onethousand (since screen sizes are 1K pixels), but
  23.  * les than 1 in 4 million (since this is the limit of single-precision
  24.  * floating point accuracy).  Of course, if double precision were used,
  25.  * then the tolerance could be increased.
  26.  * 
  27.  * Potentially, this naive assumption could cause problems if the CAD
  28.  * package attempts to zoom in on small details, and turns out, certain
  29.  * points should not hvae been degenerate.  The problem presented here
  30.  * is that the tolerance could run out before single-precision ran
  31.  * out, and so the CAD packages would perceive this as a "bug".
  32.  * One alternative is to fiddle around & try to tighten the tolerance.
  33.  * However, the right alternative is to code the graphics pipeline in
  34.  * double-precision (and tighten the tolerance).
  35.  *
  36.  * By the way, note that Degernate Tolerance is a "dimensionless"
  37.  * quantitiy -- it has no units -- it does not measure feet, inches,
  38.  * millimeters or pixels.  It is used only in the computations of ratios
  39.  * and relative lengths.
  40.  */
  41. /* 
  42.  * Right now, the tolerance is set to 2 parts in a million, which
  43.  * corresponds to a 19-bit distinction of mantissas. Note that
  44.  * single-precsion numbers have 24 bit mantissas.
  45.  */
  46. #define DEGENERATE_TOLERANCE   (0.000002)
  47. /* ========================================================== */
  48. /* 
  49.  * The macro and subroutine INTERSECT are designed to compute the
  50.  * intersection of a line (defined by the points v1 and v2) and a plane
  51.  * (defined as plane which is normal to the vector n, and contains the
  52.  * point p).  Both return the point sect, which is the point of
  53.  * interesection.
  54.  *
  55.  * This MACRO attemps to be fairly robust by checking for a divide by
  56.  * zero.
  57.  */
  58. /* ========================================================== */
  59. /*
  60.  * HACK ALERT
  61.  * The intersection parameter t has the nice property that if t>1,
  62.  * then the intersection is "in front of" p1, and if t<0, then the
  63.  * intersection is "behind" p2. Unfortunately, as the intersecting plane
  64.  * and the line become parallel, t wraps through infinity -- i.e. t can
  65.  * become so large that t becomes "greater than infinity" and comes back 
  66.  * as a negative number (i.e. winding number hopped by one unit).  We 
  67.  * have no way of detecting this situation without adding gazzillions 
  68.  * of lines of code of topological algebra to detect the winding number;
  69.  * and this would be incredibly difficult, and ruin performance.
  70.  * 
  71.  * Thus, we've installed a cheap hack for use by the "cut style" drawing
  72.  * routines. If t proves to be a large negative number (more negative
  73.  * than -5), then we assume that t was positive and wound through
  74.  * infinity.  This makes most cuts look good, without introducing bogus
  75.  * cuts at infinity.
  76.  */
  77. /* ========================================================== */
  78. #define INTERSECT(sect,p,n,v1,v2)
  79. {
  80.    gleDouble deno, numer, t, omt;
  81.    deno = (v1[0] - v2[0]) * n[0];
  82.    deno += (v1[1] - v2[1]) * n[1];
  83.    deno += (v1[2] - v2[2]) * n[2];
  84.    
  85.    if (deno == 0.0) {
  86.       VEC_COPY (n, v1);
  87.       /* printf ("Intersect: Warning: line is coplanar with plane n"); */ 
  88.    } else {
  89.       numer = (p[0] - v2[0]) * n[0];
  90.       numer += (p[1] - v2[1]) * n[1];
  91.       numer += (p[2] - v2[2]) * n[2];
  92.       t = numer / deno;
  93.       omt = 1.0 - t;
  94.       sect[0] = t * v1[0] + omt * v2[0];
  95.       sect[1] = t * v1[1] + omt * v2[1];
  96.       sect[2] = t * v1[2] + omt * v2[2];
  97.    }
  98. }
  99. /* ========================================================== */
  100. /* 
  101.  * The macro and subroutine BISECTING_PLANE compute a normal vector that
  102.  * describes the bisecting plane between three points (v1, v2 and v3).  
  103.  * This bisecting plane has the following properties:
  104.  * 1) it contains the point v2
  105.  * 2) the angle it makes with v21 == v2 - v1 is equal to the angle it 
  106.  *    makes with v32 == v3 - v2 
  107.  * 3) it is perpendicular to the plane defined by v1, v2, v3.
  108.  *
  109.  * Having input v1, v2, and v3, it returns a unit vector n.
  110.  *
  111.  * In some cases, the user may specify degenerate points, and still
  112.  * expect "reasonable" or "obvious" behaviour.  The "expected"
  113.  * behaviour for these degenerate cases is:
  114.  *
  115.  * 1) if v1 == v2 == v3, then return n=0
  116.  * 2) if v1 == v2, then return v32 (normalized).
  117.  * 3) if v2 == v3, then return v21 (normalized).
  118.  * 4) if v1, v2 and v3 co-linear, then return v21 (normalized).
  119.  *
  120.  * Mathematically, these special cases "make sense" -- we just have to
  121.  * code around potential divide-by-zero's in the code below.
  122.  */
  123. /* ========================================================== */
  124. #define BISECTING_PLANE(valid,n,v1,v2,v3)
  125. {
  126.    double v21[3], v32[3];
  127.    double len21, len32;
  128.    double dot;
  129.    VEC_DIFF (v21, v2, v1);
  130.    VEC_DIFF (v32, v3, v2);
  131.    VEC_LENGTH (len21, v21);
  132.    VEC_LENGTH (len32, v32);
  133.    if (len21 <= DEGENERATE_TOLERANCE * len32) {
  134.       if (len32 == 0.0) {
  135.          /* all three points lie ontop of one-another */
  136.          VEC_ZERO (n);
  137.          valid = FALSE;
  138.       } else {
  139.          /* return a normalized copy of v32 as bisector */
  140.          len32 = 1.0 / len32;
  141.          VEC_SCALE (n, len32, v32);
  142.          valid = TRUE;
  143.       }
  144.    } else {
  145.       valid = TRUE;
  146.       if (len32 <= DEGENERATE_TOLERANCE * len21) {
  147.          /* return a normalized copy of v21 as bisector */
  148.          len21 = 1.0 / len21;
  149.          VEC_SCALE (n, len21, v21);
  150.       } else {
  151.          /* normalize v21 to be of unit length */
  152.          len21 = 1.0 / len21;
  153.          VEC_SCALE (v21, len21, v21);
  154.          /* normalize v32 to be of unit length */
  155.          len32 = 1.0 / len32;
  156.          VEC_SCALE (v32, len32, v32);
  157.          VEC_DOT_PRODUCT (dot, v32, v21);
  158.          /* if dot == 1 or -1, then points are colinear */
  159.          if ((dot >= (1.0-DEGENERATE_TOLERANCE)) || 
  160.              (dot <= (-1.0+DEGENERATE_TOLERANCE))) {
  161.             VEC_COPY (n, v21);
  162.          } else {
  163.    
  164.             /* go do the full computation */ 
  165.             n[0] = dot * (v32[0] + v21[0]) - v32[0] - v21[0];
  166.             n[1] = dot * (v32[1] + v21[1]) - v32[1] - v21[1];
  167.             n[2] = dot * (v32[2] + v21[2]) - v32[2] - v21[2];
  168.             /* if above if-test's passed, 
  169.              * n should NEVER be of zero length */
  170.             VEC_NORMALIZE (n);
  171.          } 
  172.       } 
  173.    } 
  174. }
  175. /* ========================================================== */
  176. /*
  177.  * The block of code below is ifdef'd out, and is here for reference
  178.  * purposes only.  It performs the "mathematically right thing" for
  179.  * computing a bisecting plane, but is, unfortunately, subject ot noise
  180.  * in the presence of near degenerate points.  Since computer graphics,
  181.  * due to sloppy coding, laziness, or correctness, is filled with
  182.  * degenerate points, we can't really use this version.  The code above
  183.  * is far more appropriate for graphics.
  184.  */
  185. #ifdef MATHEMATICALLY_EXACT_GRAPHICALLY_A_KILLER
  186. #define BISECTING_PLANE(n,v1,v2,v3)
  187. {
  188.    double v21[3], v32[3];
  189.    double len21, len32;
  190.    double dot;
  191.    VEC_DIFF (v21, v2, v1);
  192.    VEC_DIFF (v32, v3, v2);
  193.    VEC_LENGTH (len21, v21);
  194.    VEC_LENGTH (len32, v32);
  195.    if (len21 == 0.0) {
  196.       if (len32 == 0.0) {
  197.          /* all three points lie ontop of one-another */
  198.          VEC_ZERO (n);
  199.          valid = FALSE;
  200.       } else {
  201.          /* return a normalized copy of v32 as bisector */
  202.          len32 = 1.0 / len32;
  203.          VEC_SCALE (n, len32, v32);
  204.       }
  205.    } else {
  206.       /* normalize v21 to be of unit length */
  207.       len21 = 1.0 / len21;
  208.       VEC_SCALE (v21, len21, v21);
  209.       if (len32 == 0.0) {
  210.          /* return a normalized copy of v21 as bisector */
  211.          VEC_COPY (n, v21);
  212.       } else {
  213.          /* normalize v32 to be of unit length */
  214.          len32 = 1.0 / len32;
  215.          VEC_SCALE (v32, len32, v32);
  216.          VEC_DOT_PRODUCT (dot, v32, v21);
  217.          /* if dot == 1 or -1, then points are colinear */
  218.          if ((dot == 1.0) || (dot == -1.0)) {
  219.             VEC_COPY (n, v21);
  220.          } else {
  221.    
  222.             /* go do the full computation */ 
  223.             n[0] = dot * (v32[0] + v21[0]) - v32[0] - v21[0];
  224.             n[1] = dot * (v32[1] + v21[1]) - v32[1] - v21[1];
  225.             n[2] = dot * (v32[2] + v21[2]) - v32[2] - v21[2];
  226.             /* if above if-test's passed, 
  227.              * n should NEVER be of zero length */
  228.             VEC_NORMALIZE (n);
  229.          } 
  230.       } 
  231.    } 
  232. }
  233. #endif
  234. /* ========================================================== */
  235. /*
  236.  * This macro computes the plane perpendicular to the the plane
  237.  * defined by three points, and whose normal vector is givven as the
  238.  * difference between the two vectors ...
  239.  * 
  240.  * (See way below for the "math" model if you want to understand this.
  241.  * The comments about relative errors above apply here.)
  242.  */
  243. #define CUTTING_PLANE(valid,n,v1,v2,v3)
  244. {
  245.    double v21[3], v32[3];
  246.    double len21, len32;
  247.    double lendiff;
  248.    VEC_DIFF (v21, v2, v1);
  249.    VEC_DIFF (v32, v3, v2);
  250.    VEC_LENGTH (len21, v21);
  251.    VEC_LENGTH (len32, v32);
  252.    if (len21 <= DEGENERATE_TOLERANCE * len32) {
  253.       if (len32 == 0.0) {
  254.          /* all three points lie ontop of one-another */
  255.          VEC_ZERO (n);
  256.          valid = FALSE;
  257.       } else {
  258.          /* return a normalized copy of v32 as cut-vector */
  259.          len32 = 1.0 / len32;
  260.          VEC_SCALE (n, len32, v32);
  261.          valid = TRUE;
  262.       }
  263.    } else {
  264.       valid = TRUE;
  265.       if (len32 <= DEGENERATE_TOLERANCE * len21) {
  266.          /* return a normalized copy of v21 as cut vector */
  267.          len21 = 1.0 / len21;
  268.          VEC_SCALE (n, len21, v21);
  269.       } else {
  270.          /* normalize v21 to be of unit length */
  271.          len21 = 1.0 / len21;
  272.          VEC_SCALE (v21, len21, v21);
  273.          /* normalize v32 to be of unit length */
  274.          len32 = 1.0 / len32;
  275.          VEC_SCALE (v32, len32, v32);
  276.          VEC_DIFF (n, v21, v32);
  277.          VEC_LENGTH (lendiff, n);
  278.          /* if the perp vector is very small, then the two 
  279.           * vectors are darn near collinear, and the cut 
  280.           * vector is probably poorly defined. */
  281.          if (lendiff < DEGENERATE_TOLERANCE) {
  282.             VEC_ZERO (n);
  283.             valid = FALSE;
  284.          } else {
  285.             lendiff = 1.0 / lendiff;
  286.             VEC_SCALE (n, lendiff, n);
  287.          } 
  288.       } 
  289.    } 
  290. }
  291. /* ========================================================== */
  292. #ifdef MATHEMATICALLY_EXACT_GRAPHICALLY_A_KILLER
  293. #define CUTTING_PLANE(n,v1,v2,v3)
  294. {
  295.    double v21[3], v32[3];
  296.    VEC_DIFF (v21, v2, v1);
  297.    VEC_DIFF (v32, v3, v2);
  298.    VEC_NORMALIZE (v21);
  299.    VEC_NORMALIZE (v32);
  300.    VEC_DIFF (n, v21, v32);
  301.    VEC_NORMALIZE (n);
  302. }
  303. #endif
  304. /* ============================================================ */
  305. /* This macro is used in several places to cycle through a series of
  306.  * points to find the next non-degenerate point in a series */
  307. #define FIND_NON_DEGENERATE_POINT(inext,npoints,len,diff,point_array)   
  308. {                                                                       
  309.    gleDouble slen;
  310.    gleDouble summa[3];
  311.    
  312.    do {                                                                 
  313.       /* get distance to next point */                                  
  314.       VEC_DIFF (diff, point_array[inext+1], point_array[inext]);        
  315.       VEC_LENGTH (len, diff);                                           
  316.       VEC_SUM (summa, point_array[inext+1], point_array[inext]);        
  317.       VEC_LENGTH (slen, summa);                                         
  318.       slen *= DEGENERATE_TOLERANCE;
  319.       inext ++;                                                         
  320.    } while ((len <= slen) && (inext < npoints-1));                      
  321. }
  322. /* ========================================================== */
  323. extern int bisecting_plane (gleDouble n[3],    /* returned */
  324.                       gleDouble v1[3],  /* input */
  325.                       gleDouble v2[3],  /* input */
  326.                       gleDouble v3[3]);  /* input */