blob: 96f90b64b594390b0e0b7d7d489d2de566550545 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <cmath>
#include <cstring>
#include "parquet/geospatial/util_internal.h"
#include "parquet/test_util.h"
namespace parquet::geospatial {
TEST(TestGeometryUtil, TestBoundingBox) {
BoundingBox box;
EXPECT_EQ(box, BoundingBox({kInf, kInf, kInf, kInf}, {-kInf, -kInf, -kInf, -kInf}));
EXPECT_EQ(box.ToString(),
"BoundingBox\n x: [inf, -inf]\n y: [inf, -inf]\n z: [inf, -inf]\n m: "
"[inf, -inf]\n");
BoundingBox box_xyzm({-1, -2, -3, -4}, {1, 2, 3, 4});
BoundingBox box_xy({-10, -20, kInf, kInf}, {10, 20, -kInf, -kInf});
BoundingBox box_xyz({kInf, kInf, -30, kInf}, {-kInf, -kInf, 30, -kInf});
BoundingBox box_xym({kInf, kInf, kInf, -40}, {-kInf, -kInf, -kInf, 40});
box_xyzm.Merge(box_xy);
EXPECT_EQ(box_xyzm, BoundingBox({-10, -20, -3, -4}, {10, 20, 3, 4}));
EXPECT_EQ(box_xyzm.ToString(),
"BoundingBox\n x: [-10, 10]\n y: [-20, 20]\n z: [-3, 3]\n m: "
"[-4, 4]\n");
box_xyzm.Merge(box_xyz);
EXPECT_EQ(box_xyzm, BoundingBox({-10, -20, -30, -4}, {10, 20, 30, 4}));
box_xyzm.Merge(box_xym);
EXPECT_EQ(box_xyzm, BoundingBox({-10, -20, -30, -40}, {10, 20, 30, 40}));
double nan_dbl = std::numeric_limits<double>::quiet_NaN();
BoundingBox box_nan({nan_dbl, nan_dbl, nan_dbl, nan_dbl},
{nan_dbl, nan_dbl, nan_dbl, nan_dbl});
box_xyzm.Merge(box_nan);
for (int i = 0; i < 4; i++) {
EXPECT_TRUE(std::isnan(box_xyzm.min[i]));
EXPECT_TRUE(std::isnan(box_xyzm.max[i]));
}
box_xyzm.Reset();
EXPECT_EQ(box_xyzm, BoundingBox());
}
TEST(TestGeometryUtil, TestBoundingBoxEquals) {
BoundingBox box_a({-1, -2, -3, -4}, {1, 2, 3, 4});
BoundingBox box_b({-1, -2, -3, -4}, {1, 2, 3, 4});
for (int i = 0; i < 4; i++) {
// Set one min component to another value and ensure inequality
box_b.min[i] = -1000;
EXPECT_NE(box_a, box_b);
// Reset the min component and ensure equality
box_b.min = box_a.min;
EXPECT_EQ(box_a, box_b);
// Set one max component to another value and ensure inequality
box_b.max[i] = -1000;
EXPECT_NE(box_a, box_b);
// Reset the max component and ensure equality
box_b.max = box_a.max;
EXPECT_EQ(box_a, box_b);
}
}
struct WKBTestCase {
WKBTestCase() = default;
WKBTestCase(GeometryType geometry_type, Dimensions dimensions,
const std::vector<uint8_t>& wkb, const std::vector<double>& box_values = {})
: geometry_type(geometry_type), dimensions(dimensions), wkb(wkb) {
std::array<double, 4> mins = {kInf, kInf, kInf, kInf};
std::array<double, 4> maxes{-kInf, -kInf, -kInf, -kInf};
if (dimensions == Dimensions::kXYM) {
mins = {box_values[0], box_values[1], kInf, box_values[2]};
maxes = {box_values[3], box_values[4], -kInf, box_values[5]};
} else {
size_t coord_size = box_values.size() / 2;
for (uint32_t i = 0; i < coord_size; i++) {
mins[i] = box_values[i];
maxes[i] = box_values[coord_size + i];
}
}
box = BoundingBox(mins, maxes);
}
WKBTestCase(const WKBTestCase& other) = default;
GeometryType geometry_type;
Dimensions dimensions;
std::vector<uint8_t> wkb;
BoundingBox box;
};
std::ostream& operator<<(std::ostream& os, const WKBTestCase& obj) {
uint32_t iso_wkb_geometry_type =
static_cast<int>(obj.dimensions) * 1000 + static_cast<int>(obj.geometry_type);
os << "WKBTestCase<" << iso_wkb_geometry_type << ">";
return os;
}
class WKBTestFixture : public ::testing::TestWithParam<WKBTestCase> {
protected:
WKBTestCase test_case;
};
TEST_P(WKBTestFixture, TestWKBBounderBounds) {
auto item = GetParam();
WKBGeometryBounder bounder;
EXPECT_EQ(bounder.Bounds(), BoundingBox());
ASSERT_NO_THROW(bounder.MergeGeometry(item.wkb));
EXPECT_EQ(bounder.Bounds(), item.box);
uint32_t wkb_type =
static_cast<int>(item.dimensions) * 1000 + static_cast<int>(item.geometry_type);
EXPECT_THAT(bounder.GeometryTypes(), ::testing::ElementsAre(::testing::Eq(wkb_type)));
bounder.Reset();
EXPECT_EQ(bounder.Bounds(), BoundingBox());
EXPECT_TRUE(bounder.GeometryTypes().empty());
}
TEST_P(WKBTestFixture, TestWKBBounderErrorForTruncatedInput) {
auto item = GetParam();
WKBGeometryBounder bounder;
// Make sure an error occurs for any version of truncated input to the bounder
for (size_t i = 0; i < item.wkb.size(); i++) {
SCOPED_TRACE(i);
ASSERT_THROW(bounder.MergeGeometry({item.wkb.data(), i}), ParquetException);
}
}
TEST_P(WKBTestFixture, TestWKBBounderErrorForInputWithTooManyBytes) {
auto item = GetParam();
WKBGeometryBounder bounder;
std::vector<uint8_t> wkb_with_extra_byte(item.wkb.size() + 1);
std::memcpy(wkb_with_extra_byte.data(), item.wkb.data(), item.wkb.size());
wkb_with_extra_byte[item.wkb.size()] = 0x00;
ASSERT_THROW(bounder.MergeGeometry(wkb_with_extra_byte), ParquetException);
}
INSTANTIATE_TEST_SUITE_P(
TestGeometryUtil, WKBTestFixture,
::testing::Values(
// POINT EMPTY
WKBTestCase(GeometryType::kPoint, Dimensions::kXY,
{0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f},
{kInf, kInf, -kInf, -kInf}),
// POINT (30 10)
WKBTestCase(GeometryType::kPoint, Dimensions::kXY,
{0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40},
{30, 10, 30, 10}),
// POINT Z (30 10 40)
WKBTestCase(GeometryType::kPoint, Dimensions::kXYZ,
{0x01, 0xe9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40},
{30, 10, 40, 30, 10, 40}),
// POINT M (30 10 300)
WKBTestCase(GeometryType::kPoint, Dimensions::kXYM,
{0x01, 0xd1, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40},
{30, 10, 300, 30, 10, 300}),
// POINT ZM (30 10 40 300)
WKBTestCase(GeometryType::kPoint, Dimensions::kXYZM,
{0x01, 0xb9, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40},
{30, 10, 40, 300, 30, 10, 40, 300}),
// POINT (30 10) (big endian)
WKBTestCase(GeometryType::kPoint, Dimensions::kXY,
{0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x40, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{30, 10, 30, 10}),
// LINESTRING EMPTY
WKBTestCase(GeometryType::kLinestring, Dimensions::kXY,
{0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{kInf, kInf, -kInf, -kInf}),
// LINESTRING (30 10, 10 30, 40 40)
WKBTestCase(GeometryType::kLinestring, Dimensions::kXY,
{0x01, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40},
{10, 10, 40, 40}),
// LINESTRING Z (30 10 40, 10 30 40, 40 40 80)
WKBTestCase(GeometryType::kLinestring, Dimensions::kXYZ,
{0x01, 0xea, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x54, 0x40},
{10, 10, 40, 40, 40, 80}),
// LINESTRING M (30 10 300, 10 30 300, 40 40 1600)
WKBTestCase(GeometryType::kLinestring, Dimensions::kXYM,
{0x01, 0xd2, 0x07, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
0x72, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x99, 0x40},
{10, 10, 300, 40, 40, 1600}),
// LINESTRING ZM (30 10 40 300, 10 30 40 300, 40 40 80 1600)
WKBTestCase(GeometryType::kLinestring, Dimensions::kXYZM,
{0x01, 0xba, 0x0b, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x99, 0x40},
{10, 10, 40, 300, 40, 40, 80, 1600}),
// LINESTRING (30 10, 10 30, 40 40) (big endian)
WKBTestCase(GeometryType::kLinestring, Dimensions::kXY,
{0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x40,
0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x24, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x24, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{10, 10, 40, 40}),
// POLYGON EMPTY
WKBTestCase(GeometryType::kPolygon, Dimensions::kXY,
{0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{kInf, kInf, -kInf, -kInf}),
// POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))
WKBTestCase(GeometryType::kPolygon, Dimensions::kXY,
{0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x24, 0x40},
{10, 10, 40, 40}),
// POLYGON Z ((30 10 40, 40 40 80, 20 40 60, 10 20 30, 30 10 40))
WKBTestCase(
GeometryType::kPolygon, Dimensions::kXYZ,
{0x01, 0xeb, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x44, 0x40},
{10, 10, 30, 40, 40, 80}),
// POLYGON M ((30 10 300, 40 40 1600, 20 40 800, 10 20 200, 30 10 300))
WKBTestCase(
GeometryType::kPolygon, Dimensions::kXYM,
{0x01, 0xd3, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x69, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0x72, 0x40},
{10, 10, 200, 40, 40, 1600}),
// POLYGON ZM ((30 10 40 300, 40 40 80 1600, 20 40 60 800, 10 20 30 200, 30 10 40
// 300))
WKBTestCase(
GeometryType::kPolygon, Dimensions::kXYZM,
{0x01, 0xbb, 0x0b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0xc0, 0x72, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x54, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x89, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0xc0, 0x72, 0x40},
{10, 10, 30, 200, 40, 40, 80, 1600}),
// MULTIPOINT EMPTY
WKBTestCase(GeometryType::kMultiPoint, Dimensions::kXY,
{0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{kInf, kInf, -kInf, -kInf}),
// MULTIPOINT ((30 10))
WKBTestCase(GeometryType::kMultiPoint, Dimensions::kXY,
{0x01, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40},
{30, 10, 30, 10}),
// MULTIPOINT Z ((30 10 40))
WKBTestCase(GeometryType::kMultiPoint, Dimensions::kXYZ,
{0x01, 0xec, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0xe9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40},
{30, 10, 40, 30, 10, 40}),
// MULTIPOINT M ((30 10 300))
WKBTestCase(GeometryType::kMultiPoint, Dimensions::kXYM,
{0x01, 0xd4, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0xd1, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40},
{30, 10, 300, 30, 10, 300}),
// MULTIPOINT ZM ((30 10 40 300))
WKBTestCase(GeometryType::kMultiPoint, Dimensions::kXYZM,
{0x01, 0xbc, 0x0b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0xb9, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0xc0, 0x72, 0x40},
{30, 10, 40, 300, 30, 10, 40, 300}),
// MULTILINESTRING EMPTY
WKBTestCase(GeometryType::kMultiLinestring, Dimensions::kXY,
{0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{kInf, kInf, -kInf, -kInf}),
// MULTILINESTRING ((30 10, 10 30, 40 40))
WKBTestCase(GeometryType::kMultiLinestring, Dimensions::kXY,
{0x01, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02,
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40},
{10, 10, 40, 40}),
// MULTILINESTRING Z ((30 10 40, 10 30 40, 40 40 80))
WKBTestCase(
GeometryType::kMultiLinestring, Dimensions::kXYZ,
{0x01, 0xed, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0xea, 0x03, 0x00,
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x40},
{10, 10, 40, 40, 40, 80}),
// MULTILINESTRING M ((30 10 300, 10 30 300, 40 40 1600))
WKBTestCase(
GeometryType::kMultiLinestring, Dimensions::kXYM,
{0x01, 0xd5, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0xd2, 0x07, 0x00,
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0x72, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x72,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x40},
{10, 10, 300, 40, 40, 1600}),
// MULTILINESTRING ZM ((30 10 40 300, 10 30 40 300, 40 40 80 1600))
WKBTestCase(
GeometryType::kMultiLinestring, Dimensions::kXYZM,
{0x01, 0xbd, 0x0b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0xba, 0x0b, 0x00,
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0xc0, 0x72, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x54, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x40},
{10, 10, 40, 300, 40, 40, 80, 1600}),
// MULTIPOLYGON EMPTY
WKBTestCase(GeometryType::kMultiPolygon, Dimensions::kXY,
{0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{kInf, kInf, -kInf, -kInf}),
// MULTIPOLYGON (((30 10, 40 40, 20 40, 10 20, 30 10)))
WKBTestCase(
GeometryType::kMultiPolygon, Dimensions::kXY,
{0x01, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40},
{10, 10, 40, 40}),
// MULTIPOLYGON Z (((30 10 40, 40 40 80, 20 40 60, 10 20 30, 30 10 40)))
WKBTestCase(
GeometryType::kMultiPolygon, Dimensions::kXYZ,
{0x01, 0xee, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0xeb, 0x03, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x54, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x4e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40},
{10, 10, 30, 40, 40, 80}),
// MULTIPOLYGON M (((30 10 300, 40 40 1600, 20 40 800, 10 20 200, 30 10 300)))
WKBTestCase(
GeometryType::kMultiPolygon, Dimensions::kXYM,
{0x01, 0xd6, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0xd3, 0x07, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x99, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x89, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40},
{10, 10, 200, 40, 40, 1600}),
// MULTIPOLYGON ZM (((30 10 40 300, 40 40 80 1600, 20 40 60 800, 10 20 30 200, 30
// 10 40 300)))
WKBTestCase(GeometryType::kMultiPolygon, Dimensions::kXYZM,
{0x01, 0xbe, 0x0b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0xbb,
0x0b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x34, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0xc0, 0x72, 0x40},
{10, 10, 30, 200, 40, 40, 80, 1600}),
// GEOMETRYCOLLECTION EMPTY
WKBTestCase(GeometryType::kGeometryCollection, Dimensions::kXY,
{0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{kInf, kInf, -kInf, -kInf}),
// GEOMETRYCOLLECTION (POINT (30 10))
WKBTestCase(GeometryType::kGeometryCollection, Dimensions::kXY,
{0x01, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40},
{30, 10, 30, 10}),
// GEOMETRYCOLLECTION Z (POINT Z (30 10 40))
WKBTestCase(GeometryType::kGeometryCollection, Dimensions::kXYZ,
{0x01, 0xef, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0xe9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40},
{30, 10, 40, 30, 10, 40}),
// GEOMETRYCOLLECTION M (POINT M (30 10 300))
WKBTestCase(GeometryType::kGeometryCollection, Dimensions::kXYM,
{0x01, 0xd7, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0xd1, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40},
{30, 10, 300, 30, 10, 300}),
// GEOMETRYCOLLECTION ZM (POINT ZM (30 10 40 300))
WKBTestCase(GeometryType::kGeometryCollection, Dimensions::kXYZM,
{0x01, 0xbf, 0x0b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0xb9, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0xc0, 0x72, 0x40},
{30, 10, 40, 300, 30, 10, 40, 300})));
struct MakeWKBPointTestCase {
std::vector<double> xyzm;
bool has_z{};
bool has_m{};
};
std::ostream& operator<<(std::ostream& os, const MakeWKBPointTestCase& obj) {
os << "MakeWKBPointTestCase<has_z=" << obj.has_z << ", has_m=" << obj.has_m << ">";
return os;
}
class MakeWKBPointTestFixture : public testing::TestWithParam<MakeWKBPointTestCase> {};
TEST_P(MakeWKBPointTestFixture, MakeWKBPoint) {
const auto& param = GetParam();
std::string wkb = test::MakeWKBPoint(param.xyzm, param.has_z, param.has_m);
WKBGeometryBounder bounder;
ASSERT_NO_THROW(bounder.MergeGeometry(wkb));
const BoundingBox::XYZM& mins = bounder.Bounds().min;
EXPECT_DOUBLE_EQ(param.xyzm[0], mins[0]);
EXPECT_DOUBLE_EQ(param.xyzm[1], mins[1]);
if (param.has_z) {
EXPECT_DOUBLE_EQ(param.xyzm[2], mins[2]);
} else {
EXPECT_TRUE(std::isinf(mins[2]));
}
if (param.has_m) {
EXPECT_DOUBLE_EQ(param.xyzm[3], mins[3]);
} else {
EXPECT_TRUE(std::isinf(mins[3]));
}
}
INSTANTIATE_TEST_SUITE_P(
TestGeometryUtil, MakeWKBPointTestFixture,
::testing::Values(MakeWKBPointTestCase{{30, 10, 40, 300}, false, false},
MakeWKBPointTestCase{{30, 10, 40, 300}, true, false},
MakeWKBPointTestCase{{30, 10, 40, 300}, false, true},
MakeWKBPointTestCase{{30, 10, 40, 300}, true, true}));
} // namespace parquet::geospatial