📄 font3d.java
字号:
/* * $RCSfile: Font3D.java,v $ * * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. * * Use is subject to license terms. * * $Revision: 1.5 $ * $Date: 2007/02/09 17:17:59 $ * $State: Exp $ */package javax.media.j3d;import com.sun.j3d.utils.geometry.*;import com.sun.j3d.internal.FastVector;import java.awt.Font;import java.awt.font.*;import java.awt.geom.Rectangle2D;import java.awt.geom.AffineTransform;import javax.vecmath.*;import java.awt.Shape;import java.awt.geom.PathIterator;import java.util.*;/** * The Font3D object is used to store extruded 2D glyphs. These * 3D glyphs can then be used to construct Text3D NodeComponent * objects. * <P> * A 3D Font consists of a Java 2D font, a tesellation tolerance, * and an extrusion path. The extrusion * path creates depth by describing how the edge of a glyph varies * in the Z axis. * <P> * The construction of a Text3D object requires a Font3D object. * The Font3D object describes the style of the text, such as its * depth. The text also needs other classes, such as java.awt.Font and * FontExtrusion. The Font object describes the font name (Helvetica, * Courier, etc.), the font style (bold, Italic, etc.), and point * size. The FontExtrusion object extends Font3D by describing * the extrusion path for the Font3D object (how the edge of the * font glyph varies in the Z axis). *<P> * To ensure correct rendering, the 2D Font object should be created * with the default AffineTransform. The point size of the 2D font will * be used as a rough measure of how fine a tesselation to use when * creating the Font3D object: the larger the point size, in * general, the finer the tesselation. * <P> * Custom 3D fonts as well as methods to store 3D fonts * to disk will be addressed in a future release. * * @see java.awt.Font * @see FontExtrusion * @see Text3D */public class Font3D extends NodeComponent { Font font; double tessellationTolerance; FontExtrusion fontExtrusion; FontRenderContext frc; // Used by triangulateGlyphs method to split contour data into islands. final static float EPS = 0.000001f; // Map glyph code to GeometryArrayRetained Hashtable geomHash = new Hashtable(20); /** * Constructs a Font3D object from the specified Font and * FontExtrusion objects, using the default value for the * tessellation tolerance. The default value is as follows: * * <ul> * tessellation tolerance : 0.01<br> * </ul> * <P> * The FontExtrusion object contains the extrusion path to use on * the 2D Font glyphs. To ensure correct rendering the font must * be created with the default AffineTransform. Passing null for * the FontExtrusion parameter results in no extrusion being done. * * @param font the Java 2D font used to create the 3D font object * @param extrudePath the extrusion path used to describe how * the edge of the font varies along the Z axis */ public Font3D(Font font, FontExtrusion extrudePath) { this(font, 0.01, extrudePath); } /** * Constructs a Font3D object from the specified Font and * FontExtrusion objects, using the specified tessellation * tolerance. * The FontExtrusion object contains the extrusion path to use on * the 2D Font glyphs. To ensure correct rendering, the font must * be created with the default AffineTransform. Passing null for * the FontExtrusion parameter results in no extrusion being done. * * @param font the Java 2D font used to create the 3D font object. * @param tessellationTolerance the tessellation tolerance value * used in tessellating the glyphs of the 2D Font. * This corresponds to the <code>flatness</code> parameter in * the <code>java.awt.Shape.getPathIterator</code> method. * @param extrudePath the extrusion path used to describe how * the edge of the font varies along the Z axis. * * @since Java 3D 1.2 */ public Font3D(Font font, double tessellationTolerance, FontExtrusion extrudePath) { this.font = font; this.tessellationTolerance = tessellationTolerance; this.fontExtrusion = extrudePath; this.frc = new FontRenderContext(new AffineTransform(), true, true); } /** * Returns the Java 2D Font used to create this Font3D object. * @return Font object used by this Font3D */ public Font getFont() { return this.font; } /** * Returns the tessellation tolerance with which this Font3D was * created. * @return the tessellation tolerance used by this Font3D * * @since Java 3D 1.2 */ public double getTessellationTolerance() { return tessellationTolerance; } /** * Copies the FontExtrusion object used to create this Font3D object * into the specified parameter. * * @param extrudePath object that will receive the * FontExtrusion information for this Font3D object */ public void getFontExtrusion(FontExtrusion extrudePath) { extrudePath = this.fontExtrusion; } /** * Returns the 3D bounding box of the specified glyph code. * * @param glyphCode the glyphCode from the original 2D Font * @param bounds the 3D glyph's bounds */ public void getBoundingBox(int glyphCode, BoundingBox bounds){ int[] gCodes = {glyphCode}; GlyphVector gVec = font.createGlyphVector(frc, gCodes); Rectangle2D.Float bounds2d = (Rectangle2D.Float) (((GlyphMetrics)(gVec.getGlyphMetrics(0))).getBounds2D()); Point3d lower = new Point3d(bounds2d.x, bounds2d.y, 0.0); Point3d upper; if (fontExtrusion != null) { upper = new Point3d(bounds2d.x + bounds2d.width, bounds2d.y + bounds2d.height, fontExtrusion.length); } else { upper = new Point3d(bounds2d.x + bounds2d.width, bounds2d.y + bounds2d.height, 0.0); } bounds.setLower(lower); bounds.setUpper(upper); } // BY MIK OF CLASSX /** * Returns a GeometryArray of a glyph in this Font3D. * * @param c character from which to generate a tessellated glyph. * * @return a GeometryArray * * @since Java 3D 1.4 */ public GeometryArray getGlyphGeometry(char c) { char code[] = { c }; GlyphVector gv = font.createGlyphVector(frc, code); // triangulate the glyph GeometryArrayRetained glyph_gar = triangulateGlyphs(gv, code[0]); // Assume that triangulateGlyphs returns a triangle array with only coords & normals // (and without by-ref, interleaved, etc.) assert glyph_gar instanceof TriangleArrayRetained : "Font3D: GeometryArray is not an instance of TrangleArray"; assert glyph_gar.getVertexFormat() == (GeometryArray.COORDINATES | GeometryArray.NORMALS) : "Font3D: Illegal GeometryArray format -- only coordinates and normals expected"; // create a correctly sized TriangleArray TriangleArray ga = new TriangleArray(glyph_gar.getVertexCount(),glyph_gar.getVertexFormat()); // temp storage for coords, normals float tmp[] = new float[3]; int vertexCount = ga.getVertexCount(); for(int i=0; i<vertexCount; i++) { // copy the glyph geometry to the TriangleArray glyph_gar.getCoordinate(i,tmp); ga.setCoordinate(i,tmp); glyph_gar.getNormal(i,tmp); ga.setNormal(i,tmp); } return ga; } // Triangulate glyph with 'unicode' if not already done. GeometryArrayRetained triangulateGlyphs(GlyphVector gv, char c) { Character ch = new Character(c); GeometryArrayRetained geo = (GeometryArrayRetained) geomHash.get(ch); if (geo == null) { // Font Y-axis is downwards, so send affine transform to flip it. Rectangle2D bnd = gv.getVisualBounds(); AffineTransform aTran = new AffineTransform(); double tx = bnd.getX() + 0.5 * bnd.getWidth(); double ty = bnd.getY() + 0.5 * bnd.getHeight(); aTran.setToTranslation(-tx, -ty); aTran.scale(1.0, -1.0); aTran.translate(tx, -ty); Shape shape = gv.getOutline(); PathIterator pIt = shape.getPathIterator(aTran, tessellationTolerance); int flag= -1, numContours = 0, numPoints = 0, i, j, k, num=0, vertCnt; UnorderList coords = new UnorderList(100, Point3f.class); float tmpCoords[] = new float[6]; float lastX= .0f, lastY= .0f; float firstPntx = Float.MAX_VALUE, firstPnty = Float.MAX_VALUE; GeometryInfo gi = null; NormalGenerator ng = new NormalGenerator(); FastVector contours = new FastVector(10); float maxY = -Float.MAX_VALUE; int maxYIndex = 0, beginIdx = 0, endIdx = 0, start = 0; boolean setMaxY = false; while (!pIt.isDone()) { Point3f vertex = new Point3f(); flag = pIt.currentSegment(tmpCoords); if (flag == PathIterator.SEG_CLOSE){ if (num > 0) { if (setMaxY) { // Get Previous point beginIdx = start; endIdx = numPoints-1; } contours.addElement(num); num = 0; numContours++; } } else if (flag == PathIterator.SEG_MOVETO){ vertex.x = tmpCoords[0]; vertex.y = tmpCoords[1]; lastX = vertex.x; lastY = vertex.y; if ((lastX == firstPntx) && (lastY == firstPnty)) { pIt.next(); continue; } setMaxY = false; coords.add(vertex); firstPntx = lastX; firstPnty = lastY; if (num> 0){ contours.addElement(num); num = 0; numContours++; } num++; numPoints++; // skip checking of first point, // since the last point will repeat this. start = numPoints ; } else if (flag == PathIterator.SEG_LINETO){ vertex.x = tmpCoords[0]; vertex.y = tmpCoords[1]; //Check here for duplicate points. Code //later in this function can not handle //duplicate points. if ((vertex.x == lastX) && (vertex.y == lastY)) { pIt.next(); continue; } if (vertex.y > maxY) { maxY = vertex.y; maxYIndex = numPoints; setMaxY = true; } lastX = vertex.x; lastY = vertex.y; coords.add(vertex); num++; numPoints++; } pIt.next(); } // No data(e.g space, control characters) // Two point can't form a valid contour if (numPoints == 0){ return null; } // Determine font winding order use for side triangles Point3f p1 = new Point3f(), p2 = new Point3f(), p3 = new Point3f(); boolean flip_side_orient = true; Point3f vertices[] = (Point3f []) coords.toArray(false); if (endIdx - beginIdx > 0) { // must be true unless it is a single line // define as "MoveTo p1 LineTo p2 Close" which is // not a valid font definition. if (maxYIndex == beginIdx) { p1.set(vertices[endIdx]); } else { p1.set(vertices[maxYIndex-1]); } p2.set(vertices[maxYIndex]); if (maxYIndex == endIdx) { p3.set(vertices[beginIdx]); } else { p3.set(vertices[maxYIndex+1]); } if (p3.x != p2.x) { if (p1.x != p2.x) { // Use the one with smallest slope if (Math.abs((p2.y - p1.y)/(p2.x - p1.x)) > Math.abs((p3.y - p2.y)/(p3.x - p2.x))) { flip_side_orient = (p3.x > p2.x); } else { flip_side_orient = (p2.x > p1.x); } } else { flip_side_orient = (p3.x > p2.x); } } else { // p1.x != p2.x, otherwise all three // point form a straight vertical line with // the middle point the highest. This is not a // valid font definition. flip_side_orient = (p2.x > p1.x); } } // Build a Tree of Islands int startIdx = 0; IslandsNode islandsTree = new IslandsNode(-1, -1); int contourCounts[] = contours.getData(); for (i= 0;i < contours.getSize(); i++) { endIdx = startIdx + contourCounts[i]; islandsTree.insert(new IslandsNode(startIdx, endIdx), vertices); startIdx = endIdx; } coords = null; // Free memory contours = null; contourCounts = null;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -