Exemple #1
0
    GeoSearch::GeoSearch(Collection* collection,
            TwoDAccessMethod* accessMethod,
            const Point& startPt,
            int numWanted,
            MatchExpression* filter,
            double maxDistance,
            GeoDistType type)
        : GeoHopper(collection, accessMethod, numWanted, startPt, filter, maxDistance, type),
        _start(accessMethod->getParams().geoHashConverter->hash(startPt.x, startPt.y)),
        _numWanted(numWanted),
        _type(type),
        _params(accessMethod->getParams()) {

            _nscanned = 0;
            _found = 0;

            if(_maxDistance < 0){
                _scanDistance = numeric_limits<double>::max();
            } else if (type == GEO_PLANE) {
                _scanDistance = maxDistance + _params.geoHashConverter->getError();
            } else if (type == GEO_SPHERE) {
                checkEarthBounds(startPt);
                // TODO: consider splitting into x and y scan distances
                _scanDistance = computeXScanDistance(startPt.y,
                        rad2deg(_maxDistance) + _params.geoHashConverter->getError());
            }

            verify(_scanDistance > 0);
        }
Exemple #2
0
    GeoCircleBrowse::GeoCircleBrowse(const TwoDParams& params, TwoDAccessMethod* accessMethod)
        : GeoBrowse(accessMethod, "circle", params.filter, params.gq.uniqueDocs()) {

        _converter = accessMethod->getParams().geoHashConverter;

        const CapWithCRS& cap = *params.gq.getGeometry()._cap;

        _startPt = cap.circle.center;
        _start = _converter->hash(_startPt);
        _maxDistance = cap.circle.radius;

        if (FLAT == cap.crs) {
            _type = GEO_PLANE;
            xScanDistance = _maxDistance + _converter->getError();
            yScanDistance = _maxDistance + _converter->getError();
        } else {
            _type = GEO_SPHERE;
            yScanDistance = rad2deg(_maxDistance) + _converter->getError();
            xScanDistance = computeXScanDistance(_startPt.y, yScanDistance);
        }

        // Bounding box includes fudge factor.
        // TODO:  Is this correct, since fudge factor may be spherically transformed?
        _bBox._min = Point(_startPt.x - xScanDistance, _startPt.y - yScanDistance);
        _bBox._max = Point(_startPt.x + xScanDistance, _startPt.y + yScanDistance);

        ok();
    }
    static R2Annulus projectBoundsToTwoDDegrees(R2Annulus sphereBounds) {

        const double outerDegrees = rad2deg(sphereBounds.getOuter() / kRadiusOfEarthInMeters);
        const double innerDegrees = rad2deg(sphereBounds.getInner() / kRadiusOfEarthInMeters);
        const double maxErrorDegrees = computeXScanDistance(sphereBounds.center().y, outerDegrees);

        return R2Annulus(sphereBounds.center(),
                         max(0.0, innerDegrees - maxErrorDegrees),
                         outerDegrees + maxErrorDegrees);
    }
Exemple #4
0
    /**
     * 2d indices don't handle wrapping so we can't use them for queries that wrap.
     */
    static bool twoDWontWrap(const Circle& circle, const IndexEntry& index) {

        GeoHashConverter::Parameters hashParams;
        Status paramStatus = GeoHashConverter::parseParameters(index.infoObj, &hashParams);
        verify(paramStatus.isOK()); // we validated the params on index creation

        GeoHashConverter conv(hashParams);

        // FYI: old code used flat not spherical error.
        double yscandist = rad2deg(circle.radius) + conv.getErrorSphere();
        double xscandist = computeXScanDistance(circle.center.y, yscandist);
        bool ret = circle.center.x + xscandist < 180
                && circle.center.x - xscandist > -180
                && circle.center.y + yscandist < 90
                && circle.center.y - yscandist > -90;
        return ret;
    }
Exemple #5
0
    /**
     * 2d indices don't handle wrapping so we can't use them for queries that wrap.
     */
    static bool twoDWontWrap(const Circle& circle, const IndexEntry& index) {
        // XXX: where does this really belong
        GeoHashConverter::Parameters params;
        params.bits = static_cast<unsigned>(fieldWithDefault(index.infoObj, "bits", 26));
        params.max = fieldWithDefault(index.infoObj, "max", 180.0);
        params.min = fieldWithDefault(index.infoObj, "min", -180.0);
        double numBuckets = (1024 * 1024 * 1024 * 4.0);
        params.scaling = numBuckets / (params.max - params.min);

        GeoHashConverter conv(params);

        // FYI: old code used flat not spherical error.
        double yscandist = rad2deg(circle.radius) + conv.getErrorSphere();
        double xscandist = computeXScanDistance(circle.center.y, yscandist);
        bool ret = circle.center.x + xscandist < 180
                && circle.center.x - xscandist > -180
                && circle.center.y + yscandist < 90
                && circle.center.y - yscandist > -90;
        return ret;
    }
Exemple #6
0
    void GeoSearch::exec() {
        if(_numWanted == 0) return;

        /*
         * Search algorithm
         * 1) use geohash prefix to find X items
         * 2) compute max distance from want to an item
         * 3) find optimal set of boxes that complete circle
         * 4) use regular btree cursors to scan those boxes
         */

        // Part 1
        {
            do {
                long long f = found();
                verify(f <= 0x7fffffff);
                fillStack(maxPointsHeuristic, _numWanted - static_cast<int>(f), true);
                processExtraPoints();
            } while(_state != DONE && _state != DONE_NEIGHBOR &&
                    found() < _numWanted &&
                    (!_prefix.constrains() ||
                     _params.geoHashConverter->sizeEdge(_prefix) <= _scanDistance));

            // If we couldn't scan or scanned everything, we're done
            if(_state == DONE){
                expandEndPoints();
                return;
            }
        }

        // Part 2
        {
            // Find farthest distance for completion scan
            double farDist = farthest();
            if(found() < _numWanted) {
                // Not enough found in Phase 1
                farDist = _scanDistance;
            }
            else if (_type == GEO_PLANE) {
                // Enough found, but need to search neighbor boxes
                farDist += _params.geoHashConverter->getError();
            }
            else if (_type == GEO_SPHERE) {
                // Enough found, but need to search neighbor boxes
                farDist = std::min(_scanDistance,
                        computeXScanDistance(_near.y,
                            rad2deg(farDist))
                        + 2 * _params.geoHashConverter->getError());
            }
            verify(farDist >= 0);

            // Find the box that includes all the points we need to return
            _want = Box(_near.x - farDist, _near.y - farDist, farDist * 2);

            // Remember the far distance for further scans
            _scanDistance = farDist;

            // Reset the search, our distances have probably changed
            if(_state == DONE_NEIGHBOR){
                _state = DOING_EXPAND;
                _neighbor = -1;
            }

            // Do regular search in the full region
            do {
                fillStack(maxPointsHeuristic);
                processExtraPoints();
            }
            while(_state != DONE);
        }

        expandEndPoints();
    }