source: josm/trunk/src/org/openstreetmap/josm/data/osm/visitor/BoundingXYVisitor.java@ 12966

Last change on this file since 12966 was 12846, checked in by bastiK, 7 years ago

see #15229 - use Config.getPref() wherever possible

  • Property svn:eol-style set to native
File size: 7.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.osm.visitor;
3
4import java.util.Collection;
5
6import org.openstreetmap.josm.Main;
7import org.openstreetmap.josm.data.Bounds;
8import org.openstreetmap.josm.data.ProjectionBounds;
9import org.openstreetmap.josm.data.coor.EastNorth;
10import org.openstreetmap.josm.data.coor.ILatLon;
11import org.openstreetmap.josm.data.coor.LatLon;
12import org.openstreetmap.josm.data.osm.Node;
13import org.openstreetmap.josm.data.osm.OsmPrimitive;
14import org.openstreetmap.josm.data.osm.Relation;
15import org.openstreetmap.josm.data.osm.RelationMember;
16import org.openstreetmap.josm.data.osm.Way;
17import org.openstreetmap.josm.gui.MainApplication;
18import org.openstreetmap.josm.gui.MapFrame;
19import org.openstreetmap.josm.spi.preferences.Config;
20
21/**
22 * Calculates the total bounding rectangle of a series of {@link OsmPrimitive} objects, using the
23 * EastNorth values as reference.
24 * @author imi
25 */
26public class BoundingXYVisitor implements OsmPrimitiveVisitor {
27
28 private ProjectionBounds bounds;
29
30 @Override
31 public void visit(Node n) {
32 visit((ILatLon) n);
33 }
34
35 @Override
36 public void visit(Way w) {
37 if (w.isIncomplete()) return;
38 for (Node n : w.getNodes()) {
39 visit(n);
40 }
41 }
42
43 @Override
44 public void visit(Relation e) {
45 // only use direct members
46 for (RelationMember m : e.getMembers()) {
47 if (!m.isRelation()) {
48 m.getMember().accept(this);
49 }
50 }
51 }
52
53 /**
54 * Visiting call for bounds.
55 * @param b bounds
56 */
57 public void visit(Bounds b) {
58 if (b != null) {
59 Main.getProjection().visitOutline(b, this::visit);
60 }
61 }
62
63 /**
64 * Visiting call for projection bounds.
65 * @param b projection bounds
66 */
67 public void visit(ProjectionBounds b) {
68 if (b != null) {
69 visit(b.getMin());
70 visit(b.getMax());
71 }
72 }
73
74 /**
75 * Visiting call for lat/lon.
76 * @param latlon lat/lon
77 * @since 12725 (public for ILatLon parameter)
78 */
79 public void visit(ILatLon latlon) {
80 if (latlon != null) {
81 visit(latlon.getEastNorth(Main.getProjection()));
82 }
83 }
84
85 /**
86 * Visiting call for lat/lon.
87 * @param latlon lat/lon
88 */
89 public void visit(LatLon latlon) {
90 visit((ILatLon) latlon);
91 }
92
93 /**
94 * Visiting call for east/north.
95 * @param eastNorth east/north
96 */
97 public void visit(EastNorth eastNorth) {
98 if (eastNorth != null) {
99 if (bounds == null) {
100 bounds = new ProjectionBounds(eastNorth);
101 } else {
102 bounds.extend(eastNorth);
103 }
104 }
105 }
106
107 /**
108 * Determines if the visitor has a non null bounds area.
109 * @return {@code true} if the visitor has a non null bounds area
110 * @see ProjectionBounds#hasExtend
111 */
112 public boolean hasExtend() {
113 return bounds != null && bounds.hasExtend();
114 }
115
116 /**
117 * @return The bounding box or <code>null</code> if no coordinates have passed
118 */
119 public ProjectionBounds getBounds() {
120 return bounds;
121 }
122
123 /**
124 * Enlarges the calculated bounding box by 0.002 degrees.
125 * If the bounding box has not been set (<code>min</code> or <code>max</code>
126 * equal <code>null</code>) this method does not do anything.
127 */
128 public void enlargeBoundingBox() {
129 enlargeBoundingBox(Config.getPref().getDouble("edit.zoom-enlarge-bbox", 0.002));
130 }
131
132 /**
133 * Enlarges the calculated bounding box by the specified number of degrees.
134 * If the bounding box has not been set (<code>min</code> or <code>max</code>
135 * equal <code>null</code>) this method does not do anything.
136 *
137 * @param enlargeDegree number of degrees to enlarge on each side
138 */
139 public void enlargeBoundingBox(double enlargeDegree) {
140 if (bounds == null)
141 return;
142 LatLon minLatlon = Main.getProjection().eastNorth2latlon(bounds.getMin());
143 LatLon maxLatlon = Main.getProjection().eastNorth2latlon(bounds.getMax());
144 bounds = new ProjectionBounds(new LatLon(
145 Math.max(-90, minLatlon.lat() - enlargeDegree),
146 Math.max(-180, minLatlon.lon() - enlargeDegree)).getEastNorth(Main.getProjection()),
147 new LatLon(
148 Math.min(90, maxLatlon.lat() + enlargeDegree),
149 Math.min(180, maxLatlon.lon() + enlargeDegree)).getEastNorth(Main.getProjection()));
150 }
151
152 /**
153 * Enlarges the bounding box up to <code>maxEnlargePercent</code>, depending on
154 * its size. If the bounding box is small, it will be enlarged more in relation
155 * to its beginning size. The larger the bounding box, the smaller the change,
156 * down to the minimum of 1% enlargement.
157 *
158 * Warning: if the bounding box only contains a single node, no expansion takes
159 * place because a node has no width/height. Use <code>enlargeToMinDegrees</code>
160 * instead.
161 *
162 * Example: You specify enlargement to be up to 100%.
163 *
164 * Bounding box is a small house: enlargement will be 95–100%, i.e.
165 * making enough space so that the house fits twice on the screen in
166 * each direction.
167 *
168 * Bounding box is a large landuse, like a forest: Enlargement will
169 * be 1–10%, i.e. just add a little border around the landuse.
170 *
171 * If the bounding box has not been set (<code>min</code> or <code>max</code>
172 * equal <code>null</code>) this method does not do anything.
173 *
174 * @param maxEnlargePercent maximum enlargement in percentage (100.0 for 100%)
175 */
176 public void enlargeBoundingBoxLogarithmically(double maxEnlargePercent) {
177 if (bounds == null)
178 return;
179
180 double diffEast = bounds.getMax().east() - bounds.getMin().east();
181 double diffNorth = bounds.getMax().north() - bounds.getMin().north();
182
183 double enlargeEast = Math.min(maxEnlargePercent - 10*Math.log(diffEast), 1)/100;
184 double enlargeNorth = Math.min(maxEnlargePercent - 10*Math.log(diffNorth), 1)/100;
185
186 visit(bounds.getMin().add(-enlargeEast/2, -enlargeNorth/2));
187 visit(bounds.getMax().add(+enlargeEast/2, +enlargeNorth/2));
188 }
189
190 /**
191 * Specify a degree larger than 0 in order to make the bounding box at least
192 * the specified size in width and height. The value is ignored if the
193 * bounding box is already larger than the specified amount.
194 *
195 * If the bounding box has not been set (<code>min</code> or <code>max</code>
196 * equal <code>null</code>) this method does not do anything.
197 *
198 * If the bounding box contains objects and is to be enlarged, the objects
199 * will be centered within the new bounding box.
200 *
201 * @param size minimum width and height in meter
202 */
203 public void enlargeToMinSize(double size) {
204 if (bounds == null)
205 return;
206 // convert size from meters to east/north units
207 MapFrame map = MainApplication.getMap();
208 double enSize = size * map.mapView.getScale() / map.mapView.getDist100Pixel() * 100;
209 visit(bounds.getMin().add(-enSize/2, -enSize/2));
210 visit(bounds.getMax().add(+enSize/2, +enSize/2));
211 }
212
213 @Override
214 public String toString() {
215 return "BoundingXYVisitor["+bounds+']';
216 }
217
218 /**
219 * Compute the bounding box of a collection of primitives.
220 * @param primitives the collection of primitives
221 */
222 public void computeBoundingBox(Collection<? extends OsmPrimitive> primitives) {
223 if (primitives == null) return;
224 for (OsmPrimitive p: primitives) {
225 if (p == null) {
226 continue;
227 }
228 p.accept(this);
229 }
230 }
231}
Note: See TracBrowser for help on using the repository browser.