C#平面几何简单操作(点、线、面)

1、二维点:

public class XPoint
{
    public double X { get; set; }
    public double Y { get; set; }

    public XPoint()
    {
        X = double.NaN;
        Y = double.NaN;
    }

    public XPoint(double x, double y)
    {
        X = x;
        Y = y;
    }

    /// <summary>
    /// 两点之间的距离
    /// </summary>
    /// <param name="p1"></param>
    /// <param name="p2"></param>
    /// <returns></returns>
    public static double Distance(XPoint p1, XPoint p2)
    {
        return Math.Sqrt((p2.X - p1.X) * (p2.X - p1.X) + (p2.Y - p1.Y) * (p2.Y - p1.Y));
    }

    /// <summary>
    /// 判断点坐标中是否包含无效值
    /// </summary>
    /// <param name="pnt"></param>
    /// <returns></returns>
    public static bool IsNaN(XPoint pnt)
    {
        if (double.IsNaN(pnt.X) || double.IsNaN(pnt.Y))
        {
            return true;
        }
        return false;
    }

    /// <summary>
    /// 判断四个点是否构成一个矩形(适当放宽矩形的精度控制,已提高适应性)
    /// </summary>
    /// <param name="p1"></param>
    /// <param name="p2"></param>
    /// <param name="p3"></param>
    /// <param name="p4"></param>
    /// <param name="tol">精度</param>
    /// <returns></returns>
    public static bool JugeRect(XPoint p1, XPoint p2, XPoint p3, XPoint p4, double tol = 0.001)
    {
        double xy = Math.Max(Math.Abs(p3.X - p1.X), Math.Abs(p3.Y - p1.Y));
        bool flag1 = Math.Abs(p1.Y - p2.Y) < tol * 10 * xy;
        bool flag2 = Math.Abs(p3.Y - p4.Y) < tol * 10 * xy;
        bool flag3 = Math.Abs(p1.X - p4.X) < tol * 10 * xy;
        bool flag4 = Math.Abs(p2.X - p3.X) < tol * 10 * xy;
        return flag1 && flag2 && flag3 && flag4;
    }
}

2、二维线段:

public class XLine
{
    public XPoint StartPt { get; set; }
    public XPoint EndPt { get; set; }

    /// <summary>
    /// 线段由多段构成时,去掉中间的空隙,剩余部分相对于起点距离比例的闭区间
    /// </summary>
    public XRangeList Range { get; set; }

    public XLine(XPoint start, XPoint end)
    {
        StartPt = start;
        EndPt = end;
        Range = new XRangeList();
        Range.Merge(new XRange(0, 1));
    }

    /// <summary>
    /// 线段长度
    /// </summary>
    /// <returns></returns>
    public double Length()
    {
        //勾股定理
        return Math.Sqrt((this.EndPt.X - this.StartPt.X) * (this.EndPt.X - this.StartPt.X) + (this.EndPt.Y - this.StartPt.Y) * (this.EndPt.Y - this.StartPt.Y));
    }

    /// <summary>
    /// 判断点是否在线段有效区间内
    /// </summary>
    /// <param name="pnt"></param>
    /// <returns></returns>
    public bool In(XPoint pnt)
    {
        double dx = this.EndPt.X - this.StartPt.X;
        double dy = this.EndPt.Y - this.StartPt.Y;
        if (Math.Abs(dx) > Math.Abs(dy))
        {
            double v = (pnt.X - this.StartPt.X) / dx;
            return this.Range.In(v);
        }
        else
        {
            double v = (pnt.Y - this.StartPt.Y) / dy;
            return this.Range.In(v);
        }
    }

    /// <summary>
    /// 判断两条线段是否平行
    /// </summary>
    /// <param name="lineA">线段A</param>
    /// <param name="lineB">线段B</param>
    /// <returns>true:平行,反之</returns>
    public static bool IsParallel(XLine lineA, XLine lineB)
    {
        bool flagA = lineA.StartPt.X == lineA.EndPt.X;
        bool flagB = lineB.StartPt.X == lineB.EndPt.X;
        if (flagA && flagB)
        {
            //两条垂直线
            return true;
        }
        else if (flagA || flagB)
        {
            //一条垂直一条不垂直
            return false;
        }
        else
        {
            //利用斜率进行判断
            var slopeA = (lineA.EndPt.Y - lineA.StartPt.Y) / (lineA.EndPt.X - lineA.StartPt.X);
            var slopeB = (lineB.EndPt.Y - lineB.StartPt.Y) / (lineB.EndPt.X - lineB.StartPt.X);
            return slopeA == slopeB;
        }
    }

    /// <summary>
    /// 获取两条线段的交点
    /// </summary>
    /// <param name="lineM">线段M</param>
    /// <param name="lineN">线段N</param>
    /// <returns>相交则返回交点坐标,否则返回null</returns>
    public static XPoint IntersectWith(XLine lineM, XLine lineN, double tol = 0.001)
    {
        if (IsParallel(lineM, lineN))
        {
            return null;
        }
        //已知直线上的两点A(x1,y1),B(x2,y2)
        //则有:A*x1 + B*y1 + C = A*x2 + B*y2 + C
        //变形得:A(x1 - x2) = B(y2 - y1)
        //求得:A = y2 - y1,B = x1 - x2,C = x2*y1 - x1*y2

        //线段M中的各常数(取百万分之一的容差)
        var constA_m = Math.Round(lineM.EndPt.Y - lineM.StartPt.Y, 6);
        var constB_m = Math.Round(lineM.StartPt.X - lineM.EndPt.X, 6);
        var constC_m = Math.Round(lineM.EndPt.X * lineM.StartPt.Y - lineM.StartPt.X * lineM.EndPt.Y, 6);

        //线段N中的各常数(取百万分之一的容差)
        var constA_n = Math.Round(lineN.EndPt.Y - lineN.StartPt.Y, 6);
        var constB_n = Math.Round(lineN.StartPt.X - lineN.EndPt.X, 6);
        var constC_n = Math.Round(lineN.EndPt.X * lineN.StartPt.Y - lineN.StartPt.X * lineN.EndPt.Y, 6);

        double istPtX, istPtY;
        if (constA_m == 0)
        {
            //线段M平行于X轴
            istPtY = -1 * constC_m / constB_m;
            if (constB_n == 0)
            {
                istPtX = -1 * constC_n / constA_n;
            }
            else
            {
                istPtX = -1 * (constB_n * istPtY + constC_n) / constA_n;//使用线段N的直线方程求交点Y值
            }
        }
        else if (constB_m == 0)
        {
            //线段M平行于Y轴
            istPtX = -1 * constC_m / constA_m;
            if (constA_n == 0)
            {
                istPtY = -1 * constC_n / constB_n;
            }
            else
            {
                istPtY = -1 * (constA_m * istPtX + constC_m) / constB_m;//使用线段M的直线方程求交点Y值
            }
        }
        else if (constA_n == 0)
        {
            //线段N平行于X轴
            istPtY = -1 * constC_n / constB_n;
            if (constB_m == 0)
            {
                istPtX = -1 * constC_m / constA_m;
            }
            else
            {
                istPtX = -1 * (constB_m * istPtY + constC_m) / constA_m;//使用线段M的直线方程求交点Y值
            }
        }
        else if (constB_n == 0)
        {
            //线段N平行于Y轴
            istPtX = -1 * constC_n / constA_n;
            if (constA_m == 0)
            {
                istPtY = -1 * constC_m / constB_m;
            }
            else
            {
                istPtY = -1 * (constA_n * istPtX + constC_n) / constB_n;//使用线段M的直线方程求交点Y值
            }
        }
        else
        {
            istPtX = (constB_n * constC_m - constB_m * constC_n) / (constA_n * constB_m - constA_m * constB_n);//求交点X值(两个直线方程带入)
            istPtY = -1 * (constA_m * istPtX + constC_m) / constB_m;//使用线段A的直线方程求交点Y值
        }


        var minX_m = Math.Min(lineM.StartPt.X, lineM.EndPt.X);
        var maxX_m = Math.Max(lineM.StartPt.X, lineM.EndPt.X);
        var minY_m = Math.Min(lineM.StartPt.Y, lineM.EndPt.Y);
        var maxY_m = Math.Max(lineM.StartPt.Y, lineM.EndPt.Y);
        var flagA = istPtX >= minX_m - tol && istPtX <= maxX_m + tol && istPtY >= minY_m - tol && istPtY <= maxY_m + tol;

        var minX_n = Math.Min(lineN.StartPt.X, lineN.EndPt.X);
        var maxX_n = Math.Max(lineN.StartPt.X, lineN.EndPt.X);
        var minY_n = Math.Min(lineN.StartPt.Y, lineN.EndPt.Y);
        var maxY_n = Math.Max(lineN.StartPt.Y, lineN.EndPt.Y);
        var flagB = istPtX >= minX_n - tol && istPtX <= maxX_n + tol && istPtY >= minY_n - tol && istPtY <= maxY_n + tol;

        //判断交点是否在两条线段上
        if (flagA && flagB)
        {
            return new XPoint(istPtX, istPtY);
        }
        return null;
    }

    /// <summary>
    /// xline合并,参数要求:在同一条直线内,方向一致,且已排好序
    /// </summary>
    /// <param name="lineList"></param>
    /// <returns></returns>
    public static XLine Merge(List<XLine> lineList)
    {
        if (lineList.Count == 0)
        {
            return null;
        }
        else if (lineList.Count == 1)
        {
            return lineList[0];
        }
        else
        {
            XPoint start = lineList[0].StartPt;
            XPoint end = lineList[0].EndPt;
            foreach (XLine item in lineList)
            {
                if (XPoint.Distance(item.EndPt, start) > XPoint.Distance(start, end))
                {
                    end = item.EndPt;
                }
            }
            XLine xline = new XLine(start, end);
            double len = xline.Length();
            List<XRange> xRanges = new List<XRange>();
            for (int i = 0; i < lineList.Count; i++)
            {
                double s = XPoint.Distance(lineList[i].StartPt, start) / len;
                double t = XPoint.Distance(lineList[i].EndPt, start) / len;
                xRanges.Add(new XRange(s, t));
            }
            xline.Range.List = XRangeList.Merge(xRanges);
            return xline;
        }
    }

    /// <summary>
    /// 判断两条线段的起点端点在误差范围内是否相连
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <param name="rol"></param>
    /// <returns></returns>
    public static bool LineJoint(XLine a, XLine b, double rol = 0.001)
    {
        if (System.Object.ReferenceEquals(a, b)) return true;
        if (System.Object.ReferenceEquals(a, null) || System.Object.ReferenceEquals(b, null)) return false;

        if (Math.Abs(a.StartPt.X - b.StartPt.X) < rol && Math.Abs(a.StartPt.Y - b.StartPt.Y) < rol) //起点相连
        {
            return true;
        }
        if (Math.Abs(a.StartPt.X - b.EndPt.X) < rol && Math.Abs(a.StartPt.Y - b.EndPt.Y) < rol)//起终点相连
        {
            return true;
        }
        if (Math.Abs(a.EndPt.X - b.StartPt.X) < rol && Math.Abs(a.EndPt.Y - b.StartPt.Y) < rol)//终起点相连
        {
            return true;
        }
        if (Math.Abs(a.EndPt.X - b.EndPt.X) < rol && Math.Abs(a.EndPt.Y - b.EndPt.Y) < rol)//终点相连
        {
            return true;
        }
        return false;
    }

    #region CAD二开中使用的方法,需引用Autodesk.AutoCAD.Geometry;
    基于CAD的起终点
    //public Point2d CadStartPt { get; set; }
    //public Point2d CadEndPt { get; set; }

    / <summary>
    / 方向
    / </summary>
    //public Vector2d Direction
    //{
    //    get
    //    {
    //        Vector2d direction = CadEndPt - CadStartPt;
    //        return direction;
    //    }
    //}

    / <summary>
    / 判断两向量是否是平行向量(方向相反也是平行向量)
    / 备注:此方法基于CAD
    / </summary>
    / <param name="v1"></param>
    / <param name="v2"></param>
    / <returns></returns>
    //static public bool Parallel(Vector2d v1, Vector2d v2, double tol = 0.001)
    //{
    //    if (Math.Abs(v1.Angle - v2.Angle) < tol)
    //    {
    //        return true;
    //    }
    //    else if (Math.Abs(Math.Abs(v1.Angle - v2.Angle) - Math.PI) < tol)
    //    {
    //        return true;
    //    }
    //    return false;
    //}

    / <summary>
    / 平面两线段交点
    / 备注:此方法基于CAD
    / </summary>
    / <param name="line1"></param>
    / <param name="line2"></param>
    / <param name="tol">精度控制值,必须为正值,默认为0</param>
    / <returns></returns>
    //public static Point2d Intersect(XLine line1, XLine line2, double tol = 0)
    //{
    //    //Line1: Line1.startPt  + s * Line1.direction   for s in [0,1]
    //    //Line2: Line1.startPt  + t * Line1.direction   for t in [0,1]
    //    if (!Parallel(line2.Direction, line1.Direction))//如果两直线平行
    //    {
    //        Vector2d v = line2.CadStartPt - line1.CadStartPt;
    //        Point2d E = new Point2d(v.X, v.Y);
    //        double kross = line1.Direction.X * line2.Direction.Y - line1.Direction.Y * line2.Direction.X;
    //        double s = (E.X * line2.Direction.Y - E.Y * line2.Direction.X) / kross;
    //        double t = (E.X * line1.Direction.Y - E.Y * line1.Direction.X) / kross;
    //        if (line1.Range.In(s, tol) && line2.Range.In(t, tol))
    //        {
    //            Point2d p = line1.CadStartPt + s * line1.Direction;
    //            return p;
    //        }
    //        else
    //        {
    //            return new Point2d(double.NaN, double.NaN);//无交点
    //        }
    //    }
    //    else
    //    {
    //        return new Point2d(double.NaN, double.NaN);//两线段平行或部分重合
    //    }
    //    //double sqrkross = kross * kross;
    //}
    #endregion
}

3、简单的平面:

public class XExtents
{
    public XPoint MinPoint { get; set; }
    public XPoint MaxPoint { get; set; }

    public XExtents()
    {
        MinPoint = new XPoint();
        MaxPoint = new XPoint();
    }

    public XExtents(XPoint minimum, XPoint maximum)
    {
        MinPoint = minimum;
        MaxPoint = maximum;
    }

    public void AddPoint(XPoint xPoint)
    {
        if (XPoint.IsNaN(xPoint))
        {
            return;
        }

        var flagMin = XPoint.IsNaN(MinPoint);
        var flagMax = XPoint.IsNaN(MaxPoint);

        if (flagMin)
        {
            if (flagMax)
            {
                MinPoint = xPoint;
                MaxPoint = xPoint;
            }
            else
            {
                double minx = xPoint.X < MaxPoint.X ? xPoint.X : MaxPoint.X;
                double miny = xPoint.Y < MaxPoint.Y ? xPoint.Y : MaxPoint.Y;
                double maxx = xPoint.X > MaxPoint.X ? xPoint.X : MaxPoint.X;
                double maxy = xPoint.Y > MaxPoint.Y ? xPoint.Y : MaxPoint.Y;

                MinPoint = new XPoint(minx, miny);
                MaxPoint = new XPoint(maxx, maxy);
            }
        }
        else
        {
            if (flagMax)
            {
                double minx = xPoint.X < MinPoint.X ? xPoint.X : MinPoint.X;
                double miny = xPoint.Y < MinPoint.Y ? xPoint.Y : MinPoint.Y;
                double maxx = xPoint.X > MinPoint.X ? xPoint.X : MinPoint.X;
                double maxy = xPoint.Y > MinPoint.Y ? xPoint.Y : MinPoint.Y;

                MinPoint = new XPoint(minx, miny);
                MaxPoint = new XPoint(maxx, maxy);
            }
            else
            {
                double minx = xPoint.X < MinPoint.X ? xPoint.X : MinPoint.X;
                double miny = xPoint.Y < MinPoint.Y ? xPoint.Y : MinPoint.Y;
                double maxx = xPoint.X > MaxPoint.X ? xPoint.X : MaxPoint.X;
                double maxy = xPoint.Y > MaxPoint.Y ? xPoint.Y : MaxPoint.Y;

                MinPoint = new XPoint(minx, miny);
                MaxPoint = new XPoint(maxx, maxy);
            }
        }
    }
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值