#include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int BAD_ARGUMENTS; } template class FunctionPolygonsIntersection : public IFunction { public: static inline const char * name; explicit FunctionPolygonsIntersection() = default; static FunctionPtr create(const Context &) { return std::make_shared(); } String getName() const override { return name; } bool isVariadic() const override { return false; } size_t getNumberOfArguments() const override { return 2; } DataTypePtr getReturnTypeImpl(const DataTypes &) const override { return DataTypeCustomMultiPolygonSerialization::nestedDataType(); } void checkInputType(const ColumnsWithTypeAndName & arguments) const { /// Array(Array(Array(Tuple(Float64, Float64)))) auto desired = std::make_shared( std::make_shared( std::make_shared( std::make_shared( DataTypes{std::make_shared(), std::make_shared()} ) ) ) ); 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(arguments[0]); auto first_container = createContainer(first_parser); auto second_parser = makeGeometryFromColumnParser(arguments[1]); auto second_container = createContainer(second_parser); MultiPolygonSerializer serializer; /// 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(first_parser, first_container, i); get(second_parser, second_container, i); auto intersection = MultiPolygon({{{{}}}}); auto first = boost::get>(first_container); auto second = boost::get>(second_container); /// Orient the polygons correctly. boost::geometry::correct(first); boost::geometry::correct(second); /// Main work here. boost::geometry::intersection(first, second, intersection); intersection.erase(intersection.begin()); serializer.add(intersection); } return serializer.finalize(); } bool useDefaultImplementationForConstants() const override { return true; } }; template <> const char * FunctionPolygonsIntersection::name = "polygonsIntersectionCartesian"; template <> const char * FunctionPolygonsIntersection::name = "polygonsIntersectionGeographic"; void registerFunctionPolygonsIntersection(FunctionFactory & factory) { factory.registerFunction>(); factory.registerFunction>(); } }