2020-06-14 17:04:10 +00:00
|
|
|
#include <Functions/geometryConverters.h>
|
2020-06-07 12:33:49 +00:00
|
|
|
|
2020-06-21 17:59:18 +00:00
|
|
|
#include <common/logger_useful.h>
|
2020-06-07 12:33:49 +00:00
|
|
|
|
2021-01-19 17:16:10 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2021-02-15 19:22:13 +00:00
|
|
|
extern const int BAD_ARGUMENTS;
|
|
|
|
extern const int LOGICAL_ERROR;
|
2021-02-20 14:39:45 +00:00
|
|
|
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
2021-01-19 17:16:10 +00:00
|
|
|
}
|
2020-06-07 13:42:09 +00:00
|
|
|
|
2021-02-19 18:09:38 +00:00
|
|
|
template <typename Point>
|
2021-02-20 13:59:37 +00:00
|
|
|
std::vector<Point> PointFromColumnConverter<Point>::convertImpl(size_t shift, size_t count) const
|
2021-02-19 18:09:38 +00:00
|
|
|
{
|
|
|
|
const auto * tuple = typeid_cast<const ColumnTuple *>(col.get());
|
|
|
|
const auto & tuple_columns = tuple->getColumns();
|
|
|
|
|
|
|
|
const auto * x_data = typeid_cast<const ColumnFloat64 *>(tuple_columns[0].get());
|
|
|
|
const auto * y_data = typeid_cast<const ColumnFloat64 *>(tuple_columns[1].get());
|
|
|
|
|
|
|
|
const auto * first_container = x_data->getData().data() + shift;
|
|
|
|
const auto * second_container = y_data->getData().data() + shift;
|
|
|
|
|
|
|
|
std::vector<Point> answer(count);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < count; ++i)
|
|
|
|
{
|
|
|
|
const Float64 first = first_container[i];
|
|
|
|
const Float64 second = second_container[i];
|
|
|
|
|
|
|
|
if (isNaN(first) || isNaN(second))
|
|
|
|
throw Exception("Point's component must not be NaN", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
|
|
|
if (isinf(first) || isinf(second))
|
|
|
|
throw Exception("Point's component must not be infinite", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
|
|
|
answer[i] = Point(first, second);
|
|
|
|
}
|
|
|
|
|
|
|
|
return answer;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Point>
|
2021-02-20 13:59:37 +00:00
|
|
|
std::vector<Ring<Point>> RingFromColumnConverter<Point>::convert() const
|
2021-02-19 18:09:38 +00:00
|
|
|
{
|
2021-02-19 22:26:33 +00:00
|
|
|
const IColumn::Offsets & offsets = typeid_cast<const ColumnArray &>(*col).getOffsets();
|
2021-02-19 18:09:38 +00:00
|
|
|
size_t prev_offset = 0;
|
|
|
|
std::vector<Ring<Point>> answer;
|
|
|
|
answer.reserve(offsets.size());
|
|
|
|
for (size_t offset : offsets)
|
|
|
|
{
|
2021-02-20 13:59:37 +00:00
|
|
|
auto tmp = point_converter.convertImpl(prev_offset, offset - prev_offset);
|
2021-02-19 18:09:38 +00:00
|
|
|
answer.emplace_back(tmp.begin(), tmp.end());
|
|
|
|
prev_offset = offset;
|
|
|
|
}
|
|
|
|
return answer;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Point>
|
2021-02-20 13:59:37 +00:00
|
|
|
std::vector<Polygon<Point>> PolygonFromColumnConverter<Point>::convert() const
|
2021-02-19 18:09:38 +00:00
|
|
|
{
|
2021-02-19 22:26:33 +00:00
|
|
|
const IColumn::Offsets & offsets = typeid_cast<const ColumnArray &>(*col).getOffsets();
|
2021-02-19 18:09:38 +00:00
|
|
|
std::vector<Polygon<Point>> answer(offsets.size());
|
2021-02-20 13:59:37 +00:00
|
|
|
auto all_rings = ring_converter.convert();
|
2021-02-19 18:09:38 +00:00
|
|
|
|
|
|
|
auto prev_offset = 0;
|
|
|
|
for (size_t iter = 0; iter < offsets.size(); ++iter)
|
|
|
|
{
|
|
|
|
const auto current_array_size = offsets[iter] - prev_offset;
|
|
|
|
answer[iter].outer() = std::move(all_rings[prev_offset]);
|
|
|
|
answer[iter].inners().reserve(current_array_size);
|
|
|
|
for (size_t inner_holes = prev_offset + 1; inner_holes < offsets[iter]; ++inner_holes)
|
|
|
|
answer[iter].inners().emplace_back(std::move(all_rings[inner_holes]));
|
|
|
|
prev_offset = offsets[iter];
|
|
|
|
}
|
|
|
|
|
|
|
|
return answer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Point>
|
2021-02-20 13:59:37 +00:00
|
|
|
std::vector<MultiPolygon<Point>> MultiPolygonFromColumnConverter<Point>::convert() const
|
2021-02-19 18:09:38 +00:00
|
|
|
{
|
2021-02-19 22:26:33 +00:00
|
|
|
const IColumn::Offsets & offsets = typeid_cast<const ColumnArray &>(*col).getOffsets();
|
2021-02-19 18:09:38 +00:00
|
|
|
size_t prev_offset = 0;
|
|
|
|
std::vector<MultiPolygon<Point>> answer(offsets.size());
|
|
|
|
|
2021-02-20 13:59:37 +00:00
|
|
|
auto all_polygons = polygon_converter.convert();
|
2021-02-19 18:09:38 +00:00
|
|
|
|
|
|
|
for (size_t iter = 0; iter < offsets.size(); ++iter)
|
|
|
|
{
|
|
|
|
for (size_t polygon_iter = prev_offset; polygon_iter < offsets[iter]; ++polygon_iter)
|
2021-02-20 13:59:37 +00:00
|
|
|
answer[iter].emplace_back(std::move(all_polygons[polygon_iter]));
|
2021-02-19 18:09:38 +00:00
|
|
|
prev_offset = offsets[iter];
|
|
|
|
}
|
|
|
|
|
|
|
|
return answer;
|
|
|
|
}
|
|
|
|
|
2020-06-07 16:04:35 +00:00
|
|
|
|
2021-02-20 13:59:37 +00:00
|
|
|
template class PointFromColumnConverter<CartesianPoint>;
|
|
|
|
template class PointFromColumnConverter<GeographicPoint>;
|
|
|
|
template class RingFromColumnConverter<CartesianPoint>;
|
|
|
|
template class RingFromColumnConverter<GeographicPoint>;
|
|
|
|
template class PolygonFromColumnConverter<CartesianPoint>;
|
|
|
|
template class PolygonFromColumnConverter<GeographicPoint>;
|
|
|
|
template class MultiPolygonFromColumnConverter<CartesianPoint>;
|
|
|
|
template class MultiPolygonFromColumnConverter<GeographicPoint>;
|
2020-06-07 16:04:35 +00:00
|
|
|
|
2021-02-15 19:22:13 +00:00
|
|
|
template <typename Point, template<typename> typename Desired>
|
|
|
|
void checkColumnTypeOrThrow(const ColumnWithTypeAndName & column)
|
|
|
|
{
|
|
|
|
DataTypePtr desired_type;
|
|
|
|
if constexpr (std::is_same_v<Desired<Point>, Ring<Point>>)
|
|
|
|
desired_type = DataTypeCustomRingSerialization::nestedDataType();
|
|
|
|
else if constexpr (std::is_same_v<Desired<Point>, Polygon<Point>>)
|
|
|
|
desired_type = DataTypeCustomPolygonSerialization::nestedDataType();
|
|
|
|
else if constexpr (std::is_same_v<Desired<Point>, MultiPolygon<Point>>)
|
|
|
|
desired_type = DataTypeCustomMultiPolygonSerialization::nestedDataType();
|
|
|
|
else
|
|
|
|
throw Exception("Unexpected Desired type.", ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
|
|
|
if (!desired_type->equals(*column.type))
|
|
|
|
throw Exception(fmt::format("Expected type {} (MultiPolygon), but got {}", desired_type->getName(), column.type->getName()), ErrorCodes::BAD_ARGUMENTS);
|
|
|
|
}
|
|
|
|
|
|
|
|
template void checkColumnTypeOrThrow<CartesianPoint, Ring>(const ColumnWithTypeAndName &);
|
|
|
|
template void checkColumnTypeOrThrow<CartesianPoint, Polygon>(const ColumnWithTypeAndName &);
|
|
|
|
template void checkColumnTypeOrThrow<CartesianPoint, MultiPolygon>(const ColumnWithTypeAndName &);
|
|
|
|
template void checkColumnTypeOrThrow<GeographicPoint, Ring>(const ColumnWithTypeAndName &);
|
|
|
|
template void checkColumnTypeOrThrow<GeographicPoint, Polygon>(const ColumnWithTypeAndName &);
|
|
|
|
template void checkColumnTypeOrThrow<GeographicPoint, MultiPolygon>(const ColumnWithTypeAndName &);
|
|
|
|
|
2020-06-07 12:33:49 +00:00
|
|
|
}
|