001 // License: GPL. Copyright 2007 by Immanuel Scholz and others
002 package org.openstreetmap.josm.data.osm.visitor;
003
004 import java.util.Collection;
005
006 import org.openstreetmap.josm.Main;
007 import org.openstreetmap.josm.data.Bounds;
008 import org.openstreetmap.josm.data.ProjectionBounds;
009 import org.openstreetmap.josm.data.coor.CachedLatLon;
010 import org.openstreetmap.josm.data.coor.EastNorth;
011 import org.openstreetmap.josm.data.coor.LatLon;
012 import org.openstreetmap.josm.data.osm.Node;
013 import org.openstreetmap.josm.data.osm.OsmPrimitive;
014 import org.openstreetmap.josm.data.osm.Relation;
015 import org.openstreetmap.josm.data.osm.RelationMember;
016 import org.openstreetmap.josm.data.osm.Way;
017
018 /**
019 * Calculates the total bounding rectangle of a series of {@link OsmPrimitive} objects, using the
020 * EastNorth values as reference.
021 * @author imi
022 */
023 public class BoundingXYVisitor extends AbstractVisitor {
024
025 private ProjectionBounds bounds = null;
026
027 public void visit(Node n) {
028 visit(n.getEastNorth());
029 }
030
031 public void visit(Way w) {
032 if (w.isIncomplete()) return;
033 for (Node n : w.getNodes()) {
034 visit(n);
035 }
036 }
037
038 public void visit(Relation e) {
039 // only use direct members
040 for (RelationMember m : e.getMembers()) {
041 if (!m.isRelation()) {
042 m.getMember().visit(this);
043 }
044 }
045 }
046
047 public void visit(Bounds b) {
048 if(b != null)
049 {
050 visit(b.getMin());
051 visit(b.getMax());
052 }
053 }
054
055 public void visit(ProjectionBounds b) {
056 if(b != null)
057 {
058 visit(b.getMin());
059 visit(b.getMax());
060 }
061 }
062
063 public void visit(LatLon latlon) {
064 if(latlon != null)
065 {
066 if(latlon instanceof CachedLatLon) {
067 visit(((CachedLatLon)latlon).getEastNorth());
068 } else {
069 visit(Main.getProjection().latlon2eastNorth(latlon));
070 }
071 }
072 }
073
074 public void visit(EastNorth eastNorth) {
075 if (eastNorth != null) {
076 if (bounds == null) {
077 bounds = new ProjectionBounds(eastNorth);
078 } else {
079 bounds.extend(eastNorth);
080 }
081 }
082 }
083
084 public boolean hasExtend()
085 {
086 return bounds != null && !bounds.getMin().equals(bounds.getMax());
087 }
088
089 /**
090 * @return The bounding box or <code>null</code> if no coordinates have passed
091 */
092 public ProjectionBounds getBounds() {
093 return bounds;
094 }
095
096 /**
097 * Enlarges the calculated bounding box by 0.002 degrees.
098 * If the bounding box has not been set (<code>min</code> or <code>max</code>
099 * equal <code>null</code>) this method does not do anything.
100 */
101 public void enlargeBoundingBox() {
102 enlargeBoundingBox(Main.pref.getDouble("edit.zoom-enlarge-bbox", 0.002));
103 }
104
105 /**
106 * Enlarges the calculated bounding box by the specified number of degrees.
107 * If the bounding box has not been set (<code>min</code> or <code>max</code>
108 * equal <code>null</code>) this method does not do anything.
109 *
110 * @param enlargeDegree
111 */
112 public void enlargeBoundingBox(double enlargeDegree) {
113 if (bounds == null)
114 return;
115 LatLon minLatlon = Main.getProjection().eastNorth2latlon(bounds.getMin());
116 LatLon maxLatlon = Main.getProjection().eastNorth2latlon(bounds.getMax());
117 bounds = new ProjectionBounds(
118 Main.getProjection().latlon2eastNorth(new LatLon(minLatlon.lat() - enlargeDegree, minLatlon.lon() - enlargeDegree)),
119 Main.getProjection().latlon2eastNorth(new LatLon(maxLatlon.lat() + enlargeDegree, maxLatlon.lon() + enlargeDegree)));
120 }
121
122 @Override public String toString() {
123 return "BoundingXYVisitor["+bounds+"]";
124 }
125
126 public void computeBoundingBox(Collection<? extends OsmPrimitive> primitives) {
127 if (primitives == null) return;
128 for (OsmPrimitive p: primitives) {
129 if (p == null) {
130 continue;
131 }
132 p.visit(this);
133 }
134 }
135 }