00001 package org.dronus.gl;
00002
00018 import java.util.*;
00019
00020 import org.lwjgl.util.vector.Vector3f;
00021
00022 public class Convexiser {
00023
00024
00025
00026 List<Vector3f> currentPoly;
00027 int n;
00028 float px[], py[];
00029 boolean pConvex[];
00030
00031
00032 List<List<Vector3f>> earPoly = new ArrayList<List<Vector3f>>();
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 void updatePoints() {
00043 n = currentPoly.size();
00044 int i = 0;
00045 for (Vector3f v : currentPoly) {
00046 px[i] = v.x - v.y;
00047 py[i] = -v.z + v.y;
00048 i++;
00049 }
00050 }
00051
00058 public List<List<Vector3f>> convexise(List<Vector3f> polygon) {
00059
00060 currentPoly = new ArrayList<Vector3f>(polygon);
00061
00062
00063
00064
00065
00066 n = polygon.size();
00067 px = new float[n];
00068 py = new float[n];
00069 pConvex = new boolean[n];
00070
00071
00072 updatePoints();
00073
00074
00075 if (!polygonClockwise()) {
00076 Collections.reverse(currentPoly);
00077 updatePoints();
00078 }
00079
00080
00081 while (n > 3) {
00082 classifyConvexity();
00083
00084 if (!cutOneEar()) break;
00085 }
00086
00087 earPoly.add(currentPoly);
00088 return earPoly;
00089 }
00090
00091
00092 boolean polygonClockwise() {
00093
00094
00095 double convex_sum = 0;
00096
00097 for (int i = 0; i < n; i++) {
00098
00099
00100 int i0 = (i + n - 1) % n, i1 = i, i2 = (i + 1) % n;
00101
00102 float aa = ((px[i2] - px[i0]) * (px[i2] - px[i0])) + ((-py[i2] + py[i0]) * (-py[i2] + py[i0])),
00103 bb = ((px[i1] - px[i0]) * (px[i1] - px[i0])) + ((-py[i1] + py[i0]) * (-py[i1] + py[i0])),
00104 cc = ((px[i2] - px[i1]) * (px[i2] - px[i1])) + ((-py[i2] + py[i1]) * (-py[i2] + py[i1]));
00105
00106 double b = Math.sqrt(bb),
00107 c = Math.sqrt(cc),
00108 theta = Math.acos((bb + cc - aa) / (2 * b * c));
00109
00110 if (convex(px[i0], py[i0], px[i1], py[i1], px[i2], py[i2])) {
00111 convex_sum += Math.PI - theta;
00112 } else {
00113 convex_sum -= Math.PI - theta;
00114 }
00115 }
00116
00117 return (convex_sum >= (2 * Math.PI - .001));
00118
00119 }
00120
00121
00122
00123
00124 boolean classifyConvexity() {
00125
00126 boolean convex = true;
00127
00128 for (int i = 0; i < n; i++) {
00129
00130 int i0 = (i + n - 1) % n, i1 = i, i2 = (i + 1) % n;
00131
00132 pConvex[i] = convex(px[i0], py[i0], px[i1], py[i1], px[i2], py[i2]);
00133 convex &= pConvex[i];
00134 }
00135
00136 return convex;
00137 }
00138
00139
00140 boolean convex(float x1, float y1, float x2, float y2, float x3, float y3) {
00141 return (area(x1, y1, x2, y2, x3, y3) < 0);
00142 }
00143
00144
00145 float area(float x1, float y1, float x2, float y2, float x3, float y3) {
00146 float area = 0;
00147
00148 area += x1 * (y3 - y2);
00149 area += x2 * (y1 - y3);
00150 area += x3 * (y2 - y1);
00151
00152 return area;
00153 }
00154
00155
00156
00157
00158 boolean triangleContainsPoint(float x1, float y1, float x2, float y2, float x3, float y3) {
00159
00160 for (int i = 0; i < n; i++) {
00161 if (!pConvex[i] && (
00162 ((px[i] != x1) && (py[i] != y1))
00163 || ((px[i] != x2) && (py[i] != y2))
00164 || ((px[i] != x3) && (py[i] != y3))
00165 )) {
00166
00167 float a1 = area(x1, y1, x2, y2, px[i], py[i]),
00168 a2 = area(x2, y2, x3, y3, px[i], py[i]),
00169 a3 = area(x3, y3, x1, y1, px[i], py[i]);
00170
00171 if ((a1 > 0 && a2 > 0 && a3 > 0)
00172 || (a1 < 0 && a2 < 0 && a3 < 0))
00173 return true;
00174 }
00175 }
00176 return false;
00177 }
00178
00179
00180 void cutEar(int index) {
00181
00182 int[] ind = new int[]{(index + n - 1) % n, index, (index + 1) % n};
00183
00184 List<Vector3f> p = new ArrayList<Vector3f>();
00185
00186 for (int i = 0; i < 3; i++)
00187 p.add(currentPoly.get(ind[i]));
00188
00189 earPoly.add(p);
00190 currentPoly.remove(index);
00191 updatePoints();
00192 }
00193
00194
00195
00196 boolean cutOneEar() {
00197 for (int i=0; i < n; i++) {
00198 if (pConvex[i]) {
00199
00200
00201 int i0 = (i + n - 1) % n, i1 = i, i2 = (i + 1) % n;
00202
00203 if (!triangleContainsPoint(px[i0], py[i0], px[i1], py[i1], px[i2], py[i2])) {
00204 cutEar(i);
00205 return true;
00206 }
00207 }
00208 }
00209 return false;
00210
00211 }
00212
00213 }