package com.vitco.low.triangulate; import org.poly2tri.geometry.polygon.PolygonPoint; import org.poly2tri.triangulation.delaunay.DelaunayTriangle; import java.util.ArrayList; /** * Helper class that converts a grid into triangles. * * Uses the Naive Greedy Meshing approach (highly optimized). * * Reference: * http://0fps.net/2012/06/30/meshing-in-a-minecraft-game/ */ public class Grid2TriNaiveGreedy { // triangulate a bit array (use shorts, slower but works with higher values) private static ArrayList<DelaunayTriangle> triangulateSave(boolean[][] bits) { ArrayList<DelaunayTriangle> result = new ArrayList<DelaunayTriangle>(); short lenX = (short) bits.length; short lenY = (short) bits[0].length; short lenXM = (short) (lenX - 1); short lenYM = (short) (lenY - 1); short pxP,pxN,pyP,pyN; for (short x = 0; x < lenX; x++) { for (short y = 0; y < lenY; y++) { // we found a set point -> start expanding if (bits[x][y]) { // unset point bits[x][y] = false; pxP = lenXM; //pxN = 0; pyP = lenYM; pyN = y; // expand in x direction (positive) for (short i = x; ++i < lenX;) { if (!bits[i][y]) { pxP = --i; break; } else { bits[i][y] = false; } } pxN = x; // expand in y direction (positive) loop: for (short i = y; ++i < lenY;) { if (!bits[pxP][i] || !bits[pxN][i]) { pyP = --i; break; } else { bits[pxP][i] = false; bits[pxN][i] = false; } for (short j = pxN; ++j < pxP;) { if (!bits[j][i]) { for (short k = j; --k > pxN;) { bits[k][i] = true; } bits[pxP][i] = true; bits[pxN][i] = true; pyP = --i; break loop; } else { bits[j][i] = false; } } } // add the triangles for this rectangle result.add(new DelaunayTriangle(new PolygonPoint(pxN, pyN), new PolygonPoint(pxP + 1, pyN), new PolygonPoint(pxN, pyP + 1))); result.add(new DelaunayTriangle(new PolygonPoint(pxP + 1, pyN), new PolygonPoint(pxP + 1, pyP + 1), new PolygonPoint(pxN, pyP + 1))); } } } return result; } // triangulate a bit array (using bytes with fallback to shorts) public static ArrayList<DelaunayTriangle> triangulate(boolean[][] bits) { byte lenX = (byte) bits.length; byte lenY = (byte) bits[0].length; // use version with shorts for larger areas if (lenX > 127 || lenY > 127) { return triangulateSave(bits); } ArrayList<DelaunayTriangle> result = new ArrayList<DelaunayTriangle>(); byte lenXM = (byte) (lenX - 1); byte lenYM = (byte) (lenY - 1); byte pxP,pxN,pyP,pyN; for (byte x = 0; x < lenX; x++) { for (byte y = 0; y < lenY; y++) { // we found a set point -> start expanding if (bits[x][y]) { // unset point bits[x][y] = false; pxP = lenXM; //pxN = 0; pyP = lenYM; pyN = y; // expand in x direction (positive) for (byte i = x; ++i < lenX;) { if (!bits[i][y]) { pxP = --i; break; } else { bits[i][y] = false; } } pxN = x; // expand in y direction (positive) loop: for (byte i = y; ++i < lenY;) { if (!bits[pxP][i] || !bits[pxN][i]) { pyP = --i; break; } else { bits[pxP][i] = false; bits[pxN][i] = false; } for (byte j = pxN; ++j < pxP;) { if (!bits[j][i]) { for (byte k = j; --k > pxN;) { bits[k][i] = true; } bits[pxP][i] = true; bits[pxN][i] = true; pyP = --i; break loop; } else { bits[j][i] = false; } } } // add the triangles for this rectangle result.add(new DelaunayTriangle(new PolygonPoint(pxN, pyN), new PolygonPoint(pxP + 1, pyN), new PolygonPoint(pxN, pyP + 1))); result.add(new DelaunayTriangle(new PolygonPoint(pxP + 1, pyN), new PolygonPoint(pxP + 1, pyP + 1), new PolygonPoint(pxN, pyP + 1))); } } } return result; } }