package org.activityinfo.server.report.generator; /* * #%L * ActivityInfo Server * %% * Copyright (C) 2009 - 2013 UNICEF * %% * 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 3 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, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ /** * @author Alex Bertram */ public final class ScaleUtil { public static class Scale { private double valmin; private double step; private double valmax; public double getValmin() { return valmin; } public double getStep() { return step; } public double getValmax() { return valmax; } } private ScaleUtil() { } // // SUBROUTINE SCALE(FMN, FMX, N, VALMIN, STEP, VALMAX, IFAULT) // C // C ALGORITHM AS 96 APPL. STATIST. (1976) VOL.25, NO.1 // C // C Given extreme values FMN, FMX, and the need for a scale with N // C marks, calculates value for the lowest scale mark (VALMIN) and // C step length (STEP) and highest scale mark (VALMAX). // C public static Scale computeScale(double fmn, double fmx, int n) { // REAL FMN, FMX, VALMIN, STEP, VALMAX // INTEGER N, IFAULT Scale scale = new Scale(); // C // C Units for step lengths // C // REAL UNIT(11) // C Local variables // INTEGER NUNIT, I, J // REAL TOL, ZERO, HALF, ONE, TEN, BIAS, FMAX, FMIN, RN, X, S, RANGE int i, j; double fmax, fmin, rn, x, s, range; // C // C Array length unit() // C // DATA NUNIT /11/ // C // C Local constant, defining effective equality of values. // C // DATA TOL /5.0E-6/ // DATA ZERO /0.0/, HALF /0.5/, ONE /1.0/, TEN /10.0/ // DATA BIAS /1.0E-4/ // DATA UNIT /1.0, 1.2, 1.6, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0, 8.0, // * 10.0/ final double tol = 5.0E-6; final double bias = 1.0E-4; final double[] unit = new double[]{1, 1.2, 1.6, 2.0, 2.5, 3, 5, 6, 8, 10}; // C // FMAX = FMX // FMIN = FMN // IFAULT = 1 fmax = fmx; fmin = fmn; // C // C Test for valid parameter values // C // IF (FMAX .LT. FMIN .OR. N .LE. 1) RETURN // IFAULT = 0 // RN = N - 1 // X = ABS(FMAX) // IF (X .EQ. ZERO) X = ONE // IF ((FMAX - FMIN) / X .GT. TOL) GO TO 20 if (fmax < fmin) { throw new IllegalArgumentException("fmax cannot be less than fmin."); } if (n < 1) { throw new IllegalArgumentException("n must be greater than or equal to n"); } rn = n - 1; x = Math.abs(fmax); if (x == 0) { x = 1; } if (!((fmax - fmin) / x > tol)) { // C // C All values effectively equal // C // IF (FMAX .LT. ZERO) THEN // FMAX = ZERO // ELSE IF (FMAX .EQ. ZERO) THEN // FMAX = ONE // ELSE // FMIN = ZERO // END IF if (fmax < 0) { fmax = 0; } else if (fmax == 0) { fmax = 1; } else { fmin = 0; } } // C // 20 STEP = (FMAX - FMIN) / RN // S = STEP scale.step = (fmax - fmin) / rn; s = scale.step; // C // C Find power of 10 // C // 25 IF (S .GE. ONE) GO TO 30 // S = S * TEN // GO TO 25 while (!(s >= 1)) { s = s * 10; } // 30 IF (S .LT. TEN) GO TO 35 // S = S / TEN // GO TO 30 while (!(s < 10)) { s = s / 10d; } // C // C Calculate STEP // C // 35 X = S - BIAS // DO 40 I = 1, NUNIT // IF (X .LE. UNIT(I)) GO TO 45 // 40 CONTINUE // 45 STEP = STEP * UNIT(I) / S // RANGE = STEP * RN x = s - bias; for (i = 0; i != unit.length; ++i) { if (x < unit[i]) { break; } } scale.step = scale.step * unit[i] / s; range = scale.step * rn; // C // C Make first estimate of VALMIN // C // X = HALF * (ONE + (FMIN + FMAX - RANGE) / STEP) // J = X - BIAS // IF (X .LT. ZERO) J = J - 1 // VALMIN = STEP * FLOAT(J) // AB: bit hackish, but if the min value is zero, we want to stay at // zero if (fmin == 0) { scale.valmin = 0; } else { x = 0.5 * (1d + (fmin + fmax - range) / scale.step); j = (int) (x - bias); if (x < 0) { j = j - 1; } scale.valmin = scale.step * j; } // C // C Test if VALMIN could be zero // C // IF (FMIN .GE. ZERO .AND. RANGE .GE. FMAX) VALMIN = ZERO // VALMAX = VALMIN + RANGE if (fmin > 0 && range > fmax) { scale.valmin = 0; } scale.valmax = scale.valmin + range; // C // C Test if VALMAX could be zero // C // IF (FMAX .GT. ZERO .OR. RANGE .LT. -FMIN) RETURN // VALMAX = ZERO // VALMIN = -RANGE // RETURN // END if (fmax > 0 || range < -fmin) { return scale; } scale.valmax = 0; scale.valmin = -range; return scale; } }