예제 #1
0
bool BigSimplePolygon::Intersects(const S2Polyline& line) const {
    //
    // A loop intersects a line if line intersects the loop border or, if it doesn't, either
    // line is contained in the loop, or line is disjoint with the loop. So checking any
    // vertex of the line is sufficient.
    //
    // TODO: Make a general Polygon/Line relation tester which uses S2 primitives
    //
    return GetLineBorder().Intersects(&line) || _loop->Contains(line.vertex(0));
}
예제 #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;
    }
예제 #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;
}
예제 #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.
    }
예제 #5
0
파일: s2common.cpp 프로젝트: ChrisBg/mongo
 double dist(const S2Point& a, const S2Polyline& b) {
     int tmp;
     S1Angle angle(a, b.Project(a, &tmp));
     return angle.radians();
 }