Merge pull request #1196 from yandex/CLICKHOUSE-3201

Clickhouse-3201
This commit is contained in:
alexey-milovidov 2017-09-04 19:56:21 +03:00 committed by GitHub
commit ea8790d077
5 changed files with 200 additions and 4 deletions

View File

@ -1,6 +1,6 @@
# This strings autochanged from release_lib.sh:
set(VERSION_DESCRIBE v1.1.54281-testing)
set(VERSION_REVISION 54281)
set(VERSION_DESCRIBE v1.1.54285-testing)
set(VERSION_REVISION 54285)
# end of autochange
set (VERSION_MAJOR 1)

View File

@ -1,13 +1,191 @@
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionsGeo.h>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <Interpreters/ExpressionActions.h>
#include <DataTypes/DataTypeTuple.h>
#include <Columns/ColumnTuple.h>
namespace DB
{
namespace ErrorCodes
{
extern const int TOO_LESS_ARGUMENTS_FOR_FUNCTION;
extern const int BAD_ARGUMENTS;
}
template <typename... Args>
using PointInPolygonCrossing = boost::geometry::strategy::within::crossings_multiply<Args...>;
template <typename... Args>
using PointInPolygonWinding = boost::geometry::strategy::within::winding<Args...>;
template <typename... Args>
using PointInPolygonFranklin = boost::geometry::strategy::within::franklin<Args...>;
template <template <typename...> typename Strategy>
class FunctionPointInPolygon : public IFunction
{
public:
static const char * name;
static FunctionPtr create(const Context & context)
{
return std::make_shared<FunctionPointInPolygon<Strategy>>();
}
String getName() const override
{
return name;
}
bool isVariadic() const override
{
return true;
}
size_t getNumberOfArguments() const override
{
return 0;
}
void getReturnTypeAndPrerequisitesImpl(
const ColumnsWithTypeAndName & arguments, DataTypePtr & out_return_type, ExpressionActions::Actions & out_prerequisites) override
{
if (arguments.size() < 2)
{
throw Exception("Too few arguments", ErrorCodes::TOO_LESS_ARGUMENTS_FOR_FUNCTION);
}
for (size_t i = 0; i < arguments.size(); ++i)
{
const DataTypeTuple * tuple = checkAndGetDataType<DataTypeTuple>(&*arguments[i].type);
if (tuple == nullptr)
{
throw Exception("Argument " + std::to_string(i+1) + " for function " + getName() + " must be tuple.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
const DataTypes & elems = tuple->getElements();
if (elems.size() != 2)
{
throw Exception("Tuple in argument " + std::to_string(i+1) + " must have exactly two elements.", ErrorCodes::BAD_ARGUMENTS);
}
for (size_t elems_index = 0; elems_index < elems.size(); ++elems_index)
{
if (!checkDataType<DataTypeFloat64>(&*elems[elems_index]))
{
throw Exception("Tuple element " + std::to_string(elems_index + 1) + " in argument " + std::to_string(i+1) + " must be Float64.", ErrorCodes::BAD_ARGUMENTS);
}
}
}
out_return_type = std::make_shared<DataTypeUInt8>();
}
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override
{
if (block.rows() == 0)
{
return;
}
using PointType = boost::geometry::model::d2::point_xy<double>;
using PolygonType = boost::geometry::model::polygon<PointType>;
std::pair<double, double> min, max;
std::vector<PointType> polygon_points(arguments.size()-1);
for (size_t i = 1; i < arguments.size(); ++i)
{
auto const_tuple_col = checkAndGetColumnConst<ColumnTuple>(block.getByPosition(arguments[i]).column.get());
if (!const_tuple_col)
{
throw Exception("Argument " + std::to_string(i+1) + " for function " + getName() + " must be constant tuple.", ErrorCodes::ILLEGAL_COLUMN);
}
TupleBackend data = const_tuple_col->getValue<Tuple>();
const double x = data[0].get<Float64>();
const double y = data[1].get<Float64>();
polygon_points[i-1] = PointType(x, y);
if (i == 1)
{
min.first = x;
min.second = y;
max.first = x;
max.second = y;
}
else
{
min.first = std::min(min.first, x);
max.first = std::max(max.first, x);
min.second = std::min(min.second, y);
max.second = std::max(max.second, y);
}
}
PolygonType polygon;
boost::geometry::assign_points(polygon, polygon_points);
Strategy<PointType> strategy;
auto point_checker = [&](double x, double y) -> bool
{
if (x < min.first || x > max.first || y < min.second || y > max.second)
{
return false;
}
PointType point(x, y);
return boost::geometry::covered_by(point, polygon, strategy);
};
auto point_column_const = checkAndGetColumnConst<ColumnTuple>(block.getByPosition(arguments[0]).column.get());
if (point_column_const)
{
TupleBackend data = point_column_const->getValue<Tuple>();
const double point_x = data[0].get<Float64>();
const double point_y = data[1].get<Float64>();
UInt8 value = point_checker(point_x, point_y) ? 1 : 0;
block.getByPosition(result).column = DataTypeUInt8().createConstColumn(block.rows(), UInt64(value));
return;
}
auto & res = block.getByPosition(result);
res.column = std::make_shared<ColumnUInt8>(block.rows());
IColumn & result_column = *res.column;
auto & result_data = static_cast<ColumnUInt8 &>(result_column).getData();
auto point_column = checkAndGetColumn<ColumnTuple>(block.getByPosition(arguments[0]).column.get());
auto column_x = checkAndGetColumn<ColumnFloat64>(point_column->getData().getByPosition(0).column.get());
auto column_y = checkAndGetColumn<ColumnFloat64>(point_column->getData().getByPosition(1).column.get());
for (size_t i = 0; i < block.rows(); ++i)
{
const double point_x = column_x->getElement(i);
const double point_y = column_y->getElement(i);
result_data[i] = point_checker(point_x, point_y) ? 1 : 0;
}
}
};
template <>
const char * FunctionPointInPolygon<PointInPolygonCrossing>::name = "pointInPolygon";
template <>
const char * FunctionPointInPolygon<PointInPolygonWinding>::name = "pointInPolygonWinding";
template <>
const char * FunctionPointInPolygon<PointInPolygonFranklin>::name = "pointInPolygonFranklin";
void registerFunctionsGeo(FunctionFactory & factory)
{
factory.registerFunction<FunctionGreatCircleDistance>();
factory.registerFunction<FunctionPointInEllipses>();
factory.registerFunction<FunctionPointInPolygon<PointInPolygonFranklin>>();
factory.registerFunction<FunctionPointInPolygon<PointInPolygonWinding>>();
factory.registerFunction<FunctionPointInPolygon<PointInPolygonCrossing>>();
}
}

View File

@ -0,0 +1,9 @@
1
0
0
1
0
0
1
0
0

View File

@ -0,0 +1,9 @@
SELECT pointInPolygonFranklin(tuple(2.0,1.0), tuple(0.0,0.0), tuple(3.0,3.0), tuple(3.0,0.0), tuple(0.0,0.0));
SELECT pointInPolygonFranklin(tuple(1.0,2.0), tuple(0.0,0.0), tuple(3.0,3.0), tuple(3.0,0.0), tuple(0.0,0.0));
SELECT pointInPolygonFranklin(tuple(4.0,1.0), tuple(0.0,0.0), tuple(3.0,3.0), tuple(3.0,0.0), tuple(0.0,0.0));
SELECT pointInPolygon(tuple(2.0,1.0), tuple(0.0,0.0), tuple(3.0,3.0), tuple(3.0,0.0), tuple(0.0,0.0));
SELECT pointInPolygon(tuple(1.0,2.0), tuple(0.0,0.0), tuple(3.0,3.0), tuple(3.0,0.0), tuple(0.0,0.0));
SELECT pointInPolygon(tuple(4.0,1.0), tuple(0.0,0.0), tuple(3.0,3.0), tuple(3.0,0.0), tuple(0.0,0.0));
SELECT pointInPolygonWinding(tuple(2.0,1.0), tuple(0.0,0.0), tuple(3.0,3.0), tuple(3.0,0.0), tuple(0.0,0.0));
SELECT pointInPolygonWinding(tuple(1.0,2.0), tuple(0.0,0.0), tuple(3.0,3.0), tuple(3.0,0.0), tuple(0.0,0.0));
SELECT pointInPolygonWinding(tuple(4.0,1.0), tuple(0.0,0.0), tuple(3.0,3.0), tuple(3.0,0.0), tuple(0.0,0.0));

4
debian/changelog vendored
View File

@ -1,5 +1,5 @@
clickhouse (1.1.54281) unstable; urgency=low
clickhouse (1.1.54285) unstable; urgency=low
* Modified source code
-- <robot-metrika-test@yandex-team.ru> Wed, 23 Aug 2017 15:09:15 +0300
-- <robot-metrika-test@yandex-team.ru> Mon, 04 Sep 2017 17:31:53 +0300