/******************************************************************************* * Breakout Cave Survey Visualizer * * Copyright (C) 2014 James Edwards * * jedwards8 at fastmail dot fm * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *******************************************************************************/ package com.andork.plot; /** * Methods relating to grids, e.g. computing nice step sizes for humans. */ public class GridMath { /** * Returns the least (closest to negative infinity) multiple of * <code>mod</code> that is greater than or equal to <code>value</code>. */ public static double modCeiling(double value, double mod) { if (value < 0) { return -modFloor(-value, mod); } mod = Math.abs(mod); double rem = value % mod; if (rem != 0) { value += mod - rem; } return value; } /** * @return the least (closest to negative infinity) value * {@code x = anchor + k * mod} for some integer {@code k} such that * {@code x >= value}. */ public static double modCeiling(double value, double mod, double anchor) { return anchor + modCeiling(value - anchor, mod); } /** * Returns the greatest (closest to positive infinity) multiple of * <code>mod</code> that is less than or equal to <code>value</code>. */ public static double modFloor(double value, double mod) { if (value < 0) { return -modCeiling(-value, mod); } mod = Math.abs(mod); return value - value % mod; } /** * @return the greatest (closest to positive infinity) value * {@code x = anchor + k * mod} for some integer {@code k} such that * {@code x <= value}. */ public static double modFloor(double value, double mod, double anchor) { return anchor + modFloor(value - anchor, mod); } /** * Computes the least (closest to negative infinity) "nice" fraction of a * power of 10 (1/8, 1/5, 1/4, or 1/2 * 10^n) greater than or equal to the * given number. */ public static double niceCeiling(double number) { if (number < 0) { return -niceFloor(-number); } int power = (int) Math.ceil(Math.log10(number)); double order = Math.pow(10, power); if (order * .125f >= number) { return order * .125f; } if (order * .2f >= number) { return order * .2f; } if (order * .25f >= number) { return order * .25f; } if (order * .5f >= number) { return order * .5f; } return order; } public static int niceCeilingFractionDigits(double number) { if (number < 0) { return niceFloorFractionDigits(-number); } int power = (int) Math.ceil(Math.log10(number)); double order = Math.pow(10, power); int digits = -power; if (order * .125f >= number) { digits += 3; } else if (order * .2f >= number) { digits += 1; } else if (order * .25f >= number) { digits += 2; } else if (order * .5f >= number) { digits += 1; } return Math.max(0, digits); } /** * Computes the greatest (closest to positive infinity) "nice" fraction of a * power of 10 (1/8, 1/5, 1/4, or 1/2 * 10^n) less than or equal to the * given number. */ public static double niceFloor(double number) { if (number < 0) { return -niceCeiling(-number); } int power = (int) Math.ceil(Math.log10(number)); double order = Math.pow(10, power); if (order * .5f <= number) { return order * .5f; } if (order * .25f <= number) { return order * .25f; } if (order * .2f <= number) { return order * .2f; } if (order * .125f <= number) { return order * .125f; } return order * .1f; } public static int niceFloorFractionDigits(double number) { if (number < 0) { return niceCeilingFractionDigits(-number); } int power = (int) Math.ceil(Math.log10(number)); double order = Math.pow(10, power); int digits = -power; if (order * .5f <= number) { digits += 1; } else if (order * .25f <= number) { digits += 2; } else if (order * .2f <= number) { digits += 1; } else if (order * .125f <= number) { digits += 3; } else { digits += 1; } return Math.max(0, digits); } /** * Computes the least (closest to negative infinity) "nice" fraction of a * power of 10 (1/8, 1/5, 1/4, or 1/2 * 10^n) greater than or equal to the * given number. */ public static double niceMajorGridLineSpacing(double minor) { if (minor < 0) { return -niceFloor(-minor); } int power = (int) Math.ceil(Math.log10(minor)); double order = Math.pow(10, power); if (order * .125f >= minor) { return order * .25f; } if (order * .2f >= minor) { return order * .2f; } if (order * .25f >= minor) { return order * .5f; } if (order * .5f >= minor) { return order; } return order; } /** * @return the least (closest to negative infinity) power of 10 that is * {@code >= number}. */ public static double order(double number) { int power = (int) Math.ceil(Math.log10(number)); return Math.pow(10, power); } }