zoukankan      html  css  js  c++  java
  • 根据空间三点或四点,求外接圆圆心和半径的方法


    Newsgroups:     comp.graphics,sci.image.processing,comp.graphics.algorithms
    From:           orourke@sophia.smith.edu (Joseph O'Rourke)
    Subject:        Re: Center of circle from 3 edge points
    Organization:   Smith College, Northampton, MA, US
    Date:           Sat, 18 Sep 1993 17:54:05 GMT
    

    It so happens I just prepared an answer to the posed question as
    part of a textbook exercise.
    
    Let a, b, and c be the three given points.  
    Use _0 and _1 as x and y coordinates.
    The coordinates of the center p=(p_0,p_1) of the circle through them is:
    
    	p_0 =
    	( b_1 a_0^2 
    	- c_1 a_0^2
    	- b_1^2 a_1
    	+ c_1^2 a_1
    	+ b_0^2 c_1
    	+ a_1^2 b_1
    	+ c_0^2 a_1
    	- c_1^2 b_1
    	- c_0^2 b_1 
    	- b_0^2 a_1
    	+ b_1^2 c_1
    	- a_1^2 c_1 )
    	 / D
    	
    	p_1 =
    	( a_0^2 c_0
    	+ a_1^2 c_0
    	+ b_0^2 a_0
    	- b_0^2 c_0
    	+ b_1^2 a_0
    	- b_1^2 c_0
    	- a_0^2 b_0
    	- a_1^2 b_0
    	- c_0^2 a_0
    	+ c_0^2 b_0
    	- c_1^2 a_0
    	+ c_1^2 b_0) 
    	 / D
    
    where
    
    D = 2( a_1 c_0 + b_1 a_0 - b_1 c_0 -a_1 b_0 -c_1 a_0 + c_1 b_0 ).
    
    The radius of the circle is then:
    
    r^2 = (a_0 - p_0)^2 + (a_1 - p_1)^2
    
    Degeneracies occur when D=0.
    

    From:           watson@madvax.uwa.oz.au (Dave Watson)
    Newsgroups:     comp.graphics,sci.image.processing,comp.graphics.algorithms
    Subject:        Re: Center of circle from 3 edge points (triangle circumcenter)
    Date:           20 Sep 1993 01:23:09 GMT
    Organization:   Maths Dept UWA
    

    In article <1993Sep18.175405.16512@sophia.smith.edu>, orourke@sophia.smith.edu
      (Joseph O'Rourke) writes:
    |> It so happens I just prepared an answer to the posed question as
    |> part of a textbook exercise.
    |> Let a, b, and c be the three given points.  
    |> Use _0 and _1 as x and y coordinates.
    |> The coordinates of the center p=(p_0,p_1) of the circle through them is:
    
    [Equations for p_0 and p_1 deleted]
     
    |> where
    |> 
    |> D = 2( a_1 c_0 + b_1 a_0 - b_1 c_0 -a_1 b_0 -c_1 a_0 + c_1 b_0 ).
    |> 
    |> The radius of the circle is then:
    |> 
    |> r^2 = (a_0 - p_0)^2 + (a_1 - p_1)^2
    |> 
    |> Degeneracies occur when D=0.
    
    More efficiently (20 multiply/divide operations versus 57) use
    
    p_0 = (((a_0 - c_0) * (a_0 + c_0) + (a_1 - c_1) * (a_1 + c_1)) / 2 * (b_1 - c_1) 
        -  ((b_0 - c_0) * (b_0 + c_0) + (b_1 - c_1) * (b_1 + c_1)) / 2 * (a_1 - c_1)) 
        / D
    
    p_1 = (((b_0 - c_0) * (b_0 + c_0) + (b_1 - c_1) * (b_1 + c_1)) / 2 * (a_0 - c_0)
        -  ((a_0 - c_0) * (a_0 + c_0) + (a_1 - c_1) * (a_1 + c_1)) / 2 * (b_0 - c_0))
        / D
    
    where D = (a_0 - c_0) * (b_1 - c_1) - (b_0 - c_0) * (a_1 - c_1)
    
    The _squared_ circumradius is then:
    
    r^2 = (c_0 - p_0)^2 + (c_1 - p_1)^2
    
    This approach uses Cramer's Rule to find the intersection of two
    perpendicular bisectors of triangle edges
    
    -- 
    Dave Watson                          Internet: watson@maths.uwa.edu.au
    Department of Mathematics                         Tel: (61 9) 380 3359
    The University of Western Australia               FAX: (61 9) 380 1028
    Nedlands, WA 6009  Australia.          Real data are full of surprises
    

    Date:           19 Jun 1997 09:45:45 -0400
    From:           William Flis <flis@indy.dynaeast.com>
    Subject:        Circumscribing simplices
    To:             "eppstein@ics.uci.edu" <eppstein@ics.uci.edu>
    

    Re: http://www.ics.uci.edu/~eppstein/junkyard/circumcircle.html
    
    Circumscribing the triangle or tet or any simplex, given the vertex
    coordinates, can easily be done algebraically with a little trick.  Expand
    
    (x - a)^2 + (y - b)^2 = R^2
    
    to
    
    x^2 - 2ax + a^2 + y^2 - 2by + b^2 = R^2
    
    Since this is non-linear in a, b, and R, it seems you can't easily use it to
    find them.  But let
    
    q = R^2 - a^2 - b^2                        [1]
    
    and re-arrange to yield
    
    (2x)a + (2y)b + q = x^2 + y^2              [2]
    
    which is now linear in a, b, and q.  Apply at 3 points and solve by Cramer's
    rule:
    
         |(x1^2 + y1^2) 2y1 1|
         |(x2^2 + y2^2) 2y2 1|   |(x2^2 + y2^2 - x1^2 - y1^2) (y2 - y1)|
         |(x3^2 + y3^2) 2y3 1|   |(x3^2 + y3^2 - x1^2 - y1^2) (y3 - y1)|
    a = ---------------------- = ---------------------------------------
            | 2x1  2y1  1 |           2 * | (x2 - x1)  (y2 - y1) |
            | 2x2  2y2  1 |               | (x3 - x1)  (y3 - y1) |
            | 2x3  2y3  1 |
    
    Similarly,
    
          |(x2 - x1) (x2^2 + y2^2 - x1^2 - y1^2)|
          |(y2 - y1) (x3^2 + y3^2 - x1^2 - y1^2)|
    b = -----------------------------------------
               (same denominator)
    
    This is equivalent to Watson's formula, which he derived geometrically.  (A
    side note: Watson could have saved 3 more multiplications in his formula by
    incorporating a factor of 2 into his denominator term D.)  It's then cheaper
    to find R by the original equation than by applying Cramer's rule a 3rd time,
    etc.
    
    This can also be written down by comparing Eq. [2] with the 'three-point
    form':
    
         | (x^2  + y^2)   x   y   1 |
         | (x1^2 + y1^2)  x1  y1  1 |  = 0
         | (x2^2 + y2^2)  x2  y2  1 |
         | (x3^2 + y3^2)  x3  y3  1 |
    
    For the sphere about a tet (after factoring out the 2's),
    
         |(x1^2 + y1^2 + z1^2)  y1  z1  1 |
         |(x2^2 + y2^2 + z2^2)  y2  z2  1 | 
         |(x3^2 + y3^2 + z3^2)  y3  z3  1 |
         |(x4^2 + y4^2 + z4^2)  y4  z4  1 |
    a = ------------------------------------
             2 *  | x1   y1   z1  1 |
                  | x2   y2   z2  1 |
                  | x3   y3   z3  1 |
                  | x4   y4   z4  1 |
    
    and so on.  (The determinants are easily reduced to 3X3 size.)
    
    This is not original with me, and I'm uncertain as to the source.  I found
    the result for triangles in a computer program that was written 15 years ago
    (which I've been using ever since) but only recently did I figure out how the
    formula is derived.
    
    P.S.: Your web pages are a valuable resource. Thank you for maintaining them
    and please keep up the good work!
    ------------------------------------------------------------
    William J. Flis, Director of Research, Dyna East Corporation
    3620 Horizon Drive, King of Prussia, PA 19406, U.S.A.
    (610)270-9900 Ext. 130   Fax: (610)270-9744
    http://www.dynaeast.com/~flis/FlisHome.html
    ------------------------------------------------------------
    

    From:           eppstein@ICS.UCI.EDU
    To:             flis@indy.dynaeast.com
    Subject:        Re: Circumscribing simplices
    Date:           Thu, 19 Jun 1997 09:56:25 -0700
    

    Yes, this linearization trick is pretty standard in computational geometry.
    The specific variation you use, mapping a vector v onto (v,|v|^2),
    turns circles or more generally spheres in d dimensions into planes
    or more generally hyperplanes in d+1 dimensions. Your equation
    
         | (x^2  + y^2)   x   y   1 |
         | (x1^2 + y1^2)  x1  y1  1 |  = 0
         | (x2^2 + y2^2)  x2  y2  1 |
         | (x3^2 + y3^2)  x3  y3  1 |
    
    is the standard equation for a plane through three points (xi,yi,xi^2+yi^2).
    
    One reference for general ideas like this (i.e. of turning nonlinear
    equations into higher-dimensional linear ones by adding extra variables
    that are polynomials in the original equations)
    is "A general approach to d-dimensional geometric queries",
    A. C. Yao and F. F. Yao, 17th ACM Symp. Theory of Computing (1985) 163-168.
    But probably the same idea was known long before then in
    less algorithmic contexts.
    
    I've added your message to my page (I assume this is ok; let me know if not).
    

    To:             compgeom-discuss@research.bell-labs.com
    Subject:        Re: circumsphere
    Date:           Wed, 1 Apr 98 0:34:28 EST
    From:           Jonathan R Shewchuk <jrs+@cs.cmu.edu>
    

    > I am searching for a numerically stable algorithm to calculate the radius r 
    > (and perhaps the center m) of the circumsphere of a tetrahedron in
    > three dimensions, given by the coordinates of the vertices a, b, c, d in R^3.
    
    Let a, b, c, d, and m be vectors in R^3.  Let ax, ay, and az be the components
    of a, and likewise for b, c, and d.  Let |a| denote the Euclidean norm of a,
    and let a x b denote the cross product of a and b.  Then
    
        |                                                                       |
        | |d-a|^2 [(b-a)x(c-a)] + |c-a|^2 [(d-a)x(b-a)] + |b-a|^2 [(c-a)x(d-a)] |
        |                                                                       |
    r = -------------------------------------------------------------------------,
                                  | bx-ax  by-ay  bz-az |
                                2 | cx-ax  cy-ay  cz-az |
                                  | dx-ax  dy-ay  dz-az |
    
    and
    
            |d-a|^2 [(b-a)x(c-a)] + |c-a|^2 [(d-a)x(b-a)] + |b-a|^2 [(c-a)x(d-a)]
    m = a + ---------------------------------------------------------------------.
                                    | bx-ax  by-ay  bz-az |
                                  2 | cx-ax  cy-ay  cz-az |
                                    | dx-ax  dy-ay  dz-az |
    
    Some notes on stability:
    
    - Note that the expression for r is purely a function of differences between
      coordinates.  The advantage is that the relative error incurred in the
      computation of r is also a function of the _differences_ between the
      vertices, and is not influenced by the _absolute_ coordinates of the
      vertices.  In most applications, vertices are usually nearer to each other
      than to the origin, so this property is advantageous.  If someone gives you
      a formula that doesn't have this property, be wary.
    
      Similarly, the formula for m incurs roundoff error proportional to the
      differences between vertices, but does not incur roundoff error proportional
      to the absolute coordinates of the vertices until the final addition.
    
    - These expressions are unstable in only one case:  if the denominator is
      close to zero.  This instability, which arises if the tetrahedron is nearly
      degenerate, is unavoidable.  Depending on your application, you may want
      to use exact arithmetic to compute the value of the determinant.
      Fortunately, this determinant is the basis of the well-studied 3D orientation
      test, and several fast algorithms for providing accurate approximations to
      the determinant are available.  Some resources are available from the
      "Numerical and algebraic computation" page of Nina Amenta's Directory of
      Computational Geometry Software:
    
      http://www.geom.umn.edu/software/cglist/alg.html
    
      If you're using floating-point inputs (as opposed to integers), one
      package that can estimate this determinant somewhat accurately is my own:
    
      http://www.cs.cmu.edu/~quake/robust.html
    
    - If you want to be even more aggressive about stability, you might reorder
      the vertices of the tetrahedron so that the vertex `a' (which is subtracted
      from the other vertices) is, roughly speaking, the vertex at the center of
      the minimum spanning tree of the tetrahedron's four vertices.  For more
      information about this idea, see Steven Fortune, "Numerical Stability of
      Algorithms for 2D Delaunay Triangulations," International Journal of
      Computational Geometry & Applications 5(1-2):193-213, March-June 1995.
    
    For completeness, here are stable expressions for the circumradius and
    circumcenter of a triangle, in R^2 and in R^3.  Incidentally, the expressions
    given here for R^2 are better behaved in terms of relative error than the
    suggestions currently given in the Geometry Junkyard
    (http://www.ics.uci.edu/~eppstein/junkyard/triangulation.html).
    
    Triangle in R^2:
    
         |b-a| |c-a| |b-c|            < Note: You only want to compute one sqrt, so
    r = ------------------,             use sqrt{ |b-a|^2 |c-a|^2 |b-c|^2 }
          | bx-ax  by-ay |
        2 | cx-ax  cy-ay |
    
              | by-ay  |b-a|^2 |
              | cy-ay  |c-a|^2 |
    mx = ax - ------------------,
                | bx-ax  by-ay |
              2 | cx-ax  cy-ay |
    
              | bx-ax  |b-a|^2 |
              | cx-ax  |c-a|^2 |
    my = ay + ------------------.
                | bx-ax  by-ay |
              2 | cx-ax  cy-ay |
    
    Triangle in R^3:
    
        |                                                           |
        | |c-a|^2 [(b-a)x(c-a)]x(b-a) + |b-a|^2 (c-a)x[(b-a)x(c-a)] |
        |                                                           |
    r = -------------------------------------------------------------,
                             2 | (b-a)x(c-a) |^2
    
            |c-a|^2 [(b-a)x(c-a)]x(b-a) + |b-a|^2 (c-a)x[(b-a)x(c-a)]
    m = a + ---------------------------------------------------------.
                               2 | (b-a)x(c-a) |^2
    
    Finally, here's some C code that computes the vector m-a (whose norm is r) in
    each of these three cases.  Notice the #ifdef statements, which allow you to
    choose whether or not to use my aforementioned package to approximate the
    determinant.  (No attempt is made here to reorder the vertices to improve
    stability.)
    
    /*****************************************************************************/
    /*                                                                           */
    /*  tetcircumcenter()   Find the circumcenter of a tetrahedron.              */
    /*                                                                           */
    /*  The result is returned both in terms of xyz coordinates and xi-eta-zeta  */
    /*  coordinates, relative to the tetrahedron's point `a' (that is, `a' is    */
    /*  the origin of both coordinate systems).  Hence, the xyz coordinates      */
    /*  returned are NOT absolute; one must add the coordinates of `a' to        */
    /*  find the absolute coordinates of the circumcircle.  However, this means  */
    /*  that the result is frequently more accurate than would be possible if    */
    /*  absolute coordinates were returned, due to limited floating-point        */
    /*  precision.  In general, the circumradius can be computed much more       */
    /*  accurately.                                                              */
    /*                                                                           */
    /*  The xi-eta-zeta coordinate system is defined in terms of the             */
    /*  tetrahedron.  Point `a' is the origin of the coordinate system.          */
    /*  The edge `ab' extends one unit along the xi axis.  The edge `ac'         */
    /*  extends one unit along the eta axis.  The edge `ad' extends one unit     */
    /*  along the zeta axis.  These coordinate values are useful for linear      */
    /*  interpolation.                                                           */
    /*                                                                           */
    /*  If `xi' is NULL on input, the xi-eta-zeta coordinates will not be        */
    /*  computed.                                                                */
    /*                                                                           */
    /*****************************************************************************/
    
    void tetcircumcenter(a, b, c, d, circumcenter, xi, eta, zeta)
    double a[3];
    double b[3];
    double c[3];
    double d[3];
    double circumcenter[3];
    double *xi;
    double *eta;
    double *zeta;
    {
      double xba, yba, zba, xca, yca, zca, xda, yda, zda;
      double balength, calength, dalength;
      double xcrosscd, ycrosscd, zcrosscd;
      double xcrossdb, ycrossdb, zcrossdb;
      double xcrossbc, ycrossbc, zcrossbc;
      double denominator;
      double xcirca, ycirca, zcirca;
    
      /* Use coordinates relative to point `a' of the tetrahedron. */
      xba = b[0] - a[0];
      yba = b[1] - a[1];
      zba = b[2] - a[2];
      xca = c[0] - a[0];
      yca = c[1] - a[1];
      zca = c[2] - a[2];
      xda = d[0] - a[0];
      yda = d[1] - a[1];
      zda = d[2] - a[2];
      /* Squares of lengths of the edges incident to `a'. */
      balength = xba * xba + yba * yba + zba * zba;
      calength = xca * xca + yca * yca + zca * zca;
      dalength = xda * xda + yda * yda + zda * zda;
      /* Cross products of these edges. */
      xcrosscd = yca * zda - yda * zca;
      ycrosscd = zca * xda - zda * xca;
      zcrosscd = xca * yda - xda * yca;
      xcrossdb = yda * zba - yba * zda;
      ycrossdb = zda * xba - zba * xda;
      zcrossdb = xda * yba - xba * yda;
      xcrossbc = yba * zca - yca * zba;
      ycrossbc = zba * xca - zca * xba;
      zcrossbc = xba * yca - xca * yba;
    
      /* Calculate the denominator of the formulae. */
    #ifdef EXACT
      /* Use orient3d() from http://www.cs.cmu.edu/~quake/robust.html     */
      /*   to ensure a correctly signed (and reasonably accurate) result, */
      /*   avoiding any possibility of division by zero.                  */
      denominator = 0.5 / orient3d(b, c, d, a);
    #else
      /* Take your chances with floating-point roundoff. */
      denominator = 0.5 / (xba * xcrosscd + yba * ycrosscd + zba * zcrosscd);
    #endif
    
      /* Calculate offset (from `a') of circumcenter. */
      xcirca = (balength * xcrosscd + calength * xcrossdb + dalength * xcrossbc) *
               denominator;
      ycirca = (balength * ycrosscd + calength * ycrossdb + dalength * ycrossbc) *
               denominator;
      zcirca = (balength * zcrosscd + calength * zcrossdb + dalength * zcrossbc) *
               denominator;
      circumcenter[0] = xcirca;
      circumcenter[1] = ycirca;
      circumcenter[2] = zcirca;
    
      if (xi != (double *) NULL) {
        /* To interpolate a linear function at the circumcenter, define a    */
        /*   coordinate system with a xi-axis directed from `a' to `b',      */
        /*   an eta-axis directed from `a' to `c', and a zeta-axis directed  */
        /*   from `a' to `d'.  The values for xi, eta, and zeta are computed */
        /*   by Cramer's Rule for solving systems of linear equations.       */
        *xi = (xcirca * xcrosscd + ycirca * ycrosscd + zcirca * zcrosscd) *
              (2.0 * denominator);
        *eta = (xcirca * xcrossdb + ycirca * ycrossdb + zcirca * zcrossdb) *
               (2.0 * denominator);
        *zeta = (xcirca * xcrossbc + ycirca * ycrossbc + zcirca * zcrossbc) *
                (2.0 * denominator);
      }
    }
    
    /*****************************************************************************/
    /*                                                                           */
    /*  tricircumcenter()   Find the circumcenter of a triangle.                 */
    /*                                                                           */
    /*  The result is returned both in terms of x-y coordinates and xi-eta       */
    /*  coordinates, relative to the triangle's point `a' (that is, `a' is       */
    /*  the origin of both coordinate systems).  Hence, the x-y coordinates      */
    /*  returned are NOT absolute; one must add the coordinates of `a' to        */
    /*  find the absolute coordinates of the circumcircle.  However, this means  */
    /*  that the result is frequently more accurate than would be possible if    */
    /*  absolute coordinates were returned, due to limited floating-point        */
    /*  precision.  In general, the circumradius can be computed much more       */
    /*  accurately.                                                              */
    /*                                                                           */
    /*  The xi-eta coordinate system is defined in terms of the triangle.        */
    /*  Point `a' is the origin of the coordinate system.  The edge `ab' extends */
    /*  one unit along the xi axis.  The edge `ac' extends one unit along the    */
    /*  eta axis.  These coordinate values are useful for linear interpolation.  */
    /*                                                                           */
    /*  If `xi' is NULL on input, the xi-eta coordinates will not be computed.   */
    /*                                                                           */
    /*****************************************************************************/
    
    void tricircumcenter(a, b, c, circumcenter, xi, eta)
    double a[2];
    double b[2];
    double c[2];
    double circumcenter[2];
    double *xi;
    double *eta;
    {
      double xba, yba, xca, yca;
      double balength, calength;
      double denominator;
      double xcirca, ycirca;
    
      /* Use coordinates relative to point `a' of the triangle. */
      xba = b[0] - a[0];
      yba = b[1] - a[1];
      xca = c[0] - a[0];
      yca = c[1] - a[1];
      /* Squares of lengths of the edges incident to `a'. */
      balength = xba * xba + yba * yba;
      calength = xca * xca + yca * yca;
    
      /* Calculate the denominator of the formulae. */
    #ifdef EXACT
      /* Use orient2d() from http://www.cs.cmu.edu/~quake/robust.html     */
      /*   to ensure a correctly signed (and reasonably accurate) result, */
      /*   avoiding any possibility of division by zero.                  */
      denominator = 0.5 / orient2d(b, c, a);
    #else
      /* Take your chances with floating-point roundoff. */
      denominator = 0.5 / (xba * yca - yba * xca);
    #endif
    
      /* Calculate offset (from `a') of circumcenter. */
      xcirca = (yca * balength - yba * calength) * denominator;  
      ycirca = (xba * calength - xca * balength) * denominator;  
      circumcenter[0] = xcirca;
      circumcenter[1] = ycirca;
    
      if (xi != (double *) NULL) {
        /* To interpolate a linear function at the circumcenter, define a     */
        /*   coordinate system with a xi-axis directed from `a' to `b' and    */
        /*   an eta-axis directed from `a' to `c'.  The values for xi and eta */
        /*   are computed by Cramer's Rule for solving systems of linear      */
        /*   equations.                                                       */
        *xi = (xcirca * yca - ycirca * xca) * (2.0 * denominator);
        *eta = (ycirca * xba - xcirca * yba) * (2.0 * denominator);
      }
    }
    
    /*****************************************************************************/
    /*                                                                           */
    /*  tricircumcenter3d()   Find the circumcenter of a triangle in 3D.         */
    /*                                                                           */
    /*  The result is returned both in terms of xyz coordinates and xi-eta       */
    /*  coordinates, relative to the triangle's point `a' (that is, `a' is       */
    /*  the origin of both coordinate systems).  Hence, the xyz coordinates      */
    /*  returned are NOT absolute; one must add the coordinates of `a' to        */
    /*  find the absolute coordinates of the circumcircle.  However, this means  */
    /*  that the result is frequently more accurate than would be possible if    */
    /*  absolute coordinates were returned, due to limited floating-point        */
    /*  precision.  In general, the circumradius can be computed much more       */
    /*  accurately.                                                              */
    /*                                                                           */
    /*  The xi-eta coordinate system is defined in terms of the triangle.        */
    /*  Point `a' is the origin of the coordinate system.  The edge `ab' extends */
    /*  one unit along the xi axis.  The edge `ac' extends one unit along the    */
    /*  eta axis.  These coordinate values are useful for linear interpolation.  */
    /*                                                                           */
    /*  If `xi' is NULL on input, the xi-eta coordinates will not be computed.   */
    /*                                                                           */
    /*****************************************************************************/
    
    void tricircumcenter3d(a, b, c, circumcenter, xi, eta)
    double a[3];
    double b[3];
    double c[3];
    double circumcenter[3];
    double *xi;
    double *eta;
    {
      double xba, yba, zba, xca, yca, zca;
      double balength, calength;
      double xcrossbc, ycrossbc, zcrossbc;
      double denominator;
      double xcirca, ycirca, zcirca;
    
      /* Use coordinates relative to point `a' of the triangle. */
      xba = b[0] - a[0];
      yba = b[1] - a[1];
      zba = b[2] - a[2];
      xca = c[0] - a[0];
      yca = c[1] - a[1];
      zca = c[2] - a[2];
      /* Squares of lengths of the edges incident to `a'. */
      balength = xba * xba + yba * yba + zba * zba;
      calength = xca * xca + yca * yca + zca * zca;
      
      /* Cross product of these edges. */
    #ifdef EXACT
      /* Use orient2d() from http://www.cs.cmu.edu/~quake/robust.html     */
      /*   to ensure a correctly signed (and reasonably accurate) result, */
      /*   avoiding any possibility of division by zero.                  */
      xcrossbc = orient2d(b[1], b[2], c[1], c[2], a[1], a[2]);
      ycrossbc = orient2d(b[2], b[0], c[2], c[0], a[2], a[0]);
      zcrossbc = orient2d(b[0], b[1], c[0], c[1], a[0], a[1]);
    #else
      /* Take your chances with floating-point roundoff. */
      xcrossbc = yba * zca - yca * zba;
      ycrossbc = zba * xca - zca * xba;
      zcrossbc = xba * yca - xca * yba;
    #endif
    
      /* Calculate the denominator of the formulae. */
      denominator = 0.5 / (xcrossbc * xcrossbc + ycrossbc * ycrossbc +
                           zcrossbc * zcrossbc);
    
      /* Calculate offset (from `a') of circumcenter. */
      xcirca = ((balength * yca - calength * yba) * zcrossbc -
                (balength * zca - calength * zba) * ycrossbc) * denominator;
      ycirca = ((balength * zca - calength * zba) * xcrossbc -
                (balength * xca - calength * xba) * zcrossbc) * denominator;
      zcirca = ((balength * xca - calength * xba) * ycrossbc -
                (balength * yca - calength * yba) * xcrossbc) * denominator;
      circumcenter[0] = xcirca;
      circumcenter[1] = ycirca;
      circumcenter[2] = zcirca;
    
      if (xi != (double *) NULL) {
        /* To interpolate a linear function at the circumcenter, define a     */
        /*   coordinate system with a xi-axis directed from `a' to `b' and    */
        /*   an eta-axis directed from `a' to `c'.  The values for xi and eta */
        /*   are computed by Cramer's Rule for solving systems of linear      */
        /*   equations.                                                       */
    
        /* There are three ways to do this calculation - using xcrossbc, */
        /*   ycrossbc, or zcrossbc.  Choose whichever has the largest    */
        /*   magnitude, to improve stability and avoid division by zero. */
        if (((xcrossbc >= ycrossbc) ^ (-xcrossbc > ycrossbc)) &&
            ((xcrossbc >= zcrossbc) ^ (-xcrossbc > zcrossbc))) {
          *xi = (ycirca * zca - zcirca * yca) / xcrossbc;
          *eta = (zcirca * yba - ycirca * zba) / xcrossbc;
        } else if ((ycrossbc >= zcrossbc) ^ (-ycrossbc > zcrossbc)) {
          *xi = (zcirca * xca - xcirca * zca) / ycrossbc;
          *eta = (xcirca * zba - zcirca * xba) / ycrossbc;
        } else {
          *xi = (xcirca * yca - ycirca * xca) / zcrossbc;
          *eta = (ycirca * xba - xcirca * yba) / zcrossbc;
        }
      }
    }
    
    -------------
    The compgeom mailing lists: see
    http://netlib.bell-labs.com/netlib/compgeom/readme.html
    or send mail to compgeom-request@research.bell-labs.com with the line:
    send readme
    

    Date:           Thu, 02 Apr 1998 08:44:46 -0500
    From:           William Flis <flis@indy.dynaeast.com>
    Reply-To:       flis@indy.dynaeast.com
    Organization:   Dyna East Corporation
    To:             compgeom-discuss@research.bell-labs.com
    Subject:        Re: circumsphere
    

    jrs+@pyramid.cmcl.cs.cmu.edu wrote:
    > 
    > > I am searching for a numerically stable algorithm to calculate the radius r
    > > (and perhaps the center m) of the circumsphere of a tetrahedron in
    > > three dimensions, given by the coordinates of the vertices a, b, c, d in R^3.
    > 
    .....(part omitted).....
    > 
    > Some notes on stability:
    > 
    > - Note that the expression for r is purely a function of differences between
    >   coordinates.  The advantage is that the relative error incurred in the
    >   computation of r is also a function of the _differences_ between the
    >   vertices, and is not influenced by the _absolute_ coordinates of the
    >   vertices.  In most applications, vertices are usually nearer to each other
    >   than to the origin, so this property is advantageous.  If someone gives you
    >   a formula that doesn't have this property, be wary.
    
    ...(part omitted)..... 
    
    > For completeness, here are stable expressions for the circumradius and
    > circumcenter of a triangle, in R^2 and in R^3.  Incidentally, the expressions
    > given here for R^2 are better behaved in terms of relative error than the
    > suggestions currently given in the Geometry Junkyard
    > (http://www.ics.uci.edu/~eppstein/junkyard/triangulation.html).
    
    In a private response to Herr Kerscher's question, I recommended that he
    look at this page, particularly my contribution to it. Let me say that
    Prof. Shewchuk's criticism regarding relative error is not only correct,
    but also of some practical significance. The good behavior which he
    refers to is obtained for 2-D triangles using the particular form
    (attributed to Jim Ward) given by the most recent
    comp.graphics.algorithms FAQ at
    http://www.cis.ohio-state.edu/hypertext/faq/usenet/graphics/algorithms-faq/faq.html
    This form has the desired property of using only differences between
    coordinates.
    An added advantage when using integer arithmetic is that such forms
    avoid overflows in many more practical cases (e.g., simplex far from
    origin).
    
    Thus, my formula given in the Geometry Junkyard:
    
         |(x1^2 + y1^2) 2y1 1|
         |(x2^2 + y2^2) 2y2 1|   |(x2^2 + y2^2 - x1^2 - y1^2) (y2 - y1)|
         |(x3^2 + y3^2) 2y3 1|   |(x3^2 + y3^2 - x1^2 - y1^2) (y3 - y1)|
    a = ---------------------- = ---------------------------------------
            | 2x1  2y1  1 |           2 * | (x2 - x1)  (y2 - y1) |
            | 2x2  2y2  1 |               | (x3 - x1)  (y3 - y1) |
            | 2x3  2y3  1 |
    
    needs to be taken another step to achieve the desired property.
    The terms in the first column of the numerator should be re-written like
    this:
    
    (x2^2 + y2^2 - x1^2 - y1^2) = (x2 - x1)(x2 + x1) + (y2 - y1)(y2 + y1)
    
    (x3^2 + y3^2 - x1^2 - y1^2) = (x3 - x1)(x3 + x1) + (y3 - y1)(y3 + y1)
    
    The formulas for tets in 3-D in the Geometry Junkyard need similar
    treatment.
    
    -- 
    *******************************************
    William J. Flis        Director of Research
    Dyna East Corporation    3620 Horizon Drive
    King of Prussia, PA  19406-2647      U.S.A.
    (610)270-9900 x130        fax:(610)270-9744
    flis@indy.dynaeast.com   or   flis@detk.com
    http://www.dynaeast.com/~flis/FlisHome.html
    *******************************************
    
    -------------
    The compgeom mailing lists: see
    http://netlib.bell-labs.com/netlib/compgeom/readme.html
    or send mail to compgeom-request@research.bell-labs.com with the line:
    send readme


    参考网址:http://www.ics.uci.edu/~eppstein/junkyard/circumcenter.html
  • 相关阅读:
    warning C4018: “<”: 有符号/无符号不匹配
    安装VS提示系统找不到指定路径
    C#调用非托管dll
    指针转引用
    C语言文件操作fclose在NDK引起的BUG
    ADT开发AndroidManifest.xml file missing错误
    利用Visual GDB在Visual Studio中进行Android开发
    OpenCv实现两幅图像的拼接
    C++读取文件夹中所有的文件或者是特定后缀的文件
    WORD2007多级列表
  • 原文地址:https://www.cnblogs.com/xpvincent/p/3324805.html
Copyright © 2011-2022 走看看