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    }