Ejemplo n.º 1
0
        public static double TorsionalAngle(Vector p1, Vector p2, Vector p3, Vector p4)
        {
            //function angle = torangle(atom1, atom2, atom3, atom4)
            //    plane_123 = cross(atom2-atom1, atom3-atom2); n1 = plane_123; n1 = n1 / sqrt(dot(n1,n1));
            //    plane_234 = cross(atom3-atom2, atom4-atom3); n2 = plane_234; n2 = n2 / sqrt(dot(n2,n2));
            //    vec_23 = atom3 - atom2;                      b  = vec_23;    b  = b  / sqrt(dot(b,b));
            //    angle = atan2(dot(cross(n1,n2),b), dot(n1,n2));
            //end

            Vector plane_123 = LinAlg.CrossProd(p2 - p1, p3 - p2); Vector n1 = plane_123.UnitVector();
            Vector plane_234 = LinAlg.CrossProd(p3 - p2, p4 - p3); Vector n2 = plane_234.UnitVector();
            Vector vec_23 = p3 - p2; Vector b = vec_23.UnitVector();
            double angle = Math.Atan2(LinAlg.VtV(LinAlg.CrossProd(n1, n2), b), LinAlg.VtV(n1, n2));

            {
                Vector p12 = p2 - p1;
                Vector p23 = p3 - p2;
                Vector p34 = p4 - p3;
                Vector nn1 = LinAlg.CrossProd(p12, p23).UnitVector();
                Vector nn2 = LinAlg.CrossProd(p23, p34).UnitVector();
                double a   = AngleBetween(nn1, nn2);
                HDebug.Assert(Math.Abs(Math.Abs(a) - Math.Abs(angle)) < 0.00000001);
            }
            return(angle);
        }
Ejemplo n.º 2
0
        public static Vector PlaneNormal(Vector pt1, Vector pt2, Vector pt3)
        {
            Vector a = pt2 - pt1;
            Vector b = pt3 - pt1;
            Vector n = LinAlg.CrossProd(a, b);

            return(n.UnitVector());
        }
Ejemplo n.º 3
0
        static void GetTriGeom(Vector pt1, Vector pt2, Vector pt3
                               , out double a, out double b, out double c
                               , out double A, out double B, out double C
                               , out double r
                               , out Vector pto
                               )
        {
            Func <Vector, Vector, Vector, double> angle2 = delegate(Vector p1, Vector p2, Vector p3)
            {
                Vector v21  = p1 - p2;
                Vector v23  = p3 - p2;
                double d21  = v21.Dist;
                double d23  = v23.Dist;
                double cos2 = LinAlg.DotProd(v21, v23) / (d21 * d23);
                double ang2 = Math.Acos(cos2);
                return(ang2);
            };
            ////////////////////////////////////////////////////////////////
            //             1     (1,2,3)
            //            /A\      |
            //           / | \     r
            //          c  |  b    |
            //         /   o   \   origin
            //        /B       C\
            //       2-----a-----3
            //
            /////////////////////////////////////////////////////////////////
            // http://schools-wikipedia.org/wp/t/Trigonometric_functions.htm
            // a/sinA = b/sinB = c/sinC = 2R
            Vector pt23 = pt2 - pt3; double dist23 = pt23.Dist;
            Vector pt31 = pt3 - pt1; double dist31 = pt31.Dist;
            Vector pt12 = pt1 - pt2; double dist12 = pt12.Dist;

            a = dist23;                // =(pt2-pt3).Dist; // distance between pt2 and pt3
            b = dist31;                // =(pt3-pt1).Dist; // distance between pt2 and pt3
            c = dist12;                // =(pt1-pt2).Dist; // distance between pt2 and pt3
            A = angle2(pt3, pt1, pt2); // angle A = ∠pt3-pt1(a)-pt2
            B = angle2(pt1, pt2, pt3); // angle B = ∠pt1-pt2(b)-pt3
            C = angle2(pt2, pt3, pt1); // angle C = ∠pt2-pt3(c)-pt1
            r = 0.5 * a / Math.Sin(A);
            // Barycentric coordinates from cross- and dot-products
            // http://en.wikipedia.org/wiki/Circumscribed_circle#Barycentric_coordinates_as_a_function_of_the_side_lengths
            /// po = v1.p1 + v2.p2 + v3.p3
            /// v1 = (|p2-p3|^2 * (p1-p2).(p1-p3)) / (2*|(p1-p2)x(p2-p3)|^2) = a*a*Dot(
            /// v2 = (|p1-p3|^2 * (p2-p1).(p2-p3)) / (2*|(p1-p2)x(p2-p3)|^2) = b*b*Dot(
            /// v3 = (|p1-p2|^2 * (p3-p1).(p3-p2)) / (2*|(p1-p2)x(p2-p3)|^2) = c*c*Dot(
            {
                double div = 2 * LinAlg.CrossProd(pt1 - pt2, pt2 - pt3).Dist2;
                double v1  = dist23 * dist23 * LinAlg.DotProd(pt12, -pt31) / div;
                double v2  = dist31 * dist31 * LinAlg.DotProd(-pt12, pt23) / div;
                double v3  = dist12 * dist12 * LinAlg.DotProd(pt31, -pt23) / div;
                pto = v1 * pt1 + v2 * pt2 + v3 * pt3;
            }
        }
Ejemplo n.º 4
0
        public static Vector RotateTangentUnit(Vector pt, Vector axis1, Vector axis2)
        {
            Vector pt_on_axis   = ClosestPointOnLine(axis1, axis2, pt, false);
            Vector direct_pt    = (pt - pt_on_axis).UnitVector();
            Vector direct_axis  = (axis2 - axis1).UnitVector();
            Vector direct_tanpt = LinAlg.CrossProd(direct_axis, direct_pt).UnitVector();

            if (HDebug.IsDebuggerAttached)
            {
                Vector dbg_axis = LinAlg.CrossProd(direct_pt, direct_tanpt).UnitVector();
                HDebug.AssertTolerance(0.00000001, (direct_axis - dbg_axis).Dist);
            }
            return(direct_tanpt);
        }
Ejemplo n.º 5
0
 public static Trans3 GetTransformNoScale(Vector from1, Vector from2, Vector to1, Vector to2)
 {
     //HTLib.DoubleVector3 lfrom1 = new HTLib.DoubleVector3(from1);
     //HTLib.DoubleVector3 lfrom2 = new HTLib.DoubleVector3(from2);
     //HTLib.DoubleVector3 lto1   = new HTLib.DoubleVector3(to1  );
     //HTLib.DoubleVector3 lto2   = new HTLib.DoubleVector3(to2  );
     //HTLib.Trans3        ltrans = HTLib.Trans3.GetTransformNoScale(lfrom1, lfrom2, lto1, lto2);
     //return new Trans3(ltrans);
     {
         double ds = 1;
         //double dx = to2.x - from2.x;     // dx + from2.x = to2.x
         //double dy = to2.y - from2.y;     // dx + from2.y = to2.y
         //double dz = to2.z - from2.z;     // dx + from2.z = to2.z
         Vector     from = (from2 - from1).UnitVector();
         Vector     to   = (to2 - to1).UnitVector();
         Quaternion dr;
         double     innerprod = LinAlg.DotProd(from, to); // InnerProduct(from,to);
         if (innerprod >= 1)
         {
             HDebug.Assert(innerprod == 1);
             dr = Quaternion.UnitRotation;
         }
         else
         {
             Vector axis = LinAlg.CrossProd(from, to);   // CrossProduct(from, to);
             if (axis.Dist2 == 0)
             {
                 // to avoid degenerate cases
                 double mag = to.Dist / 100000000;
                 axis = LinAlg.CrossProd(from, to + (new double[] { mag, mag * 2, mag * 3 }));     //Vector.CrossProduct(from, to+new DoubleVector3(mag, mag*2, mag*3));
             }
             double angle = Math.Acos(innerprod);
             dr = new Quaternion(axis, angle);
             HDebug.Assert(LinAlg.DotProd((dr.RotationMatrix * from), to) > 0.99999);
         }
         Trans3 trans = Trans3.GetTransform(-from1, 1, Quaternion.UnitRotation);
         trans = Trans3.AppendTrans(trans, Trans3.GetTransform(new double[3], ds, dr));
         trans = Trans3.AppendTrans(trans, Trans3.GetTransform(to1, 1, Quaternion.UnitRotation));
         //new Trans3(dx, dy, dz, ds, dr);
         if (HDebug.IsDebuggerAttached)
         {
             Vector fromto1 = trans.DoTransform(from1);
             HDebug.Assert((fromto1 - to1).Dist < 0.000001);
             Vector fromto2 = trans.DoTransform(from2);
             HDebug.Assert(((fromto2 - fromto1).UnitVector() - (to2 - to1).UnitVector()).Dist < 0.000001);
         }
         return(trans);
     }
 }
Ejemplo n.º 6
0
        public static Tuple <Vector, Vector> LineOnTwoPlanes(Vector norm1, double val1, Vector norm2, double val2)
        {
            /// http://intumath.org/Math/Geometry/Analytic%20Geometry/plane-planeinter.html
            ///
            if (LineOnTwoPlanes_SelfTest)
            {
                LineOnTwoPlanes_SelfTest = false;
                Vector tn1 = new double[] { 1, 2, 3 };
                Vector tn2 = new double[] { 2, 5, 3 };
                double td1 = 10;
                double td2 = 2;
                LineOnTwoPlanes(tn1, td1, tn2, td2);
            }

            Vector norm = LinAlg.CrossProd(norm1, norm2);
            /// norm1' * pt = -val1      [n1x n1y n1z]   [ptx]   [-val1]      [n1x n1y 0]   [ptx]   [-val1]
            /// norm2' * pt = -val2  =>  [n2x n2y n2z] * [pty] = [-val2]  =>  [n2x n2y 0] * [pty] = [-val2]
            ///                                          [ptz]                              [0  ]
            ///                      =>  [n1x n1y] * [ptx] = [-val1]  =>  [n1x n1y] * [ptx] = [-val1]
            ///                          [n2x n2y]   [pty]   [-val2]      [n2x n2y]   [pty]   [-val2]
            ///                      =>  [ptx] = [n1x n1y]-1  [-val1] = [ n2y -n1y] * [-val1] / (n1x*n2y - n1y*n2x)
            ///                          [pty]   [n2x n2y]  * [-val2]   [-n2x  n1x]   [-val2]
            ///                                = [ n2y*-val1 + -n1y*-val2 ] / (n1x*n2y - n1y*n2x)
            ///                                  [-n2x*-val1 +  n1x*-val2 ]
            double n1x = norm1[0], n1y = norm1[1];
            double n2x = norm2[0], n2y = norm2[1];
            double div = n1x * n2y - n1y * n2x;
            Vector pt  = new double[] { (n2y * -val1 + -n1y * -val2) / div,
                                        (-n2x * -val1 + n1x * -val2) / div,
                                        0 };

            if (HDebug.IsDebuggerAttached)
            {
                Vector dbg_pt;
                dbg_pt = pt + 1 * norm;
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(norm1, dbg_pt) + val1);
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(norm2, dbg_pt) + val2);
                dbg_pt = pt + 2 * norm;
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(norm1, dbg_pt) + val1);
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(norm2, dbg_pt) + val2);
                dbg_pt = pt - 2 * norm;
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(norm1, dbg_pt) + val1);
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(norm2, dbg_pt) + val2);
            }
            return(new Tuple <Vector, Vector>(pt, norm));
        }
Ejemplo n.º 7
0
        public static double DistancePointLine(Vector point, Vector line1, Vector line2)
        {
            // http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
            if (DistancePointLine_selftest)
            {
                DistancePointLine_selftest = false;
                Vector tp     = new Vector(2, 2, 0);
                Vector tl1    = new Vector(0, 0, -20);
                Vector tl2    = new Vector(0, 0, -10);
                double tdist0 = tp.Dist;
                double tdist1 = DistancePointLine(tp, tl1, tl2);
                double tdist2 = (ClosestPointOnLine(tl1, tl2, tp, false) - tp).Dist;
                HDebug.AssertTolerance(0.00000001, tdist0 - tdist1);
                HDebug.AssertTolerance(0.00000001, tdist0 - tdist2);
            }
            Vector x21 = line2 - line1;
            Vector x10 = line1 - point;
            double dist
                = LinAlg.CrossProd(x21, x10).Dist
                  / x21.Dist;

            return(dist);
        }
        public static Tuple <double, Vector, bool> MaxCircleBetweenCircles(Vector pt1, double rad1,
                                                                           Vector pt2, double rad2,
                                                                           Vector pt3, double rad3)
        {
            ///        b:pt3
            ///        /   \
            ///      /      \
            ///    /         \
            /// o:pt1 ------ a:pt2
            ///
            /// o : (0  ,   0), radii ro
            /// a : (pax,   0), radii ra
            /// b : (pbx, pby), radii rb

            Vector uvec12 = (pt2 - pt1).UnitVector();
            Vector uvec23 = (pt3 - pt2).UnitVector();
            Vector uvec31 = (pt1 - pt3).UnitVector();
            double cos123 = LinAlg.VtV(-uvec12, uvec23);
            double cos231 = LinAlg.VtV(-uvec23, uvec31);
            double cos312 = LinAlg.VtV(-uvec31, uvec12);

            double cos_aob;
            double ro, ra, rb;
            Vector po, pa, pb;

            if (cos123 > 0)
            {
                pa = pt1; ra = rad1; po = pt2; ro = rad2; pb = pt3; rb = rad3; cos_aob = cos123;
            }
            else if (cos231 > 0)
            {
                pa = pt2; ra = rad2; po = pt3; ro = rad3; pb = pt1; rb = rad1; cos_aob = cos231;
            }
            else if (cos312 > 0)
            {
                pa = pt2; ra = rad2; po = pt1; ro = rad1; pb = pt3; rb = rad3; cos_aob = cos312;
            }
            else
            {
                throw new Exception("cos123>0 and cos231>0");
            }

            Vector uvec_oa = (pa - po).UnitVector();
            Vector uvec_ob = (pb - po).UnitVector();
            Vector normal  = LinAlg.CrossProd(uvec_oa, uvec_ob);
            double sin_aob = normal.Dist;

            double pax = (pa - po).Dist;
            double pbx = (pb - po).Dist * cos_aob;
            double pby = (pb - po).Dist * sin_aob;
            Trans3 trans;
            {
                Vector npo = new double[] { 0, 0, 0 };
                Vector npa = new double[] { 0, pax, 0 };
                Vector npb = new double[] { 0, pbx, pby };
                trans = Trans3.GetTransformNoScale(npo, npa, npb, po, pa, pb);
                if (HDebug.IsDebuggerAttached)
                {
                    Vector pox = trans.DoTransform(npo);
                    HDebug.AssertTolerance(0.0000001, po - trans.DoTransform(npo));
                    HDebug.AssertTolerance(0.0000001, pa - trans.DoTransform(npa));
                    HDebug.AssertTolerance(0.0000001, pb - trans.DoTransform(npb));
                }
            }

            Tuple <double, Vector, bool> rad_cent_in = MaxCircleBetweenCircles(ro, ra, rb, pax, pbx, pby);

            if (rad_cent_in == null)
            {
                return(null);
            }
            double radius          = rad_cent_in.Item1;
            bool   cenerInTriangle = rad_cent_in.Item3;

            Vector center;

            {
                HDebug.Assert(rad_cent_in.Item2.Size == 2);
                center = new double[] { 0, rad_cent_in.Item2[0], rad_cent_in.Item2[1] };
                center = trans.DoTransform(center);
            }
            if (HDebug.IsDebuggerAttached)
            {
                double radx_1 = (center - pt1).Dist - rad1;
                double radx_2 = (center - pt2).Dist - rad2;
                double radx_3 = (center - pt3).Dist - rad3;
                HDebug.AssertTolerance(0.000001, radx_1 - radx_2, radx_2 - radx_3, radx_3 - radx_1);
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(normal, pt1 - pt2));
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(normal, pt2 - pt3));
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(normal, pt3 - pt1));
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(normal, pt1 - center));
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(normal, pt2 - center));
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(normal, pt3 - center));
            }

            return(new Tuple <double, Vector, bool>(radius, center, cenerInTriangle));
        }
Ejemplo n.º 9
0
            public static void GetTriGeom(Vector pa, Vector pb, Vector pc
                                          , out double a, out double b, out double c
                                          , out double A, out double B, out double C
                                          , out double r
                                          , out Vector po
                                          )
            {
                Func <Vector, Vector, Vector, double> angle2 = delegate(Vector p1, Vector p2, Vector p3)
                {
                    Vector v21  = p1 - p2;
                    Vector v23  = p3 - p2;
                    double d21  = v21.Dist;
                    double d23  = v23.Dist;
                    double cos2 = LinAlg.DotProd(v21, v23) / (d21 * d23);
                    double ang2 = Math.Acos(cos2);
                    return(ang2);
                };
                ////////////////////////////////////////////////////////////////
                //             1     (1,2,3)
                //            /A\      |
                //           / | \     r
                //          c  |  b    |
                //         /   o   \   origin
                //        /B       C\
                //       2-----a-----3
                //
                /////////////////////////////////////////////////////////////////
                // http://schools-wikipedia.org/wp/t/Trigonometric_functions.htm
                // a/sinA = b/sinB = c/sinC = 2R
                Vector pt23 = pb - pc; double dist23 = pt23.Dist;
                Vector pt31 = pc - pa; double dist31 = pt31.Dist;
                Vector pt12 = pa - pb; double dist12 = pt12.Dist;

                a = dist23;             // =(pt2-pt3).Dist; // distance between pt2 and pt3
                b = dist31;             // =(pt3-pt1).Dist; // distance between pt2 and pt3
                c = dist12;             // =(pt1-pt2).Dist; // distance between pt2 and pt3
                A = angle2(pc, pa, pb); // angle A = ∠pt3-pt1(a)-pt2
                B = angle2(pa, pb, pc); // angle B = ∠pt1-pt2(b)-pt3
                C = angle2(pb, pc, pa); // angle C = ∠pt2-pt3(c)-pt1
                r = 0.5 * a / Math.Sin(A);
                // Barycentric coordinates from cross- and dot-products
                // http://en.wikipedia.org/wiki/Circumscribed_circle#Barycentric_coordinates_as_a_function_of_the_side_lengths
                /// po = v1.p1 + v2.p2 + v3.p3
                /// v1 = (|p2-p3|^2 * (p1-p2).(p1-p3)) / (2*|(p1-p2)x(p2-p3)|^2) = a*a*Dot(
                /// v2 = (|p1-p3|^2 * (p2-p1).(p2-p3)) / (2*|(p1-p2)x(p2-p3)|^2) = b*b*Dot(
                /// v3 = (|p1-p2|^2 * (p3-p1).(p3-p2)) / (2*|(p1-p2)x(p2-p3)|^2) = c*c*Dot(
                {
                    double div = 2 * LinAlg.CrossProd(pa - pb, pb - pc).Dist2;
                    double v1  = dist23 * dist23 * LinAlg.DotProd(pt12, -pt31) / div;
                    double v2  = dist31 * dist31 * LinAlg.DotProd(-pt12, pt23) / div;
                    double v3  = dist12 * dist12 * LinAlg.DotProd(pt31, -pt23) / div;
                    po = v1 * pa + v2 * pb + v3 * pc;
                }
                if (HDebug.IsDebuggerAttached)
                {
                    double la, lb, lc;
                    double lA, lB, lC;
                    double lr;
                    Vector lpo;
                    Geometry.GetTriGeom(pa, pb, pc, out la, out lb, out lc, out lA, out lB, out lC, out lr, out lpo);
                    HDebug.Assert(la == a, lb == b, lc == c);
                    HDebug.Assert(lA == A, lB == B, lC == C);
                    HDebug.Assert(lr == r);
                    HDebug.Assert(lpo == po);
                }
            }
Ejemplo n.º 10
0
        public static double DerivativeOfTriangleRadius(Vector p1, Vector p2, Vector p3, Vector dp1, Vector dp2, Vector dp3)
        {
            /// r = |p1-p2|*|p2-p3|*|p3-p1| / (2 area(p1,p2,p3))
            ///   = |p1-p2|*|p2-p3|*|p3-p1| / (2 |(p1-p2)x(p2-p3)|)
            /// r2 = ( |p1-p2|*|p2-p3|*|p3-p1| / (2 area(p1,p2,p3)) )^2
            ///    = |p1-p2|^2 * |p2-p3|^2 * |p3-p1|^2 / (4 |(p1-p2)x(p2-p3)|^2)
            /// (r+dr*t)  = R  = |(p1+dp1*t)-(p2+dp2*t)|*|(p2+dp2*t)-(p3+dp3*t)|*|(p3+dp3*t)-(p1+dp1*t)| / (2 area(p1+dp1*t,p2+dp2*t,p3+dp3*t))
            /// (r+dr*t)2 = R2 = { |(p1+dp1*t)-(p2+dp2*t)|*|(p2+dp2*t)-(p3+dp3*t)|*|(p3+dp3*t)-(p1+dp1*t)| / (2 area(p1+dp1*t,p2+dp2*t,p3+dp3*t)) }^2
            ///
            /// d(r+dr*t)/dt = dR_dt
            ///              = d(r+dr*t)/d((r+dr*t)^2) * d((r+dr*t)^2)/dt
            ///              = dR_dR2 * dR2_dt
            /// d(r+dr*t)/d((r+dr*t)^2) = dR_dR2
            ///                         = 1/(2*r)
            /// d((r+dr*t)^2)/dt = dR2_dt
            ///                = + (   Dotp31dp31 * P12dist2 * P23dist2
            ///                      + Dotp23dp31 * P12dist2 * P31dist2
            ///                      + Dotp12dp12 * P23dist2 * P31dist2
            ///                    )/(2 * Area2)
            ///                  - ( DotCroP12P23CroP12Dp23CroDp12P23 * P12dist2 * P23dist2 * P31dist2)/(2 * Area4)
            ///
            /// P12dist2 := ((p1x-p2x)^2+(p1y-p2y)^2+(p1z-p2z)^2) = (p1-p2).dist2
            /// P23dist2 := ((p2x-p3x)^2+(p2y-p3y)^2+(p2z-p3z)^2) = (p2-p3).dist2
            /// P31dist2 := ((p1x-p3x)^2+(p1y-p3y)^2+(p1z-p3z)^2) = (p1-p3).dist2
            /// Dotp12dp12 := ((dp1x-dp2x)*(p1x-p2x) + (dp1y-dp2y)*(p1y-p2y) + (dp1z-dp2z)*(p1z-p2z))
            ///             = [dp1x-dp2x, dp1y-dp2y, dp1z-dp2z] . [p1x-p2x, p1y-p2y, p1z-p2z]
            ///             = (dp1-dp2).(p1-p2)
            /// Dotp23dp31 := ((dp2x-dp3x)*(p2x-p3x) + (dp2y-dp3y)*(p2y-p3y) + (dp2z-dp3z)*(p2z-p3z))
            ///             = (dp2-dp3).(p2-p3)
            /// Dotp31dp31 := ((dp1x-dp3x)*(p1x-p3x) + (dp1y-dp3y)*(p1y-p3y) + (dp1z-dp3z)*(p1z-p3z))
            ///             = (dp1-dp3).(p1-p3)
            /// DotCroP12P23CroP12Dp23CroDp12P23 := Dot[Cross[p1-p2,p2-p3],(Cross[p1-p2,dp2-dp3]+Cross[dp1-dp2,p2-p3])]
            ///                                   = [(p1-p2)x(p2-p3)] . [(p1-p2)x(dp2-dp3) + (dp1-dp2)x(p2-p3)]

            if (HDebug.Selftest())
            #region selftest
            {
                Vector lp1  = new double[] { 1, 0, 0 };
                Vector lp2  = new double[] { 0, 1, 0 };
                Vector lp3  = new double[] { 0, 0, 1 };
                Vector ldp1 = new double[] { 0.1, 0.1, 0.1 };
                Vector ldp2 = new double[] { 1, 2, 3 };
                Vector ldp3 = new double[] { -1, 0, -0.1 };

                double r0  = Geometry.RadiusOfTriangle(lp1, lp2, lp3);
                double dr0 = DerivativeOfTriangleRadius(lp1, lp2, lp3, ldp1, ldp2, ldp3);
                List <Tuple <double, double, double, double> > drx = new List <Tuple <double, double, double, double> >();
                foreach (double dt in new double[] { 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001 })
                {
                    double t00 = -dt; double r00 = Geometry.RadiusOfTriangle(lp1 + t00 * ldp1, lp2 + t00 * ldp2, lp3 + t00 * ldp3);
                    double t01 = +dt; double r01 = Geometry.RadiusOfTriangle(lp1 + t01 * ldp1, lp2 + t01 * ldp2, lp3 + t01 * ldp3);
                    double dr1 = (r01 - r00) / (t01 - t00);
                    double dr2 = (r01 * r01 - r00 * r00) / (t01 - t00);

                    drx.Add(new Tuple <double, double, double, double>(dt, dr1, dr2, (0.5 / r0) * dr2));
                }
                double diff = dr0 - drx.Last().Item2;
                HDebug.AssertTolerance(0.00000001, diff);
            }
            #endregion

            double P12dist2   = (p1 - p2).Dist2;
            double P23dist2   = (p2 - p3).Dist2;
            double P31dist2   = (p1 - p3).Dist2;
            double Dotp12dp12 = LinAlg.VtV(dp1 - dp2, p1 - p2);
            double Dotp23dp31 = LinAlg.VtV(dp2 - dp3, p2 - p3);
            double Dotp31dp31 = LinAlg.VtV(dp1 - dp3, p1 - p3);
            double DotCroP12P23CroP12Dp23CroDp12P23 = LinAlg.VtV(LinAlg.CrossProd(p1 - p2, p2 - p3)
                                                                 , LinAlg.CrossProd(p1 - p2, dp2 - dp3) + LinAlg.CrossProd(dp1 - dp2, p2 - p3)
                                                                 );
            double Area2 = LinAlg.CrossProd(p1 - p2, p2 - p3).Dist2;
            double Area4 = Area2 * Area2;
            double Rad2  = P12dist2 * P23dist2 * P31dist2 / (4 * Area2);
            double Rad   = Math.Sqrt(Rad2);
            HDebug.AssertTolerance(0.00000001, Rad - Geometry.RadiusOfTriangle(p1, p2, p3));

            double t      = 1;
            double dR_dR2 = 0.5 / Rad;
            double dR2_dt = ((t * Dotp31dp31) * P12dist2 * P23dist2 + (t * Dotp23dp31) * P12dist2 * P31dist2 + (t * Dotp12dp12) * P23dist2 * P31dist2) / (2 * Area2)
                            - ((t * DotCroP12P23CroP12Dp23CroDp12P23) * P12dist2 * P23dist2 * P31dist2) / (2 * Area4);
            double dR_dt = dR_dR2 * dR2_dt;
            return(dR_dt);
        }