1 /*
2  * Copyright (c) 2002-2008 LWJGL Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
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.
15  *
16  * * Neither the name of 'LWJGL' nor the names of
17  *   its contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
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.
31  */
32 
33 /*
34 * Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
35 * All rights reserved.
36 */
37 
38 /*
39 ** License Applicability. Except to the extent portions of this file are
40 ** made subject to an alternative license as permitted in the SGI Free
41 ** Software License B, Version 1.1 (the "License"), the contents of this
42 ** file are subject only to the provisions of the License. You may not use
43 ** this file except in compliance with the License. You may obtain a copy
44 ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
45 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
46 **
47 ** http://oss.sgi.com/projects/FreeB
48 **
49 ** Note that, as provided in the License, the Software is distributed on an
50 ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
51 ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
52 ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
53 ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
54 **
55 ** NOTE:  The Original Code (as defined below) has been licensed to Sun
56 ** Microsystems, Inc. ("Sun") under the SGI Free Software License B
57 ** (Version 1.1), shown above ("SGI License").   Pursuant to Section
58 ** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
59 ** you under an alternative license ("Alternative License").  This
60 ** Alternative License includes all of the provisions of the SGI License
61 ** except that Section 2.2 and 11 are omitted.  Any differences between
62 ** the Alternative License and the SGI License are offered solely by Sun
63 ** and not by SGI.
64 **
65 ** Original Code. The Original Code is: OpenGL Sample Implementation,
66 ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
67 ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
68 ** Copyright in any portions created by third parties is as indicated
69 ** elsewhere herein. All Rights Reserved.
70 **
71 ** Additional Notice Provisions: The application programming interfaces
72 ** established by SGI in conjunction with the Original Code are The
73 ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
74 ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
75 ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
76 ** Window System(R) (Version 1.3), released October 19, 1998. This software
77 ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
78 ** published by SGI, but has not been independently verified as being
79 ** compliant with the OpenGL(R) version 1.2.1 Specification.
80 **
81 ** Author: Eric Veach, July 1994
82 ** Java Port: Pepijn Van Eeckhoudt, July 2003
83 ** Java Port: Nathan Parker Burg, August 2003
84 */
85 package org.lwjgl.util.glu.tessellation;
86 
87 class Geom {
Geom()88     private Geom() {
89     }
90 
91     /* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
92      * evaluates the t-coord of the edge uw at the s-coord of the vertex v.
93      * Returns v->t - (uw)(v->s), ie. the signed distance from uw to v.
94      * If uw is vertical (and thus passes thru v), the result is zero.
95      *
96      * The calculation is extremely accurate and stable, even when v
97      * is very close to u or w.  In particular if we set v->t = 0 and
98      * let r be the negated result (this evaluates (uw)(v->s)), then
99      * r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t).
100      */
EdgeEval(GLUvertex u, GLUvertex v, GLUvertex w)101     static double EdgeEval(GLUvertex u, GLUvertex v, GLUvertex w) {
102         double gapL, gapR;
103 
104         assert (VertLeq(u, v) && VertLeq(v, w));
105 
106         gapL = v.s - u.s;
107         gapR = w.s - v.s;
108 
109         if (gapL + gapR > 0) {
110             if (gapL < gapR) {
111                 return (v.t - u.t) + (u.t - w.t) * (gapL / (gapL + gapR));
112             } else {
113                 return (v.t - w.t) + (w.t - u.t) * (gapR / (gapL + gapR));
114             }
115         }
116         /* vertical line */
117         return 0;
118     }
119 
EdgeSign(GLUvertex u, GLUvertex v, GLUvertex w)120     static double EdgeSign(GLUvertex u, GLUvertex v, GLUvertex w) {
121         double gapL, gapR;
122 
123         assert (VertLeq(u, v) && VertLeq(v, w));
124 
125         gapL = v.s - u.s;
126         gapR = w.s - v.s;
127 
128         if (gapL + gapR > 0) {
129             return (v.t - w.t) * gapL + (v.t - u.t) * gapR;
130         }
131         /* vertical line */
132         return 0;
133     }
134 
135 
136     /***********************************************************************
137      * Define versions of EdgeSign, EdgeEval with s and t transposed.
138      */
139 
TransEval(GLUvertex u, GLUvertex v, GLUvertex w)140     static double TransEval(GLUvertex u, GLUvertex v, GLUvertex w) {
141         /* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w),
142          * evaluates the t-coord of the edge uw at the s-coord of the vertex v.
143          * Returns v->s - (uw)(v->t), ie. the signed distance from uw to v.
144          * If uw is vertical (and thus passes thru v), the result is zero.
145          *
146          * The calculation is extremely accurate and stable, even when v
147          * is very close to u or w.  In particular if we set v->s = 0 and
148          * let r be the negated result (this evaluates (uw)(v->t)), then
149          * r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s).
150          */
151         double gapL, gapR;
152 
153         assert (TransLeq(u, v) && TransLeq(v, w));
154 
155         gapL = v.t - u.t;
156         gapR = w.t - v.t;
157 
158         if (gapL + gapR > 0) {
159             if (gapL < gapR) {
160                 return (v.s - u.s) + (u.s - w.s) * (gapL / (gapL + gapR));
161             } else {
162                 return (v.s - w.s) + (w.s - u.s) * (gapR / (gapL + gapR));
163             }
164         }
165         /* vertical line */
166         return 0;
167     }
168 
TransSign(GLUvertex u, GLUvertex v, GLUvertex w)169     static double TransSign(GLUvertex u, GLUvertex v, GLUvertex w) {
170         /* Returns a number whose sign matches TransEval(u,v,w) but which
171          * is cheaper to evaluate.  Returns > 0, == 0 , or < 0
172          * as v is above, on, or below the edge uw.
173          */
174         double gapL, gapR;
175 
176         assert (TransLeq(u, v) && TransLeq(v, w));
177 
178         gapL = v.t - u.t;
179         gapR = w.t - v.t;
180 
181         if (gapL + gapR > 0) {
182             return (v.s - w.s) * gapL + (v.s - u.s) * gapR;
183         }
184         /* vertical line */
185         return 0;
186     }
187 
188 
VertCCW(GLUvertex u, GLUvertex v, GLUvertex w)189     static boolean VertCCW(GLUvertex u, GLUvertex v, GLUvertex w) {
190         /* For almost-degenerate situations, the results are not reliable.
191          * Unless the floating-point arithmetic can be performed without
192          * rounding errors, *any* implementation will give incorrect results
193          * on some degenerate inputs, so the client must have some way to
194          * handle this situation.
195          */
196         return (u.s * (v.t - w.t) + v.s * (w.t - u.t) + w.s * (u.t - v.t)) >= 0;
197     }
198 
199 /* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b),
200  * or (x+y)/2 if a==b==0.  It requires that a,b >= 0, and enforces
201  * this in the rare case that one argument is slightly negative.
202  * The implementation is extremely stable numerically.
203  * In particular it guarantees that the result r satisfies
204  * MIN(x,y) <= r <= MAX(x,y), and the results are very accurate
205  * even when a and b differ greatly in magnitude.
206  */
Interpolate(double a, double x, double b, double y)207     static double Interpolate(double a, double x, double b, double y) {
208         a = (a < 0) ? 0 : a;
209         b = (b < 0) ? 0 : b;
210         if (a <= b) {
211             if (b == 0) {
212                 return (x + y) / 2.0;
213             } else {
214                 return (x + (y - x) * (a / (a + b)));
215             }
216         } else {
217             return (y + (x - y) * (b / (a + b)));
218         }
219     }
220 
EdgeIntersect(GLUvertex o1, GLUvertex d1, GLUvertex o2, GLUvertex d2, GLUvertex v)221     static void EdgeIntersect(GLUvertex o1, GLUvertex d1,
222                               GLUvertex o2, GLUvertex d2,
223                               GLUvertex v)
224 /* Given edges (o1,d1) and (o2,d2), compute their point of intersection.
225  * The computed point is guaranteed to lie in the intersection of the
226  * bounding rectangles defined by each edge.
227  */ {
228         double z1, z2;
229 
230         /* This is certainly not the most efficient way to find the intersection
231          * of two line segments, but it is very numerically stable.
232          *
233          * Strategy: find the two middle vertices in the VertLeq ordering,
234          * and interpolate the intersection s-value from these.  Then repeat
235          * using the TransLeq ordering to find the intersection t-value.
236          */
237 
238         if (!VertLeq(o1, d1)) {
239             GLUvertex temp = o1;
240             o1 = d1;
241             d1 = temp;
242         }
243         if (!VertLeq(o2, d2)) {
244             GLUvertex temp = o2;
245             o2 = d2;
246             d2 = temp;
247         }
248         if (!VertLeq(o1, o2)) {
249             GLUvertex temp = o1;
250             o1 = o2;
251             o2 = temp;
252             temp = d1;
253             d1 = d2;
254             d2 = temp;
255         }
256 
257         if (!VertLeq(o2, d1)) {
258             /* Technically, no intersection -- do our best */
259             v.s = (o2.s + d1.s) / 2.0;
260         } else if (VertLeq(d1, d2)) {
261             /* Interpolate between o2 and d1 */
262             z1 = EdgeEval(o1, o2, d1);
263             z2 = EdgeEval(o2, d1, d2);
264             if (z1 + z2 < 0) {
265                 z1 = -z1;
266                 z2 = -z2;
267             }
268             v.s = Interpolate(z1, o2.s, z2, d1.s);
269         } else {
270             /* Interpolate between o2 and d2 */
271             z1 = EdgeSign(o1, o2, d1);
272             z2 = -EdgeSign(o1, d2, d1);
273             if (z1 + z2 < 0) {
274                 z1 = -z1;
275                 z2 = -z2;
276             }
277             v.s = Interpolate(z1, o2.s, z2, d2.s);
278         }
279 
280         /* Now repeat the process for t */
281 
282         if (!TransLeq(o1, d1)) {
283             GLUvertex temp = o1;
284             o1 = d1;
285             d1 = temp;
286         }
287         if (!TransLeq(o2, d2)) {
288             GLUvertex temp = o2;
289             o2 = d2;
290             d2 = temp;
291         }
292         if (!TransLeq(o1, o2)) {
293             GLUvertex temp = o2;
294             o2 = o1;
295             o1 = temp;
296             temp = d2;
297             d2 = d1;
298             d1 = temp;
299         }
300 
301         if (!TransLeq(o2, d1)) {
302             /* Technically, no intersection -- do our best */
303             v.t = (o2.t + d1.t) / 2.0;
304         } else if (TransLeq(d1, d2)) {
305             /* Interpolate between o2 and d1 */
306             z1 = TransEval(o1, o2, d1);
307             z2 = TransEval(o2, d1, d2);
308             if (z1 + z2 < 0) {
309                 z1 = -z1;
310                 z2 = -z2;
311             }
312             v.t = Interpolate(z1, o2.t, z2, d1.t);
313         } else {
314             /* Interpolate between o2 and d2 */
315             z1 = TransSign(o1, o2, d1);
316             z2 = -TransSign(o1, d2, d1);
317             if (z1 + z2 < 0) {
318                 z1 = -z1;
319                 z2 = -z2;
320             }
321             v.t = Interpolate(z1, o2.t, z2, d2.t);
322         }
323     }
324 
VertEq(GLUvertex u, GLUvertex v)325     static boolean VertEq(GLUvertex u, GLUvertex v) {
326         return u.s == v.s && u.t == v.t;
327     }
328 
VertLeq(GLUvertex u, GLUvertex v)329     static boolean VertLeq(GLUvertex u, GLUvertex v) {
330         return u.s < v.s || (u.s == v.s && u.t <= v.t);
331     }
332 
333 /* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */
334 
TransLeq(GLUvertex u, GLUvertex v)335     static boolean TransLeq(GLUvertex u, GLUvertex v) {
336         return u.t < v.t || (u.t == v.t && u.s <= v.s);
337     }
338 
EdgeGoesLeft(GLUhalfEdge e)339     static boolean EdgeGoesLeft(GLUhalfEdge e) {
340         return VertLeq(e.Sym.Org, e.Org);
341     }
342 
EdgeGoesRight(GLUhalfEdge e)343     static boolean EdgeGoesRight(GLUhalfEdge e) {
344         return VertLeq(e.Org, e.Sym.Org);
345     }
346 
VertL1dist(GLUvertex u, GLUvertex v)347     static double VertL1dist(GLUvertex u, GLUvertex v) {
348         return Math.abs(u.s - v.s) + Math.abs(u.t - v.t);
349     }
350 }
351