This commit is contained in:
Nikita Mikhailov 2021-01-19 17:52:53 +03:00 committed by Nikita Mikhaylov
parent 3e36fae3df
commit cfee417ce0
18 changed files with 325 additions and 445 deletions

View File

@ -62,33 +62,20 @@ public:
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
auto get_parser = [&arguments] (size_t i) {
const auto * const_col =
checkAndGetColumn<ColumnConst>(arguments[i].column.get());
bool is_const = static_cast<bool>(const_col);
return std::pair<bool, CartesianGeometryFromColumnParser>{is_const, is_const ?
makeCartesianGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), arguments[i].type, arguments[i].name)) :
makeCartesianGeometryFromColumnParser(arguments[i])};
};
auto [is_first_polygon_const, first_parser] = get_parser(0);
auto first_parser = makeGeometryFromColumnParser<CartesianPoint>(arguments[0]);
auto first_container = createContainer(first_parser);
auto [is_second_polygon_const, second_parser] = get_parser(1);
auto second_parser = makeGeometryFromColumnParser<CartesianPoint>(arguments[1]);
auto second_container = createContainer(second_parser);
CartesianMultiPolygonSerializer serializer;
MultiPolygonSerializer<CartesianPoint> serializer;
for (size_t i = 0; i < input_rows_count; i++)
{
if (!is_first_polygon_const || i == 0)
get(first_parser, first_container, i);
if (!is_second_polygon_const || i == 0)
get(second_parser, second_container, i);
get<CartesianPoint>(first_parser, first_container, i);
get<CartesianPoint>(second_parser, second_container, i);
CartesianGeometry polygons_union = CartesianMultiPolygon({{{{}}}});
Geometry<CartesianPoint> polygons_union = CartesianMultiPolygon({{{{}}}});
boost::geometry::union_(
boost::get<CartesianMultiPolygon>(first_container),
boost::get<CartesianMultiPolygon>(second_container),

View File

@ -30,11 +30,11 @@ public:
}
};
template <typename Geometry>
template <typename Point>
class Getter : public boost::static_visitor<void>
{
public:
constexpr Getter(Geometry & container_, size_t i_)
constexpr Getter(Geometry<Point> & container_, size_t i_)
: container(container_)
, i(i_)
{}
@ -46,7 +46,7 @@ public:
}
private:
Geometry & container;
Geometry<Point> & container;
size_t i;
};
@ -64,52 +64,41 @@ Parser makeParser(const ColumnWithTypeAndName & col)
}
CartesianGeometryFromColumnParser makeCartesianGeometryFromColumnParser(const ColumnWithTypeAndName & col)
template <typename Point>
Geometry<Point> createContainer(const GeometryFromColumnParser<Point> & parser)
{
static ContainerCreator<Geometry<Point>> creator;
return boost::apply_visitor(creator, parser);
}
template <typename Point>
void get(const GeometryFromColumnParser<Point> & parser, Geometry<Point> & container, size_t i)
{
boost::apply_visitor(Getter<Point>(container, i), parser);
}
template <typename Point>
GeometryFromColumnParser<Point> makeGeometryFromColumnParser(const ColumnWithTypeAndName & col)
{
switch (getArrayDepth(col.type, 3))
{
case 0: return makeParser<DataTypeCustomPointSerialization, PointFromColumnParser<CartesianPoint>>(col);
case 1: return makeParser<DataTypeCustomRingSerialization, CartesianRingFromColumnParser>(col);
case 2: return makeParser<DataTypeCustomPolygonSerialization, CartesianPolygonFromColumnParser>(col);
case 3: return makeParser<DataTypeCustomMultiPolygonSerialization, CartesianMultiPolygonFromColumnParser>(col);
case 0: return makeParser<DataTypeCustomPointSerialization, PointFromColumnParser<Point>>(col);
case 1: return makeParser<DataTypeCustomRingSerialization, RingFromColumnParser<Point>>(col);
case 2: return makeParser<DataTypeCustomPolygonSerialization, PolygonFromColumnParser<Point>>(col);
case 3: return makeParser<DataTypeCustomMultiPolygonSerialization, MultiPolygonFromColumnParser<Point>>(col);
default: throw Exception("Cannot parse geometry from column with type " + col.type->getName()
+ ", array depth is too big", ErrorCodes::ILLEGAL_COLUMN);
}
}
CartesianGeometry createContainer(const CartesianGeometryFromColumnParser & parser)
{
static ContainerCreator<CartesianGeometry> creator;
return boost::apply_visitor(creator, parser);
}
/// Explicit instantiations to avoid linker errors.
void get(const CartesianGeometryFromColumnParser & parser, CartesianGeometry & container, size_t i)
{
boost::apply_visitor(Getter(container, i), parser);
}
template Geometry<CartesianPoint> createContainer(const GeometryFromColumnParser<CartesianPoint> &);
template Geometry<GeographicPoint> createContainer(const GeometryFromColumnParser<GeographicPoint> &);
template void get(const GeometryFromColumnParser<CartesianPoint> & parser, Geometry<CartesianPoint> & container, size_t i);
template void get(const GeometryFromColumnParser<GeographicPoint> & parser, Geometry<GeographicPoint> & container, size_t i);
template GeometryFromColumnParser<CartesianPoint> makeGeometryFromColumnParser(const ColumnWithTypeAndName & col);
template GeometryFromColumnParser<GeographicPoint> makeGeometryFromColumnParser(const ColumnWithTypeAndName & col);
GeographicGeometryFromColumnParser makeGeographicGeometryFromColumnParser(const ColumnWithTypeAndName & col)
{
switch (getArrayDepth(col.type, 3))
{
case 0: return makeParser<DataTypeCustomPointSerialization, PointFromColumnParser<GeographicPoint>>(col);
case 1: return makeParser<DataTypeCustomRingSerialization, GeographicRingFromColumnParser>(col);
case 2: return makeParser<DataTypeCustomPolygonSerialization, GeographicPolygonFromColumnParser>(col);
case 3: return makeParser<DataTypeCustomMultiPolygonSerialization, GeographicMultiPolygonFromColumnParser>(col);
default: throw Exception("Cannot parse geometry from column with type " + col.type->getName()
+ ", array depth is too big", ErrorCodes::ILLEGAL_COLUMN);
}
}
GeographicGeometry createContainer(const GeographicGeometryFromColumnParser & parser)
{
static ContainerCreator<GeographicGeometry> creator;
return boost::apply_visitor(creator, parser);
}
void get(const GeographicGeometryFromColumnParser & parser, GeographicGeometry & container, size_t i)
{
boost::apply_visitor(Getter(container, i), parser);
}
}

View File

@ -27,17 +27,31 @@ namespace ErrorCodes
}
namespace bg = boost::geometry;
template <typename Point>
using Ring = bg::model::ring<Point>;
template <typename Point>
using Polygon = bg::model::polygon<Point>;
template <typename Point>
using MultiPolygon = bg::model::multi_polygon<Polygon<Point>>;
template <typename Point>
using Geometry = boost::variant<Point, Ring<Point>, Polygon<Point>, MultiPolygon<Point>>;
using CartesianPoint = bg::model::d2::point_xy<Float64>;
using CartesianRing = bg::model::ring<CartesianPoint>;
using CartesianPolygon = bg::model::polygon<CartesianPoint>;
using CartesianMultiPolygon = bg::model::multi_polygon<CartesianPolygon>;
using CartesianGeometry = boost::variant<CartesianPoint, CartesianRing, CartesianPolygon, CartesianMultiPolygon>;
using CartesianRing = Ring<CartesianPoint>;
using CartesianPolygon = Polygon<CartesianPoint>;
using CartesianMultiPolygon = MultiPolygon<CartesianPoint>;
using CartesianGeometry = Geometry<CartesianPoint>;
using GeographicPoint = bg::model::point<Float64, 2, bg::cs::geographic<bg::degree>>;
using GeographicRing = bg::model::ring<GeographicPoint>;
using GeographicPolygon = bg::model::polygon<GeographicPoint>;
using GeographicMultiPolygon = bg::model::multi_polygon<GeographicPolygon>;
using GeographicGeometry = boost::variant<GeographicPoint, GeographicRing, GeographicPolygon, GeographicMultiPolygon>;
using GeographicRing = Ring<GeographicPoint>;
using GeographicPolygon = Polygon<GeographicPoint>;
using GeographicMultiPolygon = MultiPolygon<GeographicPoint>;
using GeographicGeometry = Geometry<GeographicPoint>;
/**
* Class which takes some boost type and returns a pair of numbers.
@ -111,27 +125,27 @@ private:
const Float64 * second;
};
template<class Geometry, class RingType, class PointParser>
template<class Point>
class RingFromColumnParser
{
public:
RingFromColumnParser(ColumnPtr col_)
: offsets(static_cast<const ColumnArray &>(*col_).getOffsets())
, pointParser(static_cast<const ColumnArray &>(*col_).getDataPtr())
, point_parser(static_cast<const ColumnArray &>(*col_).getDataPtr())
{
}
Geometry createContainer() const
Geometry<Point> createContainer() const
{
return RingType();
return Ring<Point>();
}
void get(Geometry & container, size_t i) const
void get(Geometry<Point> & container, size_t i) const
{
get(boost::get<RingType>(container), i);
get(boost::get<Ring<Point>>(container), i);
}
void get(RingType & container, size_t i) const
void get(Ring<Point> & container, size_t i) const
{
size_t l = offsets[i - 1];
size_t r = offsets[i];
@ -141,7 +155,7 @@ public:
container.resize(r - l);
for (size_t j = l; j < r; j++) {
pointParser.get(container[j - l], j);
point_parser.get(container[j - l], j);
}
// make ring closed
@ -153,138 +167,127 @@ public:
private:
const IColumn::Offsets & offsets;
const PointParser pointParser;
const PointFromColumnParser<Point> point_parser;
};
template<class Geometry, class PolygonType, class RingParser>
template<class Point>
class PolygonFromColumnParser
{
public:
PolygonFromColumnParser(ColumnPtr col_)
: offsets(static_cast<const ColumnArray &>(*col_).getOffsets())
, ringParser(static_cast<const ColumnArray &>(*col_).getDataPtr())
, ring_parser(static_cast<const ColumnArray &>(*col_).getDataPtr())
{}
Geometry createContainer() const
Geometry<Point> createContainer() const
{
return PolygonType();
return Polygon<Point>();
}
void get(Geometry & container, size_t i) const
void get(Geometry<Point> & container, size_t i) const
{
get(boost::get<PolygonType>(container), i);
get(boost::get<Polygon<Point>>(container), i);
}
void get(PolygonType & container, size_t i) const
void get(Polygon<Point> & container, size_t i) const
{
size_t l = offsets[i - 1];
size_t r = offsets[i];
ringParser.get(container.outer(), l);
ring_parser.get(container.outer(), l);
container.inners().resize(r - l - 1);
for (size_t j = l + 1; j < r; j++)
{
ringParser.get(container.inners()[j - l - 1], j);
ring_parser.get(container.inners()[j - l - 1], j);
}
}
private:
const IColumn::Offsets & offsets;
const RingParser ringParser;
const RingFromColumnParser<Point> ring_parser;
};
template<class Geometry, class MultiPolygonType, class PolygonParser>
template<class Point>
class MultiPolygonFromColumnParser
{
public:
MultiPolygonFromColumnParser(ColumnPtr col_)
: offsets(static_cast<const ColumnArray &>(*col_).getOffsets())
, polygonParser(static_cast<const ColumnArray &>(*col_).getDataPtr())
, polygon_parser(static_cast<const ColumnArray &>(*col_).getDataPtr())
{}
Geometry createContainer() const
Geometry<Point> createContainer() const
{
return MultiPolygonType();
return MultiPolygon<Point>();
}
void get(Geometry & container, size_t i) const
void get(Geometry<Point> & container, size_t i) const
{
MultiPolygonType & multi_polygon = boost::get<MultiPolygonType>(container);
auto & multi_polygon = boost::get<MultiPolygon<Point>>(container);
size_t l = offsets[i - 1];
size_t r = offsets[i];
multi_polygon.resize(r - l);
for (size_t j = l; j < r; j++)
{
polygonParser.get(multi_polygon[j - l], j);
polygon_parser.get(multi_polygon[j - l], j);
}
}
private:
const IColumn::Offsets & offsets;
const PolygonParser polygonParser;
const PolygonFromColumnParser<Point> polygon_parser;
};
/// Cartesian coordinates
using CartesianRingFromColumnParser = RingFromColumnParser<CartesianGeometry, CartesianRing, PointFromColumnParser<CartesianPoint>>;
using CartesianPolygonFromColumnParser = PolygonFromColumnParser<CartesianGeometry, CartesianPolygon, CartesianRingFromColumnParser>;
using CartesianMultiPolygonFromColumnParser = MultiPolygonFromColumnParser<CartesianGeometry, CartesianMultiPolygon, CartesianPolygonFromColumnParser>;
using CartesianGeometryFromColumnParser = boost::variant<
PointFromColumnParser<CartesianPoint>,
CartesianRingFromColumnParser,
CartesianPolygonFromColumnParser,
CartesianMultiPolygonFromColumnParser
template <typename Point>
using GeometryFromColumnParser = boost::variant<
PointFromColumnParser<Point>,
RingFromColumnParser<Point>,
PolygonFromColumnParser<Point>,
MultiPolygonFromColumnParser<Point>
>;
CartesianGeometry createContainer(const CartesianGeometryFromColumnParser & parser);
template <typename Point>
Geometry<Point> createContainer(const GeometryFromColumnParser<Point> & parser);
void get(const CartesianGeometryFromColumnParser & parser, CartesianGeometry & container, size_t i);
extern template Geometry<CartesianPoint> createContainer(const GeometryFromColumnParser<CartesianPoint> & parser);
extern template Geometry<GeographicPoint> createContainer(const GeometryFromColumnParser<GeographicPoint> & parser);
CartesianGeometryFromColumnParser makeCartesianGeometryFromColumnParser(const ColumnWithTypeAndName & col);
template <typename Point>
void get(const GeometryFromColumnParser<Point> & parser, Geometry<Point> & container, size_t i);
/// Geographic coordinates
extern template void get(const GeometryFromColumnParser<CartesianPoint> & parser, Geometry<CartesianPoint> & container, size_t i);
extern template void get(const GeometryFromColumnParser<GeographicPoint> & parser, Geometry<GeographicPoint> & container, size_t i);
using GeographicRingFromColumnParser = RingFromColumnParser<GeographicGeometry, GeographicRing, PointFromColumnParser<GeographicPoint>>;
using GeographicPolygonFromColumnParser = PolygonFromColumnParser<GeographicGeometry, GeographicPolygon, GeographicRingFromColumnParser>;
using GeographicMultiPolygonFromColumnParser = MultiPolygonFromColumnParser<GeographicGeometry, GeographicMultiPolygon, GeographicPolygonFromColumnParser>;
template <typename Point>
GeometryFromColumnParser<Point> makeGeometryFromColumnParser(const ColumnWithTypeAndName & col);
using GeographicGeometryFromColumnParser = boost::variant<
PointFromColumnParser<GeographicPoint>,
GeographicRingFromColumnParser,
GeographicPolygonFromColumnParser,
GeographicMultiPolygonFromColumnParser
>;
extern template GeometryFromColumnParser<CartesianPoint> makeGeometryFromColumnParser(const ColumnWithTypeAndName & col);
extern template GeometryFromColumnParser<GeographicPoint> makeGeometryFromColumnParser(const ColumnWithTypeAndName & col);
GeographicGeometry createContainer(const GeographicGeometryFromColumnParser & parser);
void get(const GeographicGeometryFromColumnParser & parser, GeographicGeometry & container, size_t i);
GeographicGeometryFromColumnParser makeGeographicGeometryFromColumnParser(const ColumnWithTypeAndName & col);
class CartesianPointSerializerVisitor : public boost::static_visitor<void>
/// To serialize Geographic or Cartesian point (a pair of numbers in both cases).
template <typename Point>
class PointSerializerVisitor : public boost::static_visitor<void>
{
public:
CartesianPointSerializerVisitor()
: x(ColumnFloat64::create())
, y(ColumnFloat64::create())
PointSerializerVisitor()
: first(ColumnFloat64::create())
, second(ColumnFloat64::create())
{}
CartesianPointSerializerVisitor(size_t n)
: x(ColumnFloat64::create(n))
, y(ColumnFloat64::create(n))
PointSerializerVisitor(size_t n)
: first(ColumnFloat64::create(n))
, second(ColumnFloat64::create(n))
{}
void operator()(const CartesianPoint & point)
void operator()(const Point & point)
{
x->insertValue(point.get<0>());
y->insertValue(point.get<1>());
first->insertValue(point.template get<0>());
second->insertValue(point.template get<1>());
}
void operator()(const CartesianRing & ring)
void operator()(const Ring<Point> & ring)
{
if (ring.size() != 1) {
throw Exception("Unable to write ring of size " + toString(ring.size()) + " != 1 to point column", ErrorCodes::BAD_ARGUMENTS);
@ -292,7 +295,7 @@ public:
(*this)(ring[0]);
}
void operator()(const CartesianPolygon & polygon)
void operator()(const Polygon<Point> & polygon)
{
if (polygon.inners().size() != 0) {
throw Exception("Unable to write polygon with holes to point column", ErrorCodes::BAD_ARGUMENTS);
@ -300,7 +303,7 @@ public:
(*this)(polygon.outer());
}
void operator()(const CartesianMultiPolygon & multi_polygon)
void operator()(const MultiPolygon<Point> & multi_polygon)
{
if (multi_polygon.size() != 1) {
throw Exception("Unable to write multi-polygon of size " + toString(multi_polygon.size()) + " != 1 to point column", ErrorCodes::BAD_ARGUMENTS);
@ -311,29 +314,30 @@ public:
ColumnPtr finalize()
{
Columns columns(2);
columns[0] = std::move(x);
columns[1] = std::move(y);
columns[0] = std::move(first);
columns[1] = std::move(second);
return ColumnTuple::create(columns);
}
private:
ColumnFloat64::MutablePtr x;
ColumnFloat64::MutablePtr y;
ColumnFloat64::MutablePtr first;
ColumnFloat64::MutablePtr second;
};
class CartesianRingSerializerVisitor : public boost::static_visitor<void>
template <typename Point>
class RingSerializerVisitor : public boost::static_visitor<void>
{
public:
CartesianRingSerializerVisitor()
RingSerializerVisitor()
: offsets(ColumnUInt64::create())
{}
CartesianRingSerializerVisitor(size_t n)
RingSerializerVisitor(size_t n)
: offsets(ColumnUInt64::create(n))
{}
void operator()(const CartesianPoint & point)
void operator()(const Point & point)
{
size++;
offsets->insertValue(size);
@ -341,7 +345,7 @@ public:
pointSerializer(point);
}
void operator()(const CartesianRing & ring)
void operator()(const Ring<Point> & ring)
{
size += ring.size();
offsets->insertValue(size);
@ -351,7 +355,7 @@ public:
}
}
void operator()(const CartesianPolygon & polygon)
void operator()(const Polygon<Point> & polygon)
{
if (polygon.inners().size() != 0) {
throw Exception("Unable to write polygon with holes to ring column", ErrorCodes::BAD_ARGUMENTS);
@ -359,7 +363,7 @@ public:
(*this)(polygon.outer());
}
void operator()(const CartesianMultiPolygon & multi_polygon)
void operator()(const MultiPolygon<Point> & multi_polygon)
{
if (multi_polygon.size() != 1) {
throw Exception("Unable to write multi-polygon of size " + toString(multi_polygon.size()) + " != 1 to ring column", ErrorCodes::BAD_ARGUMENTS);
@ -374,36 +378,37 @@ public:
private:
size_t size = 0;
CartesianPointSerializerVisitor pointSerializer;
PointSerializerVisitor<Point> pointSerializer;
ColumnUInt64::MutablePtr offsets;
};
class CartesianPolygonSerializerVisitor : public boost::static_visitor<void>
template <typename Point>
class PolygonSerializerVisitor : public boost::static_visitor<void>
{
public:
CartesianPolygonSerializerVisitor()
PolygonSerializerVisitor()
: offsets(ColumnUInt64::create())
{}
CartesianPolygonSerializerVisitor(size_t n)
PolygonSerializerVisitor(size_t n)
: offsets(ColumnUInt64::create(n))
{}
void operator()(const CartesianPoint & point)
void operator()(const Point & point)
{
size++;
offsets->insertValue(size);
ringSerializer(point);
}
void operator()(const CartesianRing & ring)
void operator()(const Ring<Point> & ring)
{
size++;
offsets->insertValue(size);
ringSerializer(ring);
}
void operator()(const CartesianPolygon & polygon)
void operator()(const Polygon<Point> & polygon)
{
size += 1 + polygon.inners().size();
offsets->insertValue(size);
@ -414,7 +419,7 @@ public:
}
}
void operator()(const CartesianMultiPolygon & multi_polygon)
void operator()(const MultiPolygon<Point> & multi_polygon)
{
if (multi_polygon.size() != 1) {
throw Exception("Unable to write multi-polygon of size " + toString(multi_polygon.size()) + " != 1 to polygon column", ErrorCodes::BAD_ARGUMENTS);
@ -429,43 +434,44 @@ public:
private:
size_t size = 0;
CartesianRingSerializerVisitor ringSerializer;
RingSerializerVisitor<Point> ringSerializer;
ColumnUInt64::MutablePtr offsets;
};
class CartesianMultiPolygonSerializerVisitor : public boost::static_visitor<void>
template <typename Point>
class MultiPolygonSerializerVisitor : public boost::static_visitor<void>
{
public:
CartesianMultiPolygonSerializerVisitor()
MultiPolygonSerializerVisitor()
: offsets(ColumnUInt64::create())
{}
CartesianMultiPolygonSerializerVisitor(size_t n)
MultiPolygonSerializerVisitor(size_t n)
: offsets(ColumnUInt64::create(n))
{}
void operator()(const CartesianPoint & point)
void operator()(const Point & point)
{
size++;
offsets->insertValue(size);
polygonSerializer(point);
}
void operator()(const CartesianRing & ring)
void operator()(const Ring<Point> & ring)
{
size++;
offsets->insertValue(size);
polygonSerializer(ring);
}
void operator()(const CartesianPolygon & polygon)
void operator()(const Polygon<Point> & polygon)
{
size++;
offsets->insertValue(size);
polygonSerializer(polygon);
}
void operator()(const CartesianMultiPolygon & multi_polygon)
void operator()(const MultiPolygon<Point> & multi_polygon)
{
size += multi_polygon.size();
offsets->insertValue(size);
@ -482,7 +488,7 @@ public:
private:
size_t size = 0;
CartesianPolygonSerializerVisitor polygonSerializer;
PolygonSerializerVisitor<Point> polygonSerializer;
ColumnUInt64::MutablePtr offsets;
};
@ -503,9 +509,16 @@ private:
Visitor visitor;
};
using CartesianPointSerializer = GeometrySerializer<CartesianGeometry, CartesianPointSerializerVisitor>;
using CartesianRingSerializer = GeometrySerializer<CartesianGeometry, CartesianRingSerializerVisitor>;
using CartesianPolygonSerializer = GeometrySerializer<CartesianGeometry, CartesianPolygonSerializerVisitor>;
using CartesianMultiPolygonSerializer = GeometrySerializer<CartesianGeometry, CartesianMultiPolygonSerializerVisitor>;
template <typename Point>
using PointSerializer = GeometrySerializer<Geometry<Point>, PointSerializerVisitor<Point>>;
template <typename Point>
using RingSerializer = GeometrySerializer<Geometry<Point>, RingSerializerVisitor<Point>>;
template <typename Point>
using PolygonSerializer = GeometrySerializer<Geometry<Point>, PolygonSerializerVisitor<Point>>;
template <typename Point>
using MultiPolygonSerializer = GeometrySerializer<Geometry<Point>, MultiPolygonSerializerVisitor<Point>>;
}

View File

@ -28,17 +28,17 @@ namespace ErrorCodes
extern const int ILLEGAL_COLUMN;
}
template <typename Derived>
class FunctionPolygonAreaBase : public IFunction
template <typename Point>
class FunctionPolygonArea : public IFunction
{
public:
static inline const char * name = Derived::name;
static inline const char * name;
explicit FunctionPolygonAreaBase() = default;
explicit FunctionPolygonArea() = default;
static FunctionPtr create(const Context &)
{
return std::make_shared<FunctionPolygonAreaBase>();
return std::make_shared<FunctionPolygonArea>();
}
String getName() const override
@ -61,9 +61,24 @@ public:
return std::make_shared<DataTypeFloat64>();
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
return static_cast<const Derived*>(this)->executeImplementation(arguments, result_type, input_rows_count);
auto parser = makeGeometryFromColumnParser<Point>(arguments[0]);
auto container = createContainer(parser);
auto res_column = ColumnFloat64::create();
for (size_t i = 0; i < input_rows_count; i++)
{
get(parser, container, i);
Float64 area = boost::geometry::area(
boost::get<MultiPolygon<Point>>(container));
res_column->insertValue(area);
}
return res_column;
}
bool useDefaultImplementationForConstants() const override
@ -72,68 +87,18 @@ public:
}
};
template <>
const char * FunctionPolygonArea<CartesianPoint>::name = "polygonAreaCartesian";
class FunctionPolygonAreaCartesian : public FunctionPolygonAreaBase<FunctionPolygonAreaCartesian>
template <>
const char * FunctionPolygonArea<GeographicPoint>::name = "polygonAreaGeographic";
void registerFunctionPolygonArea(FunctionFactory & factory)
{
public:
static inline const char * name = "polygonAreaCartesian";
ColumnPtr executeImplementation(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const
{
auto parser = makeCartesianGeometryFromColumnParser(arguments[0]);
auto container = createContainer(parser);
auto res_column = ColumnFloat64::create();
for (size_t i = 0; i < input_rows_count; i++)
{
get(parser, container, i);
Float64 area = boost::geometry::area(
boost::get<CartesianMultiPolygon>(container));
res_column->insertValue(area);
}
return res_column;
}
};
class FunctionPolygonAreaGeographic : public FunctionPolygonAreaBase<FunctionPolygonAreaGeographic>
{
public:
static inline const char * name = "polygonAreaGeographic";
ColumnPtr executeImplementation(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const
{
auto parser = makeGeographicGeometryFromColumnParser(arguments[0]);
auto container = createContainer(parser);
auto res_column = ColumnFloat64::create();
for (size_t i = 0; i < input_rows_count; i++)
{
get(parser, container, i);
Float64 area = boost::geometry::area(
boost::get<GeographicMultiPolygon>(container));
res_column->insertValue(area);
}
return res_column;
}
};
void registerFunctionPolygonAreaCartesian(FunctionFactory & factory)
{
factory.registerFunction<FunctionPolygonAreaCartesian>();
factory.registerFunction<FunctionPolygonArea<CartesianPoint>>();
factory.registerFunction<FunctionPolygonArea<GeographicPoint>>();
}
void registerFunctionPolygonAreaGeographic(FunctionFactory & factory)
{
factory.registerFunction<FunctionPolygonAreaGeographic>();
}
}

View File

@ -28,10 +28,11 @@ namespace ErrorCodes
extern const int ILLEGAL_COLUMN;
}
template <typename Point>
class FunctionPolygonConvexHull : public IFunction
{
public:
static inline const char * name = "polygonConvexHull";
static const char * name;
explicit FunctionPolygonConvexHull() = default;
@ -62,27 +63,22 @@ public:
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
auto get_parser = [&arguments] (size_t i) {
const ColumnWithTypeAndName polygon = arguments[i];
return makeCartesianGeometryFromColumnParser(polygon);
};
auto parser = get_parser(0);
auto parser = makeGeometryFromColumnParser<Point>(arguments[0]);
auto container = createContainer(parser);
CartesianPolygonSerializer serializer;
PolygonSerializer<Point> serializer;
for (size_t i = 0; i < input_rows_count; i++)
{
get(parser, container, i);
CartesianGeometry convex_hull = CartesianPolygon({{{}}});
Geometry<Point> convex_hull = Polygon<Point>({{{}}});
boost::geometry::convex_hull(
boost::get<CartesianMultiPolygon>(container),
boost::get<CartesianPolygon>(convex_hull));
boost::get<MultiPolygon<Point>>(container),
boost::get<Polygon<Point>>(convex_hull));
boost::get<CartesianPolygon>(convex_hull).outer().erase(
boost::get<CartesianPolygon>(convex_hull).outer().begin());
boost::get<Polygon<Point>>(convex_hull).outer().erase(
boost::get<Polygon<Point>>(convex_hull).outer().begin());
serializer.add(convex_hull);
}
@ -97,9 +93,17 @@ public:
};
template <>
const char * FunctionPolygonConvexHull<CartesianPoint>::name = "polygonConvexHullCartesian";
// template <>
// const char * FunctionPolygonConvexHull<GeographicPoint>::name = "polygonConvexHullGeographic";
void registerFunctionPolygonConvexHull(FunctionFactory & factory)
{
factory.registerFunction<FunctionPolygonConvexHull>();
factory.registerFunction<FunctionPolygonConvexHull<CartesianPoint>>();
// factory.registerFunction<FunctionPolygonConvexHull<GeographicPoint>>();
}
}

View File

@ -28,17 +28,17 @@ namespace ErrorCodes
extern const int ILLEGAL_COLUMN;
}
template <typename Derived>
class FunctionPolygonPerimeterBase : public IFunction
template <typename Point>
class FunctionPolygonPerimeter : public IFunction
{
public:
static inline const char * name = Derived::name;
static const char * name;
explicit FunctionPolygonPerimeterBase() = default;
explicit FunctionPolygonPerimeter() = default;
static FunctionPtr create(const Context &)
{
return std::make_shared<FunctionPolygonPerimeterBase>();
return std::make_shared<FunctionPolygonPerimeter>();
}
String getName() const override
@ -61,9 +61,24 @@ public:
return std::make_shared<DataTypeFloat64>();
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
return static_cast<const Derived*>(this)->executeImplementation(arguments, result_type, input_rows_count);
auto parser = makeGeometryFromColumnParser<Point>(arguments[0]);
auto container = createContainer(parser);
auto res_column = ColumnFloat64::create();
for (size_t i = 0; i < input_rows_count; i++)
{
get(parser, container, i);
Float64 perimeter = boost::geometry::perimeter(
boost::get<MultiPolygon<Point>>(container));
res_column->insertValue(perimeter);
}
return res_column;
}
bool useDefaultImplementationForConstants() const override
@ -72,69 +87,18 @@ public:
}
};
class FunctionPolygonPerimeterCartesian : public FunctionPolygonPerimeterBase<FunctionPolygonPerimeterCartesian>
template <>
const char * FunctionPolygonPerimeter<CartesianPoint>::name = "polygonPerimeterCartesian";
template <>
const char * FunctionPolygonPerimeter<GeographicPoint>::name = "polygonPerimeterGeographic";
void registerFunctionPolygonPerimeter(FunctionFactory & factory)
{
public:
static inline const char * name = "polygonPerimeterCartesian";
ColumnPtr executeImplementation(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const
{
auto parser = makeCartesianGeometryFromColumnParser(arguments[0]);
auto container = createContainer(parser);
auto res_column = ColumnFloat64::create();
for (size_t i = 0; i < input_rows_count; i++)
{
get(parser, container, i);
Float64 perimeter = boost::geometry::perimeter(
boost::get<CartesianMultiPolygon>(container));
res_column->insertValue(perimeter);
}
return res_column;
}
};
class FunctionPolygonPerimeterGeographic : public FunctionPolygonPerimeterBase<FunctionPolygonPerimeterGeographic>
{
public:
static inline const char * name = "polygonPerimeterGeographic";
ColumnPtr executeImplementation(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const
{
auto parser = makeGeographicGeometryFromColumnParser(arguments[0]);
auto container = createContainer(parser);
auto res_column = ColumnFloat64::create();
for (size_t i = 0; i < input_rows_count; i++)
{
get(parser, container, i);
Float64 perimeter = boost::geometry::perimeter(
boost::get<GeographicMultiPolygon>(container));
res_column->insertValue(perimeter);
}
return res_column;
}
};
void registerFunctionPolygonPerimeterCartesian(FunctionFactory & factory)
{
factory.registerFunction<FunctionPolygonPerimeterCartesian>();
factory.registerFunction<FunctionPolygonPerimeter<CartesianPoint>>();
factory.registerFunction<FunctionPolygonPerimeter<GeographicPoint>>();
}
void registerFunctionPolygonPerimeterGeographic(FunctionFactory & factory)
{
factory.registerFunction<FunctionPolygonPerimeterGeographic>();
}
}

View File

@ -30,17 +30,17 @@ namespace ErrorCodes
extern const int ILLEGAL_COLUMN;
}
template <typename Derived>
class FunctionPolygonsDistanceBase : public IFunction
template <typename Point>
class FunctionPolygonsDistance : public IFunction
{
public:
static inline const char * name = Derived::name;
static inline const char * name;
explicit FunctionPolygonsDistanceBase() = default;
explicit FunctionPolygonsDistance() = default;
static FunctionPtr create(const Context &)
{
return std::make_shared<FunctionPolygonsDistanceBase>();
return std::make_shared<FunctionPolygonsDistance>();
}
String getName() const override
@ -63,9 +63,29 @@ public:
return std::make_shared<DataTypeFloat64>();
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
return static_cast<const Derived*>(this)->executeImplementation(arguments, result_type, input_rows_count);
auto first_parser = makeGeometryFromColumnParser<Point>(arguments[0]);
auto first_container = createContainer(first_parser);
auto second_parser = makeGeometryFromColumnParser<Point>(arguments[1]);
auto second_container = createContainer(second_parser);
auto res_column = ColumnFloat64::create();
for (size_t i = 0; i < input_rows_count; i++)
{
get(first_parser, first_container, i);
get(second_parser, second_container, i);
Float64 distance = boost::geometry::distance(
boost::get<MultiPolygon<Point>>(first_container),
boost::get<MultiPolygon<Point>>(second_container));
res_column->insertValue(distance);
}
return res_column;
}
bool useDefaultImplementationForConstants() const override
@ -74,73 +94,18 @@ public:
}
};
template <>
const char * FunctionPolygonsDistance<CartesianPoint>::name = "polygonsDistanceCartesian";
class FunctionPolygonsDistanceCartesian : public FunctionPolygonsDistanceBase<FunctionPolygonsDistanceCartesian>
template <>
const char * FunctionPolygonsDistance<GeographicPoint>::name = "polygonsDistanceGeographic";
void registerFunctionPolygonsDistance(FunctionFactory & factory)
{
public:
static inline const char * name = "polygonsDistanceCartesian";
ColumnPtr executeImplementation(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const
{
auto first_parser = makeCartesianGeometryFromColumnParser(arguments[0]);
auto first_container = createContainer(first_parser);
auto second_parser = makeCartesianGeometryFromColumnParser(arguments[1]);
auto second_container = createContainer(second_parser);
auto res_column = ColumnFloat64::create();
for (size_t i = 0; i < input_rows_count; i++)
{
Float64 distance = boost::geometry::distance(
boost::get<CartesianMultiPolygon>(first_container),
boost::get<CartesianMultiPolygon>(second_container));
res_column->insertValue(distance);
}
return res_column;
}
};
class FunctionPolygonsDistanceGeographic : public FunctionPolygonsDistanceBase<FunctionPolygonsDistanceGeographic>
{
public:
static inline const char * name = "polygonsDistanceGeographic";
ColumnPtr executeImplementation(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const
{
auto first_parser = makeGeographicGeometryFromColumnParser(arguments[0]);
auto first_container = createContainer(first_parser);
auto second_parser = makeGeographicGeometryFromColumnParser(arguments[1]);
auto second_container = createContainer(second_parser);
auto res_column = ColumnFloat64::create();
for (size_t i = 0; i < input_rows_count; i++)
{
Float64 distance = boost::geometry::distance(
boost::get<GeographicMultiPolygon>(first_container),
boost::get<GeographicMultiPolygon>(second_container));
res_column->insertValue(distance);
}
return res_column;
}
};
void registerFunctionPolygonsDistanceCartesian(FunctionFactory & factory)
{
factory.registerFunction<FunctionPolygonsDistanceCartesian>();
factory.registerFunction<FunctionPolygonsDistance<CartesianPoint>>();
factory.registerFunction<FunctionPolygonsDistance<GeographicPoint>>();
}
void registerFunctionPolygonsDistanceGeographic(FunctionFactory & factory)
{
factory.registerFunction<FunctionPolygonsDistanceGeographic>();
}
}

View File

@ -70,9 +70,9 @@ public:
bool is_const = static_cast<bool>(const_col);
return std::pair<bool, CartesianGeometryFromColumnParser>{is_const, is_const ?
makeCartesianGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), arguments[i].type, arguments[i].name)) :
makeCartesianGeometryFromColumnParser(arguments[i])};
return std::pair<bool, GeometryFromColumnParser<CartesianPoint>>{is_const, is_const ?
makeGeometryFromColumnParser<CartesianPoint>(ColumnWithTypeAndName(const_col->getDataColumnPtr(), arguments[i].type, arguments[i].name)) :
makeGeometryFromColumnParser<CartesianPoint>(arguments[i])};
};
auto [is_first_polygon_const, first_parser] = get_parser(0);

View File

@ -63,13 +63,13 @@ public:
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
auto first_parser = makeCartesianGeometryFromColumnParser(arguments[0]);
auto first_parser = makeGeometryFromColumnParser<CartesianPoint>(arguments[0]);
auto first_container = createContainer(first_parser);
auto second_parser = makeCartesianGeometryFromColumnParser(arguments[1]);
auto second_parser = makeGeometryFromColumnParser<CartesianPoint>(arguments[1]);
auto second_container = createContainer(second_parser);
CartesianMultiPolygonSerializer serializer;
MultiPolygonSerializer<CartesianPoint> serializer;
for (size_t i = 0; i < input_rows_count; i++)
{

View File

@ -28,10 +28,11 @@ namespace ErrorCodes
extern const int ILLEGAL_COLUMN;
}
template <typename Point>
class FunctionPolygonsSymDifference : public IFunction
{
public:
static inline const char * name = "polygonsSymDifference";
static const char * name;
explicit FunctionPolygonsSymDifference() = default;
@ -62,40 +63,27 @@ public:
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
auto get_parser = [&arguments] (size_t i) {
const auto * const_col =
checkAndGetColumn<ColumnConst>(arguments[i].column.get());
bool is_const = static_cast<bool>(const_col);
return std::pair<bool, CartesianGeometryFromColumnParser>{is_const, is_const ?
makeCartesianGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), arguments[i].type, arguments[i].name)) :
makeCartesianGeometryFromColumnParser(arguments[i])};
};
auto [is_first_polygon_const, first_parser] = get_parser(0);
auto first_parser = makeGeometryFromColumnParser<Point>(arguments[0]);
auto first_container = createContainer(first_parser);
auto [is_second_polygon_const, second_parser] = get_parser(1);
auto second_parser = makeGeometryFromColumnParser<Point>(arguments[1]);
auto second_container = createContainer(second_parser);
CartesianMultiPolygonSerializer serializer;
MultiPolygonSerializer<Point> serializer;
for (size_t i = 0; i < input_rows_count; i++)
{
if (!is_first_polygon_const || i == 0)
get(first_parser, first_container, i);
if (!is_second_polygon_const || i == 0)
get(second_parser, second_container, i);
CartesianGeometry sym_difference = CartesianMultiPolygon({{{{}}}});
Geometry<Point> sym_difference = MultiPolygon<Point>({{{{}}}});
boost::geometry::sym_difference(
boost::get<CartesianMultiPolygon>(first_container),
boost::get<CartesianMultiPolygon>(second_container),
boost::get<CartesianMultiPolygon>(sym_difference));
boost::get<MultiPolygon<Point>>(first_container),
boost::get<MultiPolygon<Point>>(second_container),
boost::get<MultiPolygon<Point>>(sym_difference));
boost::get<CartesianMultiPolygon>(sym_difference).erase(
boost::get<CartesianMultiPolygon>(sym_difference).begin());
boost::get<MultiPolygon<Point>>(sym_difference).erase(
boost::get<MultiPolygon<Point>>(sym_difference).begin());
serializer.add(sym_difference);
}
@ -109,10 +97,18 @@ public:
}
};
template <>
const char * FunctionPolygonsSymDifference<CartesianPoint>::name = "polygonsSymDifferenceCartesian";
template <>
const char * FunctionPolygonsSymDifference<GeographicPoint>::name = "polygonsSymDifferenceGeographic";
void registerFunctionPolygonsSymDifference(FunctionFactory & factory)
{
factory.registerFunction<FunctionPolygonsSymDifference>();
factory.registerFunction<FunctionPolygonsSymDifference<CartesianPoint>>();
factory.registerFunction<FunctionPolygonsSymDifference<GeographicPoint>>();
}
}

View File

@ -70,9 +70,9 @@ public:
bool is_const = static_cast<bool>(const_col);
return std::pair<bool, CartesianGeometryFromColumnParser>{is_const, is_const ?
makeCartesianGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), arguments[i].type, arguments[i].name)) :
makeCartesianGeometryFromColumnParser(arguments[i])};
return std::pair<bool, GeometryFromColumnParser<CartesianPoint>>{is_const, is_const ?
makeGeometryFromColumnParser<CartesianPoint>(ColumnWithTypeAndName(const_col->getDataColumnPtr(), arguments[i].type, arguments[i].name)) :
makeGeometryFromColumnParser<CartesianPoint>(arguments[i])};
};
auto [is_first_polygon_const, first_parser] = get_parser(0);

View File

@ -62,7 +62,7 @@ public:
}
};
class FunctionReadWktPoint : public FunctionReadWkt<DataTypeCustomPointSerialization, CartesianPoint, CartesianPointSerializer>
class FunctionReadWktPoint : public FunctionReadWkt<DataTypeCustomPointSerialization, CartesianPoint, PointSerializer<CartesianPoint>>
{
public:
static inline const char * name = "readWktPoint";
@ -76,7 +76,7 @@ public:
}
};
class FunctionReadWktPolygon : public FunctionReadWkt<DataTypeCustomPolygonSerialization, CartesianPolygon, CartesianPolygonSerializer>
class FunctionReadWktPolygon : public FunctionReadWkt<DataTypeCustomPolygonSerialization, CartesianPolygon, PolygonSerializer<CartesianPoint>>
{
public:
static inline const char * name = "readWktPolygon";
@ -90,7 +90,7 @@ public:
}
};
class FunctionReadWktMultiPolygon : public FunctionReadWkt<DataTypeCustomMultiPolygonSerialization, CartesianMultiPolygon, CartesianMultiPolygonSerializer>
class FunctionReadWktMultiPolygon : public FunctionReadWkt<DataTypeCustomMultiPolygonSerialization, CartesianMultiPolygon, MultiPolygonSerializer<CartesianPoint>>
{
public:
static inline const char * name = "readWktMultiPolygon";

View File

@ -12,16 +12,13 @@ void registerFunctionPointInEllipses(FunctionFactory & factory);
void registerFunctionPointInPolygon(FunctionFactory & factory);
void registerFunctionPolygonsIntersection(FunctionFactory & factory);
void registerFunctionPolygonsUnion(FunctionFactory & factory);
void registerFunctionPolygonAreaCartesian(FunctionFactory & factory);
void registerFunctionPolygonAreaGeographic (FunctionFactory & factory);
void registerFunctionPolygonArea(FunctionFactory & factory);
void registerFunctionPolygonConvexHull(FunctionFactory & factory);
void registerFunctionPolygonsSymDifference(FunctionFactory & factory);
void registerFunctionPolygonsEquals(FunctionFactory & factory);
void registerFunctionPolygonsDistanceCartesian(FunctionFactory & factory);
void registerFunctionPolygonsDistanceGeographic(FunctionFactory & factory);
void registerFunctionPolygonsDistance(FunctionFactory & factory);
void registerFunctionPolygonsWithin(FunctionFactory & factory);
void registerFunctionPolygonPerimeterCartesian(FunctionFactory & factory);
void registerFunctionPolygonPerimeterGeographic(FunctionFactory & factory);
void registerFunctionPolygonPerimeter(FunctionFactory & factory);
void registerFunctionGeohashEncode(FunctionFactory & factory);
void registerFunctionGeohashDecode(FunctionFactory & factory);
void registerFunctionGeohashesInBox(FunctionFactory & factory);
@ -53,16 +50,13 @@ void registerFunctionsGeo(FunctionFactory & factory)
registerFunctionPointInPolygon(factory);
registerFunctionPolygonsIntersection(factory);
registerFunctionPolygonsUnion(factory);
registerFunctionPolygonAreaCartesian(factory);
registerFunctionPolygonAreaGeographic(factory);
registerFunctionPolygonArea(factory);
registerFunctionPolygonConvexHull(factory);
registerFunctionPolygonsSymDifference(factory);
registerFunctionPolygonsEquals(factory);
registerFunctionPolygonsDistanceCartesian(factory);
registerFunctionPolygonsDistanceGeographic(factory);
registerFunctionPolygonsDistance(factory);
registerFunctionPolygonsWithin(factory);
registerFunctionPolygonPerimeterCartesian(factory);
registerFunctionPolygonPerimeterGeographic(factory);
registerFunctionPolygonPerimeter(factory);
registerFunctionGeohashEncode(factory);
registerFunctionGeohashDecode(factory);
registerFunctionGeohashesInBox(factory);

View File

@ -65,8 +65,8 @@ public:
const auto * const_col = checkAndGetColumn<ColumnConst>(arguments[0].column.get());
auto parser = const_col ?
makeCartesianGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), arguments[0].type, arguments[0].name)) :
makeCartesianGeometryFromColumnParser(arguments[0]);
makeGeometryFromColumnParser<CartesianPoint>(ColumnWithTypeAndName(const_col->getDataColumnPtr(), arguments[0].type, arguments[0].name)) :
makeGeometryFromColumnParser<CartesianPoint>(arguments[0]);
bool geo_column_is_const = static_cast<bool>(const_col);

View File

@ -38,7 +38,7 @@ public:
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{
auto parser = makeCartesianGeometryFromColumnParser(arguments[0]);
auto parser = makeGeometryFromColumnParser<CartesianPoint>(arguments[0]);
auto res_column = ColumnString::create();
auto container = createContainer(parser);

View File

@ -1,7 +1,8 @@
select polygonsDistanceCartesian([[[(0, 0),(0, 3),(1, 2.9),(2, 2.6),(2.6, 2),(2.9, 1),(3, 0),(0, 0)]]], [[[(1, 1),(1, 4),(4, 4),(4, 1),(1, 1)]]]);
select polygonsDistanceCartesian([[[(0, 0), (0, 0.1), (0.1, 0.1), (0.1, 0)]]], [[[(1, 1),(1, 4),(4, 4),(4, 1),(1, 1)]]]);
select polygonsDistanceGeographic([[[(23.725750, 37.971536)]]], [[[(4.3826169, 50.8119483)]]]);
drop table if exists polygon_01302
drop table if exists polygon_01302;
create table polygon_01302 (x Array(Array(Array(Tuple(Float64, Float64)))), y Array(Array(Array(Tuple(Float64, Float64))))) engine=Memory();
insert into polygon_01302 values ([[[(23.725750, 37.971536)]]], [[[(4.3826169, 50.8119483)]]]);
select polygonsDistanceGeographic(x, y) from polygon;
select polygonsDistanceGeographic(x, y) from polygon_01302;

View File

@ -1 +1,2 @@
[[[(1,2.9),(2,2.6),(2.6,2),(2.9,1),(1,1),(1,2.9)]]]
[]

View File

@ -1 +1,2 @@
select polygonsIntersection([[[(0, 0),(0, 3),(1, 2.9),(2, 2.6),(2.6, 2),(2.9, 1),(3, 0),(0, 0)]]], [[[(1, 1),(1, 4),(4, 4),(4, 1),(1, 1)]]])
select polygonsIntersection([[[(0, 0),(0, 3),(1, 2.9),(2, 2.6),(2.6, 2),(2.9, 1),(3, 0),(0, 0)]]], [[[(1, 1),(1, 4),(4, 4),(4, 1),(1, 1)]]]);
select polygonsIntersection([[[(0, 0),(0, 3),(1, 2.9),(2, 2.6),(2.6, 2),(2.9, 1),(3, 0),(0, 0)]]], [[[(3, 3),(3, 4),(4, 4),(4, 3),(3, 3)]]]);