2 * Copyright (c) 2003-2009 jMonkeyEngine
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 package com.jmex.font3d.math;
34 import java.util.logging.Logger;
36 import com.jme.math.FastMath;
37 import com.jme.math.Vector3f;
41 * Used to do a triangulation of a complex polygon.
42 * Please note that you should make sure all of these vertices are two-manifold,
43 * if they are not the triangulation will fail with nullpointers.
47 public class TriangulationVertex extends PlanarVertex
49 private static final Logger logger = Logger
50 .getLogger(TriangulationVertex.class.getName());
52 // Easy access pointers
53 //TriangulationVertex prev_vert,next_vert;
54 //TriangulationEdge ingoing_edge,outgoing_edge;
56 public enum VertexType
66 VertexType vert_type = VertexType.UNSET;
67 public boolean is_left_chain = false;
69 TriangulationVertex(int i, Vector3f p)
74 boolean yLessThan(PlanarVertex vertex)
76 return (point.y == vertex.point.y ? point.x > vertex.point.x : point.y < vertex.point.y);
81 if(vert_type == VertexType.UNSET)
83 logger.info("VertexType not set!");
89 public String toString()
91 return "[indx:"+index+",("+point.x+","+point.y+"),type:"+vert_type+"]";
94 public void initializeType()
96 // Find the previous and next vertex
97 TriangulationEdge outgoing_edge = getOutGoingEdge();
98 TriangulationEdge ingoing_edge = getInGoingEdge();
99 TriangulationVertex prev_vert = (TriangulationVertex) ingoing_edge.getOrigin();
100 TriangulationVertex next_vert = (TriangulationVertex) outgoing_edge.getTwin().getOrigin();
102 if(prev_vert.yLessThan(this) && next_vert.yLessThan(this))
104 // Are we at the top but are we start/split
105 Vector3f v1 = prev_vert.point;
107 Vector3f v = next_vert.point;
108 float turnang = (v2.x - v1.x) * (v.y - v1.y) - (v.x - v1.x) * (v2.y - v1.y);
111 vert_type = VertexType.START;
115 vert_type = VertexType.SPLIT;
118 else if(yLessThan(prev_vert) && yLessThan(next_vert))
120 // We are at the bottom, but are we end/merge ?
121 Vector3f v1 = prev_vert.point;
123 Vector3f v = next_vert.point;
124 float turnang = (v2.x - v1.x) * (v.y - v1.y) - (v.x - v1.x) * (v2.y - v1.y);
127 vert_type = VertexType.END;
131 vert_type = VertexType.MERGE;
134 else if(prev_vert.yLessThan(this))
136 // Regular on the right side
137 vert_type = VertexType.REGULAR_RIGHT;
139 else if(next_vert.yLessThan(this))
141 // Regular on the right side
142 vert_type = VertexType.REGULAR_LEFT;
146 logger.info("PNIX: we are none of the above types !!!!");
147 logger.info("GetType: (prev:"+prev_vert+",this:"+this+",next:"+next_vert);
151 public boolean checkAllEdges()
153 // This one is used for sanity (HACK: hardcoded value)
154 int sanity_check = 10000;
157 // Walk around our-selves with tmp = outgoing; tmp = tmp.prev.twin (clockwise)
158 PlanarEdge tmp = getFirstEdge();
160 float anglimit = FastMath.TWO_PI+FastMath.FLT_EPSILON*2;
164 sanity_check = 10000;
167 // Test that tmp has us as origin
168 if(tmp.getOrigin() != this)
170 throw new GeometricException("edge "+tmp+" does not have a correct origin");
172 // Test surface links (clockwise)
173 PlanarEdge tmp2 = tmp;
174 //String debugString = "[";
177 //debugString += " -> "+tmp2;
178 if(tmp2.isRealEdge() != tmp2.getPrev().isRealEdge())
180 //logger.info("VERT: "+tmp2.getOrigin());
181 logger.info("Edge1:"+tmp2);
182 logger.info("Edge2:"+tmp2.getPrev());
183 //logger.info("Tour: "+debugString+" -> "+tmp2.getPrev());
184 throw new GeometricException("Bound two edges, one real one unreal, that is not possible in a closed polygon");
186 tmp2 = tmp2.getPrev();
187 if(sanity_check-- <= 0)
188 throw new GeometricException("Sanity check !");
191 anglesum += tmp.getTwin().getNext().angleCounterClockWise(tmp);
193 if(anglesum > anglimit)
195 logger.info("HERE ARE MY EDGES");
197 throw new GeometricException("The sum of angles between edges exceeded 2 PI ("+anglesum+" > "+anglimit+") on this vert: "+this);
199 tmp = tmp.getTwin().getNext();
201 while(tmp != getFirstEdge());
202 //logger.info("anglesum:"+anglesum+",edgecount:"+edgecount);
205 // Walk around our-selves with tmp = outgoing; tmp = tmp.twin.next(counter-clockwise)
206 tmp = getFirstEdge();
211 sanity_check = 10000;
215 // Test that tmp has us as origin
216 if(tmp.getOrigin() != this)
218 throw new GeometricException("edge "+tmp+" does not have a correct origin");
220 // Test surface links (counter-clockwise)
221 PlanarEdge tmp2 = tmp;
224 if(tmp2.isRealEdge() != tmp2.getNext().isRealEdge())
226 logger.info("VERT: "+tmp2.getOrigin());
227 logger.info("Edge1:"+tmp2);
228 logger.info("Edge2:"+tmp2.getNext());
229 throw new GeometricException("Bound two edges, one real one unreal, that is not possible in a closed polygon");
231 tmp2 = tmp2.getNext();
232 if(sanity_check-- <= 0)
233 throw new GeometricException("Sanity check !");
237 anglesum += tmp.angleCounterClockWise(tmp.getPrev().getTwin());
239 if(anglesum > anglimit)
241 throw new GeometricException("The sum of angles between edges exceeded 2 PI ("+anglesum+" > "+anglimit+") on this vert: "+this);
243 tmp = tmp.getPrev().getTwin();
245 while(tmp != getFirstEdge());
246 //logger.info("anglesum:"+anglesum+",edgecount:"+edgecount);
253 * This method returns the first and best real edge going out of this vertex, there should be only one before the triangulation.
257 public TriangulationEdge getOutGoingEdge()
259 if(getFirstEdge() == null)
261 TriangulationEdge next = (TriangulationEdge) getFirstEdge();
264 if(next.isRealEdge())
266 next = (TriangulationEdge) next.getTwin().getNext();
268 while(next != getFirstEdge()); // Only one round
273 * This method returns the first and best real edge going in to this vertex, there should be only one before the triangulation.
277 public TriangulationEdge getInGoingEdge()
279 if(getFirstEdge() == null)
281 TriangulationEdge next = (TriangulationEdge) getFirstEdge();
284 if(next.getTwin().isRealEdge())
285 return (TriangulationEdge) next.getTwin();
286 next = (TriangulationEdge) next.getTwin().getNext();
288 while(next != getFirstEdge()); // Only one round