1. 程式人生 > >c#實現的一些幾何演算法(二)

c#實現的一些幾何演算法(二)

續一

//關於線的一些演算法

   public class GeometricClass

    {

        /* 判斷點與線段的關係,用途很廣泛 

         本函式是根據下面的公式寫的,P是點C到線段AB所在直線的垂足 

                 AC dot AB 

         r =     --------- 

                  ||AB||^2 

              (Cx-Ax)(Bx-Ax) + (Cy-Ay)(By-Ay) 

           = ------------------------------- 

                           L^2 

         r has the following meaning: 

         r=0      P = A 

         r=1      P = B 

         r<0 P is on the backward extension of AB 

         r>1      P is on the forward extension of AB 

         0<r<1 P is interior to AB 

        */

        public static double RelationOfPointAndLine(SpatialPoint p, SpatialLine l)

        {

            SpatialLine tl = new SpatialLine();

            tl.startPoint = l.startPoint;

            tl.endPoint = p;

            return dotmultiply(tl.endPoint, l.endPoint, l.startPoint) / (CalculateFlatDistance(l.startPoint, l.endPoint) * CalculateFlatDistance(l.startPoint, l.endPoint));

        }

        // 根據已知兩點座標,求過這兩點的直線解析方程: a*x+b*y+c = 0  (a >= 0)  

        public static SpatialLine Makeline(SpatialPoint p1, SpatialPoint p2)

        {

            SpatialLine tl = new SpatialLine();

            int sign = 1;

            tl.a = p2.y - p1.y;

            if (tl.a < 0)

            {

                sign = -1;

                tl.a = sign * tl.a;

            }

            tl.b = sign * (p1.x - p2.x);

            tl.c = sign * (p1.y * p2.x - p1.x * p2.y);

            return tl;

        }

        // 根據直線解析方程返回直線的斜率k,水平線返回 0,豎直線返回 1e200 

        public static double SlopeOfLine(SpatialLine l)

        {

            if (Math.Abs(l.a) < INF)

                return 0;

            if (Math.Abs(l.b) < INF)

                return double.MaxValue;

            return -(l.a / l.b);

        }

        // 返回直線的傾斜角alpha ( 0 - pi) 

        public static double alphaOfLine(SpatialLine l)

        {

            if (Math.Abs(l.a) < INF)

                return 0;

            if (Math.Abs(l.b) < INF)

                return PI / 2;

            double k = SlopeOfLine(l);

            if (k > 0)

                return Math.Atan(k);

            else

                return PI + Math.Atan(k);

        }

        // 求點C到線段AB所在直線的垂足 P 

        public static SpatialPoint PerpendicularOnLine(SpatialPoint p, SpatialLine l)

        {

            double r = RelationOfPointAndLine(p, l);

            SpatialPoint tp = new SpatialPoint();

            tp.x = l.startPoint.x + r * (l.endPoint.x - l.startPoint.x);

            tp.y = l.startPoint.y + r * (l.endPoint.y - l.startPoint.y);

            return tp;

        }

        // 求點p到線段l所在直線的距離,請注意本函式與上個函式的區別  

        public static double DistanceInPointToLine(SpatialPoint p, SpatialLine l)

        {

            return Math.Abs(multiply(p, l.endPoint, l.startPoint)) / CalculateFlatDistance(l.startPoint, l.endPoint);

        }

        // 返回線段l1與l2之間的夾角 單位:弧度 範圍(-pi,pi) 

        public static double AngleOfTwoLine(SpatialLine l1, SpatialLine l2)

        {

            SpatialPoint o, s, e;

            o = new SpatialPoint();

            s = new SpatialPoint();

            e = new SpatialPoint();

            o.x = o.y = 0;

            s.x = l1.endPoint.x - l1.startPoint.x;

            s.y = l1.endPoint.y - l1.startPoint.y;

            e.x = l2.endPoint.x - l2.startPoint.x;

            e.y = l2.endPoint.y - l2.startPoint.y;

            return AngleOfThreePoint(o, s, e);

        }

        // 如果線段u和v相交(包括相交在端點處)時,返回true 

        //判斷P1P2跨立Q1Q2的依據是:( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >= 0。

        //判斷Q1Q2跨立P1P2的依據是:( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) >= 0。

        public static bool IsIntersect(SpatialLine u, SpatialLine v)

        {

            return ((Math.Max(u.startPoint.x, u.endPoint.x) >= Math.Min(v.startPoint.x, v.endPoint.x)) &&                     //排斥實驗 

                    (Math.Max(v.startPoint.x, v.endPoint.x) >= Math.Min(u.startPoint.x, u.endPoint.x)) &&

                    (Math.Max(u.startPoint.y, u.endPoint.y) >= Math.Min(v.startPoint.y, v.endPoint.y)) &&

                    (Math.Max(v.startPoint.y, v.endPoint.y) >= Math.Min(u.startPoint.y, u.endPoint.y)) &&

                    (multiply(v.startPoint, u.endPoint, u.startPoint) * multiply(u.endPoint, v.endPoint, u.startPoint) >= 0) &&         //跨立實驗 

                    (multiply(u.startPoint, v.endPoint, v.startPoint) * multiply(v.endPoint, u.endPoint, v.startPoint) >= 0));

        }

        //  (線段u和v相交)&&(交點不是雙方的端點) 時返回true    

        public static bool IsIntersect_A(SpatialLine u, SpatialLine v)

        {

            return ((IsIntersect(u, v)) &&

                    (!PointIsOnLine(u, v.startPoint)) &&

                    (!PointIsOnLine(u, v.endPoint)) &&

                    (!PointIsOnLine(v, u.endPoint)) &&

                    (!PointIsOnLine(v, u.startPoint)));

        }

        // 線段v所在直線與線段u相交時返回true;方法:判斷線段u是否跨立線段v  

        public static bool intersect_l(SpatialLine u, SpatialLine v)

        {

            return multiply(u.startPoint, v.endPoint, v.startPoint) * multiply(v.endPoint, u.endPoint, v.startPoint) >= 0;

        }

        // 如果兩條直線 l1(a1*x+b1*y+c1 = 0), l2(a2*x+b2*y+c2 = 0)相交,返回true,且返回交點p  

        public static bool LineIntersect(SpatialLine l1, SpatialLine l2, out SpatialPoint intersectPoint) // 是 L1,L2 

        {

            double d = l1.a * l2.b - l2.a * l1.b;

            intersectPoint = new SpatialPoint();

            if (Math.Abs(d) < EP) // 不相交 

                return false;

            intersectPoint.x = (l2.c * l1.b - l1.c * l2.b) / d;

            intersectPoint.y = (l2.a * l1.c - l1.a * l2.c) / d;

            intersectPoint.h = 0;

            return true;

        }

        // 如果線段l1和l2相交,返回true且交點由(intersectPoint)返回,否則返回false 

        public static bool LineSegmentIntersection(SpatialLine l1, SpatialLine l2, out SpatialPoint intersectPoint)

        {

            SpatialLine ll1, ll2;

            intersectPoint = new SpatialPoint();

            ll1 = Makeline(l1.startPoint, l1.endPoint);

            ll2 = Makeline(l2.startPoint, l2.endPoint);

            if (LineIntersect(ll1, ll2, out intersectPoint))

                return PointIsOnLine(l1, intersectPoint) && PointIsOnLine(l2, intersectPoint);

            else

                return false;

        } 

    }