Source Code Cross Referenced for Font3D.java in  » 6.0-JDK-Modules » java-3d » javax » media » j3d » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » java 3d » javax.media.j3d 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $RCSfile: Font3D.java,v $
0003:         *
0004:         * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
0005:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0006:         *
0007:         * This code is free software; you can redistribute it and/or modify it
0008:         * under the terms of the GNU General Public License version 2 only, as
0009:         * published by the Free Software Foundation.  Sun designates this
0010:         * particular file as subject to the "Classpath" exception as provided
0011:         * by Sun in the LICENSE file that accompanied this code.
0012:         *
0013:         * This code is distributed in the hope that it will be useful, but WITHOUT
0014:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0015:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0016:         * version 2 for more details (a copy is included in the LICENSE file that
0017:         * accompanied this code).
0018:         *
0019:         * You should have received a copy of the GNU General Public License version
0020:         * 2 along with this work; if not, write to the Free Software Foundation,
0021:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0022:         *
0023:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0024:         * CA 95054 USA or visit www.sun.com if you need additional information or
0025:         * have any questions.
0026:         *
0027:         * $Revision: 1.6 $
0028:         * $Date: 2008/02/28 20:17:21 $
0029:         * $State: Exp $
0030:         */
0031:
0032:        package javax.media.j3d;
0033:
0034:        import com.sun.j3d.utils.geometry.*;
0035:        import com.sun.j3d.internal.FastVector;
0036:        import java.awt.Font;
0037:        import java.awt.font.*;
0038:        import java.awt.geom.Rectangle2D;
0039:        import java.awt.geom.AffineTransform;
0040:        import javax.vecmath.*;
0041:        import java.awt.Shape;
0042:        import java.awt.geom.PathIterator;
0043:        import java.util.*;
0044:
0045:        /**
0046:         * The Font3D object is used to store extruded 2D glyphs.  These
0047:         * 3D glyphs can then be used to construct Text3D NodeComponent
0048:         * objects.
0049:         * <P>
0050:         * A 3D Font consists of a Java 2D font, a tesellation tolerance,
0051:         * and an extrusion path.  The extrusion
0052:         * path creates depth by describing how the edge of a glyph varies
0053:         * in the Z axis.
0054:         * <P>
0055:         * The construction of a Text3D object requires a Font3D object.
0056:         * The Font3D object describes the style of the text, such as its
0057:         * depth. The text also needs other classes, such as java.awt.Font and
0058:         * FontExtrusion. The Font object describes the font name (Helvetica,
0059:         * Courier, etc.), the font style (bold, Italic, etc.), and point
0060:         * size. The FontExtrusion object extends Font3D by describing
0061:         * the extrusion path for the Font3D object (how the edge of the
0062:         * font glyph varies in the Z axis).
0063:         *<P>
0064:         * To ensure correct rendering, the 2D Font object should be created
0065:         * with the default AffineTransform. The point size of the 2D font will
0066:         * be used as a rough measure of how fine a tesselation to use when
0067:         * creating the Font3D object: the larger the point size, in
0068:         * general, the finer the tesselation.
0069:         * <P>
0070:         * Custom 3D fonts as well as methods to store 3D fonts
0071:         * to disk will be addressed in a future release.
0072:         *
0073:         * @see java.awt.Font
0074:         * @see FontExtrusion
0075:         * @see Text3D
0076:         */
0077:        public class Font3D extends NodeComponent {
0078:
0079:            Font font;
0080:            double tessellationTolerance;
0081:            FontExtrusion fontExtrusion;
0082:            FontRenderContext frc;
0083:            // Used by triangulateGlyphs method to split contour data into islands.
0084:            final static float EPS = 0.000001f;
0085:
0086:            // Map glyph code to GeometryArrayRetained
0087:            Hashtable geomHash = new Hashtable(20);
0088:
0089:            /**
0090:             * Constructs a Font3D object from the specified Font and
0091:             * FontExtrusion objects, using the default value for the
0092:             * tessellation tolerance.  The default value is as follows:
0093:             *
0094:             * <ul>
0095:             * tessellation tolerance : 0.01<br>
0096:             * </ul>
0097:             * <P>
0098:             * The FontExtrusion object contains the extrusion path to use on
0099:             * the 2D Font glyphs.  To ensure correct rendering the font must
0100:             * be created with the default AffineTransform.  Passing null for
0101:             * the FontExtrusion parameter results in no extrusion being done.
0102:             *
0103:             * @param font the Java 2D font used to create the 3D font object
0104:             * @param extrudePath the extrusion path used to describe how
0105:             * the edge of the font varies along the Z axis
0106:             */
0107:            public Font3D(Font font, FontExtrusion extrudePath) {
0108:                this (font, 0.01, extrudePath);
0109:            }
0110:
0111:            /**
0112:             * Constructs a Font3D object from the specified Font and
0113:             * FontExtrusion objects, using the specified tessellation
0114:             * tolerance.
0115:             * The FontExtrusion object contains the extrusion path to use on
0116:             * the 2D Font glyphs.  To ensure correct rendering, the font must
0117:             * be created with the default AffineTransform.  Passing null for
0118:             * the FontExtrusion parameter results in no extrusion being done.
0119:             *
0120:             * @param font the Java 2D font used to create the 3D font object.
0121:             * @param tessellationTolerance the tessellation tolerance value
0122:             * used in tessellating the glyphs of the 2D Font.
0123:             * This corresponds to the <code>flatness</code> parameter in
0124:             * the <code>java.awt.Shape.getPathIterator</code> method.
0125:             * @param extrudePath the extrusion path used to describe how
0126:             * the edge of the font varies along the Z axis.
0127:             *
0128:             * @since Java 3D 1.2
0129:             */
0130:            public Font3D(Font font, double tessellationTolerance,
0131:                    FontExtrusion extrudePath) {
0132:
0133:                this .font = font;
0134:                this .tessellationTolerance = tessellationTolerance;
0135:                this .fontExtrusion = extrudePath;
0136:                this .frc = new FontRenderContext(new AffineTransform(), true,
0137:                        true);
0138:            }
0139:
0140:            /**
0141:             * Returns the Java 2D Font used to create this Font3D object.
0142:             * @return Font object used by this Font3D
0143:             */
0144:            public Font getFont() {
0145:                return this .font;
0146:            }
0147:
0148:            /**
0149:             * Returns the tessellation tolerance with which this Font3D was
0150:             * created.
0151:             * @return the tessellation tolerance used by this Font3D
0152:             *
0153:             * @since Java 3D 1.2
0154:             */
0155:            public double getTessellationTolerance() {
0156:                return tessellationTolerance;
0157:            }
0158:
0159:            /**
0160:             * Copies the FontExtrusion object used to create this Font3D object
0161:             * into the specified parameter.
0162:             *
0163:             * @param extrudePath object that will receive the
0164:             * FontExtrusion information for this Font3D object
0165:             */
0166:            public void getFontExtrusion(FontExtrusion extrudePath) {
0167:                extrudePath = this .fontExtrusion;
0168:            }
0169:
0170:            /**
0171:             * Returns the 3D bounding box of the specified glyph code.
0172:             *
0173:             * @param glyphCode the glyphCode from the original 2D Font
0174:             * @param bounds the 3D glyph's bounds
0175:             */
0176:            public void getBoundingBox(int glyphCode, BoundingBox bounds) {
0177:                int[] gCodes = { glyphCode };
0178:                GlyphVector gVec = font.createGlyphVector(frc, gCodes);
0179:                Rectangle2D.Float bounds2d = (Rectangle2D.Float) (((GlyphMetrics) (gVec
0180:                        .getGlyphMetrics(0))).getBounds2D());
0181:
0182:                Point3d lower = new Point3d(bounds2d.x, bounds2d.y, 0.0);
0183:                Point3d upper;
0184:                if (fontExtrusion != null) {
0185:                    upper = new Point3d(bounds2d.x + bounds2d.width, bounds2d.y
0186:                            + bounds2d.height, fontExtrusion.length);
0187:                } else {
0188:                    upper = new Point3d(bounds2d.x + bounds2d.width, bounds2d.y
0189:                            + bounds2d.height, 0.0);
0190:                }
0191:                bounds.setLower(lower);
0192:                bounds.setUpper(upper);
0193:            }
0194:
0195:            // BY MIK OF CLASSX
0196:            /**
0197:             * Returns a GeometryArray of a glyph in this Font3D.
0198:             *
0199:             * @param c character from which to generate a tessellated glyph.
0200:             *
0201:             * @return a GeometryArray
0202:             *
0203:             * @since Java 3D 1.4
0204:             */
0205:            public GeometryArray getGlyphGeometry(char c) {
0206:                char code[] = { c };
0207:                GlyphVector gv = font.createGlyphVector(frc, code);
0208:
0209:                // triangulate the glyph
0210:                GeometryArrayRetained glyph_gar = triangulateGlyphs(gv, code[0]);
0211:
0212:                // Assume that triangulateGlyphs returns a triangle array with only coords & normals
0213:                // (and without by-ref, interleaved, etc.)
0214:                assert glyph_gar instanceof  TriangleArrayRetained : "Font3D: GeometryArray is not an instance of TrangleArray";
0215:                assert glyph_gar.getVertexFormat() == (GeometryArray.COORDINATES | GeometryArray.NORMALS) : "Font3D: Illegal GeometryArray format -- only coordinates and normals expected";
0216:
0217:                // create a correctly sized TriangleArray
0218:                TriangleArray ga = new TriangleArray(
0219:                        glyph_gar.getVertexCount(), glyph_gar.getVertexFormat());
0220:
0221:                // temp storage for coords, normals
0222:                float tmp[] = new float[3];
0223:
0224:                int vertexCount = ga.getVertexCount();
0225:                for (int i = 0; i < vertexCount; i++) {
0226:                    // copy the glyph geometry to the TriangleArray
0227:                    glyph_gar.getCoordinate(i, tmp);
0228:                    ga.setCoordinate(i, tmp);
0229:
0230:                    glyph_gar.getNormal(i, tmp);
0231:                    ga.setNormal(i, tmp);
0232:                }
0233:
0234:                return ga;
0235:            }
0236:
0237:            // Triangulate glyph with 'unicode' if not already done.
0238:            GeometryArrayRetained triangulateGlyphs(GlyphVector gv, char c) {
0239:                Character ch = new Character(c);
0240:                GeometryArrayRetained geo = (GeometryArrayRetained) geomHash
0241:                        .get(ch);
0242:
0243:                if (geo == null) {
0244:                    // Font Y-axis is downwards, so send affine transform to flip it.
0245:                    Rectangle2D bnd = gv.getVisualBounds();
0246:                    AffineTransform aTran = new AffineTransform();
0247:                    double tx = bnd.getX() + 0.5 * bnd.getWidth();
0248:                    double ty = bnd.getY() + 0.5 * bnd.getHeight();
0249:                    aTran.setToTranslation(-tx, -ty);
0250:                    aTran.scale(1.0, -1.0);
0251:                    aTran.translate(tx, -ty);
0252:                    Shape shape = gv.getOutline();
0253:                    PathIterator pIt = shape.getPathIterator(aTran,
0254:                            tessellationTolerance);
0255:                    int flag = -1, numContours = 0, numPoints = 0, i, j, k, num = 0, vertCnt;
0256:                    UnorderList coords = new UnorderList(100, Point3f.class);
0257:                    float tmpCoords[] = new float[6];
0258:                    float lastX = .0f, lastY = .0f;
0259:                    float firstPntx = Float.MAX_VALUE, firstPnty = Float.MAX_VALUE;
0260:                    GeometryInfo gi = null;
0261:                    NormalGenerator ng = new NormalGenerator();
0262:                    FastVector contours = new FastVector(10);
0263:                    float maxY = -Float.MAX_VALUE;
0264:                    int maxYIndex = 0, beginIdx = 0, endIdx = 0, start = 0;
0265:
0266:                    boolean setMaxY = false;
0267:
0268:                    while (!pIt.isDone()) {
0269:                        Point3f vertex = new Point3f();
0270:                        flag = pIt.currentSegment(tmpCoords);
0271:                        if (flag == PathIterator.SEG_CLOSE) {
0272:                            if (num > 0) {
0273:                                if (setMaxY) {
0274:                                    // Get Previous point
0275:                                    beginIdx = start;
0276:                                    endIdx = numPoints - 1;
0277:                                }
0278:                                contours.addElement(num);
0279:                                num = 0;
0280:                                numContours++;
0281:                            }
0282:                        } else if (flag == PathIterator.SEG_MOVETO) {
0283:                            vertex.x = tmpCoords[0];
0284:                            vertex.y = tmpCoords[1];
0285:                            lastX = vertex.x;
0286:                            lastY = vertex.y;
0287:
0288:                            if ((lastX == firstPntx) && (lastY == firstPnty)) {
0289:                                pIt.next();
0290:                                continue;
0291:                            }
0292:                            setMaxY = false;
0293:                            coords.add(vertex);
0294:                            firstPntx = lastX;
0295:                            firstPnty = lastY;
0296:                            if (num > 0) {
0297:                                contours.addElement(num);
0298:                                num = 0;
0299:                                numContours++;
0300:                            }
0301:                            num++;
0302:                            numPoints++;
0303:                            // skip checking of first point,
0304:                            // since the last point will repeat this.
0305:                            start = numPoints;
0306:                        } else if (flag == PathIterator.SEG_LINETO) {
0307:                            vertex.x = tmpCoords[0];
0308:                            vertex.y = tmpCoords[1];
0309:                            //Check here for duplicate points. Code
0310:                            //later in this function can not handle
0311:                            //duplicate points.
0312:
0313:                            if ((vertex.x == lastX) && (vertex.y == lastY)) {
0314:                                pIt.next();
0315:                                continue;
0316:                            }
0317:                            if (vertex.y > maxY) {
0318:                                maxY = vertex.y;
0319:                                maxYIndex = numPoints;
0320:                                setMaxY = true;
0321:                            }
0322:                            lastX = vertex.x;
0323:                            lastY = vertex.y;
0324:                            coords.add(vertex);
0325:                            num++;
0326:                            numPoints++;
0327:                        }
0328:                        pIt.next();
0329:                    }
0330:
0331:                    // No data(e.g space, control characters)
0332:                    // Two point can't form a valid contour
0333:                    if (numPoints == 0) {
0334:                        return null;
0335:                    }
0336:
0337:                    // Determine font winding order use for side triangles
0338:                    Point3f p1 = new Point3f(), p2 = new Point3f(), p3 = new Point3f();
0339:                    boolean flip_side_orient = true;
0340:                    Point3f vertices[] = (Point3f[]) coords.toArray(false);
0341:
0342:                    if (endIdx - beginIdx > 0) {
0343:                        // must be true unless it is a single line
0344:                        // define as "MoveTo p1 LineTo p2 Close" which is
0345:                        // not a valid font definition.
0346:
0347:                        if (maxYIndex == beginIdx) {
0348:                            p1.set(vertices[endIdx]);
0349:                        } else {
0350:                            p1.set(vertices[maxYIndex - 1]);
0351:                        }
0352:                        p2.set(vertices[maxYIndex]);
0353:                        if (maxYIndex == endIdx) {
0354:                            p3.set(vertices[beginIdx]);
0355:                        } else {
0356:                            p3.set(vertices[maxYIndex + 1]);
0357:                        }
0358:
0359:                        if (p3.x != p2.x) {
0360:                            if (p1.x != p2.x) {
0361:                                // Use the one with smallest slope
0362:                                if (Math.abs((p2.y - p1.y) / (p2.x - p1.x)) > Math
0363:                                        .abs((p3.y - p2.y) / (p3.x - p2.x))) {
0364:                                    flip_side_orient = (p3.x > p2.x);
0365:                                } else {
0366:                                    flip_side_orient = (p2.x > p1.x);
0367:                                }
0368:                            } else {
0369:                                flip_side_orient = (p3.x > p2.x);
0370:                            }
0371:                        } else {
0372:                            // p1.x != p2.x, otherwise all three
0373:                            // point form a straight vertical line with
0374:                            // the middle point the highest. This is not a
0375:                            // valid font definition.
0376:                            flip_side_orient = (p2.x > p1.x);
0377:                        }
0378:                    }
0379:
0380:                    // Build a Tree of Islands
0381:                    int startIdx = 0;
0382:                    IslandsNode islandsTree = new IslandsNode(-1, -1);
0383:                    int contourCounts[] = contours.getData();
0384:
0385:                    for (i = 0; i < contours.getSize(); i++) {
0386:                        endIdx = startIdx + contourCounts[i];
0387:                        islandsTree.insert(new IslandsNode(startIdx, endIdx),
0388:                                vertices);
0389:                        startIdx = endIdx;
0390:                    }
0391:
0392:                    coords = null; // Free memory 
0393:                    contours = null;
0394:                    contourCounts = null;
0395:
0396:                    // Compute islandCounts[][] and outVerts[][]
0397:                    UnorderList islandsList = new UnorderList(10,
0398:                            IslandsNode.class);
0399:                    islandsTree.collectOddLevelNode(islandsList, 0);
0400:                    IslandsNode nodes[] = (IslandsNode[]) islandsList
0401:                            .toArray(false);
0402:                    int islandCounts[][] = new int[islandsList.arraySize()][];
0403:                    Point3f outVerts[][] = new Point3f[islandCounts.length][];
0404:                    int nchild, sum;
0405:                    IslandsNode node;
0406:
0407:                    for (i = 0; i < islandCounts.length; i++) {
0408:                        node = nodes[i];
0409:                        nchild = node.numChild();
0410:                        islandCounts[i] = new int[nchild + 1];
0411:                        islandCounts[i][0] = node.numVertices();
0412:                        sum = 0;
0413:                        sum += islandCounts[i][0];
0414:                        for (j = 0; j < nchild; j++) {
0415:                            islandCounts[i][j + 1] = node.getChild(j)
0416:                                    .numVertices();
0417:                            sum += islandCounts[i][j + 1];
0418:                        }
0419:                        outVerts[i] = new Point3f[sum];
0420:                        startIdx = 0;
0421:                        for (k = node.startIdx; k < node.endIdx; k++) {
0422:                            outVerts[i][startIdx++] = vertices[k];
0423:                        }
0424:
0425:                        for (j = 0; j < nchild; j++) {
0426:                            endIdx = node.getChild(j).endIdx;
0427:                            for (k = node.getChild(j).startIdx; k < endIdx; k++) {
0428:                                outVerts[i][startIdx++] = vertices[k];
0429:                            }
0430:                        }
0431:                    }
0432:
0433:                    islandsTree = null; // Free memory 
0434:                    islandsList = null;
0435:                    vertices = null;
0436:
0437:                    contourCounts = new int[1];
0438:                    int currCoordIndex = 0, vertOffset = 0;
0439:                    ArrayList triangData = new ArrayList();
0440:
0441:                    Point3f q1 = new Point3f(), q2 = new Point3f(), q3 = new Point3f();
0442:                    Vector3f n1 = new Vector3f(), n2 = new Vector3f();
0443:                    numPoints = 0;
0444:                    //Now loop thru each island, calling triangulator once per island.
0445:                    //Combine triangle data for all islands together in one object.
0446:                    for (i = 0; i < islandCounts.length; i++) {
0447:                        contourCounts[0] = islandCounts[i].length;
0448:                        numPoints += outVerts[i].length;
0449:                        gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);
0450:                        gi.setCoordinates(outVerts[i]);
0451:                        gi.setStripCounts(islandCounts[i]);
0452:                        gi.setContourCounts(contourCounts);
0453:                        ng.generateNormals(gi);
0454:
0455:                        GeometryArray ga = gi.getGeometryArray(false, false,
0456:                                false);
0457:                        vertOffset += ga.getVertexCount();
0458:
0459:                        triangData.add(ga);
0460:                    }
0461:                    // Multiply by 2 since we create 2 faces of the font
0462:                    // Second term is for side-faces along depth of the font
0463:                    if (fontExtrusion == null)
0464:                        vertCnt = vertOffset;
0465:                    else {
0466:                        if (fontExtrusion.shape == null)
0467:                            vertCnt = vertOffset * 2 + numPoints * 6;
0468:                        else {
0469:                            vertCnt = vertOffset * 2 + numPoints * 6
0470:                                    * (fontExtrusion.pnts.length - 1);
0471:                        }
0472:                    }
0473:
0474:                    // XXXX: Should use IndexedTriangleArray to avoid 
0475:                    // duplication of vertices. To create triangles for
0476:                    // side faces, every vertex is duplicated currently.
0477:                    TriangleArray triAry = new TriangleArray(vertCnt,
0478:                            GeometryArray.COORDINATES | GeometryArray.NORMALS);
0479:
0480:                    boolean flip_orient[] = new boolean[islandCounts.length];
0481:                    boolean findOrient;
0482:                    // last known non-degenerate normal
0483:                    Vector3f goodNormal = new Vector3f();
0484:
0485:                    for (j = 0; j < islandCounts.length; j++) {
0486:                        GeometryArray ga = (GeometryArray) triangData.get(j);
0487:                        vertOffset = ga.getVertexCount();
0488:
0489:                        findOrient = false;
0490:
0491:                        //Create the triangle array
0492:                        for (i = 0; i < vertOffset; i += 3, currCoordIndex += 3) {
0493:                            //Get 3 points. Since triangle is known to be flat, normal
0494:                            // must be same for all 3 points.
0495:                            ga.getCoordinate(i, p1);
0496:                            ga.getNormal(i, n1);
0497:                            ga.getCoordinate(i + 1, p2);
0498:                            ga.getCoordinate(i + 2, p3);
0499:
0500:                            if (!findOrient) {
0501:                                //Check here if triangles are wound incorrectly and need
0502:                                //to be flipped.
0503:                                if (!getNormal(p1, p2, p3, n2)) {
0504:                                    continue;
0505:                                }
0506:
0507:                                if (n2.z >= EPS) {
0508:                                    flip_orient[j] = false;
0509:                                } else if (n2.z <= -EPS) {
0510:                                    flip_orient[j] = true;
0511:                                } else {
0512:                                    continue;
0513:                                }
0514:                                findOrient = true;
0515:                            }
0516:                            if (flip_orient[j]) {
0517:                                //New Triangulator preserves contour orientation. If contour
0518:                                //input is wound incorrectly, swap 2nd and 3rd points to
0519:                                //sure all triangles are wound correctly for j3d.
0520:                                q1.x = p2.x;
0521:                                q1.y = p2.y;
0522:                                q1.z = p2.z;
0523:                                p2.x = p3.x;
0524:                                p2.y = p3.y;
0525:                                p2.z = p3.z;
0526:                                p3.x = q1.x;
0527:                                p3.y = q1.y;
0528:                                p3.z = q1.z;
0529:                                n1.x = -n1.x;
0530:                                n1.y = -n1.y;
0531:                                n1.z = -n1.z;
0532:                            }
0533:
0534:                            if (fontExtrusion != null) {
0535:                                n2.x = -n1.x;
0536:                                n2.y = -n1.y;
0537:                                n2.z = -n1.z;
0538:
0539:                                triAry.setCoordinate(currCoordIndex, p1);
0540:                                triAry.setNormal(currCoordIndex, n2);
0541:                                triAry.setCoordinate(currCoordIndex + 1, p3);
0542:                                triAry.setNormal(currCoordIndex + 1, n2);
0543:                                triAry.setCoordinate(currCoordIndex + 2, p2);
0544:                                triAry.setNormal(currCoordIndex + 2, n2);
0545:
0546:                                q1.x = p1.x;
0547:                                q1.y = p1.y;
0548:                                q1.z = p1.z + fontExtrusion.length;
0549:                                q2.x = p2.x;
0550:                                q2.y = p2.y;
0551:                                q2.z = p2.z + fontExtrusion.length;
0552:                                q3.x = p3.x;
0553:                                q3.y = p3.y;
0554:                                q3.z = p3.z + fontExtrusion.length;
0555:
0556:                                triAry.setCoordinate(currCoordIndex
0557:                                        + vertOffset, q1);
0558:                                triAry.setNormal(currCoordIndex + vertOffset,
0559:                                        n1);
0560:                                triAry.setCoordinate(currCoordIndex + 1
0561:                                        + vertOffset, q2);
0562:                                triAry.setNormal(currCoordIndex + 1
0563:                                        + vertOffset, n1);
0564:                                triAry.setCoordinate(currCoordIndex + 2
0565:                                        + vertOffset, q3);
0566:                                triAry.setNormal(currCoordIndex + 2
0567:                                        + vertOffset, n1);
0568:                            } else {
0569:                                triAry.setCoordinate(currCoordIndex, p1);
0570:                                triAry.setNormal(currCoordIndex, n1);
0571:                                triAry.setCoordinate(currCoordIndex + 1, p2);
0572:                                triAry.setNormal(currCoordIndex + 1, n1);
0573:                                triAry.setCoordinate(currCoordIndex + 2, p3);
0574:                                triAry.setNormal(currCoordIndex + 2, n1);
0575:                            }
0576:
0577:                        }
0578:                        if (fontExtrusion != null) {
0579:                            currCoordIndex += vertOffset;
0580:                        }
0581:                    }
0582:
0583:                    //Now add side triangles in both cases.
0584:
0585:                    // Since we duplicated triangles with different Z, make sure
0586:                    // currCoordIndex points to correct location.
0587:                    if (fontExtrusion != null) {
0588:                        if (fontExtrusion.shape == null) {
0589:                            boolean smooth;
0590:                            // we'll put a crease if the angle between the normals is
0591:                            // greater than 44 degrees
0592:                            float threshold = (float) Math
0593:                                    .cos(44.0 * Math.PI / 180.0);
0594:                            float cosine;
0595:                            // need the previous normals to check for smoothing
0596:                            Vector3f pn1 = null, pn2 = null;
0597:                            // need the next normals to check for smoothing
0598:                            Vector3f n3 = new Vector3f(), n4 = new Vector3f();
0599:                            //  store the normals for each point because they are
0600:                            // the same for both triangles
0601:                            Vector3f p1Normal = new Vector3f();
0602:                            Vector3f p2Normal = new Vector3f();
0603:                            Vector3f p3Normal = new Vector3f();
0604:                            Vector3f q1Normal = new Vector3f();
0605:                            Vector3f q2Normal = new Vector3f();
0606:                            Vector3f q3Normal = new Vector3f();
0607:
0608:                            for (i = 0; i < islandCounts.length; i++) {
0609:                                for (j = 0, k = 0, num = 0; j < islandCounts[i].length; j++) {
0610:                                    num += islandCounts[i][j];
0611:                                    p1.x = outVerts[i][num - 1].x;
0612:                                    p1.y = outVerts[i][num - 1].y;
0613:                                    p1.z = 0.0f;
0614:                                    q1.x = p1.x;
0615:                                    q1.y = p1.y;
0616:                                    q1.z = p1.z + fontExtrusion.length;
0617:                                    p2.z = 0.0f;
0618:                                    q2.z = p2.z + fontExtrusion.length;
0619:                                    for (int m = 0; m < num; m++) {
0620:                                        p2.x = outVerts[i][m].x;
0621:                                        p2.y = outVerts[i][m].y;
0622:                                        q2.x = p2.x;
0623:                                        q2.y = p2.y;
0624:                                        if (getNormal(p1, q1, p2, n1)) {
0625:
0626:                                            if (!flip_side_orient) {
0627:                                                n1.negate();
0628:                                            }
0629:                                            goodNormal.set(n1);
0630:                                            break;
0631:                                        }
0632:                                    }
0633:
0634:                                    for (; k < num; k++) {
0635:                                        p2.x = outVerts[i][k].x;
0636:                                        p2.y = outVerts[i][k].y;
0637:                                        p2.z = 0.0f;
0638:                                        q2.x = p2.x;
0639:                                        q2.y = p2.y;
0640:                                        q2.z = p2.z + fontExtrusion.length;
0641:
0642:                                        if (!getNormal(p1, q1, p2, n1)) {
0643:                                            n1.set(goodNormal);
0644:                                        } else {
0645:                                            if (!flip_side_orient) {
0646:                                                n1.negate();
0647:                                            }
0648:                                            goodNormal.set(n1);
0649:                                        }
0650:
0651:                                        if (!getNormal(p2, q1, q2, n2)) {
0652:                                            n2.set(goodNormal);
0653:                                        } else {
0654:                                            if (!flip_side_orient) {
0655:                                                n2.negate();
0656:                                            }
0657:                                            goodNormal.set(n2);
0658:                                        }
0659:                                        // if there is a previous normal, see if we need to smooth
0660:                                        // this normal or make a crease
0661:
0662:                                        if (pn1 != null) {
0663:                                            cosine = n1.dot(pn2);
0664:                                            smooth = cosine > threshold;
0665:                                            if (smooth) {
0666:                                                p1Normal.x = (pn1.x + pn2.x + n1.x);
0667:                                                p1Normal.y = (pn1.y + pn2.y + n1.y);
0668:                                                p1Normal.z = (pn1.z + pn2.z + n1.z);
0669:                                                normalize(p1Normal);
0670:
0671:                                                q1Normal.x = (pn2.x + n1.x + n2.x);
0672:                                                q1Normal.y = (pn2.y + n1.y + n2.y);
0673:                                                q1Normal.z = (pn2.z + n1.z + n2.z);
0674:                                                normalize(q1Normal);
0675:                                            } // if smooth
0676:                                            else {
0677:                                                p1Normal.x = n1.x;
0678:                                                p1Normal.y = n1.y;
0679:                                                p1Normal.z = n1.z;
0680:                                                q1Normal.x = n1.x + n2.x;
0681:                                                q1Normal.y = n1.y + n2.y;
0682:                                                q1Normal.z = n1.z + n2.z;
0683:                                                normalize(q1Normal);
0684:                                            } // else
0685:                                        } // if pn1 != null
0686:                                        else {
0687:                                            pn1 = new Vector3f();
0688:                                            pn2 = new Vector3f();
0689:                                            p1Normal.x = n1.x;
0690:                                            p1Normal.y = n1.y;
0691:                                            p1Normal.z = n1.z;
0692:
0693:                                            q1Normal.x = (n1.x + n2.x);
0694:                                            q1Normal.y = (n1.y + n2.y);
0695:                                            q1Normal.z = (n1.z + n2.z);
0696:                                            normalize(q1Normal);
0697:                                        } // else
0698:
0699:                                        // if there is a next, check if we should smooth normal
0700:
0701:                                        if (k + 1 < num) {
0702:                                            p3.x = outVerts[i][k + 1].x;
0703:                                            p3.y = outVerts[i][k + 1].y;
0704:                                            p3.z = 0.0f;
0705:                                            q3.x = p3.x;
0706:                                            q3.y = p3.y;
0707:                                            q3.z = p3.z + fontExtrusion.length;
0708:
0709:                                            if (!getNormal(p2, q2, p3, n3)) {
0710:                                                n3.set(goodNormal);
0711:                                            } else {
0712:                                                if (!flip_side_orient) {
0713:                                                    n3.negate();
0714:                                                }
0715:                                                goodNormal.set(n3);
0716:                                            }
0717:
0718:                                            if (!getNormal(p3, q2, q3, n4)) {
0719:                                                n4.set(goodNormal);
0720:                                            } else {
0721:                                                if (!flip_side_orient) {
0722:                                                    n4.negate();
0723:                                                }
0724:                                                goodNormal.set(n4);
0725:                                            }
0726:
0727:                                            cosine = n2.dot(n3);
0728:                                            smooth = cosine > threshold;
0729:
0730:                                            if (smooth) {
0731:                                                p2Normal.x = (n1.x + n2.x + n3.x);
0732:                                                p2Normal.y = (n1.y + n2.y + n3.y);
0733:                                                p2Normal.z = (n1.z + n2.z + n3.z);
0734:                                                normalize(p2Normal);
0735:
0736:                                                q2Normal.x = (n2.x + n3.x + n4.x);
0737:                                                q2Normal.y = (n2.y + n3.y + n4.y);
0738:                                                q2Normal.z = (n2.z + n3.z + n4.z);
0739:                                                normalize(q2Normal);
0740:                                            } else { // if smooth
0741:                                                p2Normal.x = n1.x + n2.x;
0742:                                                p2Normal.y = n1.y + n2.y;
0743:                                                p2Normal.z = n1.z + n2.z;
0744:                                                normalize(p2Normal);
0745:                                                q2Normal.x = n2.x;
0746:                                                q2Normal.y = n2.y;
0747:                                                q2Normal.z = n2.z;
0748:                                            } // else
0749:                                        } else { // if k+1 < num
0750:                                            p2Normal.x = (n1.x + n2.x);
0751:                                            p2Normal.y = (n1.y + n2.y);
0752:                                            p2Normal.z = (n1.z + n2.z);
0753:                                            normalize(p2Normal);
0754:
0755:                                            q2Normal.x = n2.x;
0756:                                            q2Normal.y = n2.y;
0757:                                            q2Normal.z = n2.z;
0758:                                        } // else
0759:
0760:                                        // add pts for the 2 tris
0761:                                        // p1, q1, p2 and p2, q1, q2
0762:
0763:                                        if (flip_side_orient) {
0764:                                            triAry.setCoordinate(
0765:                                                    currCoordIndex, p1);
0766:                                            triAry.setNormal(currCoordIndex,
0767:                                                    p1Normal);
0768:                                            currCoordIndex++;
0769:
0770:                                            triAry.setCoordinate(
0771:                                                    currCoordIndex, q1);
0772:                                            triAry.setNormal(currCoordIndex,
0773:                                                    q1Normal);
0774:                                            currCoordIndex++;
0775:
0776:                                            triAry.setCoordinate(
0777:                                                    currCoordIndex, p2);
0778:                                            triAry.setNormal(currCoordIndex,
0779:                                                    p2Normal);
0780:                                            currCoordIndex++;
0781:
0782:                                            triAry.setCoordinate(
0783:                                                    currCoordIndex, p2);
0784:                                            triAry.setNormal(currCoordIndex,
0785:                                                    p2Normal);
0786:                                            currCoordIndex++;
0787:
0788:                                            triAry.setCoordinate(
0789:                                                    currCoordIndex, q1);
0790:                                            triAry.setNormal(currCoordIndex,
0791:                                                    q1Normal);
0792:                                            currCoordIndex++;
0793:                                        } else {
0794:                                            triAry.setCoordinate(
0795:                                                    currCoordIndex, q1);
0796:                                            triAry.setNormal(currCoordIndex,
0797:                                                    q1Normal);
0798:                                            currCoordIndex++;
0799:
0800:                                            triAry.setCoordinate(
0801:                                                    currCoordIndex, p1);
0802:                                            triAry.setNormal(currCoordIndex,
0803:                                                    p1Normal);
0804:                                            currCoordIndex++;
0805:
0806:                                            triAry.setCoordinate(
0807:                                                    currCoordIndex, p2);
0808:                                            triAry.setNormal(currCoordIndex,
0809:                                                    p2Normal);
0810:                                            currCoordIndex++;
0811:
0812:                                            triAry.setCoordinate(
0813:                                                    currCoordIndex, q1);
0814:                                            triAry.setNormal(currCoordIndex,
0815:                                                    q1Normal);
0816:                                            currCoordIndex++;
0817:
0818:                                            triAry.setCoordinate(
0819:                                                    currCoordIndex, p2);
0820:                                            triAry.setNormal(currCoordIndex,
0821:                                                    p2Normal);
0822:                                            currCoordIndex++;
0823:                                        }
0824:                                        triAry
0825:                                                .setCoordinate(currCoordIndex,
0826:                                                        q2);
0827:                                        triAry.setNormal(currCoordIndex,
0828:                                                q2Normal);
0829:                                        currCoordIndex++;
0830:                                        pn1.x = n1.x;
0831:                                        pn1.y = n1.y;
0832:                                        pn1.z = n1.z;
0833:                                        pn2.x = n2.x;
0834:                                        pn2.y = n2.y;
0835:                                        pn2.z = n2.z;
0836:                                        p1.x = p2.x;
0837:                                        p1.y = p2.y;
0838:                                        p1.z = p2.z;
0839:                                        q1.x = q2.x;
0840:                                        q1.y = q2.y;
0841:                                        q1.z = q2.z;
0842:
0843:                                    }// for k
0844:
0845:                                    // set the previous normals to null when we are done
0846:                                    pn1 = null;
0847:                                    pn2 = null;
0848:                                }// for j
0849:                            }//for i
0850:                        } else { // if shape
0851:                            int m, offset = 0;
0852:                            Point3f P2 = new Point3f(), Q2 = new Point3f(), P1 = new Point3f();
0853:                            Vector3f nn = new Vector3f(), nn1 = new Vector3f(), nn2 = new Vector3f(), nn3 = new Vector3f();
0854:                            Vector3f nna = new Vector3f(), nnb = new Vector3f();
0855:                            float length;
0856:                            boolean validNormal = false;
0857:
0858:                            // fontExtrusion.shape is specified, and is NOT straight line
0859:                            for (i = 0; i < islandCounts.length; i++) {
0860:                                for (j = 0, k = 0, offset = num = 0; j < islandCounts[i].length; j++) {
0861:                                    num += islandCounts[i][j];
0862:
0863:                                    p1.x = outVerts[i][num - 1].x;
0864:                                    p1.y = outVerts[i][num - 1].y;
0865:                                    p1.z = 0.0f;
0866:                                    q1.x = p1.x;
0867:                                    q1.y = p1.y;
0868:                                    q1.z = p1.z + fontExtrusion.length;
0869:                                    p3.z = 0.0f;
0870:                                    for (m = num - 2; m >= 0; m--) {
0871:                                        p3.x = outVerts[i][m].x;
0872:                                        p3.y = outVerts[i][m].y;
0873:
0874:                                        if (getNormal(p3, q1, p1, nn1)) {
0875:                                            if (!flip_side_orient) {
0876:                                                nn1.negate();
0877:                                            }
0878:                                            goodNormal.set(nn1);
0879:                                            break;
0880:                                        }
0881:                                    }
0882:                                    for (; k < num; k++) {
0883:                                        p2.x = outVerts[i][k].x;
0884:                                        p2.y = outVerts[i][k].y;
0885:                                        p2.z = 0.0f;
0886:                                        q2.x = p2.x;
0887:                                        q2.y = p2.y;
0888:                                        q2.z = p2.z + fontExtrusion.length;
0889:                                        getNormal(p1, q1, p2, nn2);
0890:
0891:                                        p3.x = outVerts[i][(k + 1) == num ? offset
0892:                                                : (k + 1)].x;
0893:                                        p3.y = outVerts[i][(k + 1) == num ? offset
0894:                                                : (k + 1)].y;
0895:                                        p3.z = 0.0f;
0896:                                        if (!getNormal(p3, p2, q2, nn3)) {
0897:                                            nn3.set(goodNormal);
0898:                                        } else {
0899:                                            if (!flip_side_orient) {
0900:                                                nn3.negate();
0901:                                            }
0902:                                            goodNormal.set(nn3);
0903:                                        }
0904:
0905:                                        // Calculate normals at the point by averaging normals
0906:                                        // of two faces on each side of the point.
0907:                                        nna.x = (nn1.x + nn2.x);
0908:                                        nna.y = (nn1.y + nn2.y);
0909:                                        nna.z = (nn1.z + nn2.z);
0910:                                        normalize(nna);
0911:
0912:                                        nnb.x = (nn3.x + nn2.x);
0913:                                        nnb.y = (nn3.y + nn2.y);
0914:                                        nnb.z = (nn3.z + nn2.z);
0915:                                        normalize(nnb);
0916:
0917:                                        P1.x = p1.x;
0918:                                        P1.y = p1.y;
0919:                                        P1.z = p1.z;
0920:                                        P2.x = p2.x;
0921:                                        P2.y = p2.y;
0922:                                        P2.z = p2.z;
0923:                                        Q2.x = q2.x;
0924:                                        Q2.y = q2.y;
0925:                                        Q2.z = q2.z;
0926:                                        for (m = 1; m < fontExtrusion.pnts.length; m++) {
0927:                                            q1.z = q2.z = fontExtrusion.pnts[m].x;
0928:                                            q1.x = P1.x + nna.x
0929:                                                    * fontExtrusion.pnts[m].y;
0930:                                            q1.y = P1.y + nna.y
0931:                                                    * fontExtrusion.pnts[m].y;
0932:                                            q2.x = P2.x + nnb.x
0933:                                                    * fontExtrusion.pnts[m].y;
0934:                                            q2.y = P2.y + nnb.y
0935:                                                    * fontExtrusion.pnts[m].y;
0936:
0937:                                            if (!getNormal(p1, q1, p2, n1)) {
0938:                                                n1.set(goodNormal);
0939:                                            } else {
0940:                                                if (!flip_side_orient) {
0941:                                                    n1.negate();
0942:                                                }
0943:                                                goodNormal.set(n1);
0944:                                            }
0945:
0946:                                            if (flip_side_orient) {
0947:                                                triAry.setCoordinate(
0948:                                                        currCoordIndex, p1);
0949:                                                triAry.setNormal(
0950:                                                        currCoordIndex, n1);
0951:                                                currCoordIndex++;
0952:
0953:                                                triAry.setCoordinate(
0954:                                                        currCoordIndex, q1);
0955:                                                triAry.setNormal(
0956:                                                        currCoordIndex, n1);
0957:                                                currCoordIndex++;
0958:                                            } else {
0959:                                                triAry.setCoordinate(
0960:                                                        currCoordIndex, q1);
0961:                                                triAry.setNormal(
0962:                                                        currCoordIndex, n1);
0963:                                                currCoordIndex++;
0964:
0965:                                                triAry.setCoordinate(
0966:                                                        currCoordIndex, p1);
0967:                                                triAry.setNormal(
0968:                                                        currCoordIndex, n1);
0969:                                                currCoordIndex++;
0970:                                            }
0971:                                            triAry.setCoordinate(
0972:                                                    currCoordIndex, p2);
0973:                                            triAry
0974:                                                    .setNormal(currCoordIndex,
0975:                                                            n1);
0976:                                            currCoordIndex++;
0977:
0978:                                            if (!getNormal(p2, q1, q2, n1)) {
0979:                                                n1.set(goodNormal);
0980:                                            } else {
0981:                                                if (!flip_side_orient) {
0982:                                                    n1.negate();
0983:                                                }
0984:                                                goodNormal.set(n1);
0985:                                            }
0986:
0987:                                            if (flip_side_orient) {
0988:                                                triAry.setCoordinate(
0989:                                                        currCoordIndex, p2);
0990:                                                triAry.setNormal(
0991:                                                        currCoordIndex, n1);
0992:                                                currCoordIndex++;
0993:
0994:                                                triAry.setCoordinate(
0995:                                                        currCoordIndex, q1);
0996:                                                triAry.setNormal(
0997:                                                        currCoordIndex, n1);
0998:                                                currCoordIndex++;
0999:                                            } else {
1000:                                                triAry.setCoordinate(
1001:                                                        currCoordIndex, q1);
1002:                                                triAry.setNormal(
1003:                                                        currCoordIndex, n1);
1004:                                                currCoordIndex++;
1005:
1006:                                                triAry.setCoordinate(
1007:                                                        currCoordIndex, p2);
1008:                                                triAry.setNormal(
1009:                                                        currCoordIndex, n1);
1010:                                                currCoordIndex++;
1011:                                            }
1012:                                            triAry.setCoordinate(
1013:                                                    currCoordIndex, q2);
1014:                                            triAry
1015:                                                    .setNormal(currCoordIndex,
1016:                                                            n1);
1017:                                            currCoordIndex++;
1018:
1019:                                            p1.x = q1.x;
1020:                                            p1.y = q1.y;
1021:                                            p1.z = q1.z;
1022:                                            p2.x = q2.x;
1023:                                            p2.y = q2.y;
1024:                                            p2.z = q2.z;
1025:                                        }// for m
1026:                                        p1.x = P2.x;
1027:                                        p1.y = P2.y;
1028:                                        p1.z = P2.z;
1029:                                        q1.x = Q2.x;
1030:                                        q1.y = Q2.y;
1031:                                        q1.z = Q2.z;
1032:                                        nn1.x = nn2.x;
1033:                                        nn1.y = nn2.y;
1034:                                        nn1.z = nn2.z;
1035:                                    }// for k
1036:                                    offset = num;
1037:                                }// for j
1038:                            }//for i
1039:                        }// if shape
1040:                    }// if fontExtrusion
1041:                    geo = (GeometryArrayRetained) triAry.retained;
1042:                    geomHash.put(ch, geo);
1043:                }
1044:
1045:                return geo;
1046:            }
1047:
1048:            static boolean getNormal(Point3f p1, Point3f p2, Point3f p3,
1049:                    Vector3f normal) {
1050:                Vector3f v1 = new Vector3f();
1051:                Vector3f v2 = new Vector3f();
1052:
1053:                // Must compute normal
1054:                v1.sub(p2, p1);
1055:                v2.sub(p2, p3);
1056:                normal.cross(v1, v2);
1057:                normal.negate();
1058:
1059:                float length = normal.length();
1060:
1061:                if (length > 0) {
1062:                    length = 1 / length;
1063:                    normal.x *= length;
1064:                    normal.y *= length;
1065:                    normal.z *= length;
1066:                    return true;
1067:                }
1068:                return false;
1069:            }
1070:
1071:            // check if 2 contours are inside/outside/intersect one another
1072:            // INPUT:
1073:            // vertCnt1, vertCnt2  - number of vertices in 2 contours
1074:            // begin1, begin2      - starting indices into vertices for 2 contours
1075:            // vertices            - actual vertex data
1076:            // OUTPUT:
1077:            // status == 1   - intersecting contours
1078:            //           2   - first contour inside the second 
1079:            //           3   - second contour inside the first
1080:            //           0   - disjoint contours(2 islands)
1081:
1082:            static int check2Contours(int begin1, int end1, int begin2,
1083:                    int end2, Point3f[] vertices) {
1084:                int i, j;
1085:                boolean inside2, inside1;
1086:
1087:                inside2 = pointInPolygon2D(vertices[begin1].x,
1088:                        vertices[begin1].y, begin2, end2, vertices);
1089:
1090:                for (i = begin1 + 1; i < end1; i++) {
1091:                    if (pointInPolygon2D(vertices[i].x, vertices[i].y, begin2,
1092:                            end2, vertices) != inside2) {
1093:                        return 1; //intersecting contours
1094:                    }
1095:                }
1096:
1097:                // Since we are using point in polygon test and not 
1098:                // line in polygon test. There are cases we miss the interesting
1099:                // if we are not checking the reverse for all points. This happen
1100:                // when two points form a line pass through a polygon but the two
1101:                // points are outside of it.
1102:
1103:                inside1 = pointInPolygon2D(vertices[begin2].x,
1104:                        vertices[begin2].y, begin1, end1, vertices);
1105:
1106:                for (i = begin2 + 1; i < end2; i++) {
1107:                    if (pointInPolygon2D(vertices[i].x, vertices[i].y, begin1,
1108:                            end1, vertices) != inside1) {
1109:                        return 1; //intersecting contours
1110:                    }
1111:                }
1112:
1113:                if (!inside2) {
1114:                    if (!inside1) {
1115:                        return 0; // disjoint countours
1116:                    }
1117:                    // inside2 = false and inside1 = true
1118:                    return 3; // second contour inside first
1119:                }
1120:
1121:                // must be inside2 = true and inside1 = false
1122:                // Note that it is not possible inside2 = inside1 = true
1123:                // unless two contour overlap to each others.
1124:                //
1125:                return 2; // first contour inside second
1126:            }
1127:
1128:            // Test if 2D point (x,y) lies inside polygon represented by verts.
1129:            // z-value of polygon vertices is ignored. Sent only to avoid data-copy.
1130:            // Uses ray-shooting algorithm to compute intersections along +X axis.
1131:            // This algorithm works for all polygons(concave, self-intersecting) and
1132:            // is best solution here due to large number of polygon vertices.
1133:            // Point is INSIDE if number of intersections is odd, OUTSIDE if number
1134:            // of intersections is even.
1135:            static boolean pointInPolygon2D(float x, float y, int begIdx,
1136:                    int endIdx, Point3f[] verts) {
1137:
1138:                int i, num_intersections = 0;
1139:                float xi;
1140:
1141:                for (i = begIdx; i < endIdx - 1; i++) {
1142:                    if ((verts[i].y >= y && verts[i + 1].y >= y)
1143:                            || (verts[i].y < y && verts[i + 1].y < y))
1144:                        continue;
1145:
1146:                    xi = verts[i].x + (verts[i].x - verts[i + 1].x)
1147:                            * (y - verts[i].y) / (verts[i].y - verts[i + 1].y);
1148:
1149:                    if (x < xi)
1150:                        num_intersections++;
1151:                }
1152:
1153:                // Check for segment from last vertex to first vertex.
1154:
1155:                if (!((verts[i].y >= y && verts[begIdx].y >= y) || (verts[i].y < y && verts[begIdx].y < y))) {
1156:                    xi = verts[i].x + (verts[i].x - verts[begIdx].x)
1157:                            * (y - verts[i].y) / (verts[i].y - verts[begIdx].y);
1158:
1159:                    if (x < xi)
1160:                        num_intersections++;
1161:                }
1162:
1163:                return ((num_intersections % 2) != 0);
1164:            }
1165:
1166:            static final boolean normalize(Vector3f v) {
1167:                float len = v.length();
1168:
1169:                if (len > 0) {
1170:                    len = 1.0f / len;
1171:                    v.x *= len;
1172:                    v.y *= len;
1173:                    v.z *= len;
1174:                    return true;
1175:                }
1176:                return false;
1177:            }
1178:
1179:            // A Tree of islands form based on contour, each parent's contour 
1180:            // enclosed all the child. We built this since Triangular fail to
1181:            // handle the case of multiple concentrated contours. i.e. if
1182:            // 4 contours A > B > C > D. Triangular will fail recongized
1183:            // two island, one form by A & B and the other by C & D.
1184:            // Using this tree we can separate out every 2 levels and pass
1185:            // in to triangular to workaround its limitation.
1186:            static private class IslandsNode {
1187:
1188:                private ArrayList islandsList = null;
1189:                int startIdx, endIdx;
1190:
1191:                IslandsNode(int startIdx, int endIdx) {
1192:                    this .startIdx = startIdx;
1193:                    this .endIdx = endIdx;
1194:                    islandsList = null;
1195:                }
1196:
1197:                void addChild(IslandsNode node) {
1198:
1199:                    if (islandsList == null) {
1200:                        islandsList = new ArrayList(5);
1201:                    }
1202:                    islandsList.add(node);
1203:                }
1204:
1205:                void removeChild(IslandsNode node) {
1206:                    islandsList.remove(islandsList.indexOf(node));
1207:                }
1208:
1209:                IslandsNode getChild(int idx) {
1210:                    return (IslandsNode) islandsList.get(idx);
1211:                }
1212:
1213:                int numChild() {
1214:                    return (islandsList == null ? 0 : islandsList.size());
1215:                }
1216:
1217:                int numVertices() {
1218:                    return endIdx - startIdx;
1219:                }
1220:
1221:                void insert(IslandsNode newNode, Point3f[] vertices) {
1222:                    boolean createNewLevel = false;
1223:
1224:                    if (islandsList != null) {
1225:                        IslandsNode childNode;
1226:                        int status;
1227:
1228:                        for (int i = numChild() - 1; i >= 0; i--) {
1229:                            childNode = getChild(i);
1230:                            status = check2Contours(newNode.startIdx,
1231:                                    newNode.endIdx, childNode.startIdx,
1232:                                    childNode.endIdx, vertices);
1233:                            switch (status) {
1234:                            case 2: // newNode inside childNode, go down recursively
1235:                                childNode.insert(newNode, vertices);
1236:                                return;
1237:                            case 3:// childNode inside newNode, 
1238:                                // continue to search other childNode also
1239:                                // inside this one and group them together.
1240:                                newNode.addChild(childNode);
1241:                                createNewLevel = true;
1242:                                break;
1243:                            default: // intersecting or disjoint
1244:
1245:                            }
1246:                        }
1247:                    }
1248:
1249:                    if (createNewLevel) {
1250:                        // Remove child in newNode from this
1251:                        for (int i = newNode.numChild() - 1; i >= 0; i--) {
1252:                            removeChild(newNode.getChild(i));
1253:                        }
1254:                        // Add the newNode to parent 
1255:                    }
1256:                    addChild(newNode);
1257:                }
1258:
1259:                // Return a list of node with odd number of level
1260:                void collectOddLevelNode(UnorderList list, int level) {
1261:                    if ((level % 2) == 1) {
1262:                        list.add(this );
1263:                    }
1264:                    if (islandsList != null) {
1265:                        level++;
1266:                        for (int i = numChild() - 1; i >= 0; i--) {
1267:                            getChild(i).collectOddLevelNode(list, level);
1268:                        }
1269:                    }
1270:                }
1271:            }
1272:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.