在three.js中有一个函数triangulateShape()
。现在,我遇到了使用 Javascript Clipper 简化的多边形三角剖分失败。Clipper 中的简化是使用联合来完成的。维基百科文章将联合定义为找到包含两个简单多边形之一内的区域的一个或多个简单多边形。同一篇文章说,在简单多边形中,“每个顶点恰好有两条边相交”,并且还确定了一个弱简单的多边形,其中边可以相交,但没有提到边不相交但一些或多个顶点相交的边缘情况. 所以有点不清楚这种情况是简单的多边形还是弱简单的多边形。
Clipper 选择了一种宽松的方法:简单的多边形可以有这些类似接触(或伪重复)的顶点。这种 Clipper 风格的许可方法导致生成的简单多边形并不像 three.js:s 所triangulateShape()
期望的那样简单。
下图显示了这种边缘情况的两个示例。左边的多边形是一个“简单”多边形,红点是一个“重复”。右边也是一个“简单”多边形,但红点是一个“重复”。
triangulateShape()
在这些情况下会失败,因为它会跟踪数组中的点allPointsMap
并从那里检查该点是否重复。要删除这些重复项,我有两个选择:
OPTION 1.
更改 Javascript Clipper 内部代码以使用额外参数处理这些,例如。breakPolygonByWeakDuplicates
对于SimplifyPolygon()
和SimplifyPolygons()
。正如 Angus Johnson在他的帖子中所描述的那样,变化将类似于:
在 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.jstriangulateShape()
源代码以接受伪重复。
我的问题是:应该在哪一端完成这种额外的简化程序?第一端是创建端(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。
更新:
基于移动重复点的建议方法似乎有效。如果将复制点替换为复制坐标一定距离上的两个点,产生“断笔尖”效果,三角剖分就可以了,因为生成的多边形是真正的简单多边形,这是三角剖分的要求。轮廓和孔之间以及孔和孔之间也不允许重复。下图显示了这种方法的效果。此处的距离为 10px 以显示效果,但实际上例如。0.001 足以使多边形变得简单。Three.js r58 中的默认三角测量器也无法按预期工作,但如果将其更改为 Poly2tri,则一切正常。这个过程在这个相当长的错误报告中描述:https://github.com/mrdoob/three.js/issues/3386。