2017-04-01 09:19:00 +00:00
|
|
|
#include <Functions/FunctionFactory.h>
|
2020-03-25 18:52:52 +00:00
|
|
|
#include <Functions/PolygonUtils.h>
|
2019-04-09 19:19:30 +00:00
|
|
|
#include <Functions/FunctionHelpers.h>
|
2016-08-12 16:51:08 +00:00
|
|
|
|
2017-09-04 13:45:50 +00:00
|
|
|
#include <boost/geometry.hpp>
|
|
|
|
#include <boost/geometry/geometries/point_xy.hpp>
|
|
|
|
#include <boost/geometry/geometries/polygon.hpp>
|
|
|
|
|
2017-09-20 02:30:44 +00:00
|
|
|
#include <Columns/ColumnArray.h>
|
2019-04-09 19:19:30 +00:00
|
|
|
#include <Columns/ColumnFixedString.h>
|
|
|
|
#include <Columns/ColumnString.h>
|
|
|
|
#include <Columns/ColumnTuple.h>
|
2018-08-30 18:40:46 +00:00
|
|
|
#include <Common/ObjectPool.h>
|
2019-04-09 19:19:30 +00:00
|
|
|
#include <Common/ProfileEvents.h>
|
|
|
|
#include <DataTypes/DataTypeArray.h>
|
|
|
|
#include <DataTypes/DataTypeString.h>
|
|
|
|
#include <DataTypes/DataTypeTuple.h>
|
2019-06-30 18:20:32 +00:00
|
|
|
#include <DataTypes/DataTypesNumber.h>
|
2019-04-09 19:19:30 +00:00
|
|
|
#include <IO/WriteHelpers.h>
|
|
|
|
#include <Interpreters/ExpressionActions.h>
|
2020-05-20 20:16:32 +00:00
|
|
|
#include <Interpreters/Context.h>
|
2019-04-09 19:19:30 +00:00
|
|
|
|
2018-04-24 07:16:39 +00:00
|
|
|
#include <string>
|
|
|
|
#include <memory>
|
2017-09-04 13:45:50 +00:00
|
|
|
|
2018-01-19 20:22:47 +00:00
|
|
|
|
2017-09-20 02:30:44 +00:00
|
|
|
namespace ProfileEvents
|
|
|
|
{
|
|
|
|
extern const Event PolygonsAddedToPool;
|
|
|
|
extern const Event PolygonsInPoolAllocatedBytes;
|
|
|
|
}
|
2016-08-12 16:51:08 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
2017-09-20 02:30:44 +00:00
|
|
|
|
2017-09-04 13:45:50 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2018-12-07 03:20:27 +00:00
|
|
|
extern const int TOO_FEW_ARGUMENTS_FOR_FUNCTION;
|
2017-09-04 13:45:50 +00:00
|
|
|
extern const int BAD_ARGUMENTS;
|
2017-09-20 02:30:44 +00:00
|
|
|
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
2019-06-30 18:20:32 +00:00
|
|
|
extern const int ILLEGAL_COLUMN;
|
2017-09-04 13:45:50 +00:00
|
|
|
}
|
|
|
|
|
2017-09-20 02:30:44 +00:00
|
|
|
|
2020-05-05 10:34:58 +00:00
|
|
|
template <typename PointInConstPolygonImpl, typename PointInNonConstPolygonImpl>
|
2017-09-20 02:30:44 +00:00
|
|
|
class FunctionPointInPolygon : public IFunction
|
|
|
|
{
|
2017-09-04 13:45:50 +00:00
|
|
|
public:
|
2020-03-25 17:29:26 +00:00
|
|
|
using CoordinateType = Float64;
|
|
|
|
|
|
|
|
using Point = boost::geometry::model::d2::point_xy<CoordinateType>;
|
|
|
|
using Polygon = boost::geometry::model::polygon<Point, false>;
|
|
|
|
using Box = boost::geometry::model::box<Point>;
|
2017-09-20 02:30:44 +00:00
|
|
|
|
2020-03-25 10:13:34 +00:00
|
|
|
static inline const char * name = "pointInPolygon";
|
2017-09-04 13:45:50 +00:00
|
|
|
|
2020-03-25 17:00:54 +00:00
|
|
|
explicit FunctionPointInPolygon(bool validate_) : validate(validate_) {}
|
2020-03-25 10:13:34 +00:00
|
|
|
|
|
|
|
static FunctionPtr create(const Context & context)
|
2017-09-04 13:45:50 +00:00
|
|
|
{
|
2020-05-05 10:34:58 +00:00
|
|
|
return std::make_shared<FunctionPointInPolygon<PointInConstPolygonImpl, PointInNonConstPolygonImpl>>(
|
|
|
|
context.getSettingsRef().validate_polygons);
|
2017-09-04 13:45:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
String getName() const override
|
|
|
|
{
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isVariadic() const override
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t getNumberOfArguments() const override
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-20 02:30:44 +00:00
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
2017-09-04 13:45:50 +00:00
|
|
|
{
|
|
|
|
if (arguments.size() < 2)
|
|
|
|
{
|
2018-12-07 03:20:27 +00:00
|
|
|
throw Exception("Too few arguments", ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION);
|
2017-09-04 13:45:50 +00:00
|
|
|
}
|
|
|
|
|
2020-05-22 19:15:29 +00:00
|
|
|
/** We allow function invocation in one of the following forms:
|
|
|
|
*
|
|
|
|
* pointInPolygon((x, y), [(x1, y1), (x2, y2), ...])
|
|
|
|
* - simple polygon
|
|
|
|
* pointInPolygon((x, y), [(x1, y1), (x2, y2), ...], [(x21, y21), (x22, y22), ...], ...)
|
|
|
|
* - polygon with a number of holes, each hole as a subsequent argument.
|
|
|
|
* pointInPolygon((x, y), [[(x1, y1), (x2, y2), ...], [(x21, y21), (x22, y22), ...], ...])
|
|
|
|
* - polygon with a number of holes, all as multidimensional array
|
|
|
|
*/
|
|
|
|
|
2020-05-02 16:48:36 +00:00
|
|
|
auto validate_tuple = [this](size_t i, const DataTypeTuple * tuple)
|
|
|
|
{
|
2017-09-04 13:45:50 +00:00
|
|
|
if (tuple == nullptr)
|
2020-05-02 06:51:10 +00:00
|
|
|
throw Exception(getMessagePrefix(i) + " must contain a tuple", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
2017-09-04 13:45:50 +00:00
|
|
|
|
2017-09-20 02:30:44 +00:00
|
|
|
const DataTypes & elements = tuple->getElements();
|
2017-09-04 13:45:50 +00:00
|
|
|
|
2017-09-20 02:30:44 +00:00
|
|
|
if (elements.size() != 2)
|
2020-05-02 06:51:10 +00:00
|
|
|
throw Exception(getMessagePrefix(i) + " must have exactly two elements", ErrorCodes::BAD_ARGUMENTS);
|
2017-09-04 13:45:50 +00:00
|
|
|
|
2017-09-20 02:30:44 +00:00
|
|
|
for (auto j : ext::range(0, elements.size()))
|
2017-09-04 13:45:50 +00:00
|
|
|
{
|
2019-05-24 12:11:03 +00:00
|
|
|
if (!isNativeNumber(elements[j]))
|
2017-09-04 13:45:50 +00:00
|
|
|
{
|
2020-05-02 06:51:10 +00:00
|
|
|
throw Exception(getMessagePrefix(i) + " must contain numeric tuple at position " + toString(j + 1),
|
2017-09-20 02:30:44 +00:00
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
2017-09-04 13:45:50 +00:00
|
|
|
}
|
|
|
|
}
|
2020-05-02 06:51:10 +00:00
|
|
|
};
|
|
|
|
|
2020-05-02 16:48:36 +00:00
|
|
|
validate_tuple(0, checkAndGetDataType<DataTypeTuple>(arguments[0].get()));
|
2020-05-02 06:51:10 +00:00
|
|
|
|
2020-05-02 16:48:36 +00:00
|
|
|
if (arguments.size() == 2)
|
|
|
|
{
|
2020-05-10 00:09:51 +00:00
|
|
|
const auto * array = checkAndGetDataType<DataTypeArray>(arguments[1].get());
|
2020-05-02 06:51:10 +00:00
|
|
|
if (array == nullptr)
|
|
|
|
throw Exception(getMessagePrefix(1) + " must contain an array of tuples or an array of arrays of tuples.",
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
2020-05-10 00:09:51 +00:00
|
|
|
const auto * nested_array = checkAndGetDataType<DataTypeArray>(array->getNestedType().get());
|
2020-05-02 16:48:36 +00:00
|
|
|
if (nested_array != nullptr)
|
|
|
|
{
|
2020-05-02 06:51:10 +00:00
|
|
|
array = nested_array;
|
|
|
|
}
|
|
|
|
|
2020-05-02 16:48:36 +00:00
|
|
|
validate_tuple(1, checkAndGetDataType<DataTypeTuple>(array->getNestedType().get()));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (size_t i = 1; i < arguments.size(); i++)
|
|
|
|
{
|
2020-05-10 00:09:51 +00:00
|
|
|
const auto * array = checkAndGetDataType<DataTypeArray>(arguments[i].get());
|
2020-05-02 06:51:10 +00:00
|
|
|
if (array == nullptr)
|
|
|
|
throw Exception(getMessagePrefix(i) + " must contain an array of tuples",
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
2020-05-02 16:48:36 +00:00
|
|
|
validate_tuple(i, checkAndGetDataType<DataTypeTuple>(array->getNestedType().get()));
|
2020-05-02 06:51:10 +00:00
|
|
|
}
|
2017-09-04 13:45:50 +00:00
|
|
|
}
|
|
|
|
|
2017-09-20 02:30:44 +00:00
|
|
|
return std::make_shared<DataTypeUInt8>();
|
2017-09-04 13:45:50 +00:00
|
|
|
}
|
|
|
|
|
2020-05-02 06:51:10 +00:00
|
|
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override
|
2017-09-04 13:45:50 +00:00
|
|
|
{
|
2017-09-20 02:30:44 +00:00
|
|
|
const IColumn * point_col = block.getByPosition(arguments[0]).column.get();
|
2020-04-22 08:45:14 +00:00
|
|
|
const auto * const_tuple_col = checkAndGetColumn<ColumnConst>(point_col);
|
2017-09-20 02:30:44 +00:00
|
|
|
if (const_tuple_col)
|
|
|
|
point_col = &const_tuple_col->getDataColumn();
|
2017-09-04 13:45:50 +00:00
|
|
|
|
2020-05-02 06:51:10 +00:00
|
|
|
const auto * tuple_col = checkAndGetColumn<ColumnTuple>(point_col);
|
2017-09-20 02:30:44 +00:00
|
|
|
if (!tuple_col)
|
|
|
|
throw Exception("First argument for function " + getName() + " must be constant array of tuples.",
|
|
|
|
ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
|
2020-03-25 17:29:26 +00:00
|
|
|
const auto & tuple_columns = tuple_col->getColumns();
|
2017-09-20 02:30:44 +00:00
|
|
|
|
2020-05-02 06:51:10 +00:00
|
|
|
const IColumn * poly_col = block.getByPosition(arguments[1]).column.get();
|
2020-05-22 13:50:12 +00:00
|
|
|
const ColumnConst * const_poly_col = checkAndGetColumn<ColumnConst>(poly_col);
|
2020-05-02 06:51:10 +00:00
|
|
|
|
|
|
|
bool point_is_const = const_tuple_col != nullptr;
|
|
|
|
bool poly_is_const = const_poly_col != nullptr;
|
|
|
|
|
2020-05-22 14:21:49 +00:00
|
|
|
if (poly_is_const)
|
2020-05-02 16:48:36 +00:00
|
|
|
{
|
2020-05-22 14:21:49 +00:00
|
|
|
Polygon polygon;
|
|
|
|
parsePolygon(block, arguments, 0, validate, polygon);
|
|
|
|
|
2020-05-22 19:37:56 +00:00
|
|
|
using Pool = ObjectPoolMap<PointInConstPolygonImpl, UInt128>;
|
|
|
|
/// C++11 has thread-safe function-local statics.
|
2020-05-22 19:15:29 +00:00
|
|
|
static Pool known_polygons;
|
|
|
|
|
|
|
|
auto factory = [&polygon]()
|
|
|
|
{
|
|
|
|
auto ptr = std::make_unique<PointInConstPolygonImpl>(polygon);
|
|
|
|
|
|
|
|
ProfileEvents::increment(ProfileEvents::PolygonsAddedToPool);
|
|
|
|
ProfileEvents::increment(ProfileEvents::PolygonsInPoolAllocatedBytes, ptr->getAllocatedBytes());
|
|
|
|
|
|
|
|
return ptr.release();
|
|
|
|
};
|
|
|
|
|
2020-05-22 19:37:56 +00:00
|
|
|
auto impl = known_polygons.get(sipHash128(polygon), factory);
|
2020-05-22 19:15:29 +00:00
|
|
|
|
2020-05-22 14:21:49 +00:00
|
|
|
if (point_is_const)
|
2020-05-02 16:48:36 +00:00
|
|
|
{
|
2020-05-22 19:15:29 +00:00
|
|
|
bool is_in = impl->contains(tuple_columns[0]->getFloat64(0), tuple_columns[1]->getFloat64(0));
|
2020-05-22 14:21:49 +00:00
|
|
|
block.getByPosition(result).column = block.getByPosition(result).type->createColumnConst(input_rows_count, is_in);
|
2020-05-02 06:51:10 +00:00
|
|
|
}
|
2020-05-22 14:21:49 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
auto res_column = ColumnVector<UInt8>::create(input_rows_count);
|
|
|
|
auto & data = res_column->getData();
|
2020-05-02 06:51:10 +00:00
|
|
|
|
2020-05-22 19:15:29 +00:00
|
|
|
for (size_t i = 0; i < input_rows_count; ++i)
|
|
|
|
data[i] = impl->contains(tuple_columns[0]->getFloat64(i), tuple_columns[1]->getFloat64(i));
|
2020-05-02 06:51:10 +00:00
|
|
|
|
2020-05-22 14:21:49 +00:00
|
|
|
block.getByPosition(result).column = std::move(res_column);
|
|
|
|
}
|
2020-05-22 13:50:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-22 14:21:49 +00:00
|
|
|
auto res_column = ColumnVector<UInt8>::create(input_rows_count);
|
|
|
|
auto & data = res_column->getData();
|
|
|
|
|
|
|
|
Polygon polygon;
|
|
|
|
for (size_t i = 0; i < input_rows_count; ++i)
|
|
|
|
{
|
|
|
|
/// Validation is used only for constant polygons, otherwise it's too computational heavy.
|
|
|
|
parsePolygon(block, arguments, i, false, polygon);
|
2020-05-22 19:15:29 +00:00
|
|
|
PointInNonConstPolygonImpl impl(polygon);
|
2020-05-22 14:21:49 +00:00
|
|
|
size_t point_index = point_is_const ? 0 : i;
|
2020-05-22 19:15:29 +00:00
|
|
|
data[i] = impl.contains(tuple_columns[0]->getFloat64(point_index), tuple_columns[1]->getFloat64(point_index));
|
2020-05-22 14:21:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
block.getByPosition(result).column = std::move(res_column);
|
2020-05-22 13:50:12 +00:00
|
|
|
}
|
2017-09-20 02:30:44 +00:00
|
|
|
}
|
|
|
|
|
2020-05-02 06:51:10 +00:00
|
|
|
|
2017-09-20 02:30:44 +00:00
|
|
|
private:
|
2020-03-25 10:13:34 +00:00
|
|
|
bool validate;
|
2017-09-20 02:30:44 +00:00
|
|
|
|
2020-05-02 06:51:10 +00:00
|
|
|
std::string getMessagePrefix(size_t i) const
|
|
|
|
{
|
|
|
|
return "Argument " + toString(i + 1) + " for function " + getName();
|
|
|
|
}
|
|
|
|
|
2020-05-22 14:07:17 +00:00
|
|
|
void parsePolygonFromSingleColumn(Block & block, const ColumnNumbers & arguments, size_t i, Polygon & out_polygon) const
|
2017-09-20 02:30:44 +00:00
|
|
|
{
|
2020-05-02 06:51:10 +00:00
|
|
|
const auto & poly = block.getByPosition(arguments[1]).column.get();
|
|
|
|
const auto * column_const = checkAndGetColumn<ColumnConst>(poly);
|
|
|
|
const auto * array_col =
|
|
|
|
column_const ? checkAndGetColumn<ColumnArray>(column_const->getDataColumn()) : checkAndGetColumn<ColumnArray>(poly);
|
|
|
|
|
|
|
|
if (!array_col)
|
|
|
|
throw Exception(getMessagePrefix(1) + " must contain an array of tuples or an array of arrays of tuples",
|
|
|
|
ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
|
|
|
|
const auto * nested_array_col = checkAndGetColumn<ColumnArray>(array_col->getData());
|
|
|
|
const auto & tuple_data = nested_array_col ? nested_array_col->getData() : array_col->getData();
|
|
|
|
const auto & tuple_col = checkAndGetColumn<ColumnTuple>(tuple_data);
|
|
|
|
if (!tuple_col)
|
|
|
|
throw Exception(getMessagePrefix(1) + " must contain an array of tuples or an array of arrays of tuples",
|
|
|
|
ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
|
|
|
|
const auto & tuple_columns = tuple_col->getColumns();
|
|
|
|
const auto & x_column = tuple_columns[0];
|
|
|
|
const auto & y_column = tuple_columns[1];
|
|
|
|
|
2020-05-02 16:48:36 +00:00
|
|
|
auto parse_polygon_part = [&x_column, &y_column](auto & container, size_t l, size_t r)
|
|
|
|
{
|
2020-05-02 06:51:10 +00:00
|
|
|
for (auto j : ext::range(l, r))
|
|
|
|
{
|
|
|
|
CoordinateType x_coord = x_column->getFloat64(j);
|
|
|
|
CoordinateType y_coord = y_column->getFloat64(j);
|
|
|
|
|
|
|
|
container.push_back(Point(x_coord, y_coord));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-05-02 16:48:36 +00:00
|
|
|
if (nested_array_col)
|
|
|
|
{
|
|
|
|
for (auto j : ext::range(array_col->getOffsets()[i - 1], array_col->getOffsets()[i]))
|
|
|
|
{
|
2020-05-02 06:51:10 +00:00
|
|
|
size_t l = nested_array_col->getOffsets()[j - 1];
|
|
|
|
size_t r = nested_array_col->getOffsets()[j];
|
2020-05-22 14:07:17 +00:00
|
|
|
if (out_polygon.outer().empty())
|
2020-05-02 16:48:36 +00:00
|
|
|
{
|
2020-05-22 14:07:17 +00:00
|
|
|
parse_polygon_part(out_polygon.outer(), l, r);
|
2020-05-02 16:48:36 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-22 14:07:17 +00:00
|
|
|
out_polygon.inners().emplace_back();
|
|
|
|
parse_polygon_part(out_polygon.inners().back(), l, r);
|
2020-05-02 06:51:10 +00:00
|
|
|
}
|
|
|
|
}
|
2020-05-02 16:48:36 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-02 06:51:10 +00:00
|
|
|
size_t l = array_col->getOffsets()[i - 1];
|
|
|
|
size_t r = array_col->getOffsets()[i];
|
2017-09-04 13:45:50 +00:00
|
|
|
|
2020-05-22 14:07:17 +00:00
|
|
|
parse_polygon_part(out_polygon.outer(), l, r);
|
2020-05-02 06:51:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-22 14:07:17 +00:00
|
|
|
void parsePolygonFromMultipleColumns(Block & block, const ColumnNumbers & arguments, size_t, Polygon & out_polygon) const
|
2020-05-02 06:51:10 +00:00
|
|
|
{
|
2017-09-20 02:30:44 +00:00
|
|
|
for (size_t i = 1; i < arguments.size(); ++i)
|
2017-09-04 13:45:50 +00:00
|
|
|
{
|
2020-04-22 08:45:14 +00:00
|
|
|
const auto * const_col = checkAndGetColumn<ColumnConst>(block.getByPosition(arguments[i]).column.get());
|
2020-05-02 06:51:10 +00:00
|
|
|
if (!const_col)
|
|
|
|
throw Exception("Multi-argument version of function " + getName() + " works only with const polygon",
|
|
|
|
ErrorCodes::BAD_ARGUMENTS);
|
|
|
|
|
|
|
|
const auto * array_col = checkAndGetColumn<ColumnArray>(&const_col->getDataColumn());
|
2020-04-22 08:45:14 +00:00
|
|
|
const auto * tuple_col = array_col ? checkAndGetColumn<ColumnTuple>(&array_col->getData()) : nullptr;
|
2017-09-04 20:21:55 +00:00
|
|
|
|
2017-09-20 02:30:44 +00:00
|
|
|
if (!tuple_col)
|
2020-05-02 06:51:10 +00:00
|
|
|
throw Exception(getMessagePrefix(i) + " must be constant array of tuples", ErrorCodes::ILLEGAL_COLUMN);
|
2017-09-04 13:45:50 +00:00
|
|
|
|
2017-12-08 00:50:25 +00:00
|
|
|
const auto & tuple_columns = tuple_col->getColumns();
|
|
|
|
const auto & column_x = tuple_columns[0];
|
|
|
|
const auto & column_y = tuple_columns[1];
|
2017-09-04 20:21:55 +00:00
|
|
|
|
2020-05-22 14:07:17 +00:00
|
|
|
if (!out_polygon.outer().empty())
|
|
|
|
out_polygon.inners().emplace_back();
|
2017-09-04 13:45:50 +00:00
|
|
|
|
2020-05-22 14:07:17 +00:00
|
|
|
auto & container = out_polygon.outer().empty() ? out_polygon.outer() : out_polygon.inners().back();
|
2017-09-04 13:45:50 +00:00
|
|
|
|
2017-09-20 02:30:44 +00:00
|
|
|
auto size = column_x->size();
|
2017-09-04 13:45:50 +00:00
|
|
|
|
2017-09-20 02:30:44 +00:00
|
|
|
if (size == 0)
|
2020-05-02 06:51:10 +00:00
|
|
|
throw Exception(getMessagePrefix(i) + " shouldn't be empty.", ErrorCodes::ILLEGAL_COLUMN);
|
2017-09-20 02:30:44 +00:00
|
|
|
|
|
|
|
for (auto j : ext::range(0, size))
|
|
|
|
{
|
2020-03-25 17:29:26 +00:00
|
|
|
CoordinateType x_coord = column_x->getFloat64(j);
|
|
|
|
CoordinateType y_coord = column_y->getFloat64(j);
|
|
|
|
container.push_back(Point(x_coord, y_coord));
|
2017-09-20 02:30:44 +00:00
|
|
|
}
|
2020-03-25 10:13:34 +00:00
|
|
|
}
|
2020-05-02 06:51:10 +00:00
|
|
|
}
|
|
|
|
|
2020-05-22 14:07:17 +00:00
|
|
|
void parsePolygon(Block & block, const ColumnNumbers & arguments, size_t i, bool validate_polygon, Polygon & out_polygon) const
|
2020-05-02 06:51:10 +00:00
|
|
|
{
|
2020-05-22 14:07:17 +00:00
|
|
|
out_polygon.clear();
|
|
|
|
|
2020-05-02 16:48:36 +00:00
|
|
|
if (arguments.size() == 2)
|
2020-05-22 14:07:17 +00:00
|
|
|
parsePolygonFromSingleColumn(block, arguments, i, out_polygon);
|
2020-05-02 16:48:36 +00:00
|
|
|
else
|
2020-05-22 14:07:17 +00:00
|
|
|
parsePolygonFromMultipleColumns(block, arguments, i, out_polygon);
|
2020-05-02 06:51:10 +00:00
|
|
|
|
2020-05-22 14:07:17 +00:00
|
|
|
boost::geometry::correct(out_polygon);
|
2020-03-25 10:13:34 +00:00
|
|
|
|
2020-03-25 17:00:54 +00:00
|
|
|
#if !defined(__clang_analyzer__) /// It does not like boost.
|
2020-05-22 13:50:12 +00:00
|
|
|
if (validate_polygon)
|
2020-03-25 10:13:34 +00:00
|
|
|
{
|
|
|
|
std::string failure_message;
|
2020-05-22 14:07:17 +00:00
|
|
|
auto is_valid = boost::geometry::is_valid(out_polygon, failure_message);
|
2020-03-25 10:13:34 +00:00
|
|
|
if (!is_valid)
|
|
|
|
throw Exception("Polygon is not valid: " + failure_message, ErrorCodes::BAD_ARGUMENTS);
|
2017-09-04 13:45:50 +00:00
|
|
|
}
|
2020-03-25 17:00:54 +00:00
|
|
|
#endif
|
2017-09-04 13:45:50 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-04-09 19:19:30 +00:00
|
|
|
|
2019-06-30 18:20:32 +00:00
|
|
|
void registerFunctionPointInPolygon(FunctionFactory & factory)
|
2016-08-12 16:51:08 +00:00
|
|
|
{
|
2020-05-05 10:34:58 +00:00
|
|
|
factory.registerFunction<FunctionPointInPolygon<PointInPolygonWithGrid<Float64>, PointInPolygonTrivial<Float64>>>();
|
2016-08-12 16:51:08 +00:00
|
|
|
}
|
2019-06-30 18:20:32 +00:00
|
|
|
|
2016-08-12 16:51:08 +00:00
|
|
|
}
|