forked from organicmaps/organicmaps
[feature][generator] Added "fallback" geometry offset flag.
Follow up f8bc87c33c
.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
This commit is contained in:
parent
84b1dc2757
commit
8e1b28cdde
4 changed files with 66 additions and 35 deletions
|
@ -5,17 +5,14 @@
|
|||
#include "generator/feature_helpers.hpp"
|
||||
#include "generator/tesselator.hpp"
|
||||
|
||||
#include "geometry/parametrized_segment.hpp"
|
||||
#include "geometry/point2d.hpp"
|
||||
#include "geometry/polygon.hpp"
|
||||
#include "geometry/simplification.hpp"
|
||||
|
||||
#include "indexer/classificator.hpp"
|
||||
#include "indexer/data_header.hpp"
|
||||
#include "indexer/feature.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
|
@ -96,6 +93,12 @@ public:
|
|||
WriteOuterPoints(points, scaleIndex);
|
||||
m_ptsPrevCount = points.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK(m_buffer.m_ptsMask != 0, ("Some valid geometry should be present already"));
|
||||
m_buffer.m_ptsMask |= (1 << scaleIndex);
|
||||
m_buffer.m_ptsOffset.push_back(feature::kGeomOffsetFallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,14 +155,25 @@ public:
|
|||
{
|
||||
CHECK(m_buffer.m_innerTrg.empty(), ());
|
||||
m_trgInner = false;
|
||||
|
||||
size_t trgPointsCount = 0;
|
||||
for (auto const & points : polys)
|
||||
trgPointsCount += points.size();
|
||||
|
||||
if (m_trgPrevCount == 0 ||
|
||||
(trgPointsCount + kGeomMinDiff <= m_trgPrevCount && trgPointsCount * kGeomMinFactor <= m_trgPrevCount))
|
||||
{
|
||||
WriteOuterTriangles(polys, scaleIndex);
|
||||
m_trgPrevCount = trgPointsCount;
|
||||
if (WriteOuterTriangles(polys, scaleIndex))
|
||||
{
|
||||
// Assign only if geometry is valid (correctly tesselated and saved).
|
||||
m_trgPrevCount = trgPointsCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK(m_buffer.m_trgMask != 0, ("Some valid geometry should be present already"));
|
||||
m_buffer.m_trgMask |= (1 << scaleIndex);
|
||||
m_buffer.m_trgOffset.push_back(feature::kGeomOffsetFallback);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,12 +208,13 @@ private:
|
|||
|
||||
m_buffer.m_ptsMask |= (1 << i);
|
||||
auto const pos = feature::CheckedFilePosCast(m_geoFileGetter(i));
|
||||
CHECK(pos != feature::kGeomOffsetFallback, ());
|
||||
m_buffer.m_ptsOffset.push_back(pos);
|
||||
|
||||
serial::SaveOuterPath(toSave, cp, m_geoFileGetter(i));
|
||||
}
|
||||
|
||||
void WriteOuterTriangles(Polygons const & polys, int i)
|
||||
bool WriteOuterTriangles(Polygons const & polys, int i)
|
||||
{
|
||||
CHECK(m_trgFileGetter, ("m_trgFileGetter must be set to write outer triangles."));
|
||||
|
||||
|
@ -207,8 +222,9 @@ private:
|
|||
tesselator::TrianglesInfo info;
|
||||
if (0 == tesselator::TesselateInterior(polys, info))
|
||||
{
|
||||
LOG(LINFO, ("GeometryHolder: No triangles in", m_fb.GetMostGenericOsmId()));
|
||||
return;
|
||||
/// @todo Some examples here: https://github.com/organicmaps/organicmaps/issues/5607
|
||||
LOG(LWARNING, ("GeometryHolder: No triangles for scale index", i, "in", m_fb.GetMostGenericOsmId()));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto const cp = m_header.GetGeometryCodingParams(i);
|
||||
|
@ -245,8 +261,11 @@ private:
|
|||
// saving to file
|
||||
m_buffer.m_trgMask |= (1 << i);
|
||||
auto const pos = feature::CheckedFilePosCast(m_trgFileGetter(i));
|
||||
CHECK(pos != feature::kGeomOffsetFallback, ());
|
||||
m_buffer.m_trgOffset.push_back(pos);
|
||||
saver.Save(m_trgFileGetter(i));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FillInnerPointsMask(Points const & points, uint32_t scaleIndex)
|
||||
|
|
|
@ -27,6 +27,11 @@ namespace
|
|||
{
|
||||
uint32_t constexpr kInvalidOffset = numeric_limits<uint32_t>::max();
|
||||
|
||||
bool IsRealGeomOffset(uint32_t offset)
|
||||
{
|
||||
return (offset != kInvalidOffset && offset != kGeomOffsetFallback);
|
||||
}
|
||||
|
||||
// Get an index of inner geometry scale range.
|
||||
// @param[in] scale:
|
||||
// -1 : index for the best geometry
|
||||
|
@ -69,7 +74,7 @@ int GetScaleIndex(SharedLoadInfo const & loadInfo, int scale,
|
|||
case FeatureType::BEST_GEOMETRY:
|
||||
// Choose the best existing geometry for the last visible scale.
|
||||
ind = count - 1;
|
||||
while (ind >= 0 && offsets[ind] == kInvalidOffset)
|
||||
while (ind >= 0 && !IsRealGeomOffset(offsets[ind]))
|
||||
--ind;
|
||||
if (ind >= 0)
|
||||
return ind;
|
||||
|
@ -77,7 +82,7 @@ int GetScaleIndex(SharedLoadInfo const & loadInfo, int scale,
|
|||
|
||||
case FeatureType::WORST_GEOMETRY:
|
||||
// Choose the worst existing geometry for the first visible scale.
|
||||
while (ind < count && offsets[ind] == kInvalidOffset)
|
||||
while (ind < count && !IsRealGeomOffset(offsets[ind]))
|
||||
++ind;
|
||||
if (ind < count)
|
||||
return ind;
|
||||
|
@ -89,15 +94,16 @@ int GetScaleIndex(SharedLoadInfo const & loadInfo, int scale,
|
|||
int const lastScale = loadInfo.GetLastScale();
|
||||
if (scale > lastScale)
|
||||
scale = lastScale;
|
||||
// If there is no geometry for the requested scale
|
||||
// fallback to the next more detailed one.
|
||||
while (ind < count && (scale > loadInfo.GetScale(ind) || offsets[ind] == kInvalidOffset))
|
||||
|
||||
// If there is no geometry for the requested scale (kHasGeoOffsetFlag) fallback to the next more detailed one.
|
||||
while (ind < count && (scale > loadInfo.GetScale(ind) || offsets[ind] == kGeomOffsetFallback))
|
||||
++ind;
|
||||
|
||||
// Some WorldCoasts features have idx == 0 geometry only and its possible
|
||||
// other features to be visible on e.g. idx == 1 only,
|
||||
// but then they shouldn't be attempted to be drawn using other geom scales.
|
||||
ASSERT_LESS(ind, count, ("No suitable geometry scale range in the map file."));
|
||||
return (ind < count ? ind : -1);
|
||||
return (offsets[ind] != kInvalidOffset ? ind : -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -498,8 +504,8 @@ FeatureType::GeomStat FeatureType::GetOuterGeometryStats()
|
|||
|
||||
for (size_t ind = 0; ind < scalesCount; ++ind)
|
||||
{
|
||||
auto const scaleOffset = m_offsets.m_pts[ind];
|
||||
if (scaleOffset != kInvalidOffset)
|
||||
uint32_t const scaleOffset = m_offsets.m_pts[ind];
|
||||
if (IsRealGeomOffset(scaleOffset))
|
||||
{
|
||||
points.clear();
|
||||
points.emplace_back(m_points.front());
|
||||
|
@ -568,15 +574,16 @@ FeatureType::GeomStat FeatureType::GetOuterTrianglesStats()
|
|||
{
|
||||
for (int ind = 0; ind < scalesCount; ++ind)
|
||||
{
|
||||
if (m_offsets.m_trg[ind] != kInvalidOffset)
|
||||
uint32_t const scaleOffset = m_offsets.m_trg[ind];
|
||||
if (IsRealGeomOffset(scaleOffset))
|
||||
{
|
||||
m_triangles.clear();
|
||||
|
||||
ReaderSource<FilesContainerR::TReader> src(m_loadInfo->GetTrianglesReader(ind));
|
||||
src.Skip(m_offsets.m_trg[ind]);
|
||||
src.Skip(scaleOffset);
|
||||
serial::LoadOuterTriangles(src, m_loadInfo->GetGeometryCodingParams(ind), m_triangles);
|
||||
|
||||
res.m_sizes[ind] = static_cast<uint32_t>(src.Pos() - m_offsets.m_trg[ind]);
|
||||
res.m_sizes[ind] = static_cast<uint32_t>(src.Pos() - scaleOffset);
|
||||
res.m_elements[ind] = m_triangles.size() / 3;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,11 @@ namespace feature
|
|||
{
|
||||
class SharedLoadInfo;
|
||||
struct NameParamsOut; // Include feature_utils.hpp when using
|
||||
}
|
||||
|
||||
// "fallback" flag value (1 is taken to distinguish from the "normal" offset value),
|
||||
// which means geometry should be loaded from the next offset of the more detailed geom level.
|
||||
uint32_t constexpr kGeomOffsetFallback = 1;
|
||||
} // namespace feature
|
||||
|
||||
namespace osm
|
||||
{
|
||||
|
|
|
@ -12,9 +12,8 @@
|
|||
#include <memory>
|
||||
#include <random>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace
|
||||
namespace multithread_mwm_test
|
||||
{
|
||||
using SourceT = FeaturesFetcher;
|
||||
|
||||
|
@ -32,14 +31,15 @@ public:
|
|||
m2::RectD const r = GetRandomRect();
|
||||
m_scale = scales::GetScaleLevel(r);
|
||||
|
||||
m_src.ForEachFeature(
|
||||
r,
|
||||
[&](FeatureType & ft) {
|
||||
// Force load feature.
|
||||
// We check asserts here. There is no any other constrains here.
|
||||
(void)ft.IsEmptyGeometry(m_scale);
|
||||
},
|
||||
m_scale);
|
||||
m_src.ForEachFeature(r, [this](FeatureType & ft)
|
||||
{
|
||||
ft.ParseHeader2();
|
||||
(void)ft.GetOuterGeometryStats();
|
||||
(void)ft.GetOuterTrianglesStats();
|
||||
|
||||
// Force load feature. We check asserts here. There is no any other constrains here.
|
||||
CHECK(!ft.IsEmptyGeometry(m_scale), (ft.GetID()));
|
||||
}, m_scale);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ private:
|
|||
// Get random rect inside m_src.
|
||||
m2::RectD GetRandomRect() const
|
||||
{
|
||||
int const count = max(1, rand() % 50);
|
||||
int const count = std::max(1, rand() % 50);
|
||||
|
||||
int const x = rand() % count;
|
||||
int const y = rand() % count;
|
||||
|
@ -66,7 +66,7 @@ private:
|
|||
int m_scale = 0;
|
||||
};
|
||||
|
||||
void RunTest(string const & file)
|
||||
void RunTest(std::string const & file)
|
||||
{
|
||||
SourceT src;
|
||||
src.InitClassificator();
|
||||
|
@ -88,13 +88,14 @@ void RunTest(string const & file)
|
|||
base::thread_pool::routine_simple::ThreadPool pool(kCount);
|
||||
|
||||
for (size_t i = 0; i < kCount; ++i)
|
||||
pool.Add(make_unique<FeaturesLoader>(src));
|
||||
pool.Add(std::make_unique<FeaturesLoader>(src));
|
||||
|
||||
pool.Join();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(Threading_ForEachFeature)
|
||||
{
|
||||
RunTest("minsk-pass");
|
||||
}
|
||||
|
||||
} // namespace multithread_mwm_test
|
||||
|
|
Loading…
Add table
Reference in a new issue