@@ -75,8 +75,8 @@ public Places(CountryCoder countryCoder) {
7575 rule (with ("place" , "state" , "province" ), with ("pm:country" , "US" , "CA" , "BR" , "IN" , "CN" , "AU" ),
7676 use ("pm:kind" , "region" )),
7777 rule (with ("place" , "city" , "town" ), use ("pm:kind" , "locality" ), use ("pm:kindDetail" , fromTag ("place" ))),
78- rule (with ("place" , "city" ), without ("population" ), use ("pm:population " , 5000 )),
79- rule (with ("place" , "town" ), without ("population" ), use ("pm:population " , 10000 )),
78+ rule (with ("place" , "city" ), without ("population" ), use ("pm:populationFallback " , 5000 )),
79+ rule (with ("place" , "town" ), without ("population" ), use ("pm:populationFallback " , 10000 )),
8080
8181 // Neighborhood-scale places
8282
@@ -87,17 +87,17 @@ public Places(CountryCoder countryCoder) {
8787 // Smaller places detailed in OSM but not fully tested for Overture
8888
8989 rule (with ("place" , "village" ), use ("pm:kind" , "locality" ), use ("pm:kindDetail" , fromTag ("place" ))),
90- rule (with ("place" , "village" ), without ("population" ), use ("pm:population " , 2000 )),
90+ rule (with ("place" , "village" ), without ("population" ), use ("pm:populationFallback " , 2000 )),
9191 rule (with ("place" , "locality" ), use ("pm:kind" , "locality" )),
92- rule (with ("place" , "locality" ), without ("population" ), use ("pm:population " , 1000 )),
92+ rule (with ("place" , "locality" ), without ("population" ), use ("pm:populationFallback " , 1000 )),
9393 rule (with ("place" , "hamlet" ), use ("pm:kind" , "locality" )),
94- rule (with ("place" , "hamlet" ), without ("population" ), use ("pm:population " , 200 )),
94+ rule (with ("place" , "hamlet" ), without ("population" ), use ("pm:populationFallback " , 200 )),
9595 rule (with ("place" , "isolated_dwelling" ), use ("pm:kind" , "locality" )),
96- rule (with ("place" , "isolated_dwelling" ), without ("population" ), use ("pm:population " , 100 )),
96+ rule (with ("place" , "isolated_dwelling" ), without ("population" ), use ("pm:populationFallback " , 100 )),
9797 rule (with ("place" , "farm" ), use ("pm:kind" , "locality" )),
98- rule (with ("place" , "farm" ), without ("population" ), use ("pm:population " , 50 )),
98+ rule (with ("place" , "farm" ), without ("population" ), use ("pm:populationFallback " , 50 )),
9999 rule (with ("place" , "allotments" ), use ("pm:kind" , "locality" )),
100- rule (with ("place" , "allotments" ), without ("population" ), use ("pm:population " , 1000 ))
100+ rule (with ("place" , "allotments" ), without ("population" ), use ("pm:populationFallback " , 1000 ))
101101
102102 )).index ();
103103
@@ -126,10 +126,14 @@ public Places(CountryCoder countryCoder) {
126126 rule (with ("pm:kind" , "region" ), use ("pm:minzoom" , 8 ), use ("pm:maxzoom" , 11 )),
127127 rule (with ("pm:kind" , "region" ), with ("pm:country" , "US" , "CA" , "BR" , "IN" , "CN" , "AU" ), use ("pm:kindRank" , 1 )),
128128
129- rule (with ("pm:kind" , "locality" ), use ("pm:kindRank" , 4 ), use ("pm:minzoom" , 7 ), use ("pm:maxzoom" , 15 )),
130- rule (with ("pm:kind" , "locality" ), atLeast ("pm:population" , 1000 ), use ("pm:minzoom" , 12 )),
131- rule (with ("pm:kind" , "locality" ), with ("pm:kindDetail" , "city" ), use ("pm:kindRank" , 2 ), use ("pm:minzoom" , 8 )),
132- rule (with ("pm:kind" , "locality" ), with ("pm:kindDetail" , "town" ), use ("pm:kindRank" , 2 ), use ("pm:minzoom" , 9 )),
129+ rule (with ("pm:kind" , "locality" ), use ("pm:kindRank" , 4 ), use ("pm:minzoom" , 11 ), use ("pm:maxzoom" , 15 )),
130+ rule (with ("pm:kind" , "locality" ), with ("pm:populationFallback" ), use ("pm:minzoom" , 12 )),
131+ rule (with ("pm:kind" , "locality" ), with ("pm:kindDetail" , "city" ), use ("pm:kindRank" , 2 ), use ("pm:minzoom" , 7 )),
132+ rule (with ("pm:kind" , "locality" ), with ("pm:kindDetail" , "city" ), with ("pm:populationFallback" ),
133+ use ("pm:minzoom" , 8 )),
134+ rule (with ("pm:kind" , "locality" ), with ("pm:kindDetail" , "town" ), use ("pm:kindRank" , 2 ), use ("pm:minzoom" , 7 )),
135+ rule (with ("pm:kind" , "locality" ), with ("pm:kindDetail" , "town" ), with ("pm:populationFallback" ),
136+ use ("pm:minzoom" , 9 )),
133137 rule (with ("pm:kind" , "locality" ), with ("pm:kindDetail" , "village" ), use ("pm:kindRank" , 3 ), use ("pm:minzoom" , 10 )),
134138 rule (with ("pm:kind" , "locality" ), with ("pm:kindDetail" , "village" ), atLeast ("pm:population" , 2000 ),
135139 use ("pm:minzoom" , 11 )),
@@ -226,6 +230,20 @@ static int getSortKey(double minZoom, int kindRank, long population, String name
226230 15 , 3
227231 ), 0 );
228232
233+ private Map <String , Object > makeTagMap (String kind , String kindDetail , Integer population ,
234+ Integer populationFallback ) {
235+ Map <String , Object > computedTags = new HashMap <>();
236+
237+ computedTags .put ("pm:kind" , kind );
238+ computedTags .put ("pm:kindDetail" , kindDetail );
239+ computedTags .put ("pm:population" , population );
240+ if (populationFallback > 0 ) {
241+ computedTags .put ("pm:populationFallback" , populationFallback );
242+ }
243+
244+ return computedTags ;
245+ }
246+
229247 public void processOsm (SourceFeature sf , FeatureCollector features ) {
230248 if (!sf .isPoint () || !sf .hasTag ("name" ) || !sf .hasTag ("place" )) {
231249 return ;
@@ -245,6 +263,7 @@ public void processOsm(SourceFeature sf, FeatureCollector features) {
245263 String kind = getString (sf , matches , "pm:kind" , "pm:undefined" );
246264 String kindDetail = getString (sf , matches , "pm:kindDetail" , "" );
247265 Integer population = getInteger (sf , matches , "pm:population" , 0 );
266+ Integer populationFallback = getInteger (sf , matches , "pm:populationFallback" , 0 );
248267
249268 if ("pm:undefined" .equals (kind )) {
250269 return ;
@@ -254,9 +273,15 @@ public void processOsm(SourceFeature sf, FeatureCollector features) {
254273 Integer maxZoom ;
255274 Integer kindRank ;
256275
257- var sf2 = new Matcher .SourceFeatureWithComputedTags (sf , Map .of ("pm:kind" , kind , "pm:kindDetail" , kindDetail ));
276+ var computedTags = makeTagMap (kind , kindDetail , population , populationFallback );
277+ var sf2 = new Matcher .SourceFeatureWithComputedTags (sf , computedTags );
258278 var zoomMatches = zoomsIndex .getMatches (sf2 );
259279
280+ // Use populationFallback for sorting if no real population
281+ if (population == 0 && populationFallback > 0 ) {
282+ population = populationFallback ;
283+ }
284+
260285 minZoom = getInteger (sf2 , zoomMatches , "pm:minzoom" , 99 );
261286 maxZoom = getInteger (sf2 , zoomMatches , "pm:maxzoom" , 99 );
262287 kindRank = getInteger (sf2 , zoomMatches , "pm:kindRank" , 99 );
@@ -345,11 +370,25 @@ public void processOverture(SourceFeature sf, FeatureCollector features) {
345370 return ;
346371 }
347372
373+ // Extract population (if available)
374+ Integer population = 0 ;
375+ if (sf .hasTag ("population" )) {
376+ Object popValue = sf .getTag ("population" );
377+ if (popValue instanceof Number number ) {
378+ population = number .intValue ();
379+ }
380+ }
381+
382+ // Overture always uses populationFallback for zoom calculations to get consistent behavior
383+ // This ensures Overture places get the higher minzoom levels (8 for city, 9 for town, etc)
384+ Integer populationFallback = 1 ; // Marker value to trigger fallback zoom levels
385+
348386 Integer minZoom ;
349387 Integer maxZoom ;
350388 Integer kindRank ;
351389
352- var sf2 = new Matcher .SourceFeatureWithComputedTags (sf , Map .of ("pm:kind" , kind , "pm:kindDetail" , kindDetail ));
390+ var computedTags = makeTagMap (kind , kindDetail , population , populationFallback );
391+ var sf2 = new Matcher .SourceFeatureWithComputedTags (sf , computedTags );
353392 var zoomMatches = zoomsIndex .getMatches (sf2 );
354393
355394 minZoom = getInteger (sf2 , zoomMatches , "pm:minzoom" , 99 );
@@ -359,15 +398,6 @@ public void processOverture(SourceFeature sf, FeatureCollector features) {
359398 // Extract name
360399 String name = sf .getString ("names.primary" );
361400
362- // Extract population (if available)
363- Integer population = 0 ;
364- if (sf .hasTag ("population" )) {
365- Object popValue = sf .getTag ("population" );
366- if (popValue instanceof Number number ) {
367- population = number .intValue ();
368- }
369- }
370-
371401 int populationRank = 0 ;
372402
373403 for (int i = 0 ; i < popBreaks .length ; i ++) {
0 commit comments