Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
233
generator/feature_maker.cpp
Normal file
233
generator/feature_maker.cpp
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
#include "generator/feature_maker.hpp"
|
||||
|
||||
#include "generator/holes.hpp"
|
||||
#include "generator/osm2type.hpp"
|
||||
#include "generator/osm_element_helpers.hpp"
|
||||
|
||||
#include "indexer/classificator.hpp"
|
||||
#include "indexer/feature_algo.hpp"
|
||||
#include "indexer/feature_visibility.hpp"
|
||||
#include "indexer/ftypes_matcher.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
namespace generator
|
||||
{
|
||||
using namespace feature;
|
||||
|
||||
std::shared_ptr<FeatureMakerBase> FeatureMakerSimple::Clone() const
|
||||
{
|
||||
return std::make_shared<FeatureMakerSimple>();
|
||||
}
|
||||
|
||||
void FeatureMakerSimple::ParseParams(FeatureBuilderParams & params, OsmElement & p) const
|
||||
{
|
||||
auto const & cl = classif();
|
||||
ftype::GetNameAndType(&p, params, [&cl](uint32_t type) { return cl.IsTypeValid(type); },
|
||||
[this](OsmElement const * p) { return GetOrigin(*p); });
|
||||
}
|
||||
|
||||
std::optional<m2::PointD> FeatureMakerSimple::ReadNode(uint64_t id) const
|
||||
{
|
||||
m2::PointD res;
|
||||
if (m_cache->GetNode(id, res.y, res.x))
|
||||
return res;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<m2::PointD> FeatureMakerSimple::GetOrigin(OsmElement const & e) const
|
||||
{
|
||||
if (e.IsNode())
|
||||
{
|
||||
CHECK(e.m_lat != 0 || e.m_lon != 0, (e.m_id));
|
||||
return mercator::FromLatLon(e.m_lat, e.m_lon);
|
||||
}
|
||||
else if (e.IsWay())
|
||||
{
|
||||
CHECK(!e.m_nodes.empty(), (e.m_id));
|
||||
return ReadNode(e.m_nodes.front());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e.m_members.empty())
|
||||
{
|
||||
// Such relations are considered invalid but could be present in OSM data still,
|
||||
// see https://wiki.openstreetmap.org/wiki/Empty_relations
|
||||
LOG(LWARNING, ("Invalid relation with no members", e.m_id));
|
||||
return {};
|
||||
}
|
||||
for (auto const & m : e.m_members)
|
||||
if (m.m_type == OsmElement::EntityType::Node)
|
||||
return ReadNode(m.m_ref);
|
||||
|
||||
for (auto const & m : e.m_members)
|
||||
{
|
||||
if (m.m_type == OsmElement::EntityType::Way)
|
||||
{
|
||||
WayElement way(m.m_ref);
|
||||
if (m_cache->GetWay(m.m_ref, way))
|
||||
{
|
||||
CHECK(!way.m_nodes.empty(), (m.m_ref));
|
||||
return ReadNode(way.m_nodes.front());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG(LWARNING, ("No geometry members for relation", e.m_id));
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
bool FeatureMakerSimple::BuildFromNode(OsmElement & p, FeatureBuilderParams const & params)
|
||||
{
|
||||
FeatureBuilder fb;
|
||||
fb.SetCenter(mercator::FromLatLon(p.m_lat, p.m_lon));
|
||||
|
||||
fb.SetOsmId(base::MakeOsmNode(p.m_id));
|
||||
fb.SetParams(params);
|
||||
|
||||
m_queue.push(std::move(fb));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FeatureMakerSimple::BuildFromWay(OsmElement & p, FeatureBuilderParams const & params)
|
||||
{
|
||||
auto const & nodes = p.Nodes();
|
||||
if (nodes.size() < 2)
|
||||
return false;
|
||||
|
||||
FeatureBuilder fb;
|
||||
|
||||
std::vector<m2::PointD> points;
|
||||
points.reserve(nodes.size());
|
||||
for (uint64_t ref : nodes)
|
||||
{
|
||||
m2::PointD pt;
|
||||
if (!m_cache->GetNode(ref, pt.y, pt.x))
|
||||
return false;
|
||||
points.push_back(pt);
|
||||
}
|
||||
fb.AssignPoints(std::move(points));
|
||||
|
||||
fb.SetOsmId(base::MakeOsmWay(p.m_id));
|
||||
fb.SetParams(params);
|
||||
|
||||
if (fb.IsGeometryClosed())
|
||||
fb.SetArea();
|
||||
else
|
||||
fb.SetLinear(params.GetReversedGeometry());
|
||||
|
||||
m_queue.push(std::move(fb));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FeatureMakerSimple::BuildFromRelation(OsmElement & p, FeatureBuilderParams const & params)
|
||||
{
|
||||
HolesRelation helper(m_cache);
|
||||
helper.Build(&p);
|
||||
auto const & holesGeometry = helper.GetHoles();
|
||||
auto const size = m_queue.size();
|
||||
|
||||
auto const createFB = [&](auto && pts, auto const & ids)
|
||||
{
|
||||
FeatureBuilder fb;
|
||||
|
||||
fb.AssignArea(std::move(pts), holesGeometry);
|
||||
CHECK(fb.IsGeometryClosed(), ());
|
||||
|
||||
for (uint64_t id : ids)
|
||||
fb.AddOsmId(base::MakeOsmWay(id));
|
||||
fb.AddOsmId(base::MakeOsmRelation(p.m_id));
|
||||
|
||||
fb.SetParams(params);
|
||||
fb.SetArea();
|
||||
|
||||
m_queue.push(std::move(fb));
|
||||
};
|
||||
|
||||
helper.GetOuter().ForEachArea(true /* collectID */, [&](auto && pts, auto && ids) { createFB(std::move(pts), ids); });
|
||||
|
||||
return size != m_queue.size();
|
||||
}
|
||||
|
||||
FeatureMaker::FeatureMaker(IDRInterfacePtr const & cache) : FeatureMakerSimple(cache)
|
||||
{
|
||||
m_placeClass = classif().GetTypeByPath({"place"});
|
||||
}
|
||||
|
||||
std::shared_ptr<FeatureMakerBase> FeatureMaker::Clone() const
|
||||
{
|
||||
return std::make_shared<FeatureMaker>();
|
||||
}
|
||||
|
||||
void FeatureMaker::ParseParams(FeatureBuilderParams & params, OsmElement & p) const
|
||||
{
|
||||
ftype::GetNameAndType(&p, params, &feature::IsUsefulType, [this](OsmElement const * p) { return GetOrigin(*p); });
|
||||
}
|
||||
|
||||
bool FeatureMaker::BuildFromRelation(OsmElement & p, FeatureBuilderParams const & params)
|
||||
{
|
||||
uint32_t const placeType = params.FindType(m_placeClass, 1);
|
||||
if (placeType != ftype::GetEmptyValue())
|
||||
{
|
||||
std::optional<m2::PointD> center;
|
||||
auto const nodes = osm_element::GetPlaceNodeFromMembers(p);
|
||||
if (!nodes.empty())
|
||||
{
|
||||
// Patch to avoid multiple instances from Node and Relation. Node should inherit all needed tags (population).
|
||||
// This is ok, because "canonical" OSM assumes that country/state place tag presents in Nodes only.
|
||||
/// @todo Store boundaries like for cities?
|
||||
if (ftypes::IsCountryChecker::Instance()(placeType) || ftypes::IsStateChecker::Instance()(placeType))
|
||||
return false;
|
||||
|
||||
// admin_centre will be the first
|
||||
center = ReadNode(nodes.front());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculate center of the biggest outer polygon.
|
||||
HolesRelation helper(m_cache);
|
||||
helper.Build(&p);
|
||||
|
||||
double maxArea = 0;
|
||||
helper.GetOuter().ForEachArea(false /* collectID */, [&](auto && pts, auto &&)
|
||||
{
|
||||
m2::RectD rect;
|
||||
CalcRect(pts, rect);
|
||||
double const currArea = rect.Area();
|
||||
if (currArea > maxArea)
|
||||
{
|
||||
center = FeatureBuilder::GetGeometryCenter(pts);
|
||||
maxArea = currArea;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!center)
|
||||
return false;
|
||||
|
||||
// Make separate place Point FeatureFuilder.
|
||||
FeatureBuilder fb;
|
||||
fb.SetCenter(*center);
|
||||
|
||||
fb.SetOsmId(base::MakeOsmRelation(p.m_id));
|
||||
|
||||
FeatureBuilderParams copyParams(params);
|
||||
copyParams.SetType(placeType);
|
||||
fb.SetParams(copyParams);
|
||||
|
||||
m_queue.push(std::move(fb));
|
||||
|
||||
// Default processing without place type.
|
||||
copyParams = params;
|
||||
copyParams.PopExactType(placeType);
|
||||
if (copyParams.FinishAddingTypes())
|
||||
FeatureMakerSimple::BuildFromRelation(p, copyParams);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return FeatureMakerSimple::BuildFromRelation(p, params);
|
||||
}
|
||||
|
||||
} // namespace generator
|
||||
Loading…
Add table
Add a link
Reference in a new issue