【20090118-01】空间数据的坐标变换

一、矢量数据的压缩

    矢量数据压缩的目的是删除冗余数据,减少数据的存贮量,节省存贮空间,加快后继处理的速度。下面介绍几种常用的矢量数据的压缩算法,以及它们之间的异同点。

1、道格拉斯——普克法(Douglas—Peucker)

    基本思路是(图4-4-1):对每一条曲线的首末点虚连一条直线,求所有点与直线的距离,并找出最大距离值dmax,用dmax与限差D相比:
    若dmax<D,这条曲线上的中间点全部舍去;
    若dmax≥D,保留dmax对应的坐标点,并以该点为界,把曲线分为两部分,对这两部分重复使用该方法。

【20090118-01】空间数据的坐标变换

2、垂距法

    垂距法的基本思路是(图4-4-2):每次顺序取曲线上的三个点,计算中间点与其它两点连线的垂线距离d,并与限差D比较。若d<D,则中间点去掉;若d≥D,则中间点保留。然后顺序取下三个点继续处理,直到这条线结束。

3、光栏法

    光栏法的基本思想是(图4-4-3):定义一个扇形区域,通过判断曲线上的点在扇形外还是在扇形内,确定保留还是舍去。设曲线上的点列为{pi},i=1,2,…,n,光栏口经为d,可根据压缩量的大小自己定义,则光栏法的实施步骤可描述为:

    1°、连接p1和p2点,过p2点作一条垂直于p1p2的直线,在该垂线上取两点a1和a2,使a1p2=a2p2=d/2,此时a1和a2为“光栏”边界点,p1与a1、p1与a2的连线为以p1为顶点的扇形的两条边,这就定义了一个扇形(这个扇形的口朝向曲线的前进方向,边长是任意的)。通过p1并在扇形内的所有直线都具有这种性质,即p1p2上各点到这些直线的垂距都不大于d/2。

    2°、若p3点在扇形内,则舍去p2点。然后连接p1和p3,过p3作p1p1的垂线,该垂线与前面定义的扇形边交于c1和c2。在垂线上找到b1和b2点,使p3b1=p3b2=d/2,若b1或b2点((图4-4-3中为b2点)落在原扇形外面,则用c1或c2取代(图4-4-3中由c2取代b2)。此时用p1b1和p1c2定义一个新的扇形,这当然是口径(b1c2)缩小了的“光栏”。

    3°、检查下一节点,若该点在新扇形内,则重复第(2)步;直到发现有一个节点在最新定义的扇形外为止。

    4°、当发现在扇形外的节点,如图4-4-3中的p4,此时保留p3点,以p3作为新起点,重复1°~3°。如此继续下去,直到整个点列检测完为止。所有被保留的节点(含首、末点),顺序地构成了简化后的新点列。

【20090118-01】空间数据的坐标变换

4、几种方法的比较

    如果某种矢量数据的压缩算法既能精确地表示数据,又能最大限度地淘汰不必要的点,那就是一种好的算法。具体可以依据简化后曲线的总长度、总面积、坐标平均值等与原始曲线的相应数据的对比来判别。

    通过分析可以发现,大多数情况下道格拉斯——普克法的压缩算法较好,但必须在对整条曲线数字化完成后才能进行,且计算量较大;光栏法的压缩算法也很好,并且可在数字化时实时处理,每次判断下一个数字化的点,且计算量较小;垂距法算法简单,速度快,但有时会将曲线的弯曲极值点p值去掉而失真。

转自:http://www.sres-whu-edu.cn/garden/courseware/gis/ch4/8.htm

 




//Douglas Peucker算法的实现



/// <summary>

/// Uses the Douglas Peucker algorithm to reduce the number of points.

/// </summary>

/// <param name="Points">The points.</param>

/// <param name="Tolerance">The tolerance.</param>

/// <returns></returns>

public static List<Point> DouglasPeuckerReduction

    (List<Point> Points, Double Tolerance)

{

    if (Points == null || Points.Count < 3)

    return Points;



    Int32 firstPoint = 0;

    Int32 lastPoint = Points.Count - 1;

    List<Int32> pointIndexsToKeep = new List<Int32>();



    //Add the first and last index to the keepers

    pointIndexsToKeep.Add(firstPoint);

    pointIndexsToKeep.Add(lastPoint);



    //The first and the last point cannot be the same

    while (Points[firstPoint].Equals(Points[lastPoint]))

    {

        lastPoint--;

    }



    DouglasPeuckerReduction(Points, firstPoint, lastPoint, 

    Tolerance, ref pointIndexsToKeep);



    List<Point> returnPoints = new List<Point>();

    pointIndexsToKeep.Sort();

    foreach (Int32 index in pointIndexsToKeep)

    {

        returnPoints.Add(Points[index]);

    }



    return returnPoints;

}

    

/// <summary>

/// Douglases the peucker reduction.

/// </summary>

/// <param name="points">The points.</param>

/// <param name="firstPoint">The first point.</param>

/// <param name="lastPoint">The last point.</param>

/// <param name="tolerance">The tolerance.</param>

/// <param name="pointIndexsToKeep">The point index to keep.</param>

private static void DouglasPeuckerReduction(List<Point> 

    points, Int32 firstPoint, Int32 lastPoint, Double tolerance, 

    ref List<Int32> pointIndexsToKeep)

{

    Double maxDistance = 0;

    Int32 indexFarthest = 0;

    

    for (Int32 index = firstPoint; index < lastPoint; index++)

    {

        Double distance = PerpendicularDistance

            (points[firstPoint], points[lastPoint], points[index]);

        if (distance > maxDistance)

        {

            maxDistance = distance;

            indexFarthest = index;

        }

    }



    if (maxDistance > tolerance && indexFarthest != 0)

    {

        //Add the largest point that exceeds the tolerance

        pointIndexsToKeep.Add(indexFarthest);

    

        DouglasPeuckerReduction(points, firstPoint, 

        indexFarthest, tolerance, ref pointIndexsToKeep);

        DouglasPeuckerReduction(points, indexFarthest, 

        lastPoint, tolerance, ref pointIndexsToKeep);

    }

}



/// <summary>

/// The distance of a point from a line made from point1 and point2.

/// </summary>

/// <param name="pt1">The PT1.</param>

/// <param name="pt2">The PT2.</param>

/// <param name="p">The p.</param>

/// <returns></returns>

public static Double PerpendicularDistance

    (Point Point1, Point Point2, Point Point)

{

    //Area = |(1/2)(x1y2 + x2y3 + x3y1 - x2y1 - x3y2 - x1y3)|   *Area of triangle

    //Base = v((x1-x2)²+(x1-x2)²)                               *Base of Triangle*

    //Area = .5*Base*H                                          *Solve for height

    //Height = Area/.5/Base



    Double area = Math.Abs(.5 * (Point1.X * Point2.Y + Point2.X * 

    Point.Y + Point.X * Point1.Y - Point2.X * Point1.Y - Point.X * 

    Point2.Y - Point1.X * Point.Y));

    Double bottom = Math.Sqrt(Math.Pow(Point1.X - Point2.X, 2) + 

    Math.Pow(Point1.Y - Point2.Y, 2));

    Double height = area / bottom * 2;



    return height;

    

    //Another option

    //Double A = Point.X - Point1.X;

    //Double B = Point.Y - Point1.Y;

    //Double C = Point2.X - Point1.X;

    //Double D = Point2.Y - Point1.Y;

    

    //Double dot = A * C + B * D;

    //Double len_sq = C * C + D * D;

    //Double param = dot / len_sq;

    

    //Double xx, yy;

    

    //if (param < 0)

    //{

    //    xx = Point1.X;

    //    yy = Point1.Y;

    //}

    //else if (param > 1)

    //{

    //    xx = Point2.X;

    //    yy = Point2.Y;

    //}

    //else

    //{

    //    xx = Point1.X + param * C;

    //    yy = Point1.Y + param * D;

    //}

    

    //Double d = DistanceBetweenOn2DPlane(Point, new Point(xx, yy));

}/// <summary>

/// Uses the Douglas Peucker algorithm to reduce the number of points.

/// </summary>

/// <param name="Points">The points.</param>

/// <param name="Tolerance">The tolerance.</param>

/// <returns></returns>

public static List<Point> DouglasPeuckerReduction

    (List<Point> Points, Double Tolerance)

{

    if (Points == null || Points.Count < 3)

    return Points;



    Int32 firstPoint = 0;

    Int32 lastPoint = Points.Count - 1;

    List<Int32> pointIndexsToKeep = new List<Int32>();



    //Add the first and last index to the keepers

    pointIndexsToKeep.Add(firstPoint);

    pointIndexsToKeep.Add(lastPoint);



    //The first and the last point cannot be the same

    while (Points[firstPoint].Equals(Points[lastPoint]))

    {

        lastPoint--;

    }



    DouglasPeuckerReduction(Points, firstPoint, lastPoint, 

    Tolerance, ref pointIndexsToKeep);



    List<Point> returnPoints = new List<Point>();

    pointIndexsToKeep.Sort();

    foreach (Int32 index in pointIndexsToKeep)

    {

        returnPoints.Add(Points[index]);

    }



    return returnPoints;

}

    

/// <summary>

/// Douglases the peucker reduction.

/// </summary>

/// <param name="points">The points.</param>

/// <param name="firstPoint">The first point.</param>

/// <param name="lastPoint">The last point.</param>

/// <param name="tolerance">The tolerance.</param>

/// <param name="pointIndexsToKeep">The point index to keep.</param>

private static void DouglasPeuckerReduction(List<Point> 

    points, Int32 firstPoint, Int32 lastPoint, Double tolerance, 

    ref List<Int32> pointIndexsToKeep)

{

    Double maxDistance = 0;

    Int32 indexFarthest = 0;

    

    for (Int32 index = firstPoint; index < lastPoint; index++)

    {

        Double distance = PerpendicularDistance

            (points[firstPoint], points[lastPoint], points[index]);

        if (distance > maxDistance)

        {

            maxDistance = distance;

            indexFarthest = index;

        }

    }



    if (maxDistance > tolerance && indexFarthest != 0)

    {

        //Add the largest point that exceeds the tolerance

        pointIndexsToKeep.Add(indexFarthest);

    

        DouglasPeuckerReduction(points, firstPoint, 

        indexFarthest, tolerance, ref pointIndexsToKeep);

        DouglasPeuckerReduction(points, indexFarthest, 

        lastPoint, tolerance, ref pointIndexsToKeep);

    }

}



/// <summary>

/// The distance of a point from a line made from point1 and point2.

/// </summary>

/// <param name="pt1">The PT1.</param>

/// <param name="pt2">The PT2.</param>

/// <param name="p">The p.</param>

/// <returns></returns>

public static Double PerpendicularDistance

    (Point Point1, Point Point2, Point Point)

{

    //Area = |(1/2)(x1y2 + x2y3 + x3y1 - x2y1 - x3y2 - x1y3)|   *Area of triangle

    //Base = v((x1-x2)²+(x1-x2)²)                               *Base of Triangle*

    //Area = .5*Base*H                                          *Solve for height

    //Height = Area/.5/Base



    Double area = Math.Abs(.5 * (Point1.X * Point2.Y + Point2.X * 

    Point.Y + Point.X * Point1.Y - Point2.X * Point1.Y - Point.X * 

    Point2.Y - Point1.X * Point.Y));

    Double bottom = Math.Sqrt(Math.Pow(Point1.X - Point2.X, 2) + 

    Math.Pow(Point1.Y - Point2.Y, 2));

    Double height = area / bottom * 2;



    return height;

    

    //Another option

    //Double A = Point.X - Point1.X;

    //Double B = Point.Y - Point1.Y;

    //Double C = Point2.X - Point1.X;

    //Double D = Point2.Y - Point1.Y;

    

    //Double dot = A * C + B * D;

    //Double len_sq = C * C + D * D;

    //Double param = dot / len_sq;

    

    //Double xx, yy;

    

    //if (param < 0)

    //{

    //    xx = Point1.X;

    //    yy = Point1.Y;

    //}

    //else if (param > 1)

    //{

    //    xx = Point2.X;

    //    yy = Point2.Y;

    //}

    //else

    //{

    //    xx = Point1.X + param * C;

    //    yy = Point1.Y + param * D;

    //}

    

    //Double d = DistanceBetweenOn2DPlane(Point, new Point(xx, yy));

}



你可能感兴趣的:(数据)