/******************************************************************************* * Copyright (c) 2007, 2010 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.scenegraph.utils; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.util.Arrays; /** * A set of utilities for calculating even spacings. Useful for grid/rules * spacing calculations. * * @author Tuukka Lehtonen * @author Marko Luukkainen (original) */ public final class GridUtils { private static double gridLineEvenSpacings[] = new double[] { 1.0, 2.0, 5.0, 10.0 }; /** * Returns next even grid spacing for value. * * @param value to round to nearest even grid spacing * @param gridSize the base grid size that will multiply the even spacings * returned by this method * @param lessThan true to select the nearest even spacing <= * value or false to select the nearest even spacing >= * value * @return the calculated nearest even grid spacing */ public static double getEvenGridSpacing(double value, double gridSize, boolean lessThan) { double exp = Math.floor(Math.log10(value)); double gs = Math.pow(10.0, exp) * gridSize; // System.out.println("getEvenGridSpacing(" + value + ", " + gridSize + ", " + lessThan + "): " + exp + ", " + gs); int i = lessThan ? 1 : 0; int max = lessThan ? gridLineEvenSpacings.length : gridLineEvenSpacings.length - 1; while (i < max) { // System.out.println("COMPARE(" + gridLineEvenSpacings[i] + "): " + gridLineEvenSpacings[i]*gs + " >= " + value); if (gridLineEvenSpacings[i] * gs >= value) { if (lessThan) --i; break; } i++; } // FIXME: this is a workaround to keep the next line from causing an NPE // Need to check the calculations and make some sense into this code once // again to be sure. if (i >= gridLineEvenSpacings.length) return 2 * gridLineEvenSpacings[gridLineEvenSpacings.length - 1] * gs; return gridLineEvenSpacings[i] * gs; } /** * Returns next even grid spacing for value with the assumed grid size of * 1.0. * * @param value to round to nearest even grid spacing * @param lessThan true to select the nearest even spacing <= * value or false to select the nearest even spacing >= * value * @return the calculated nearest even grid spacing */ public static double getEvenGridSpacing(double value, boolean lessThan) { return getEvenGridSpacing(value, 1.0, lessThan); } /** * Returns next even number for value and exponent of the value. * * @param value in units * @param array of at least two elements where the results will be put * @return the specified array, where even number is element [0] and * exponent is element [1] */ public static double[] getEvenGridSpacingWithExp(double value, double[] array) { if (array == null) throw new NullPointerException("null array"); if (array.length < 2) throw new NullPointerException(""); /* TODO Time-Spacing 1s 5s 10s 20s 30s 1m 5m 10m 20m 30m 1h 2h 6h 12h */ double sig = Math.signum( value ); double exp = Math.floor(Math.log10( Math.abs(value) )); double gs = Math.pow(10.0, exp); int i = 0; while (i < gridLineEvenSpacings.length - 1) { if (gridLineEvenSpacings[i] * gs >= value) { break; } i++; } array[0] = gridLineEvenSpacings[i] * gs * sig; array[1] = exp; return array; } /** * Returns next even number for value and exponent of the value. * * @param value in units * @return array where even number is [0] element and exponent is [1] * element */ public static double[] getEvenGridSpacingWithExp(double value) { return getEvenGridSpacingWithExp(value, new double[2]); } /** * @param fromCoord * @param gridSpacing * @return */ public static double distanceToNextGridCoord(double fromCoord, double gridSpacing) { double mod = Math.IEEEremainder(fromCoord, gridSpacing); if (mod < 0) { return -mod; } else if (mod > 0) { return (gridSpacing - mod); } return 0; } /** * @param fromCoord * @param gridSpacing * @return */ public static double distanceToPrevGridCoord(double fromCoord, double gridSpacing) { double mod = Math.IEEEremainder(fromCoord, gridSpacing); if (mod < 0) { return (gridSpacing + mod); } else if (mod > 0) { return mod; } return 0; } /** * @param coord * @param gridSpacing * @param scale * @return */ public static double distanceToNextGridCoordScaled(double coord, double gridSpacing, double scale) { double result = distanceToNextGridCoord(coord, gridSpacing); return result * scale; } /** * @param coord * @param gridSpacing * @param scale * @return */ public static double distanceToPrevGridCoordScaled(double coord, double gridSpacing, double scale) { double result = distanceToPrevGridCoord(coord, gridSpacing); return result * scale; } /** * @param coord * @param gridSpacing * @return */ public static double distanceToNearestGridCoord(double coord, double gridSpacing) { double dist = GridUtils.distanceToNextGridCoord(coord, gridSpacing); if (dist > gridSpacing / 2) dist = dist - gridSpacing; return dist; } /** * @param tr * @param gridSpacing */ public static void snapToGrid(AffineTransform tr, double gridSpacing) { double gdx = GridUtils.distanceToNearestGridCoord(tr.getTranslateX(), gridSpacing); double gdy = GridUtils.distanceToNearestGridCoord(tr.getTranslateY(), gridSpacing); //System.out.println("SNAP TO GRID: delta=(" + gdx + ", " + gdy + "), tr = " + tr); tr.translate(gdx, gdy); } /** * @param p * @param gridSpacing */ public static void snapToGrid(Point2D p, double gridSpacing) { snapToGrid(p, gridSpacing, gridSpacing); } /** * @param p * @param gridXSpacing * @param gridYSpacing */ public static void snapToGrid(Point2D p, double gridXSpacing, double gridYSpacing) { double x = p.getX(); double y = p.getY(); double gdx = GridUtils.distanceToNearestGridCoord(x, gridXSpacing); double gdy = GridUtils.distanceToNearestGridCoord(y, gridYSpacing); p.setLocation(x + gdx, y + gdy); } /** * @param t * @param gridSpacing * @return */ public static double snapToGrid(double t, double gridSpacing) { double dt = GridUtils.distanceToNearestGridCoord(t, gridSpacing); return t + dt; } /** * Returns an even grid spacing where initialValue*scale <= limit. * * @param initialValue * @param scale * @param limit * @param gridSize * @param lessThan true to select the nearest even spacing <= * limit/scale or false to select the nearest even spacing >= * limit/scale * @return */ public static double limitedEvenGridSpacing(double initialValue, double scale, double limit, double gridSize, boolean lessThan) { while (initialValue * scale > limit) initialValue /= 2; return getEvenGridSpacing(initialValue, gridSize, lessThan); } /** * Returns an even grid spacing where initialValue*scale <= limit * * @param initialValue * @param scale * @param limit * @param lessThan true to select the nearest even spacing <= * limit/scale or false to select the nearest even spacing >= * limit/scale * @return */ public static double limitedEvenGridSpacing(double initialValue, double scale, double limit, boolean lessThan) { return limitedEvenGridSpacing(initialValue, scale, limit, 1.0, lessThan); } /** * A simple test for these routines. */ public static void main(String[] args) { System.out.println(Arrays.toString(getEvenGridSpacingWithExp(15))); System.out.println(Arrays.toString(getEvenGridSpacingWithExp(16.3))); System.out.println(Arrays.toString(getEvenGridSpacingWithExp(143.41))); System.out.println(Arrays.toString(getEvenGridSpacingWithExp(500.0))); System.out.println(Arrays.toString(getEvenGridSpacingWithExp(10000.0))); System.out.println(Arrays.toString(getEvenGridSpacingWithExp(0.5))); //double aa[] = new double[2]; System.out.println(getEvenGridSpacing(15, true)); System.out.println(getEvenGridSpacing(15, false)); System.out.println(getEvenGridSpacing(16.3, true)); System.out.println(getEvenGridSpacing(16.3, false)); System.out.println(getEvenGridSpacing(143.41, true)); System.out.println(getEvenGridSpacing(143.41, false)); System.out.println(getEvenGridSpacing(500.0, true)); System.out.println(getEvenGridSpacing(500.0, false)); System.out.println(getEvenGridSpacing(10000.0, true)); System.out.println(getEvenGridSpacing(10000.0, false)); System.out.println(getEvenGridSpacing(0.5, true)); System.out.println(getEvenGridSpacing(0.5, false)); System.out.println(getEvenGridSpacing(0.045, true)); System.out.println(getEvenGridSpacing(0.045, false)); System.out.println(getEvenGridSpacing(0.000605, true)); System.out.println(getEvenGridSpacing(0.000605, false)); System.out.println(getEvenGridSpacing(143, 2.54, true)); System.out.println(getEvenGridSpacing(143, 2.54, false)); } }