Example #1
0
// Orders Bounds by their midpoint.  This is really only useful if the bounds
// are arranged in a grid and are of equal size (like during a MetaQuery).
inline bool operator<(const Bounds& lhs, const Bounds& rhs)
{
    const auto& lhsMid(lhs.mid());
    const auto& rhsMid(rhs.mid());

    return
        (lhsMid.x < rhsMid.x) ||
        (lhsMid.x == rhsMid.x && lhsMid.y < rhsMid.y) ||
        (lhsMid.x == rhsMid.x && lhsMid.y == rhsMid.y && lhsMid.z < rhsMid.z);
}
Example #2
0
TEST(Infer, Reprojection)
{
    const std::string path(test::dataPath() + "ellipsoid-single-nyc");
    const std::string badPath(path + "-wrong-srs");

    const Bounds utmBounds(
            Point(580621.19214, 4504618.31537, -50),
            Point(580850.55166, 4504772.01557, 50));

    {
        Inference inference(path);
        inference.go();
        ASSERT_TRUE(inference.done());

        checkBoundsNear(inference.bounds(), nycBounds);

        const Delta* d(inference.delta());
        ASSERT_TRUE(d);
        EXPECT_EQ(d->scale(), Scale(.01));
        checkPointNear(d->offset(), nycCenter, 20.0);
    }

    {
        const Reprojection r("", "EPSG:26918");
        Inference inference(path, &r);
        inference.go();
        ASSERT_TRUE(inference.done());

        checkBoundsNear(inference.bounds(), utmBounds);

        const Delta* d(inference.delta());
        ASSERT_TRUE(d);
        EXPECT_EQ(d->scale(), Scale(.01));
        checkPointNear(d->offset(), utmBounds.mid(), 20.0);
    }

    {
        const Reprojection r("EPSG:3857", "EPSG:26918", true);
        Inference inference(badPath, &r);
        inference.go();
        ASSERT_TRUE(inference.done());

        const Delta* d(inference.delta());
        ASSERT_TRUE(d);
        EXPECT_EQ(d->scale(), Scale(.01));
        checkPointNear(d->offset(), utmBounds.mid(), 20.0);
    }
}
Example #3
0
    // Returns true if these Bounds share any area in common with another.
    bool overlaps(const Bounds& other, bool force2d = false) const
    {
        Point otherMid(other.mid());

        return
            std::abs(m_mid.x - otherMid.x) <=
                width() / 2.0 + other.width() / 2.0 &&
            std::abs(m_mid.y - otherMid.y) <=
                depth() / 2.0 + other.depth() / 2.0 &&
            (force2d || std::abs(m_mid.z - otherMid.z) <=
                height() / 2.0 + other.height() / 2.0);
    }
Example #4
0
Transformation Inference::calcTransformation()
{
    // We have our full bounds and info for all files in EPSG:4978.  Now:
    //      1) determine a transformation matrix so outward is up
    //      2) transform our file info and bounds accordingly

    // We're going to use our Point class to represent Vectors in this function.
    using Vector = Point;

    // Let O = (0,0,0) be the origin (center of the earth).  This is our native
    // projection system with unit vectors i=(1,0,0), j=(0,1,0), and k=(0,0,1).

    // Let P = bounds.mid(), our transformed origin point.

    // Let S be the sphere centered at O with radius ||P||.

    // Let T = the plane tangent to S at P.

    // Now, we can define our desired coordinate system:
    //
    // k' = "up" = normalized vector O->P
    //
    // j' = "north" = the normalized projected vector onto tangent plane T, of
    // the north pole vector (0,0,1) from the non-transformed coordinate system.
    //
    // i' = "east" = j' cross k'

    // Determine normalized vector k'.
    const Point p(bounds().mid());
    const Vector up(Vector::normalize(p));

    // Project the north pole vector onto k'.
    const Vector northPole(0, 0, 1);
    const double dot(Point::dot(up, northPole));
    const Vector proj(up * dot);

    // Subtract that projection from the north pole vector to project it onto
    // tangent plane T - then normalize to determine vector j'.
    const Vector north(Vector::normalize(northPole - proj));

    // Finally, calculate j' cross k' to determine i', which should turn out to
    // be normalized since the inputs are orthogonal and normalized.
    const Vector east(Vector::cross(north, up));

    // First, rotate so up is outward from the center of the earth.
    const std::vector<double> rotation
    {
        east.x,     east.y,     east.z,     0,
        north.x,    north.y,    north.z,    0,
        up.x,       up.y,       up.z,       0,
        0,          0,          0,          1
    };

    // Then, translate around our current best guess at a center point.  This
    // should be close enough to the origin for reasonable precision.
    const Bounds tentativeCenter(
            m_executor.transform(bounds(), rotation));
    const std::vector<double> translation
    {
        1, 0, 0, -tentativeCenter.mid().x,
        0, 1, 0, -tentativeCenter.mid().y,
        0, 0, 1, -tentativeCenter.mid().z,
        0, 0, 0, 1
    };

    return matrix::multiply(translation, rotation);
}