2013-04-23 58 views
6

Trong three.js có một hàm triangulateShape(). Bây giờ tôi gặp phải sự thất bại trong việc triangulate đa giác được đơn giản hóa bằng cách sử dụng Javascript Clipper. Đơn giản hóa trong Clipper được thực hiện bằng cách sử dụng Unioning. Wikipedia article xác định liên kết khi tìm đa giác đơn giản hoặc đa giác chứa vùng bên trong một trong hai đa giác đơn giản. Cùng một bài báo nói rằng trong đa giác đơn giản "chính xác hai cạnh gặp nhau ở mỗi đỉnh" và cũng xác định một đa giác đơn giản yếu, nơi các cạnh có thể gặp nhau, nhưng không nói gì về trường hợp cạnh không đáp ứng, nhưng một số hoặc nhiều đỉnh đáp ứng . Vì vậy, có một chút không rõ ràng nếu trường hợp này giống như đa giác đơn giản hoặc đa giác đơn giản yếu.Ba.js đa giác tam giác không thành công trong các điểm trùng lặp giả

Clipper đã chọn một cách tiếp cận cho phép: đa giác đơn giản có thể có các điểm tương tự như chạm (hoặc trùng lặp). This Clipper style permissive approach khiến các đa giác đơn giản được tạo ra không đơn giản theo ý nghĩa của những gì three.js: s triangulateShape() mong đợi.

Hình ảnh sau đây cho thấy hai ví dụ về trường hợp cạnh này. Đa giác bên trái là một đa giác "đơn giản", chấm đỏ là "trùng lặp". Một trong những quyền cũng là một đa giác "đơn giản", nhưng dấu chấm màu đỏ là một "trùng lặp".

enter image description here

triangulateShape() thất bại trong những trường hợp này, bởi vì nó theo dõi điểm trong mảng allPointsMap và kiểm tra từ đó nếu điểm là trùng lặp. Để loại bỏ các bản sao như tôi có hai lựa chọn:


OPTION 1.

Change Javascript Clipper mã nội bộ để xử lý các sử dụng thêm tham số ví dụ. breakPolygonByWeakDuplicates cho SimplifyPolygon()SimplifyPolygons(). Như Angus Johnson mô tả in his post, sự thay đổi sẽ là một cái gì đó như:

Trong IntersectEdges() phương pháp, thay đổi theo từ ...

 
if (e1Contributing && e2contributing) 
{ 
    if (e1stops || e2stops || 
    (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) || 
    (e1->polyType != e2->polyType && m_ClipType != ctXor)) 
     AddLocalMaxPoly(e1, e2, pt); 
    else 
     DoBothEdges(e1, e2, pt); 
} 

để ...

 

if (e1Contributing && e2contributing) 
{ 
    AddLocalMaxPoly(e1, e2, pt); 
    AddLocalMinPoly(e1, e2, pt); 
} 

Các thay đổi là rất dễ dàng, nhưng sau đó ban đầu Angus Johnson Clipper và Javascript Clipper sẽ không được bất kỳ tương thích hơn. Tất nhiên nếu Clipper ban đầu sẽ thực hiện thay đổi, thì Clipper Clipper sẽ thực hiện theo.


OPTION 2.

Để thay đổi three.js đang triangulateShape() nguồn để chấp nhận cũng giả bản sao.


Câu hỏi của tôi là: Trong đó chấm dứt thói quen đơn giản hóa thêm như thế này nên được thực hiện? Đầu tiên là bên sáng tạo (Clipper) và đầu kia là bên tam giác (ba.js).

Tôi không biết thói quen tam giác đa giác trong các thư viện 3D khác nhau, vì vậy không thể tưởng tượng cách thói quen tam giác cho phép nói chung là như thế nào. Nếu ai đó biết khu vực này, anh/cô ấy có thể đưa ra câu trả lời phức tạp hơn.

Ngoài ra tôi không biết cách các thư viện boolean khác xử lý liên kết hoặc đơn giản hóa việc này như trùng lặp giả. Chắc chắn có một lý do tại sao Clipper được cho phép trong các phương tiện của đa giác đơn giản (ví dụ: tương thích với các thư viện boolean khác), nhưng chắc chắn điều này làm cho các vấn đề trong tam giác đa giác trong ba.js.

Để tham khảo ở đây là mã triangulating của 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 

UPDATE: Tôi đã thực hiện một SVG http://jsbin.com/ugimab/1 nơi là một ví dụ của một đa giác có điểm (150.150) mà là một yếu trùng lặp hoặc trùng lặp giả. Chương trình sau nhiều cách khác nhau để đại diện cho đa giác này:

 
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"; 


UPDATE: Nếu ai đó đã cố gắng tìm một giải pháp cho triangulating cũng đa giác mà có điều này như một cách yếu ớt lặp lại điểm, nó sẽ rất hữu ích nếu bạn sẽ xuất bản phát hiện của bạn.


Cập nhật: Đã chọn tùy chọn 1, nhưng không thành công: http://jsbin.com/owivew/1. Đa giác vẫn là một mảnh, mặc dù nó phải được nhổ ra thành hai phần. Có lẽ Angus Johnson (tác giả của Clipper) có giải pháp tốt hơn để cung cấp.


CẬP NHẬT: Đây là đa giác "đơn giản" phức tạp hơn (sau khi đơn giản hóa trong Clipper). Tất cả các điểm mà dường như được với nhau là chính xác giống hệt nhau. Để phân chia điều này thành đa giác thực sự đơn giản, sẽ yêu cầu nó được chia thành nhiều phần. Đôi mắt của tôi nói rằng đây là 4 đa giác dưới cùng và một đa giác trên (lớn hơn) có lỗ, vì vậy tổng số đơn giản hóa điều này sẽ tạo ra 5 đa giác bên ngoài và 1 lỗ. Hoặc cách khác một đa giác bên ngoài có 5 lỗ. Hoặc có thể một số kết hợp khác của outers và lỗ. Nó có thể được đơn giản hóa theo nhiều cách khác nhau.

Fiddle nằm trong http://jsbin.com/ugimab/3 (cũng là phiên bản JSON của đa giác).

enter image description here

Và đây là những điểm được đánh số 0-25:

enter image description here

Trong các đỉnh hình ảnh 2,11,14,25 đều giống nhau phối hợp, vì vậy nó là một " pseudo-multiple-vertice ". Vertex3 không phải là bản sao, nhưng nó chạm vào cạnh 6-7.


UPDATE:

The suggested method đó là dựa trên di chuyển điểm trùng lặp dường như làm việc. Nếu điểm trùng lặp được thay thế bằng hai điểm nằm trên khoảng cách nhất định của tọa độ trùng lặp, tạo ra hiệu ứng "ngòi bút bị hỏng", công cụ triangulation, vì đa giác được tạo ra sau đó là đa giác đơn giản thực sự, đó là yêu cầu cho tam giác. Ngoài ra không được phép trùng lặp giữa đường bao và lỗ cũng không giữa các lỗ và lỗ. Hình ảnh sau đây cho thấy hiệu quả của phương pháp này. Khoảng cách là ở đây 10px để hiển thị hiệu ứng, nhưng trong thực tế ví dụ. 0,001 là đủ để làm cho đa giác đơn giản. Ngoài ra triangulator mặc định trong Three.js r58 không hoạt động như mong đợi, nhưng nếu nó được thay đổi thành Poly2tri, thì tất cả đều tốt. Quá trình này được mô tả trong báo cáo lỗi khá dài này: https://github.com/mrdoob/three.js/issues/3386.

enter image description here

+0

Bạn có thể chia sẻ tệp json nguồn của mình với các điểm không. Bạn đang đề cập đến nó nhưng liên kết dường như bị thiếu. – Wilt

+0

[{"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}] –

Trả lời

3

Bạn có thể viết một hàm có khả năng dò đỉnh trùng lặp và di chuyển chúng ngược 1px để làm cho họ rời rạc (họ không chia sẻ một cạnh chung). Bằng cách này sẽ không có cạnh phổ biến hơn và không có lỗi được tạo ra nhưng kết quả hình ảnh vẫn trông giống nhau.

Loại dung dịch thô nhưng có thể hoạt động.

+1

Cảm ơn câu trả lời! Giải pháp này nghe có vẻ tốt. Bạn có nghĩa là lạc hậu = về phía đỉnh trước đó? –

+0

Có chính xác lời xin lỗi của tôi vì đã không nói rõ điều đó. –

+1

Giải pháp này dường như hoạt động rất tốt, nếu thêm một đỉnh được thêm vào cạnh tiếp theo của bản sao, để có một chút "hiệu ứng đầu bút bị hỏng", không thể nhìn thấy trong thế giới thực. Không gây ra bất kỳ ngã tư nào. Nhưng tôi cũng phải thử nghiệm với các đa giác thực sự phức tạp, trước khi có thể chắc chắn rằng phương pháp này thực sự hoạt động như một bước trước khi triangulations. –

0

Có một số vấn đề với giải pháp tam giác được sử dụng trong three.js. Có một số thư viện triangulation javascript khác có sẵn và nó có thể rất tốt là trong tương lai thư viện hiện tại sẽ được trao đổi cho một cái gì đó khác như ví dụ earcut.js. Có một cuộc thảo luận về điều này here in this issue on GitHub.

Vấn đề của bạn về các cạnh tự giao nhau không phải là vấn đề đối với việc cắt tai như được minh họa in this multi viewer here.


Nếu bạn đã muốn sử dụng giải pháp tam giác khác trong dự án của mình, tôi muốn tham khảo three.js triangulation library (an adapter) Tôi đã thực hiện. Adapter cho phép kết nối ba thư viện tam giác khác hoàn hảo cho dự án three.js của bạn:

  • earcut - earcut triangulation thư viện
  • poly2tri - poly2tri triangulation thư viện
  • libtess - libtess thư viện tessellation

Tất cả bạn cần làm là bao gồm tệp triangulation.js:

<script src="triangulation.js"></script> 

Và thiết lập các thư viện lựa chọn của bạn bằng cách sử dụng phương pháp setLibrary:

THREE.Triangulation.setLibrary('earcut'); 

Tùy thuộc vào thư viện bạn chọn bạn sẽ rõ ràng cần phải nhúng các tập tin cho các thư viện riêng của mình. Hiện tại đối với libtess cần thêm tessy.js có thể tìm thấy trong kho lưu trữ.

Đọc thêm về dự án here on GitHub.

Các vấn đề liên quan