Teigha做dwg数据转换shp过程中特殊图层拟合

Teigha做dwg数据转换shp过程中特殊图层拟合

shp数据格式因为很老,所以不支持圆、圆弧、贝斯尔曲线等特殊图形。
在数据转换过程中需要通过算法拟合生成一个类似的线段或面来达到同等效果。
主要思路是通过正弦、余弦、正贴值计算。

定义点对象

首先定义一个简单的对象,用来存储转换后的点结果。

//非常简单的对象
   public class DwgPoint
    {
        public DwgPoint()
        {

        }

        public DwgPoint(double x, double y)
        {
            X = x;
            Y = y;
        }
        public double X { get; set; }
        public double Y { get; set; }
    }

拟合圆形

1、首先将半圆形的等分180快,计算过程中使用的都是弧度。
2、从x正轴开始逆时针旋转。
3、利用三角形关系求正弦值,即为x轴的值。
4、利用三角形关系求余弦值,即为y轴的值。
5、上面x,y值即就是圆形任意夹角位置的任意点值。
6、上面的位置是默认圆心在象限原点,再根据中心点加上偏移量即可。
        /// 
        /// 根据圆心 半径
        /// 计算圆上的点
        /// 用来表达圆形图形
        /// 
        /// 中心点x
        /// 中心点y
        /// 半径
        /// 
        public static List CalcuteCirclePoints(double centerX, double centerY, double radio)
        {
            List pointFs = new List();
            double step = Math.PI / 180.0;
            for (int i = 0; i < 360; i++)
            {
                double x = centerX + radio * Math.Sin(step * i);
                double y = centerY + radio * Math.Cos(step * i);
                pointFs.Add(new DwgPoint(x, y));
            }
            pointFs.Add(new DwgPoint(pointFs[0].X, pointFs[0].Y));
            return pointFs;
        }

拟合圆弧

圆弧的稍微复杂。
首先要根据起始角度大小判定圆弧的长度,以为起点终点如果不区分会有两种解释
也会产生两种圆弧,正圆弧和反圆弧。
圆弧拟合中会根据等分大小,先去计算到底要分成多少分,避免拟合的点过多。
        /// 
        /// 圆弧计算函数
        /// 正弦为0度,逆时针旋转
        /// 圆弧有其特殊性
        /// 如果起始大于终止,则将圆弧分为两部分模拟
        /// 
        /// 中心点x
        /// 中心点y
        /// 半径
        /// 起始角度
        /// 终止角度
        /// 
        public static List CalcuteArcPoints(double centerX, double centerY, double radio, double start, double end)
        {
            List pointFs = new List();
            double step = Math.PI / 180.0;
            if (start > end)
            {
                int count = (int)((2 * Math.PI - start) / step);
                for (int i = 0; i < count; i++)
                {
                    double x = centerX + radio * Math.Sin(start + step * i);
                    double y = centerY + radio * Math.Cos(start + step * i);
                    pointFs.Add(new DwgPoint(x, y));
                }
                count = (int)((end) / step);
                for (int i = 0; i < count; i++)
                {
                    double x = centerX + radio * Math.Sin(step * i);
                    double y = centerY + radio * Math.Cos(step * i);
                    pointFs.Add(new DwgPoint(x, y));
                }
            }
            else
            {
                int count = (int)((end - start) / step);
                for (int i = 0; i < count; i++)
                {
                    double x = centerX + radio * Math.Sin(start + step * i);
                    double y = centerY + radio * Math.Cos(start + step * i);
                    pointFs.Add(new DwgPoint(x, y));
                }
            }
            return pointFs;
        }

拟合椭圆和椭圆弧

椭圆跟椭圆弧的拟合就很麻烦了,且还融合在一起写。
先实现根据中心点、长短半轴、夹角、旋转角度计算一个点位置
1、椭圆的半径是不定长的,会根据角度变化不停的变化,首先就要计算某个角度下椭圆的半径
2、再根据半径和角度计算点的x、y值
3、如果椭圆没有旋转的话,到这是已经计算完成了,但椭圆大多都是有旋转角度的
4、计算旋转后点值算法是套用的函数,高中数学有转换关系函数,做完后思路已经忘了
5、最后根据中心点加上偏移量即可
        /// 
        /// 根据长短半轴计算椭圆上的一个点
        /// 
        /// 
        /// 
        /// 
        /// 
        public static DwgPoint CalcuteGetEllipseArcPoint(double centerX, double centerY, double majorRadius, double minorRadius, double angle, double rotateAngle)
        {
            DwgPoint dwgPoint = new DwgPoint();
            double a = majorRadius;
            double b = minorRadius;
            double yc = Math.Sin(angle);
            double xc = Math.Cos(angle);
            double radio = (a * b) / Math.Sqrt(Math.Pow(yc * a, 2.0) + Math.Pow(xc * b, 2.0));
            double ax = radio * xc;
            double ay = radio * yc;
            double rotatex = ax * Math.Cos(rotateAngle) - ay * Math.Sin(rotateAngle);
            double rotatey = ax * Math.Sin(rotateAngle) + ay * Math.Cos(rotateAngle);
            dwgPoint.X = centerX + rotatex;
            dwgPoint.Y = centerY + rotatey;
            return dwgPoint;
        }
计算椭圆弧算法
1、normalX、normalY表示是椭圆长半轴极端的点
2、Math.Atan2(normalY, normalX)函数可以直接计算线段的角度
3、其余的逻辑跟圆弧一致
        /// 
        /// 根据椭圆心 半径
        /// 计算椭圆上的点
        /// 用来表达椭圆形图形
        /// 
        /// 中心点x
        /// 中心点y
        /// 半径
        /// 
        public static List CalcuteEllipseArcPoints(double centerX, double centerY, double majorRadius, double minorRadius, double start, double end, double normalX, double normalY)
        {
            double rotateAngle = Math.Atan2(normalY, normalX);
            List pointFs = new List();
            double step = Math.PI / 180.0;
            if (start > end)
            {
                int count = (int)((2 * Math.PI - start) / step);
                for (int i = 0; i < count; i++)
                {
                    pointFs.Add(CalcuteGetEllipseArcPoint(centerX, centerY, majorRadius, minorRadius, start + step * i, rotateAngle));
                }
                count = (int)((end) / step);
                for (int i = 0; i < count; i++)
                {
                    pointFs.Add(CalcuteGetEllipseArcPoint(centerX, centerY, majorRadius, minorRadius, step * i, rotateAngle));
                }
            }
            else
            {
                int count = (int)((end - start) / step);
                for (int i = 0; i < count; i++)
                {
                    pointFs.Add(CalcuteGetEllipseArcPoint(centerX, centerY, majorRadius, minorRadius, start + step * i, rotateAngle));
                }
            }
            return pointFs;
        }
计算椭圆算法
1、椭圆跟椭圆弧算法一致,区别只是起点跟终点的问题
        /// 
        /// 计算椭圆的点
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static List CalcuteEllipsePoints(double centerX, double centerY, double majorRadius, double minorRadius, double normalX, double normalY)
        {
            List pointFs = CalcuteEllipseArcPoints(centerX, centerY, majorRadius, minorRadius, 0, 2 * Math.PI, normalX, normalY);
            pointFs.Add(new DwgPoint(pointFs[0].X, pointFs[0].Y));
            return pointFs;
        }

到此拟合算法差不多完成

你可能感兴趣的:(开源GIS大杂烩,dwg)