mapbox / carto

fast CSS-like map stylesheets
https://cartocss.readthedocs.io/
Apache License 2.0
654 stars 129 forks source link

Zoom level inheritance #175

Open rundel opened 12 years ago

rundel commented 12 years ago

I've been playing around with a simplified version of the fontset-duplication.mss test and I noticed something about how zoom level inheritance is being handled by carto. Specifically, it appears that if child rules define zoom levels that inclue either the min or max zoom level then the parent rule has its zoom level range truncated, it is not clear to me if this is intended behavior or not.

My results are based on the following minimal mss:

#country-label[zoom>1][zoom<6]{
  text-face-name: "Franklin Gothic FS Book","DejaVu Sans Book";
  text-name:"''";
  text-size:6;
  [zoom=2] {
    text-size:8;
  }
  [zoom=3] {
    text-size:9;
  }
  [zoom=4] {
    text-size:11;
  }
  [zoom=5] {
    text-size:12;
  }
}

Based on this mss the parent rule should be defined on zoom levels 2 through 5 which corresponds to <MinScaleDenominator>12500000</MinScaleDenominator> and <MaxScaleDenominator>200000000</MaxScaleDenominator> in the xml output.

If I comment out the child rule with zoom level 2, the relevant xml output looks like:

  <Rule>
    <MaxScaleDenominator>200000000</MaxScaleDenominator>
    <MinScaleDenominator>100000000</MinScaleDenominator>
    <TextSymbolizer fontset-name="fontset-0" size="6" ><![CDATA['']]></TextSymbolizer>
  </Rule>

which corresponds to just zoom level 2.

Similarly, commenting out the child rule with zoom level 5 results in the range for zoom level 5

  <Rule>
    <MaxScaleDenominator>25000000</MaxScaleDenominator>
    <MinScaleDenominator>12500000</MinScaleDenominator>
    <TextSymbolizer fontset-name="fontset-0" size="6" ><![CDATA['']]></TextSymbolizer>
  </Rule>

Finally, if the I comment out both child rules at zoom level 2 and 5, the output returns a rule with a range that covers zoom levels 2 through 5.

  <Rule>
    <MaxScaleDenominator>200000000</MaxScaleDenominator>
    <MinScaleDenominator>12500000</MinScaleDenominator>
    <TextSymbolizer fontset-name="fontset-0" size="6" ><![CDATA['']]></TextSymbolizer>
  </Rule>
kkaefer commented 12 years ago

I think this is correct behavior. Since you can't override Symbolizers, we have to generate a symbolizer for every unique combination of properties. In this case, there should always be four rules, even if you comment out a child rule (in that case, the parent rule gets reduced to just one zoom level).

rundel commented 12 years ago

In that case shouldn't the third example alter the parent rule such that it is defined just for zoom level 2 and zoom level 5? Currently there is no way to translate this to mapnik xml without duplicating the rule so it seems kludgy but this seems like it would be the ideal behavior.

kkaefer commented 12 years ago

Yeah, ideally. However, Carto uses filter-mode="first" and reorders the rules so that more specific rules are matched before less specific rules in those cases. This is just how Carto deals with this so that Carto doesn't have to create duplicates of these rules.

rundel commented 12 years ago

I'm not completely up to speed on how styles are processed and how the filter-mode is handled since there doesn't seem to be any documentation. From a brief survey of the code in feature_style_processor_impl.hpp it seems like if you are using filter-mode="first" then the processor walks through the if rules in the style until it finds the first if rule where the filter evaluates to true.

As such, if the child rules appear before the parent rule then it shouldn't matter if we truncate the zoom levels or not when using filter-mode="first" since the style processor should never get that far. Is there some case that I am missing?