2020-06-17 15:29:08 +00:00
# include <Functions/FunctionFactory.h>
# include <Functions/geometryConverters.h>
# include <boost/geometry.hpp>
# include <boost/geometry/geometries/point_xy.hpp>
# include <boost/geometry/geometries/polygon.hpp>
2020-06-21 14:54:13 +00:00
# include <common/logger_useful.h>
2020-06-17 15:29:08 +00:00
# include <Columns/ColumnArray.h>
# include <Columns/ColumnTuple.h>
2020-06-22 16:15:11 +00:00
# include <Columns/ColumnConst.h>
2020-06-17 15:29:08 +00:00
# include <DataTypes/DataTypeArray.h>
# include <DataTypes/DataTypeTuple.h>
# include <DataTypes/DataTypeCustomGeo.h>
# include <memory>
2020-06-22 16:15:11 +00:00
# include <utility>
2020-06-17 15:29:08 +00:00
namespace DB
{
2021-01-21 12:31:47 +00:00
2021-02-11 20:37:05 +00:00
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS ;
}
2021-01-21 12:31:47 +00:00
template < typename Point >
2020-06-17 15:29:08 +00:00
class FunctionPolygonsIntersection : public IFunction
{
public :
2021-01-21 12:31:47 +00:00
static inline const char * name ;
2020-06-17 15:29:08 +00:00
explicit FunctionPolygonsIntersection ( ) = default ;
static FunctionPtr create ( const Context & )
{
return std : : make_shared < FunctionPolygonsIntersection > ( ) ;
}
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 ( ) ;
}
2021-02-11 20:37:05 +00:00
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) ;
}
2021-01-18 23:51:34 +00:00
ColumnPtr executeImpl ( const ColumnsWithTypeAndName & arguments , const DataTypePtr & /*result_type*/ , size_t input_rows_count ) const override
2020-06-17 15:29:08 +00:00
{
2021-02-11 20:37:05 +00:00
checkInputType ( arguments ) ;
2021-01-21 12:31:47 +00:00
auto first_parser = makeGeometryFromColumnParser < Point > ( arguments [ 0 ] ) ;
2020-06-17 15:29:08 +00:00
auto first_container = createContainer ( first_parser ) ;
2021-01-21 12:31:47 +00:00
auto second_parser = makeGeometryFromColumnParser < Point > ( arguments [ 1 ] ) ;
2020-06-17 15:29:08 +00:00
auto second_container = createContainer ( second_parser ) ;
2021-01-21 12:31:47 +00:00
MultiPolygonSerializer < Point > serializer ;
2020-06-17 15:29:08 +00:00
2021-01-21 12:31:47 +00:00
/// We are not interested in some pitfalls in third-party libraries
2021-01-20 23:12:47 +00:00
/// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Assign)
2020-06-17 15:29:08 +00:00
for ( size_t i = 0 ; i < input_rows_count ; i + + )
{
2021-01-20 23:12:47 +00:00
get ( first_parser , first_container , i ) ;
get ( second_parser , second_container , i ) ;
2020-06-17 15:29:08 +00:00
2021-01-21 12:31:47 +00:00
auto intersection = MultiPolygon < Point > ( { { { { } } } } ) ;
auto first = boost : : get < MultiPolygon < Point > > ( first_container ) ;
auto second = boost : : get < MultiPolygon < Point > > ( second_container ) ;
/// Orient the polygons correctly.
boost : : geometry : : correct ( first ) ;
boost : : geometry : : correct ( second ) ;
/// Main work here.
2021-02-11 20:37:05 +00:00
boost : : geometry : : intersection ( first , second , intersection ) ;
2020-06-17 15:29:08 +00:00
2021-01-21 12:31:47 +00:00
intersection . erase ( intersection . begin ( ) ) ;
2020-06-21 16:36:43 +00:00
2020-06-17 16:29:31 +00:00
serializer . add ( intersection ) ;
2020-06-17 15:29:08 +00:00
}
2021-01-18 23:51:34 +00:00
return serializer . finalize ( ) ;
2020-06-21 14:54:13 +00:00
}
bool useDefaultImplementationForConstants ( ) const override
{
return true ;
2020-06-17 15:29:08 +00:00
}
} ;
2021-01-21 12:31:47 +00:00
template < >
const char * FunctionPolygonsIntersection < CartesianPoint > : : name = " polygonsIntersectionCartesian " ;
template < >
const char * FunctionPolygonsIntersection < GeographicPoint > : : name = " polygonsIntersectionGeographic " ;
2020-06-17 15:29:08 +00:00
void registerFunctionPolygonsIntersection ( FunctionFactory & factory )
{
2021-01-21 12:31:47 +00:00
factory . registerFunction < FunctionPolygonsIntersection < CartesianPoint > > ( ) ;
factory . registerFunction < FunctionPolygonsIntersection < GeographicPoint > > ( ) ;
2020-06-17 15:29:08 +00:00
}
}