Browse Source

mxg:添加Geometry方法

mengxiangge 6 years ago
parent
commit
62a08fa45c

+ 29 - 0
MBI/SAGA.DotNetUtils/Geometry/Extends.cs

@@ -0,0 +1,29 @@
+/////////////////////////////////////////////
+//Copyright (c) 2011, 北京探索者软件公司
+//All rights reserved.       
+//文件名称: 
+//文件描述: 
+//创 建 者: mjy
+//创建日期: 2011-11-02
+//版 本 号:4.0.0.0  
+/////////////////////////////////////////////
+
+using System.Drawing;
+
+namespace SAGA.DotNetUtils.Geometry
+{
+    public static class Extends
+    {
+        public static Geometry2D.PointD ToPointD(this PointF p)
+        {
+            return new Geometry2D.PointD(p.X, p.Y);
+        }
+
+        public static PointF ToPointF(this Geometry2D.PointD p)
+        {
+            return new PointF((float)p.X, (float)p.Y);
+        }
+
+
+    }
+}

File diff suppressed because it is too large
+ 1682 - 0
MBI/SAGA.DotNetUtils/Geometry/Geometry2d.cs


+ 89 - 0
MBI/SAGA.DotNetUtils/Geometry/HTwoPointRelation.cs

@@ -0,0 +1,89 @@
+/////////////////////////////////////////////
+//Copyright (c) 2011, 北京探索者软件公司
+//All rights reserved.       
+//文件名称: 
+//文件描述: 
+//创 建 者: mjy
+//创建日期: 2011-11-02
+//版 本 号:4.0.0.0  
+/////////////////////////////////////////////
+
+using System;
+using System.Drawing;
+
+namespace SAGA.DotNetUtils.Geometry
+{
+    public class HTwoPointRelation
+    {
+        private PointF fix;
+        private PointF other;
+        public HTwoPointRelation(PointF fix, PointF other)
+        {
+            this.fix = fix;
+            this.other = other;
+        }
+
+        public PointF Fix { get { return fix; } }
+        public PointF Other { get { return other; } }
+        public double Distance
+        {
+            get
+            {
+                return Geometry2D.Dist(fix.ToPointD(), other.ToPointD());
+            }
+        }
+
+        public RelationOptions RelationGraphics
+        {
+            get
+            {
+                if (fix == other)
+                    return RelationOptions.Override;
+                if (other.X > fix.X)
+                {
+                    return RelationOptions.Right;
+                }
+                else
+                {
+                    return RelationOptions.Left;
+                }
+            }
+        }
+
+        public RelationOptions RelationCAD
+        {
+            get
+            {
+                if (fix == other)
+                    return RelationOptions.Override;
+                if (other.X > fix.X)
+                {
+                    return RelationOptions.Right;
+                }
+                else
+                {
+                    return RelationOptions.Left;
+                }
+            }
+        }
+
+        public PointF HOther
+        {
+            get
+            {               
+                return new PointF(other.X, fix.Y);
+            }
+        }
+
+        public double HDistance
+        {
+            get
+            {
+                double d = Math.Abs(other.X - fix.X);
+                if (d < 0.000001d)
+                    return 0d;
+                return d;
+            }
+        }
+    }
+}

+ 413 - 0
MBI/SAGA.DotNetUtils/Geometry/OffsetPolyLine.cs

@@ -0,0 +1,413 @@
+/////////////////////////////////////////////
+//Copyright (c) 2011, 北京探索者软件公司
+//All rights reserved.       
+//文件名称: 
+//文件描述: 
+//创 建 者: mjy
+//创建日期: 2011-11-02
+//版 本 号:4.0.0.0  
+/////////////////////////////////////////////
+
+using System;
+using System.Collections.Generic;
+
+namespace SAGA.DotNetUtils.Geometry
+{
+    public static class OffsetPolyLine
+    {
+        public static Geometry2D.PointD[] Offset(Geometry2D.PointD[] ps, double dOffset, int nRotType)
+        {
+            int nData = ps.Length;
+            double[,] polyLine = new double[nData, 2];
+            for (int i = 0; i < ps.Length; i++)
+            {
+                polyLine[i, 0] = ps[i].X;
+                polyLine[i, 1] = ps[i].Y;
+            }
+            bool result = Offset(dOffset, nData, polyLine, nRotType);
+            if (!result) return null;
+            List<Geometry2D.PointD> listPoints = new List<Geometry2D.PointD>();
+            for (int i = 0; i < polyLine.GetLength(0); i++)
+            {
+                Geometry2D.PointD p = new Geometry2D.PointD();
+                p.X = polyLine[i, 0];
+                p.Y = polyLine[i, 1];
+                listPoints.Add(p);
+            }
+            return listPoints.ToArray();
+        }
+
+        private static bool Offset(double dOffset, int nData, double[,] polyLine, int nRotType)
+        {
+            List<double> raOffset = new List<double>(nData);
+            for (int i = 0; i < nData; i++)
+                raOffset.Add(dOffset);
+            if (nData < 3) return false;
+            double[,] polyLine_Org = new double[nData, 2];
+            for (int i = 0; i < nData; i++)
+            {
+                for (int j = 0; j < 2; j++)
+                    polyLine_Org[i, j] = polyLine[i, j];
+            }
+            if (nRotType <= 0)
+            {
+                nRotType = mathGetRotType(nData, polyLine) ? 1 : 2;
+            }
+            double[] vector = new double[2];
+            double[] cross = new double[2];
+            double[] vectorOuter = new double[2];
+            double[,] line1 = new double[2, 2];
+            double[,] line2 = new double[2, 2];
+            double dL_line1, dL_line2;
+            int nStrID, nEndID;
+            nStrID = nData - 1;
+            nEndID = 0;
+            vector[0] = polyLine_Org[nEndID, 0] - polyLine_Org[nStrID, 0];
+            vector[1] = polyLine_Org[nEndID, 1] - polyLine_Org[nStrID, 1];
+            mathNormalize(vector[0], vector[1], ref vector[0], ref vector[1]);
+            if (nRotType == 1)
+            {
+                vectorOuter[0] = vector[1];
+                vectorOuter[1] = -1.0*vector[0];
+            }
+            else
+            {
+                vectorOuter[0] = -1.0*vector[1];
+                vectorOuter[1] = vector[0];
+            }
+            line1[0, 0] = polyLine_Org[nStrID, 0] + raOffset[nStrID]*vectorOuter[0];
+            line1[0, 1] = polyLine_Org[nStrID, 1] + raOffset[nStrID]*vectorOuter[1];
+            line1[1, 0] = polyLine_Org[nEndID, 0] + raOffset[nStrID]*vectorOuter[0];
+            line1[1, 1] = polyLine_Org[nEndID, 1] + raOffset[nStrID]*vectorOuter[1];
+            dL_line1 = mathLength(line1[0, 0], line1[0, 1], line1[1, 0], line1[1, 1]);
+            for (int i = 0; i < nData; i++)
+            {
+                if (i < nData - 1)
+                {
+                    nStrID = i;
+                    nEndID = i + 1;
+                }
+                else
+                {
+                    nStrID = i;
+                    nEndID = 0;
+                }
+                vector[0] = polyLine_Org[nEndID, 0] - polyLine_Org[nStrID, 0];
+                vector[1] = polyLine_Org[nEndID, 1] - polyLine_Org[nStrID, 1];
+                mathNormalize(vector[0], vector[1], ref vector[0], ref vector[1]);
+                if (nRotType == 1)
+                {
+                    vectorOuter[0] = vector[1];
+                    vectorOuter[1] = -1.0*vector[0];
+                }
+                else
+                {
+                    vectorOuter[0] = -1.0*vector[1];
+                    vectorOuter[1] = vector[0];
+                }
+                line2[0, 0] = polyLine_Org[nStrID, 0] + raOffset[nStrID]*vectorOuter[0];
+                line2[0, 1] = polyLine_Org[nStrID, 1] + raOffset[nStrID]*vectorOuter[1];
+                line2[1, 0] = polyLine_Org[nEndID, 0] + raOffset[nStrID]*vectorOuter[0];
+                line2[1, 1] = polyLine_Org[nEndID, 1] + raOffset[nStrID]*vectorOuter[1];
+                dL_line2 = mathLength(line2[0, 0], line2[0, 1], line2[1, 0], line2[1, 1]);
+                if (mathLength(line1[1, 0], line1[1, 1], line2[0, 0], line2[0, 1])
+                    <= m_NormalZero*(dL_line1 + dL_line2))
+                {
+                    polyLine[i, 0] = line2[0, 0];
+                    polyLine[i, 1] = line2[0, 1];
+                }
+                else
+                {
+                    if (mathLineLineCross2D(line1, line2, cross) == 0)
+                    {
+                        return false;
+                    }
+                    else
+                    {
+                        polyLine[i, 0] = cross[0];
+                        polyLine[i, 1] = cross[1];
+                    }
+                }
+                line1[0, 0] = line2[0, 0];
+                line1[0, 1] = line2[0, 1];
+                line1[1, 0] = line2[1, 0];
+                line1[1, 1] = line2[1, 1];
+                dL_line1 = dL_line2;
+            }
+            return true;
+        }
+
+        private static bool mathGetRotType(int nData, double[,] polyLine)
+        {
+            int nRotType = 1;
+            int iBegin = 0;
+            for (int i = 0; i < nData; i++)
+            {
+                if (polyLine[i, 0] < polyLine[iBegin, 0] + m_NormalZero)
+                {
+                    iBegin = i;
+                }
+            }
+            double dblX1 = polyLine[iBegin + 0, 0];
+            double dblY1 = polyLine[iBegin + 0, 1];
+            double dblX2 = polyLine[0, 0];
+            double dblY2 = polyLine[0, 1];
+            if (iBegin < nData - 1)
+            {
+                dblX2 = polyLine[iBegin + 1, 0];
+                dblY2 = polyLine[iBegin + 1, 1];
+            }
+            double[] vector = new double[2];
+            vector[0] = dblX2 - dblX1;
+            vector[1] = dblY2 - dblY1;
+            mathNormalize(vector[0], vector[1], ref vector[0], ref vector[1]);
+            double[] vectorLeft = new double[2];
+            vectorLeft[0] = -1.0*vector[1];
+            vectorLeft[1] = vector[0];
+            double dDeltaLength = 10.0* /*m_NormalZero*/0.000001*mathLength(dblX2 - dblX1, dblY2 - dblY1);
+            double[] dPoint = new double[2];
+            dPoint[0] = (dblX2 + dblX1)/2.0 + dDeltaLength*vectorLeft[0];
+            dPoint[1] = (dblY2 + dblY1)/2.0 + dDeltaLength*vectorLeft[1];
+            bool bInside = mathIsInsidePoint2D(dPoint, nData, polyLine, true);
+            if (bInside)
+                nRotType = 1;
+            else
+                nRotType = 2;
+            return nRotType == 1 ? true : false;
+        }
+
+        public static bool mathIsInsidePoint2D(double[] p1, int nData, double[,] polyLine, bool bIncludeOutLine = true)
+        {
+            int count = 0;
+            int ic = 0;
+            double[] p2 = new double[2];
+            p2[0] = p1[1] + 10e10;
+            p2[1] = p1[1];
+            int i;
+            for (i = 0; i < nData; i++)
+            {
+                if (p2[0] < polyLine[i, 0]) p2[0] = polyLine[i, 0] + 100;
+            }
+            double[] polyLineSub1 = new double[2];
+            double[] polyLineSub2 = new double[2];
+            for (i = 0; i < nData - 1; i++)
+            {
+                //ic = mathIntersect_ccw2D(p1, p2, polyLine[i], polyLine[i + 1]);
+                polyLineSub1[0] = polyLine[i, 0];
+                polyLineSub1[1] = polyLine[i, 0];
+                polyLineSub2[0] = polyLine[i + 1, 0];
+                polyLineSub2[1] = polyLine[i + 1, 0];
+                ic = mathIntersect_ccw2D(p1, p2, polyLineSub1, polyLineSub2);
+                if (ic > 0)
+                    count++;
+                else if (ic == 0)
+                {
+                    //if (mathIsPointOfLine2D(polyLine[i], polyLine[i + 1], p1))
+                    if (mathIsPointOfLine2D(polyLineSub1, polyLineSub2, p1))
+                        return bIncludeOutLine;
+                    if (p1[1] == Math.Min(polyLine[i, 1], polyLine[i + 1, 1]) && polyLine[i, 1] != polyLine[i + 1, 1])
+                        count++;
+                }
+            }
+            polyLineSub1[0] = polyLine[nData - 1, 0];
+            polyLineSub1[1] = polyLine[nData - 1, 0];
+            polyLineSub2[0] = polyLine[0, 0];
+            polyLineSub2[1] = polyLine[0, 0];
+            //ic = mathIntersect_ccw2D(p1, p2, polyLine[nData - 1], polyLine[0]);
+            ic = mathIntersect_ccw2D(p1, p2, polyLineSub1, polyLineSub2);
+            if (ic > 0)
+                count++;
+            else if (ic == 0)
+            {
+                //if (mathIsPointOfLine2D(polyLine[nData - 1], polyLine[0], p1))
+                if (mathIsPointOfLine2D(polyLineSub1, polyLineSub2, p1))
+                    return bIncludeOutLine;
+                if (p1[1] == Math.Min(polyLine[nData - 1, 1], polyLine[0, 1]) &&
+                    polyLine[nData - 1, 1] != polyLine[0, 1])
+                    count++;
+            }
+            return (count%2) == 1;
+        }
+
+        private static bool mathIsPointOfLine2D(double[] bound1, double[] bound2, double[] targetPt,
+            bool isOnLine = true)
+        {
+            double dNormalZero = m_NormalZero*10000.0;
+            return mathIsPointOfLine2D(bound1, bound2, targetPt, isOnLine, dNormalZero);
+        }
+
+        private static bool mathIsPointOfLine2D(double[] bound1, double[] bound2, double[] targetPt, bool isOnLine,
+            double dUserTol)
+        {
+            double dNormalZero = dUserTol;
+            double dTol = Math.Max(mathLength(bound1[0] - bound2[0], bound1[1] - bound2[1]), m_NormalZero);
+            if (Math.Abs(targetPt[0] - bound1[0]) < dNormalZero*dTol &&
+                Math.Abs(targetPt[1] - bound1[1]) < dNormalZero*dTol)
+                return isOnLine;
+            if (Math.Abs(targetPt[0] - bound2[0]) < dNormalZero*dTol &&
+                Math.Abs(targetPt[1] - bound2[1]) < dNormalZero*dTol)
+                return isOnLine;
+            double[] vector1 = new double[2];
+            vector1[0] = bound1[0] - targetPt[0];
+            vector1[1] = bound1[1] - targetPt[1];
+            mathNormalize2D(vector1, vector1);
+            double[] vector2 = new double[2];
+            vector2[0] = bound2[0] - targetPt[0];
+            vector2[1] = bound2[1] - targetPt[1];
+            mathNormalize2D(vector2, vector2);
+            if (Math.Abs(mathCross2D(vector1, vector2)) < dNormalZero*dTol &&
+                !(Math.Abs(vector1[0] - vector2[0]) < dNormalZero*dTol &&
+                  Math.Abs(vector1[1] - vector2[1]) < dNormalZero*dTol))
+                return true;
+            return false;
+        }
+
+        private static int mathIntersect_ccw2D(double[] p1Org, double[] p2Org, double[] p3Org, double[] p4Org)
+        {
+            double[] p1 = new double[2];
+            double[] p2 = new double[2];
+            double[] p3 = new double[2];
+            double[] p4 = new double[2];
+            for (int i = 0; i < 2; i++)
+            {
+                p1[i] = p1Org[i];
+                p2[i] = p2Org[i];
+                p3[i] = p3Org[i];
+                p4[i] = p4Org[i];
+            }
+            if (p1[0] > p2[0])
+            {
+                mathSwap2D(p1, p2);
+            }
+            if (p3[0] > p4[0])
+            {
+                mathSwap2D(p3, p4);
+            }
+            if (p1[1] > p2[1])
+            {
+                mathSwap2D(p1, p2);
+            }
+            if (p3[1] > p4[1])
+            {
+                mathSwap2D(p3, p4);
+            }
+            int r123 = math_ccw(p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]);
+            int r124 = math_ccw(p1[0], p1[1], p2[0], p2[1], p4[0], p4[1]);
+            int r341 = math_ccw(p3[0], p3[1], p4[0], p4[1], p1[0], p1[1]);
+            int r342 = math_ccw(p3[0], p3[1], p4[0], p4[1], p2[0], p2[1]);
+            if (r123*r124 < 0 && r341*r342 < 0)
+                return 1;
+            if (r123 == 0 && r124 == 0)
+            {
+                if (!(p3[0] > p2[0] || p1[0] > p4[0]) && !(p3[1] > p2[1] || p1[1] > p4[1]))
+                    // JSOH (2008.8.29) y绵俊 措茄 厚背侥 眠啊
+                    return 0;
+                else
+                    return -1;
+            }
+            if (r123 == 0)
+            {
+                if (p1[0] <= p3[0] && p3[0] <= p2[0] && p1[1] <= p3[1] && p3[1] <= p2[1]) return 0;
+                else return -1;
+            }
+            if (r124 == 0)
+            {
+                if (p1[0] <= p4[0] && p4[0] <= p2[0] && p1[1] <= p4[1] && p4[1] <= p2[1]) return 0;
+                else return -1;
+            }
+            if (r341 == 0)
+            {
+                if (p3[0] <= p1[0] && p1[0] <= p4[0] && p3[1] <= p1[1] && p1[1] <= p4[1]) return 0;
+                else return -1;
+            }
+            if (r342 == 0)
+            {
+                if (p3[0] <= p2[0] && p2[0] <= p4[0] && p3[1] <= p2[1] && p2[1] <= p4[1]) return 0;
+                else return -1;
+            }
+            return -1;
+        }
+
+        private static void mathSwap2D(double[] p1, double[] p2)
+        {
+            double tx = p1[0];
+            double ty = p1[1];
+            p1[0] = p2[0];
+            p1[1] = p2[1];
+            p2[0] = tx;
+            p2[1] = ty;
+        }
+
+        private static int math_ccw(double ax, double ay, double bx, double by, double cx, double cy)
+        {
+            double l = bx*cy - ay*bx - ax*cy - by*cx + ax*by + ay*cx;
+            if (Math.Abs(l) < 1.0e-10) return 0;
+            else if (l > 0.0) return 1;
+            else return -1;
+        }
+
+        private static double mathLength(double dx, double dy, double dz = 0)
+        {
+            return Math.Sqrt(dx*dx + dy*dy + dz*dz);
+        }
+
+        private static double mathLength(double dxi, double dyi, double dxj, double dyj)
+        {
+            double dblLength = (dxi - dxj)*(dxi - dxj) + (dyi - dyj)*(dyi - dyj);
+            if (dblLength < 0)
+                dblLength = 0;
+            return Math.Sqrt(dblLength);
+        }
+
+        private static readonly double m_NormalZero = 0.0000000000001;
+
+        private static double mathLineLineCross2D(double[,] line1, double[,] line2, double[] cross)
+        {
+            double[] vector1 = new double[2];
+            vector1[0] = line1[0, 0] - line1[1, 0];
+            vector1[1] = line1[0, 1] - line1[1, 1];
+            mathNormalize2D(vector1, vector1);
+            double[] vector2 = new double[2];
+            vector2[0] = line2[0, 0] - line2[1, 0];
+            vector2[1] = line2[0, 1] - line2[1, 1];
+            mathNormalize2D(vector2, vector2);
+            double product = mathCross2D(vector1, vector2);
+            //if (fabs(product) < m_NormalZero*100000)  
+            if (Math.Abs(product) < m_NormalZero*100000)
+            {
+                cross[0] = 0.0;
+                cross[1] = 0.0;
+                return 0;
+            }
+            double[] vector3 = new double[2];
+            vector3[0] = line1[0, 0] - line2[0, 0];
+            vector3[1] = line1[0, 1] - line2[0, 1];
+            double H = mathCross2D(vector2, vector3);
+            cross[0] = line1[0, 0] + vector1[0]*(H/product);
+            cross[1] = line1[0, 1] + vector1[1]*(H/product);
+            return 1;
+        }
+
+        private static double mathCross2D(double[] vector1, double[] vector2)
+        {
+            return vector1[0]*vector2[1] - vector1[1]*vector2[0];
+        }
+
+        private static bool mathNormalize2D(double[] vector, double[] vectorn)
+        {
+            return mathNormalize(vector[0], vector[1], ref vectorn[0], ref vectorn[1]);
+        }
+
+        private static bool mathNormalize(double dx, double dy, ref double dxn, ref double dyn)
+        {
+            dxn = 0;
+            dyn = 0;
+            double Length = mathLength(dx, dy);
+            if (Length < m_NormalZero)
+                return false;
+            dxn = dx/Length;
+            dyn = dy/Length;
+            return true;
+        }
+    }
+}

+ 76 - 0
MBI/SAGA.DotNetUtils/Geometry/RelationOptions.cs

@@ -0,0 +1,76 @@
+/////////////////////////////////////////////
+//Copyright (c) 2011, 北京探索者软件公司
+//All rights reserved.       
+//文件名称: 
+//文件描述: 
+//创 建 者: mjy
+//创建日期: 2011-11-02
+//版 本 号:4.0.0.0  
+/////////////////////////////////////////////
+
+namespace SAGA.DotNetUtils.Geometry
+{
+    public enum RelationOptions
+    {
+        RightUp = 1,
+        RightDown,
+        LeftUp,
+        LeftDown,
+        Left,
+        Right,
+        Up,
+        Down,
+        Override
+    }
+
+    public class RelationOptionDirection
+    {
+        public static bool IsSameDirectionH(RelationOptions a, RelationOptions b)
+        {
+            switch (a)
+            {
+                case RelationOptions.LeftUp:
+                case RelationOptions.LeftDown:
+                case RelationOptions.Left:
+                    if (b == RelationOptions.LeftDown ||
+                        b == RelationOptions.LeftUp ||
+                        b == RelationOptions.Left)
+                        return true;
+                    break;
+                case RelationOptions.RightUp:
+                case RelationOptions.RightDown:
+                case RelationOptions.Right:
+                    if (b == RelationOptions.RightUp ||
+                        b == RelationOptions.RightDown ||
+                        b == RelationOptions.Right)
+                        return true;
+                    break;
+            }
+            return false;
+        }
+
+        public static bool IsSameDirectionV(RelationOptions a, RelationOptions b)
+        {
+            switch (a)
+            {
+                case RelationOptions.LeftUp:
+                case RelationOptions.RightUp:
+                case RelationOptions.Up:
+                    if (b == RelationOptions.LeftUp ||
+                        b == RelationOptions.RightUp ||
+                        b == RelationOptions.Up)
+                        return true;
+                    break;
+                case RelationOptions.RightDown:
+                case RelationOptions.LeftDown:
+                case RelationOptions.Down:
+                    if (b == RelationOptions.RightDown ||
+                        b == RelationOptions.LeftDown ||
+                        b == RelationOptions.Down)
+                        return true;
+                    break;
+            }
+            return false;
+        }
+    }
+}

+ 592 - 0
MBI/SAGA.DotNetUtils/Geometry/TszGeoUtil.cs

@@ -0,0 +1,592 @@
+using System;
+using System.Collections.Generic;
+using SAGA.DotNetUtils.Extend;
+
+namespace SAGA.DotNetUtils.Geometry
+{
+    public static class TszGeoUtil
+    {
+        /// <summary>
+        /// 转字符串
+        /// </summary>
+        /// <param name="xyz"></param>
+        /// <returns></returns>
+        public static string XYZToString(TszXYZ xyz)
+        {
+            return xyz.x + "," + xyz.y + "," + xyz.z;
+        }
+
+        /// <summary>
+        /// 转换成点
+        /// </summary>
+        /// <param name="strPtStr"></param>
+        /// <returns></returns>
+        public static TszXYZ StringToXYZ(string strPtStr)
+        {
+            strPtStr = strPtStr.TrimStart('(');
+            strPtStr = strPtStr.TrimEnd(')');
+            strPtStr = strPtStr.TrimStart('[');
+            strPtStr = strPtStr.TrimEnd(']');
+            string[] strTemps = strPtStr.Split(',');
+            return new TszXYZ(double.Parse(strTemps[0]), double.Parse(strTemps[1]), double.Parse(strTemps[2]));
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="strPtStr"></param>
+        /// <param name="dZ"></param>
+        /// <returns></returns>
+        public static TszXYZ StringToXYZ(string strPtStr, double dZ)
+        {
+            strPtStr = strPtStr.TrimStart('(');
+            strPtStr = strPtStr.TrimEnd(')');
+            strPtStr = strPtStr.TrimStart('[');
+            strPtStr = strPtStr.TrimEnd(']');
+            string[] strTemps = strPtStr.Split(',');
+            return new TszXYZ(double.Parse(strTemps[0]), double.Parse(strTemps[1]), dZ);
+        }
+
+        /// <summary>
+        /// Checks if the two double values are equal taking into consideration the equality value.
+        /// </summary>
+        /// <param name="val1">First double value needed.</param>
+        /// <param name="val2">Second double value needed.</param>
+        /// <param name="eq">A double value representing the equality(for example 0.00001)</param>
+        /// <returns>True if the two passed values are equal.</returns>
+        public static bool AreEqual(double val1, double val2, double eq)
+        {
+            return (Math.Abs((double)(val1 - val2)) < eq);
+        }
+
+        /// <summary>
+        /// Transform old coordinate system in the new coordinate system 
+        /// </summary>
+        /// <param name="point">the TszXYZ which need to be transformed</param>
+        /// <param name="transform">the value of the coordinate system to be transformed</param>
+        /// <returns>the new TszXYZ which has been transformed</returns>
+        public static TszXYZ TransformPoint(TszXYZ point, TszTransform transform)
+        {
+            //get the coordinate value in X, Y, Z axis
+            double x = point.x;
+            double y = point.y;
+            double z = point.z;
+            //transform basis of the old coordinate system in the new coordinate system
+            TszXYZ b0 = transform.get_Basis(0);
+            TszXYZ b1 = transform.get_Basis(1);
+            TszXYZ b2 = transform.get_Basis(2);
+            TszXYZ origin = transform.Origin;
+            //transform the origin of the old coordinate system in the new coordinate system
+            double xTemp = x * b0.x + y * b1.x + z * b2.x + origin.x;
+            double yTemp = x * b0.y + y * b1.y + z * b2.y + origin.y;
+            double zTemp = x * b0.z + y * b1.z + z * b2.z + origin.z;
+            return new TszXYZ(xTemp, yTemp, zTemp);
+        }
+
+        /// <summary>
+        /// Judge whether the two double data are equal
+        /// </summary>
+        /// <param name="d1">The first double data</param>
+        /// <param name="d2">The second double data</param>
+        /// <returns>true if two double data is equal, otherwise false</returns>
+        public static bool IsEqual(double d1, double d2)
+        {
+            return d1.IsEqual(d2);
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="d1"></param>
+        /// <param name="d2"></param>
+        /// <param name="d3"></param>
+        /// <returns></returns>
+        public static bool IsEqual(double d1, double d2, double d3)
+        {
+            return IsEqual(d1, d2) && IsEqual(d1, d3);
+        }
+
+        /// <summary>
+        /// Judge whether the two TszXYZ point are equal
+        /// </summary>
+        /// <param name="first">The first TszXYZ point</param>
+        /// <param name="second">The second TszXYZ point</param>
+        /// <returns>true if two TszXYZ point is equal, otherwise false</returns>
+        public static bool IsEqual(TszXYZ first, TszXYZ second)
+        {
+            bool flag = true;
+            flag = flag && IsEqual(first.x, second.x);
+            flag = flag && IsEqual(first.y, second.y);
+            flag = flag && IsEqual(first.z, second.z);
+            return flag;
+        }
+
+        /// <summary>
+        /// dot product of two TszXYZ as Matrix
+        /// </summary>
+        /// <param name="p1">The first TszXYZ</param>
+        /// <param name="p2">The second TszXYZ</param>
+        /// <returns>the cosine value of the angle between vector p1 an p2</returns>
+        public static double DotMatrix(TszXYZ p1, TszXYZ p2)
+        {
+            //get the coordinate of the TszXYZ 
+            double v1 = p1.x;
+            double v2 = p1.y;
+            double v3 = p1.z;
+            double u1 = p2.x;
+            double u2 = p2.y;
+            double u3 = p2.z;
+            return v1 * u1 + v2 * u2 + v3 * u3;
+        }
+
+        /// <summary>
+        /// judge whether the two vectors have the same direction
+        /// </summary>
+        /// <param name="firstVec">the first vector</param>
+        /// <param name="secondVec">the second vector</param>
+        /// <returns>true if the two vector is in same direction, otherwise false</returns>
+        public static bool IsSameDirection(TszXYZ firstVec, TszXYZ secondVec)
+        {
+            // get the unit vector for two vectors
+            TszXYZ first = UnitVector(firstVec);
+            TszXYZ second = UnitVector(secondVec);
+            // if the dot product of two unit vectors is equal to 1, return true
+            double dot = DotMatrix(first, second);
+            return (IsEqual(dot, 1));
+        }
+
+        /// <summary>
+        /// Judge whether the two vectors have the opposite direction
+        /// </summary>
+        /// <param name="firstVec">the first vector</param>
+        /// <param name="secondVec">the second vector</param>
+        /// <returns>true if the two vector is in opposite direction, otherwise false</returns>
+        public static bool IsOppositeDirection(TszXYZ firstVec, TszXYZ secondVec)
+        {
+            // get the unit vector for two vectors
+            TszXYZ first = UnitVector(firstVec);
+            TszXYZ second = UnitVector(secondVec);
+            // if the dot product of two unit vectors is equal to -1, return true
+            double dot = DotMatrix(first, second);
+            return (IsEqual(dot, -1));
+        }
+
+        /// <summary>
+        /// multiplication cross of two TszXYZ as Matrix
+        /// </summary>
+        /// <param name="p1">The first TszXYZ</param>
+        /// <param name="p2">The second TszXYZ</param>
+        /// <returns>the normal vector of the face which first and secend vector lie on</returns>
+        public static TszXYZ CrossMatrix(TszXYZ p1, TszXYZ p2)
+        {
+            double x = p2.z * p1.y - p2.y * p1.z;
+            double y = p2.x * p1.z - p2.z * p1.x;
+            double z = p2.y * p1.x - p2.x * p1.y;
+            return new TszXYZ(x, y, z);
+        }
+
+        /// <summary>
+        /// Set the vector into unit length
+        /// </summary>
+        /// <param name="vector">the input vector</param>
+        /// <returns>the vector in unit length</returns>
+        public static TszXYZ UnitVector(TszXYZ vector)
+        {
+            // calculate the distance from grid origin to the TszXYZ
+            double length = GetLength(vector);
+            // changed the vector into the unit length
+            double x = vector.x / length;
+            double y = vector.y / length;
+            double z = vector.z / length;
+            return new TszXYZ(x, y, z);
+        }
+
+        /// <summary>
+        /// calculate the distance from grid origin to the TszXYZ(vector length)
+        /// </summary>
+        /// <param name="vector">the input vector</param>
+        /// <returns>the length of the vector</returns>
+        public static double GetLength(TszXYZ vector)
+        {
+            double x = vector.x;
+            double y = vector.y;
+            double z = vector.z;
+            return Math.Sqrt(x * x + y * y + z * z);
+        }
+
+        /// <summary>
+        /// Subtraction of two points(or vectors), get a new vector 
+        /// </summary>
+        /// <param name="p1">the first point(vector)</param>
+        /// <param name="p2">the second point(vector)</param>
+        /// <returns>return a new vector from point p2 to p1</returns>
+        public static TszXYZ SubXYZ(TszXYZ p1, TszXYZ p2)
+        {
+            double x = p1.x - p2.x;
+            double y = p1.y - p2.y;
+            double z = p1.z - p2.z;
+            return new TszXYZ(x, y, z);
+        }
+
+        /// <summary>
+        /// Add of two points(or vectors), get a new point(vector) 
+        /// </summary>
+        /// <param name="p1">the first point(vector)</param>
+        /// <param name="p2">the first point(vector)</param>
+        /// <returns>a new vector(point)</returns>
+        public static TszXYZ AddXYZ(TszXYZ p1, TszXYZ p2)
+        {
+            double x = p1.x + p2.x;
+            double y = p1.y + p2.y;
+            double z = p1.z + p2.z;
+            return new TszXYZ(x, y, z);
+        }
+
+        /// <summary>
+        /// Multiply a verctor with a number
+        /// </summary>
+        /// <param name="vector">a vector</param>
+        /// <param name="rate">the rate number</param>
+        /// <returns></returns>
+        public static TszXYZ MultiplyVector(TszXYZ vector, double rate)
+        {
+            double x = vector.x * rate;
+            double y = vector.y * rate;
+            double z = vector.z * rate;
+            return new TszXYZ(x, y, z);
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="pt"></param>
+        /// <returns></returns>
+        public static double GetAngle(TszXYZ pt)
+        {
+            return Math.Atan2(pt.y, pt.x);
+        }
+
+        /// <summary>
+        /// Get the angle between two gPoints in radians.
+        /// </summary>
+        /// <param name="p1">First TszXYZ needed.</param>
+        /// <param name="p2">Second TszXYZ needed.</param>
+        /// <returns>The angle in radians between two gPoints.</returns>
+        public static double GetAngle(TszXYZ p1, TszXYZ p2)
+        {
+            if (AreEqual(p1.FindDistance2(p2), 0.0, 1E-08))
+            {
+                return 0.0;
+            }
+            return FixAngle(Math.Atan2(p2.y - p1.y, p2.x - p1.x));
+        }
+
+        /// <summary>
+        /// Fixes the passed angle in radians to be between 0.0 and 2 * PI.
+        /// </summary>
+        /// <param name="inangle">A passed angle in radians to be fixed.</param>
+        /// <returns>The fixed angle in radians.</returns>
+        public static double FixAngle(double inangle)
+        {
+            double eq = 1E-06;
+            if (AreEqual(inangle, 6.2831853071796, eq))
+            {
+                return 6.2831853071796;
+            }
+            double num2 = inangle;
+            num2 = num2 % 6.2831853071796;
+            if (num2 > (6.2831853071796 + eq))
+            {
+                num2 -= 6.2831853071796;
+            }
+            if ((num2 + eq) < 0.0)
+            {
+                num2 += 6.2831853071796;
+            }
+            if (AreEqual(num2, 0.0, eq))
+            {
+                return 0.0;
+            }
+            if (AreEqual(num2, 1.5707963267948, eq))
+            {
+                return 1.5707963267948;
+            }
+            if (AreEqual(num2, 3.1415926535898, eq))
+            {
+                return 3.1415926535898;
+            }
+            if (AreEqual(num2, 4.7123889803844, eq))
+            {
+                return 4.7123889803844;
+            }
+            if (AreEqual(num2, 6.2831853071796, eq))
+            {
+                return 6.2831853071796;
+            }
+            return num2;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="xyz"></param>
+        /// <returns></returns>
+        public static TszXYZ XYZ3DTo2D(TszXYZ xyz)
+        {
+            return new TszXYZ(xyz.x, xyz.y);
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="xyz"></param>
+        /// <param name="z"></param>
+        /// <returns></returns>
+        public static TszXYZ XYZ2DTo3D(TszXYZ xyz, double z)
+        {
+            return new TszXYZ(xyz.x, xyz.y, z);
+        }
+
+        /// <summary>
+        /// Find the distance between two points
+        /// </summary>
+        /// <param name="first">the first point</param>
+        /// <param name="second">the first point</param>
+        /// <returns>the distance of two points</returns>
+        public static double FindDistance(TszXYZ first, TszXYZ second)
+        {
+            double x = first.x - second.x;
+            double y = first.y - second.y;
+            double z = first.z - second.z;
+            return Math.Sqrt(x * x + y * y + z * z);
+        }
+
+        /// <summary>
+        /// Find the distance between two points
+        /// </summary>
+        /// <param name="first">the first point</param>
+        /// <param name="second">the first point</param>
+        /// <returns>the distance of two points</returns>
+        public static double FindDistance2(TszXYZ first, TszXYZ second)
+        {
+            double x = first.x - second.x;
+            double y = first.y - second.y;
+            return Math.Sqrt(x * x + y * y);
+        }
+
+        /// <summary>
+        /// 点的平移再旋转
+        /// </summary>
+        /// <param name="pt"></param>
+        /// <param name="vecM"></param>
+        /// <param name="dAngle"></param>
+        /// <returns></returns>
+        public static TszXYZ GetXyz(TszXYZ pt,TszXYZ vecM,double dAngle)
+        {
+            TszXYZ vecMr = VectorRotate(vecM, dAngle, pt);
+            return pt + vecMr;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="ptS"></param>
+        /// <param name="ptE"></param>
+        /// <param name="dBulge"></param>
+        /// <param name="ptCenter"></param>
+        /// <param name="dRadius"></param>
+        /// <param name="dStartAngle"></param>
+        /// <param name="dEndAngle"></param>
+        public static void GetArcInfo(TszXYZ ptS, TszXYZ ptE, double dBulge,
+            out TszXYZ ptCenter, out double dRadius, out double dStartAngle, out double dEndAngle)
+        {
+            dStartAngle = 0;
+            dEndAngle = 0;
+            //半径
+            double dS = FindDistance2(ptS, ptE) / 2.0;
+            double dL = Math.Abs(dBulge) * dS;
+            dRadius = (dS * dS + dL * dL) / (dL * 2);
+            //圆心
+            TszXYZ VecArc = (ptE - ptS) / 2;
+            ptCenter = ptS + VecArc;
+            VecArc = VecArc.Normalize();
+            if (dBulge > 0)
+                VecArc = VectorRotate(VecArc, Math.PI / 2, ptCenter);
+            else
+                VecArc = VectorRotate(VecArc, -Math.PI / 2, ptCenter);
+            ptCenter = ptCenter + VecArc * (dRadius - dS * Math.Abs(dBulge));
+            //起始角
+            TszXYZ Vec = ptS - ptCenter;
+            if (dBulge < 0)
+                Vec = ptE - ptCenter;
+            dStartAngle = GetDeltaAngle(Vec);
+            //终点角
+            Vec = ptE - ptCenter;
+            if (dBulge < 0)
+                Vec = ptS - ptCenter;
+            dEndAngle = GetDeltaAngle(Vec);
+            //终点角必须大于起始角
+            if (dStartAngle > dEndAngle)
+            {
+                dEndAngle += 2 * Math.PI;
+            }
+        }
+
+        public static double GetDeltaAngle(TszXYZ vec)
+        {
+            double dRtn = 0;
+            if (vec.x == 0 || vec.y == 0)
+            {
+                if (vec.x == 0)
+                {
+                    if (vec.y > 0)
+                    {
+                        dRtn = Math.PI / 2;
+                    }
+                    else
+                    {
+                        dRtn = Math.PI / 2 + Math.PI;
+                    }
+                }
+                else
+                {
+                    if (vec.x > 0)
+                    {
+                        dRtn = 0;
+                    }
+                    else
+                    {
+                        dRtn = Math.PI;
+                    }
+                }
+            }
+            else
+            {
+                dRtn = Math.Atan(vec.y / vec.x);
+                dRtn = Math.Abs(dRtn);
+                if (vec.x > 0)
+                {
+                    if (vec.y > 0)
+                    {
+                        //1
+                        dRtn = Math.Abs(dRtn);
+                    }
+                    else
+                    {
+                        //4
+                        dRtn = (2 * Math.PI - dRtn);
+                    }
+                }
+                else
+                {
+                    if (vec.y > 0)
+                    {
+                        //2
+                        dRtn = (Math.PI - dRtn);
+                    }
+                    else
+                    {
+                        //3
+                        dRtn = (Math.PI + dRtn);
+                    }
+                }
+            }
+            return dRtn;
+        }
+
+        /// <summary>
+        /// (cosA -sinA 0 0)
+        /// (sinA cosA  0 0)
+        /// (0    0     1 0)
+        /// </summary>
+        /// <param name="vec"></param>
+        /// <param name="dAngle"></param>
+        /// <returns></returns>
+        public static TszXYZ VectorRotate(TszXYZ vec, double dAngle, TszXYZ pt)
+        {
+            TszTransform transform = new TszTransform();
+            transform.Origin = pt;
+            TszXYZ basisX = new TszXYZ(Math.Cos(dAngle), -Math.Sin(dAngle), 0);
+            TszXYZ basisY = new TszXYZ(Math.Sin(dAngle), Math.Cos(dAngle), 0);
+            TszXYZ basisZ = new TszXYZ(0, 0, 1);
+            transform.set_Basis(0, basisX);
+            transform.set_Basis(1, basisY);
+            transform.set_Basis(2, basisZ);
+            return TransformVector(vec, transform);
+        }
+
+        /// <summary>
+        /// 平移矩阵
+        /// </summary>
+        /// <param name="vec"></param>
+        /// <returns></returns>
+        public static TszTransform GetTranslation(TszXYZ vec)
+        {
+            TszTransform transform = new TszTransform();
+            transform.Origin = vec;
+            return transform;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="v"></param>
+        /// <param name="transform"></param>
+        /// <returns></returns>
+        public static TszXYZ TransformVector(TszXYZ v, TszTransform transform)
+        {
+            TszXYZ pt = TransformPoint(new TszXYZ(), transform);
+            TszXYZ ptV = TransformPoint(v, transform);
+            return SubXYZ(pt, ptV).Normalize();
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="pStart"></param>
+        /// <param name="pEnd"></param>
+        /// <param name="pCenter"></param>
+        /// <param name="dWidth"></param>
+        /// <returns></returns>
+        public static List<TszXYZ> ArcElementEdges(TszXYZ pStart, TszXYZ pEnd, TszXYZ pCenter, double dWidth)
+        {
+            List<TszXYZ> listRtn = new List<TszXYZ>();
+            double dWidthHalf = dWidth / 2;
+            TszXYZ vStart = SubXYZ(pStart, pCenter);
+            TszXYZ vEnd = SubXYZ(pEnd, pCenter);
+            listRtn.Add(pStart + vStart.Normalize() * dWidthHalf);
+            listRtn.Add(pEnd + vEnd.Normalize() * dWidthHalf);
+            listRtn.Add(pStart - vStart.Normalize() * dWidthHalf);
+            listRtn.Add(pEnd - vEnd.Normalize() * dWidthHalf);
+            return listRtn;
+        }
+        
+        /// <summary>
+        /// 弧度转角度
+        /// </summary>
+        /// <param name="dRadian"></param>
+        /// <returns></returns>
+        public static double RadianToAngle(double dRadian)
+        {
+            return dRadian * 180 / Math.PI;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <returns></returns>
+        public static bool ListContainsXyz(List<TszXYZ> listPt, TszXYZ ptAdd)
+        {
+            bool blnRtn = false;
+            foreach (TszXYZ pt in listPt)
+            {
+                if (IsEqual(pt, ptAdd))
+                {
+                    blnRtn = true;
+                    break;
+                }
+            }
+            return blnRtn;
+        }
+    }
+}

+ 103 - 0
MBI/SAGA.DotNetUtils/Geometry/TszTransform.cs

@@ -0,0 +1,103 @@
+namespace SAGA.DotNetUtils.Geometry
+{
+    public class TszTransform
+    {
+        private TszXYZ m_BasisX = new TszXYZ(1, 0, 0);
+        /// <summary>
+        /// 
+        /// </summary>
+        public TszXYZ BasisX
+        {
+            get
+            {
+                return m_BasisX;
+            }
+            set
+            {
+                m_BasisX = value;
+            }
+        }
+
+        private TszXYZ m_BasisY = new TszXYZ(0, 1, 0);
+        /// <summary>
+        /// 
+        /// </summary>
+        public TszXYZ BasisY
+        {
+            get
+            {
+                return m_BasisY;
+            }
+            set
+            {
+                m_BasisY = value;
+            }
+        }
+
+        private TszXYZ m_BasisZ = new TszXYZ(0, 0, 1);
+        /// <summary>
+        /// 
+        /// </summary>
+        public TszXYZ BasisZ
+        {
+            get
+            {
+                return m_BasisZ;
+            }
+            set
+            {
+                m_BasisZ = value;
+            }
+        }
+
+        private TszXYZ m_Origin = new TszXYZ();
+        /// <summary>
+        /// 
+        /// </summary>
+        public TszXYZ Origin
+        {
+            get
+            {
+                return m_Origin;
+            }
+            set
+            {
+                m_Origin = value;
+            }
+        }
+
+        public TszXYZ get_Basis(int index)
+        {
+            TszXYZ xyzRtn = new TszXYZ();
+            switch (index)
+            {
+                case 0:
+                    xyzRtn = BasisX;
+                    break;
+                case 1:
+                    xyzRtn = BasisY;
+                    break;
+                case 2:
+                    xyzRtn = BasisZ;
+                    break;
+            }
+            return xyzRtn;
+        }
+
+        public void set_Basis(int index, TszXYZ ifcxyz)
+        {
+            switch (index)
+            {
+                case 0:
+                    BasisX = ifcxyz;
+                    break;
+                case 1:
+                    BasisY = ifcxyz;
+                    break;
+                case 2:
+                    BasisZ = ifcxyz;
+                    break;
+            }
+        }
+    }
+}

+ 907 - 0
MBI/SAGA.DotNetUtils/Geometry/TszXYZ.cs

@@ -0,0 +1,907 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using SAGA.DotNetUtils.Extend;
+
+namespace SAGA.DotNetUtils.Geometry
+{
+    public class TszXYZ
+    {
+        internal xyz mxyz;
+
+        /// <summary>
+        /// Initializes a TszXYZ object (0.0,0.0,0.0). 
+        /// </summary>
+        public TszXYZ()
+        {
+            this.x = 0.0;
+            this.y = 0.0;
+            this.z = 0.0;
+        }
+
+        public TszXYZ(double X, double Y)
+        {
+            this.x = X;
+            this.y = Y;
+            this.z = 0;
+        }
+
+        public TszXYZ(TszXYZ pt, double Z)
+        {
+            this.x = pt.x;
+            this.y = pt.y;
+            this.z = Z;
+        }
+
+        /// <summary>
+        /// Initializes a TszXYZ object (X,Y,Z).
+        /// </summary>
+        /// <param name="X">The x coordinate of the point.</param>
+        /// <param name="Y">The y coordinate of the point.</param>
+        /// <param name="Z">The z coordinate of the point.</param>
+        public TszXYZ(double X, double Y, double Z)
+        {
+            this.x = X;
+            this.y = Y;
+            this.z = Z;
+        }
+
+        /// <summary>
+        /// Initializes a TszXYZ object at the coordinates of the pt parameter.
+        /// </summary>
+        /// <param name="pt">A TszXYZ object from which the coordinjates will be taken from.</param>
+        public TszXYZ(TszXYZ pt)
+        {
+            this.x = pt.x;
+            this.y = pt.y;
+            this.z = pt.z;
+        }
+
+        /// <summary>
+        /// The x value of the point.
+        /// </summary>
+        public double x
+        {
+            get { return this.mxyz._x; }
+            set { this.mxyz._x = value; }
+        }
+
+        /// <summary>
+        /// The y value of the point.
+        /// </summary>
+        public double y
+        {
+            get { return this.mxyz._y; }
+            set { this.mxyz._y = value; }
+        }
+
+        /// <summary>
+        /// The z value of the point.
+        /// </summary>
+        public double z
+        {
+            get { return this.mxyz._z; }
+            set { this.mxyz._z = value; }
+        }
+
+        /// <summary>
+        /// X
+        /// </summary>
+        public static TszXYZ BasisX
+        {
+            get { return new TszXYZ(1, 0, 0); }
+        }
+
+        /// <summary>
+        /// Y
+        /// </summary>
+        public static TszXYZ BasisY
+        {
+            get { return new TszXYZ(0, 1, 0); }
+        }
+
+        /// <summary>
+        /// Z
+        /// </summary>
+        public static TszXYZ BasisZ
+        {
+            get { return new TszXYZ(0, 0, 1); }
+        }
+
+        /// <summary>
+        /// Get the angle between the given point and this in radians.
+        /// </summary>
+        /// <param name="pt">The other gPoint needed.</param>
+        /// <returns>The angle in radians.</returns>
+        public double GetAngle(TszXYZ pt)
+        {
+            return TszGeoUtil.GetAngle(this, pt);
+        }
+
+        /// <summary>
+        /// Implements the + operator for two gPoints.
+        /// </summary>
+        /// <param name="p"></param>
+        /// <param name="pt"></param>
+        /// <returns></returns>
+        public static TszXYZ operator +(TszXYZ p, TszXYZ pt)
+        {
+            TszXYZ point = new TszXYZ();
+            point.x = p.x + pt.x;
+            point.y = p.y + pt.y;
+            point.z = p.z + pt.z;
+            return point;
+        }
+
+        /// <summary>
+        /// Implements the / operator for two gPoints.
+        /// </summary>
+        /// <param name="p"></param>
+        /// <param name="value"></param>
+        /// <returns></returns>
+        public static TszXYZ operator /(TszXYZ p, double value)
+        {
+            TszXYZ point = new TszXYZ();
+            point.x = p.x/value;
+            point.y = p.y/value;
+            point.z = p.z/value;
+            return point;
+        }
+
+        /// <summary>
+        /// Implements the == operator for two gPoints.
+        /// </summary>
+        /// <param name="a"></param>
+        /// <param name="b"></param>
+        /// <returns></returns>
+        public static bool operator ==(TszXYZ a, TszXYZ b)
+        {
+            return (ReferenceEquals(a, b) || (((null != a) && (null != b)) && a.Equals(b)));
+        }
+
+        /// <summary>
+        /// Implements the != operator for two gPoints.
+        /// </summary>
+        /// <param name="obj1"></param>
+        /// <param name="obj2"></param>
+        /// <returns></returns>
+        public static bool operator !=(TszXYZ obj1, TszXYZ obj2)
+        {
+            return !(obj1 == obj2);
+        }
+
+        /// <summary>
+        /// Implements the * operator for a TszXYZ with a double value.
+        /// </summary>
+        /// <param name="value"></param>
+        /// <param name="p"></param>
+        /// <returns></returns>
+        public static TszXYZ operator *(double value, TszXYZ p)
+        {
+            TszXYZ point = new TszXYZ();
+            point.x = p.x*value;
+            point.y = p.y*value;
+            point.z = p.z*value;
+            return point;
+        }
+
+        /// <summary>
+        /// Implements the * operator for two gPoints.
+        /// </summary>
+        /// <param name="p"></param>
+        /// <param name="value"></param>
+        /// <returns></returns>
+        public static TszXYZ operator *(TszXYZ p, double value)
+        {
+            TszXYZ point = new TszXYZ();
+            point.x = p.x*value;
+            point.y = p.y*value;
+            point.z = p.z*value;
+            return point;
+        }
+
+        /// <summary>
+        /// Implements the - operator for two gPoints.
+        /// </summary>
+        /// <param name="p"></param>
+        /// <param name="pt"></param>
+        /// <returns></returns>
+        public static TszXYZ operator -(TszXYZ p, TszXYZ pt)
+        {
+            TszXYZ point = new TszXYZ();
+            point.x = p.x - pt.x;
+            point.y = p.y - pt.y;
+            point.z = p.z - pt.z;
+            return point;
+        }
+
+        /// <summary>
+        /// Serves as a hash function for the collection.
+        /// </summary>
+        /// <returns></returns>
+        public override int GetHashCode()
+        {
+            return ((this.x.GetHashCode() ^ this.y.GetHashCode()) ^ this.z.GetHashCode());
+        }
+
+        /// <summary>
+        /// Checks if the parameter object is equal to this object.
+        /// </summary>
+        /// <param name="obj">An object to be checked if it is equal with this TszXYZ object.</param>
+        /// <returns>True if the objects are equal.</returns>
+        public override bool Equals(object obj)
+        {
+            if (obj == null)
+            {
+                return false;
+            }
+            TszXYZ p = obj as TszXYZ;
+            return this.Equals(p);
+        }
+
+        public override string ToString()
+        {
+            return string.Format("({0},{1},{2})", this.x, this.y, this.z);
+        }
+
+        /// <summary>
+        /// 相等判断
+        /// </summary>
+        /// <param name="p"></param>
+        /// <param name="dTol"></param>
+        /// <returns></returns>
+        public bool Equals(TszXYZ p, double dTol = 0)
+        {
+            if (p == null)
+            {
+                return false;
+            }
+            return (((this.x.IsEqual(p.x, dTol)) && (this.y.IsEqual(p.y, dTol))) && (this.z.IsEqual(p.z, dTol)));
+        }
+
+        /// <summary>
+        /// Convert this Vector to one unit length.
+        /// </summary>
+        public TszXYZ Normalize()
+        {
+            double dX = 0;
+            double dY = 0;
+            double dZ = 0;
+            double num = Math.Sqrt(((x*x) + (y*y)) + (z*z));
+            if (TszGeoUtil.AreEqual(num, 0.0, 1E-08))
+            {
+                dX = 0.0;
+                dY = 0.0;
+                dZ = 1.0;
+            }
+            else
+            {
+                dX = x/num;
+                dY = y/num;
+                dZ = z/num;
+                if (TszGeoUtil.AreEqual(dX, 0.0, 1E-08))
+                {
+                    dX = 0.0;
+                }
+                if (TszGeoUtil.AreEqual(dX, 1.0, 1E-08))
+                {
+                    dX = 1.0;
+                }
+                if (TszGeoUtil.AreEqual(dY, 0.0, 1E-08))
+                {
+                    dY = 0.0;
+                }
+                if (TszGeoUtil.AreEqual(dY, 1.0, 1E-08))
+                {
+                    dY = 1.0;
+                }
+                if (TszGeoUtil.AreEqual(dZ, 0.0, 1E-08))
+                {
+                    dZ = 0.0;
+                }
+                if (TszGeoUtil.AreEqual(dZ, 1.0, 1E-08))
+                {
+                    dZ = 1.0;
+                }
+            }
+            return new TszXYZ(dX, dY, dZ);
+        }
+
+        /// <summary>
+        /// Changes this Vector regarding the crossing operation with another Vector.
+        /// </summary>
+        /// <param name="other">A Vector object required for the operation.</param>
+        public void Cross(TszXYZ other)
+        {
+            double num = (y*other.z) - (other.y*z);
+            double num2 = (z*other.x) - (other.z*x);
+            double num3 = (x*other.y) - (other.x*y);
+            x = num;
+            y = num2;
+            z = num3;
+        }
+
+        /// <summary>
+        /// Calculates and returns a Vector produced by crossing two other Vectors.
+        /// </summary>
+        /// <param name="v1">First Vector used.</param>
+        /// <param name="v2">Second Vector used.</param>
+        /// <returns>A Vector as a crossing result from the passed two vectors.</returns>
+        public static TszXYZ CrossProduct(TszXYZ v1, TszXYZ v2)
+        {
+            TszXYZ vector = new TszXYZ(v1);
+            vector.Cross(v2);
+            return vector;
+        }
+
+        /// <summary>
+        /// Check if the passed TszXYZ has equal x,y,z values with this object.
+        /// </summary>
+        /// <param name="pt">A TszXYZ to be checked if it is equal to this object.</param>
+        /// <param name="Equality">A double value representing the equality(for example 0.00001).</param>
+        /// <returns>True if the x,y,z values are equal.</returns>
+        public bool AreEqual(TszXYZ pt, double Equality)
+        {
+            return ((((pt != null) && TszGeoUtil.AreEqual(this.x, pt.x, Equality)) &&
+                     TszGeoUtil.AreEqual(this.y, pt.y, Equality)) && TszGeoUtil.AreEqual(this.z, pt.z, Equality));
+        }
+
+        /// <summary>
+        /// Returns the distance between this TszXYZ and the parameter.The z is not taken into consideration.
+        /// </summary>
+        /// <param name="pt">A TszXYZ needed for the calculation of the distance.</param>
+        /// <returns>The 2D distance between the two points.</returns>
+        public virtual double FindDistance2(TszXYZ pt)
+        {
+            return Math.Sqrt(((this.x - pt.x)*(this.x - pt.x)) + ((this.y - pt.y)*(this.y - pt.y)));
+        }
+
+        /// <summary>
+        /// Calculates the 2D distance between two gPoints.
+        /// </summary>
+        /// <param name="fromThis">First TszXYZ needed.</param>
+        /// <param name="toThis">Second TszXYZ needed.</param>
+        /// <returns>The 2D distance between the two given gPoints.</returns>
+        public static double FindDistance2(TszXYZ fromThis, TszXYZ toThis)
+        {
+            return
+                Math.Sqrt(((fromThis.x - toThis.x)*(fromThis.x - toThis.x)) +
+                          ((fromThis.y - toThis.y)*(fromThis.y - toThis.y)));
+        }
+
+        /// <summary>
+        /// Returns the distance between this TszXYZ and the parameter.
+        /// </summary>
+        /// <param name="other">A TszXYZ needed for the calculation of the distance.</param>
+        /// <returns>The distance between the two points.</returns>
+        public virtual double Distance3D(TszXYZ other)
+        {
+            return Math.Sqrt(this.DistanceSquared(other));
+        }
+
+        /// <summary>
+        /// Calculates the distance between two gPoints.
+        /// </summary>
+        /// <param name="fromThis">First TszXYZ needed.</param>
+        /// <param name="toThis">Second TszXYZ needed.</param>
+        /// <returns>The distance between the two given gPoints.</returns>
+        public static double Distance3D(TszXYZ fromThis, TszXYZ toThis)
+        {
+            return Math.Sqrt(DistanceSquared(fromThis, toThis));
+        }
+
+        /// <summary>
+        /// Returns the square of the distance between two gPoints.
+        /// </summary>
+        /// <param name="other">The other TszXYZ object.</param>
+        /// <returns>The square of distance between the given TszXYZ and this one.</returns>
+        public virtual double DistanceSquared(TszXYZ other)
+        {
+            double num = other.x - this.x;
+            double num2 = other.y - this.y;
+            double num3 = other.z - this.z;
+            return (((num*num) + (num2*num2)) + (num3*num3));
+        }
+
+        /// <summary>
+        /// Calculate the squared distance between two gPoints.
+        /// </summary>
+        /// <param name="fromThis">First TszXYZ needed.</param>
+        /// <param name="toThis">Second TszXYZ needed</param>
+        /// <returns>The squared distance between the two given gPoints.</returns>
+        public static double DistanceSquared(TszXYZ fromThis, TszXYZ toThis)
+        {
+            double num = toThis.x - fromThis.x;
+            double num2 = toThis.y - fromThis.y;
+            double num3 = toThis.z - fromThis.z;
+            return (((num*num) + (num2*num2)) + (num3*num3));
+        }
+
+        public TszXYZ Round()
+        {
+            return new TszXYZ(x.Round(), y.Round(), z.Round());
+        }
+
+        public TszXYZ NewZ(double dZ)
+        {
+            return new TszXYZ(x, y, dZ);
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        internal struct xyz
+        {
+            internal double _x;
+            internal double _y;
+            internal double _z;
+        }
+    }
+
+    public class TszXYZComparer : IComparer<TszXYZ>
+    {
+        /// <summary>
+        /// 左下、右上
+        /// </summary>
+        /// <param name="first"></param>
+        /// <param name="second"></param>
+        /// <returns></returns>
+        int IComparer<TszXYZ>.Compare(TszXYZ first, TszXYZ second)
+        {
+            // first compare z coordinate, then y coordinate, at last x coordinate
+            if (TszGeoUtil.IsEqual(first.z, second.z))
+            {
+                if (TszGeoUtil.IsEqual(first.y, second.y))
+                {
+                    if (TszGeoUtil.IsEqual(first.x, second.x))
+                    {
+                        return 0;
+                    }
+                    return (first.x > second.x) ? 1 : -1;
+                }
+                return (first.y > second.y) ? 1 : -1;
+            }
+            return (first.z > second.z) ? 1 : -1;
+        }
+    }
+
+    public class TszVector
+    {
+        internal xyz mxyz;
+
+        /// <summary>
+        /// Initializes a TszVector object (0.0,0.0,0.0). 
+        /// </summary>
+        public TszVector()
+        {
+            this.x = 0.0;
+            this.y = 0.0;
+            this.z = 0.0;
+        }
+
+        public TszVector(double X, double Y)
+        {
+            this.x = X;
+            this.y = Y;
+            this.z = 0;
+        }
+
+        public TszVector(TszVector pt, double Z)
+        {
+            this.x = pt.x;
+            this.y = pt.y;
+            this.z = Z;
+        }
+
+        /// <summary>
+        /// Initializes a TszVector object (X,Y,Z).
+        /// </summary>
+        /// <param name="X">The x coordinate of the point.</param>
+        /// <param name="Y">The y coordinate of the point.</param>
+        /// <param name="Z">The z coordinate of the point.</param>
+        public TszVector(double X, double Y, double Z)
+        {
+            this.x = X;
+            this.y = Y;
+            this.z = Z;
+        }
+
+        /// <summary>
+        /// Initializes a TszVector object at the coordinates of the pt parameter.
+        /// </summary>
+        /// <param name="pt">A TszVector object from which the coordinjates will be taken from.</param>
+        public TszVector(TszVector pt)
+        {
+            this.x = pt.x;
+            this.y = pt.y;
+            this.z = pt.z;
+        }
+
+        /// <summary>
+        /// The x value of the point.
+        /// </summary>
+        public double x
+        {
+            get { return this.mxyz._x; }
+            set { this.mxyz._x = value; }
+        }
+
+        /// <summary>
+        /// The y value of the point.
+        /// </summary>
+        public double y
+        {
+            get { return this.mxyz._y; }
+            set { this.mxyz._y = value; }
+        }
+
+        /// <summary>
+        /// The z value of the point.
+        /// </summary>
+        public double z
+        {
+            get { return this.mxyz._z; }
+            set { this.mxyz._z = value; }
+        }
+
+        /// <summary>
+        /// X
+        /// </summary>
+        public static TszVector BasisX
+        {
+            get { return new TszVector(1, 0, 0); }
+        }
+
+        /// <summary>
+        /// Y
+        /// </summary>
+        public static TszVector BasisY
+        {
+            get { return new TszVector(0, 1, 0); }
+        }
+
+        /// <summary>
+        /// Z
+        /// </summary>
+        public static TszVector BasisZ
+        {
+            get { return new TszVector(0, 0, 1); }
+        }
+
+        /// <summary>
+        /// Implements the + operator for two gPoints.
+        /// </summary>
+        /// <param name="p"></param>
+        /// <param name="pt"></param>
+        /// <returns></returns>
+        public static TszVector operator +(TszVector p, TszVector pt)
+        {
+            TszVector point = new TszVector();
+            point.x = p.x + pt.x;
+            point.y = p.y + pt.y;
+            point.z = p.z + pt.z;
+            return point;
+        }
+
+        /// <summary>
+        /// Implements the / operator for two gPoints.
+        /// </summary>
+        /// <param name="p"></param>
+        /// <param name="value"></param>
+        /// <returns></returns>
+        public static TszVector operator /(TszVector p, double value)
+        {
+            TszVector point = new TszVector();
+            point.x = p.x/value;
+            point.y = p.y/value;
+            point.z = p.z/value;
+            return point;
+        }
+
+        /// <summary>
+        /// Implements the == operator for two gPoints.
+        /// </summary>
+        /// <param name="a"></param>
+        /// <param name="b"></param>
+        /// <returns></returns>
+        public static bool operator ==(TszVector a, TszVector b)
+        {
+            return (ReferenceEquals(a, b) || (((null != a) && (null != b)) && a.Equals(b)));
+        }
+
+        /// <summary>
+        /// Implements the != operator for two gPoints.
+        /// </summary>
+        /// <param name="obj1"></param>
+        /// <param name="obj2"></param>
+        /// <returns></returns>
+        public static bool operator !=(TszVector obj1, TszVector obj2)
+        {
+            return !(obj1 == obj2);
+        }
+
+        /// <summary>
+        /// Implements the * operator for a TszVector with a double value.
+        /// </summary>
+        /// <param name="value"></param>
+        /// <param name="p"></param>
+        /// <returns></returns>
+        public static TszVector operator *(double value, TszVector p)
+        {
+            TszVector point = new TszVector();
+            point.x = p.x*value;
+            point.y = p.y*value;
+            point.z = p.z*value;
+            return point;
+        }
+
+        /// <summary>
+        /// Implements the * operator for two gPoints.
+        /// </summary>
+        /// <param name="p"></param>
+        /// <param name="value"></param>
+        /// <returns></returns>
+        public static TszVector operator *(TszVector p, double value)
+        {
+            TszVector point = new TszVector();
+            point.x = p.x*value;
+            point.y = p.y*value;
+            point.z = p.z*value;
+            return point;
+        }
+
+        /// <summary>
+        /// Implements the - operator for two gPoints.
+        /// </summary>
+        /// <param name="p"></param>
+        /// <param name="pt"></param>
+        /// <returns></returns>
+        public static TszVector operator -(TszVector p, TszVector pt)
+        {
+            TszVector point = new TszVector();
+            point.x = p.x - pt.x;
+            point.y = p.y - pt.y;
+            point.z = p.z - pt.z;
+            return point;
+        }
+
+        /// <summary>
+        /// Serves as a hash function for the collection.
+        /// </summary>
+        /// <returns></returns>
+        public override int GetHashCode()
+        {
+            return ((this.x.GetHashCode() ^ this.y.GetHashCode()) ^ this.z.GetHashCode());
+        }
+
+        /// <summary>
+        /// Checks if the parameter object is equal to this object.
+        /// </summary>
+        /// <param name="obj">An object to be checked if it is equal with this TszVector object.</param>
+        /// <returns>True if the objects are equal.</returns>
+        public override bool Equals(object obj)
+        {
+            if (obj == null)
+            {
+                return false;
+            }
+            TszVector p = obj as TszVector;
+            return this.Equals(p);
+        }
+
+        /// <summary>
+        /// Checks if the parameter TszVector object is equal to this object.
+        /// </summary>
+        /// <param name="p">A TszVector object to be checked if the x,y,z values are the same with this object's values.</param>
+        /// <returns>True if all x,y,z values are equal.</returns>
+        public bool Equals(TszVector p)
+        {
+            if (p == null)
+            {
+                return false;
+            }
+            return (((this.x == p.x) && (this.y == p.y)) && (this.z == p.z));
+        }
+
+        /// <summary>
+        /// Convert this Vector to one unit length.
+        /// </summary>
+        public TszVector Normalize()
+        {
+            double dX = 0;
+            double dY = 0;
+            double dZ = 0;
+            double num = Math.Sqrt(((x*x) + (y*y)) + (z*z));
+            if (TszGeoUtil.AreEqual(num, 0.0, 1E-08))
+            {
+                dX = 0.0;
+                dY = 0.0;
+                dZ = 1.0;
+            }
+            else
+            {
+                dX = x/num;
+                dY = y/num;
+                dZ = z/num;
+                if (TszGeoUtil.AreEqual(dX, 0.0, 1E-08))
+                {
+                    dX = 0.0;
+                }
+                if (TszGeoUtil.AreEqual(dX, 1.0, 1E-08))
+                {
+                    dX = 1.0;
+                }
+                if (TszGeoUtil.AreEqual(dY, 0.0, 1E-08))
+                {
+                    dY = 0.0;
+                }
+                if (TszGeoUtil.AreEqual(dY, 1.0, 1E-08))
+                {
+                    dY = 1.0;
+                }
+                if (TszGeoUtil.AreEqual(dZ, 0.0, 1E-08))
+                {
+                    dZ = 0.0;
+                }
+                if (TszGeoUtil.AreEqual(dZ, 1.0, 1E-08))
+                {
+                    dZ = 1.0;
+                }
+            }
+            return new TszVector(dX, dY, dZ);
+        }
+
+        /// <summary>
+        /// Changes this Vector regarding the crossing operation with another Vector.
+        /// </summary>
+        /// <param name="other">A Vector object required for the operation.</param>
+        public void Cross(TszVector other)
+        {
+            double num = (y*other.z) - (other.y*z);
+            double num2 = (z*other.x) - (other.z*x);
+            double num3 = (x*other.y) - (other.x*y);
+            x = num;
+            y = num2;
+            z = num3;
+        }
+
+        /// <summary>
+        /// Calculates and returns a Vector produced by crossing two other Vectors.
+        /// </summary>
+        /// <param name="v1">First Vector used.</param>
+        /// <param name="v2">Second Vector used.</param>
+        /// <returns>A Vector as a crossing result from the passed two vectors.</returns>
+        public static TszVector CrossProduct(TszVector v1, TszVector v2)
+        {
+            TszVector vector = new TszVector(v1);
+            vector.Cross(v2);
+            return vector;
+        }
+
+        /// <summary>
+        /// Check if the passed TszVector has equal x,y,z values with this object.
+        /// </summary>
+        /// <param name="pt">A TszVector to be checked if it is equal to this object.</param>
+        /// <param name="Equality">A double value representing the equality(for example 0.00001).</param>
+        /// <returns>True if the x,y,z values are equal.</returns>
+        public bool AreEqual(TszVector pt, double Equality)
+        {
+            return ((((pt != null) && TszGeoUtil.AreEqual(this.x, pt.x, Equality)) &&
+                     TszGeoUtil.AreEqual(this.y, pt.y, Equality)) && TszGeoUtil.AreEqual(this.z, pt.z, Equality));
+        }
+
+        /// <summary>
+        /// Returns the distance between this TszVector and the parameter.The z is not taken into consideration.
+        /// </summary>
+        /// <param name="pt">A TszVector needed for the calculation of the distance.</param>
+        /// <returns>The 2D distance between the two points.</returns>
+        public virtual double FindDistance2(TszVector pt)
+        {
+            return Math.Sqrt(((this.x - pt.x)*(this.x - pt.x)) + ((this.y - pt.y)*(this.y - pt.y)));
+        }
+
+        /// <summary>
+        /// Calculates the 2D distance between two gPoints.
+        /// </summary>
+        /// <param name="fromThis">First TszVector needed.</param>
+        /// <param name="toThis">Second TszVector needed.</param>
+        /// <returns>The 2D distance between the two given gPoints.</returns>
+        public static double FindDistance2(TszVector fromThis, TszVector toThis)
+        {
+            return
+                Math.Sqrt(((fromThis.x - toThis.x)*(fromThis.x - toThis.x)) +
+                          ((fromThis.y - toThis.y)*(fromThis.y - toThis.y)));
+        }
+
+        /// <summary>
+        /// Returns the distance between this TszVector and the parameter.
+        /// </summary>
+        /// <param name="other">A TszVector needed for the calculation of the distance.</param>
+        /// <returns>The distance between the two points.</returns>
+        public virtual double Distance3D(TszVector other)
+        {
+            return Math.Sqrt(this.DistanceSquared(other));
+        }
+
+        /// <summary>
+        /// Calculates the distance between two gPoints.
+        /// </summary>
+        /// <param name="fromThis">First TszVector needed.</param>
+        /// <param name="toThis">Second TszVector needed.</param>
+        /// <returns>The distance between the two given gPoints.</returns>
+        public static double Distance3D(TszVector fromThis, TszVector toThis)
+        {
+            return Math.Sqrt(DistanceSquared(fromThis, toThis));
+        }
+
+        /// <summary>
+        /// Returns the square of the distance between two gPoints.
+        /// </summary>
+        /// <param name="other">The other TszVector object.</param>
+        /// <returns>The square of distance between the given TszVector and this one.</returns>
+        public virtual double DistanceSquared(TszVector other)
+        {
+            double num = other.x - this.x;
+            double num2 = other.y - this.y;
+            double num3 = other.z - this.z;
+            return (((num*num) + (num2*num2)) + (num3*num3));
+        }
+
+        /// <summary>
+        /// Calculate the squared distance between two gPoints.
+        /// </summary>
+        /// <param name="fromThis">First TszVector needed.</param>
+        /// <param name="toThis">Second TszVector needed</param>
+        /// <returns>The squared distance between the two given gPoints.</returns>
+        public static double DistanceSquared(TszVector fromThis, TszVector toThis)
+        {
+            double num = toThis.x - fromThis.x;
+            double num2 = toThis.y - fromThis.y;
+            double num3 = toThis.z - fromThis.z;
+            return (((num*num) + (num2*num2)) + (num3*num3));
+        }
+
+        public TszVector Round()
+        {
+            return new TszVector(x.Round(), y.Round(), z.Round());
+        }
+
+        public TszVector NewZ(double dZ)
+        {
+            return new TszVector(x, y, dZ);
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        internal struct xyz
+        {
+            internal double _x;
+            internal double _y;
+            internal double _z;
+        }
+    }
+
+    public class VectorComparer : IComparer<TszVector>
+    {
+        /// <summary>
+        /// 左下、右上
+        /// </summary>
+        /// <param name="first"></param>
+        /// <param name="second"></param>
+        /// <returns></returns>
+        int IComparer<TszVector>.Compare(TszVector first, TszVector second)
+        {
+            // first compare z coordinate, then y coordinate, at last x coordinate
+            if (TszGeoUtil.IsEqual(first.z, second.z))
+            {
+                if (TszGeoUtil.IsEqual(first.y, second.y))
+                {
+                    if (TszGeoUtil.IsEqual(first.x, second.x))
+                    {
+                        return 0;
+                    }
+                    return (first.x > second.x) ? 1 : -1;
+                }
+                return (first.y > second.y) ? 1 : -1;
+            }
+            return (first.z > second.z) ? 1 : -1;
+        }
+    }
+}

+ 63 - 0
MBI/SAGA.DotNetUtils/Geometry/TwoPointRelation.cs

@@ -0,0 +1,63 @@
+/////////////////////////////////////////////
+//Copyright (c) 2011, 北京探索者软件公司
+//All rights reserved.       
+//文件名称: 
+//文件描述: 
+//创 建 者: mjy
+//创建日期: 2011-11-02
+//版 本 号:4.0.0.0  
+/////////////////////////////////////////////
+
+using System.Drawing;
+
+namespace SAGA.DotNetUtils.Geometry
+{
+    public class TwoPointRelation
+    {
+        private PointF fix;
+        private PointF other;
+        public TwoPointRelation(PointF fix, PointF other)
+        {
+            this.fix = fix;
+            this.other = other;
+        }
+
+        public RelationOptions RelationGraphics
+        {
+            get
+            {
+                if (other.X >= fix.X)
+                {
+                    if (other.Y >= fix.Y)
+                        return RelationOptions.RightDown;
+                    return RelationOptions.RightUp;
+                }
+                else
+                {
+                    if (other.Y >= fix.Y)
+                        return RelationOptions.LeftDown;
+                    return RelationOptions.LeftUp;
+                }
+            }
+        }
+
+        public RelationOptions RelationCAD
+        {
+            get
+            {
+                if (other.X >= fix.X)
+                {
+                    if (other.Y >= fix.Y)
+                        return RelationOptions.RightUp;
+                    return RelationOptions.RightDown;
+                }
+                else
+                {
+                    if (other.Y >= fix.Y)
+                        return RelationOptions.LeftUp;
+                    return RelationOptions.LeftDown;
+                }
+            }
+        }        
+    }
+}

+ 89 - 0
MBI/SAGA.DotNetUtils/Geometry/VTwoPointRelation.cs

@@ -0,0 +1,89 @@
+/////////////////////////////////////////////
+//Copyright (c) 2011, 北京探索者软件公司
+//All rights reserved.       
+//文件名称: 
+//文件描述: 
+//创 建 者: mjy
+//创建日期: 2011-11-02
+//版 本 号:4.0.0.0  
+/////////////////////////////////////////////
+
+using System;
+using System.Drawing;
+
+namespace SAGA.DotNetUtils.Geometry
+{
+   public class VTwoPointRelation
+    {
+        private PointF fix;
+        private PointF other;
+        public VTwoPointRelation(PointF fix, PointF other)
+        {
+            this.fix = fix;
+            this.other = other;
+        }
+
+        public PointF Fix { get { return fix; } }
+        public PointF Other { get { return other; } }
+        public double Distance
+        {
+            get
+            {
+                return Geometry2D.Dist(fix.ToPointD(), other.ToPointD());
+            }
+        }
+
+        public RelationOptions RelationGraphics
+        {
+            get
+            {
+                if (fix == other)
+                    return RelationOptions.Override;
+                if (other.Y > fix.Y)
+                {
+                    return RelationOptions.Down;
+                }
+                else
+                {
+                    return RelationOptions.Up;
+                }
+            }
+        }
+
+        public RelationOptions RelationCAD
+        {
+            get
+            {
+                if (fix == other)
+                    return RelationOptions.Override;
+                if (other.Y > fix.Y)
+                {
+                    return RelationOptions.Up;
+                }
+                else
+                {
+                    return RelationOptions.Down;
+                }
+            }
+        }
+
+        public PointF VOther
+        {
+            get
+            {
+                return new PointF(fix.X, other.Y);
+            }
+        }
+
+        public double VDistance
+        {
+            get
+            {
+                double d = Math.Abs(other.Y - fix.Y);
+                if (d < 0.000001d)
+                    return 0d;
+                return d;
+            }
+        }
+    }
+}

+ 10 - 0
MBI/SAGA.DotNetUtils/SAGA.DotNetUtils.csproj

@@ -323,6 +323,16 @@
     <Compile Include="FileOperate\FileStreamOperate.cs" />
     <Compile Include="Extend\IEnumerableExtend.cs" />
     <Compile Include="Extend\IntExt.cs" />
+    <Compile Include="Geometry\Extends.cs" />
+    <Compile Include="Geometry\Geometry2d.cs" />
+    <Compile Include="Geometry\HTwoPointRelation.cs" />
+    <Compile Include="Geometry\OffsetPolyLine.cs" />
+    <Compile Include="Geometry\RelationOptions.cs" />
+    <Compile Include="Geometry\TszGeoUtil.cs" />
+    <Compile Include="Geometry\TszTransform.cs" />
+    <Compile Include="Geometry\TszXYZ.cs" />
+    <Compile Include="Geometry\TwoPointRelation.cs" />
+    <Compile Include="Geometry\VTwoPointRelation.cs" />
     <Compile Include="Hook\ActivityHookImpl.cs" />
     <Compile Include="Hook\IActivityHook.cs" />
     <Compile Include="Hook\KeyBordHook.cs" />

+ 4 - 3
MBI/SAGA.MBI/Calc/ObjectCalc.cs

@@ -165,6 +165,7 @@ namespace SAGA.MBI.Calc
         private static void CalcEquipPartRlt(CalcContext context)
         {
             var familyInstances = context.RevitDoc.GetFamilyInstances();
+            var rspaces = context.RevitDoc.GetSpaces().Where(t => t.IsValidObject).ToList();
             List<FamilyInstance> parts = new List<FamilyInstance>();
             foreach (FamilyInstance fi in familyInstances)
             {
@@ -177,7 +178,7 @@ namespace SAGA.MBI.Calc
                     context.MEquipments.Add(equipment);
 
                     //识别设备所在空间
-                    var space = fi.GetReferenceSpace();
+                    var space = fi.GetReferenceSpace(rspaces);
                     if (space == null) continue;
                     string spaceId = space.GetCloudBIMId();
                     MISpace mSpace = context.MSpaces.FirstOrDefault(t => t.BimID == spaceId);
@@ -197,7 +198,7 @@ namespace SAGA.MBI.Calc
                     context.MBeacons.Add(mode);
 
                     //识别信标所在元空间
-                    var space = fi.GetReferenceSpace();
+                    var space = fi.GetReferenceSpace(rspaces);
                     if (space == null) continue;
                     string spaceId = space.GetCloudBIMId();
                     MISpace mSpace = context.MSpaces.FirstOrDefault(t => t.BimID == spaceId);
@@ -222,7 +223,7 @@ namespace SAGA.MBI.Calc
                 context.MEquipmentParts.Add(equipment);
 
                 //识别设备所在空间
-                var space = fi.GetReferenceSpace();
+                var space = fi.GetReferenceSpace(rspaces);
                 if (space == null) continue;
                 string spaceId = space.GetCloudBIMId();
                 MISpace mSpace = context.MSpaces.FirstOrDefault(t => t.BimID == spaceId);

+ 1 - 115
MBI/SAGA.MBI/DataArrange/DalUploadFloor.cs

@@ -450,121 +450,7 @@ namespace SAGA.MBI.DataArrange
             }
             return list;
         }
-        /// <summary>
-        /// 关闭revit文件
-        /// </summary>
-        /// <param name="uploadFloors"></param>
-        /// <returns></returns>
-        public static ObservableCollection<MTopologyGriph> CloseFloorDoc(ObservableCollection<UploadFloor> uploadFloors)
-        {
-            ObservableCollection<MTopologyGriph> list = new ObservableCollection<MTopologyGriph>();
-            foreach (var uploadFloor in uploadFloors)
-            {
-                uploadFloor.CalcContext?.RevitDoc.CloseDoc();
-            }
-            return list;
-        }
-        /// <summary>
-        /// 处理设备所在空间
-        /// </summary>
-        /// <param name="context"></param>
-        private static void CheckEquipSpaceRlt(CalcContext context)
-        {
-            //设备
-            foreach (MEquipment equip in context.MEquipments)
-            {
-                OperateEquipInSpace(equip, context);
-            }
-            //部件
-            foreach (MEquipmentPart equip in context.MEquipmentParts)
-            {
-                OperateEquipInSpace(equip, context);
-            }
-            //信标
-            foreach (MBeacon mode in context.MBeacons)
-            {
-                OperateRltBeaconinElementSp(mode, context);
-            }
-        }
-        /// <summary>
-        /// 处理设备所在空间
-        /// </summary>
-        /// <param name="mode"></param>
-        /// <param name="context"></param>
-        private static void OperateEquipInSpace(MRevitEquipBase mode, CalcContext context)
-        {
-            //if (mode.Operator == DocumentChangedOperator.None) return;
-            var revitId = mode.BimID.GetBIMID();
-            if (revitId == 0) return;
-            var fi = context.RevitDoc.GetElement(revitId) as FamilyInstance;
-            Autodesk.Revit.DB.Mechanical.Space space = fi?.GetReferenceSpace();
-            if (space == null) return;
-            //查询有没有Space对象
-            string spaceId = space.GetCloudBIMId();
-            var mspace = context.MSpaces.FirstOrDefault(t => t.BimID == spaceId);
-            if (mspace == null) return;
-            switch (mode.Operator)
-            {
-                case DocumentChangedOperator.Add:
-                    context.RltEquipInSpaces.Add(new RltEquipInSpace(mspace, mode) { Operator = DocumentChangedOperator.Add });
-                    break;
-                case DocumentChangedOperator.Delete:
-                    context.RltEquipInSpaces.Add(new RltEquipInSpace(null, mode) { Operator = DocumentChangedOperator.Delete });
-                    break;
-                case DocumentChangedOperator.Modified:
-                    //修改为,先删除,再新建
-                    context.RltEquipInSpaces.Add(new RltEquipInSpace(null, mode) { Operator = DocumentChangedOperator.Delete });
-                    context.RltEquipInSpaces.Add(new RltEquipInSpace(mspace, mode) { Operator = DocumentChangedOperator.Add });
-                    break;
-                case DocumentChangedOperator.None:
-                    //空间更改可能不引起设备修改,所以设备所在元空间关系跟据元空间状态重新计算。
-                    if (mspace.Operator == DocumentChangedOperator.Add ||
-                        mspace.Operator == DocumentChangedOperator.Modified)
-                    {
-                        context.RltEquipInSpaces.Add(new RltEquipInSpace(null, mode) { Operator = DocumentChangedOperator.Delete });
-                        context.RltEquipInSpaces.Add(new RltEquipInSpace(mspace, mode) { Operator = DocumentChangedOperator.Add });
-                    }
-                    else if (mspace.Operator == DocumentChangedOperator.Delete)
-                    {
-                        context.RltEquipInSpaces.Add(new RltEquipInSpace(null, mode) { Operator = DocumentChangedOperator.Delete });
-                    }
-                    break;
-            }
-        }
-
-        /// <summary>
-        /// 信标所在元空间
-        /// </summary>
-        /// <param name="mode"></param>
-        /// <param name="context"></param>
-        private static void OperateRltBeaconinElementSp(MRevitEquipBase mode, CalcContext context)
-        {
-            if (mode.Operator == DocumentChangedOperator.None) return;
-            var revitId = mode.BimID.GetBIMID();
-            var fi = context.RevitDoc.GetElement(revitId) as FamilyInstance;
-            Autodesk.Revit.DB.Mechanical.Space space = fi?.Space;
-            if (space == null) return;
-            //查询有没有Space对象
-            string spaceId = space.GetCloudBIMId();
-            var mspace = context.MSpaces.FirstOrDefault(t => t.BimID == spaceId);
-            if (mspace == null) return;
-            switch (mode.Operator)
-            {
-                case DocumentChangedOperator.Add:
-                    context.RltBeaconinElementSps.Add(new RltBeaconinElementSp(mspace, mode) { Operator = DocumentChangedOperator.Add });
-                    break;
-                case DocumentChangedOperator.Modified:
-                    //修改为,先删除,再新建
-                    context.RltBeaconinElementSps.Add(new RltBeaconinElementSp(null, mode) { Operator = DocumentChangedOperator.Delete });
-                    context.RltBeaconinElementSps.Add(new RltBeaconinElementSp(mspace, mode) { Operator = DocumentChangedOperator.Add });
-                    break;
-                case DocumentChangedOperator.Delete:
-                    context.RltBeaconinElementSps.Add(new RltBeaconinElementSp(null, mode) { Operator = DocumentChangedOperator.Delete });
-                    break;
-            }
-        }
-
-
+       
         /// <summary>
         /// 上传
         /// </summary>

+ 4 - 12
MBI/SAGA.MBI/Extend/ElementExtend.cs

@@ -188,14 +188,13 @@ namespace SAGA.MBI.Tools
         /// </summary>
         /// <param name="fi"></param>
         /// <returns></returns>
-        public static Space GetReferenceSpace(this FamilyInstance fi)
+        public static Space GetReferenceSpace(this FamilyInstance fi, List<Space> spaces = null)
         {
             Space space = fi.Space;
             if (space != null) return space;
-            var spaces = fi.Document.GetSpaces().Where(t => t.IsValidObject).ToList();
-            Space temSpace2 = null;
+            if (spaces == null)
+                spaces = fi.Document.GetSpaces().Where(t => t.IsValidObject).ToList();
             var origin1 = fi.GetLocationPointMBIXYZ();
-            var origin2 = fi.GetBoxCenter();
             foreach (Space tempSpace in spaces)
             {
                 //没有Space属性,取定位点,判断定位点所在空间
@@ -204,16 +203,9 @@ namespace SAGA.MBI.Tools
                     space = tempSpace;
                     break;
                 }
-
-                //还没有找到空间,取Box中心点,判断点所在空间
-                if (temSpace2 != null) continue;
-                if (tempSpace.IsPointInSpace(origin2))
-                {
-                    temSpace2 = tempSpace;
-                }
             }
 
-            return space ?? (temSpace2);
+            return space;
         }
     }
 }

+ 115 - 0
MBI/SAGA.MBI/TestCommand.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using System.Text;
@@ -14,7 +15,9 @@ using Autodesk.Revit.UI;
 using Autodesk.Revit.UI.Selection;
 using SAGA.DotNetUtils;
 using SAGA.DotNetUtils.Extend;
+using SAGA.DotNetUtils.Geometry;
 using SAGA.DotNetUtils.Logger;
+using SAGA.DotNetUtils.Others;
 using SAGA.MBI.Calc;
 using SAGA.MBI.DataArrange;
 using SAGA.MBI.Interaction;
@@ -31,6 +34,118 @@ using Color = Autodesk.Revit.DB.Color;
 
 namespace SAGA.MBI
 {
+    #region 测试命令
+    /// <summary>
+    /// 
+    /// </summary>
+    [Transaction(TransactionMode.Manual)]
+    [Regeneration(RegenerationOption.Manual)]
+    public class EquipInSpaceSpeedTest : ExternalCommand, IExternalCommandAvailability
+    {
+        public override Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
+        {
+            try
+            {
+                var fi = ExternalDataWrapper.Current.UiApp.GetSelectedElement() as FamilyInstance;
+                var space = fi.GetReferenceSpace();
+                string str = "";
+                while (true)
+                {
+                    if (space != null)
+                    {
+                        List<XYZ> spaceVertex = space.GetBoundaryVertexes().FirstOrDefault();
+                        if (spaceVertex == null)
+                        {
+                            str = "Boundary 为Null";
+                            break;
+                        }
+
+                        var xyz = fi.GetLocationPointMBIXYZ();
+                        str = "Geometry Intersection Result" + xyz.PointInPolygonByRay(spaceVertex);
+
+
+                            break;
+
+                    }
+
+                }
+                MessageShowBase.Infomation($"{str}");
+
+                //var doc = commandData.View.Document;
+                //var spaces = doc.GetSpaces().Where(t => t.IsValidObject).ToList();
+                //var fis = doc.GetFamilyInstances().Where(t=>t.IsEquipmentPart()||t.IsEquipment());
+                //List<List<List<XYZ>>> spaceVertexes = spaces.Select(t => t.GetBoundaryVertexes()).ToList();
+                //List<KeyValuePair<FamilyInstance, XYZ>> keyValuePairs = fis.Select(t => new KeyValuePair<FamilyInstance,XYZ>(t,t.GetLocationPointMBIXYZ())).ToList();
+                //List<KeyValuePair<FamilyInstance, XYZ>> keyValuePairs_bak = new List<KeyValuePair<FamilyInstance, XYZ>>();
+                //long rtime = 0,gtime = 0;
+                //int rcount = 0, gcount = 0;
+                //Stopwatch watch = new Stopwatch();
+                //#region 使用Revit计算
+                //watch.Start();
+                //foreach (var pair in keyValuePairs)
+                //{
+                //    FamilyInstance fi = pair.Key;
+                //    var space=fi.GetReferenceSpace(spaces);
+                //    if (space != null)
+                //    {
+                //        rcount++;
+                //        keyValuePairs_bak.Add(pair);
+                //    }
+                //}
+                //watch.Stop();
+                //rtime = watch.ElapsedMilliseconds;
+
+                //#endregion
+
+                //#region 使用Geomety计算
+
+                //List<List<XYZ>> spaceBorderVertexes = spaceVertexes.Select(t => t.FirstOrDefault()).ToList();
+                //watch.Reset();
+                //watch.Start();
+
+                //foreach (var pair in keyValuePairs)
+                //{
+                //    XYZ xyz = pair.Value;
+                //    double z = xyz.Z;
+                //    var point = xyz.ToPointD();
+                //    foreach (var spaceVertex in spaceBorderVertexes)
+                //    {
+                //        if(spaceVertex==null)continue;
+                        
+                //        double minz = spaceVertex.Min(t => t.Z);
+                //        double maxz = spaceVertex.Max(t => t.Z);
+                //        //if (z.IsBetween(minz, maxz))
+                //        {
+                //            //if(Geometry2D.InSidePolygon(spaceVertex.Count,spaceVertex.Select(t=>t.ToPointD()).ToArray(),point)==1)
+                //            if (xyz.PointInPolygonByRay(spaceVertex) != -1)
+                //            {
+                //                gcount++;
+                                
+                //                keyValuePairs_bak.Remove(pair);
+                //                break;
+                //            }
+                //        }
+                //    }
+                //}
+                //watch.Stop();
+                //gtime = watch.ElapsedMilliseconds;
+
+                //#endregion
+
+                //MessageShow.Infomation($"Revit计算耗时{rtime},共识别出{rcount}个空间" + "\r\n" +
+                //                       $"Geometry计算耗时{gtime},共识别出{gcount}个空间"+"\r\n"+
+                //                       $"{string.Join(",",keyValuePairs_bak.Select(t=>t.Key.Id))}");
+            }
+            catch (Exception e)
+            {
+                MessageShow.Show(e);
+                return Result.Cancelled;
+            }
+            return Result.Succeeded;
+        }
+    }
+    #endregion
+
     /// <summary>
     /// 上传当前楼层数据
     /// </summary>

+ 3 - 2
MBI/SAGA.MBI/ToolsData/CheckEquipCategory.cs

@@ -100,6 +100,7 @@ namespace SAGA.MBI.ToolsData
             //        //addContext.MSpaces.Add(mode);
             //    }
             //}
+            var spaces = baseContext.RevitDoc.GetSpaces().Where(t => t.IsValidObject).ToList();
             //检查设备
             foreach (var mode in baseContext.MEquipments)
             {
@@ -124,7 +125,7 @@ namespace SAGA.MBI.ToolsData
                     addContext.MEquipments.Add(equip);
 
                     //识别设备所在空间
-                    var space = fi.GetReferenceSpace();
+                    var space = fi.GetReferenceSpace(spaces);
                     if (space == null) continue;
                     string spaceId = space.GetCloudBIMId();
                     MISpace mSpace = addContext.MSpaces.FirstOrDefault(t => t.BimID == spaceId);
@@ -160,7 +161,7 @@ namespace SAGA.MBI.ToolsData
                     DalUploadFloor.SetSavePropertyValue(equipment, mode);
                     addContext.MEquipmentParts.Add(equipment);
                     //识别设备所在空间
-                    var space = fi.GetReferenceSpace();
+                    var space = fi.GetReferenceSpace(spaces);
                     if (space == null) continue;
                     string spaceId = space.GetCloudBIMId();
                     MISpace mSpace = addContext.MSpaces.FirstOrDefault(t => t.BimID == spaceId);

+ 5 - 3
MBI/SAGA.MBI/ToolsData/CheckEquipInSpace.cs

@@ -58,13 +58,14 @@ namespace SAGA.MBI.ToolsData
             context.OpenDocument();
             var document = context.RevitDoc;
             var spaces = context.MSpaces;
+            var rspaces = context.RevitDoc.GetSpaces().Where(t => t.IsValidObject).ToList(); 
             foreach (var equipment in context.MEquipments)
             {
                 var bimId = equipment.BimID;
                 FamilyInstance fi=document.GetElement(bimId.GetBIMID()) as FamilyInstance;
                 if (fi != null)
                 {
-                    var space = fi.GetReferenceSpace();
+                    var space = fi.GetReferenceSpace(rspaces);
                     if (space != null)
                     {
                         var spaceBimid = space.GetCloudBIMId();
@@ -111,6 +112,7 @@ namespace SAGA.MBI.ToolsData
         private static void CalcEquipPartRlt(CalcContext context)
         {
             var linkElements = context.RevitDoc.GetFamilyInstances();
+            var rspaces = context.RevitDoc.GetSpaces();
             //过滤出的所有实体
             foreach (FamilyInstance fi in linkElements)
             {
@@ -121,7 +123,7 @@ namespace SAGA.MBI.ToolsData
 
 
                     //识别设备所在空间
-                    var space = fi.GetReferenceSpace();
+                    var space = fi.GetReferenceSpace(rspaces);
                     if (space == null)
                     {
                         string familyName = fi.GetFamily().Name;
@@ -141,7 +143,7 @@ namespace SAGA.MBI.ToolsData
                     context.MEquipmentParts.Add(part);
 
                     //识别设备所在空间
-                    var space = fi.GetReferenceSpace();
+                    var space = fi.GetReferenceSpace(rspaces);
                     if (space == null)
                     {
                         string familyName = fi.GetFamily().Name;

+ 5 - 3
MBI/SAGA.MBI/ToolsData/ModeCheck/EquipmentInSpaceCheck.cs

@@ -9,6 +9,7 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Mechanical;
 using NPOI.SS.UserModel;
 using SAGA.DotNetUtils.Others;
 using SAGA.MBI.DataArrange;
@@ -53,9 +54,10 @@ namespace SAGA.MBI.ToolsData.ModeCheck
                 var document = signResult.RDocument;
                 var elements = document.GetFamilyInstances();
                 var parts = elements.Where(t => t.IsEquipment()|| t.IsEquipmentPart());
+                var rspaces = document.GetSpaces().Where(t => t.IsValidObject).ToList();
                 foreach (FamilyInstance fi in parts)
                 {
-                    var result = GetCheckResult(fi);
+                    var result = GetCheckResult(fi,rspaces);
                     result.RBase = signResult;
                     Results.Add(result);
                 }
@@ -68,12 +70,12 @@ namespace SAGA.MBI.ToolsData.ModeCheck
         /// </summary>
         /// <param name="fi"></param>
         /// <returns></returns>
-        private ModeCheckResultBase GetCheckResult(FamilyInstance fi)
+        private ModeCheckResultBase GetCheckResult(FamilyInstance fi,List<Space> spaces)
         {
             var result = new EquipmentInSpaceCheckResult();
             result.FamilyName = fi.GetFamily().Name;
             result.Id = fi.Id.ToString();
-            var space = fi.GetReferenceSpace();
+            var space = fi.GetReferenceSpace(spaces);
             if (space == null)
             {
                 result.IsRight = false;

+ 6 - 0
MBI/SAGA.RevitUtils/Extends/XYZExtend.cs

@@ -1,10 +1,12 @@
 using System;
 using System.Collections.Generic;
+using System.Drawing;
 using System.Linq;
 using System.Text.RegularExpressions;
 using Autodesk.Revit.DB;
 using SAGA.DotNetUtils;
 using SAGA.DotNetUtils.Extend;
+using SAGA.DotNetUtils.Geometry;
 using SAGA.RevitUtils.Infrastructure;
 using SAGA.RevitUtils.Utils;
 using Point = System.Windows.Point;
@@ -232,6 +234,10 @@ namespace SAGA.RevitUtils.Extends
             if (pt == null) return default(Point);
             return new Point(pt.X,pt.Y);
         }
+        public static Geometry2D.PointD ToPointD(this XYZ pt)
+        {
+            return new Geometry2D.PointD(pt.X, pt.Y);
+        }
 
         /// <summary>
         /// ת2DPoint