/** * Calculates Delaunay triangles out of array of 2D points * * @param innerPts points inside edges defined by edgePts * @param edgePts points on the edge (the edge should be naked having only one triangle touching); * order of edge points needs to be counter clockwise for outer trim loop, clockwise for inner * hole trim loop. * @return array of triangles, which consist of array of 3 points of IVec2 */ public static IVec2[][] getTriangles(IVec2[] innerPts, IVec2[][] edgePts) { int innerPtsNum = 0; int edgePtsNum = 0; if (innerPts != null) innerPtsNum = innerPts.length; if (edgePts != null) { for (int i = 0; i < edgePts.length; i++) edgePtsNum += edgePts[i].length; } IVec2[] pts = new IVec2[innerPtsNum + edgePtsNum]; if (innerPts != null) { for (int i = 0; i < innerPts.length; i++) { pts[i] = innerPts[i]; // IOut.p("pts["+i+"] is innerPts "+innerPts[i]); // } } int[][] edgePtIdx = null; if (edgePts != null) { edgePtIdx = new int[edgePts.length][]; int ptIdx = innerPtsNum; for (int i = 0; i < edgePts.length; i++) { edgePtIdx[i] = new int[edgePts[i].length]; for (int j = 0; j < edgePts[i].length; j++) { // IOut.p("ptIdx="+ptIdx+" / pts.length="+pts.length); // // IOut.p("pts["+ptIdx+"] is edgePts "+edgePts[i][j]); // pts[ptIdx] = edgePts[i][j]; edgePtIdx[i][j] = ptIdx; ptIdx++; } } } if (pts.length == 3) { if (isClockwise(pts[0], pts[1], pts[2])) return new IVec2[][] {new IVec2[] {pts[0], pts[2], pts[1]}}; return new IVec2[][] {new IVec2[] {pts[0], pts[1], pts[2]}}; } ArrayList<IVec2[]> triangles = new ArrayList<IVec2[]>(); ArrayList<FaceIndex> triangleIndex = new ArrayList<FaceIndex>(); // IOut.p("pts.length = "+pts.length); // // for(int i=0; i<pts.length; i++) IOut.p("pts["+i+"] = "+ pts[i]); // EdgeCounter edgeCount = new EdgeCounter(pts.length); for (int i = 0; i < edgePtIdx.length; i++) { for (int j = 0; j < edgePtIdx[i].length; j++) { edgeCount.addEdge(edgePtIdx[i][j], edgePtIdx[i][(j + 1) % edgePtIdx[i].length]); } } // in case a point on edges are on other loop's edge for (int i = 0; i < edgePtIdx.length; i++) { for (int j = 0; j < edgePtIdx[i].length; j++) { int ept1 = edgePtIdx[i][j]; int ept2 = edgePtIdx[i][(j + 1) % edgePtIdx[i].length]; for (int k = 0; k < edgePtIdx.length; k++) { if (k != i) { for (int l = 0; l < edgePtIdx[k].length; l++) { if (pts[edgePtIdx[k][l]].isStraight(pts[ept1], pts[ept2]) && pts[edgePtIdx[k][l]].isBetween(pts[ept1], pts[ept2])) { edgeCount.addEdge(ept1, edgePtIdx[k][l]); edgeCount.addEdge(ept2, edgePtIdx[k][l]); } } } } } } for (int i = 0; i < pts.length - 2; i++) { // IOut.p((i+1)+"/"+(pts.length-2)); // for (int j = i + 1; j < pts.length - 1; j++) { for (int k = j + 1; k < pts.length && edgeCount.isEdgeOpen(i, j); k++) { boolean anyInside = false; // IOut.p("<"+i+","+j+","+k+">"); // // IOut.p("isFaceCrossing = "+ isFaceCrossing(pts, edgeCount, i, j, k)); // IOut.p("checkDirectionOnEdgePoints = // "+checkDirectionOnEdgePoints(pts,edgePts,i,j,k,innerPtsNum) ); // IOut.p("isStraight = "+pts[i].isStraight(pts[j],pts[k])); // if (edgeCount.isEdgeOpen(i, k) && edgeCount.isEdgeOpen(j, k) && !isFaceCrossing(pts, edgeCount, i, j, k) // && checkFaceDirection(pts, edgeCount, i, j, k) && checkDirectionOnEdgePoints(pts, edgePts, i, j, k, innerPtsNum) // added && !pts[i].isStraight(pts[j], pts[k]) // added ) { for (int l = 0; l < pts.length && !anyInside; l++) if (l != i && l != j && l != k) { // IOut.p("<"+i+","+j+","+k+","+l+">"); // if (isInsideCircumcircle(pts[l], pts[i], pts[j], pts[k])) { // check if case pts[l] is crossing edge of trim lines if (checkDirectionOfInnerCircumcirclePoint( pts, edgePts, i, j, k, l, innerPtsNum)) { anyInside = true; // IOut.p(pts[l] + " is inside <"+pts[i]+", "+pts[j]+", "+pts[k]+">"); // // IOut.p("pt["+l+"] is INside pt["+i+"], pt["+j+"], pt["+k+"]"); // } // else; // when pts[l] is crossing the edge of trim } else { // IOut.p(pts[l] + " is outside <"+pts[i]+", "+pts[j]+", "+pts[k]+">"); // // IOut.p("pt["+l+"] is OUTside pt["+i+"], pt["+j+"], pt["+k+"]"); // } } if (!anyInside) { // nothing is inside // IOut.p("<"+i+","+j+","+k+">: triangle is added at "+triangles.size()); // if (isClockwise(pts[i], pts[j], pts[k])) { triangles.add(new IVec2[] {pts[i], pts[k], pts[j]}); triangleIndex.add(new FaceIndex(i, k, j)); } else { triangles.add(new IVec2[] {pts[i], pts[j], pts[k]}); triangleIndex.add(new FaceIndex(i, j, k)); } /* if(i==0&&j==1&&k==4){ new IGCurve(new IVec[]{ new IVec(pts[i]), new IVec(pts[j]), new IVec(pts[k])}); } */ edgeCount.addFace(i, j, k); // IOut.p("edgeCount.isEdgeOnOutline("+i+","+j+") = "+edgeCount.isEdgeOnOutline(i,j)); // IOut.p("edgeCount.getEdgeNum("+i+","+j+") = "+edgeCount.getEdgeNum(i,j)); // IOut.p("edgeCount.getFaceVertexIndex("+i+","+j+") = // "+edgeCount.getFaceVertexIndex(i,j)); // edgeCount.addEdge(i,j); // edgeCount.addEdge(i,k); // edgeCount.addEdge(j,k); } // else IOut.p("pt out"); // } } } } // filling holes checkNakedEdge(pts, triangleIndex, triangles, edgeCount); // IOut.p("trinangles.size()="+triangles.size()); // return triangles.toArray(new IVec2[triangles.size()][]); }