ClickHouse/dbms/src/Dictionaries/PolygonDictionary.cpp

636 lines
22 KiB
C++
Raw Normal View History

2019-12-02 15:26:59 +00:00
#include <ext/map.h>
#include <Columns/ColumnArray.h>
2019-12-02 15:26:59 +00:00
#include "PolygonDictionary.h"
#include "DictionaryBlockInputStream.h"
#include "DictionaryFactory.h"
namespace DB
{
namespace ErrorCodes
{
extern const int TYPE_MISMATCH;
extern const int BAD_ARGUMENTS;
extern const int UNSUPPORTED_METHOD;
}
IPolygonDictionary::IPolygonDictionary(
const std::string & database_,
2019-12-02 15:26:59 +00:00
const std::string & name_,
const DictionaryStructure & dict_struct_,
DictionarySourcePtr source_ptr_,
const DictionaryLifetime dict_lifetime_)
: database(database_)
, name(name_)
, full_name{database_.empty() ? name_ : (database_ + "." + name_)}
2019-12-02 15:26:59 +00:00
, dict_struct(dict_struct_)
, source_ptr(std::move(source_ptr_))
, dict_lifetime(dict_lifetime_)
{
2019-12-16 15:34:46 +00:00
createAttributes();
loadData();
2019-12-02 15:26:59 +00:00
}
const std::string & IPolygonDictionary::getDatabase() const
{
return database;
}
const std::string & IPolygonDictionary::getName() const
2019-12-02 15:26:59 +00:00
{
return name;
}
const std::string & IPolygonDictionary::getFullName() const
{
return full_name;
}
2019-12-02 15:26:59 +00:00
std::string IPolygonDictionary::getTypeName() const
{
return "Polygon";
}
2019-12-16 15:46:51 +00:00
std::string IPolygonDictionary::getKeyDescription() const
{
return dict_struct.getKeyDescription();
}
2019-12-02 15:26:59 +00:00
size_t IPolygonDictionary::getBytesAllocated() const
{
return bytes_allocated;
}
size_t IPolygonDictionary::getQueryCount() const
{
return query_count.load(std::memory_order_relaxed);
}
double IPolygonDictionary::getHitRate() const
{
return 1.0;
}
size_t IPolygonDictionary::getElementCount() const
{
return element_count;
}
double IPolygonDictionary::getLoadFactor() const
{
return 1.0;
}
const IDictionarySource * IPolygonDictionary::getSource() const
{
return source_ptr.get();
}
const DictionaryLifetime & IPolygonDictionary::getLifetime() const
{
return dict_lifetime;
}
const DictionaryStructure & IPolygonDictionary::getStructure() const
{
return dict_struct;
}
bool IPolygonDictionary::isInjective(const std::string &) const
{
return false;
}
2019-12-27 10:57:32 +00:00
BlockInputStreamPtr IPolygonDictionary::getBlockInputStream(const Names &, size_t) const
{
2019-12-27 13:06:03 +00:00
// TODO: In order for this to work one would first have to support retrieving arrays from dictionaries.
// I believe this is a separate task done by some other people.
2019-12-02 15:26:59 +00:00
throw Exception{"Reading the dictionary is not allowed", ErrorCodes::UNSUPPORTED_METHOD};
}
template <typename T>
void IPolygonDictionary::appendNullValueImpl(const Field & null_value)
{
null_values.emplace_back(T(null_value.get<NearestFieldType<T>>()));
}
void IPolygonDictionary::appendNullValue(AttributeUnderlyingType type, const Field & null_value)
{
switch (type)
{
case AttributeUnderlyingType::utUInt8:
appendNullValueImpl<UInt8>(null_value);
break;
case AttributeUnderlyingType::utUInt16:
appendNullValueImpl<UInt16>(null_value);
break;
case AttributeUnderlyingType::utUInt32:
appendNullValueImpl<UInt32>(null_value);
break;
case AttributeUnderlyingType::utUInt64:
appendNullValueImpl<UInt64>(null_value);
break;
case AttributeUnderlyingType::utUInt128:
appendNullValueImpl<UInt128>(null_value);
break;
case AttributeUnderlyingType::utInt8:
appendNullValueImpl<Int8>(null_value);
break;
case AttributeUnderlyingType::utInt16:
appendNullValueImpl<Int16>(null_value);
break;
case AttributeUnderlyingType::utInt32:
appendNullValueImpl<Int32>(null_value);
break;
case AttributeUnderlyingType::utInt64:
appendNullValueImpl<Int64>(null_value);
break;
case AttributeUnderlyingType::utFloat32:
appendNullValueImpl<Float32>(null_value);
break;
case AttributeUnderlyingType::utFloat64:
appendNullValueImpl<Float64>(null_value);
break;
case AttributeUnderlyingType::utDecimal32:
appendNullValueImpl<Decimal32>(null_value);
break;
case AttributeUnderlyingType::utDecimal64:
appendNullValueImpl<Decimal64>(null_value);
break;
case AttributeUnderlyingType::utDecimal128:
appendNullValueImpl<Decimal128>(null_value);
break;
case AttributeUnderlyingType::utString:
appendNullValueImpl<String>(null_value);
break;
2019-12-27 14:22:51 +00:00
}
}
2019-12-27 13:06:03 +00:00
void IPolygonDictionary::createAttributes()
{
2019-12-23 13:23:11 +00:00
attributes.resize(dict_struct.attributes.size());
2019-12-02 15:26:59 +00:00
for (size_t i = 0; i < dict_struct.attributes.size(); ++i)
{
const auto & attr = dict_struct.attributes[i];
attribute_index_by_name.emplace(attr.name, i);
appendNullValue(attr.underlying_type, attr.null_value);
2019-12-02 15:26:59 +00:00
if (attr.hierarchical)
2019-12-02 15:26:59 +00:00
throw Exception{name + ": hierarchical attributes not supported for dictionary of type " + getTypeName(),
ErrorCodes::TYPE_MISMATCH};
}
}
2019-12-24 18:21:50 +00:00
void IPolygonDictionary::blockToAttributes(const DB::Block &block)
{
2019-12-02 15:26:59 +00:00
const auto rows = block.rows();
element_count += rows;
2019-12-27 10:57:32 +00:00
for (size_t i = 0; i < attributes.size(); ++i)
{
2019-12-23 13:23:11 +00:00
const auto & column = block.safeGetByPosition(i + 1);
if (attributes[i])
{
MutableColumnPtr mutated = std::move(*attributes[i]).mutate();
mutated->insertRangeFrom(*column.column, 0, column.column->size());
attributes[i] = std::move(mutated);
}
else
attributes[i] = column.column;
}
2019-12-02 15:26:59 +00:00
polygons.reserve(polygons.size() + rows);
const auto & key = block.safeGetByPosition(0).column;
for (const auto row : ext::range(0, rows))
{
const auto & field = (*key)[row];
2019-12-23 13:23:11 +00:00
// TODO: Get data more efficiently using
2019-12-02 15:26:59 +00:00
polygons.push_back(fieldToMultiPolygon(field));
}
}
2019-12-24 18:21:50 +00:00
void IPolygonDictionary::loadData()
{
2019-12-02 15:26:59 +00:00
auto stream = source_ptr->loadAll();
stream->readPrefix();
2019-12-24 18:21:50 +00:00
while (const auto block = stream->read())
2019-12-02 15:26:59 +00:00
blockToAttributes(block);
stream->readSuffix();
}
void IPolygonDictionary::calculateBytesAllocated()
{
2019-12-23 13:43:12 +00:00
// TODO:: Account for key.
for (const auto & column : attributes)
bytes_allocated += column->allocatedBytes();
2019-12-02 15:26:59 +00:00
}
2019-12-23 13:23:11 +00:00
std::vector<IPolygonDictionary::Point> IPolygonDictionary::extractPoints(const Columns &key_columns)
{
if (key_columns.size() != DIM)
throw Exception{"Expected " + std::to_string(DIM) + " columns of coordinates", ErrorCodes::BAD_ARGUMENTS};
const auto column_x = typeid_cast<const ColumnVector<Float64>*>(key_columns[0].get());
const auto column_y = typeid_cast<const ColumnVector<Float64>*>(key_columns[1].get());
if (!column_x || !column_y)
throw Exception{"Expected columns of Float64", ErrorCodes::TYPE_MISMATCH};
2019-12-02 15:26:59 +00:00
const auto rows = key_columns.front()->size();
2019-12-23 13:23:11 +00:00
std::vector<Point> result;
result.reserve(rows);
2019-12-02 15:26:59 +00:00
for (const auto row : ext::range(0, rows))
2019-12-23 13:23:11 +00:00
result.emplace_back(column_x->getElement(row), column_y->getElement(row));
return result;
}
2019-12-27 10:57:32 +00:00
void IPolygonDictionary::has(const Columns &key_columns, const DataTypes &, PaddedPODArray<UInt8> &out) const
{
2019-12-23 13:23:11 +00:00
size_t row = 0;
for (const auto & pt : extractPoints(key_columns))
2019-12-02 15:26:59 +00:00
{
// TODO: Check whether this will be optimized by the compiler.
2019-12-23 13:23:11 +00:00
size_t trash = 0;
2019-12-02 15:26:59 +00:00
out[row] = find(pt, trash);
2019-12-23 13:23:11 +00:00
++row;
}
2019-12-25 17:32:02 +00:00
2019-12-25 18:49:27 +00:00
query_count.fetch_add(row, std::memory_order_relaxed);
2019-12-23 13:23:11 +00:00
}
2019-12-24 18:21:50 +00:00
size_t IPolygonDictionary::getAttributeIndex(const std::string & attribute_name) const
{
2019-12-23 13:23:11 +00:00
const auto it = attribute_index_by_name.find(attribute_name);
if (it == attribute_index_by_name.end())
throw Exception{"No such attribute: " + attribute_name, ErrorCodes::BAD_ARGUMENTS};
return it->second;
}
#define DECLARE(TYPE) \
void IPolygonDictionary::get##TYPE( \
2019-12-23 13:41:35 +00:00
const std::string & attribute_name, const Columns & key_columns, const DataTypes &, ResultArrayType<TYPE> & out) const \
2019-12-23 13:23:11 +00:00
{ \
const auto ind = getAttributeIndex(attribute_name); \
2019-12-23 13:40:42 +00:00
checkAttributeType(name, attribute_name, dict_struct.attributes[ind].underlying_type, AttributeUnderlyingType::ut##TYPE); \
2019-12-23 13:23:11 +00:00
\
const auto null_value = std::get<TYPE>(null_values[ind]); \
2019-12-23 13:23:11 +00:00
\
getItemsImpl<TYPE, TYPE>( \
ind, \
key_columns, \
[&](const size_t row, const auto value) { out[row] = value; }, \
[&](const size_t) { return null_value; }); \
}
DECLARE(UInt8)
DECLARE(UInt16)
DECLARE(UInt32)
DECLARE(UInt64)
DECLARE(UInt128)
DECLARE(Int8)
DECLARE(Int16)
DECLARE(Int32)
DECLARE(Int64)
DECLARE(Float32)
DECLARE(Float64)
DECLARE(Decimal32)
DECLARE(Decimal64)
DECLARE(Decimal128)
#undef DECLARE
void IPolygonDictionary::getString(
2019-12-23 13:41:35 +00:00
const std::string & attribute_name, const Columns & key_columns, const DataTypes &, ColumnString * out) const
2019-12-23 13:23:11 +00:00
{
const auto ind = getAttributeIndex(attribute_name);
2019-12-23 13:39:17 +00:00
checkAttributeType(name, attribute_name, dict_struct.attributes[ind].underlying_type, AttributeUnderlyingType::utString);
2019-12-23 13:23:11 +00:00
const auto & null_value = StringRef{std::get<String>(null_values[ind])};
2019-12-23 13:23:11 +00:00
2019-12-26 13:23:04 +00:00
getItemsImpl<String, StringRef>(
2019-12-23 13:23:11 +00:00
ind,
key_columns,
2019-12-26 13:23:04 +00:00
[&](const size_t, const StringRef & value) { out->insertData(value.data, value.size); },
2019-12-23 13:23:11 +00:00
[&](const size_t) { return null_value; });
}
#define DECLARE(TYPE) \
void IPolygonDictionary::get##TYPE( \
const std::string & attribute_name, \
const Columns & key_columns, \
2019-12-23 13:39:17 +00:00
const DataTypes &, \
2019-12-23 13:23:11 +00:00
const PaddedPODArray<TYPE> & def, \
ResultArrayType<TYPE> & out) const \
{ \
const auto ind = getAttributeIndex(attribute_name); \
2019-12-23 13:39:17 +00:00
checkAttributeType(name, attribute_name, dict_struct.attributes[ind].underlying_type, AttributeUnderlyingType::ut##TYPE); \
2019-12-23 13:23:11 +00:00
\
getItemsImpl<TYPE, TYPE>( \
ind, \
key_columns, \
[&](const size_t row, const auto value) { out[row] = value; }, \
[&](const size_t row) { return def[row]; }); \
}
DECLARE(UInt8)
DECLARE(UInt16)
DECLARE(UInt32)
DECLARE(UInt64)
DECLARE(UInt128)
DECLARE(Int8)
DECLARE(Int16)
DECLARE(Int32)
DECLARE(Int64)
DECLARE(Float32)
DECLARE(Float64)
DECLARE(Decimal32)
DECLARE(Decimal64)
DECLARE(Decimal128)
#undef DECLARE
void IPolygonDictionary::getString(
const std::string & attribute_name,
const Columns & key_columns,
2019-12-23 13:39:17 +00:00
const DataTypes &,
2019-12-23 13:23:11 +00:00
const ColumnString * const def,
ColumnString * const out) const
{
const auto ind = getAttributeIndex(attribute_name);
2019-12-23 13:39:17 +00:00
checkAttributeType(name, attribute_name, dict_struct.attributes[ind].underlying_type, AttributeUnderlyingType::utString);
2019-12-23 13:23:11 +00:00
2019-12-25 16:31:57 +00:00
getItemsImpl<String, StringRef>(
2019-12-23 13:23:11 +00:00
ind,
key_columns,
[&](const size_t, const StringRef value) { out->insertData(value.data, value.size); },
[&](const size_t row) { return def->getDataAt(row); });
}
#define DECLARE(TYPE) \
void IPolygonDictionary::get##TYPE( \
const std::string & attribute_name, \
const Columns & key_columns, \
2019-12-23 13:39:17 +00:00
const DataTypes &, \
2019-12-23 13:23:11 +00:00
const TYPE def, \
ResultArrayType<TYPE> & out) const \
{ \
const auto ind = getAttributeIndex(attribute_name); \
2019-12-23 13:39:17 +00:00
checkAttributeType(name, attribute_name, dict_struct.attributes[ind].underlying_type, AttributeUnderlyingType::ut##TYPE); \
2019-12-23 13:23:11 +00:00
\
getItemsImpl<TYPE, TYPE>( \
ind, key_columns, [&](const size_t row, const auto value) { out[row] = value; }, [&](const size_t) { return def; }); \
}
DECLARE(UInt8)
DECLARE(UInt16)
DECLARE(UInt32)
DECLARE(UInt64)
DECLARE(UInt128)
DECLARE(Int8)
DECLARE(Int16)
DECLARE(Int32)
DECLARE(Int64)
DECLARE(Float32)
DECLARE(Float64)
DECLARE(Decimal32)
DECLARE(Decimal64)
DECLARE(Decimal128)
#undef DECLARE
void IPolygonDictionary::getString(
const std::string & attribute_name,
const Columns & key_columns,
2019-12-23 13:39:17 +00:00
const DataTypes &,
2019-12-23 13:23:11 +00:00
const String & def,
ColumnString * const out) const
{
const auto ind = getAttributeIndex(attribute_name);
2019-12-23 13:39:17 +00:00
checkAttributeType(name, attribute_name, dict_struct.attributes[ind].underlying_type, AttributeUnderlyingType::utString);
2019-12-23 13:23:11 +00:00
2019-12-25 16:31:57 +00:00
getItemsImpl<String, StringRef>(
2019-12-23 13:23:11 +00:00
ind,
key_columns,
[&](const size_t, const StringRef value) { out->insertData(value.data, value.size); },
[&](const size_t) { return StringRef{def}; });
}
template <typename AttributeType, typename OutputType, typename ValueSetter, typename DefaultGetter>
void IPolygonDictionary::getItemsImpl(
size_t attribute_ind, const Columns & key_columns, ValueSetter && set_value, DefaultGetter && get_default) const
{
const auto points = extractPoints(key_columns);
2019-12-26 13:23:04 +00:00
using ColVecType = std::conditional_t<IsDecimalNumber<AttributeType>, ColumnDecimal<AttributeType>, ColumnVector<AttributeType>>;
using ColType = std::conditional_t<std::is_same<AttributeType, String>::value, ColumnString, ColVecType>;
const auto column = typeid_cast<const ColType *>(attributes[attribute_ind].get());
if (!column)
throw Exception{"An attribute should be a column of its type", ErrorCodes::BAD_ARGUMENTS};
2019-12-23 13:23:11 +00:00
for (const auto i : ext::range(0, points.size()))
{
size_t id = 0;
2019-12-26 13:23:04 +00:00
const auto found = find(points[i], id);
if (!found)
{
set_value(i, static_cast<OutputType>(get_default(i)));
2019-12-26 13:23:04 +00:00
continue;
}
if constexpr (std::is_same<AttributeType, String>::value)
set_value(i, static_cast<OutputType>(column->getDataAt(id)));
else
set_value(i, static_cast<OutputType>(column->getElement(id)));
2019-12-02 15:26:59 +00:00
}
2019-12-23 13:23:11 +00:00
query_count.fetch_add(points.size(), std::memory_order_relaxed);
2019-12-02 15:26:59 +00:00
}
namespace
{
inline void makeDifferences(IColumn::Offsets & values)
{
for (size_t i = 1; i < values.size(); ++i)
values[i] -= values[i - 1];
}
}
void IPolygonDictionary::extractMultiPolygons(const ColumnPtr &column, std::vector<MultiPolygon> &dest) {
IColumn::Offsets polygons, rings, points;
const auto ptr_multi_polygons = typeid_cast<const ColumnArray*>(column.get());
if (!ptr_multi_polygons)
throw Exception{"Expected a column containing arrays of polygons", ErrorCodes::TYPE_MISMATCH};
const auto ptr_polygons = typeid_cast<const ColumnArray*>(&ptr_multi_polygons->getData());
if (!ptr_polygons)
throw Exception{"Expected a column containing arrays of rings when reading polygons", ErrorCodes::TYPE_MISMATCH};
polygons.assign(ptr_multi_polygons->getOffsets());
const auto ptr_rings = typeid_cast<const ColumnArray*>(&ptr_polygons->getData());
if (!ptr_rings)
throw Exception{"Expected a column containing arrays of points when reading rings", ErrorCodes::TYPE_MISMATCH};
rings.assign(ptr_polygons->getOffsets());
2019-12-26 13:23:04 +00:00
const auto ptr_points = typeid_cast<const ColumnArray*>(&ptr_rings->getData());
if (!ptr_points)
throw Exception{"Expected a column containing arrays of Float64s when reading points", ErrorCodes::TYPE_MISMATCH};
points.assign(tr_rings->getOffsets());
const auto ptr_coord = typeid_cast<const ColumnVector<Float64>*>(&ptr_points->getData());
if (!ptr_coord)
throw Exception{"Expected a column containing Float64s when reading coordinates", ErrorCodes::TYPE_MISMATCH};
const auto & coordinates = ptr_points->getOffsets();
makeDifferences(polygons), makeDifferences(rings), makeDifferences(points);
IColumn::Offset point_offset = 0, ring_offset = 0, polygon_offset = 0;
dest.emplace_back();
for (size_t i = 0; i < coordinates.size(); ++i)
{
if (coordinates[i] - (i == 0 ? 0 : coordinates[i - 1]) != DIM)
throw Exception{"All points should be " + std::to_string(DIM) + "-dimensional", ErrorCodes::BAD_ARGUMENTS};
if (points[point_offset] == 0)
{
++point_offset;
if (!dest.back().back().outer().empty())
dest.back().back().inners().emplace_back();
if (rings[ring_offset] == 0)
{
++ring_offset;
dest.back().emplace_back();
if (polygons[polygon_offset] == 0)
{
dest.emplace_back();
++polygon_offset;
}
if (polygon_offset == polygons.size())
throw Exception{"Incorrect polygon formatting", ErrorCodes::BAD_ARGUMENTS};
--polygons[polygon_offset];
}
if (ring_offset == rings.size())
throw Exception{"Incorrect polygon formatting", ErrorCodes::BAD_ARGUMENTS};
--rings[ring_offset];
}
if (point_offset == points.size())
throw Exception{"Incorrect polygon formatting", ErrorCodes::BAD_ARGUMENTS};
--points[point_offset];
auto & ring = (dest.back().back().inners().empty() ? dest.back().back().outer() : dest.back().back().inners().back());
ring.emplace_back(ptr_coord->getElement(2 * i), ptr_coord->getElement(2 * i + 1));
}
}
2019-12-26 13:23:04 +00:00
2019-12-02 15:26:59 +00:00
IPolygonDictionary::Point IPolygonDictionary::fieldToPoint(const Field &field)
{
if (field.getType() == Field::Types::Array)
{
auto coordinate_array = field.get<Array>();
if (coordinate_array.size() != DIM)
throw Exception{"All points should be " + std::to_string(DIM) + "-dimensional", ErrorCodes::BAD_ARGUMENTS};
2019-12-02 15:26:59 +00:00
Float64 values[DIM];
for (size_t i = 0; i < DIM; ++i)
{
if (coordinate_array[i].getType() != Field::Types::Float64)
throw Exception{"Coordinates should be Float64", ErrorCodes::TYPE_MISMATCH};
values[i] = coordinate_array[i].get<Float64>();
}
return {values[0], values[1]};
}
else
throw Exception{"Point is not represented by an array", ErrorCodes::TYPE_MISMATCH};
}
2019-12-24 18:21:50 +00:00
IPolygonDictionary::Polygon IPolygonDictionary::fieldToPolygon(const Field & field)
{
2019-12-02 15:26:59 +00:00
Polygon result;
if (field.getType() == Field::Types::Array)
{
const auto & ring_array = field.get<Array>();
if (ring_array.empty())
throw Exception{"Empty polygons are not allowed", ErrorCodes::BAD_ARGUMENTS};
2019-12-02 15:26:59 +00:00
result.inners().resize(ring_array.size() - 1);
if (ring_array[0].getType() != Field::Types::Array)
throw Exception{"Outer polygon ring is not represented by an array", ErrorCodes::TYPE_MISMATCH};
for (const auto & point : ring_array[0].get<Array>())
bg::append(result.outer(), fieldToPoint(point));
2019-12-27 10:57:32 +00:00
for (size_t i = 0; i < result.inners().size(); ++i)
{
2019-12-02 15:26:59 +00:00
if (ring_array[i + 1].getType() != Field::Types::Array)
throw Exception{"Inner polygon ring is not represented by an array", ErrorCodes::TYPE_MISMATCH};
for (const auto & point : ring_array[i + 1].get<Array>())
bg::append(result.inners()[i], fieldToPoint(point));
}
}
else
throw Exception{"Polygon is not represented by an array", ErrorCodes::TYPE_MISMATCH};
2019-12-23 13:52:44 +00:00
bg::correct(result);
2019-12-02 15:26:59 +00:00
return result;
}
2019-12-24 18:21:50 +00:00
// TODO: Do this more efficiently by casting to the corresponding Column and avoiding Fields.
IPolygonDictionary::MultiPolygon IPolygonDictionary::fieldToMultiPolygon(const Field &field)
{
2019-12-02 15:26:59 +00:00
MultiPolygon result;
if (field.getType() == Field::Types::Array)
{
const auto& polygon_array = field.get<Array>();
result.reserve(polygon_array.size());
for (const auto & polygon : polygon_array)
result.push_back(fieldToPolygon(polygon));
}
else
throw Exception{"MultiPolygon is not represented by an array", ErrorCodes::TYPE_MISMATCH};
return result;
}
2019-12-16 15:11:16 +00:00
SimplePolygonDictionary::SimplePolygonDictionary(
const std::string & database_,
2019-12-23 13:23:11 +00:00
const std::string & name_,
const DictionaryStructure & dict_struct_,
DictionarySourcePtr source_ptr_,
const DictionaryLifetime dict_lifetime_)
: IPolygonDictionary(database_, name_, dict_struct_, std::move(source_ptr_), dict_lifetime_)
2019-12-16 15:11:16 +00:00
{
}
2019-12-16 15:24:26 +00:00
std::shared_ptr<const IExternalLoadable> SimplePolygonDictionary::clone() const
{
return std::make_shared<SimplePolygonDictionary>(
this->database,
2019-12-16 15:24:26 +00:00
this->name,
this->dict_struct,
this->source_ptr->clone(),
this->dict_lifetime);
}
2019-12-02 15:26:59 +00:00
bool SimplePolygonDictionary::find(const Point &point, size_t & id) const
{
for (size_t i = 0; i < (this->polygons).size(); ++i)
{
2019-12-27 10:57:32 +00:00
if (bg::covered_by(point, (this->polygons)[i]))
{
2019-12-02 15:26:59 +00:00
id = i;
return true;
}
}
return false;
}
void registerDictionaryPolygon(DictionaryFactory & factory)
{
auto create_layout = [=](const std::string &,
2019-12-02 15:26:59 +00:00
const DictionaryStructure & dict_struct,
const Poco::Util::AbstractConfiguration & config,
const std::string & config_prefix,
DictionarySourcePtr source_ptr) -> DictionaryPtr
{
const String database = config.getString(config_prefix + ".database", "");
const String name = config.getString(config_prefix + ".name");
2019-12-02 15:26:59 +00:00
// TODO: Check that there is only one key and it is of the correct type.
if (dict_struct.range_min || dict_struct.range_max)
throw Exception{name
+ ": elements .structure.range_min and .structure.range_max should be defined only "
"for a dictionary of layout 'range_hashed'",
ErrorCodes::BAD_ARGUMENTS};
2019-12-02 15:26:59 +00:00
const DictionaryLifetime dict_lifetime{config, config_prefix + ".lifetime"};
return std::make_unique<SimplePolygonDictionary>(database, name, dict_struct, std::move(source_ptr), dict_lifetime);
2019-12-02 15:26:59 +00:00
};
factory.registerLayout("polygon", create_layout, true);
}
2019-12-25 22:02:55 +00:00
}