道格拉斯算法-go语言实现

1.算法概述

道格拉斯算法是一种曲线的点简化算法。

一般来说,在计算机中表示一条曲线往往使用若干个点来表示,将点连接后形成的折线来趋近想要表示的曲线。点的数量越多,就越贴合想要表示的曲线。

点的数量过多,就需要更多的空间去保存,同时,涉及传输或者计算,如将点的现象传输给前端或者用点生成复杂图像,往往需要更多的时间。

在不影响最终绘制效果的前提下,可以将曲线中的点进行适当删除。这个步骤就是点的简化。而在对精确度要求不高的情况下,可以简化更多。

2.算法步骤

算法的基本思路是:

  • 假设要简化一条曲线,曲线的两个端点分别是A和B,容忍度为D,D为一个数值(距离),用于判断一个点是否要保留;
  • 端点AB连接后得到的直线为AB;
  • 遍历曲线上的所有点,计算所有点到AB的距离, 寻找曲线上离AB最远的点C。
  • 假设C到AB的距离为dMax,将dMax与D相比;
  • 如果dMax <D,则只保留AB两点,这个时候,认为曲线是一条直线;
  • 如果dMax ≥D,保留对应的点C,并对AC和CB之间的曲线重复上述流程。

3.代码实现

package Util

import (
    "math"
)

/*
* @author dust347
* @brief
*/
//point
type Point struct{
    X float64
    Y float64
}


//计算两点之间距离
func GetDistPt(x1, y1 float64, x2, y2 float64) float64 {
    return math.Sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2))
}

//计算点到另外两点所确定的直线的距离
func GetDistPt2Line(linePtX1, linePtY1 float64, linePtX2, linePtY2 float64, x, y float64) float64 {
    //如果线的两个点一样,相当于计算两点之间距离
    if (linePtX1 == linePtX2) && (linePtY1 == linePtY2) {
        return GetDistPt(linePtX1, linePtY1, x, y)
    }

    d := (linePtY2*x-linePtY1*x + linePtX1*y-linePtX2*y + linePtX2*linePtY1-linePtX1*linePtY2) / math.Sqrt((linePtY2-linePtY1)*(linePtY2-linePtY1)+(linePtX2-linePtX1)*(linePtX2-linePtX1))
    return math.Abs(d)
}

//道格拉斯抽稀算法
func Douglas(vecPt []Point, tolerance float64) (vecPtRes []Point) {
    l := len(vecPt)
    if l <= 2 {         //小于两个点直接返回
        return vecPt
    }


    //用于标记哪些点需要保留
    m := make(map[int]bool)

    //两端点必保留
    m[0] = true
    m[l-1] = true
    douglas(&vecPt, 0, l-1, tolerance, &m)

    //返回数据
    for i, pt := range vecPt {
        if m[i] {
            vecPtRes = append(vecPtRes, pt)
        }
    }
    return
}

func douglas(vecPt *[]Point, l, r int, tolerance float64, m *map[int]bool) {
    if r - l <= 1 {
        return
    }

    //取两个端点的数据
    x1, y1 := pt2float((*vecPt)[l])
    x2, y2 := pt2float((*vecPt)[r])

    var maxDist float64 = -1        //记录最大距离
    var keepIndex int = -1          //记录要保留的点的index

    for i := l+1; i < r; i++ {
        x, y := pt2float((*vecPt)[i])
        d := GetDistPt2Line(x1, y1, x2, y2, x, y)

        if d > maxDist {
            maxDist = d
            keepIndex = i
        }
    }

    if maxDist > tolerance {
        (*m)[keepIndex] = true
        douglas(vecPt, l, keepIndex, tolerance, m)
        douglas(vecPt, keepIndex, r, tolerance, m)
    }
}

func pt2float(pt Point) (float64, float64) {
    return pt.X, pt.Y
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,527评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,314评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,535评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,006评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,961评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,220评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,664评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,351评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,481评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,397评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,443评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,123评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,713评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,801评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,010评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,494评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,075评论 2 341