diff --git a/src/Functions/geometryFromColumn.cpp b/src/Functions/geometryFromColumn.cpp index c8947659f66c85c2516b57c65a08a9a632f32bdb..03013266caa45063d2071c4fbdcc4adc97b6828a 100644 --- a/src/Functions/geometryFromColumn.cpp +++ b/src/Functions/geometryFromColumn.cpp @@ -1,25 +1,10 @@ -#include -#include -#include -#include #include - namespace DB { -namespace ErrorCodes -{ - extern const int ILLEGAL_COLUMN; -} namespace { -Exception failedToParse(const ColumnWithTypeAndName & col, std::string reason = "") -{ - return Exception("Cannot parse geometry from column with type " + col.type->getName() - + (reason.empty() ? std::string() : ", " + reason), ErrorCodes::ILLEGAL_COLUMN); -} - size_t getArrayDepth(const ColumnWithTypeAndName & col, size_t max_depth) { size_t depth = 0; @@ -35,37 +20,15 @@ size_t getArrayDepth(const ColumnWithTypeAndName & col, size_t max_depth) } -PointFromColumnParser::PointFromColumnParser(const ColumnWithTypeAndName & col) -{ - const auto & tuple_columns = static_cast(*col.column).getColumns(); - - if (tuple_columns.size() != 2) { - throw failedToParse(col, "tuple must have exactly 2 columns"); - } - - x = static_cast(*tuple_columns[0]).getData().data(); - y = static_cast(*tuple_columns[1]).getData().data(); -} - -Point PointFromColumnParser::createContainer() const -{ - return Point(); -} - -void PointFromColumnParser::get(Point & container, size_t i) const -{ - boost::geometry::set<0>(container, x[i]); - boost::geometry::set<0>(container, y[i]); -} - GeometryFromColumnParser makeGeometryFromColumnParser(const ColumnWithTypeAndName & col) { switch (getArrayDepth(col, 3)) { - case 0: return PointFromColumnParser(col); - // case 1: return parseRing(col, i); + case 0: return Float64PointFromColumnParser(*col.column); + case 1: return Float64RingFromColumnParser(*col.column); // case 2: return parsePolygon(col, i); // case 3: return parseMultyPoligon(col, i); - default: throw failedToParse(col, "array depth is too big"); + default: throw Exception("Cannot parse geometry from column with type " + col.type->getName() + + ", array depth is too big", ErrorCodes::ILLEGAL_COLUMN); } } diff --git a/src/Functions/geometryFromColumn.h b/src/Functions/geometryFromColumn.h index 3b381277597c1c207d26af69fe945215fab39e6c..cc9e743ccc3a37561431984b0cd01307c0df8684 100644 --- a/src/Functions/geometryFromColumn.h +++ b/src/Functions/geometryFromColumn.h @@ -8,27 +8,101 @@ #include #include +#include +#include +#include +#include +#include + namespace DB { -using Point = boost::geometry::model::d2::point_xy; -using Ring = boost::geometry::model::ring; -using Polygon = boost::geometry::model::polygon; -using MultiPolygon = boost::geometry::model::multi_polygon; -using Geometry = boost::variant; +namespace ErrorCodes +{ + extern const int ILLEGAL_COLUMN; +} -class PointFromColumnParser +using Float64Point = boost::geometry::model::d2::point_xy; +using Float64Ring = boost::geometry::model::ring; +using Float64Polygon = boost::geometry::model::polygon; +using Float64MultiPolygon = boost::geometry::model::multi_polygon; +using Float64Geometry = boost::variant; + +class Float64PointFromColumnParser { public: - PointFromColumnParser(const ColumnWithTypeAndName & col); - Point createContainer() const; - void get(Point & container, size_t i) const; + Float64PointFromColumnParser(const IColumn & col) + { + const auto & tuple_columns = static_cast(col).getColumns(); + + if (tuple_columns.size() != 2) + { + throw Exception("tuple size must be equal to 2", ErrorCodes::ILLEGAL_COLUMN); + } + + x = static_cast(*tuple_columns[0]).getData().data(); + if (!x) + { + throw Exception("failed to get x column", ErrorCodes::ILLEGAL_COLUMN); + } + + y = static_cast(*tuple_columns[1]).getData().data(); + if (!y) + { + throw Exception("failed to get y column", ErrorCodes::ILLEGAL_COLUMN); + } + } + + Float64Point createContainer() const + { + return Float64Point(); + } + + void get(Float64Point & container, size_t i) const + { + boost::geometry::set<0>(container, x[i]); + boost::geometry::set<0>(container, y[i]); + } private: const Float64 * x; const Float64 * y; }; -using GeometryFromColumnParser = boost::variant; +template +class RingFromColumnParser +{ +public: + RingFromColumnParser(const IColumn & col) + : offsets(static_cast(col).getOffsets()) + , pointParser(static_cast(col).getData()) + { + } + + RingType createContainer() const + { + return RingType(); + } + + void get(RingType & container, size_t i) const + { + size_t l = offsets[i - 1]; + size_t r = offsets[i]; + + container.resize(r - l); + + for (size_t j = l; j < r; j++) { + pointParser.parse(container[j - l], l); + } + } + +private: + const IColumn::Offsets & offsets; + PointParser pointParser; +}; + +using Float64RingFromColumnParser = RingFromColumnParser; + +using GeometryFromColumnParser = boost::variant; GeometryFromColumnParser makeGeometryFromColumnParser(const ColumnWithTypeAndName & col);