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

Last change on this file since 10878 was 10806, checked in by Don-vip, 8 years ago

fix #13303 - Fixes for hatched texture (modified patch by michael2402) - gsoc-core

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