This commit is contained in:
Nikita Mikhailov 2021-01-19 02:51:34 +03:00 committed by Nikita Mikhaylov
parent 373b429e61
commit 0425d566d3
21 changed files with 481 additions and 346 deletions

View File

@ -28,14 +28,6 @@ namespace ErrorCodes
extern const int ILLEGAL_COLUMN; extern const int ILLEGAL_COLUMN;
} }
using CoordinateType = Float64;
using Point = boost::geometry::model::d2::point_xy<CoordinateType>;
using Polygon = boost::geometry::model::polygon<Point, false>;
using MultiPolygon = boost::geometry::model::multi_polygon<Float64Polygon>;
using Box = boost::geometry::model::box<Point>;
class FunctionPolygonsUnion : public IFunction class FunctionPolygonsUnion : public IFunction
{ {
public: public:
@ -68,17 +60,17 @@ public:
return DataTypeCustomMultiPolygonSerialization::nestedDataType(); return DataTypeCustomMultiPolygonSerialization::nestedDataType();
} }
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{ {
auto get_parser = [&block, &arguments] (size_t i) { auto get_parser = [&arguments] (size_t i) {
const auto * const_col = const auto * const_col =
checkAndGetColumn<ColumnConst>(block.getByPosition(arguments[i]).column.get()); checkAndGetColumn<ColumnConst>(arguments[i].column.get());
bool is_const = static_cast<bool>(const_col); bool is_const = static_cast<bool>(const_col);
return std::pair<bool, GeometryFromColumnParser>{is_const, is_const ? return std::pair<bool, CartesianGeometryFromColumnParser>{is_const, is_const ?
makeGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), block.getByPosition(arguments[i]).type, block.getByPosition(arguments[i]).name)) : makeCartesianGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), arguments[i].type, arguments[i].name)) :
makeGeometryFromColumnParser(block.getByPosition(arguments[i]))}; makeCartesianGeometryFromColumnParser(arguments[i])};
}; };
auto [is_first_polygon_const, first_parser] = get_parser(0); auto [is_first_polygon_const, first_parser] = get_parser(0);
@ -87,7 +79,7 @@ public:
auto [is_second_polygon_const, second_parser] = get_parser(1); auto [is_second_polygon_const, second_parser] = get_parser(1);
auto second_container = createContainer(second_parser); auto second_container = createContainer(second_parser);
Float64MultiPolygonSerializer serializer; CartesianMultiPolygonSerializer serializer;
for (size_t i = 0; i < input_rows_count; i++) for (size_t i = 0; i < input_rows_count; i++)
{ {
@ -96,19 +88,19 @@ public:
if (!is_second_polygon_const || i == 0) if (!is_second_polygon_const || i == 0)
get(second_parser, second_container, i); get(second_parser, second_container, i);
Float64Geometry polygons_union = Float64MultiPolygon({{{{}}}}); CartesianGeometry polygons_union = CartesianMultiPolygon({{{{}}}});
boost::geometry::union_( boost::geometry::union_(
boost::get<Float64MultiPolygon>(first_container), boost::get<CartesianMultiPolygon>(first_container),
boost::get<Float64MultiPolygon>(second_container), boost::get<CartesianMultiPolygon>(second_container),
boost::get<Float64MultiPolygon>(polygons_union)); boost::get<CartesianMultiPolygon>(polygons_union));
boost::get<Float64MultiPolygon>(polygons_union).erase( boost::get<CartesianMultiPolygon>(polygons_union).erase(
boost::get<Float64MultiPolygon>(polygons_union).begin()); boost::get<CartesianMultiPolygon>(polygons_union).begin());
serializer.add(polygons_union); serializer.add(polygons_union);
} }
block.getByPosition(result).column = std::move(serializer.finalize()); return serializer.finalize();
} }
bool useDefaultImplementationForConstants() const override bool useDefaultImplementationForConstants() const override

View File

@ -9,32 +9,32 @@ namespace {
size_t getArrayDepth(DataTypePtr data_type, size_t max_depth) size_t getArrayDepth(DataTypePtr data_type, size_t max_depth)
{ {
LOG_FATAL(&Poco::Logger::get("geoconv"), "getting depth");
size_t depth = 0; size_t depth = 0;
while (data_type && isArray(data_type) && depth != max_depth + 1) while (data_type && isArray(data_type) && depth != max_depth + 1)
{ {
depth++; depth++;
data_type = static_cast<const DataTypeArray &>(*data_type).getNestedType(); data_type = static_cast<const DataTypeArray &>(*data_type).getNestedType();
} }
LOG_FATAL(&Poco::Logger::get("geoconv"), "got depth");
return depth; return depth;
} }
class ContainerCreator : public boost::static_visitor<Float64Geometry> template <typename Geometry>
class ContainerCreator : public boost::static_visitor<Geometry>
{ {
public: public:
template <class T> template <class T>
Float64Geometry operator()(const T & parser) const Geometry operator()(const T & parser) const
{ {
return parser.createContainer(); return parser.createContainer();
} }
}; };
template <typename Geometry>
class Getter : public boost::static_visitor<void> class Getter : public boost::static_visitor<void>
{ {
public: public:
constexpr Getter(Float64Geometry & container_, size_t i_) constexpr Getter(Geometry & container_, size_t i_)
: container(container_) : container(container_)
, i(i_) , i(i_)
{} {}
@ -46,7 +46,7 @@ public:
} }
private: private:
Float64Geometry & container; Geometry & container;
size_t i; size_t i;
}; };
@ -64,26 +64,50 @@ Parser makeParser(const ColumnWithTypeAndName & col)
} }
GeometryFromColumnParser makeGeometryFromColumnParser(const ColumnWithTypeAndName & col) CartesianGeometryFromColumnParser makeCartesianGeometryFromColumnParser(const ColumnWithTypeAndName & col)
{ {
LOG_FATAL(&Poco::Logger::get("geoconv"), "Fine"); switch (getArrayDepth(col.type, 3))
switch (getArrayDepth(col.type, 3)) { {
case 0: return makeParser<DataTypeCustomPointSerialization, Float64PointFromColumnParser>(col); case 0: return makeParser<DataTypeCustomPointSerialization, PointFromColumnParser<CartesianPoint>>(col);
case 1: return makeParser<DataTypeCustomRingSerialization, Float64RingFromColumnParser>(col); case 1: return makeParser<DataTypeCustomRingSerialization, CartesianRingFromColumnParser>(col);
case 2: return makeParser<DataTypeCustomPolygonSerialization, Float64PolygonFromColumnParser>(col); case 2: return makeParser<DataTypeCustomPolygonSerialization, CartesianPolygonFromColumnParser>(col);
case 3: return makeParser<DataTypeCustomMultiPolygonSerialization, Float64MultiPolygonFromColumnParser>(col); case 3: return makeParser<DataTypeCustomMultiPolygonSerialization, CartesianMultiPolygonFromColumnParser>(col);
default: throw Exception("Cannot parse geometry from column with type " + col.type->getName() default: throw Exception("Cannot parse geometry from column with type " + col.type->getName()
+ ", array depth is too big", ErrorCodes::ILLEGAL_COLUMN); + ", array depth is too big", ErrorCodes::ILLEGAL_COLUMN);
} }
} }
Float64Geometry createContainer(const GeometryFromColumnParser & parser) CartesianGeometry createContainer(const CartesianGeometryFromColumnParser & parser)
{ {
static ContainerCreator creator; static ContainerCreator<CartesianGeometry> creator;
return boost::apply_visitor(creator, parser); return boost::apply_visitor(creator, parser);
} }
void get(const GeometryFromColumnParser & parser, Float64Geometry & container, size_t i) void get(const CartesianGeometryFromColumnParser & parser, CartesianGeometry & container, size_t i)
{
boost::apply_visitor(Getter(container, i), parser);
}
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); boost::apply_visitor(Getter(container, i), parser);
} }

View File

@ -26,49 +26,89 @@ namespace ErrorCodes
extern const int BAD_ARGUMENTS; extern const int BAD_ARGUMENTS;
} }
using Float64Point = boost::geometry::model::d2::point_xy<Float64>; namespace bg = boost::geometry;
using Float64Ring = boost::geometry::model::ring<Float64Point>; using CartesianPoint = bg::model::d2::point_xy<Float64>;
using Float64Polygon = boost::geometry::model::polygon<Float64Point>; using CartesianRing = bg::model::ring<CartesianPoint>;
using Float64MultiPolygon = boost::geometry::model::multi_polygon<Float64Polygon>; using CartesianPolygon = bg::model::polygon<CartesianPoint>;
using Float64Geometry = boost::variant<Float64Point, Float64Ring, Float64Polygon, Float64MultiPolygon>; using CartesianMultiPolygon = bg::model::multi_polygon<CartesianPolygon>;
using CartesianGeometry = boost::variant<CartesianPoint, CartesianRing, CartesianPolygon, CartesianMultiPolygon>;
class Float64PointFromColumnParser 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>;
/**
* Class which takes some boost type and returns a pair of numbers.
* They are (x,y) in case of cartesian coordinated and (lon,lat) in case of geographic.
*/
template <typename PointType>
class PointFromColumnParser
{ {
public: public:
Float64PointFromColumnParser(ColumnPtr col_) PointFromColumnParser(ColumnPtr col_) : col(col_)
: col(col_)
{ {
const auto & tuple = static_cast<const ColumnTuple &>(*col_); const auto & tuple = static_cast<const ColumnTuple &>(*col_);
const auto & tuple_columns = tuple.getColumns(); const auto & tuple_columns = tuple.getColumns();
#ifndef NDEBUG
size = tuple.size();
#endif
const auto & x_data = static_cast<const ColumnFloat64 &>(*tuple_columns[0]); const auto & x_data = static_cast<const ColumnFloat64 &>(*tuple_columns[0]);
x = x_data.getData().data(); first = x_data.getData().data();
const auto & y_data = static_cast<const ColumnFloat64 &>(*tuple_columns[1]); const auto & y_data = static_cast<const ColumnFloat64 &>(*tuple_columns[1]);
y = y_data.getData().data(); second = y_data.getData().data();
} }
template<class Q = PointType>
Float64Geometry createContainer() const typename std::enable_if_t<std::is_same_v<Q, CartesianPoint>, CartesianGeometry> createContainer() const
{ {
return Float64Point(); return CartesianPoint();
} }
void get(Float64Geometry & container, size_t i) const template<class Q = PointType>
typename std::enable_if_t<std::is_same_v<Q, GeographicPoint>, GeographicGeometry> createContainer() const
{ {
get(boost::get<Float64Point>(container), i); return GeographicPoint();
} }
void get(Float64Point & container, size_t i) const template<class Q = PointType>
void get(std::enable_if_t<std::is_same_v<Q, CartesianPoint>, CartesianGeometry> & container, size_t i) const
{ {
boost::geometry::set<0>(container, x[i]); #ifndef NDEBUG
boost::geometry::set<1>(container, y[i]); assert(i < size);
#endif
get(boost::get<PointType>(container), i);
} }
template<class Q = PointType>
void get(std::enable_if_t<std::is_same_v<Q, GeographicPoint>, GeographicGeometry> & container, size_t i) const
{
#ifndef NDEBUG
assert(i < size);
#endif
get(boost::get<PointType>(container), i);
}
void get(PointType & container, size_t i) const
{
#ifndef NDEBUG
assert(i < size);
#endif
boost::geometry::set<0>(container, first[i]);
boost::geometry::set<1>(container, second[i]);
}
private: private:
/// Note, this is needed to prevent use-after-free.
ColumnPtr col; ColumnPtr col;
#ifndef NDEBUG
const Float64 * x; size_t size;
const Float64 * y; #endif
const Float64 * first;
const Float64 * second;
}; };
template<class Geometry, class RingType, class PointParser> template<class Geometry, class RingType, class PointParser>
@ -142,8 +182,6 @@ public:
ringParser.get(container.outer(), l); ringParser.get(container.outer(), l);
LOG_FATAL(&Poco::Logger::get("geoconv"), "polygon: l = {}, r = {}", l, r);
container.inners().resize(r - l - 1); container.inners().resize(r - l - 1);
for (size_t j = l + 1; j < r; j++) for (size_t j = l + 1; j < r; j++)
{ {
@ -176,8 +214,6 @@ public:
size_t l = offsets[i - 1]; size_t l = offsets[i - 1];
size_t r = offsets[i]; size_t r = offsets[i];
LOG_FATAL(&Poco::Logger::get("geoconv"), "multipolygon: l = {}, r = {}", l, r);
multi_polygon.resize(r - l); multi_polygon.resize(r - l);
for (size_t j = l; j < r; j++) for (size_t j = l; j < r; j++)
{ {
@ -190,43 +226,65 @@ private:
const PolygonParser polygonParser; const PolygonParser polygonParser;
}; };
using Float64RingFromColumnParser = RingFromColumnParser<Float64Geometry, Float64Ring, Float64PointFromColumnParser>; /// Cartesian coordinates
using Float64PolygonFromColumnParser = PolygonFromColumnParser<Float64Geometry, Float64Polygon, Float64RingFromColumnParser>;
using Float64MultiPolygonFromColumnParser = MultiPolygonFromColumnParser<Float64Geometry, Float64MultiPolygon, Float64PolygonFromColumnParser>;
using GeometryFromColumnParser = boost::variant< using CartesianRingFromColumnParser = RingFromColumnParser<CartesianGeometry, CartesianRing, PointFromColumnParser<CartesianPoint>>;
Float64PointFromColumnParser, using CartesianPolygonFromColumnParser = PolygonFromColumnParser<CartesianGeometry, CartesianPolygon, CartesianRingFromColumnParser>;
Float64RingFromColumnParser, using CartesianMultiPolygonFromColumnParser = MultiPolygonFromColumnParser<CartesianGeometry, CartesianMultiPolygon, CartesianPolygonFromColumnParser>;
Float64PolygonFromColumnParser,
Float64MultiPolygonFromColumnParser using CartesianGeometryFromColumnParser = boost::variant<
PointFromColumnParser<CartesianPoint>,
CartesianRingFromColumnParser,
CartesianPolygonFromColumnParser,
CartesianMultiPolygonFromColumnParser
>; >;
Float64Geometry createContainer(const GeometryFromColumnParser & parser); CartesianGeometry createContainer(const CartesianGeometryFromColumnParser & parser);
void get(const GeometryFromColumnParser & parser, Float64Geometry & container, size_t i); void get(const CartesianGeometryFromColumnParser & parser, CartesianGeometry & container, size_t i);
GeometryFromColumnParser makeGeometryFromColumnParser(const ColumnWithTypeAndName & col); CartesianGeometryFromColumnParser makeCartesianGeometryFromColumnParser(const ColumnWithTypeAndName & col);
class Float64PointSerializerVisitor : public boost::static_visitor<void> /// Geographic coordinates
using GeographicRingFromColumnParser = RingFromColumnParser<GeographicGeometry, GeographicRing, PointFromColumnParser<GeographicPoint>>;
using GeographicPolygonFromColumnParser = PolygonFromColumnParser<GeographicGeometry, GeographicPolygon, GeographicRingFromColumnParser>;
using GeographicMultiPolygonFromColumnParser = MultiPolygonFromColumnParser<GeographicGeometry, GeographicMultiPolygon, GeographicPolygonFromColumnParser>;
using GeographicGeometryFromColumnParser = boost::variant<
PointFromColumnParser<GeographicPoint>,
GeographicRingFromColumnParser,
GeographicPolygonFromColumnParser,
GeographicMultiPolygonFromColumnParser
>;
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>
{ {
public: public:
Float64PointSerializerVisitor() CartesianPointSerializerVisitor()
: x(ColumnFloat64::create()) : x(ColumnFloat64::create())
, y(ColumnFloat64::create()) , y(ColumnFloat64::create())
{} {}
Float64PointSerializerVisitor(size_t n) CartesianPointSerializerVisitor(size_t n)
: x(ColumnFloat64::create(n)) : x(ColumnFloat64::create(n))
, y(ColumnFloat64::create(n)) , y(ColumnFloat64::create(n))
{} {}
void operator()(const Float64Point & point) void operator()(const CartesianPoint & point)
{ {
x->insertValue(point.x()); x->insertValue(point.get<0>());
y->insertValue(point.y()); y->insertValue(point.get<0>());
} }
void operator()(const Float64Ring & ring) void operator()(const CartesianRing & ring)
{ {
if (ring.size() != 1) { if (ring.size() != 1) {
throw Exception("Unable to write ring of size " + toString(ring.size()) + " != 1 to point column", ErrorCodes::BAD_ARGUMENTS); throw Exception("Unable to write ring of size " + toString(ring.size()) + " != 1 to point column", ErrorCodes::BAD_ARGUMENTS);
@ -234,7 +292,7 @@ public:
(*this)(ring[0]); (*this)(ring[0]);
} }
void operator()(const Float64Polygon & polygon) void operator()(const CartesianPolygon & polygon)
{ {
if (polygon.inners().size() != 0) { if (polygon.inners().size() != 0) {
throw Exception("Unable to write polygon with holes to point column", ErrorCodes::BAD_ARGUMENTS); throw Exception("Unable to write polygon with holes to point column", ErrorCodes::BAD_ARGUMENTS);
@ -242,7 +300,7 @@ public:
(*this)(polygon.outer()); (*this)(polygon.outer());
} }
void operator()(const Float64MultiPolygon & multi_polygon) void operator()(const CartesianMultiPolygon & multi_polygon)
{ {
if (multi_polygon.size() != 1) { 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); throw Exception("Unable to write multi-polygon of size " + toString(multi_polygon.size()) + " != 1 to point column", ErrorCodes::BAD_ARGUMENTS);
@ -264,18 +322,18 @@ private:
ColumnFloat64::MutablePtr y; ColumnFloat64::MutablePtr y;
}; };
class Float64RingSerializerVisitor : public boost::static_visitor<void> class CartesianRingSerializerVisitor : public boost::static_visitor<void>
{ {
public: public:
Float64RingSerializerVisitor() CartesianRingSerializerVisitor()
: offsets(ColumnUInt64::create()) : offsets(ColumnUInt64::create())
{} {}
Float64RingSerializerVisitor(size_t n) CartesianRingSerializerVisitor(size_t n)
: offsets(ColumnUInt64::create(n)) : offsets(ColumnUInt64::create(n))
{} {}
void operator()(const Float64Point & point) void operator()(const CartesianPoint & point)
{ {
size++; size++;
offsets->insertValue(size); offsets->insertValue(size);
@ -283,7 +341,7 @@ public:
pointSerializer(point); pointSerializer(point);
} }
void operator()(const Float64Ring & ring) void operator()(const CartesianRing & ring)
{ {
size += ring.size(); size += ring.size();
offsets->insertValue(size); offsets->insertValue(size);
@ -293,7 +351,7 @@ public:
} }
} }
void operator()(const Float64Polygon & polygon) void operator()(const CartesianPolygon & polygon)
{ {
if (polygon.inners().size() != 0) { if (polygon.inners().size() != 0) {
throw Exception("Unable to write polygon with holes to ring column", ErrorCodes::BAD_ARGUMENTS); throw Exception("Unable to write polygon with holes to ring column", ErrorCodes::BAD_ARGUMENTS);
@ -301,7 +359,7 @@ public:
(*this)(polygon.outer()); (*this)(polygon.outer());
} }
void operator()(const Float64MultiPolygon & multi_polygon) void operator()(const CartesianMultiPolygon & multi_polygon)
{ {
if (multi_polygon.size() != 1) { 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); throw Exception("Unable to write multi-polygon of size " + toString(multi_polygon.size()) + " != 1 to ring column", ErrorCodes::BAD_ARGUMENTS);
@ -316,36 +374,36 @@ public:
private: private:
size_t size = 0; size_t size = 0;
Float64PointSerializerVisitor pointSerializer; CartesianPointSerializerVisitor pointSerializer;
ColumnUInt64::MutablePtr offsets; ColumnUInt64::MutablePtr offsets;
}; };
class Float64PolygonSerializerVisitor : public boost::static_visitor<void> class CartesianPolygonSerializerVisitor : public boost::static_visitor<void>
{ {
public: public:
Float64PolygonSerializerVisitor() CartesianPolygonSerializerVisitor()
: offsets(ColumnUInt64::create()) : offsets(ColumnUInt64::create())
{} {}
Float64PolygonSerializerVisitor(size_t n) CartesianPolygonSerializerVisitor(size_t n)
: offsets(ColumnUInt64::create(n)) : offsets(ColumnUInt64::create(n))
{} {}
void operator()(const Float64Point & point) void operator()(const CartesianPoint & point)
{ {
size++; size++;
offsets->insertValue(size); offsets->insertValue(size);
ringSerializer(point); ringSerializer(point);
} }
void operator()(const Float64Ring & ring) void operator()(const CartesianRing & ring)
{ {
size++; size++;
offsets->insertValue(size); offsets->insertValue(size);
ringSerializer(ring); ringSerializer(ring);
} }
void operator()(const Float64Polygon & polygon) void operator()(const CartesianPolygon & polygon)
{ {
size += 1 + polygon.inners().size(); size += 1 + polygon.inners().size();
offsets->insertValue(size); offsets->insertValue(size);
@ -356,7 +414,7 @@ public:
} }
} }
void operator()(const Float64MultiPolygon & multi_polygon) void operator()(const CartesianMultiPolygon & multi_polygon)
{ {
if (multi_polygon.size() != 1) { 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); throw Exception("Unable to write multi-polygon of size " + toString(multi_polygon.size()) + " != 1 to polygon column", ErrorCodes::BAD_ARGUMENTS);
@ -371,43 +429,43 @@ public:
private: private:
size_t size = 0; size_t size = 0;
Float64RingSerializerVisitor ringSerializer; CartesianRingSerializerVisitor ringSerializer;
ColumnUInt64::MutablePtr offsets; ColumnUInt64::MutablePtr offsets;
}; };
class Float64MultiPolygonSerializerVisitor : public boost::static_visitor<void> class CartesianMultiPolygonSerializerVisitor : public boost::static_visitor<void>
{ {
public: public:
Float64MultiPolygonSerializerVisitor() CartesianMultiPolygonSerializerVisitor()
: offsets(ColumnUInt64::create()) : offsets(ColumnUInt64::create())
{} {}
Float64MultiPolygonSerializerVisitor(size_t n) CartesianMultiPolygonSerializerVisitor(size_t n)
: offsets(ColumnUInt64::create(n)) : offsets(ColumnUInt64::create(n))
{} {}
void operator()(const Float64Point & point) void operator()(const CartesianPoint & point)
{ {
size++; size++;
offsets->insertValue(size); offsets->insertValue(size);
polygonSerializer(point); polygonSerializer(point);
} }
void operator()(const Float64Ring & ring) void operator()(const CartesianRing & ring)
{ {
size++; size++;
offsets->insertValue(size); offsets->insertValue(size);
polygonSerializer(ring); polygonSerializer(ring);
} }
void operator()(const Float64Polygon & polygon) void operator()(const CartesianPolygon & polygon)
{ {
size++; size++;
offsets->insertValue(size); offsets->insertValue(size);
polygonSerializer(polygon); polygonSerializer(polygon);
} }
void operator()(const Float64MultiPolygon & multi_polygon) void operator()(const CartesianMultiPolygon & multi_polygon)
{ {
size += multi_polygon.size(); size += multi_polygon.size();
offsets->insertValue(size); offsets->insertValue(size);
@ -424,7 +482,7 @@ public:
private: private:
size_t size = 0; size_t size = 0;
Float64PolygonSerializerVisitor polygonSerializer; CartesianPolygonSerializerVisitor polygonSerializer;
ColumnUInt64::MutablePtr offsets; ColumnUInt64::MutablePtr offsets;
}; };
@ -445,9 +503,9 @@ private:
Visitor visitor; Visitor visitor;
}; };
using Float64PointSerializer = GeometrySerializer<Float64Geometry, Float64PointSerializerVisitor>; using CartesianPointSerializer = GeometrySerializer<CartesianGeometry, CartesianPointSerializerVisitor>;
using Float64RingSerializer = GeometrySerializer<Float64Geometry, Float64RingSerializerVisitor>; using CartesianRingSerializer = GeometrySerializer<CartesianGeometry, CartesianRingSerializerVisitor>;
using Float64PolygonSerializer = GeometrySerializer<Float64Geometry, Float64PolygonSerializerVisitor>; using CartesianPolygonSerializer = GeometrySerializer<CartesianGeometry, CartesianPolygonSerializerVisitor>;
using Float64MultiPolygonSerializer = GeometrySerializer<Float64Geometry, Float64MultiPolygonSerializerVisitor>; using CartesianMultiPolygonSerializer = GeometrySerializer<CartesianGeometry, CartesianMultiPolygonSerializerVisitor>;
} }

View File

@ -28,24 +28,17 @@ namespace ErrorCodes
extern const int ILLEGAL_COLUMN; extern const int ILLEGAL_COLUMN;
} }
template <typename Derived>
using CoordinateType = Float64; class FunctionPolygonAreaBase : public IFunction
using Point = boost::geometry::model::d2::point_xy<CoordinateType>;
using Polygon = boost::geometry::model::polygon<Point, false>;
using MultiPolygon = boost::geometry::model::multi_polygon<Float64Polygon>;
using Box = boost::geometry::model::box<Point>;
class FunctionPolygonArea : public IFunction
{ {
public: public:
static inline const char * name = "polygonArea"; static inline const char * name = Derived::name;
explicit FunctionPolygonArea() = default; explicit FunctionPolygonAreaBase() = default;
static FunctionPtr create(const Context &) static FunctionPtr create(const Context &)
{ {
return std::make_shared<FunctionPolygonArea>(); return std::make_shared<FunctionPolygonAreaBase>();
} }
String getName() const override String getName() const override
@ -68,29 +61,9 @@ public:
return std::make_shared<DataTypeFloat64>(); return std::make_shared<DataTypeFloat64>();
} }
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
{ {
auto get_parser = [&block, &arguments] (size_t i) { return static_cast<const Derived*>(this)->executeImplementation(arguments, result_type, input_rows_count);
const ColumnWithTypeAndName polygon = block.getByPosition(arguments[i]);
return makeGeometryFromColumnParser(polygon);
};
auto parser = get_parser(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<Float64MultiPolygon>(container));
res_column->insertValue(area);
}
block.getByPosition(result).column = std::move(res_column);
} }
bool useDefaultImplementationForConstants() const override bool useDefaultImplementationForConstants() const override
@ -100,9 +73,67 @@ public:
}; };
void registerFunctionPolygonArea(FunctionFactory & factory) class FunctionPolygonAreaCartesian : public FunctionPolygonAreaBase<FunctionPolygonAreaCartesian>
{ {
factory.registerFunction<FunctionPolygonArea>(); 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>();
}
void registerFunctionPolygonAreaGeographic(FunctionFactory & factory)
{
factory.registerFunction<FunctionPolygonAreaGeographic>();
} }
} }

View File

@ -28,14 +28,6 @@ namespace ErrorCodes
extern const int ILLEGAL_COLUMN; extern const int ILLEGAL_COLUMN;
} }
using CoordinateType = Float64;
using Point = boost::geometry::model::d2::point_xy<CoordinateType>;
using Polygon = boost::geometry::model::polygon<Point, false>;
using MultiPolygon = boost::geometry::model::multi_polygon<Float64Polygon>;
using Box = boost::geometry::model::box<Point>;
class FunctionPolygonConvexHull : public IFunction class FunctionPolygonConvexHull : public IFunction
{ {
public: public:
@ -68,34 +60,34 @@ public:
return DataTypeCustomPolygonSerialization::nestedDataType(); return DataTypeCustomPolygonSerialization::nestedDataType();
} }
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{ {
auto get_parser = [&block, &arguments] (size_t i) { auto get_parser = [&arguments] (size_t i) {
const ColumnWithTypeAndName polygon = block.getByPosition(arguments[i]); const ColumnWithTypeAndName polygon = arguments[i];
return makeGeometryFromColumnParser(polygon); return makeCartesianGeometryFromColumnParser(polygon);
}; };
auto parser = get_parser(0); auto parser = get_parser(0);
auto container = createContainer(parser); auto container = createContainer(parser);
Float64PolygonSerializer serializer; CartesianPolygonSerializer serializer;
for (size_t i = 0; i < input_rows_count; i++) for (size_t i = 0; i < input_rows_count; i++)
{ {
get(parser, container, i); get(parser, container, i);
Float64Geometry convex_hull = Float64Polygon({{{}}}); CartesianGeometry convex_hull = CartesianPolygon({{{}}});
boost::geometry::convex_hull( boost::geometry::convex_hull(
boost::get<Float64MultiPolygon>(container), boost::get<CartesianMultiPolygon>(container),
boost::get<Float64Polygon>(convex_hull)); boost::get<CartesianPolygon>(convex_hull));
boost::get<Float64Polygon>(convex_hull).outer().erase( boost::get<CartesianPolygon>(convex_hull).outer().erase(
boost::get<Float64Polygon>(convex_hull).outer().begin()); boost::get<CartesianPolygon>(convex_hull).outer().begin());
serializer.add(convex_hull); serializer.add(convex_hull);
} }
block.getByPosition(result).column = std::move(serializer.finalize()); return serializer.finalize();
} }
bool useDefaultImplementationForConstants() const override bool useDefaultImplementationForConstants() const override

View File

@ -28,24 +28,17 @@ namespace ErrorCodes
extern const int ILLEGAL_COLUMN; extern const int ILLEGAL_COLUMN;
} }
template <typename Derived>
using CoordinateType = Float64; class FunctionPolygonPerimeterBase : public IFunction
using Point = boost::geometry::model::d2::point_xy<CoordinateType>;
using Polygon = boost::geometry::model::polygon<Point, false>;
using MultiPolygon = boost::geometry::model::multi_polygon<Float64Polygon>;
using Box = boost::geometry::model::box<Point>;
class FunctionPolygonPerimeter : public IFunction
{ {
public: public:
static inline const char * name = "polygonPerimeter"; static inline const char * name = Derived::name;
explicit FunctionPolygonPerimeter() = default; explicit FunctionPolygonPerimeterBase() = default;
static FunctionPtr create(const Context &) static FunctionPtr create(const Context &)
{ {
return std::make_shared<FunctionPolygonPerimeter>(); return std::make_shared<FunctionPolygonPerimeterBase>();
} }
String getName() const override String getName() const override
@ -68,14 +61,25 @@ public:
return std::make_shared<DataTypeFloat64>(); return std::make_shared<DataTypeFloat64>();
} }
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
{ {
auto get_parser = [&block, &arguments] (size_t i) { return static_cast<const Derived*>(this)->executeImplementation(arguments, result_type, input_rows_count);
const ColumnWithTypeAndName polygon = block.getByPosition(arguments[i]); }
return makeGeometryFromColumnParser(polygon);
};
auto parser = get_parser(0); bool useDefaultImplementationForConstants() const override
{
return true;
}
};
class FunctionPolygonPerimeterCartesian : public FunctionPolygonPerimeterBase<FunctionPolygonPerimeterCartesian>
{
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 container = createContainer(parser);
auto res_column = ColumnFloat64::create(); auto res_column = ColumnFloat64::create();
@ -85,24 +89,52 @@ public:
get(parser, container, i); get(parser, container, i);
Float64 perimeter = boost::geometry::perimeter( Float64 perimeter = boost::geometry::perimeter(
boost::get<Float64MultiPolygon>(container)); boost::get<CartesianMultiPolygon>(container));
res_column->insertValue(perimeter); res_column->insertValue(perimeter);
} }
block.getByPosition(result).column = std::move(res_column); return res_column;
}
bool useDefaultImplementationForConstants() const override
{
return true;
} }
}; };
void registerFunctionPolygonPerimeter(FunctionFactory & factory) class FunctionPolygonPerimeterGeographic : public FunctionPolygonPerimeterBase<FunctionPolygonPerimeterGeographic>
{ {
factory.registerFunction<FunctionPolygonPerimeter>(); 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>();
}
void registerFunctionPolygonPerimeterGeographic(FunctionFactory & factory)
{
factory.registerFunction<FunctionPolygonPerimeterGeographic>();
} }
} }

View File

@ -30,24 +30,17 @@ namespace ErrorCodes
extern const int ILLEGAL_COLUMN; extern const int ILLEGAL_COLUMN;
} }
template <typename Derived>
using CoordinateType = Float64; class FunctionPolygonsDistanceBase : public IFunction
using Point = boost::geometry::model::d2::point_xy<CoordinateType>;
using Polygon = boost::geometry::model::polygon<Point, false>;
using MultiPolygon = boost::geometry::model::multi_polygon<Float64Polygon>;
using Box = boost::geometry::model::box<Point>;
class FunctionPolygonsDistance : public IFunction
{ {
public: public:
static inline const char * name = "polygonsDistance"; static inline const char * name = Derived::name;
explicit FunctionPolygonsDistance() = default; explicit FunctionPolygonsDistanceBase() = default;
static FunctionPtr create(const Context &) static FunctionPtr create(const Context &)
{ {
return std::make_shared<FunctionPolygonsDistance>(); return std::make_shared<FunctionPolygonsDistanceBase>();
} }
String getName() const override String getName() const override
@ -70,42 +63,9 @@ public:
return std::make_shared<DataTypeFloat64>(); return std::make_shared<DataTypeFloat64>();
} }
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
{ {
auto get_parser = [&block, &arguments] (size_t i) { return static_cast<const Derived*>(this)->executeImplementation(arguments, result_type, input_rows_count);
const auto * const_col =
checkAndGetColumn<ColumnConst>(block.getByPosition(arguments[i]).column.get());
bool is_const = static_cast<bool>(const_col);
return std::pair<bool, GeometryFromColumnParser>{is_const, is_const ?
makeGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), block.getByPosition(arguments[i]).type, block.getByPosition(arguments[i]).name)) :
makeGeometryFromColumnParser(block.getByPosition(arguments[i]))};
};
auto [is_first_polygon_const, first_parser] = get_parser(0);
auto first_container = createContainer(first_parser);
auto [is_second_polygon_const, second_parser] = get_parser(1);
auto second_container = createContainer(second_parser);
auto res_column = ColumnFloat64::create();
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);
Float64 distance = boost::geometry::distance(
boost::get<Float64MultiPolygon>(first_container),
boost::get<Float64MultiPolygon>(second_container));
res_column->insertValue(distance);
}
block.getByPosition(result).column = std::move(res_column);
} }
bool useDefaultImplementationForConstants() const override bool useDefaultImplementationForConstants() const override
@ -115,9 +75,72 @@ public:
}; };
void registerFunctionPolygonsDistance(FunctionFactory & factory) class FunctionPolygonsDistanceCartesian : public FunctionPolygonsDistanceBase<FunctionPolygonsDistanceCartesian>
{ {
factory.registerFunction<FunctionPolygonsDistance>(); 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>();
}
void registerFunctionPolygonsDistanceGeographic(FunctionFactory & factory)
{
factory.registerFunction<FunctionPolygonsDistanceGeographic>();
} }
} }

View File

@ -30,14 +30,6 @@ namespace ErrorCodes
extern const int ILLEGAL_COLUMN; extern const int ILLEGAL_COLUMN;
} }
using CoordinateType = Float64;
using Point = boost::geometry::model::d2::point_xy<CoordinateType>;
using Polygon = boost::geometry::model::polygon<Point, false>;
using MultiPolygon = boost::geometry::model::multi_polygon<Float64Polygon>;
using Box = boost::geometry::model::box<Point>;
class FunctionPolygonsEquals : public IFunction class FunctionPolygonsEquals : public IFunction
{ {
public: public:
@ -70,17 +62,17 @@ public:
return std::make_shared<DataTypeUInt8>(); return std::make_shared<DataTypeUInt8>();
} }
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{ {
auto get_parser = [&block, &arguments] (size_t i) { auto get_parser = [&arguments] (size_t i) {
const auto * const_col = const auto * const_col =
checkAndGetColumn<ColumnConst>(block.getByPosition(arguments[i]).column.get()); checkAndGetColumn<ColumnConst>(arguments[i].column.get());
bool is_const = static_cast<bool>(const_col); bool is_const = static_cast<bool>(const_col);
return std::pair<bool, GeometryFromColumnParser>{is_const, is_const ? return std::pair<bool, CartesianGeometryFromColumnParser>{is_const, is_const ?
makeGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), block.getByPosition(arguments[i]).type, block.getByPosition(arguments[i]).name)) : makeCartesianGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), arguments[i].type, arguments[i].name)) :
makeGeometryFromColumnParser(block.getByPosition(arguments[i]))}; makeCartesianGeometryFromColumnParser(arguments[i])};
}; };
auto [is_first_polygon_const, first_parser] = get_parser(0); auto [is_first_polygon_const, first_parser] = get_parser(0);
@ -99,13 +91,13 @@ public:
get(second_parser, second_container, i); get(second_parser, second_container, i);
bool equals = boost::geometry::equals( bool equals = boost::geometry::equals(
boost::get<Float64MultiPolygon>(first_container), boost::get<CartesianMultiPolygon>(first_container),
boost::get<Float64MultiPolygon>(second_container)); boost::get<CartesianMultiPolygon>(second_container));
res_column->insertValue(equals); res_column->insertValue(equals);
} }
block.getByPosition(result).column = std::move(res_column); return res_column;
} }
bool useDefaultImplementationForConstants() const override bool useDefaultImplementationForConstants() const override

View File

@ -29,13 +29,6 @@ namespace ErrorCodes
} }
using CoordinateType = Float64;
using Point = boost::geometry::model::d2::point_xy<CoordinateType>;
using Polygon = boost::geometry::model::polygon<Point, false>;
using MultiPolygon = boost::geometry::model::multi_polygon<Float64Polygon>;
using Box = boost::geometry::model::box<Point>;
class FunctionPolygonsIntersection : public IFunction class FunctionPolygonsIntersection : public IFunction
{ {
public: public:
@ -68,17 +61,17 @@ public:
return DataTypeCustomMultiPolygonSerialization::nestedDataType(); return DataTypeCustomMultiPolygonSerialization::nestedDataType();
} }
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{ {
auto get_parser = [&block, &arguments] (size_t i) { auto get_parser = [&arguments] (size_t i) {
const auto * const_col = const auto * const_col =
checkAndGetColumn<ColumnConst>(block.getByPosition(arguments[i]).column.get()); checkAndGetColumn<ColumnConst>(arguments[i].column.get());
bool is_const = static_cast<bool>(const_col); bool is_const = static_cast<bool>(const_col);
return std::pair<bool, GeometryFromColumnParser>{is_const, is_const ? return std::pair<bool, CartesianGeometryFromColumnParser>{is_const, is_const ?
makeGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), block.getByPosition(arguments[i]).type, block.getByPosition(arguments[i]).name)) : makeCartesianGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), arguments[i].type, arguments[i].name)) :
makeGeometryFromColumnParser(block.getByPosition(arguments[i]))}; makeCartesianGeometryFromColumnParser(arguments[i])};
}; };
auto [is_first_polygon_const, first_parser] = get_parser(0); auto [is_first_polygon_const, first_parser] = get_parser(0);
@ -87,7 +80,7 @@ public:
auto [is_second_polygon_const, second_parser] = get_parser(1); auto [is_second_polygon_const, second_parser] = get_parser(1);
auto second_container = createContainer(second_parser); auto second_container = createContainer(second_parser);
Float64MultiPolygonSerializer serializer; CartesianMultiPolygonSerializer serializer;
for (size_t i = 0; i < input_rows_count; i++) for (size_t i = 0; i < input_rows_count; i++)
{ {
@ -96,19 +89,19 @@ public:
if (!is_second_polygon_const || i == 0) if (!is_second_polygon_const || i == 0)
get(second_parser, second_container, i); get(second_parser, second_container, i);
Float64Geometry intersection = Float64MultiPolygon({{{{}}}}); CartesianGeometry intersection = CartesianMultiPolygon({{{{}}}});
boost::geometry::intersection( boost::geometry::intersection(
boost::get<Float64MultiPolygon>(first_container), boost::get<CartesianMultiPolygon>(first_container),
boost::get<Float64MultiPolygon>(second_container), boost::get<CartesianMultiPolygon>(second_container),
boost::get<Float64MultiPolygon>(intersection)); boost::get<CartesianMultiPolygon>(intersection));
boost::get<Float64MultiPolygon>(intersection).erase( boost::get<CartesianMultiPolygon>(intersection).erase(
boost::get<Float64MultiPolygon>(intersection).begin()); boost::get<CartesianMultiPolygon>(intersection).begin());
serializer.add(intersection); serializer.add(intersection);
} }
block.getByPosition(result).column = std::move(serializer.finalize()); return serializer.finalize();
} }
bool useDefaultImplementationForConstants() const override bool useDefaultImplementationForConstants() const override

View File

@ -28,14 +28,6 @@ namespace ErrorCodes
extern const int ILLEGAL_COLUMN; extern const int ILLEGAL_COLUMN;
} }
using CoordinateType = Float64;
using Point = boost::geometry::model::d2::point_xy<CoordinateType>;
using Polygon = boost::geometry::model::polygon<Point, false>;
using MultiPolygon = boost::geometry::model::multi_polygon<Float64Polygon>;
using Box = boost::geometry::model::box<Point>;
class FunctionPolygonsSymDifference : public IFunction class FunctionPolygonsSymDifference : public IFunction
{ {
public: public:
@ -68,17 +60,17 @@ public:
return DataTypeCustomMultiPolygonSerialization::nestedDataType(); return DataTypeCustomMultiPolygonSerialization::nestedDataType();
} }
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{ {
auto get_parser = [&block, &arguments] (size_t i) { auto get_parser = [&arguments] (size_t i) {
const auto * const_col = const auto * const_col =
checkAndGetColumn<ColumnConst>(block.getByPosition(arguments[i]).column.get()); checkAndGetColumn<ColumnConst>(arguments[i].column.get());
bool is_const = static_cast<bool>(const_col); bool is_const = static_cast<bool>(const_col);
return std::pair<bool, GeometryFromColumnParser>{is_const, is_const ? return std::pair<bool, CartesianGeometryFromColumnParser>{is_const, is_const ?
makeGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), block.getByPosition(arguments[i]).type, block.getByPosition(arguments[i]).name)) : makeCartesianGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), arguments[i].type, arguments[i].name)) :
makeGeometryFromColumnParser(block.getByPosition(arguments[i]))}; makeCartesianGeometryFromColumnParser(arguments[i])};
}; };
auto [is_first_polygon_const, first_parser] = get_parser(0); auto [is_first_polygon_const, first_parser] = get_parser(0);
@ -87,7 +79,7 @@ public:
auto [is_second_polygon_const, second_parser] = get_parser(1); auto [is_second_polygon_const, second_parser] = get_parser(1);
auto second_container = createContainer(second_parser); auto second_container = createContainer(second_parser);
Float64MultiPolygonSerializer serializer; CartesianMultiPolygonSerializer serializer;
for (size_t i = 0; i < input_rows_count; i++) for (size_t i = 0; i < input_rows_count; i++)
{ {
@ -96,19 +88,19 @@ public:
if (!is_second_polygon_const || i == 0) if (!is_second_polygon_const || i == 0)
get(second_parser, second_container, i); get(second_parser, second_container, i);
Float64Geometry sym_difference = Float64MultiPolygon({{{{}}}}); CartesianGeometry sym_difference = CartesianMultiPolygon({{{{}}}});
boost::geometry::sym_difference( boost::geometry::sym_difference(
boost::get<Float64MultiPolygon>(first_container), boost::get<CartesianMultiPolygon>(first_container),
boost::get<Float64MultiPolygon>(second_container), boost::get<CartesianMultiPolygon>(second_container),
boost::get<Float64MultiPolygon>(sym_difference)); boost::get<CartesianMultiPolygon>(sym_difference));
boost::get<Float64MultiPolygon>(sym_difference).erase( boost::get<CartesianMultiPolygon>(sym_difference).erase(
boost::get<Float64MultiPolygon>(sym_difference).begin()); boost::get<CartesianMultiPolygon>(sym_difference).begin());
serializer.add(sym_difference); serializer.add(sym_difference);
} }
block.getByPosition(result).column = std::move(serializer.finalize()); return serializer.finalize();
} }
bool useDefaultImplementationForConstants() const override bool useDefaultImplementationForConstants() const override

View File

@ -30,14 +30,6 @@ namespace ErrorCodes
extern const int ILLEGAL_COLUMN; extern const int ILLEGAL_COLUMN;
} }
using CoordinateType = Float64;
using Point = boost::geometry::model::d2::point_xy<CoordinateType>;
using Polygon = boost::geometry::model::polygon<Point, false>;
using MultiPolygon = boost::geometry::model::multi_polygon<Float64Polygon>;
using Box = boost::geometry::model::box<Point>;
class FunctionPolygonsWithin : public IFunction class FunctionPolygonsWithin : public IFunction
{ {
public: public:
@ -70,17 +62,17 @@ public:
return std::make_shared<DataTypeUInt8>(); return std::make_shared<DataTypeUInt8>();
} }
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{ {
auto get_parser = [&block, &arguments] (size_t i) { auto get_parser = [&arguments] (size_t i) {
const auto * const_col = const auto * const_col =
checkAndGetColumn<ColumnConst>(block.getByPosition(arguments[i]).column.get()); checkAndGetColumn<ColumnConst>(arguments[i].column.get());
bool is_const = static_cast<bool>(const_col); bool is_const = static_cast<bool>(const_col);
return std::pair<bool, GeometryFromColumnParser>{is_const, is_const ? return std::pair<bool, CartesianGeometryFromColumnParser>{is_const, is_const ?
makeGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), block.getByPosition(arguments[i]).type, block.getByPosition(arguments[i]).name)) : makeCartesianGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), arguments[i].type, arguments[i].name)) :
makeGeometryFromColumnParser(block.getByPosition(arguments[i]))}; makeCartesianGeometryFromColumnParser(arguments[i])};
}; };
auto [is_first_polygon_const, first_parser] = get_parser(0); auto [is_first_polygon_const, first_parser] = get_parser(0);
@ -99,13 +91,13 @@ public:
get(second_parser, second_container, i); get(second_parser, second_container, i);
bool within = boost::geometry::within( bool within = boost::geometry::within(
boost::get<Float64MultiPolygon>(first_container), boost::get<CartesianMultiPolygon>(first_container),
boost::get<Float64MultiPolygon>(second_container)); boost::get<CartesianMultiPolygon>(second_container));
res_column->insertValue(within); res_column->insertValue(within);
} }
block.getByPosition(result).column = std::move(res_column); return res_column;
} }
bool useDefaultImplementationForConstants() const override bool useDefaultImplementationForConstants() const override

View File

@ -39,9 +39,9 @@ public:
return DataType::nestedDataType(); return DataType::nestedDataType();
} }
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{ {
auto column_string = checkAndGetColumn<ColumnString>(block.getByPosition(arguments[0]).column.get()); auto column_string = checkAndGetColumn<ColumnString>(arguments[0].column.get());
Serializer serializer; Serializer serializer;
Geometry geometry; Geometry geometry;
@ -53,7 +53,7 @@ public:
serializer.add(geometry); serializer.add(geometry);
} }
block.getByPosition(result).column = serializer.finalize(); return serializer.finalize();
} }
bool useDefaultImplementationForConstants() const override bool useDefaultImplementationForConstants() const override
@ -62,7 +62,7 @@ public:
} }
}; };
class FunctionReadWktPoint : public FunctionReadWkt<DataTypeCustomPointSerialization, Float64Point, Float64PointSerializer> class FunctionReadWktPoint : public FunctionReadWkt<DataTypeCustomPointSerialization, CartesianPoint, CartesianPointSerializer>
{ {
public: public:
static inline const char * name = "readWktPoint"; static inline const char * name = "readWktPoint";
@ -76,7 +76,7 @@ public:
} }
}; };
class FunctionReadWktPolygon : public FunctionReadWkt<DataTypeCustomPolygonSerialization, Float64Polygon, Float64PolygonSerializer> class FunctionReadWktPolygon : public FunctionReadWkt<DataTypeCustomPolygonSerialization, CartesianPolygon, CartesianPolygonSerializer>
{ {
public: public:
static inline const char * name = "readWktPolygon"; static inline const char * name = "readWktPolygon";
@ -90,7 +90,7 @@ public:
} }
}; };
class FunctionReadWktMultiPolygon : public FunctionReadWkt<DataTypeCustomMultiPolygonSerialization, Float64MultiPolygon, Float64MultiPolygonSerializer> class FunctionReadWktMultiPolygon : public FunctionReadWkt<DataTypeCustomMultiPolygonSerialization, CartesianMultiPolygon, CartesianMultiPolygonSerializer>
{ {
public: public:
static inline const char * name = "readWktMultiPolygon"; static inline const char * name = "readWktMultiPolygon";

View File

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

View File

@ -60,13 +60,13 @@ public:
return std::make_shared<DataTypeString>(); return std::make_shared<DataTypeString>();
} }
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{ {
const auto * const_col = checkAndGetColumn<ColumnConst>(block.getByPosition(arguments[0]).column.get()); const auto * const_col = checkAndGetColumn<ColumnConst>(arguments[0].column.get());
auto parser = const_col ? auto parser = const_col ?
makeGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), block.getByPosition(arguments[0]).type, block.getByPosition(arguments[0]).name)) : makeCartesianGeometryFromColumnParser(ColumnWithTypeAndName(const_col->getDataColumnPtr(), arguments[0].type, arguments[0].name)) :
makeGeometryFromColumnParser(block.getByPosition(arguments[0])); makeCartesianGeometryFromColumnParser(arguments[0]);
bool geo_column_is_const = static_cast<bool>(const_col); bool geo_column_is_const = static_cast<bool>(const_col);
@ -76,7 +76,7 @@ public:
bool has_style = arguments.size() > 1; bool has_style = arguments.size() > 1;
ColumnPtr style; ColumnPtr style;
if (has_style) { if (has_style) {
style = block.getByPosition(arguments[1]).column; style = arguments[1].column;
} }
for (size_t i = 0; i < input_rows_count; i++) for (size_t i = 0; i < input_rows_count; i++)
@ -90,7 +90,7 @@ public:
res_column->insertData(serialized.c_str(), serialized.size()); res_column->insertData(serialized.c_str(), serialized.size());
} }
block.getByPosition(result).column = std::move(res_column); return res_column;
} }
bool useDefaultImplementationForConstants() const override bool useDefaultImplementationForConstants() const override

View File

@ -36,9 +36,9 @@ public:
return std::make_shared<DataTypeString>(); return std::make_shared<DataTypeString>();
} }
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & /*result_type*/, size_t input_rows_count) const override
{ {
auto parser = makeGeometryFromColumnParser(block.getByPosition(arguments[0])); auto parser = makeCartesianGeometryFromColumnParser(arguments[0]);
auto res_column = ColumnString::create(); auto res_column = ColumnString::create();
auto container = createContainer(parser); auto container = createContainer(parser);
@ -52,7 +52,7 @@ public:
res_column->insertData(serialized.c_str(), serialized.size()); res_column->insertData(serialized.c_str(), serialized.size());
} }
block.getByPosition(result).column = std::move(res_column); return res_column;
} }
bool useDefaultImplementationForConstants() const override bool useDefaultImplementationForConstants() const override

View File

@ -1 +1 @@
[[(0,0),(0,5),(5,5),(5,0),(0,0)]] [[(0,0),(0,5),(5,5),(5,0),(0,0)]]

View File

@ -1,2 +1,4 @@
0 0
1.2727922061357855 1.2727922061357855
2088389.0786590837
2088389.0786590837

View File

@ -1,3 +1,7 @@
select polygonsDistance([[[(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, 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 polygonsDistance([[[(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
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;

View File

@ -1 +1 @@
select polygonPerimeter([[[(0, 0), (0., 5), (5, 5), (5., 0)]]]) select polygonPerimeterCartesian([[[(0, 0), (0., 5), (5, 5), (5., 0)]]]);

View File

@ -1 +1,2 @@
25 25
3848183.73456666

View File

@ -1 +1,2 @@
select polygonArea([[[(0, 0), (0., 5), (5, 5), (5., 0)]]]) select polygonAreaCartesian([[[(0, 0), (0., 5), (5, 5), (5., 0)]]]);
select polygonAreaGeographic([[[(4.346693, 50.858306), (4.367945, 50.852455), (4.366227, 50.840809), (4.344961, 50.833264), (4.338074, 50.848677), (4.346693, 50.858306)]]]);