/*******************************************************************************
* 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));
}
}