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