Esempio n. 1
0
    // Get the index keys for elements that are GeoJSON.
    void S2AccessMethod::getGeoKeys(const BSONElementSet& elements, BSONObjSet* out) const {
        S2RegionCoverer coverer;
        _params.configureCoverer(&coverer);

        // See here for GeoJSON format: geojson.org/geojson-spec.html
        for (BSONElementSet::iterator i = elements.begin(); i != elements.end(); ++i) {
            uassert(16754, "Can't parse geometry from element: " + i->toString(),
                    i->isABSONObj());
            const BSONObj &obj = i->Obj();

            vector<string> cells;
            S2Polyline line;
            S2Cell point;
            // We only support GeoJSON polygons.  Why?:
            // 1. we don't automagically do WGS84/flat -> WGS84, and
            // 2. the old polygon format must die.
            if (GeoParser::isGeoJSONPolygon(obj)) {
                S2Polygon polygon;
                GeoParser::parseGeoJSONPolygon(obj, &polygon);
                keysFromRegion(&coverer, polygon, &cells);
            } else if (GeoParser::parseLineString(obj, &line)) {
                keysFromRegion(&coverer, line, &cells);
            } else if (GeoParser::parsePoint(obj, &point)) {
                S2CellId parent(point.id().parent(_params.finestIndexedLevel));
                cells.push_back(parent.toString());
            } else {
                uasserted(16755, "Can't extract geo keys from object, malformed geometry?:"
                        + obj.toString());
            }
            uassert(16756, "Unable to generate keys for (likely malformed) geometry: "
                    + obj.toString(),
                    cells.size() > 0);

            for (vector<string>::const_iterator it = cells.begin(); it != cells.end(); ++it) {
                BSONObjBuilder b;
                b.append("", *it);
                out->insert(b.obj());
            }
        }

        if (0 == out->size()) {
            BSONObjBuilder b;
            b.appendNull("");
            out->insert(b.obj());
        }
    }
Esempio n. 2
0
    double S2NearCursor::distanceBetween(const QueryGeometry &field, const BSONObj &obj) {
        S2Point us = field.getCentroid();
        S2Point them;

        S2Polygon polygon;
        S2Polyline line;
        S2Cell point;
        if (GeoJSONParser::parsePolygon(obj, &polygon)) {
            them = polygon.Project(us);
        } else if (GeoJSONParser::parseLineString(obj, &line)) {
            int tmp;
            them = line.Project(us, &tmp);
        } else if (GeoJSONParser::parsePoint(obj, &point)) {
            them = point.GetCenter();
        } else {
            warning() << "unknown geometry: " << obj.toString();
        }
        S1Angle angle(us, them);
        return angle.radians() * _params.radius;
    }
Esempio n. 3
0
double S2NearIndexCursor::distanceTo(const BSONObj& obj) {
    const S2Point &us = _nearQuery.centroid;
    S2Point them;

    S2Polygon polygon;
    S2Polyline line;
    S2Cell point;
    if (GeoParser::parsePolygon(obj, &polygon)) {
        them = polygon.Project(us);
    } else if (GeoParser::parseLineString(obj, &line)) {
        int tmp;
        them = line.Project(us, &tmp);
    } else if (GeoParser::parsePoint(obj, &point)) {
        them = point.GetCenter();
    } else {
        warning() << "unknown geometry: " << obj.toString();
        return numeric_limits<double>::max();
    }
    S1Angle angle(us, them);
    return angle.radians() * _params.radius;
}
Esempio n. 4
0
    // Fill _results with the next shell of results.  We may have to search several times to do
    // this.  If _results.empty() after calling fillResults, there are no more possible results.
    void S2NearCursor::fillResults() {
        verify(_results.empty());
        if (_innerRadius >= _outerRadius) { return; }
        if (_innerRadius > _maxDistance) { return; }

        // We iterate until 1. our search radius is too big or 2. we find results.
        do {
            // Some of these arguments are opaque, look at the definitions of the involved classes.
            FieldRangeSet frs(_details->parentNS().c_str(), makeFRSObject(), false, false);
            shared_ptr<FieldRangeVector> frv(new FieldRangeVector(frs, _specForFRV, 1));
            scoped_ptr<BtreeCursor> cursor(BtreeCursor::make(nsdetails(_details->parentNS().c_str()),
                                                             *_details, frv, 0, 1));

            // Do the actual search through this annulus.
            size_t considered = 0;
            for (; cursor->ok(); cursor->advance()) {
                ++_nscanned;
                ++considered;

                MatchDetails details;
                bool matched = _matcher->matchesCurrent(cursor.get(), &details);
                if (!matched) { continue; }

                const BSONObj& indexedObj = cursor->currLoc().obj();

                size_t geoFieldsInRange = 0;
                double minMatchingDistance = 1e20;

                // Calculate the distance from our query point(s) to the geo field(s).
                for (size_t i = 0; i < _fields.size(); ++i) {
                    const GeoQueryField& field = _fields[i];

                    BSONElementSet geoFieldElements;
                    indexedObj.getFieldsDotted(field.field, geoFieldElements);
                    if (geoFieldElements.empty()) { continue; }

                    S2Point us = field.getCentroid();
                    for (BSONElementSet::iterator oi = geoFieldElements.begin();
                            oi != geoFieldElements.end(); ++oi) {
                        const BSONObj &geoObj = oi->Obj();
                        double dist = -1;
                        S2Point them;
                        if (GeoJSONParser::isPolygon(geoObj)) {
                            S2Polygon shape;
                            GeoJSONParser::parsePolygon(geoObj, &shape);
                            them = shape.Project(us);
                        } else if (GeoJSONParser::isLineString(geoObj)) {
                            S2Polyline shape;
                            GeoJSONParser::parseLineString(geoObj, &shape);
                            int tmp;
                            them = shape.Project(us, &tmp);
                        } else if (GeoJSONParser::isPoint(geoObj)) {
                            S2Cell point;
                            GeoJSONParser::parsePoint(geoObj, &point);
                            them = point.GetCenter();
                        }
                        S1Angle angle(us, them);
                        dist = angle.radians() * _params.radius;
                        if (dist >= _innerRadius && dist <= _outerRadius) {
                            ++geoFieldsInRange;
                            minMatchingDistance = min(dist, minMatchingDistance);
                        }
                    }
                }
                if (_fields.size() == geoFieldsInRange) {
                    if (_returned.end() == _returned.find(cursor->currLoc())) {
                        _results.push(Result(cursor->currLoc(), cursor->currKey(), minMatchingDistance));
                    }
                }
            }
            if (_results.empty()) {
                _radiusIncrement *= 2;
                nextAnnulus();
            }
        } while (_results.empty() && _innerRadius < M_PI  * _params.radius);
        // TODO: consider shrinking _radiusIncrement if _results.size() meets some criteria.
    }