diff --git a/dbms/src/Functions/h3EdgeAngle.cpp b/dbms/src/Functions/h3EdgeAngle.cpp new file mode 100644 index 00000000000..be3dac0e9d7 --- /dev/null +++ b/dbms/src/Functions/h3EdgeAngle.cpp @@ -0,0 +1,78 @@ +#include "config_functions.h" +#if USE_H3 +# include +# include +# include +# include +# include +# include + + +extern "C" { +# ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdocumentation" +# endif + +# include + +# ifdef __clang__ +# pragma clang diagnostic pop +# endif +} + +namespace DB +{ +class FunctionH3EdgeAngle : public IFunction +{ +public: + static constexpr auto name = "h3EdgeAngle"; + + static FunctionPtr create(const Context &) { return std::make_shared(); } + + std::string getName() const override { return name; } + + size_t getNumberOfArguments() const override { return 1; } + bool useDefaultImplementationForConstants() const override { return true; } + + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override + { + auto arg = arguments[0].get(); + if (!WhichDataType(arg).isUInt8()) + throw Exception( + "Illegal type " + arg->getName() + " of argument " + std::to_string(1) + " of function " + getName() + ". Must be UInt8", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + return std::make_shared(); + } + + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override + { + const auto col_hindex = block.getByPosition(arguments[0]).column.get(); + + auto dst = ColumnVector::create(); + auto & dst_data = dst->getData(); + dst_data.resize(input_rows_count); + + for (const auto row : ext::range(0, input_rows_count)) + { + const int resolution = col_hindex->getUInt(row); + + // Numerical constant is 180 degrees / pi / Earth radius, Earth radius is from h3 sources + Float64 res = 8.99320592271288084e-6 * H3_EXPORT(edgeLengthM)(resolution); + + dst_data[row] = res; + } + + block.getByPosition(result).column = std::move(dst); + } +}; + + +void registerFunctionH3EdgeAngle(FunctionFactory & factory) +{ + factory.registerFunction(); +} + +} +#endif diff --git a/dbms/src/Functions/registerFunctionsGeo.cpp b/dbms/src/Functions/registerFunctionsGeo.cpp index 0a102dbbecc..b3e164145a8 100644 --- a/dbms/src/Functions/registerFunctionsGeo.cpp +++ b/dbms/src/Functions/registerFunctionsGeo.cpp @@ -14,6 +14,7 @@ void registerFunctionGeohashesInBox(FunctionFactory & factory); #if USE_H3 void registerFunctionGeoToH3(FunctionFactory &); +void registerFunctionH3EdgeAngle(FunctionFactory &); void registerFunctionH3EdgeLengthM(FunctionFactory &); void registerFunctionH3GetResolution(FunctionFactory &); void registerFunctionH3IsValid(FunctionFactory &); @@ -31,6 +32,7 @@ void registerFunctionsGeo(FunctionFactory & factory) #if USE_H3 registerFunctionGeoToH3(factory); + registerFunctionH3EdgeAngle(factory); registerFunctionH3EdgeLengthM(factory); registerFunctionH3GetResolution(factory); registerFunctionH3IsValid(factory); diff --git a/dbms/tests/queries/0_stateless/01044_h3_edge_angle.reference b/dbms/tests/queries/0_stateless/01044_h3_edge_angle.reference new file mode 100644 index 00000000000..e64c5a2787e --- /dev/null +++ b/dbms/tests/queries/0_stateless/01044_h3_edge_angle.reference @@ -0,0 +1,2 @@ +0.0005927224846720883 +0 diff --git a/dbms/tests/queries/0_stateless/01044_h3_edge_angle.sql b/dbms/tests/queries/0_stateless/01044_h3_edge_angle.sql new file mode 100644 index 00000000000..a22121971f4 --- /dev/null +++ b/dbms/tests/queries/0_stateless/01044_h3_edge_angle.sql @@ -0,0 +1,2 @@ +SELECT h3EdgeAngle(10); +SELECT h3EdgeLengthM(2) * 180 / pi() / 6371007.180918475 - h3EdgeAngle(2);