Improve layer=* pocessing #5366

Merged
root merged 4 commits from pastk-layering into master 2023-06-30 18:15:32 +00:00
25 changed files with 47200 additions and 50949 deletions

View file

@ -421,6 +421,8 @@
3425648640
3431500856
3432785840
3640664610
3649819616
3942645760
4043309055
4278401920

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -30,9 +30,9 @@
/* 1.Z-INDEX BASE MAP */
area[natural=coastline]
{z-index: -10;}
/* Linear and areal water features are put into the "bg-top" layer
above landcover/background areas and below lines and foreground areas.
*/
line[waterway=river],
line[waterway=riverbank],
line[waterway=stream],
@ -41,15 +41,14 @@ line[waterway=fish_pass],
line[waterway=ditch],
line[waterway=drain],
line[natural=strait],
{z-index: 1;}
{fill-position: background-top; z-index: 1;}
/* man_made=bridge is always layer>=1 and other l=1 features should be drawn above it, hence a low base priority. */
area[man_made=bridge],
{fill-position: foreground; z-index: 1;}
/*
Foreground area water should be above linear water (e.g. rivers)
and below hatching fills, dams, piers.
Areal water should be above linear water (e.g. rivers).
*/
area[natural=water],
area[waterway=dock],
@ -57,10 +56,11 @@ area[waterway=riverbank],
area[landuse=salt_pond],
area[landuse=basin],
area[landuse=reservoir],
{fill-position: foreground; z-index: 1;}
{fill-position: background-top; z-index: 2;}
/* These are foreground areas with semi-transparent hardcoded hatching-style fills.
They are rendered over all other background areas only.
They are rendered over all other background areas.
And we want lines to be rendered above them, hence minimum z-index.
*/
area[leisure=nature_reserve],
@ -79,6 +79,9 @@ line[man_made=breakwater],
{fill-position: foreground; z-index: 3;}
area[natural=coastline]
{z-index: -10;}
area[natural=land],
area[place=islet]
{z-index: 0;}
@ -383,13 +386,15 @@ area|z0-[natural=desert],
/* 6.WATER */
area|z0-[natural=water],
area|z0-[natural=water][!tunnel],
area|z0-[waterway=dock],
area|z0-[waterway=riverbank],
area|z0-[landuse=salt_pond],
area|z12-[landuse=basin],
area|z12-[landuse=reservoir],
{fill-opacity: 1;}
area|z15-[natural=water][tunnel],
{fill-opacity: 0.15;}
area|z11-[natural=wetland],
area|z11-[leisure=marina],
@ -409,13 +414,14 @@ line|z13-[natural=strait],
/* 6.1 Area water(lake,pond etc.) */
area|z0-[natural=water],
area|z0-[natural=water][!tunnel],
area|z0-[landuse=salt_pond],
area|z0-[waterway=dock],
area|z0-[waterway=riverbank],
area|z12-[landuse=basin],
area|z12-[landuse=reservoir],
area|z13-[leisure=swimming_pool],
area|z15-[natural=water][tunnel],
area|z16-[amenity=fountain],
{fill-color: @water;}

View file

@ -529,7 +529,7 @@ node|z15-[natural=beach],
node|z1-[place=ocean],
node|z4-[place=sea],
area|z10-[landuse=reservoir][bbox_area>=4000000],
area|z10-[natural=water][bbox_area>=4000000],
area|z10-[natural=water][!tunnel][bbox_area>=4000000],
line|z11-[waterway=river],
line|z11-[waterway=riverbank],
line|z13-[waterway=stream],
@ -537,13 +537,17 @@ line|z13-[waterway=canal],
line|z13-[waterway=fish_pass],
line|z13-[natural=strait],
node|z14-[natural=strait],
node|z14-[natural=water],
node|z14-[natural=bay],
area|z14-[natural=water],
node|z16-[natural=wetland],
area|z16-[natural=wetland],
{text:name;text-color: @water_label;}
area|z10-[natural=water][!tunnel][bbox_area<4000000],
{text:name;text-color: @water_label;}
area|z12-[landuse=reservoir][bbox_area<4000000],
{text:name;text-color: @water_label;}
/*6.1 Area water(ocean,sea,lake,pond etc.)*/
node|z1-2[place=ocean]
@ -558,25 +562,28 @@ node|z5-[place=ocean]
node|z4-[place=sea]
{font-size: 12;}
node|z14-15[natural=water],
area|z10-[landuse=reservoir][bbox_area>=4000000],
area|z10-13[natural=water][!tunnel][bbox_area>=4000000],
{font-size: 9;}
area|z12-[landuse=reservoir][bbox_area<4000000],
area|z10-13[natural=water][!tunnel][bbox_area<4000000],
{text: none;}
node|z14-15[natural=bay],
node|z14-15[natural=strait],
area|z14-15[natural=water]
area|z14-15[natural=water][!tunnel][bbox_area>=4000000],
{font-size: 10;}
node|z16-[natural=water],
area|z14-15[natural=water][!tunnel][bbox_area<4000000],
{font-size: 10;}
node|z16-[natural=bay],
node|z16-[natural=strait],
node|z16-[natural=wetland],
area|z16-[natural=water],
area|z16-[natural=water][!tunnel][bbox_area>=4000000],
area|z16-[natural=wetland],
{font-size: 11;}
area|z10-[landuse=reservoir][bbox_area>=4000000],
area|z10-[natural=water][bbox_area>=4000000],
{font-size: 9;}
area|z10-[landuse=reservoir][bbox_area<4000000],
area|z10-[natural=water][bbox_area<4000000],
{font-size: 0;} /*check*/
area|z16-[natural=water][!tunnel][bbox_area<4000000],
{font-size: 11;}
/* 6.2 Line water(river,canal etc.) Do not draw tunnel waterways */

View file

@ -28,25 +28,25 @@
/* 1.Z-INDEX BASE MAP */
area[natural=coastline]
{z-index: -10;}
/* Linear and areal water features are put into the "bg-top" layer
above landcover/background areas and below lines and foreground areas.
*/
line[waterway=river],
line[waterway=riverbank],
line[waterway=stream],
line[waterway=canal],
line[waterway=fish_pass],
line[waterway=ditch],
line[waterway=drain],
line[natural=strait],
{z-index: 1;}
{fill-position: background-top; z-index: 1;}
/* man_made=bridge is always layer>=1 and other l=1 features should be drawn above it, hence a low base priority. */
area[man_made=bridge],
{fill-position: foreground; z-index: 1;}
/*
Foreground area water should be above linear water (e.g. rivers)
and below dams, piers.
Areal water should be above linear water (e.g. rivers).
*/
area[natural=water],
area[waterway=dock],
@ -54,7 +54,8 @@ area[waterway=riverbank],
area[landuse=salt_pond],
area[landuse=basin],
area[landuse=reservoir],
{fill-position: foreground; z-index: 1;}
{fill-position: background-top; z-index: 2;}
/* Foreground areas which should be above water. */
area[waterway=dam],
@ -66,6 +67,9 @@ line[man_made=breakwater],
{fill-position: foreground; z-index: 3;}
area[natural=coastline]
{z-index: -10;}
area[natural=land],
area[place=islet]
{z-index: 0;}
@ -334,7 +338,7 @@ area|z0-[natural=desert],
/* 6.WATER */
area|z0-[natural=water],
area|z0-[natural=water][!tunnel],
area|z0-[waterway=dock],
area|z0-[waterway=riverbank],
area|z0-[landuse=salt_pond],
@ -357,7 +361,7 @@ line|z13-[natural=strait],
/* 6.1 Area water(lake,pond etc.) */
area|z0-[natural=water],
area|z0-[natural=water][!tunnel],
area|z0-[landuse=salt_pond],
area|z0-[waterway=dock],
area|z0-[waterway=riverbank],

View file

@ -446,23 +446,22 @@ node|z17-[natural=beach]
node|z1-[place=ocean],
node|z4-[place=sea],
area|z10-[landuse=reservoir][bbox_area>=4000000],
area|z10-[natural=water][bbox_area>=80000000],
area|z10-[natural=water][!tunnel][bbox_area>=4000000],
line|z11-[waterway=river],
line|z11-[waterway=riverbank],
line|z13-[waterway=canal],
line|z13-[natural=strait],
node|z14-[natural=water][bbox_area>=1000000],
node|z14-[natural=bay],
node|z14-[natural=strait],
area|z14-[natural=water][bbox_area>=1000000],
node|z16-[natural=wetland],
area|z16-[natural=wetland],
{text:name;text-color: @water_label;}
/* Don't want to break current logic, but there are several strange moments here:
- removing NODE rule "node|z14-[natural=water][bbox_area>=1000000]" breaks other rules.
- z14-[natural=water], bbox_area=[1000000-4000000] range can stay without captions (see rules below).
*/
area|z10-[natural=water][!tunnel][bbox_area<4000000],
{text:name;text-color: @water_label;}
area|z12-[landuse=reservoir][bbox_area<4000000],
{text:name;text-color: @water_label;}
/*6.1 Area water(ocean,sea,lake,pond etc.)*/
@ -478,25 +477,28 @@ node|z5-[place=ocean]
node|z4-[place=sea]
{font-size: 12;}
node|z14-15[natural=water],
area|z10-[landuse=reservoir][bbox_area>=4000000],
area|z10-13[natural=water][!tunnel][bbox_area>=4000000],
{font-size: 8.5;}
area|z12-[landuse=reservoir][bbox_area<4000000],
area|z10-13[natural=water][!tunnel][bbox_area<4000000],
{text: none;}
node|z14-15[natural=bay],
node|z14-15[natural=strait],
area|z14-15[natural=water]
area|z14-15[natural=water][!tunnel][bbox_area>=4000000],
{font-size: 9.5;}
node|z16-[natural=water],
area|z14-15[natural=water][!tunnel][bbox_area<4000000],
{font-size: 9.5;}
node|z16-[natural=bay],
node|z16-[natural=strait],
node|z16-[natural=wetland],
area|z16-[natural=water],
area|z16-[natural=water][!tunnel][bbox_area>=4000000],
area|z16-[natural=wetland],
{font-size: 10.5;}
area|z10-[landuse=reservoir][bbox_area>=4000000],
area|z10-[natural=water][bbox_area>=4000000],
{font-size: 8.5;}
area|z10-[landuse=reservoir][bbox_area<4000000],
area|z10-[natural=water][bbox_area<4000000],
{font-size: 0;} /*check*/
area|z16-[natural=water][!tunnel][bbox_area<4000000],
{font-size: 10.5;}
/* 6.2 Line water(river,canal etc.) Do not draw tunnel waterways */

View file

@ -722,7 +722,7 @@ world 00000000000000000000 +
pond 11111111111111111111 -
reservoir 11111111111111111111 -
river 11111111111111111111 -
tunnel 11111111111111111111 -
tunnel 00000000000000000000 -
{}
wetland 00000000000111111111 +
bog 00000000000111111111 -

View file

@ -6,8 +6,9 @@
namespace dp
{
float constexpr kMinDepth = -20000.0f;
float constexpr kMaxDepth = 20000.0f;
/// @todo: asymmetric values lead to in-range polygons being clipped still, might be a bug in projection matrix?
float constexpr kMinDepth = -25000.0f;
float constexpr kMaxDepth = 25000.0f;
std::array<float, 16> MakeProjection(dp::ApiVersion apiVersion, float left, float right,
float bottom, float top);

View file

@ -16,10 +16,47 @@ namespace df
{
namespace
{
// Minimum possible log2() value for the float (== -126).
double const kMinLog2 = std::log2(std::numeric_limits<float>::min());
// Minimum priority/depth value for lines and foreground areas. Should be same as in kothic.
static double constexpr kMinLinesDepth = 999.0f;
/*
* The overall rendering depth range [dp::kMinDepth;dp::kMaxDepth] is divided
* into following specific depth ranges:
* FG - foreground lines and areas (buildings..), rendered on top of other geometry always,
* even if a fg feature is layer=-10 (e.g. tunnels should be visibile over landcover and water).
* BG-top - rendered just on top of BG-by-size range, because ordering by size
* doesn't always work with e.g. water mapped over a forest,
* so water should be on top of other landcover always,
* but linear waterways should be hidden beneath it.
* BG-by-size - landcover areas rendered in bbox size order, smaller areas are above larger ones.
* Still, a BG-top water area with layer=-1 should go below other landcover,
* and a layer=1 landcover area should be displayed above water,
* so BG-top and BG-by-size should share the same "layer" space.
*/
// Priority values coming from style files are expected to be separated into following ranges.
static double constexpr kBasePriorityFg = 0,
kBasePriorityBgTop = -1000,
kBasePriorityBgBySize = -2000;
// Define depth ranges boundaries to accomodate for all possible layer=* values.
// One layer space is df::kLayerDepthRange (1000). So each +1/-1 layer value shifts
// depth of the drule by -1000/+1000.
// FG depth range: [0;1000).
static double constexpr kBaseDepthFg = 0,
// layer=-10/10 gives an overall FG range of [-10000;11000).
kMaxLayeredDepthFg = kBaseDepthFg + (1 + feature::LAYER_HIGH) * df::kLayerDepthRange,
kMinLayeredDepthFg = kBaseDepthFg + feature::LAYER_LOW * df::kLayerDepthRange,
// Split the background layer space as 100 for BG-top and 900 for BG-by-size.
kBgTopRangeFraction = 0.1,
kDepthRangeBgTop = kBgTopRangeFraction * df::kLayerDepthRange,
kDepthRangeBgBySize = df::kLayerDepthRange - kDepthRangeBgTop,
// So the BG-top range is [-10100,-10000).
kBaseDepthBgTop = kMinLayeredDepthFg - kDepthRangeBgTop,
// And BG-by-size range is [-11000,-11000).
kBaseDepthBgBySize = kBaseDepthBgTop - kDepthRangeBgBySize,
// Minimum BG depth for layer=-10 is -21000.
kMinLayeredDepthBg = kBaseDepthBgBySize + feature::LAYER_LOW * df::kLayerDepthRange;
static_assert(dp::kMinDepth <= kMinLayeredDepthBg && kMaxLayeredDepthFg <= dp::kMaxDepth);
enum Type
{
@ -110,31 +147,32 @@ private:
{
double depth = key.m_priority;
// Prioritize background areas by their sizes instead of style-set priorities.
// Foreground areas continue to use priorities to be orderable inbetween lines.
if (depth <= kMinLinesDepth && IsTypeOf(key, Area))
depth = m_areaDepth;
if (m_featureLayer != feature::LAYER_EMPTY)
if (IsTypeOf(key, Area | Line))
{
// @todo layers are applicable relative to intersecting features only
// (atm layer correction changes feature's priority against ALL other features);
// and the current implementation is dependent on a stable priorities range.
if (IsTypeOf(key, Line))
if (depth < kBasePriorityBgTop)
{
double const layerPart = m_featureLayer * drule::layer_base_priority;
double const depthPart = fmod(depth, drule::layer_base_priority);
depth = layerPart + depthPart;
ASSERT(IsTypeOf(key, Area), (m_f.GetID()));
ASSERT_GREATER_OR_EQUAL(depth, kBasePriorityBgBySize, (m_f.GetID()));
// Prioritize BG-by-size areas by their bbox sizes instead of style-set priorities.
depth = m_areaDepth;
}
else if (IsTypeOf(key, Area))
else if (depth < kBasePriorityFg)
{
// Background areas have big negative priorities (-13000, -8000), so just add layer correction.
depth += m_featureLayer * drule::layer_base_priority;
// Adjust BG-top features depth range so that it sits just above the BG-by-size range.
depth = kBaseDepthBgTop + (depth - kBasePriorityBgTop) * kBgTopRangeFraction;
}
else
// Shift the depth according to layer=* value.
// Note we don't adjust priorities of "point-styles" according to layer=*,
// because their priorities are used for displacement logic only.
/// @todo we might want to hide e.g. a trash bin under man_made=bridge or a bench on underground railway station?
if (m_featureLayer != feature::LAYER_EMPTY)
{
/// @todo Take into account depth-layer for "point-styles". Like priority in OverlayHandle?
depth += m_featureLayer * df::kLayerDepthRange;
}
// Check no features are clipped by the depth range constraints.
ASSERT(dp::kMinDepth <= depth && depth <= dp::kMaxDepth, (depth, m_f.GetID(), m_featureLayer));
}
drule::BaseRule const * const dRule = drule::rules().Find(key);
@ -158,20 +196,23 @@ private:
void Init()
{
m_featureLayer = m_f.GetLayer();
if (m_geomType == feature::GeomType::Area)
{
// Calculate depth based on areas' sizes instead of style-set priorities.
// Calculate depth based on areas' bbox sizes instead of style-set priorities.
m2::RectD const r = m_f.GetLimitRect(m_zoomLevel);
// Raw areas' size range of about (1e-10, 3000) is too big, have to shrink it.
// Raw areas' size range is about (1e-11, 3000).
double const areaSize = r.SizeX() * r.SizeY();
// log2() of numbers <1.0 is negative, adjust it to be positive.
double const areaSizeCompact = std::log2(areaSize) - kMinLog2;
// Should be well below lines and foreground areas for the layering logic to work correctly,
// produces a depth range of about (-13000, -8000).
m_areaDepth = kMinLinesDepth - areaSizeCompact * 100.0f;
// Use log2() to have more precision distinguishing smaller areas.
double const areaSizeCompact = std::log2(areaSize);
// Compacted range is approx (-37;13).
double constexpr minSize = -37,
maxSize = 13,
stretchFactor = kDepthRangeBgBySize / (maxSize - minSize);
// Adjust the range to fit into [kBaseDepthBgBySize;kBaseDepthBgTop).
m_areaDepth = kBaseDepthBgBySize + (maxSize - areaSizeCompact) * stretchFactor;
// There are depth limits out of which areas won't render.
ASSERT(dp::kMinDepth < m_areaDepth && m_areaDepth < dp::kMaxDepth, (m_areaDepth));
ASSERT(kBaseDepthBgBySize <= m_areaDepth && m_areaDepth < kBaseDepthBgTop, (m_areaDepth, areaSize, areaSizeCompact, m_f.GetID()));
}
}

View file

@ -16,6 +16,11 @@ namespace drule { class BaseRule; }
namespace df
{
// Priority range for area and line drules. Each layer = +/-1 value shifts the range by this number,
// so that e.g. priorities of the default layer=0 range [0;1000) don't intersect with layer=-1 range [-1000;0) and so on..
double constexpr kLayerDepthRange = 1000;
class IsHatchingTerritoryChecker : public ftypes::BaseChecker
{
IsHatchingTerritoryChecker();

View file

@ -31,8 +31,6 @@ namespace drule
/// text field type - can be one of ...
enum text_type_t { text_type_name = 0, text_type_housename, text_type_housenumber };
double const layer_base_priority = 2000;
typedef buffer_vector<Key, 16> KeysT;
void MakeUnique(KeysT & keys);
}

View file

@ -318,7 +318,7 @@ m2::PointD FeatureType::GetCenter()
int8_t FeatureType::GetLayer()
{
if ((m_header & feature::HEADER_MASK_HAS_LAYER) == 0)
return 0;
return feature::LAYER_EMPTY;
ParseCommon();
return m_params.layer;

View file

@ -5,6 +5,7 @@
#include "drape_frontend/navigator.hpp"
#include "drape_frontend/visual_params.hpp"
#include "drape/utils/projection.hpp"
#include "geometry/angles.hpp"
#include "geometry/tree4d.hpp"
@ -715,10 +716,10 @@ void CPUDrawer::Draw(FeatureData const & data)
bool const isArea = !data.m_areas.empty();
drule::BaseRule const * pSymbolRule = nullptr;
double symbolDepth = software_renderer::minDepth;
double symbolDepth = dp::kMinDepth;
drule::BaseRule const * pShieldRule = nullptr;
double shieldDepth = software_renderer::minDepth;
double shieldDepth = dp::kMinDepth;
// separating path rules from other
for (size_t i = 0; i < rules.size(); ++i)

View file

@ -4,6 +4,9 @@
#include "software_renderer/glyph_cache.hpp"
#include "software_renderer/geometry_processors.hpp"
#include "drape_frontend/stylist.hpp"
#include "drape/utils/projection.hpp"
#include "indexer/drawing_rules.hpp"
#include "indexer/feature.hpp"
#include "indexer/feature_data.hpp"
@ -38,7 +41,7 @@ namespace software_renderer
{
DrawRule::DrawRule(drule::BaseRule const * p, double depth)
: m_rule(p)
, m_depth(base::Clamp(depth, static_cast<double>(minDepth), static_cast<double>(maxDepth)))
, m_depth(base::Clamp(depth, static_cast<double>(dp::kMinDepth), static_cast<double>(dp::kMaxDepth)))
{
}
@ -156,12 +159,12 @@ FeatureStyler::FeatureStyler(FeatureType & f,
if (layer != 0 && depth < 19000)
{
if (keys[i].m_type == drule::line || keys[i].m_type == drule::waymarker)
depth = (layer * drule::layer_base_priority) + fmod(depth, drule::layer_base_priority);
depth = (layer * df::kLayerDepthRange) + fmod(depth, df::kLayerDepthRange);
else if (keys[i].m_type == drule::area)
{
// Use raw depth adding in area feature layers
// (avoid overlap linear objects in case of "fmod").
depth += layer * drule::layer_base_priority;
depth += layer * df::kLayerDepthRange;
}
}

View file

@ -14,9 +14,6 @@ class ScreenBase;
namespace software_renderer
{
const int maxDepth = 20000;
const int minDepth = -20000;
class GlyphCache;
struct DrawRule

@ -1 +1 @@
Subproject commit dbba1c41e0237ad37be0905cf7502e609fca58ab
Subproject commit 2f311e7504986111d4fd0cca7f305238ba611c6f