// Verify that odd polygons (huge or "narrow") behave as we expect.
// Note that since 2dsphere is spherical, polygons that seem narrow are actually
// rather wide if their latitude (or longitude) range is large.
var t = db.geo_s2oddshapes
t.drop()
t.ensureIndex( { geo : "2dsphere" } );

var testPoint = {
    name: "origin",
    geo: {
        type: "Point",
        coordinates: [0.0, 0.0]
    }
};

var testHorizLine = {
    name: "horiz",
    geo: {
        type: "LineString",
        coordinates: [[-2.0, 10.0], [2.0, 10.0]]
    }
};

var testVertLine = {
    name: "vert",
    geo: {
        type: "LineString",
        coordinates: [[10.0, -2.0], [10.0, 2.0]]
    }
};

t.insert(testPoint);
t.insert(testHorizLine);
t.insert(testVertLine);

//Test a poly that runs vertically all the way along the meridian.

var tallPoly = {type: "Polygon",
    coordinates: [
        [[1.0, 89.0], [-1.0, 89.0], [-1.0, -89.0], [1.0, -89.0], [1.0, 89.0]]
    ]};
//We expect that the testPoint (at the origin) will be within this poly.
var result = t.find({geo: {$within: {$geometry: tallPoly}}});
assert.eq(result.itcount(), 1);
var result = t.find({geo: {$within: {$geometry: tallPoly}}});
assert.eq(result[0].name, 'origin');

//We expect that the testPoint, and the testHorizLine should geoIntersect
//with this poly.
result = t.find({geo: {$geoIntersects: {$geometry: tallPoly}}});
assert.eq(result.itcount(), 2);
result = t.find({geo: {$geoIntersects: {$geometry: tallPoly}}});

//Test a poly that runs horizontally along the equator.

var longPoly = {type: "Polygon",
    coordinates: [
        [[89.0, 1.0], [-89.0, 1.0], [-89.0, -1.0], [89.0, -1.0], [89.0, 1.0]]
    ]};

// Thanks to spherical geometry, this poly contains most of the hemisphere.
result = t.find({geo: {$within: {$geometry: longPoly}}});
assert.eq(result.itcount(), 3);
result = t.find({geo: {$geoIntersects: {$geometry: longPoly}}});
assert.eq(result.itcount(), 3);

//Test a poly that is the size of half the earth.

t.drop()
t.ensureIndex( { geo : "2dsphere" } );

var insidePoint = {
    name: "inside",
    geo: {
        type: "Point",
        name: "inside",
        coordinates: [100.0, 0.0]
    }
};

var outsidePoint = {
    name: "inside",
    geo: {
        type: "Point",
        name: "inside",
        coordinates: [-100.0, 0.0]
    }
};

t.insert(insidePoint);
t.insert(outsidePoint);

var largePoly = {type: "Polygon",
    coordinates: [
        [[0.0, -90.0], [0.0, 90.0], [180.0, 0], [0.0, -90.0]]
    ]};

result = t.find({geo: {$within: {$geometry: largePoly}}});
assert.eq(result.itcount(), 1);
result = t.find({geo: {$within: {$geometry: largePoly}}});
var point = result[0]
assert.eq(point.name, 'inside');

//Test a poly that is very small.  A couple meters around.

t.drop()
t.ensureIndex( { geo : "2dsphere" } );

insidePoint = {
    name: "inside",
    geo: {
        type: "Point",
        name: "inside",
        coordinates: [0.01, 0.0]
    }};

outsidePoint = {
    name: "inside",
    geo: {
        type: "Point",
        name: "inside",
        coordinates: [0.2, 0.0]
    }};

t.insert(insidePoint);
t.insert(outsidePoint);

smallPoly = {type: "Polygon",
    coordinates: [
        [[0.0, -0.01], [0.015, -0.01], [0.015, 0.01], [0.0, 0.01], [0.0, -0.01]]
    ]};

result = t.find({geo: {$within: {$geometry: smallPoly}}});
assert.eq(result.itcount(), 1);
result = t.find({geo: {$within: {$geometry: smallPoly}}});
point = result[0]
assert.eq(point.name, 'inside');

