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

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

see #15229 - deprecate ILatLon#getEastNorth() so ILatLon has no dependency on Main.proj

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