ClickHouse
120 строк · 3.5 Кб
1#include <Functions/FunctionFactory.h>
2#include <Functions/geometryConverters.h>
3
4#include <boost/geometry.hpp>
5#include <boost/geometry/geometries/point_xy.hpp>
6
7#include <Common/logger_useful.h>
8
9#include <Columns/ColumnTuple.h>
10#include <DataTypes/DataTypeTuple.h>
11
12#include <memory>
13
14
15namespace DB
16{
17
18namespace ErrorCodes
19{
20extern const int ILLEGAL_TYPE_OF_ARGUMENT;
21}
22
23namespace
24{
25
26template <typename Point>
27class FunctionPolygonsUnion : public IFunction
28{
29public:
30static inline const char * name;
31
32explicit FunctionPolygonsUnion() = default;
33
34static FunctionPtr create(ContextPtr)
35{
36return std::make_shared<FunctionPolygonsUnion>();
37}
38
39String getName() const override
40{
41return name;
42}
43
44bool isVariadic() const override
45{
46return false;
47}
48
49size_t getNumberOfArguments() const override
50{
51return 2;
52}
53
54DataTypePtr getReturnTypeImpl(const DataTypes &) const override
55{
56return DataTypeFactory::instance().get("MultiPolygon");
57}
58
59bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
60
61ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
62{
63MultiPolygonSerializer<Point> serializer;
64
65callOnTwoGeometryDataTypes<Point>(arguments[0].type, arguments[1].type, [&](const auto & left_type, const auto & right_type)
66{
67using LeftConverterType = std::decay_t<decltype(left_type)>;
68using RightConverterType = std::decay_t<decltype(right_type)>;
69
70using LeftConverter = typename LeftConverterType::Type;
71using RightConverter = typename RightConverterType::Type;
72
73if constexpr (std::is_same_v<ColumnToPointsConverter<Point>, LeftConverter> || std::is_same_v<ColumnToPointsConverter<Point>, RightConverter>)
74throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Any argument of function {} must not be Point", getName());
75else
76{
77auto first = LeftConverter::convert(arguments[0].column->convertToFullColumnIfConst());
78auto second = RightConverter::convert(arguments[1].column->convertToFullColumnIfConst());
79
80/// We are not interested in some pitfalls in third-party libraries
81/// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Assign)
82for (size_t i = 0; i < input_rows_count; ++i)
83{
84/// Orient the polygons correctly.
85boost::geometry::correct(first[i]);
86boost::geometry::correct(second[i]);
87
88MultiPolygon<Point> polygons_union{};
89/// Main work here.
90boost::geometry::union_(first[i], second[i], polygons_union);
91
92serializer.add(polygons_union);
93}
94}
95});
96
97return serializer.finalize();
98}
99
100bool useDefaultImplementationForConstants() const override
101{
102return true;
103}
104};
105
106template <>
107const char * FunctionPolygonsUnion<CartesianPoint>::name = "polygonsUnionCartesian";
108
109template <>
110const char * FunctionPolygonsUnion<SphericalPoint>::name = "polygonsUnionSpherical";
111
112}
113
114REGISTER_FUNCTION(PolygonsUnion)
115{
116factory.registerFunction<FunctionPolygonsUnion<CartesianPoint>>();
117factory.registerFunction<FunctionPolygonsUnion<SphericalPoint>>();
118}
119
120}
121