/*
* ******************************************************************************
* * Copyright 2015 See AUTHORS file.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
* *****************************************************************************
*/
package com.uwsoft.editor.utils.poly.earclipping.ewjordan;
import com.badlogic.gdx.math.Vector2;
/**
* Original code from EwJordan (http://www.ewjordan.com/earClip/)
*/
public class EwjordanDecomposer {
public static Vector2[][] decompose(Vector2[] points) {
int vNum = points.length;
float[] xv = new float[vNum];
float[] yv = new float[vNum];
for (int i = 0; i < vNum; i++) {
xv[i] = points[i].x;
yv[i] = points[i].y;
}
Triangle[] tempTriangles = triangulatePolygon(xv, yv, vNum);
Polygon[] tempPolygons = polygonizeTriangles(tempTriangles);
if (tempPolygons == null)
return null;
Vector2[][] polygons = new Vector2[tempPolygons.length][];
for (int i = 0; i < tempPolygons.length; i++) {
polygons[i] = new Vector2[tempPolygons[i].nVertices];
for (int ii = 0; ii < tempPolygons[i].nVertices; ii++)
polygons[i][ii] = new Vector2(tempPolygons[i].x[ii], tempPolygons[i].y[ii]);
}
return polygons;
}
// -------------------------------------------------------------------------
private static Triangle[] triangulatePolygon(float[] xv, float[] yv, int vNum) {
if (vNum < 3)
return null;
Triangle[] buffer = new Triangle[vNum];
int bufferSize = 0;
float[] xrem = new float[vNum];
float[] yrem = new float[vNum];
for (int i = 0; i < vNum; ++i) {
xrem[i] = xv[i];
yrem[i] = yv[i];
}
while (vNum > 3) {
int earIndex = -1;
for (int i = 0; i < vNum; ++i) {
if (isEar(i, xrem, yrem)) {
earIndex = i;
break;
}
}
if (earIndex == -1)
return null;
--vNum;
float[] newx = new float[vNum];
float[] newy = new float[vNum];
int currDest = 0;
for (int i = 0; i < vNum; ++i) {
if (currDest == earIndex) {
++currDest;
}
newx[i] = xrem[currDest];
newy[i] = yrem[currDest];
++currDest;
}
int under = (earIndex == 0) ? (xrem.length - 1) : (earIndex - 1);
int over = (earIndex == xrem.length - 1) ? 0 : (earIndex + 1);
Triangle toAdd = new Triangle(xrem[earIndex], yrem[earIndex], xrem[over], yrem[over], xrem[under], yrem[under]);
buffer[bufferSize] = toAdd;
++bufferSize;
xrem = newx;
yrem = newy;
}
Triangle toAdd = new Triangle(xrem[1], yrem[1], xrem[2], yrem[2], xrem[0], yrem[0]);
buffer[bufferSize] = toAdd;
++bufferSize;
Triangle[] res = new Triangle[bufferSize];
System.arraycopy(buffer, 0, res, 0, bufferSize);
return res;
}
private static Polygon[] polygonizeTriangles(Triangle[] triangulated) {
Polygon[] polys;
int polyIndex = 0;
if (triangulated == null)
return null;
polys = new Polygon[triangulated.length];
boolean[] covered = new boolean[triangulated.length];
for (int i = 0; i < triangulated.length; i++)
covered[i] = false;
boolean notDone = true;
while (notDone) {
int currTri = -1;
for (int i = 0; i < triangulated.length; i++) {
if (!covered[i]) {
currTri = i;
break;
}
}
if (currTri == -1) {
notDone = false;
} else {
Polygon poly = new Polygon(triangulated[currTri]);
covered[currTri] = true;
for (int i = 0; i < triangulated.length; i++) {
if (covered[i])
continue;
Polygon newP = poly.add(triangulated[i]);
if (newP == null)
continue;
if (newP.isConvex()) {
poly = newP;
covered[i] = true;
}
}
polys[polyIndex] = poly;
polyIndex++;
}
}
Polygon[] ret = new Polygon[polyIndex];
System.arraycopy(polys, 0, ret, 0, polyIndex);
return ret;
}
private static boolean isEar(int i, float[] xv, float[] yv) {
float dx0, dy0, dx1, dy1;
dx0 = dy0 = dx1 = dy1 = 0;
if (i >= xv.length || i < 0 || xv.length < 3)
return false;
int upper = i + 1;
int lower = i - 1;
if (i == 0) {
dx0 = xv[0] - xv[xv.length - 1];
dy0 = yv[0] - yv[yv.length - 1];
dx1 = xv[1] - xv[0];
dy1 = yv[1] - yv[0];
lower = xv.length - 1;
} else if (i == xv.length - 1) {
dx0 = xv[i] - xv[i - 1];
dy0 = yv[i] - yv[i - 1];
dx1 = xv[0] - xv[i];
dy1 = yv[0] - yv[i];
upper = 0;
} else {
dx0 = xv[i] - xv[i - 1];
dy0 = yv[i] - yv[i - 1];
dx1 = xv[i + 1] - xv[i];
dy1 = yv[i + 1] - yv[i];
}
float cross = dx0 * dy1 - dx1 * dy0;
if (cross > 0)
return false;
Triangle myTri = new Triangle(xv[i], yv[i], xv[upper], yv[upper], xv[lower], yv[lower]);
for (int j = 0; j < xv.length; ++j) {
if (j == i || j == lower || j == upper)
continue;
if (myTri.isInside(xv[j], yv[j]))
return false;
}
return true;
}
}