1 /*******************************************************************************
2 * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.g2d.utils;
14 import java.awt.BasicStroke;
16 import java.awt.FontMetrics;
17 import java.awt.Graphics2D;
18 import java.awt.font.FontRenderContext;
19 import java.awt.font.GlyphVector;
20 import java.awt.font.LineMetrics;
21 import java.awt.geom.Line2D;
22 import java.text.Format;
24 import org.simantics.scenegraph.utils.GridUtils;
26 public class GridUtil {
28 public static final BasicStroke GRID_LINE_STROKE;
29 public static final BasicStroke RULER_LINE_STROKE;
30 public static final Font RULER_FONT;
31 public static final Font RULER_FONT_BOLD;
32 public static final FontRenderContext frc = new FontRenderContext(null, true, true);
35 RULER_LINE_STROKE = new BasicStroke(1.0f, BasicStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE, 10.0f, null, 0.0f);
36 GRID_LINE_STROKE = new BasicStroke(1.0f, BasicStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE, 10.0f, null, 0.0f);
37 RULER_FONT = new Font("Tahoma", Font.PLAIN, 12);
38 RULER_FONT_BOLD = new Font("Tahoma", Font.BOLD, 12);
44 public static void paintGridLines(
45 GridSpacing xgrid, GridSpacing ygrid,
47 double xMin, double yMax,
49 double controlHeightForVerticalLines,
50 double controlHeightForHorizLines) {
52 g.setStroke(GRID_LINE_STROKE);
53 Line2D line = new Line2D.Double();
57 double controlX = GridUtils.distanceToNextGridCoordScaled(xMin, xgrid.segment, xgrid.pixelsPerUnit);
59 while (controlX <= controlWidth+0.1) {
60 line.setLine(controlX, 0, controlX, (int) (controlHeightForVerticalLines - 1));
62 controlX += xgrid.pixelsPerSegment;
68 double canvasDiff = GridUtils.distanceToNextGridCoord(yMax, ygrid.segment);
69 double controlY = controlHeightForHorizLines - canvasDiff * ygrid.pixelsPerUnit;
71 while (controlY >= -0.1) {
72 line.setLine(0, controlY, (int) (controlWidth - 1), controlY);
74 controlY -= ygrid.pixelsPerSegment;
79 public static void paintHorizontalRuler(
85 g.setStroke(RULER_LINE_STROKE);
88 double canvasDiff = GridUtils.distanceToNextGridCoord(xMin, grid.segment);
89 double canvasX = xMin + canvasDiff;
90 double controlX = canvasDiff * grid.pixelsPerUnit;
91 Line2D line = new Line2D.Double();
92 line.setLine(0, 3, controlWidth, 3);
95 while (controlX <= controlWidth + 0.1) {
96 line.setLine(controlX, 3, controlX, 8);
98 controlX += grid.pixelsPerSegment;
102 Font font = RULER_FONT;
103 g.setFont(RULER_FONT);
104 FontMetrics fm = g.getFontMetrics(font);
106 canvasDiff = GridUtils.distanceToNextGridCoord(xMin, grid.segment);
107 double canvasStart = canvasX = xMin + canvasDiff;
108 controlX = canvasDiff * grid.pixelsPerUnit;
111 while (controlX <= controlWidth + 0.1) {
112 String value = labelFormat.format( canvasX );
113 double labelCenter = fm.getStringBounds(value, g).getCenterX();
114 g.drawString(value, (float) (controlX-labelCenter), (float) 20);
115 controlX += grid.pixelsPerSegment;
116 canvasX = canvasStart + grid.segment * (++i);
121 public static void paintVerticalRuler(
125 double controlHeight,
126 Format labelFormat) {
128 g.setStroke(RULER_LINE_STROKE);
131 double canvasDiff = GridUtils.distanceToNextGridCoord(yMin+grid.segment, grid.segment);
132 double controlY = controlHeight - canvasDiff * grid.pixelsPerUnit;
133 Line2D line = new Line2D.Double();
134 line.setLine(3, 0, 3, controlHeight);
137 while (controlY >= -0.1) {
138 line.setLine(3, controlY, 8, controlY);
140 controlY -= grid.pixelsPerSegment;
144 g.setFont(RULER_FONT);
145 FontMetrics fm = g.getFontMetrics(RULER_FONT);
146 canvasDiff = GridUtils.distanceToNextGridCoord(yMin, grid.segment);
147 double canvasY = yMin + canvasDiff;
148 double canvasStart = canvasY;
149 controlY = controlHeight - canvasDiff * grid.pixelsPerUnit;
151 while (controlY >= -0.1) {
152 String value = labelFormat.format( canvasY );
153 LineMetrics lm = fm.getLineMetrics(value, g);
155 g.drawString(value, (float) 13, (float) (controlY+lm.getAscent()/2)-1);
156 controlY -= grid.pixelsPerSegment;
157 canvasY = canvasStart + grid.segment * (++i);
161 public static void paintVerticalSlaveRuler(
162 GridSpacing masterGrid,
163 GridSpacing slaveGrid,
165 double yMinMaster, double yMinSlave,
166 double controlHeight,
167 Format labelFormat) {
169 g.setStroke(RULER_LINE_STROKE);
172 double canvasDiff = GridUtils.distanceToNextGridCoord(yMinMaster+masterGrid.segment, masterGrid.segment);
173 double controlDiff = canvasDiff * masterGrid.pixelsPerUnit;
174 double startY = controlHeight - controlDiff;
175 double controlY = startY;
176 Line2D line = new Line2D.Double();
177 line.setLine(3, 0, 3, controlHeight);
180 while (controlY >= -0.1) {
181 line.setLine(3, controlY, 8, controlY);
183 controlY -= masterGrid.pixelsPerSegment;
187 g.setFont(RULER_FONT);
188 FontMetrics fm = g.getFontMetrics(RULER_FONT);
189 canvasDiff = GridUtils.distanceToNextGridCoord(yMinMaster, masterGrid.segment);
190 double masterY = yMinMaster + canvasDiff;
191 double canvasStart = masterY;
192 controlY = controlHeight - canvasDiff * masterGrid.pixelsPerUnit;
193 // double slaveGridSegment = masterGrid.pixelsPerSegment * slaveGrid.unitsPerPixel;
195 while (controlY >= -0.1) {
196 // System.out.println("controlY="+controlY+", canvasY="+masterY);
197 // Convert value from master coordinates to slave
198 double slaveY = (masterY - yMinMaster) * masterGrid.pixelsPerUnit * slaveGrid.unitsPerPixel + yMinSlave;
199 if (Math.abs(slaveY) < 1e-5) slaveY=0.0;
200 String value = labelFormat.format( slaveY );
201 LineMetrics lm = fm.getLineMetrics(value, g);
203 g.drawString(value, (float) 13, (float) (controlY+lm.getAscent()/2)-1);
204 controlY -= masterGrid.pixelsPerSegment;
205 masterY = canvasStart + masterGrid.segment * (++i);
209 public static int getTickCount(GridSpacing grid, double yMin, double controlHeight)
211 double canvasDiff = GridUtils.distanceToNextGridCoord(yMin+grid.segment, grid.segment);
212 double startY = controlHeight - canvasDiff * grid.pixelsPerUnit;
213 double x = startY / grid.pixelsPerSegment;
214 return (int) Math.ceil( x );
218 * Estimate label width, by sampling values from xMin to xMax
219 * using given font and format.
226 public static double calcLabelWidth(double xMin, double xMax, Format format, GridSpacing grid)
229 double canvasDiff = GridUtils.distanceToNextGridCoord(xMin, grid.segment);
231 double canvasStart = xMin + canvasDiff;
232 for (double x=canvasStart; x<xMax; ) {
233 // This nearZero-logic causes a discrepancy between how the labels
234 // are rendered in paintVerticalRuler() and calculated in this method.
235 // Removing it doesn't seem to be causing any immediate adverse effects.
236 // However, this was introduced ages ago to "fix a glitch" so some kind
237 // of regressions might happen if rmeoved.
238 // boolean nearZero = (x < 0.000000000001) && (x > -0.000000000001);
239 // if (nearZero) x = 0.0;
241 String label = format.format(x);
242 if (label==null || label.equals("")) continue;
243 GlyphVector glyphVector;
244 glyphVector = RULER_FONT.createGlyphVector(frc, label);
245 double labelWidth = glyphVector.getVisualBounds().getWidth();
246 //System.out.format("calcLabelWidth[%d](%s, %f, %f)%n", c, label, labelWidth, width);
247 width = Math.max( width, labelWidth );
248 if (c++ > 100) break;
250 // It is floating-point-wise more precise to calculate x like this than
251 // accumulating x += grid.segment.
252 // Also, this is how paintVerticalRuler does it and we want to match that
253 // in order to calculate the label width from the exact same values that
254 // paintVerticalRuler will draw.
255 x = canvasStart + grid.segment * c;