【发布时间】:2013-04-23 00:24:37
【问题描述】:
在three.js 中有一个函数triangulateShape()。现在,我遇到了使用 Javascript Clipper 简化的多边形三角剖分失败。 Clipper 中的简化是使用联合来完成的。 Wikipedia article 将联合确定为找到包含两个简单多边形之一内的区域的一个或多个简单多边形。同一篇文章说,在简单多边形中,“每个顶点恰好有两条边相交”,并且还确定了一个弱简单的多边形,其中边可以相交,但没有提到边不相交但一些或多个顶点相交的边缘情况.所以有点不清楚这种情况是简单多边形还是弱简单多边形。
Clipper 选择了一种宽松的方法:简单的多边形可以有这些类似接触(或伪重复)的顶点。 This Clipper style permissive approach 导致生成的简单多边形并不像three.js:s triangulateShape() 所期望的那样简单。
下图显示了这种边缘情况的两个示例。左边的多边形是一个“简单”多边形,红点是一个“重复”。右边也是一个“简单”多边形,但红点是一个“重复”。
triangulateShape() 在这些情况下会失败,因为它会跟踪数组 allPointsMap 中的点,并从那里检查该点是否重复。要删除这些类似的重复项,我有两个选择:
OPTION 1.
更改 Javascript Clipper 内部代码以使用额外参数来处理这些问题,例如。 breakPolygonByWeakDuplicates 用于 SimplifyPolygon() 和 SimplifyPolygons()。正如 Angus Johnson 所描述的 in his post,更改将类似于:
在 IntersectEdges() 方法中,将跟随从 ...
if ( e1Contributing && e2contributing ) { 如果 ( e1stops || e2stops || (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) || (e1->polyType != e2->polyType && m_ClipType != ctXor) ) AddLocalMaxPoly(e1, e2, pt); 别的 DoBothEdges(e1,e2,pt); }到...
if ( e1Contributing && e2contributing ) { AddLocalMaxPoly(e1, e2, pt); AddLocalMinPoly(e1, e2, pt); }更改非常简单,但原来的 Angus Johnson Clipper 和 Javascript Clipper 将不再那么兼容。当然,如果原来的 Clipper 会做出改变,Javascript Clipper 也会跟着做。
OPTION 2.
更改 three.js triangulateShape() 源代码以接受伪重复。
我的问题是:应该在哪一端完成这种额外的简化程序?一端是创建端(Clipper),另一端是三角剖分端(three.js)。
我不知道各种 3D 库中的多边形三角剖分例程,因此无法想象三角剖分例程一般有多么宽松。如果有人知道这个领域,他/她可以给出更复杂的答案。
另外我不知道其他布尔库如何处理联合或简化这种伪重复。 Clipper 允许使用简单多边形的方式肯定是有原因的(例如,与其他布尔库的兼容性),但这肯定会在 three.js 中对多边形进行三角剖分。
这里是three.js的三角代码供参考:
triangulateShape: function ( contour, holes ) {
var shapeWithoutHoles = THREE.Shape.Utils.removeHoles( contour, holes );
var shape = shapeWithoutHoles.shape,
allpoints = shapeWithoutHoles.allpoints,
isolatedPts = shapeWithoutHoles.isolatedPts;
var triangles = THREE.FontUtils.Triangulate( shape, false ); // True returns indices for points of spooled shape
// To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first.
//console.log( "triangles",triangles, triangles.length );
//console.log( "allpoints",allpoints, allpoints.length );
var i, il, f, face,
key, index,
allPointsMap = {},
isolatedPointsMap = {};
// prepare all points map
for ( i = 0, il = allpoints.length; i < il; i ++ ) {
key = allpoints[ i ].x + ":" + allpoints[ i ].y;
if ( allPointsMap[ key ] !== undefined ) {
console.log( "Duplicate point", key );
}
allPointsMap[ key ] = i;
}
// check all face vertices against all points map
for ( i = 0, il = triangles.length; i < il; i ++ ) {
face = triangles[ i ];
for ( f = 0; f < 3; f ++ ) {
key = face[ f ].x + ":" + face[ f ].y;
index = allPointsMap[ key ];
if ( index !== undefined ) {
face[ f ] = index;
}
}
}
// check isolated points vertices against all points map
for ( i = 0, il = isolatedPts.length; i < il; i ++ ) {
face = isolatedPts[ i ];
for ( f = 0; f < 3; f ++ ) {
key = face[ f ].x + ":" + face[ f ].y;
index = allPointsMap[ key ];
if ( index !== undefined ) {
face[ f ] = index;
}
}
}
return triangles.concat( isolatedPts );
}, // end triangulate shapes
更新:我制作了一个 SVG http://jsbin.com/ugimab/1,其中是具有点 (150,150) 的多边形的示例,该点是弱重复或伪重复。以下显示了表示此多边形的各种方法:
var weakDuplicate1 = [{"X":100,"Y":200},{"X":150,"Y":150},{"X":100,"Y":100},{"X" :200,"Y":100},{"X":150,"Y":150},{"X":200,"Y":200}]; var weakDuplicate2 = [100,200, 150,150, 100,100, 200,100, 150,150, 200,200]; var weakDuplicate3 = "M100,200 L150,150 L100,100 L200,100 L150,150 L200,200Z";更新:如果有人设法找到一种解决方案来对具有这种弱重复点的多边形进行三角剖分,那么如果您能发布您的发现将会非常有帮助。
更新:已测试选项 1,但未成功:http://jsbin.com/owivew/1。多边形仍然是一个整体,尽管它应该被分成两部分。也许安格斯·约翰逊(快船的创造者)可以提供更好的解决方案。
更新:这是一个更复杂的“简单”多边形(在 Clipper 中简化后)。所有似乎在一起的点都是完全相同的。要将其划分为真正简单的多边形,需要将其分成几部分。我的眼睛说这里有 4 个底部多边形和一个(更大的)带有孔的上部多边形,因此总体简化这将产生 5 个外部多边形和 1 个孔。或者,一个具有 5 个孔的外部多边形。或者可能是其他一些外部和孔的组合。它可以通过多种不同的方式进行简化。
小提琴在http://jsbin.com/ugimab/3(也是多边形的JSON版本)中。
这里是从 0 到 25 编号的点:
图像中2、11、14、25的顶点坐标相同,所以是“伪多顶点”。 Vertex3 不是重复的,但它触及边 6-7。
更新:
The suggested method 基于移动重复点似乎有效。如果将复制点替换为复制坐标一定距离上的两个点,产生“断笔尖”效果,三角剖分就可以了,因为生成的多边形是真正的简单多边形,这是三角剖分的要求。轮廓和孔之间以及孔和孔之间也不允许重复。下图显示了这种方法的效果。此处的距离为 10px 以显示效果,但实际上例如。 0.001 足以使多边形变得简单。 Three.js r58 中的默认三角测量器也无法按预期工作,但如果将其更改为 Poly2tri,则一切正常。这个过程在这个相当长的错误报告中描述:https://github.com/mrdoob/three.js/issues/3386。
【问题讨论】:
-
你能把你的源json文件分享给点。您指的是它,但链接似乎丢失了。
-
[{"X":270,"Y":520},{"X":130,"Y":490},{"X":210,"Y":250} ,{"X":60,"Y":170},{"X":130,"Y":490},{"X":20,"Y":410},{"X":60, "Y":300},{"X":60,"Y":20},{"X":780,"Y":40},{"X":680,"Y":180},{ "X":460,"Y":130},{"X":210,"Y":250},{"X":320,"Y":100},{"X":220,"Y ":80},{"X":210,"Y":250},{"X":520,"Y":250},{"X":680,"Y":180},{"X ":770,"Y":480},{"X":540,"Y":470},{"X":520,"Y":250},{"X":380,"Y": 280},{"X":430,"Y":390},{"X":540,"Y":470},{"X":270,"Y":520},{"X": 330,"Y":350},{"X":210,"Y":250}]
标签: three.js polygon boolean-operations