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

Last change on this file since 14206 was 13852, checked in by Don-vip, 6 years ago

SonarQube - fix more code issues

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