source: josm/trunk/src/org/openstreetmap/josm/gui/layer/NativeScaleLayer.java@ 10461

Last change on this file since 10461 was 10378, checked in by Don-vip, 8 years ago

Checkstyle 6.19: enable SingleSpaceSeparator and fix violations

File size: 9.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.layer;
3
4import java.util.ArrayList;
5import java.util.Collection;
6import java.util.List;
7
8import org.openstreetmap.josm.gui.NavigatableComponent;
9
10/**
11 * Represents a layer that has native scales.
12 * @author András Kolesár
13 */
14public interface NativeScaleLayer {
15
16 /**
17 * Get native scales of this layer.
18 * @return {@link ScaleList} of native scales
19 */
20 ScaleList getNativeScales();
21
22 /**
23 * Represents a scale with native flag, used in {@link ScaleList}
24 */
25 class Scale {
26 /**
27 * Scale factor, same unit as in {@link NavigatableComponent}
28 */
29 private final double scale;
30
31 /**
32 * True if this scale is native resolution for data source.
33 */
34 private final boolean isNative;
35
36 private final int index;
37
38 /**
39 * Constructs a new Scale with given scale, native defaults to true.
40 * @param scale as defined in WMTS (scaleDenominator)
41 * @param index zoom index for this scale
42 */
43 public Scale(double scale, int index) {
44 this.scale = scale;
45 this.isNative = true;
46 this.index = index;
47 }
48
49 /**
50 * Constructs a new Scale with given scale, native and index values.
51 * @param scale as defined in WMTS (scaleDenominator)
52 * @param isNative is this scale native to the source or not
53 * @param index zoom index for this scale
54 */
55 public Scale(double scale, boolean isNative, int index) {
56 this.scale = scale;
57 this.isNative = isNative;
58 this.index = index;
59 }
60
61 @Override
62 public String toString() {
63 return String.format("%f [%s]", scale, isNative);
64 }
65
66 /**
67 * Get index of this scale in a {@link ScaleList}
68 * @return index
69 */
70 public int getIndex() {
71 return index;
72 }
73
74 public double getScale() {
75 return scale;
76 }
77 }
78
79 /**
80 * List of scales, may include intermediate steps between native resolutions
81 */
82 class ScaleList {
83 private final List<Scale> scales = new ArrayList<>();
84
85 protected ScaleList() {
86 }
87
88 public ScaleList(Collection<Double> scales) {
89 int i = 0;
90 for (Double scale: scales) {
91 this.scales.add(new Scale(scale, i++));
92 }
93 }
94
95 protected void addScale(Scale scale) {
96 scales.add(scale);
97 }
98
99 /**
100 * Returns a ScaleList that has intermediate steps between native scales.
101 * Native steps are split to equal steps near given ratio.
102 * @param ratio user defined zoom ratio
103 * @return a {@link ScaleList} with intermediate steps
104 */
105 public ScaleList withIntermediateSteps(double ratio) {
106 ScaleList result = new ScaleList();
107 Scale previous = null;
108 for (Scale current: this.scales) {
109 if (previous != null) {
110 double step = previous.scale / current.scale;
111 double factor = Math.log(step) / Math.log(ratio);
112 int steps = (int) Math.round(factor);
113 if (steps != 0) {
114 double smallStep = Math.pow(step, 1.0/steps);
115 for (int j = 1; j < steps; j++) {
116 double intermediate = previous.scale / Math.pow(smallStep, j);
117 result.addScale(new Scale(intermediate, false, current.index));
118 }
119 }
120 }
121 result.addScale(current);
122 previous = current;
123 }
124 return result;
125 }
126
127 /**
128 * Get a scale from this ScaleList or a new scale if zoomed outside.
129 * @param scale previous scale
130 * @param floor use floor instead of round, set true when fitting view to objects
131 * @return new {@link Scale}
132 */
133 public Scale getSnapScale(double scale, boolean floor) {
134 return getSnapScale(scale, NavigatableComponent.PROP_ZOOM_RATIO.get(), floor);
135 }
136
137 /**
138 * Get a scale from this ScaleList or a new scale if zoomed outside.
139 * @param scale previous scale
140 * @param ratio zoom ratio from starting from previous scale
141 * @param floor use floor instead of round, set true when fitting view to objects
142 * @return new {@link Scale}
143 */
144 public Scale getSnapScale(double scale, double ratio, boolean floor) {
145 if (scales.isEmpty())
146 return null;
147 int size = scales.size();
148 Scale first = scales.get(0);
149 Scale last = scales.get(size-1);
150
151 if (scale > first.scale) {
152 double step = scale / first.scale;
153 double factor = Math.log(step) / Math.log(ratio);
154 int steps = (int) (floor ? Math.floor(factor) : Math.round(factor));
155 if (steps == 0) {
156 return new Scale(first.scale, first.isNative, steps);
157 } else {
158 return new Scale(first.scale * Math.pow(ratio, steps), false, steps);
159 }
160 } else if (scale < last.scale) {
161 double step = last.scale / scale;
162 double factor = Math.log(step) / Math.log(ratio);
163 int steps = (int) (floor ? Math.floor(factor) : Math.round(factor));
164 if (steps == 0) {
165 return new Scale(last.scale, last.isNative, size-1+steps);
166 } else {
167 return new Scale(last.scale / Math.pow(ratio, steps), false, size-1+steps);
168 }
169 } else {
170 Scale previous = null;
171 for (int i = 0; i < size; i++) {
172 Scale current = this.scales.get(i);
173 if (previous != null) {
174 if (scale <= previous.scale && scale >= current.scale) {
175 if (floor || previous.scale / scale < scale / current.scale) {
176 return new Scale(previous.scale, previous.isNative, i-1);
177 } else {
178 return new Scale(current.scale, current.isNative, i);
179 }
180 }
181 }
182 previous = current;
183 }
184 return null;
185 }
186 }
187
188 /**
189 * Get new scale for zoom in/out with a ratio at a number of times.
190 * Used by mousewheel zoom where wheel can step more than one between events.
191 * @param scale previois scale
192 * @param ratio user defined zoom ratio
193 * @param times number of times to zoom
194 * @return new {@link Scale} object from {@link ScaleList} or outside
195 */
196 public Scale scaleZoomTimes(double scale, double ratio, int times) {
197 Scale next = getSnapScale(scale, ratio, false);
198 int abs = Math.abs(times);
199 for (int i = 0; i < abs; i++) {
200 if (times < 0) {
201 next = getNextIn(next, ratio);
202 } else {
203 next = getNextOut(next, ratio);
204 }
205 }
206 return next;
207 }
208
209 /**
210 * Get new scale for zoom in.
211 * @param scale previous scale
212 * @param ratio user defined zoom ratio
213 * @return next scale in list or a new scale when zoomed outside
214 */
215 public Scale scaleZoomIn(double scale, double ratio) {
216 Scale snap = getSnapScale(scale, ratio, false);
217 return getNextIn(snap, ratio);
218 }
219
220 /**
221 * Get new scale for zoom out.
222 * @param scale previous scale
223 * @param ratio user defined zoom ratio
224 * @return next scale in list or a new scale when zoomed outside
225 */
226 public Scale scaleZoomOut(double scale, double ratio) {
227 Scale snap = getSnapScale(scale, ratio, false);
228 return getNextOut(snap, ratio);
229 }
230
231 @Override
232 public String toString() {
233 StringBuilder stringBuilder = new StringBuilder();
234 for (Scale s: this.scales) {
235 stringBuilder.append(s.toString() + '\n');
236 }
237 return stringBuilder.toString();
238 }
239
240 private Scale getNextIn(Scale scale, double ratio) {
241 if (scale == null)
242 return null;
243 int nextIndex = scale.getIndex() + 1;
244 if (nextIndex <= 0 || nextIndex > this.scales.size()-1) {
245 return new Scale(scale.scale / ratio, nextIndex == 0, nextIndex);
246 } else {
247 Scale nextScale = this.scales.get(nextIndex);
248 return new Scale(nextScale.scale, nextScale.isNative, nextIndex);
249 }
250 }
251
252 private Scale getNextOut(Scale scale, double ratio) {
253 if (scale == null)
254 return null;
255 int nextIndex = scale.getIndex() - 1;
256 if (nextIndex < 0 || nextIndex >= this.scales.size()-1) {
257 return new Scale(scale.scale * ratio, nextIndex == this.scales.size()-1, nextIndex);
258 } else {
259 Scale nextScale = this.scales.get(nextIndex);
260 return new Scale(nextScale.scale, nextScale.isNative, nextIndex);
261 }
262 }
263 }
264}
Note: See TracBrowser for help on using the repository browser.