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

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

make BoundingXYVisitor accept IPrimitive

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