1 // Copyright 2008, Google Inc. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met:
5 //
6 //  1. Redistributions of source code must retain the above copyright notice,
7 //     this list of conditions and the following disclaimer.
8 //  2. Redistributions in binary form must reproduce the above copyright notice,
9 //     this list of conditions and the following disclaimer in the documentation
10 //     and/or other materials provided with the distribution.
11 //  3. Neither the name of Google Inc. nor the names of its contributors may be
12 //     used to endorse or promote products derived from this software without
13 //     specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 // This file contains the definition of the Bbox class.
27 
28 #ifndef KML_ENGINE_BBOX_H__
29 #define KML_ENGINE_BBOX_H__
30 
31 namespace kmlengine {
32 
33 const double kMinLat = -180.0;
34 const double kMaxLat = 180.0;
35 const double kMinLon = -180.0;
36 const double kMaxLon = 180.0;
37 
38 // This class maintains a simple geographic bounding box.  Example usage:
39 //   Bbox bbox;
40 //   bbox.ExpandLatLon(lat, lon);  // 0 or more times for a set of lat,lon.
41 //
42 //   // Inquire some things about the bounding box:
43 //   double mid_lat, mid_lon;
44 //   bbox.GetCenter(&mid_lat, &mid_lon);
45 //   double north = bbox.get_north()  // Same for s,e,w
46 //   bool contains = bbox.Contains(lat, lon);
47 //
48 // NOTE: There is no provision for the ante-meridian nor for the validity
49 // of any latitude or longitude value.
50 class Bbox {
51  public:
52   // Construct a default bounding box.  The mininums and maximums are set such
53   // that any valid latitude/longitude are handled properly.
Bbox()54   Bbox() : north_(kMinLat), south_(kMaxLat), east_(kMinLon), west_(kMaxLon) {}
55 
56   // Construct a bounding box of a given extent.  There are no checks for
57   // the validity of these parameters.
Bbox(double north,double south,double east,double west)58   Bbox(double north, double south, double east, double west)
59      : north_(north), south_(south), east_(east), west_(west) {}
60 
61   // This aligns this Bbox within the quadtree specified down to the maximum
62   // level specified.
AlignBbox(Bbox * qt,unsigned int max_depth)63   void AlignBbox(Bbox* qt, unsigned int max_depth) {
64     if (!qt) {
65       return;
66     }
67     double lat = qt->GetCenterLat();
68     double lon = qt->GetCenterLon();
69     if (ContainedByBox(qt->get_north(), lat, qt->get_east(), lon)) {
70       qt->set_south(lat);
71       qt->set_west(lon);
72     } else if (ContainedByBox(qt->get_north(), lat, lon, qt->get_west())) {
73       qt->set_south(lat);
74       qt->set_east(lon);
75     } else if (ContainedByBox(lat, qt->get_south(), qt->get_east(), lon)) {
76       qt->set_north(lat);
77       qt->set_west(lon);
78     } else if (ContainedByBox(lat, qt->get_south(), lon, qt->get_west())) {
79       qt->set_north(lat);
80       qt->set_east(lon);
81     } else {
82       return;  // target not contained by any child quadrant of qt.
83     }
84     // Fall through from above and recurse.
85     if (max_depth > 0) {
86       AlignBbox(qt, max_depth - 1);
87     }
88   }
89 
90   // This returns true if this Bbox is contained by the given Bbox.
ContainedByBbox(const Bbox & b)91   bool ContainedByBbox(const Bbox& b) const {
92     return ContainedByBox(b.get_north(), b.get_south(), b.get_east(),
93                           b.get_west());
94   }
95 
96   // This returns true of this Bbox is contained with the given bounds.
ContainedByBox(double north,double south,double east,double west)97   bool ContainedByBox(double north, double south,
98                       double east, double west) const {
99     return north >= north_ && south <= south_ && east >= east_ && west <= west_;
100   }
101 
102   // This returns true if the bbox contains the given latitude,longitude.
Contains(double latitude,double longitude)103   bool Contains(double latitude, double longitude) const {
104     return north_ >= latitude && south_ <= latitude &&
105            east_ >= longitude && west_ <= longitude;
106   }
107 
108   // This expands this Bbox to contain the given Bbox.
ExpandFromBbox(const Bbox & bbox)109   void ExpandFromBbox(const Bbox& bbox) {
110     ExpandLatitude(bbox.get_north());
111     ExpandLatitude(bbox.get_south());
112     ExpandLongitude(bbox.get_east());
113     ExpandLongitude(bbox.get_west());
114   }
115 
116   // This expands the bounding box to include the given latitude.
ExpandLatitude(double latitude)117   void ExpandLatitude(double latitude) {
118     if (latitude > north_) {
119       north_ = latitude;
120     }
121     if (latitude < south_) {
122       south_ = latitude;
123     }
124   }
125 
126   // This expands the bounding box to include the given longitude.
ExpandLongitude(double longitude)127   void ExpandLongitude(double longitude) {
128     if (longitude > east_) {
129       east_ = longitude;
130     }
131     if (longitude < west_) {
132       west_ = longitude;
133     }
134   }
135 
136   // This expands the bounding box to include the given latitude and longitude.
ExpandLatLon(double latitude,double longitude)137   void ExpandLatLon(double latitude, double longitude) {
138     ExpandLatitude(latitude);
139     ExpandLongitude(longitude);
140   }
141 
get_north()142   double get_north() const {
143     return north_;
144   }
get_south()145   double get_south() const {
146     return south_;
147   }
get_east()148   double get_east() const {
149     return east_;
150   }
get_west()151   double get_west() const {
152     return west_;
153   }
154 
155   // This returns the center of the bounding box.
GetCenter(double * latitude,double * longitude)156   void GetCenter(double* latitude, double* longitude) const {
157     if (latitude) {
158       *latitude = GetCenterLat();
159     }
160     if (longitude) {
161       *longitude = GetCenterLon();
162     }
163   }
164 
GetCenterLat()165   double GetCenterLat() const {
166     return (north_ + south_)/2.0;
167   }
168 
GetCenterLon()169   double GetCenterLon() const {
170     return (east_ + west_)/2.0;
171   }
172 
set_north(double n)173   void set_north(double n) {
174     north_ = n;
175   }
set_south(double s)176   void set_south(double s) {
177     south_ = s;
178   }
set_east(double e)179   void set_east(double e) {
180     east_ = e;
181   }
set_west(double w)182   void set_west(double w) {
183     west_ = w;
184   }
185 
186  private:
187   double north_, south_, east_, west_;
188 };
189 
190 }  // end namespace kmlengine
191 
192 #endif  // KML_ENGINE_BBOX_H__
193