2012-08-13 156 views
9

我正在使用JavaScript画布处理项目,并且需要能够将光标捕捉到与多边形相距一定距离。我已经可以捕捉到多边形本身,但是我需要将光标放得更远。缩放多边形,使边缘匹配

据我可以告诉最好的方法去做这个是缩放多边形和捕捉,但是当我缩放多边形时,旧的多边形的边缘和新的多边形的边缘之间的距离don永远不会匹配。

这里是问题的一个例子:

enter image description here enter image description here

编辑:灰色代表原始多边形,红色的是什么,我得到,如果我正常缩放多边形,和绿色是我正在努力完成的

我已经尝试将多边形转换为原点并乘以比例因子,但似乎无法将每个边缘缩放一定的距离。

+0

请解释一下你的形象,这部分做的红色和绿色代表什么? – Hogan 2012-08-13 20:48:55

+0

谢谢。编辑。 – davey555 2012-08-13 21:08:16

+0

您可以发布您用于多边形,平移和缩放的代码吗?你是什​​么意思“不总是匹配”?它在什么情况下失败? – 2012-08-13 21:14:52

回答

1

我可以提供使用JSTS库(的JTS JavaScript的端口)的溶液中。图书馆有多边形膨胀/收缩(抵消)的方法。

如果要获取具有不同类型边的充气多边形,可以设置顶盖和连接样式。你所要做的唯一一件事情就是转换你的多边形坐标的JSTS坐标是非常简单的:

function vectorCoordinates2JTS (polygon) { var coordinates = []; for (var i = 0; i < polygon.length; i++) { coordinates.push(new jsts.geom.Coordinate(polygon[i].x, polygon[i].y)); } return coordinates; }

一旦你转换的坐标,你可以抬高你的多边形:

function inflatePolygon(poly, spacing) { 
    var geoInput = vectorCoordinates2JTS(poly); 
    geoInput.push(geoInput[0]); 

    var geometryFactory = new jsts.geom.GeometryFactory(); 

    var shell = geometryFactory.createPolygon(geoInput); 
    var polygon = shell.buffer(spacing); 
    //try with different cap style 
    //var polygon = shell.buffer(spacing, jsts.operation.buffer.BufferParameters.CAP_FLAT); 

    var inflatedCoordinates = []; 
    var oCoordinates; 
    oCoordinates = polygon.shell.points.coordinates; 

    for (i = 0; i < oCoordinates.length; i++) { 
    var oItem; 
    oItem = oCoordinates[i]; 
    inflatedCoordinates.push(new Vector2(Math.ceil(oItem.x), Math.ceil(oItem.y))); 
    } 
    return inflatedCoordinates; 
} 

随着代码我已经张贴在jsFiddle你会得到这样的事情:

enter image description here

附加信息: 我通常会在地图上绘制的多边形(使用Leaflet或Google地图)上使用此类型的充气/缩小(稍微更改)来设置具有半径的边界。您只需将lat,lng对转换为JSTS坐标,其他部分都是相同的。例如:

enter image description here

+0

哇,这很好,我希望我有这3年前... – davey555 2016-08-29 18:16:30

2

一种方法是找到多边形的每条边和光标点之间的距离,并保持最小。

要计算点与线段之间的距离,请将点投影到支撑线上;如果投影落在端点之间,则解决方案是点到线距离;否则,解决方案是到最近端点的距离。

这很容易使用矢量演算来计算。

3

ISTM你所追求的是多边形抵消算法或库。
An algorithm for inflating/deflating (offsetting, buffering) polygons

+0

在JavaScript中做多边形偏移的任何想法? – 2012-11-06 01:52:16

+1

Java库JTS(Java Topology Suite)可以抵消(尽管它在那里称为缓冲)。请参阅https://sourceforge.net/projects/jts-topo-suite/ – 2012-11-07 12:56:24

+0

它是Java,而不是JavaScript,并且在那里也需要移植过程。它如何与Clipper相比? – 2012-11-07 13:02:28

5

我做了一个jsFiddle对于给定的多边形,计算外多边形,我希望能满足您的要求。我已经在这个pdf document后面加上了数学。

更新:代码已经作出处理垂直线。

function Vector2(x, y) 
{ 
    this.x = x; 
    this.y = y; 
} 

function straight_skeleton(poly, spacing) 
{ 
    // http://stackoverflow.com/a/11970006/796832 
    // Accompanying Fiddle: http://jsfiddle.net/vqKvM/35/ 

    var resulting_path = []; 
    var N = poly.length; 
    var mi, mi1, li, li1, ri, ri1, si, si1, Xi1, Yi1; 
    for(var i = 0; i < N; i++) 
    { 
     mi = (poly[(i+1) % N].y - poly[i].y)/(poly[(i+1) % N].x - poly[i].x); 
     mi1 = (poly[(i+2) % N].y - poly[(i+1) % N].y)/(poly[(i+2) % N].x - poly[(i+1) % N].x); 
     li = Math.sqrt((poly[(i+1) % N].x - poly[i].x)*(poly[(i+1) % N].x - poly[i].x)+(poly[(i+1) % N].y - poly[i].y)*(poly[(i+1) % N].y - poly[i].y)); 
     li1 = Math.sqrt((poly[(i+2) % N].x - poly[(i+1) % N].x)*(poly[(i+2) % N].x - poly[(i+1) % N].x)+(poly[(i+2) % N].y - poly[(i+1) % N].y)*(poly[(i+2) % N].y - poly[(i+1) % N].y)); 
     ri = poly[i].x+spacing*(poly[(i+1) % N].y - poly[i].y)/li; 
     ri1 = poly[(i+1) % N].x+spacing*(poly[(i+2) % N].y - poly[(i+1) % N].y)/li1; 
     si = poly[i].y-spacing*(poly[(i+1) % N].x - poly[i].x)/li; 
     si1 = poly[(i+1) % N].y-spacing*(poly[(i+2) % N].x - poly[(i+1) % N].x)/li1; 
     Xi1 = (mi1*ri1-mi*ri+si-si1)/(mi1-mi); 
     Yi1 = (mi*mi1*(ri1-ri)+mi1*si-mi*si1)/(mi1-mi); 
     // Correction for vertical lines 
     if(poly[(i+1) % N].x - poly[i % N].x==0) 
     { 
      Xi1 = poly[(i+1) % N].x + spacing*(poly[(i+1) % N].y - poly[i % N].y)/Math.abs(poly[(i+1) % N].y - poly[i % N].y); 
      Yi1 = mi1*Xi1 - mi1*ri1 + si1; 
     } 
     if(poly[(i+2) % N].x - poly[(i+1) % N].x==0) 
     { 
      Xi1 = poly[(i+2) % N].x + spacing*(poly[(i+2) % N].y - poly[(i+1) % N].y)/Math.abs(poly[(i+2) % N].y - poly[(i+1) % N].y); 
      Yi1 = mi*Xi1 - mi*ri + si; 
     } 

     //console.log("mi:", mi, "mi1:", mi1, "li:", li, "li1:", li1); 
     //console.log("ri:", ri, "ri1:", ri1, "si:", si, "si1:", si1, "Xi1:", Xi1, "Yi1:", Yi1); 

     resulting_path.push({ 
      x: Xi1, 
      y: Yi1 
     }); 
    } 

    return resulting_path; 
} 


var canvas = document.getElementById("Canvas"); 
var ctx = canvas.getContext("2d"); 

var poly = [ 
    new Vector2(150, 170), 
    new Vector2(400, 120), 
    new Vector2(200, 270), 
    new Vector2(350, 400), 
    new Vector2(210, 470) 
]; 

draw(poly); 
draw(straight_skeleton(poly, 10)); 

function draw(p) { 
    ctx.beginPath(); 
    ctx.moveTo(p[0].x, p[0].y); 
    for(var i = 1; i < p.length; i++) 
    { 
     ctx.lineTo(p[i].x, p[i].y); 
    } 
    ctx.strokeStyle = "#000000"; 
    ctx.closePath(); 
    ctx.stroke(); 
} 

将多边形放入点对象数组中。

函数draw(p)在画布上绘制多边形p

给定的多边形位于数组poly中,数组poly中的外部。

spacing是继安格斯·约翰逊的评论多边形之间的距离(如沿着你的绿色图中的箭头)


,我已经产生了一些更小提琴展现他提出的问题。这个问题比我第一次想到的要困难得多。

+1

我已经很快地看过你的代码和ISTM,它只会恰当地抵消最简单的多边形。例如,我看不到任何代码来管理顶点可以相对于偏移距离移动指数距离的非常尖锐的凸角。而且,对于相对短边的锐角凹角,需要有代码来消除由简单偏移引起的自交。 – 2012-08-15 13:43:29

+0

@Angus Johnson我刚刚用你指定的条件试过了,我明白你的意思了。感谢您指出了这一点。我会再考虑一下。也许davey555会评论这些条件是否会在他的申请中出现。 – jing3142 2012-08-15 16:51:24

6

我做了快船的一个javascript端口,有了它,你可以做你想要的方式缩放。

这是充气多边形的一个例子:

enter image description here

检查的Javascript限幅合约的LIVE DEMO

并从https://sourceforge.net/projects/jsclipper/获取clipper.js文件。

Full code example如何抵消多边形,并在html5画布上绘制它们。

相反(放气)也是可能的,如果需要的话:

Offsetting polygons