GIS 二维常见算法-入门篇

本文介绍了一种用于处理点与线及线与线之间关系的算法,包括判断点在线的哪一侧、判断两线段是否相交、计算两线段间的最小距离及判断两条线的方向是否相同等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

处理点与线的关系,线与线的关系的算法等等,如有错误,欢迎指正。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PointLinePositionRelation
{
    #region Entity
    /// <summary>
    /// Entity Point
    /// </summary>
    public class Point
    {
        public Point(double x, double y)
        {
            this.x = x;
            this.y = y;
        }

        private double x;

        public double X
        {
            get { return x; }
            set { x = value; }
        }
        private double y;

        public double Y
        {
            get { return y; }
            set { y = value; }
        }
    }

    /// <summary>
    /// Entity of line
    /// </summary>
    public class Line
    {
        public Line()
        {
        }

        public Line(List<Point> _points)
        {
            this.points = _points;
        }

        private List<Point> points = new List<Point>();

        public List<Point> Points
        {
            get { return points; }
        }

        public bool AddPoint(Point p)
        {
            bool success = false;
            if (!points.Contains(p))
            {
                points.Add(p);
                success = true;
            }
            return success;
        }

        public bool RemovePoint(Point p)
        {
            bool success = false;
            if (points.Contains(p))
            {
                points.Remove(p);
                success = true;
            }
            return success;
        }

        public bool UpdatePoint(Point src_p, Point tar_p)
        {
            bool success = false;
            if (points.Contains(src_p))
            {
                src_p.X = tar_p.X;
                src_p.Y = tar_p.Y;
                success = true;
            }
            return success;
        }
    }

    /// <summary>
    /// Position Status
    /// </summary>
    enum Position
    {
        LEFT = 0,
        RIGHT = 1,
        ON_K = 2,
        UP = 3,
        DOWN = 4,
        ON = 5,
        ERROE = 6
    }
    #endregion

    #region Function
    public static class PointLineAlgorithems
    {
        #region Algorithems
        /// <summary>
        /// return the traingle degree 
        /// </summary>
        /// <param name="tupe"></param>
        /// tuple item1:the first point
        /// tuple item2:the last point
        /// tuple item3:the middle point
        /// <returns></returns>
        public static double GetTraingleDegree(Tuple<Point, Point, Point> tupe)
        {
            double distance1 = GetDistance(tupe.Item1, tupe.Item2);
            double distance2 = GetDistance(tupe.Item1, tupe.Item3);
            double distance3 = GetDistance(tupe.Item2, tupe.Item3);

            return Math.Acos(Math.Pow(distance1,2)+Math.Pow(distance2,2)-Math.Pow(distance3,2)/2*distance1*distance2);
        }

        /// <summary>
        /// to judage point and line position
        /// </summary>
        /// <param name="l"></param>
        /// <param name="p"></param>
        /// <returns></returns>
        public static string JudgePointLineRelation(Line l, Point p)
        {
            //y = kx + b
            //the k of line combine with two points
            double k;
            //the b of line 
            double b;

            //the result 
            string POSITION = string.Empty;

            //this function is to deal with one point with a line with two points
            //if line point is not 2,you should split to two or more lines with 
            //two points,so here we return string.Empty
            if (l.Points.Count != 2 || p == null) return string.Empty;

            //if the X value of two points are the same
            //wo can not get k,then we can deal it as follows
            if (l.Points[0].X == l.Points[1].X)
            {
                if (p.X > l.Points[0].X) POSITION = "LEFT";
                else if (p.X < l.Points[0].X) POSITION = "RIGHT";
                else if (p.X == l.Points[0].X) POSITION = "ON";
                //else POSITION = "ERROR_K";
            }
            //if the k is not zero,we can deal it as follows
            else
            {
                k = (l.Points[0].Y - l.Points[1].Y) / (l.Points[0].X - l.Points[1].X);
                b = ((l.Points[0].X * l.Points[1].Y) - (l.Points[0].Y * l.Points[1].X)) / (l.Points[0].X - l.Points[1].X);

                if (p.Y > k * p.X + b) POSITION = "UP";
                else if (p.Y < k * p.X + b) POSITION = "DOWN";
                else if (p.Y == k * p.X + b) POSITION = "ON";
                //else POSITION = "ERROR_N";
            }
            return POSITION;
        }

        /// <summary>
        /// to judage if two line clips
        /// </summary>
        /// <param name="src"></param>
        /// <param name="tar"></param>
        /// <returns></returns>
        public static int? JudageLinesRelation(Line src, Line tar)
        {
            //if point count of line is less then 2,we do not 
            //deal with this
            if (src.Points.Count < 2 || tar.Points.Count < 2)
                return null;
            Point p = null;
            Line l = null;
            string flag = string.Empty;
            //falg of clip,if not clip 1,else 0
            int? clip = 1;
            for (int i = 0; i < src.Points.Count; i++)
            {
                //the first loop point
                p = new Point(src.Points[i].X, src.Points[i].Y);
                //the loop for tar line
                for (int j = 0; j + 1 < tar.Points.Count; j++)
                {
                    //temp line with two points
                    l = new Line();
                    l.AddPoint(tar.Points[j]);
                    l.AddPoint(tar.Points[j + 1]);
                    //if the value of flag is Null or Empty,means flag has not been given value
                    if (string.IsNullOrEmpty(flag))
                        flag = JudgePointLineRelation(l, p);
                    else
                    {
                        //if the new point position is not the same as the old point,the two line cliped
                        //there is no need to contine the loop,we change the flag value to 0(means two line cliped)
                        if (flag != JudgePointLineRelation(l, p))
                        {
                            clip = 0;
                            break;
                        }
                    }
                }
            }
            return clip;
        }

        /// <summary>
        /// get distance of two points
        /// </summary>
        /// <param name="src"></param>
        /// <param name="tar"></param>
        /// <returns></returns>
        public static double GetDistance(Point src, Point tar)
        {
            if (src.X == tar.X && src.Y == tar.Y) return 0;
            return Math.Sqrt(Math.Pow(Math.Abs(src.X - tar.X), 2) + Math.Pow(Math.Abs(src.Y - tar.Y), 2));
        }

        /// <summary>
        /// To get min distance of two lines
        /// </summary>
        /// <param name="src"></param>
        /// <param name="tar"></param>
        /// <returns></returns>
        public static Tuple<double?, int?, int?> CalcMinDistance(Line src, Line tar)
        {
            //if the point count less than 2,we do not think it is a line.
            if (src.Points.Count < 2 || tar.Points.Count < 2) return null;
            //if the two line cliped,we do not deal with this situation
            if (0 == JudageLinesRelation(src, tar)) return null;

            #region Params
            //the min distance point src_index
            int? src_index = null;
            //the min distance point tar_index
            int? tar_index = null;
            //the temp value to keep the distance
            double? temp = null;
            //the min distance
            double dist = 0;
            #endregion

            //loop for the src line
            for (int i = 0; i < src.Points.Count; i++)
            {
                //loop for tar line
                for (int j = 0; j < tar.Points.Count; j++)
                {
                    //the distance 
                    dist = GetDistance(src.Points[i], tar.Points[j]);
                    //if the temp has not been given value
                    if (null == temp)
                    {
                        temp = dist;
                        src_index = i;
                        tar_index = j;
                    }
                    else
                    {
                        //if the new value < temp,then keep the min value
                        if (temp > dist)
                        {
                            temp = dist;
                            src_index = i;
                            tar_index = j;
                        }
                    }
                }
            }
            return new Tuple<double?, int?, int?>(temp, src_index, tar_index);
        }

        /// <summary>
        /// to judage the two line direction
        /// </summary>
        /// <param name="src_line"></param>
        /// <param name="tar_line"></param>
        /// <returns></returns>
        public static bool? JudageLineDirection(Line src_line, Line tar_line)
        {
            //if the point count of line less than 2,we do not deal with this
            if (src_line.Points.Count < 2 || tar_line.Points.Count < 2)
                return null;
            //the boolean flag,if the two line are the same direction,then true
            //else the flag will be false.Note:if the exception has occoured
            //the value null will be returned
            bool flag = false;
            //the line temp value.
            //Note:this line is not always represent the min distance line
            Line line = null;
            //the temp value to recored the result that the position of point on 
            //src_line position and temp line(mostly min distance line) 
            string src_temp = string.Empty;
            //the temp value to recored the result that the position of point on 
            //tar_line position and temp line(mostly min distance line) 
            string tar_temp = string.Empty;
            //the temp tuple value that recored the min distance line information
            //item1:min distance value
            //item2:the index of the point on src_line
            //item3:the index of the point on tar_line
            Tuple<double?, int?, int?> tuple = CalcMinDistance(src_line, tar_line);
            //if the min diatance information is not null
            if (tuple != null)
            {
                //the index of src_line or tar_line type is int?,if index has not been given value
                //the value will be null,else will be the index of point,which combine the min distance line
                if (tuple.Item2.HasValue && tuple.Item3.HasValue)
                {
                    #region different situation
                    //if the index of point which combine the min distance line is less than count
                    if ((tuple.Item2.Value < src_line.Points.Count - 1) && (tuple.Item2.Value < tar_line.Points.Count - 1))
                    {
                        line = new Line(new List<Point> { src_line.Points[tuple.Item2.Value], tar_line.Points[tuple.Item3.Value] });
                        src_temp = JudgePointLineRelation(line, src_line.Points[tuple.Item2.Value + 1]);
                        tar_temp = JudgePointLineRelation(line, tar_line.Points[tuple.Item3.Value + 1]);
                    }
                    //if the index of point of src_line equals count-1
                    else if (tuple.Item2.Value == src_line.Points.Count - 1)
                    {
                        line = new Line(new List<Point> { src_line.Points[tuple.Item2.Value - 1], tar_line.Points[tuple.Item3.Value] });
                        src_temp = JudgePointLineRelation(line, src_line.Points[tuple.Item2.Value]);
                        tar_temp = JudgePointLineRelation(line, tar_line.Points[tuple.Item3.Value + 1]);
                    }
                    //if the index of point of tar_line equals count-1
                    else if (tuple.Item3.Value == tar_line.Points.Count - 1)
                    {
                        line = new Line(new List<Point> { src_line.Points[tuple.Item2.Value], tar_line.Points[tuple.Item3.Value - 1] });
                        src_temp = JudgePointLineRelation(line, src_line.Points[tuple.Item2.Value + 1]);
                        tar_temp = JudgePointLineRelation(line, tar_line.Points[tuple.Item3.Value]);
                    }
                    //both of them are equals count - 1
                    else
                    {
                        line = new Line(new List<Point> { src_line.Points[tuple.Item2.Value], tar_line.Points[tuple.Item3.Value] });
                        src_temp = JudgePointLineRelation(line, src_line.Points[tuple.Item2.Value - 1]);
                        tar_temp = JudgePointLineRelation(line, tar_line.Points[tuple.Item3.Value - 1]);
                    }
                    #endregion
                }
                else
                {
                    //if did not get min distance information,return null
                    return null;
                }
                //if the result are different,different direction
                //else the same direction
                if ((src_temp != tar_temp) && (src_temp != "ON" && tar_temp != "ON"))
                {
                    flag = false;
                }
                else
                {
                    flag = true;
                }
            }
            return flag;
        }
        #endregion
    }
    #endregion
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值