This commit is contained in:
Nikita Mikhailov 2021-02-15 22:22:13 +03:00 committed by Nikita Mikhaylov
parent 2cce75808b
commit 05cf1b5bc5
21 changed files with 147 additions and 360 deletions

View File

@ -26,8 +26,9 @@ void DataTypeCustomPointSerialization::deserializeText(
DataTypePtr DataTypeCustomPointSerialization::nestedDataType()
{
static auto data_type = DataTypePtr(std::make_unique<DataTypeTuple>(
DataTypes({std::make_unique<DataTypeFloat64>(), std::make_unique<DataTypeFloat64>()})));
static const auto data_type = std::make_shared<const DataTypeTuple>(
DataTypes{std::make_shared<const DataTypeFloat64>(), std::make_shared<const DataTypeFloat64>()}
);
return data_type;
}
@ -45,7 +46,7 @@ void DataTypeCustomRingSerialization::deserializeText(
DataTypePtr DataTypeCustomRingSerialization::nestedDataType()
{
static auto data_type = DataTypePtr(std::make_unique<DataTypeArray>(DataTypeCustomPointSerialization::nestedDataType()));
static auto data_type = std::make_shared<const DataTypeArray>(DataTypeCustomPointSerialization::nestedDataType());
return data_type;
}
@ -63,7 +64,7 @@ void DataTypeCustomPolygonSerialization::deserializeText(
DataTypePtr DataTypeCustomPolygonSerialization::nestedDataType()
{
static auto data_type = DataTypePtr(std::make_unique<DataTypeArray>(DataTypeCustomRingSerialization::nestedDataType()));
static auto data_type = std::make_shared<const DataTypeArray>(DataTypeCustomRingSerialization::nestedDataType());
return data_type;
}
@ -81,7 +82,7 @@ void DataTypeCustomMultiPolygonSerialization::deserializeText(
DataTypePtr DataTypeCustomMultiPolygonSerialization::nestedDataType()
{
static auto data_type = DataTypePtr(std::make_unique<DataTypeArray>(DataTypeCustomPolygonSerialization::nestedDataType()));
static auto data_type = std::make_shared<const DataTypeArray>(DataTypeCustomPolygonSerialization::nestedDataType());
return data_type;
}

View File

@ -9,6 +9,8 @@ namespace DB
namespace ErrorCodes
{
extern const int ILLEGAL_COLUMN;
extern const int BAD_ARGUMENTS;
extern const int LOGICAL_ERROR;
}
namespace
@ -108,4 +110,28 @@ template GeometryFromColumnParser<CartesianPoint> makeGeometryFromColumnParser(c
template GeometryFromColumnParser<GeographicPoint> makeGeometryFromColumnParser(const ColumnWithTypeAndName & col);
template <typename Point, template<typename> typename Desired>
void checkColumnTypeOrThrow(const ColumnWithTypeAndName & column)
{
DataTypePtr desired_type;
if constexpr (std::is_same_v<Desired<Point>, Ring<Point>>)
desired_type = DataTypeCustomRingSerialization::nestedDataType();
else if constexpr (std::is_same_v<Desired<Point>, Polygon<Point>>)
desired_type = DataTypeCustomPolygonSerialization::nestedDataType();
else if constexpr (std::is_same_v<Desired<Point>, MultiPolygon<Point>>)
desired_type = DataTypeCustomMultiPolygonSerialization::nestedDataType();
else
throw Exception("Unexpected Desired type.", ErrorCodes::LOGICAL_ERROR);
if (!desired_type->equals(*column.type))
throw Exception(fmt::format("Expected type {} (MultiPolygon), but got {}", desired_type->getName(), column.type->getName()), ErrorCodes::BAD_ARGUMENTS);
}
template void checkColumnTypeOrThrow<CartesianPoint, Ring>(const ColumnWithTypeAndName &);
template void checkColumnTypeOrThrow<CartesianPoint, Polygon>(const ColumnWithTypeAndName &);
template void checkColumnTypeOrThrow<CartesianPoint, MultiPolygon>(const ColumnWithTypeAndName &);
template void checkColumnTypeOrThrow<GeographicPoint, Ring>(const ColumnWithTypeAndName &);
template void checkColumnTypeOrThrow<GeographicPoint, Polygon>(const ColumnWithTypeAndName &);
template void checkColumnTypeOrThrow<GeographicPoint, MultiPolygon>(const ColumnWithTypeAndName &);
}

View File

@ -233,14 +233,18 @@ public:
void get(Geometry<Point> & container, size_t i) const
{
auto & multi_polygon = boost::get<MultiPolygon<Point>>(container);
get(boost::get<MultiPolygon<Point>>(container), i);
}
void get(MultiPolygon<Point> & container, size_t i) const
{
size_t l = offsets[i - 1];
size_t r = offsets[i];
multi_polygon.resize(r - l);
container.resize(r - l);
for (size_t j = l; j < r; j++)
{
polygon_parser.get(multi_polygon[j - l], j);
polygon_parser.get(container[j - l], j);
}
}
@ -262,18 +266,17 @@ using GeometryFromColumnParser = boost::variant<
template <typename Point>
Geometry<Point> createContainer(const GeometryFromColumnParser<Point> & parser);
extern template Geometry<CartesianPoint> createContainer(const GeometryFromColumnParser<CartesianPoint> & parser);
extern template Geometry<GeographicPoint> createContainer(const GeometryFromColumnParser<GeographicPoint> & parser);
template <typename Point>
void get(const GeometryFromColumnParser<Point> & parser, Geometry<Point> & container, size_t i);
extern template void get(const GeometryFromColumnParser<CartesianPoint> & parser, Geometry<CartesianPoint> & container, size_t i);
extern template void get(const GeometryFromColumnParser<GeographicPoint> & parser, Geometry<GeographicPoint> & container, size_t i);
template <typename Point>
GeometryFromColumnParser<Point> makeGeometryFromColumnParser(const ColumnWithTypeAndName & col);
extern template Geometry<CartesianPoint> createContainer(const GeometryFromColumnParser<CartesianPoint> & parser);
extern template Geometry<GeographicPoint> createContainer(const GeometryFromColumnParser<GeographicPoint> & parser);
extern template void get(const GeometryFromColumnParser<CartesianPoint> & parser, Geometry<CartesianPoint> & container, size_t i);
extern template void get(const GeometryFromColumnParser<GeographicPoint> & parser, Geometry<GeographicPoint> & container, size_t i);
extern template GeometryFromColumnParser<CartesianPoint> makeGeometryFromColumnParser(const ColumnWithTypeAndName & col);
extern template GeometryFromColumnParser<GeographicPoint> makeGeometryFromColumnParser(const ColumnWithTypeAndName & col);
@ -532,4 +535,8 @@ using PolygonSerializer = GeometrySerializer<Geometry<Point>, PolygonSerializerV
template <typename Point>
using MultiPolygonSerializer = GeometrySerializer<Geometry<Point>, MultiPolygonSerializerVisitor<Point>>;
template <typename Point, template<typename> typename Desired>
void checkColumnTypeOrThrow(const ColumnWithTypeAndName & column);
}

View File

@ -20,11 +20,6 @@
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
}
template <typename Point>
class FunctionPolygonArea : public IFunction
{
@ -58,40 +53,18 @@ public:
return std::make_shared<DataTypeFloat64>();
}
void checkInputType(const ColumnsWithTypeAndName & arguments) const
{
/// Array(Array(Array(Tuple(Float64, Float64))))
auto desired = std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeTuple>(
DataTypes{std::make_shared<const DataTypeFloat64>(), std::make_shared<const DataTypeFloat64>()}
)
)
)
);
if (!desired->equals(*arguments[0].type))
throw Exception(fmt::format("The type of first argument of function {} must be Array(Array(Array(Tuple(Float64, Float64))))", name), ErrorCodes::BAD_ARGUMENTS);
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
checkInputType(arguments);
auto parser = makeGeometryFromColumnParser<Point>(arguments[0]);
std::cout << arguments[0].type->getName() << std::endl;
auto container = createContainer(parser);
checkColumnTypeOrThrow<Point, MultiPolygon>(arguments[0]);
auto parser = MultiPolygonFromColumnParser<Point>(std::move(arguments[0].column->convertToFullColumnIfConst()));
MultiPolygon<Point> container;
auto res_column = ColumnFloat64::create();
for (size_t i = 0; i < input_rows_count; i++)
{
get(parser, container, i);
Float64 area = boost::geometry::area(
boost::get<MultiPolygon<Point>>(container));
res_column->insertValue(area);
parser.get(container, i);
res_column->insertValue(boost::geometry::area(container));
}
return res_column;

View File

@ -20,11 +20,6 @@
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
}
template <typename Point>
class FunctionPolygonConvexHull : public IFunction
{
@ -58,42 +53,19 @@ public:
return DataTypeCustomPolygonSerialization::nestedDataType();
}
void checkInputType(const ColumnsWithTypeAndName & arguments) const
{
/// Array(Array(Array(Tuple(Float64, Float64))))
auto desired = std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeTuple>(
DataTypes{std::make_shared<const DataTypeFloat64>(), std::make_shared<const DataTypeFloat64>()}
)
)
)
);
if (!desired->equals(*arguments[0].type))
throw Exception(fmt::format("The type of the argument of function {} must be Array(Array(Array(Tuple(Float64, Float64))))", name), ErrorCodes::BAD_ARGUMENTS);
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
checkInputType(arguments);
auto parser = makeGeometryFromColumnParser<Point>(arguments[0]);
auto container = createContainer(parser);
checkColumnTypeOrThrow<Point, MultiPolygon>(arguments[0]);
auto parser = MultiPolygonFromColumnParser<Point>(std::move(arguments[0].column->convertToFullColumnIfConst()));
MultiPolygon<Point> container;
PolygonSerializer<Point> serializer;
Polygon<Point> convex_hull{};
for (size_t i = 0; i < input_rows_count; i++)
{
get(parser, container, i);
auto convex_hull = Polygon<Point>({{{}}});
boost::geometry::convex_hull(
boost::get<MultiPolygon<Point>>(container),
convex_hull);
convex_hull.outer().erase(convex_hull.outer().begin());
parser.get(container, i);
boost::geometry::convex_hull(container, convex_hull);
serializer.add(convex_hull);
}

View File

@ -20,11 +20,6 @@
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
}
template <typename Point>
class FunctionPolygonPerimeter : public IFunction
{
@ -58,38 +53,18 @@ public:
return std::make_shared<DataTypeFloat64>();
}
void checkInputType(const ColumnsWithTypeAndName & arguments) const
{
/// Array(Array(Array(Tuple(Float64, Float64))))
auto desired = std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeTuple>(
DataTypes{std::make_shared<const DataTypeFloat64>(), std::make_shared<const DataTypeFloat64>()}
)
)
)
);
if (!desired->equals(*arguments[0].type))
throw Exception(fmt::format("The type of the argument of function {} must be Array(Array(Array(Tuple(Float64, Float64))))", name), ErrorCodes::BAD_ARGUMENTS);
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
checkInputType(arguments);
auto parser = makeGeometryFromColumnParser<Point>(arguments[0]);
auto container = createContainer(parser);
checkColumnTypeOrThrow<Point, MultiPolygon>(arguments[0]);
auto parser = MultiPolygonFromColumnParser<Point>(std::move(arguments[0].column->convertToFullColumnIfConst()));
MultiPolygon<Point> container;
auto res_column = ColumnFloat64::create();
for (size_t i = 0; i < input_rows_count; i++)
{
get(parser, container, i);
Float64 perimeter = boost::geometry::perimeter(
boost::get<MultiPolygon<Point>>(container));
res_column->insertValue(perimeter);
parser.get(container, i);
res_column->insertValue(boost::geometry::perimeter(container));
}
return res_column;

View File

@ -22,11 +22,6 @@
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
}
template <typename Point>
class FunctionPolygonsDistance : public IFunction
{
@ -60,49 +55,27 @@ public:
return std::make_shared<DataTypeFloat64>();
}
void checkInputType(const ColumnsWithTypeAndName & arguments) const
{
/// Array(Array(Array(Tuple(Float64, Float64))))
auto desired = std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeTuple>(
DataTypes{std::make_shared<const DataTypeFloat64>(), std::make_shared<const DataTypeFloat64>()}
)
)
)
);
if (!desired->equals(*arguments[0].type))
throw Exception(fmt::format("The type of the first argument of function {} must be Array(Array(Array(Tuple(Float64, Float64))))", name), ErrorCodes::BAD_ARGUMENTS);
if (!desired->equals(*arguments[1].type))
throw Exception(fmt::format("The type of the second argument of function {} must be Array(Array(Array(Tuple(Float64, Float64))))", name), ErrorCodes::BAD_ARGUMENTS);
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
auto first_parser = makeGeometryFromColumnParser<Point>(arguments[0]);
auto first_container = createContainer(first_parser);
checkColumnTypeOrThrow<Point, MultiPolygon>(arguments[0]);
auto first_parser = MultiPolygonFromColumnParser<Point>(std::move(arguments[0].column->convertToFullColumnIfConst()));
MultiPolygon<Point> first_container;
auto second_parser = makeGeometryFromColumnParser<Point>(arguments[1]);
auto second_container = createContainer(second_parser);
checkColumnTypeOrThrow<Point, MultiPolygon>(arguments[1]);
auto second_parser = MultiPolygonFromColumnParser<Point>(std::move(arguments[1].column->convertToFullColumnIfConst()));
MultiPolygon<Point> second_container;
auto res_column = ColumnFloat64::create();
for (size_t i = 0; i < input_rows_count; i++)
{
get(first_parser, first_container, i);
get(second_parser, second_container, i);
first_parser.get(first_container, i);
second_parser.get(second_container, i);
auto first = boost::get<MultiPolygon<Point>>(first_container);
auto second = boost::get<MultiPolygon<Point>>(second_container);
boost::geometry::correct(first_container);
boost::geometry::correct(second_container);
boost::geometry::correct(first);
boost::geometry::correct(second);
Float64 distance = boost::geometry::distance(first, second);
res_column->insertValue(distance);
res_column->insertValue(boost::geometry::distance(first_container, second_container));
}
return res_column;

View File

@ -22,11 +22,6 @@
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
}
template <typename Point>
class FunctionPolygonsEquals : public IFunction
{
@ -60,50 +55,27 @@ public:
return std::make_shared<DataTypeUInt8>();
}
void checkInputType(const ColumnsWithTypeAndName & arguments) const
{
/// Array(Array(Array(Tuple(Float64, Float64))))
auto desired = std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeTuple>(
DataTypes{std::make_shared<const DataTypeFloat64>(), std::make_shared<const DataTypeFloat64>()}
)
)
)
);
if (!desired->equals(*arguments[0].type))
throw Exception(fmt::format("The type of the first argument of function {} must be Array(Array(Array(Tuple(Float64, Float64))))", name), ErrorCodes::BAD_ARGUMENTS);
if (!desired->equals(*arguments[1].type))
throw Exception(fmt::format("The type of the second argument of function {} must be Array(Array(Array(Tuple(Float64, Float64))))", name), ErrorCodes::BAD_ARGUMENTS);
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
checkInputType(arguments);
auto first_parser = makeGeometryFromColumnParser<Point>(arguments[0]);
auto first_container = createContainer(first_parser);
checkColumnTypeOrThrow<Point, MultiPolygon>(arguments[0]);
auto first_parser = MultiPolygonFromColumnParser<Point>(std::move(arguments[0].column->convertToFullColumnIfConst()));
MultiPolygon<Point> first_container;
auto second_parser = makeGeometryFromColumnParser<Point>(arguments[1]);
auto second_container = createContainer(second_parser);
checkColumnTypeOrThrow<Point, MultiPolygon>(arguments[1]);
auto second_parser = MultiPolygonFromColumnParser<Point>(std::move(arguments[1].column->convertToFullColumnIfConst()));
MultiPolygon<Point> second_container;
auto res_column = ColumnUInt8::create();
for (size_t i = 0; i < input_rows_count; i++)
{
get(first_parser, first_container, i);
get(second_parser, second_container, i);
first_parser.get(first_container, i);
second_parser.get(second_container, i);
auto first = boost::get<MultiPolygon<Point>>(first_container);
auto second = boost::get<MultiPolygon<Point>>(second_container);
boost::geometry::correct(first_container);
boost::geometry::correct(second_container);
boost::geometry::correct(first);
boost::geometry::correct(second);
bool equals = boost::geometry::equals(first, second);
res_column->insertValue(equals);
res_column->insertValue(boost::geometry::equals(first_container, second_container));
}
return res_column;

View File

@ -20,11 +20,6 @@
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
}
template <typename Point>
class FunctionPolygonsIntersection : public IFunction
{
@ -58,55 +53,32 @@ public:
return DataTypeCustomMultiPolygonSerialization::nestedDataType();
}
void checkInputType(const ColumnsWithTypeAndName & arguments) const
{
/// Array(Array(Array(Tuple(Float64, Float64))))
auto desired = std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeTuple>(
DataTypes{std::make_shared<const DataTypeFloat64>(), std::make_shared<const DataTypeFloat64>()}
)
)
)
);
if (!desired->equals(*arguments[0].type))
throw Exception(fmt::format("The type of the first argument of function {} must be Array(Array(Array(Tuple(Float64, Float64))))", name), ErrorCodes::BAD_ARGUMENTS);
if (!desired->equals(*arguments[1].type))
throw Exception(fmt::format("The type of the second argument of function {} must be Array(Array(Array(Tuple(Float64, Float64))))", name), ErrorCodes::BAD_ARGUMENTS);
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
checkInputType(arguments);
auto first_parser = makeGeometryFromColumnParser<Point>(arguments[0]);
auto first_container = createContainer(first_parser);
checkColumnTypeOrThrow<Point, MultiPolygon>(arguments[0]);
auto first_parser = MultiPolygonFromColumnParser<Point>(std::move(arguments[0].column->convertToFullColumnIfConst()));
MultiPolygon<Point> first_container;
auto second_parser = makeGeometryFromColumnParser<Point>(arguments[1]);
auto second_container = createContainer(second_parser);
checkColumnTypeOrThrow<Point, MultiPolygon>(arguments[1]);
auto second_parser = MultiPolygonFromColumnParser<Point>(std::move(arguments[1].column->convertToFullColumnIfConst()));
MultiPolygon<Point> second_container;
MultiPolygonSerializer<Point> serializer;
MultiPolygon<Point> intersection{};
/// We are not interested in some pitfalls in third-party libraries
/// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Assign)
for (size_t i = 0; i < input_rows_count; i++)
for (size_t i = 0; i < input_rows_count; ++i)
{
get(first_parser, first_container, i);
get(second_parser, second_container, i);
auto intersection = MultiPolygon<Point>({{{{}}}});
auto first = boost::get<MultiPolygon<Point>>(first_container);
auto second = boost::get<MultiPolygon<Point>>(second_container);
first_parser.get(first_container, i);
second_parser.get(second_container, i);
/// Orient the polygons correctly.
boost::geometry::correct(first);
boost::geometry::correct(second);
boost::geometry::correct(first_container);
boost::geometry::correct(second_container);
/// Main work here.
boost::geometry::intersection(first, second, intersection);
intersection.erase(intersection.begin());
boost::geometry::intersection(first_container, second_container, intersection);
serializer.add(intersection);
}

View File

@ -20,11 +20,6 @@
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
}
template <typename Point>
class FunctionPolygonsSymDifference : public IFunction
{
@ -58,53 +53,29 @@ public:
return DataTypeCustomMultiPolygonSerialization::nestedDataType();
}
void checkInputType(const ColumnsWithTypeAndName & arguments) const
{
/// Array(Array(Array(Tuple(Float64, Float64))))
auto desired = std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeTuple>(
DataTypes{std::make_shared<const DataTypeFloat64>(), std::make_shared<const DataTypeFloat64>()}
)
)
)
);
if (!desired->equals(*arguments[0].type))
throw Exception(fmt::format("The type of the first argument of function {} must be Array(Array(Array(Tuple(Float64, Float64))))", name), ErrorCodes::BAD_ARGUMENTS);
if (!desired->equals(*arguments[1].type))
throw Exception(fmt::format("The type of the second argument of function {} must be Array(Array(Array(Tuple(Float64, Float64))))", name), ErrorCodes::BAD_ARGUMENTS);
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
checkInputType(arguments);
auto first_parser = makeGeometryFromColumnParser<Point>(arguments[0]);
auto first_container = createContainer(first_parser);
checkColumnTypeOrThrow<Point, MultiPolygon>(arguments[0]);
auto first_parser = MultiPolygonFromColumnParser<Point>(std::move(arguments[0].column->convertToFullColumnIfConst()));
MultiPolygon<Point> first_container;
auto second_parser = makeGeometryFromColumnParser<Point>(arguments[1]);
auto second_container = createContainer(second_parser);
checkColumnTypeOrThrow<Point, MultiPolygon>(arguments[1]);
auto second_parser = MultiPolygonFromColumnParser<Point>(std::move(arguments[1].column->convertToFullColumnIfConst()));
MultiPolygon<Point> second_container;
MultiPolygonSerializer<Point> serializer;
MultiPolygon<Point> sym_difference{};
/// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Assign)
for (size_t i = 0; i < input_rows_count; i++)
{
get(first_parser, first_container, i);
get(second_parser, second_container, i);
first_parser.get(first_container, i);
second_parser.get(second_container, i);
auto sym_difference = MultiPolygon<Point>({{{{}}}});
boost::geometry::correct(first_container);
boost::geometry::correct(second_container);
auto first = boost::get<MultiPolygon<Point>>(first_container);
auto second = boost::get<MultiPolygon<Point>>(second_container);
boost::geometry::correct(first);
boost::geometry::correct(second);
boost::geometry::sym_difference(first, second, sym_difference);
sym_difference.erase(sym_difference.begin());
boost::geometry::sym_difference(first_container, second_container, sym_difference);
serializer.add(sym_difference);
}

View File

@ -19,10 +19,6 @@
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
}
template <typename Point>
class FunctionPolygonsUnion : public IFunction
@ -57,55 +53,32 @@ public:
return DataTypeCustomMultiPolygonSerialization::nestedDataType();
}
void checkInputType(const ColumnsWithTypeAndName & arguments) const
{
/// Array(Array(Array(Tuple(Float64, Float64))))
auto desired = std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeTuple>(
DataTypes{std::make_shared<const DataTypeFloat64>(), std::make_shared<const DataTypeFloat64>()}
)
)
)
);
if (!desired->equals(*arguments[0].type))
throw Exception(fmt::format("The type of the first argument of function {} must be Array(Array(Array(Tuple(Float64, Float64))))", name), ErrorCodes::BAD_ARGUMENTS);
if (!desired->equals(*arguments[1].type))
throw Exception(fmt::format("The type of the second argument of function {} must be Array(Array(Array(Tuple(Float64, Float64))))", name), ErrorCodes::BAD_ARGUMENTS);
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
checkInputType(arguments);
auto first_parser = makeGeometryFromColumnParser<Point>(arguments[0]);
auto first_container = createContainer(first_parser);
checkColumnTypeOrThrow<Point, MultiPolygon>(arguments[0]);
auto first_parser = MultiPolygonFromColumnParser<Point>(std::move(arguments[0].column->convertToFullColumnIfConst()));
MultiPolygon<Point> first_container;
auto second_parser = makeGeometryFromColumnParser<Point>(arguments[1]);
auto second_container = createContainer(second_parser);
checkColumnTypeOrThrow<Point, MultiPolygon>(arguments[1]);
auto second_parser = MultiPolygonFromColumnParser<Point>(std::move(arguments[1].column->convertToFullColumnIfConst()));
MultiPolygon<Point> second_container;
MultiPolygonSerializer<Point> serializer;
MultiPolygon<Point> polygons_union{};
/// We are not interested in some pitfalls in third-party libraries
/// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Assign)
for (size_t i = 0; i < input_rows_count; i++)
{
get<Point>(first_parser, first_container, i);
get<Point>(second_parser, second_container, i);
auto first = boost::get<MultiPolygon<Point>>(first_container);
auto second = boost::get<MultiPolygon<Point>>(second_container);
auto polygons_union = MultiPolygon<Point>({{{{}}}});
first_parser.get(first_container, i);
second_parser.get(second_container, i);
/// Orient the polygons correctly.
boost::geometry::correct(first);
boost::geometry::correct(second);
boost::geometry::correct(first_container);
boost::geometry::correct(second_container);
/// Main work here.
boost::geometry::union_(first, second, polygons_union);
polygons_union.erase(polygons_union.begin());
boost::geometry::union_(first_container, second_container, polygons_union);
serializer.add(polygons_union);
}

View File

@ -22,11 +22,6 @@
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
}
template <typename Point>
class FunctionPolygonsWithin : public IFunction
{
@ -60,51 +55,28 @@ public:
return std::make_shared<DataTypeUInt8>();
}
void checkInputType(const ColumnsWithTypeAndName & arguments) const
{
/// Array(Array(Array(Tuple(Float64, Float64))))
auto desired = std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeArray>(
std::make_shared<const DataTypeTuple>(
DataTypes{std::make_shared<const DataTypeFloat64>(), std::make_shared<const DataTypeFloat64>()}
)
)
)
);
if (!desired->equals(*arguments[0].type))
throw Exception(fmt::format("The type of the first argument of function {} must be Array(Array(Array(Tuple(Float64, Float64))))", name), ErrorCodes::BAD_ARGUMENTS);
if (!desired->equals(*arguments[1].type))
throw Exception(fmt::format("The type of the second argument of function {} must be Array(Array(Array(Tuple(Float64, Float64))))", name), ErrorCodes::BAD_ARGUMENTS);
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
checkInputType(arguments);
auto first_parser = makeGeometryFromColumnParser<Point>(arguments[0]);
auto first_container = createContainer(first_parser);
checkColumnTypeOrThrow<Point, MultiPolygon>(arguments[0]);
auto first_parser = MultiPolygonFromColumnParser<Point>(std::move(arguments[0].column->convertToFullColumnIfConst()));
MultiPolygon<Point> first_container;
auto second_parser = makeGeometryFromColumnParser<Point>(arguments[1]);
auto second_container = createContainer(second_parser);
checkColumnTypeOrThrow<Point, MultiPolygon>(arguments[1]);
auto second_parser = MultiPolygonFromColumnParser<Point>(std::move(arguments[1].column->convertToFullColumnIfConst()));
MultiPolygon<Point> second_container;
auto res_column = ColumnUInt8::create();
/// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Assign)
for (size_t i = 0; i < input_rows_count; i++)
{
get<Point>(first_parser, first_container, i);
get<Point>(second_parser, second_container, i);
first_parser.get(first_container, i);
second_parser.get(second_container, i);
auto first = boost::get<MultiPolygon<Point>>(first_container);
auto second = boost::get<MultiPolygon<Point>>(second_container);
boost::geometry::correct(first_container);
boost::geometry::correct(second_container);
boost::geometry::correct(first);
boost::geometry::correct(second);
bool within = boost::geometry::within(first, second);
res_column->insertValue(within);
res_column->insertValue(boost::geometry::within(first_container, second_container));
}
return res_column;

View File

@ -1 +1 @@
select polygonConvexHullCartesian([[[(0, 0), (0, 5), (5, 5), (5, 0), (2, 3)]]]);
select polygonConvexHullCartesian([[[(0., 0.), (0., 5.), (5., 5.), (5., 0.), (2., 3.)]]]);

View File

@ -1,5 +1,5 @@
select polygonsWithinCartesian([[[(0, 0),(0, 3),(1, 2.9),(2, 2.6),(2.6, 2),(2.9, 1),(3, 0),(0, 0)]]], [[[(1, 1),(1, 4),(4, 4),(4, 1),(1, 1)]]]);
select polygonsWithinCartesian([[[(2, 2), (2, 3), (3, 3), (3, 2)]]], [[[(1, 1),(1, 4),(4, 4),(4, 1),(1, 1)]]]);
select polygonsWithinCartesian([[[(0, 0),(0, 3),(1, 2.9),(2, 2.6),(2.6, 2),(2.9, 1),(3, 0),(0, 0)]]], [[[(1., 1.),(1., 4.),(4., 4.),(4., 1.),(1., 1.)]]]);
select polygonsWithinCartesian([[[(2., 2.), (2., 3.), (3., 3.), (3., 2.)]]], [[[(1., 1.),(1., 4.),(4., 4.),(4., 1.),(1., 1.)]]]);
select polygonsWithinGeographic([[[(4.3613577, 50.8651821), (4.349556, 50.8535879), (4.3602419, 50.8435626), (4.3830299, 50.8428851), (4.3904543, 50.8564867), (4.3613148, 50.8651279)]]], [[[(4.346693, 50.858306), (4.367945, 50.852455), (4.366227, 50.840809), (4.344961, 50.833264), (4.338074, 50.848677), (4.346693, 50.858306)]]]);
select polygonsWithinGeographic([[[(4.3501568, 50.8518269), (4.3444920, 50.8439961), (4.3565941, 50.8443213), (4.3501568, 50.8518269)]]], [[[(4.3679450, 50.8524550),(4.3466930, 50.8583060),(4.3380740, 50.8486770),(4.3449610, 50.8332640),(4.3662270, 50.8408090),(4.3679450, 50.8524550)]]]);

View File

@ -1,5 +1,5 @@
select polygonsDistanceCartesian([[[(0, 0),(0, 3),(1, 2.9),(2, 2.6),(2.6, 2),(2.9, 1),(3, 0),(0, 0)]]], [[[(1, 1),(1, 4),(4, 4),(4, 1),(1, 1)]]]);
select polygonsDistanceCartesian([[[(0, 0), (0, 0.1), (0.1, 0.1), (0.1, 0)]]], [[[(1, 1),(1, 4),(4, 4),(4, 1),(1, 1)]]]);
select polygonsDistanceCartesian([[[(0, 0),(0, 3),(1, 2.9),(2, 2.6),(2.6, 2),(2.9, 1),(3, 0),(0, 0)]]], [[[(1., 1.),(1., 4.),(4., 4.),(4., 1.),(1., 1.)]]]);
select polygonsDistanceCartesian([[[(0, 0), (0, 0.1), (0.1, 0.1), (0.1, 0)]]], [[[(1., 1.),(1., 4.),(4., 4.),(4., 1.),(1., 1.)]]]);
select polygonsDistanceGeographic([[[(23.725750, 37.971536)]]], [[[(4.3826169, 50.8119483)]]]);
drop table if exists polygon_01302;

View File

@ -1,2 +1,2 @@
select polygonsEqualsCartesian([[[(0, 0),(0, 3),(1, 2.9),(2, 2.6),(2.6, 2),(2.9, 1),(3, 0),(0, 0)]]], [[[(1, 1),(1, 4),(4, 4),(4, 1),(1, 1)]]]);
select polygonsEqualsCartesian([[[(1, 1),(1, 4),(4, 4),(4, 1)]]], [[[(1, 1),(1, 4),(4, 4),(4, 1),(1, 1)]]]);
select polygonsEqualsCartesian([[[(0, 0),(0, 3),(1, 2.9),(2, 2.6),(2.6, 2),(2.9, 1),(3, 0),(0, 0)]]], [[[(1., 1.),(1., 4.),(4., 4.),(4., 1.),(1., 1.)]]]);
select polygonsEqualsCartesian([[[(1., 1.),(1., 4.),(4., 4.),(4., 1.)]]], [[[(1., 1.),(1., 4.),(4., 4.),(4., 1.),(1., 1.)]]]);

View File

@ -1,2 +1,2 @@
select polygonsSymDifferenceCartesian([[[(0, 0),(0, 3),(1, 2.9),(2, 2.6),(2.6, 2),(2.9, 1),(3, 0),(0, 0)]]], [[[(1, 1),(1, 4),(4, 4),(4, 1),(1, 1)]]])
select polygonsSymDifferenceCartesian([[[(0, 0),(0, 3),(1, 2.9),(2, 2.6),(2.6, 2),(2.9, 1),(3, 0),(0, 0)]]], [[[(1., 1.),(1., 4.),(4., 4.),(4., 1.),(1., 1.)]]])

View File

@ -1,3 +1,3 @@
select polygonsUnionCartesian([[[(0, 0),(0, 3),(1, 2.9),(2, 2.6),(2.6, 2),(2.9, 1),(3, 0),(0, 0)]]], [[[(1, 1),(1, 4),(4, 4),(4, 1),(1, 1)]]]);
select polygonsUnionCartesian([[[(0., 0.),(0., 3.),(1., 2.9),(2., 2.6),(2.6, 2.),(2.9, 1),(3., 0.),(0., 0.)]]], [[[(1., 1.),(1., 4.),(4., 4.),(4., 1.),(1., 1.)]]]);
select polygonsUnionGeographic([[[(4.3613577, 50.8651821), (4.349556, 50.8535879), (4.3602419, 50.8435626), (4.3830299, 50.8428851), (4.3904543, 50.8564867), (4.3613148, 50.8651279)]]], [[[(4.346693, 50.858306), (4.367945, 50.852455), (4.366227, 50.840809), (4.344961, 50.833264), (4.338074, 50.848677), (4.346693, 50.858306)]]]);

View File

@ -1,5 +1,5 @@
select polygonsIntersectionCartesian([[[(0, 0),(0, 3),(1, 2.9),(2, 2.6),(2.6, 2),(2.9, 1),(3, 0),(0, 0)]]], [[[(1, 1),(1, 4),(4, 4),(4, 1),(1, 1)]]]);
select polygonsIntersectionCartesian([[[(0, 0),(0, 3),(1, 2.9),(2, 2.6),(2.6, 2),(2.9, 1),(3, 0),(0, 0)]]], [[[(3, 3),(3, 4),(4, 4),(4, 3),(3, 3)]]]);
select polygonsIntersectionCartesian([[[(0., 0.),(0., 3.),(1., 2.9),(2., 2.6),(2.6, 2.),(2.9, 1.),(3., 0.),(0., 0.)]]], [[[(1., 1.),(1., 4.),(4., 4.),(4., 1.),(1., 1.)]]]);
select polygonsIntersectionCartesian([[[(0., 0.),(0., 3.),(1., 2.9),(2., 2.6),(2.6, 2.),(2.9, 1.),(3., 0.),(0., 0.)]]], [[[(3., 3.),(3., 4.),(4., 4.),(4., 3.),(3., 3.)]]]);
select polygonsIntersectionGeographic([[[(4.346693, 50.858306), (4.367945, 50.852455), (4.366227, 50.840809), (4.344961, 50.833264), (4.338074, 50.848677), (4.346693, 50.858306)]]], [[[(25.0010, 136.9987), (17.7500, 142.5000), (11.3733, 142.5917)]]]);
select polygonsIntersectionGeographic([[[(4.3613577, 50.8651821), (4.349556, 50.8535879), (4.3602419, 50.8435626), (4.3830299, 50.8428851), (4.3904543, 50.8564867), (4.3613148, 50.8651279)]]], [[[(4.346693, 50.858306), (4.367945, 50.852455), (4.366227, 50.840809), (4.344961, 50.833264), (4.338074, 50.848677), (4.346693, 50.858306)]]]);

View File

@ -1 +1 @@
select polygonPerimeterCartesian([[[(0, 0), (0., 5), (5, 5), (5., 0)]]]);
select polygonPerimeterCartesian([[[(0., 0.), (0., 5.), (5., 5.), (5., 0.)]]]);

View File

@ -1,3 +1,3 @@
select polygonAreaCartesian([[[(0, 0), (0., 5), (5, 5), (5., 0)]]]);
select polygonAreaCartesian([[[(0., 0.), (0., 5.), (5., 5.), (5., 0.)]]]);
select polygonAreaGeographic([[[(4.346693, 50.858306), (4.367945, 50.852455), (4.366227, 50.840809), (4.344961, 50.833264), (4.338074, 50.848677), (4.346693, 50.858306)]]]);
SELECT polygonAreaCartesian([]); -- { serverError 36 }