View Javadoc

1   /*
2    * Copyright (c) 2003-2008 by Cosylab d. d.
3    *
4    * This file is part of CosyBeans-Common.
5    *
6    * CosyBeans-Common is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * CosyBeans-Common is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with CosyBeans-Common.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  package com.cosylab.gui.components.range2;
21  
22  import java.util.ArrayList;
23  
24  /**
25   * <Code>ManualTickCalculator</code> calculates ticks explicitely. Ticks are calculated
26   * according to the supplied parameters which define at which values major and minor
27   * ticks should be.
28   *   
29   * @author <a href="mailto:jaka.bobnar@cosylab.com">Jaka Bobnar</a>
30   * @version $Id: ManualTickCalculator.java,v 1.4 2008-04-22 12:28:40 jbobnar Exp $
31   *
32   */
33  public class ManualTickCalculator implements TickCalculator {
34  
35  	private double[] majorTicks = null;
36  	private double[] labels = null;
37  	private double minor = 0;
38  	
39  	/**
40  	 * Constructs a new ManualTickProvider with null value.
41  	 *
42  	 */
43  	public ManualTickCalculator() {
44  		
45  	}
46  	
47  	/**
48  	 * Constructs a new ManualTickProvider with the given parameters.
49  	 * 
50  	 * @param majorTicks values that major ticks will be created for
51  	 * @param labels values that will have labels (only major ticks can have labels).
52  	 * @param minor number of minor ticks between two major ticks
53  	 */
54  	public ManualTickCalculator(double[] majorTicks, double[] labels, double minor) {
55  		this.majorTicks = majorTicks;
56  		this.labels = labels;
57  		this.minor = minor;
58  		
59  	}
60  	
61  	/**
62  	 * Sets the values that will have labels printed next to ticks. Only major ticks
63  	 * can have labels.
64  	 * 
65  	 * @param labels
66  	 */
67  	public void setLabels(double[] labels) {
68  		this.labels = labels;
69  	}
70  	
71  	/**
72  	 * Sets the values which will have major ticks.
73  	 * 
74  	 * @param majorTicks
75  	 */
76  	public void setMajorTicks(double[] majorTicks) {
77  		this.majorTicks = majorTicks;
78  	}
79  	
80  	/**
81  	 * Sets the number of minor ticks between two major ticks.
82  	 * 
83  	 * @param minor
84  	 */
85  	public void setMinor(double minor) {
86  		this.minor = minor;
87  	}
88  	
89  	/**
90  	 * Returns the values which have labels printed next to the ticks.
91  	 * 
92  	 * @return
93  	 */
94  	public double[] getLabels() {
95  		return labels;
96  	}
97  	
98  	/**
99  	 * Returns the values which have major ticks.
100 	 * 
101 	 * @return
102 	 */
103 	public double[] getMajorTicks() {
104 		return majorTicks;
105 	}
106 	
107 	/**
108 	 * Returns the number of minor ticks between two major ticks.
109 	 * @return
110 	 */
111 	public double getMinor() {
112 		return minor;
113 	}
114 		
115 	private String getLabel(double d, TickParameters measurer) {
116 		if (this.labels == null) return "";
117 		for (int i = 0; i < labels.length; i++) {
118 			if (labels[i] == d) return measurer.formatNumber(d); 
119 		}
120 		return "";
121 	}
122 	
123 	/*
124 	 * (non-Javadoc)
125 	 * @see com.cosylab.gui.components.range2.TickCalculator#calculateTicks(com.cosylab.gui.components.range2.Range, com.cosylab.gui.components.range2.RangedValue)
126 	 */
127 	public Tick[] calculateTicks(int length, Range range, RangedValue rangedValue) {
128 		return calculateTicks(length, new DefaultTickParameters(), range, rangedValue);
129 	}
130 	
131 	private double getMinimumMajorTick(double limit) {
132 		if (majorTicks.length == 0) return Double.NaN;
133 		double min = majorTicks[0];
134 		for (int i = 1; i < majorTicks.length; i++) {
135 			if (majorTicks[i] < limit) continue;
136 			min = Math.min(min, majorTicks[i]);
137 		}
138 		return Math.max(min, limit);
139 	}
140 	
141 	private double getMinorStep(double min, double max, int majorCount) {
142 		if (minor != 0) return minor;
143 		else if (majorCount == 0) return (max-min)/2.;
144 		else return (max-min)/majorCount/5.;
145 	}
146 		
147 	/*
148 	 * (non-Javadoc)
149 	 * @see com.cosylab.gui.components.range2.TickCalculator#calculateTicks(com.cosylab.gui.components.range2.TickParameters, com.cosylab.gui.components.range2.Range, com.cosylab.gui.components.range2.RangedValue)
150 	 */
151 	public Tick[] calculateTicks(int spaceLength, TickParameters measurer, Range range, RangedValue rangedValue) {
152 		if (this.majorTicks == null || this.majorTicks.length == 0) return new Tick[0];
153 		if (measurer == null) measurer = new DefaultTickParameters();
154 		int length = majorTicks.length;
155 		
156 //		int num = (int)((rangedValue.getMaximum() - rangedValue.getMinimum())/minor);
157 		double rMax = rangedValue.getMaximum();
158 		double rMin = rangedValue.getMinimum();
159 		double mMin = getMinimumMajorTick(rMin);
160 		double minor = getMinorStep(rMin, rMax, length);
161 		int num = (int)((rMax - mMin)/minor);
162 		int n2 = 0;
163 		if (rMin < mMin) {
164 			n2 = (int)((mMin-rMin)/minor);
165 		}
166 		
167 		ArrayList<Tick> ticks;
168 		if (length + num + n2 < 0 || length + num + n2 > 1000000) {
169 			throw new IllegalStateException("Number of minor ticks is too large. Adjust the minor step.");
170 		} else {
171 			ticks = new ArrayList<Tick>(length + num + n2);
172 		}
173 		
174 		for (int i = n2 -1; i >= 0 ; i--) {
175 			ticks.add(new Tick(mMin - (i+1)*minor, range.toRelative(mMin - (i+1)*minor, rangedValue), false, ""));
176 		}
177 		
178 		for (int i = n2; i < n2 + num; i++) {
179 			ticks.add(new Tick(mMin + (i-n2 + 1) *minor, range.toRelative(mMin + (i-n2 + 1)*minor, rangedValue), false, ""));
180 		}
181 		
182 		for (int i = n2 + num; i < length + num + n2; i++) {
183 			if (majorTicks[i - num - n2] > rMax || majorTicks[i - num - n2] < rMin) continue;
184 			ticks.add(new Tick(majorTicks[i - num-n2], range.toRelative(majorTicks[i - num-n2], rangedValue), true, getLabel(majorTicks[i-num-n2], measurer)));
185 		}
186 		
187 		return ticks.toArray(new Tick[ticks.size()]);
188 	}
189 	
190 	public static void main(String[] args) {
191 		double[] vals = new double[]{0,5,10,15};
192 		double[] lab = new double[]{5,15};
193 		ManualTickCalculator pr = new ManualTickCalculator(vals,lab,4);
194 		Tick[] t = pr.calculateTicks(0, new LinearRange(), new RangedValue(0,15,3));
195 		for (int i = 0; i < t.length; i++) {
196 			System.out.println(t[i]);
197 		}
198 	}
199 }