2020-06-07 13:42:09 +00:00
|
|
|
#pragma once
|
|
|
|
|
2020-06-07 12:33:49 +00:00
|
|
|
#include <Core/ColumnWithTypeAndName.h>
|
|
|
|
#include <Core/Types.h>
|
|
|
|
|
|
|
|
#include <boost/variant.hpp>
|
|
|
|
#include <boost/geometry/geometries/geometries.hpp>
|
|
|
|
#include <boost/geometry.hpp>
|
|
|
|
#include <boost/geometry/geometries/point_xy.hpp>
|
|
|
|
|
2020-06-07 14:28:46 +00:00
|
|
|
#include <Columns/ColumnsNumber.h>
|
|
|
|
#include <Columns/ColumnArray.h>
|
|
|
|
#include <Columns/ColumnTuple.h>
|
|
|
|
#include <DataTypes/DataTypeArray.h>
|
|
|
|
#include <DataTypes/IDataType.h>
|
2020-06-07 16:47:56 +00:00
|
|
|
#include <IO/WriteHelpers.h>
|
|
|
|
#include <Interpreters/castColumn.h>
|
2020-06-07 14:28:46 +00:00
|
|
|
|
2020-06-07 12:33:49 +00:00
|
|
|
namespace DB {
|
|
|
|
|
2020-06-07 14:28:46 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int ILLEGAL_COLUMN;
|
2020-06-14 17:04:10 +00:00
|
|
|
extern const int BAD_ARGUMENTS;
|
2020-06-07 14:28:46 +00:00
|
|
|
}
|
2020-06-07 12:33:49 +00:00
|
|
|
|
2020-06-07 14:28:46 +00:00
|
|
|
using Float64Point = boost::geometry::model::d2::point_xy<Float64>;
|
|
|
|
using Float64Ring = boost::geometry::model::ring<Float64Point>;
|
|
|
|
using Float64Polygon = boost::geometry::model::polygon<Float64Point>;
|
|
|
|
using Float64MultiPolygon = boost::geometry::model::multi_polygon<Float64Polygon>;
|
|
|
|
using Float64Geometry = boost::variant<Float64Point, Float64Ring, Float64Polygon, Float64MultiPolygon>;
|
|
|
|
|
|
|
|
class Float64PointFromColumnParser
|
2020-06-07 13:42:09 +00:00
|
|
|
{
|
|
|
|
public:
|
2020-06-14 17:04:10 +00:00
|
|
|
Float64PointFromColumnParser(ColumnPtr col_)
|
|
|
|
: col(col_)
|
2020-06-07 14:28:46 +00:00
|
|
|
{
|
2020-06-14 17:04:10 +00:00
|
|
|
const auto & tuple = static_cast<const ColumnTuple &>(*col_);
|
|
|
|
const auto & tuple_columns = tuple.getColumns();
|
2020-06-07 14:28:46 +00:00
|
|
|
|
2020-06-14 17:04:10 +00:00
|
|
|
const auto & x_data = static_cast<const ColumnFloat64 &>(*tuple_columns[0]);
|
|
|
|
x = x_data.getData().data();
|
2020-06-07 14:28:46 +00:00
|
|
|
|
2020-06-14 17:04:10 +00:00
|
|
|
const auto & y_data = static_cast<const ColumnFloat64 &>(*tuple_columns[1]);
|
|
|
|
y = y_data.getData().data();
|
2020-06-07 14:28:46 +00:00
|
|
|
}
|
|
|
|
|
2020-06-14 17:04:10 +00:00
|
|
|
|
2020-06-07 16:04:35 +00:00
|
|
|
Float64Geometry createContainer() const
|
2020-06-07 14:28:46 +00:00
|
|
|
{
|
|
|
|
return Float64Point();
|
|
|
|
}
|
|
|
|
|
2020-06-07 16:04:35 +00:00
|
|
|
void get(Float64Geometry & container, size_t i) const
|
|
|
|
{
|
|
|
|
get(boost::get<Float64Point>(container), i);
|
|
|
|
}
|
|
|
|
|
2020-06-07 14:28:46 +00:00
|
|
|
void get(Float64Point & container, size_t i) const
|
|
|
|
{
|
|
|
|
boost::geometry::set<0>(container, x[i]);
|
2020-06-07 18:26:18 +00:00
|
|
|
boost::geometry::set<1>(container, y[i]);
|
2020-06-07 14:28:46 +00:00
|
|
|
}
|
2020-06-07 13:42:09 +00:00
|
|
|
private:
|
2020-06-14 17:04:10 +00:00
|
|
|
ColumnPtr col;
|
|
|
|
|
2020-06-07 13:42:09 +00:00
|
|
|
const Float64 * x;
|
|
|
|
const Float64 * y;
|
|
|
|
};
|
|
|
|
|
2020-06-07 16:04:35 +00:00
|
|
|
template<class Geometry, class RingType, class PointParser>
|
2020-06-07 14:28:46 +00:00
|
|
|
class RingFromColumnParser
|
|
|
|
{
|
|
|
|
public:
|
2020-06-14 17:04:10 +00:00
|
|
|
RingFromColumnParser(ColumnPtr col_)
|
|
|
|
: offsets(static_cast<const ColumnArray &>(*col_).getOffsets())
|
|
|
|
, pointParser(static_cast<const ColumnArray &>(*col_).getDataPtr())
|
2020-06-07 18:26:18 +00:00
|
|
|
{
|
|
|
|
}
|
2020-06-07 14:28:46 +00:00
|
|
|
|
2020-06-07 16:04:35 +00:00
|
|
|
Geometry createContainer() const
|
2020-06-07 14:28:46 +00:00
|
|
|
{
|
|
|
|
return RingType();
|
|
|
|
}
|
|
|
|
|
2020-06-07 16:04:35 +00:00
|
|
|
void get(Geometry & container, size_t i) const
|
|
|
|
{
|
|
|
|
get(boost::get<RingType>(container), i);
|
|
|
|
}
|
|
|
|
|
2020-06-07 14:28:46 +00:00
|
|
|
void get(RingType & container, size_t i) const
|
|
|
|
{
|
|
|
|
size_t l = offsets[i - 1];
|
|
|
|
size_t r = offsets[i];
|
|
|
|
|
2020-06-07 14:58:34 +00:00
|
|
|
// reserve extra point for case when polygon is open
|
|
|
|
container.reserve(r - l + 1);
|
2020-06-07 14:28:46 +00:00
|
|
|
container.resize(r - l);
|
|
|
|
|
|
|
|
for (size_t j = l; j < r; j++) {
|
2020-06-07 14:58:34 +00:00
|
|
|
pointParser.get(container[j - l], j);
|
|
|
|
}
|
|
|
|
|
|
|
|
// make ring closed
|
|
|
|
if (!boost::geometry::equals(container[0], container.back()))
|
|
|
|
{
|
|
|
|
container.push_back(container[0]);
|
2020-06-07 14:28:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const IColumn::Offsets & offsets;
|
2020-06-07 14:58:34 +00:00
|
|
|
const PointParser pointParser;
|
2020-06-07 14:28:46 +00:00
|
|
|
};
|
|
|
|
|
2020-06-07 16:04:35 +00:00
|
|
|
template<class Geometry, class PolygonType, class RingParser>
|
2020-06-07 14:58:34 +00:00
|
|
|
class PolygonFromColumnParser
|
|
|
|
{
|
|
|
|
public:
|
2020-06-14 17:04:10 +00:00
|
|
|
PolygonFromColumnParser(ColumnPtr col_)
|
|
|
|
: offsets(static_cast<const ColumnArray &>(*col_).getOffsets())
|
|
|
|
, ringParser(static_cast<const ColumnArray &>(*col_).getDataPtr())
|
2020-06-07 14:58:34 +00:00
|
|
|
{}
|
|
|
|
|
2020-06-07 16:04:35 +00:00
|
|
|
Geometry createContainer() const
|
2020-06-07 14:58:34 +00:00
|
|
|
{
|
|
|
|
return PolygonType();
|
|
|
|
}
|
|
|
|
|
2020-06-07 16:04:35 +00:00
|
|
|
void get(Geometry & container, size_t i) const
|
|
|
|
{
|
|
|
|
get(boost::get<PolygonType>(container), i);
|
|
|
|
}
|
|
|
|
|
2020-06-07 14:58:34 +00:00
|
|
|
void get(PolygonType & container, size_t i) const
|
|
|
|
{
|
|
|
|
size_t l = offsets[i - 1];
|
|
|
|
size_t r = offsets[i];
|
|
|
|
|
|
|
|
ringParser.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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const IColumn::Offsets & offsets;
|
|
|
|
const RingParser ringParser;
|
|
|
|
};
|
|
|
|
|
2020-06-07 16:04:35 +00:00
|
|
|
template<class Geometry, class MultiPolygonType, class PolygonParser>
|
2020-06-07 14:58:34 +00:00
|
|
|
class MultiPolygonFromColumnParser
|
|
|
|
{
|
|
|
|
public:
|
2020-06-14 17:04:10 +00:00
|
|
|
MultiPolygonFromColumnParser(ColumnPtr col_)
|
|
|
|
: offsets(static_cast<const ColumnArray &>(*col_).getOffsets())
|
|
|
|
, polygonParser(static_cast<const ColumnArray &>(*col_).getDataPtr())
|
2020-06-07 14:58:34 +00:00
|
|
|
{}
|
|
|
|
|
2020-06-07 16:04:35 +00:00
|
|
|
Geometry createContainer() const
|
2020-06-07 14:58:34 +00:00
|
|
|
{
|
|
|
|
return MultiPolygonType();
|
|
|
|
}
|
|
|
|
|
2020-06-07 16:04:35 +00:00
|
|
|
void get(Geometry & container, size_t i) const
|
2020-06-07 14:58:34 +00:00
|
|
|
{
|
2020-06-07 16:04:35 +00:00
|
|
|
MultiPolygonType & multi_polygon = boost::get<MultiPolygonType>(container);
|
2020-06-07 14:58:34 +00:00
|
|
|
size_t l = offsets[i - 1];
|
|
|
|
size_t r = offsets[i];
|
|
|
|
|
2020-06-07 16:04:35 +00:00
|
|
|
multi_polygon.resize(r - l);
|
2020-06-07 14:58:34 +00:00
|
|
|
for (size_t j = l; j < r; j++)
|
|
|
|
{
|
2020-06-07 16:04:35 +00:00
|
|
|
polygonParser.get(multi_polygon[j - l], j - l);
|
2020-06-07 14:58:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const IColumn::Offsets & offsets;
|
|
|
|
const PolygonParser polygonParser;
|
|
|
|
};
|
|
|
|
|
2020-06-07 16:04:35 +00:00
|
|
|
using Float64RingFromColumnParser = RingFromColumnParser<Float64Geometry, Float64Ring, Float64PointFromColumnParser>;
|
|
|
|
using Float64PolygonFromColumnParser = PolygonFromColumnParser<Float64Geometry, Float64Polygon, Float64RingFromColumnParser>;
|
|
|
|
using Float64MultiPolygonFromColumnParser = MultiPolygonFromColumnParser<Float64Geometry, Float64MultiPolygon, Float64PolygonFromColumnParser>;
|
2020-06-07 14:58:34 +00:00
|
|
|
|
|
|
|
using GeometryFromColumnParser = boost::variant<
|
|
|
|
Float64PointFromColumnParser,
|
|
|
|
Float64RingFromColumnParser,
|
|
|
|
Float64PolygonFromColumnParser,
|
|
|
|
Float64MultiPolygonFromColumnParser
|
|
|
|
>;
|
2020-06-07 13:42:09 +00:00
|
|
|
|
2020-06-07 16:04:35 +00:00
|
|
|
Float64Geometry createContainer(const GeometryFromColumnParser & parser);
|
|
|
|
|
|
|
|
void get(const GeometryFromColumnParser & parser, Float64Geometry & container, size_t i);
|
|
|
|
|
2020-06-07 13:45:28 +00:00
|
|
|
GeometryFromColumnParser makeGeometryFromColumnParser(const ColumnWithTypeAndName & col);
|
2020-06-07 12:33:49 +00:00
|
|
|
|
2020-06-14 17:04:10 +00:00
|
|
|
class Float64PointSerializerVisitor : publicc boost::static_visitor<void>
|
|
|
|
{
|
|
|
|
Float64PointSerializerVisitor()
|
|
|
|
: x(ColumnFloat64::create())
|
|
|
|
, y(ColumnFloat64::create())
|
|
|
|
{}
|
|
|
|
|
|
|
|
Float64PointSerializerVisitor(size_t n)
|
|
|
|
: x(ColumnFloat64::create(n))
|
|
|
|
, y(ColumnFloat64::create(n))
|
|
|
|
{}
|
|
|
|
|
|
|
|
void operator()(const Float64Point & point)
|
|
|
|
{
|
|
|
|
x->insertValue(point.x());
|
|
|
|
y->insertValue(point.y());
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(const Float64Ring & ring)
|
|
|
|
{
|
|
|
|
if (ring.size() != 1) {
|
|
|
|
throw Exception("Unable to write ring of size " + toString(ring.size()) + " != 1 to point column", ErrorCodes::BAD_ARGUMENTS);
|
|
|
|
}
|
|
|
|
(*this)(ring[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(const Float64Polygon & polygon)
|
|
|
|
{
|
|
|
|
if (polygon.inners().size() != 0) {
|
|
|
|
throw Exception("Unable to write polygon with holes to point column", ErrorCodes::BAD_ARGUMENTS);
|
|
|
|
}
|
|
|
|
(*this)(polygon.outer());
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(const Float64MultiPolygon & 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);
|
|
|
|
}
|
|
|
|
(*this)(multi_polygon[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
ColumnPtr finalize()
|
|
|
|
{
|
|
|
|
Columns columns(2);
|
|
|
|
columns[0] = std::move(x);
|
|
|
|
columns[1] = std::move(y);
|
|
|
|
|
|
|
|
return ColumnTuple::create(columns);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class Geometry, class Visitor>
|
|
|
|
class GeometrySerializer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void add(const Geometry & geometry)
|
|
|
|
{
|
|
|
|
boost::apply_visitor(visitor, geometry);
|
|
|
|
}
|
|
|
|
|
|
|
|
ColumnPtr finalize()
|
|
|
|
{
|
|
|
|
return visitor.finalize();
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
Visitor visitor;
|
|
|
|
}
|
|
|
|
|
|
|
|
using Float64PointSerializer = GeometrySerializer<Float64Geometry, Float64PointSerializerVisitor>;
|
|
|
|
|
2020-06-07 12:33:49 +00:00
|
|
|
}
|