/** * Copyright 2013 The Loon Authors * * 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 loon.physics; import loon.geom.Vector2f; import loon.utils.MathUtils; public class PFigure { Vector2f[] done; int numVertices; private PVertexLoop vers; public PFigure() { } private float calcArea(Vector2f v1, Vector2f v2, Vector2f v3) { return (v1.x - v3.x) * (v2.y - v3.y) - (v1.y - v3.y) * (v2.x - v3.x); } private Vector2f checkCrossEdge(Vector2f s1, Vector2f e1, Vector2f s2, Vector2f e2) { if (s1.x == e2.x && s1.y == e2.y || e1.x == s2.x && e1.y == s2.y || s1.x == s2.x && s1.y == s2.y || e1.x == e2.x && e1.y == e2.y) { return null; } float a1 = calcArea(s1, e1, e2); float a2 = calcArea(s1, e1, s2); if (a1 * a2 >= 0.0F) { return null; } float a3 = calcArea(s2, e2, s1); float a4 = (a3 + a2) - a1; if (a3 * a4 >= 0.0F) { return null; } else { float t = a3 / (a3 - a4); return new Vector2f(s1.x + t * (e1.x - s1.x), s1.y + t * (e1.y - s1.y)); } } private void insertVertex(PVertexLoop prev, PVertexLoop add) { prev.next.prev = add; add.next = prev.next; add.prev = prev; prev.next = add; numVertices++; } private void makeVertexList(Vector2f vertices[]) { vers = new PVertexLoop(vertices[0].x, vertices[0].y); PVertexLoop list = vers; int skipCount = 0; for (int i = 1; i < numVertices; i++) { if (list.v.x == vertices[i].x && list.v.y == vertices[i].y) { skipCount++; } else { PVertexLoop next = new PVertexLoop(vertices[i].x, vertices[i].y); list.next = next; next.prev = list; list = list.next; } } numVertices -= skipCount; vers.prev = list; list.next = vers; for (int i = 0; i < numVertices; i++) { vers.v.set(vers.v.x + MathUtils.random() * 0.001F, vers.v.y + MathUtils.random() * 0.001F); vers = vers.next; } } private void reverseVertices(PVertexLoop begin, PVertexLoop end) { if (begin.next == end) return; PVertexLoop prevBegin = begin.next; PVertexLoop prevEnd = end.prev; PVertexLoop next; for (PVertexLoop loop = begin.next; loop != end; loop = next) { next = loop.next; loop.next = loop.prev; loop.prev = next; } prevBegin.next = end; end.prev = prevBegin; prevEnd.prev = begin; begin.next = prevEnd; } private void figure() { PVertexLoop vi = vers; float e = 0.0001F; for (int i = 0; i < numVertices; i++) { PVertexLoop vj = vers; for (int j = 0; j < numVertices; j++) { if (vi != vj) { Vector2f cross = checkCrossEdge(vi.v, vi.next.v, vj.v, vj.next.v); if (cross != null) { Vector2f epsilon1 = vi.v.sub(vi.next.v); epsilon1.normalize(); epsilon1.mulLocal(e); Vector2f epsilon2 = vj.next.v.sub(vj.v); epsilon2.normalize(); epsilon2.mulLocal(e); insertVertex(vi, new PVertexLoop(cross.x, cross.y)); insertVertex(vj, new PVertexLoop(cross.x, cross.y)); vi.next.crossPoint = true; vj.next.crossPoint = true; vi.next.pair = vj.next; vi.next.epsilon = epsilon1; vj.next.epsilon = epsilon2; } } vj = vj.next; } vi = vi.next; } PVertexLoop v[] = new PVertexLoop[numVertices]; for (int i = 0; i < numVertices; i++) { vers = v[i] = vers.next; } for (int i = 0; i < numVertices; i++) { if (v[i].crossPoint && v[i].pair != null) { reverseVertices(v[i], v[i].pair); v[i].v.addSelf(v[i].epsilon); v[i].pair.v.addSelf(v[i].pair.epsilon); if (checkCrossEdge(v[i].v, v[i].next.v, v[i].pair.v, v[i].pair.prev.v) != null) { float tx = v[i].v.x; float ty = v[i].v.y; v[i].v.set(v[i].pair.v.x, v[i].pair.v.y); v[i].pair.v.set(tx, ty); } } } done = new Vector2f[numVertices]; for (int i = 0; i < numVertices; i++) { done[i] = new Vector2f(vers.v.x, vers.v.y); vers = vers.next; } } public void figure(Vector2f vertices[], int numVers) { numVertices = numVers; makeVertexList(vertices); figure(); } }