/******************************************************************************* * Copyright (c) 2007, 2011 Association for Decentralized Information Management in * Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.g2d.utils; import java.awt.BasicStroke; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.font.LineMetrics; import java.awt.geom.Line2D; import java.text.Format; import org.simantics.scenegraph.utils.GridUtils; public class GridUtil { public static final BasicStroke GRID_LINE_STROKE; public static final BasicStroke RULER_LINE_STROKE; public static final Font RULER_FONT; public static final Font RULER_FONT_BOLD; public static final FontRenderContext frc = new FontRenderContext(null, true, true); static { RULER_LINE_STROKE = new BasicStroke(1.0f, BasicStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE, 10.0f, null, 0.0f); GRID_LINE_STROKE = new BasicStroke(1.0f, BasicStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE, 10.0f, null, 0.0f); RULER_FONT = new Font("Tahoma", Font.PLAIN, 12); RULER_FONT_BOLD = new Font("Tahoma", Font.BOLD, 12); } public GridUtil() { } public static void paintGridLines( GridSpacing xgrid, GridSpacing ygrid, Graphics2D g, double xMin, double yMax, double controlWidth, double controlHeightForVerticalLines, double controlHeightForHorizLines) { g.setStroke(GRID_LINE_STROKE); Line2D line = new Line2D.Double(); if (xgrid != null) { // Vertical lines double controlX = GridUtils.distanceToNextGridCoordScaled(xMin, xgrid.segment, xgrid.pixelsPerUnit); while (controlX <= controlWidth+0.1) { line.setLine(controlX, 0, controlX, (int) (controlHeightForVerticalLines - 1)); g.draw(line); controlX += xgrid.pixelsPerSegment; } } // Horizontal lines if (ygrid != null) { double canvasDiff = GridUtils.distanceToNextGridCoord(yMax, ygrid.segment); double controlY = controlHeightForHorizLines - canvasDiff * ygrid.pixelsPerUnit; while (controlY >= -0.1) { line.setLine(0, controlY, (int) (controlWidth - 1), controlY); g.draw(line); controlY -= ygrid.pixelsPerSegment; } } } public static void paintHorizontalRuler( GridSpacing grid, Graphics2D g, double xMin, double controlWidth, Format labelFormat) { g.setStroke(RULER_LINE_STROKE); // Draw ticks double canvasDiff = GridUtils.distanceToNextGridCoord(xMin, grid.segment); double canvasX = xMin + canvasDiff; double controlX = canvasDiff * grid.pixelsPerUnit; Line2D line = new Line2D.Double(); line.setLine(0, 3, controlWidth, 3); g.draw(line); while (controlX <= controlWidth + 0.1) { line.setLine(controlX, 3, controlX, 8); g.draw(line); controlX += grid.pixelsPerSegment; } // Labels Font font = RULER_FONT; g.setFont(RULER_FONT); FontMetrics fm = g.getFontMetrics(font); canvasDiff = GridUtils.distanceToNextGridCoord(xMin, grid.segment); double canvasStart = canvasX = xMin + canvasDiff; controlX = canvasDiff * grid.pixelsPerUnit; int i = 0; while (controlX <= controlWidth + 0.1) { String value = labelFormat.format( canvasX ); double labelCenter = fm.getStringBounds(value, g).getCenterX(); g.drawString(value, (float) (controlX-labelCenter), (float) 20); controlX += grid.pixelsPerSegment; canvasX = canvasStart + grid.segment * (++i); } } public static void paintVerticalRuler( GridSpacing grid, Graphics2D g, double yMin, double controlHeight, Format labelFormat) { g.setStroke(RULER_LINE_STROKE); // Draw ticks double canvasDiff = GridUtils.distanceToNextGridCoord(yMin+grid.segment, grid.segment); double controlY = controlHeight - canvasDiff * grid.pixelsPerUnit; Line2D line = new Line2D.Double(); line.setLine(3, 0, 3, controlHeight); g.draw(line); while (controlY >= -0.1) { line.setLine(3, controlY, 8, controlY); g.draw( line ); controlY -= grid.pixelsPerSegment; } // Labels g.setFont(RULER_FONT); FontMetrics fm = g.getFontMetrics(RULER_FONT); canvasDiff = GridUtils.distanceToNextGridCoord(yMin, grid.segment); double canvasY = yMin + canvasDiff; double canvasStart = canvasY; controlY = controlHeight - canvasDiff * grid.pixelsPerUnit; int i=0; while (controlY >= -0.1) { String value = labelFormat.format( canvasY ); LineMetrics lm = fm.getLineMetrics(value, g); g.drawString(value, (float) 13, (float) (controlY+lm.getAscent()/2)-1); controlY -= grid.pixelsPerSegment; canvasY = canvasStart + grid.segment * (++i); } } public static void paintVerticalSlaveRuler( GridSpacing masterGrid, GridSpacing slaveGrid, Graphics2D g, double yMinMaster, double yMinSlave, double controlHeight, Format labelFormat) { g.setStroke(RULER_LINE_STROKE); // Draw ticks double canvasDiff = GridUtils.distanceToNextGridCoord(yMinMaster+masterGrid.segment, masterGrid.segment); double controlDiff = canvasDiff * masterGrid.pixelsPerUnit; double startY = controlHeight - controlDiff; double controlY = startY; Line2D line = new Line2D.Double(); line.setLine(3, 0, 3, controlHeight); g.draw(line); while (controlY >= -0.1) { line.setLine(3, controlY, 8, controlY); g.draw( line ); controlY -= masterGrid.pixelsPerSegment; } // Labels g.setFont(RULER_FONT); FontMetrics fm = g.getFontMetrics(RULER_FONT); canvasDiff = GridUtils.distanceToNextGridCoord(yMinMaster, masterGrid.segment); double masterY = yMinMaster + canvasDiff; double canvasStart = masterY; controlY = controlHeight - canvasDiff * masterGrid.pixelsPerUnit; // double slaveGridSegment = masterGrid.pixelsPerSegment * slaveGrid.unitsPerPixel; int i=0; while (controlY >= -0.1) { // System.out.println("controlY="+controlY+", canvasY="+masterY); // Convert value from master coordinates to slave double slaveY = (masterY - yMinMaster) * masterGrid.pixelsPerUnit * slaveGrid.unitsPerPixel + yMinSlave; if (Math.abs(slaveY) < 1e-5) slaveY=0.0; String value = labelFormat.format( slaveY ); LineMetrics lm = fm.getLineMetrics(value, g); g.drawString(value, (float) 13, (float) (controlY+lm.getAscent()/2)-1); controlY -= masterGrid.pixelsPerSegment; masterY = canvasStart + masterGrid.segment * (++i); } } public static int getTickCount(GridSpacing grid, double yMin, double controlHeight) { double canvasDiff = GridUtils.distanceToNextGridCoord(yMin+grid.segment, grid.segment); double startY = controlHeight - canvasDiff * grid.pixelsPerUnit; double x = startY / grid.pixelsPerSegment; return (int) Math.ceil( x ); } /** * Estimate label width, by sampling values from xMin to xMax * using given font and format. * * @param xMin * @param xMax * @param format * @return */ public static double calcLabelWidth(double xMin, double xMax, Format format, GridSpacing grid) { double width = 0.0; double canvasDiff = GridUtils.distanceToNextGridCoord(xMin, grid.segment); int c = 0; double canvasStart = xMin + canvasDiff; for (double x=canvasStart; x -0.000000000001); // if (nearZero) x = 0.0; String label = format.format(x); if (label==null || label.equals("")) continue; GlyphVector glyphVector; glyphVector = RULER_FONT.createGlyphVector(frc, label); double labelWidth = glyphVector.getVisualBounds().getWidth(); //System.out.format("calcLabelWidth[%d](%s, %f, %f)%n", c, label, labelWidth, width); width = Math.max( width, labelWidth ); if (c++ > 100) break; // It is floating-point-wise more precise to calculate x like this than // accumulating x += grid.segment. // Also, this is how paintVerticalRuler does it and we want to match that // in order to calculate the label width from the exact same values that // paintVerticalRuler will draw. x = canvasStart + grid.segment * c; } return width * 1.05; } }