MongoDB C++ Driver  legacy-1.1.2
geometry.h
Go to the documentation of this file.
1 /* Copyright 2014 MongoDB Inc.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
18 #pragma once
19 
20 #include <algorithm>
21 #include <limits>
22 #include <vector>
23 
24 #include "mongo/client/export_macros.h"
25 #include "mongo/db/jsobj.h"
26 #include "mongo/geo/boundingbox.h"
27 #include "mongo/geo/constants.h"
28 #include "mongo/geo/geoobj.h"
29 #include "mongo/util/assert_util.h"
30 
31 namespace mongo {
32 namespace geo {
33 
34 // forward declaration needed for Geometry's static helpers
35 template <typename TCoordinates>
36 class Point;
37 
38 template <typename TCoordinates>
39 class Geometry : public GeoObj<TCoordinates> {
40 protected:
41  static BSONElement getCoordsField(const BSONObj& bson);
42  static std::vector<double> parseCoords(const BSONElement& coordArr);
43  static std::vector<double> parseCoords(const BSONObj& bson);
44  static Point<TCoordinates> parsePoint(const BSONElement& coordArr);
45  static std::vector<Point<TCoordinates> > parsePointArray(
46  const std::vector<BSONElement>& pointArr);
47  static std::vector<Point<TCoordinates> > parseAllPoints(const BSONObj& bson);
48 
58  const std::vector<Point<TCoordinates> >& points);
59 
71  const std::vector<BoundingBox<TCoordinates> >& bboxes);
72 
84 
85 private:
86  static void findMinAndMaxCoordinatesOfDimension(const std::vector<Point<TCoordinates> >& points,
87  size_t dimension,
88  double* min,
89  double* max);
90 };
91 
92 template <typename TCoordinates>
94  BSONElement coordsField = bson.getField(kCoordsFieldName);
95  uassert(0,
96  "bson must contain a field \"coordinates\" of type Array",
97  !coordsField.eoo() && coordsField.type() == Array);
98  return coordsField;
99 }
100 
101 template <typename TCoordinates>
102 std::vector<double> Geometry<TCoordinates>::parseCoords(const BSONElement& coordArr) {
103  std::vector<BSONElement> coordElems = coordArr.Array();
104  std::vector<double> coords;
105  for (size_t i = 0; i < coordElems.size(); ++i)
106  coords.push_back(coordElems[i].Double());
107  return coords;
108 }
109 
110 template <typename TCoordinates>
111 std::vector<double> Geometry<TCoordinates>::parseCoords(const BSONObj& bson) {
112  return parseCoords(getCoordsField(bson));
113 }
114 
115 template <typename TCoordinates>
116 Point<TCoordinates> Geometry<TCoordinates>::parsePoint(const BSONElement& coordArr) {
117  TCoordinates pointCoords(parseCoords(coordArr));
118  return Point<TCoordinates>(pointCoords);
119 }
120 
121 template <typename TCoordinates>
122 std::vector<Point<TCoordinates> > Geometry<TCoordinates>::parsePointArray(
123  const std::vector<BSONElement>& pointArr) {
124  std::vector<Point<TCoordinates> > points;
125  for (size_t i = 0; i < pointArr.size(); ++i) {
126  points.push_back(parsePoint(pointArr[i]));
127  }
128  return points;
129 }
130 
131 template <typename TCoordinates>
132 std::vector<Point<TCoordinates> > Geometry<TCoordinates>::parseAllPoints(const BSONObj& bson) {
133  return parsePointArray(getCoordsField(bson).Array());
134 }
135 
136 template <typename TCoordinates>
138  const std::vector<Point<TCoordinates> >& points) {
139  // For a TCoordinates type with dimensions d1, d2, ..., dn,
140  // the bounding box of these points will have min coordinates
141  // whose d1 value is the minimum of all d1-axis values in points,
142  // whose d2 value is the minimum of all d2-axis values in points,
143  // and so on up through dn. Similarly for the max coordinates.
144  //
145  // So to compute the bounding box, we iterate through each dimension
146  // and find the min / max values in points for that dimension.
147  std::vector<double> minCoordComponents, maxCoordComponents;
148  for (size_t i = 0; i < TCoordinates::dimensionality(); ++i) {
149  double min, max;
150  findMinAndMaxCoordinatesOfDimension(points, i, &min, &max);
151  minCoordComponents.push_back(min);
152  maxCoordComponents.push_back(max);
153  }
154  TCoordinates minCoords(minCoordComponents);
155  TCoordinates maxCoords(maxCoordComponents);
156  return new BoundingBox<TCoordinates>(minCoords, maxCoords);
157 }
158 
159 template <typename TCoordinates>
161  const std::vector<Point<TCoordinates> >& points, size_t dimension, double* min, double* max) {
162  // Initialize min and max to the positive and negative double values
163  // farthest from 0, respectively. Note that we initialize max to
164  // -::max(). Initializing to ::min() is incorrect because it returns
165  // the smallest positive normalized double, which is still greater than
166  // every negative double (and coordinates can have negative values).
167  *min = std::numeric_limits<double>::max();
168  *max = -std::numeric_limits<double>::max();
169 
170  // Update min and max with the smallest and largest values for the given dimension.
171  for (size_t i = 0; i < points.size(); ++i) {
172  if (points[i][dimension] < *min)
173  *min = points[i][dimension];
174  if (points[i][dimension] > *max)
175  *max = points[i][dimension];
176  }
177 }
178 
179 template <typename TCoordinates>
181  const std::vector<BoundingBox<TCoordinates> >& bboxes) {
182  if (bboxes.empty())
183  return NULL;
184 
185  std::vector<double> minCoords = bboxes[0].getMin().getValues();
186  std::vector<double> maxCoords = bboxes[0].getMax().getValues();
187  for (size_t i = 1; i < bboxes.size(); ++i) {
188  std::vector<double> curMin = bboxes[i].getMin().getValues();
189  std::vector<double> curMax = bboxes[i].getMax().getValues();
190  for (size_t j = 0; j < curMin.size(); ++j) {
191  minCoords[j] = std::min(minCoords[j], curMin[j]);
192  maxCoords[j] = std::max(maxCoords[j], curMax[j]);
193  }
194  }
195 
196  TCoordinates globalMin(minCoords), globalMax(maxCoords);
197  return new BoundingBox<TCoordinates>(globalMin, globalMax);
198 }
199 
200 template <typename TCoordinates>
202  if (bson.hasField(kBoundingBoxFieldName))
203  return new BoundingBox<TCoordinates>(bson);
204  return NULL;
205 }
206 
207 } // namespace geo
208 } // namespace mongo
static BoundingBox< TCoordinates > * parseBoundingBox(const BSONObj &bson)
Parses the bounding box defined by the given geometry shape, represented in BSON. ...
Definition: geometry.h:201
bool hasField(const StringData &name) const
Definition: bsonobj.h:250
Utility functions for parsing numbers from strings.
Definition: compare_numbers.h:20
BSON classes.
Definition: geoobj.h:34
BSONType type() const
Returns the type of the element.
Definition: bsonelement.h:154
BSONElement getField(const StringData &name) const
Get the field of the specified name.
Represents a Point.
Definition: geometry.h:36
bool eoo() const
Indicates if it is the end-of-object element, which is present at the end of every BSON object...
Definition: bsonelement.h:172
an embedded array
Definition: bsontypes.h:50
BSONElement represents an "element" in a BSONObj.
Definition: bsonelement.h:55
Definition: geometry.h:39
C++ representation of a "BSON" object – that is, an extended JSON-style object in a binary represent...
Definition: bsonobj.h:78
static BoundingBox< TCoordinates > * computeBoundingBox(const std::vector< Point< TCoordinates > > &points)
Compute the bounding box around the given points.
Definition: geometry.h:137
Represents a bounding box.
Definition: boundingbox.h:67