private void calculateGridTranslation() { if (transformCells.getScaleX() >= SHOW_GRID_MIN_SCALE) { @SuppressWarnings("SuspiciousNameCombination") double modX = Math.floorMod(round(transformCells.getTranslateX()), cellWidth); double modY = Math.floorMod(round(transformCells.getTranslateY()), cellHeight); transformGrid.setToTranslation(-cellWidth + modX - 1, -cellHeight + modY - 1); } }
public void tree(Graphics2D g2d, double size, int phase) { g2d.setColor(colors[phase % 3]); new TextLayout(theT.toString(), theFont, g2d.getFontRenderContext()).draw(g2d, 0.0f, 0.0f); if (size > 10.0) { AffineTransform at = new AffineTransform(); at.setToTranslation(Twidth, -0.1); at.scale(0.6, 0.6); g2d.transform(at); size *= 0.6; new TextLayout(theR.toString(), theFont, g2d.getFontRenderContext()).draw(g2d, 0.0f, 0.0f); at.setToTranslation(Rwidth + 0.75, 0); g2d.transform(at); Graphics2D g2dt = (Graphics2D) g2d.create(); at.setToRotation(-Math.PI / 2.0); g2dt.transform(at); tree(g2dt, size, phase + 1); g2dt.dispose(); at.setToTranslation(.75, 0); at.rotate(-Math.PI / 2.0); at.scale(-1.0, 1.0); at.translate(-Twidth, 0); g2d.transform(at); tree(g2d, size, phase); } g2d.setTransform(new AffineTransform()); }
@Override protected void paintComponent(Graphics graphics) { // Fill in the background: Graphics2D g = (Graphics2D) graphics; Shape clip = g.getClip(); g.setColor(LightZoneSkin.Colors.NeutralGray); g.fill(clip); if (preview == null) { PlanarImage image = currentImage.get(); if (image == null) { engine.update(null, false); } else if (visibleRect != null && getHeight() > 1 && getWidth() > 1) { preview = cropScaleGrayscale(visibleRect, image); } } if (preview != null) { int dx, dy; AffineTransform transform = new AffineTransform(); if (getSize().width > preview.getWidth()) dx = (getSize().width - preview.getWidth()) / 2; else dx = 0; if (getSize().height > preview.getHeight()) dy = (getSize().height - preview.getHeight()) / 2; else dy = 0; transform.setToTranslation(dx, dy); try { g.drawRenderedImage(preview, transform); } catch (Exception e) { e.printStackTrace(); } } }
public void update() { x += Math.cos(heading) * speed; y += Math.sin(heading) * speed; rect.setLocation((int) Math.round(x), (int) Math.round(y)); affineTransform.setToTranslation(x, y); affineTransform.rotate(heading + (Math.PI / 2)); }
/** * Gets the mark for the specified panel. * * @param trackerPanel the tracker panel * @return the mark */ protected Mark getMark(TrackerPanel trackerPanel) { Mark mark = marks.get(trackerPanel); TPoint selection = null; if (mark == null) { selection = trackerPanel.getSelectedPoint(); Point p = null; valid = true; // assume true for (int n = 0; n < points.length; n++) { if (!valid) continue; // determine if point is valid (ie not NaN) valid = valid && !Double.isNaN(points[n].getX()) && !Double.isNaN(points[n].getY()); screenPoints[n] = points[n].getScreenPosition(trackerPanel); if (valid && selection == points[n]) p = screenPoints[n]; } mark = footprint.getMark(screenPoints); if (p != null) { // point is selected, so draw selection shape transform.setToTranslation(p.x, p.y); int scale = FontSizer.getIntegerFactor(); if (scale > 1) { transform.scale(scale, scale); } final Color color = footprint.getColor(); final Mark stepMark = mark; final Shape selectedShape = transform.createTransformedShape(selectionShape); mark = new Mark() { public void draw(Graphics2D g, boolean highlighted) { stepMark.draw(g, false); Paint gpaint = g.getPaint(); g.setPaint(color); g.fill(selectedShape); g.setPaint(gpaint); } public Rectangle getBounds(boolean highlighted) { Rectangle bounds = selectedShape.getBounds(); bounds.add(stepMark.getBounds(false)); return bounds; } }; } final Mark theMark = mark; mark = new Mark() { public void draw(Graphics2D g, boolean highlighted) { if (!valid) return; theMark.draw(g, false); } public Rectangle getBounds(boolean highlighted) { return theMark.getBounds(highlighted); } }; marks.put(trackerPanel, mark); } return mark; }
protected AffineTransform getArrowTrans( double sx, double sy, double ex, double ey, double width, double theta) { m_arrowTrans.setToTranslation(ex, ey); m_arrowTrans.rotate(-HALF_PI + theta + Math.atan2(ey - sy, ex - sx)); if (width > m_width) { double scalar = width / 3; m_arrowTrans.scale(scalar, scalar); } return m_arrowTrans; }
@Override public Transition2DInstruction[] getInstructions(float progress, Dimension size) { if (type == OUT) { progress = 1 - progress; } progress = (float) Math.pow(progress, .5); float ySize = (size.height) * .05f; float xSize = (size.width) * .05f; Vector<RectangularShape> v = new Vector<RectangularShape>(); float angleProgress = (float) Math.pow(1 - Math.min(progress, 1), .5); // pop it over 1: float progressZ = 1.3f * progress; double w = xSize * progressZ; double h = ySize * progressZ; float min = (float) (Math.min(w, h)); for (float y = 0; y < size.height; y += ySize) { for (float x = 0; x < size.width; x += xSize) { v.add( new RoundRectangle2D.Double( x + xSize / 2 - w / 2, y + ySize / 2 - h / 2, w * progress + (1 - progress) * min, h * progress + (1 - progress) * min, w * angleProgress * progress + (1 - progress) * min * angleProgress, h * angleProgress * progress + (1 - progress) * min * angleProgress)); } } ImageInstruction[] instr = new ImageInstruction[v.size() + 1]; instr[0] = new ImageInstruction(false); for (int a = 0; a < v.size(); a++) { float progress2 = progress; // (float)Math.pow(progress, .9+.2*random.nextFloat()); RectangularShape r = v.get(a); Point2D p1 = new Point2D.Double(r.getCenterX(), r.getCenterY()); Point2D p2 = new Point2D.Double(r.getCenterX(), r.getCenterY()); AffineTransform transform = new AffineTransform(); transform.translate(r.getCenterX(), r.getCenterY()); transform.scale(30 * (1 - progress) + 1, 30 * (1 - progress) + 1); transform.translate(-r.getCenterX(), -r.getCenterY()); transform.rotate(.3 * (1 - progress2), size.width / 3, size.height / 2); transform.transform(p1, p2); transform.setToTranslation(p1.getX() - p2.getX(), p1.getY() - p2.getY()); Shape shape = transform.createTransformedShape(r); instr[a + 1] = new ImageInstruction(true, transform, shape); } if (type == IN) { for (int a = 0; a < instr.length; a++) { instr[a].isFirstFrame = !instr[a].isFirstFrame; } } return instr; }
/** * Rotate an image using an AffineTransform. * * @param timg The image you want to rotate * @param degrees Degrees to rotate * @return The rotated image */ public BufferedImage rotate(BufferedImage timg, double degrees) { AffineTransform xform = new AffineTransform(); xform.setToTranslation(0.5 * timg.getWidth(), 0.5 * timg.getHeight()); xform.rotate(degrees); xform.translate(-0.5 * timg.getHeight(), -0.5 * timg.getWidth()); AffineTransformOp op = new AffineTransformOp(xform, AffineTransformOp.TYPE_BILINEAR); return op.filter(timg, null); }
private void adjustEndingPoint(Point2D start, Point2D end, VisualItem source, VisualItem target) { Rectangle2D sourceBounds = source.getBounds(); Rectangle2D targetBounds = target.getBounds(); if (source.getShape() == Constants.SHAPE_ELLIPSE) { m_edgeTrans.setToTranslation(start.getX(), start.getY()); m_edgeTrans.rotate( -HALF_PI + Math.atan2(start.getY() - end.getY(), start.getX() - end.getX())); start.setLocation(0, -sourceBounds.getWidth() / 2.0D); m_edgeTrans.transform(start, start); } else if (GraphicsLib.intersectLineRectangle(start, end, sourceBounds, m_isctPoints) > 0) { start.setLocation(m_isctPoints[0]); } if (target.getShape() == Constants.SHAPE_ELLIPSE) { m_edgeTrans.setToTranslation(end.getX(), end.getY()); m_edgeTrans.rotate( -HALF_PI + Math.atan2(end.getY() - start.getY(), end.getX() - start.getX())); end.setLocation(0, -targetBounds.getWidth() / 2.0D); m_edgeTrans.transform(end, end); } else if (GraphicsLib.intersectLineRectangle(start, end, targetBounds, m_isctPoints) > 0) { end.setLocation(m_isctPoints[0]); } }
/** * Determines the control points to use for cubic (Bezier) curve edges. Override this method to * provide custom curve specifications. To reduce object initialization, the entries of the * Point2D array are already initialized, so use the <tt>Point2D.setLocation()</tt> method rather * than <tt>new Point2D.Double()</tt> to more efficiently set custom control points. * * @param eitem the EdgeItem we are determining the control points for * @param cp array of Point2D's (length >= 2) in which to return the control points * @param x1 the x co-ordinate of the first node this edge connects to * @param y1 the y co-ordinate of the first node this edge connects to * @param x2 the x co-ordinate of the second node this edge connects to * @param y2 the y co-ordinate of the second node this edge connects to */ protected void getCurveControlPoints( EdgeItem eitem, Point2D[] cp, double x1, double y1, double x2, double y2) { // double dx = x2 - x1, dy = y2 - y1; // cp[0].setLocation(x1 + 2 * dx / 3, y1); // cp[1].setLocation(x2 - dx / 8, y2 - dy / 8); double d = Point2D.distance(x1, y1, x2, y2); cp[0].setLocation(d / 10, -d / 2); // cp[0].setLocation(-d / 10, -d / 2); m_edgeTrans.setToTranslation(x2, y2); m_edgeTrans.rotate(-HALF_PI + Math.atan2(y2 - y1, x2 - x1)); m_edgeTrans.transform(cp[0], cp[0]); // cp[1].setLocation(x2, y2); }
/* Draws the ball at its current position */ public void draw(Graphics2D g) { double imageWidth = img.getWidth(parent); double imageHeight = img.getHeight(parent); // translate image such that its centred on its actual position objectTransform.setToTranslation( (double) pos_x - imageWidth / 2, (double) pos_y - imageHeight / 2); // // this rotates the planet! // objectTransform.rotate(Math.PI/800,50.0,51.0); g.setTransform(new AffineTransform()); g.drawImage(img, objectTransform, parent); }
protected int adjustEndingPointByMultipleEdge(EdgeItem e, Point2D start, Point2D end) { int edgeIndex = getEdgeIndex(e); if (edgeIndex < 0) { return edgeIndex; } m_edgeTrans.setToTranslation(end.getX(), end.getY()); m_edgeTrans.rotate(-HALF_PI + Math.atan2(end.getY() - start.getY(), end.getX() - start.getX())); if (edgeIndex % 2 == 1) { end.setLocation(4 + edgeIndex, 0); } else { end.setLocation(-4 - (edgeIndex - 1), 0); } m_edgeTrans.transform(end, end); return edgeIndex; }
protected void getCurveControlPoints( int edgeIndex, Point2D[] cp, double x1, double y1, double x2, double y2) { if (edgeIndex < 0) { // draw the line straight if we found one edge // cp[0].setLocation(x2, y2); // cp[1].setLocation(x1, y1); return; } double d = Point2D.distance(x1, y1, x2, y2); if (edgeIndex % 2 == 1) { cp[0].setLocation(d / 10 * edgeIndex, -d / 2); } else { cp[0].setLocation(-d / 10 * (edgeIndex - 1), -d / 2); } m_edgeTrans.setToTranslation(x2, y2); m_edgeTrans.rotate(-HALF_PI + Math.atan2(y2 - y1, x2 - x1)); m_edgeTrans.transform(cp[0], cp[0]); // cp[1].setLocation(x2, y2); }
public static void drawService(Graphics2D g2, int x, int y) { g2.setPaint(Color.BLACK); g2.setStroke(BPMNUtils.extraThinStroke); Path2D path = new Path2D.Double(); path.moveTo(-0.7, 5.0); path.lineTo(0.7, 5.0); path.lineTo(0.7, 3.6); path.lineTo(2.0, 3.0); path.lineTo(3.0, 4.0); path.lineTo(4.0, 3.0); path.lineTo(3.0, 2.0); path.lineTo(3.6, 0.7); path.lineTo(5.0, 0.7); path.lineTo(5.0, -0.7); path.lineTo(3.6, -0.7); path.lineTo(3.0, -2.0); path.lineTo(4.0, -3.0); path.lineTo(3.0, -4.0); path.lineTo(2.0, -3.0); path.lineTo(0.7, -3.6); path.lineTo(0.7, -5.0); path.lineTo(-0.7, -5.0); path.lineTo(-0.7, -3.6); path.lineTo(-2.0, -3.0); path.lineTo(-3.0, -4.0); path.lineTo(-4.0, -3.0); path.lineTo(-3.0, -2.0); path.lineTo(-3.6, -0.7); path.lineTo(-5.0, -0.7); path.lineTo(-5.0, 0.7); path.lineTo(-3.6, 0.7); path.lineTo(-3.0, 2.0); path.lineTo(-4.0, 3.0); path.lineTo(-3.0, 4.0); path.lineTo(-2.0, 3.0); path.lineTo(-0.7, 3.6); path.closePath(); // Tranform and scale to target AffineTransform at = new AffineTransform(); // Draw outer shape at.scale(Activity.STEREOTYPE_ICON_SIZE * 0.07, Activity.STEREOTYPE_ICON_SIZE * 0.07); Shape shape = at.createTransformedShape(path); at.setToTranslation(x, y); shape = at.createTransformedShape(shape); g2.setColor(Color.WHITE); g2.fill(shape); g2.setColor(Color.BLACK); g2.draw(shape); // Draw inner shape at = new AffineTransform(); at.scale(Activity.STEREOTYPE_ICON_SIZE * 0.035, Activity.STEREOTYPE_ICON_SIZE * 0.035); shape = at.createTransformedShape(path); at.setToTranslation(x, y); shape = at.createTransformedShape(shape); g2.setColor(Color.WHITE); g2.fill(shape); g2.setColor(Color.BLACK); g2.draw(shape); // Draw second outer shape at = new AffineTransform(); at.scale(Activity.STEREOTYPE_ICON_SIZE * 0.07, Activity.STEREOTYPE_ICON_SIZE * 0.07); shape = at.createTransformedShape(path); at.setToTranslation(x + STEREOTYPE_ICON_SIZE / 6, y + STEREOTYPE_ICON_SIZE / 6); shape = at.createTransformedShape(shape); g2.setColor(Color.WHITE); g2.fill(shape); g2.setColor(Color.BLACK); g2.draw(shape); // Draw second inner shape at = new AffineTransform(); at.scale(Activity.STEREOTYPE_ICON_SIZE * 0.035, Activity.STEREOTYPE_ICON_SIZE * 0.035); shape = at.createTransformedShape(path); at.setToTranslation(x + STEREOTYPE_ICON_SIZE / 6, y + STEREOTYPE_ICON_SIZE / 6); shape = at.createTransformedShape(shape); g2.setColor(Color.WHITE); g2.fill(shape); g2.setColor(Color.BLACK); g2.draw(shape); }
@Override public void draw(Graphics2D g2d, MapContent map, MapViewport viewport) { if (map != null && this.map == null) { this.map = map; } if (viewport == null) { viewport = map.getViewport(); // use the map viewport if one has not been provided } if (viewport == null || viewport.getScreenArea() == null) { return; // renderer is not set up for use yet } if (collection != null && signsdb == null) { signsdb = new Hashtable(); for (Iterator it1 = collection.iterator(); it1.hasNext(); ) { SimpleFeature feature = (SimpleFeature) it1.next(); StructOffset offset = new StructOffset(0, 0, -1); signsdb.put(feature, offset); } } // 消除线条锯齿 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); DefaultFeatureCollection collection = this.getCollection(); // 遍历得到每个SimpleFeature for (Iterator it1 = collection.iterator(); it1.hasNext(); ) { SimpleFeature feature = (SimpleFeature) it1.next(); String id = feature.getID(); DirectPosition2D geoCoords = null; DirectPosition2D signCoords = null; Point point = (Point) feature.getAttribute("the_geom"); if (point != null) { // 保存前一次刷新所处的位置 double x = point.getX(); double y = point.getY(); geoCoords = new DirectPosition2D(x, y); } // 经纬度坐标转换为屏幕坐标 MathTransform transform_math; try { transform_math = CRS.findMathTransform( DefaultGeographicCRS.WGS84, viewport.getCoordinateReferenceSystem(), true); transform_math.transform(geoCoords, geoCoords); AffineTransform transform_affine = viewport.getWorldToScreen(); transform_affine.transform(geoCoords, geoCoords); g2d.setColor(Color.CYAN); g2d.drawOval((int) geoCoords.x, (int) geoCoords.y, 10, 10); // 如果被选中,填充空心成实体 if (id.equals(selectedId)) g2d.fillOval((int) geoCoords.x, (int) geoCoords.y, 10, 10); if (signsdb.get(feature) != null) { StructOffset offset = (StructOffset) (signsdb.get(feature)); double offsetX = offset.getX(); double offsetY = offset.getY(); signCoords = new DirectPosition2D(geoCoords.x + offsetX, geoCoords.y + offsetY); } if (signCoords != null) { // 坐标默认偏移量<-25,-60> int width = 60, height = 40; g2d.setColor(Color.CYAN); g2d.drawLine( (int) geoCoords.x + 5, (int) geoCoords.y + 5, (int) signCoords.x + offsetX + width / 2, (int) signCoords.y + offsetY + height / 2); g2d.setColor(Color.BLACK); g2d.drawRect((int) signCoords.x + offsetX, (int) signCoords.y + offsetY, width, height); g2d.setColor(Color.ORANGE); g2d.fillRect((int) signCoords.x + offsetX, (int) signCoords.y + offsetY, width, height); g2d.setColor(Color.RED); String signsText = (String) feature.getAttribute("name"); g2d.drawString( signsText, (int) signCoords.x + offsetX + 2, (int) signCoords.y + offsetY + 12); } } catch (Exception e) { e.printStackTrace(); } } // 绘制指南针 // int x[] = {20,10,20,30}; // int y[] = {10,20,30,20}; // int nPoint = 4; // g2d.drawPolygon(x, y, nPoint); String APP_PATH = ""; Bundle bundle = Platform.getBundle("MapControl"); try { APP_PATH = FileLocator.resolve(bundle.getEntry("")).getPath().substring(1) + "icons/map/compass.png"; } catch (Exception e) { System.out.println(e.getMessage()); System.exit(1); } Image src = Toolkit.getDefaultToolkit().getImage(APP_PATH); double dx = 0.72, dy = 0.72; double x = 10, y = 10; // 指南针左上角 g2d.rotate( -MainMapViewPart.rotateAngle + (Math.PI / 360) * 40, x + dx * src.getWidth(null) / 2, y + dy * src.getHeight(null) / 2); AffineTransform affine = new AffineTransform(); affine.setToTranslation(x, y); affine.scale(dx, dy); // 缩放图片 g2d.drawImage(src, affine, null); }
/** * Formats a transformation matrix in millipoints with values as points. * * @param transform the transformation matrix in millipoints * @return the formatted matrix in points */ public static String formatAffineTransformMptToPt(AffineTransform transform) { AffineTransform scaled = new AffineTransform(transform); scaled.setToTranslation(transform.getTranslateX() / 1000, transform.getTranslateY() / 1000); return IFUtil.toString(scaled); }
public static void main(String args[]) { XComponent xDrawDoc = null; try { // get the remote office context of a running office (a new office // instance is started if necessary) com.sun.star.uno.XComponentContext xOfficeContext = Helper.connect(); // suppress Presentation Autopilot when opening the document // properties are the same as described for // com.sun.star.document.MediaDescriptor PropertyValue[] pPropValues = new PropertyValue[1]; pPropValues[0] = new PropertyValue(); pPropValues[0].Name = "Silent"; pPropValues[0].Value = Boolean.TRUE; xDrawDoc = Helper.createDocument( xOfficeContext, "private:factory/simpress", "_blank", 0, pPropValues); XDrawPage xPage = PageHelper.getDrawPageByIndex(xDrawDoc, 0); XPropertySet xPagePropSet = UnoRuntime.queryInterface(XPropertySet.class, xPage); XShapes xShapes = UnoRuntime.queryInterface(XShapes.class, xPage); XShape xShape = ShapeHelper.createShape( xDrawDoc, new Point(0, 0), new Size(10000, 2500), "com.sun.star.drawing.RectangleShape"); xShapes.add(xShape); XPropertySet xPropSet = UnoRuntime.queryInterface(XPropertySet.class, xShape); HomogenMatrix3 aHomogenMatrix3 = (HomogenMatrix3) xPropSet.getPropertyValue("Transformation"); java.awt.geom.AffineTransform aOriginalMatrix = new java.awt.geom.AffineTransform( aHomogenMatrix3.Line1.Column1, aHomogenMatrix3.Line2.Column1, aHomogenMatrix3.Line1.Column2, aHomogenMatrix3.Line2.Column2, aHomogenMatrix3.Line1.Column3, aHomogenMatrix3.Line2.Column3); AffineTransform aNewMatrix1 = new AffineTransform(); aNewMatrix1.setToRotation(Math.PI / 180 * 15); aNewMatrix1.concatenate(aOriginalMatrix); AffineTransform aNewMatrix2 = new AffineTransform(); aNewMatrix2.setToTranslation(2000, 2000); aNewMatrix2.concatenate(aNewMatrix1); double aFlatMatrix[] = new double[6]; aNewMatrix2.getMatrix(aFlatMatrix); aHomogenMatrix3.Line1.Column1 = aFlatMatrix[0]; aHomogenMatrix3.Line2.Column1 = aFlatMatrix[1]; aHomogenMatrix3.Line1.Column2 = aFlatMatrix[2]; aHomogenMatrix3.Line2.Column2 = aFlatMatrix[3]; aHomogenMatrix3.Line1.Column3 = aFlatMatrix[4]; aHomogenMatrix3.Line2.Column3 = aFlatMatrix[5]; xPropSet.setPropertyValue("Transformation", aHomogenMatrix3); } catch (Exception ex) { System.out.println(ex); } System.exit(0); }
// Triangulate glyph with 'unicode' if not already done. GeometryArrayRetained triangulateGlyphs(GlyphVector gv, char c) { Character ch = new Character(c); GeometryArrayRetained geo = 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; // Compute islandCounts[][] and outVerts[][] UnorderList islandsList = new UnorderList(10, IslandsNode.class); islandsTree.collectOddLevelNode(islandsList, 0); IslandsNode nodes[] = (IslandsNode[]) islandsList.toArray(false); int islandCounts[][] = new int[islandsList.arraySize()][]; Point3f outVerts[][] = new Point3f[islandCounts.length][]; int nchild, sum; IslandsNode node; for (i = 0; i < islandCounts.length; i++) { node = nodes[i]; nchild = node.numChild(); islandCounts[i] = new int[nchild + 1]; islandCounts[i][0] = node.numVertices(); sum = 0; sum += islandCounts[i][0]; for (j = 0; j < nchild; j++) { islandCounts[i][j + 1] = node.getChild(j).numVertices(); sum += islandCounts[i][j + 1]; } outVerts[i] = new Point3f[sum]; startIdx = 0; for (k = node.startIdx; k < node.endIdx; k++) { outVerts[i][startIdx++] = vertices[k]; } for (j = 0; j < nchild; j++) { endIdx = node.getChild(j).endIdx; for (k = node.getChild(j).startIdx; k < endIdx; k++) { outVerts[i][startIdx++] = vertices[k]; } } } islandsTree = null; // Free memory islandsList = null; vertices = null; contourCounts = new int[1]; int currCoordIndex = 0, vertOffset = 0; ArrayList<GeometryArray> triangData = new ArrayList<GeometryArray>(); Point3f q1 = new Point3f(), q2 = new Point3f(), q3 = new Point3f(); Vector3f n1 = new Vector3f(), n2 = new Vector3f(); numPoints = 0; // Now loop thru each island, calling triangulator once per island. // Combine triangle data for all islands together in one object. for (i = 0; i < islandCounts.length; i++) { contourCounts[0] = islandCounts[i].length; numPoints += outVerts[i].length; gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY); gi.setCoordinates(outVerts[i]); gi.setStripCounts(islandCounts[i]); gi.setContourCounts(contourCounts); ng.generateNormals(gi); GeometryArray ga = gi.getGeometryArray(false, false, false); vertOffset += ga.getVertexCount(); triangData.add(ga); } // Multiply by 2 since we create 2 faces of the font // Second term is for side-faces along depth of the font if (fontExtrusion == null) vertCnt = vertOffset; else { if (fontExtrusion.shape == null) vertCnt = vertOffset * 2 + numPoints * 6; else { vertCnt = vertOffset * 2 + numPoints * 6 * (fontExtrusion.pnts.length - 1); } } // XXXX: Should use IndexedTriangleArray to avoid // duplication of vertices. To create triangles for // side faces, every vertex is duplicated currently. TriangleArray triAry = new TriangleArray(vertCnt, GeometryArray.COORDINATES | GeometryArray.NORMALS); boolean flip_orient[] = new boolean[islandCounts.length]; boolean findOrient; // last known non-degenerate normal Vector3f goodNormal = new Vector3f(); for (j = 0; j < islandCounts.length; j++) { GeometryArray ga = triangData.get(j); vertOffset = ga.getVertexCount(); findOrient = false; // Create the triangle array for (i = 0; i < vertOffset; i += 3, currCoordIndex += 3) { // Get 3 points. Since triangle is known to be flat, normal // must be same for all 3 points. ga.getCoordinate(i, p1); ga.getNormal(i, n1); ga.getCoordinate(i + 1, p2); ga.getCoordinate(i + 2, p3); if (!findOrient) { // Check here if triangles are wound incorrectly and need // to be flipped. if (!getNormal(p1, p2, p3, n2)) { continue; } if (n2.z >= EPS) { flip_orient[j] = false; } else if (n2.z <= -EPS) { flip_orient[j] = true; } else { continue; } findOrient = true; } if (flip_orient[j]) { // New Triangulator preserves contour orientation. If contour // input is wound incorrectly, swap 2nd and 3rd points to // sure all triangles are wound correctly for j3d. q1.x = p2.x; q1.y = p2.y; q1.z = p2.z; p2.x = p3.x; p2.y = p3.y; p2.z = p3.z; p3.x = q1.x; p3.y = q1.y; p3.z = q1.z; n1.x = -n1.x; n1.y = -n1.y; n1.z = -n1.z; } if (fontExtrusion != null) { n2.x = -n1.x; n2.y = -n1.y; n2.z = -n1.z; triAry.setCoordinate(currCoordIndex, p1); triAry.setNormal(currCoordIndex, n2); triAry.setCoordinate(currCoordIndex + 1, p3); triAry.setNormal(currCoordIndex + 1, n2); triAry.setCoordinate(currCoordIndex + 2, p2); triAry.setNormal(currCoordIndex + 2, n2); q1.x = p1.x; q1.y = p1.y; q1.z = p1.z + fontExtrusion.length; q2.x = p2.x; q2.y = p2.y; q2.z = p2.z + fontExtrusion.length; q3.x = p3.x; q3.y = p3.y; q3.z = p3.z + fontExtrusion.length; triAry.setCoordinate(currCoordIndex + vertOffset, q1); triAry.setNormal(currCoordIndex + vertOffset, n1); triAry.setCoordinate(currCoordIndex + 1 + vertOffset, q2); triAry.setNormal(currCoordIndex + 1 + vertOffset, n1); triAry.setCoordinate(currCoordIndex + 2 + vertOffset, q3); triAry.setNormal(currCoordIndex + 2 + vertOffset, n1); } else { triAry.setCoordinate(currCoordIndex, p1); triAry.setNormal(currCoordIndex, n1); triAry.setCoordinate(currCoordIndex + 1, p2); triAry.setNormal(currCoordIndex + 1, n1); triAry.setCoordinate(currCoordIndex + 2, p3); triAry.setNormal(currCoordIndex + 2, n1); } } if (fontExtrusion != null) { currCoordIndex += vertOffset; } } // Now add side triangles in both cases. // Since we duplicated triangles with different Z, make sure // currCoordIndex points to correct location. if (fontExtrusion != null) { if (fontExtrusion.shape == null) { boolean smooth; // we'll put a crease if the angle between the normals is // greater than 44 degrees float threshold = (float) Math.cos(44.0 * Math.PI / 180.0); float cosine; // need the previous normals to check for smoothing Vector3f pn1 = null, pn2 = null; // need the next normals to check for smoothing Vector3f n3 = new Vector3f(), n4 = new Vector3f(); // store the normals for each point because they are // the same for both triangles Vector3f p1Normal = new Vector3f(); Vector3f p2Normal = new Vector3f(); Vector3f p3Normal = new Vector3f(); Vector3f q1Normal = new Vector3f(); Vector3f q2Normal = new Vector3f(); Vector3f q3Normal = new Vector3f(); for (i = 0; i < islandCounts.length; i++) { for (j = 0, k = 0, num = 0; j < islandCounts[i].length; j++) { num += islandCounts[i][j]; p1.x = outVerts[i][num - 1].x; p1.y = outVerts[i][num - 1].y; p1.z = 0.0f; q1.x = p1.x; q1.y = p1.y; q1.z = p1.z + fontExtrusion.length; p2.z = 0.0f; q2.z = p2.z + fontExtrusion.length; for (int m = 0; m < num; m++) { p2.x = outVerts[i][m].x; p2.y = outVerts[i][m].y; q2.x = p2.x; q2.y = p2.y; if (getNormal(p1, q1, p2, n1)) { if (!flip_side_orient) { n1.negate(); } goodNormal.set(n1); break; } } for (; k < num; k++) { p2.x = outVerts[i][k].x; p2.y = outVerts[i][k].y; p2.z = 0.0f; q2.x = p2.x; q2.y = p2.y; q2.z = p2.z + fontExtrusion.length; if (!getNormal(p1, q1, p2, n1)) { n1.set(goodNormal); } else { if (!flip_side_orient) { n1.negate(); } goodNormal.set(n1); } if (!getNormal(p2, q1, q2, n2)) { n2.set(goodNormal); } else { if (!flip_side_orient) { n2.negate(); } goodNormal.set(n2); } // if there is a previous normal, see if we need to smooth // this normal or make a crease if (pn1 != null) { cosine = n1.dot(pn2); smooth = cosine > threshold; if (smooth) { p1Normal.x = (pn1.x + pn2.x + n1.x); p1Normal.y = (pn1.y + pn2.y + n1.y); p1Normal.z = (pn1.z + pn2.z + n1.z); normalize(p1Normal); q1Normal.x = (pn2.x + n1.x + n2.x); q1Normal.y = (pn2.y + n1.y + n2.y); q1Normal.z = (pn2.z + n1.z + n2.z); normalize(q1Normal); } // if smooth else { p1Normal.x = n1.x; p1Normal.y = n1.y; p1Normal.z = n1.z; q1Normal.x = n1.x + n2.x; q1Normal.y = n1.y + n2.y; q1Normal.z = n1.z + n2.z; normalize(q1Normal); } // else } // if pn1 != null else { pn1 = new Vector3f(); pn2 = new Vector3f(); p1Normal.x = n1.x; p1Normal.y = n1.y; p1Normal.z = n1.z; q1Normal.x = (n1.x + n2.x); q1Normal.y = (n1.y + n2.y); q1Normal.z = (n1.z + n2.z); normalize(q1Normal); } // else // if there is a next, check if we should smooth normal if (k + 1 < num) { p3.x = outVerts[i][k + 1].x; p3.y = outVerts[i][k + 1].y; p3.z = 0.0f; q3.x = p3.x; q3.y = p3.y; q3.z = p3.z + fontExtrusion.length; if (!getNormal(p2, q2, p3, n3)) { n3.set(goodNormal); } else { if (!flip_side_orient) { n3.negate(); } goodNormal.set(n3); } if (!getNormal(p3, q2, q3, n4)) { n4.set(goodNormal); } else { if (!flip_side_orient) { n4.negate(); } goodNormal.set(n4); } cosine = n2.dot(n3); smooth = cosine > threshold; if (smooth) { p2Normal.x = (n1.x + n2.x + n3.x); p2Normal.y = (n1.y + n2.y + n3.y); p2Normal.z = (n1.z + n2.z + n3.z); normalize(p2Normal); q2Normal.x = (n2.x + n3.x + n4.x); q2Normal.y = (n2.y + n3.y + n4.y); q2Normal.z = (n2.z + n3.z + n4.z); normalize(q2Normal); } else { // if smooth p2Normal.x = n1.x + n2.x; p2Normal.y = n1.y + n2.y; p2Normal.z = n1.z + n2.z; normalize(p2Normal); q2Normal.x = n2.x; q2Normal.y = n2.y; q2Normal.z = n2.z; } // else } else { // if k+1 < num p2Normal.x = (n1.x + n2.x); p2Normal.y = (n1.y + n2.y); p2Normal.z = (n1.z + n2.z); normalize(p2Normal); q2Normal.x = n2.x; q2Normal.y = n2.y; q2Normal.z = n2.z; } // else // add pts for the 2 tris // p1, q1, p2 and p2, q1, q2 if (flip_side_orient) { triAry.setCoordinate(currCoordIndex, p1); triAry.setNormal(currCoordIndex, p1Normal); currCoordIndex++; triAry.setCoordinate(currCoordIndex, q1); triAry.setNormal(currCoordIndex, q1Normal); currCoordIndex++; triAry.setCoordinate(currCoordIndex, p2); triAry.setNormal(currCoordIndex, p2Normal); currCoordIndex++; triAry.setCoordinate(currCoordIndex, p2); triAry.setNormal(currCoordIndex, p2Normal); currCoordIndex++; triAry.setCoordinate(currCoordIndex, q1); triAry.setNormal(currCoordIndex, q1Normal); currCoordIndex++; } else { triAry.setCoordinate(currCoordIndex, q1); triAry.setNormal(currCoordIndex, q1Normal); currCoordIndex++; triAry.setCoordinate(currCoordIndex, p1); triAry.setNormal(currCoordIndex, p1Normal); currCoordIndex++; triAry.setCoordinate(currCoordIndex, p2); triAry.setNormal(currCoordIndex, p2Normal); currCoordIndex++; triAry.setCoordinate(currCoordIndex, q1); triAry.setNormal(currCoordIndex, q1Normal); currCoordIndex++; triAry.setCoordinate(currCoordIndex, p2); triAry.setNormal(currCoordIndex, p2Normal); currCoordIndex++; } triAry.setCoordinate(currCoordIndex, q2); triAry.setNormal(currCoordIndex, q2Normal); currCoordIndex++; pn1.x = n1.x; pn1.y = n1.y; pn1.z = n1.z; pn2.x = n2.x; pn2.y = n2.y; pn2.z = n2.z; p1.x = p2.x; p1.y = p2.y; p1.z = p2.z; q1.x = q2.x; q1.y = q2.y; q1.z = q2.z; } // for k // set the previous normals to null when we are done pn1 = null; pn2 = null; } // for j } // for i } else { // if shape int m, offset = 0; Point3f P2 = new Point3f(), Q2 = new Point3f(), P1 = new Point3f(); Vector3f nn = new Vector3f(), nn1 = new Vector3f(), nn2 = new Vector3f(), nn3 = new Vector3f(); Vector3f nna = new Vector3f(), nnb = new Vector3f(); float length; boolean validNormal = false; // fontExtrusion.shape is specified, and is NOT straight line for (i = 0; i < islandCounts.length; i++) { for (j = 0, k = 0, offset = num = 0; j < islandCounts[i].length; j++) { num += islandCounts[i][j]; p1.x = outVerts[i][num - 1].x; p1.y = outVerts[i][num - 1].y; p1.z = 0.0f; q1.x = p1.x; q1.y = p1.y; q1.z = p1.z + fontExtrusion.length; p3.z = 0.0f; for (m = num - 2; m >= 0; m--) { p3.x = outVerts[i][m].x; p3.y = outVerts[i][m].y; if (getNormal(p3, q1, p1, nn1)) { if (!flip_side_orient) { nn1.negate(); } goodNormal.set(nn1); break; } } for (; k < num; k++) { p2.x = outVerts[i][k].x; p2.y = outVerts[i][k].y; p2.z = 0.0f; q2.x = p2.x; q2.y = p2.y; q2.z = p2.z + fontExtrusion.length; getNormal(p1, q1, p2, nn2); p3.x = outVerts[i][(k + 1) == num ? offset : (k + 1)].x; p3.y = outVerts[i][(k + 1) == num ? offset : (k + 1)].y; p3.z = 0.0f; if (!getNormal(p3, p2, q2, nn3)) { nn3.set(goodNormal); } else { if (!flip_side_orient) { nn3.negate(); } goodNormal.set(nn3); } // Calculate normals at the point by averaging normals // of two faces on each side of the point. nna.x = (nn1.x + nn2.x); nna.y = (nn1.y + nn2.y); nna.z = (nn1.z + nn2.z); normalize(nna); nnb.x = (nn3.x + nn2.x); nnb.y = (nn3.y + nn2.y); nnb.z = (nn3.z + nn2.z); normalize(nnb); P1.x = p1.x; P1.y = p1.y; P1.z = p1.z; P2.x = p2.x; P2.y = p2.y; P2.z = p2.z; Q2.x = q2.x; Q2.y = q2.y; Q2.z = q2.z; for (m = 1; m < fontExtrusion.pnts.length; m++) { q1.z = q2.z = fontExtrusion.pnts[m].x; q1.x = P1.x + nna.x * fontExtrusion.pnts[m].y; q1.y = P1.y + nna.y * fontExtrusion.pnts[m].y; q2.x = P2.x + nnb.x * fontExtrusion.pnts[m].y; q2.y = P2.y + nnb.y * fontExtrusion.pnts[m].y; if (!getNormal(p1, q1, p2, n1)) { n1.set(goodNormal); } else { if (!flip_side_orient) { n1.negate(); } goodNormal.set(n1); } if (flip_side_orient) { triAry.setCoordinate(currCoordIndex, p1); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; triAry.setCoordinate(currCoordIndex, q1); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; } else { triAry.setCoordinate(currCoordIndex, q1); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; triAry.setCoordinate(currCoordIndex, p1); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; } triAry.setCoordinate(currCoordIndex, p2); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; if (!getNormal(p2, q1, q2, n1)) { n1.set(goodNormal); } else { if (!flip_side_orient) { n1.negate(); } goodNormal.set(n1); } if (flip_side_orient) { triAry.setCoordinate(currCoordIndex, p2); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; triAry.setCoordinate(currCoordIndex, q1); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; } else { triAry.setCoordinate(currCoordIndex, q1); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; triAry.setCoordinate(currCoordIndex, p2); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; } triAry.setCoordinate(currCoordIndex, q2); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; p1.x = q1.x; p1.y = q1.y; p1.z = q1.z; p2.x = q2.x; p2.y = q2.y; p2.z = q2.z; } // for m p1.x = P2.x; p1.y = P2.y; p1.z = P2.z; q1.x = Q2.x; q1.y = Q2.y; q1.z = Q2.z; nn1.x = nn2.x; nn1.y = nn2.y; nn1.z = nn2.z; } // for k offset = num; } // for j } // for i } // if shape } // if fontExtrusion geo = (GeometryArrayRetained) triAry.retained; geomHash.put(ch, geo); } return geo; }