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

Last change on this file since 12340 was 11386, checked in by Don-vip, 7 years ago

sonar - squid:S1066 - Collapsible "if" statements should be merged

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