geoserversld

SLD Geometry function 'area' returns different values at each zoom level


I'm using an SLD to label polygons with the derived area (cartesian) using the area function.

I would expect that the area of the polygon would remain consistent - the polygon isn't changing size, but I'm finding that the area value changes at each zoom level.

Am I misunderstanding what the area function should do? Any advice welcome.

Screenshots:

The SLD:

<?xml version="1.0" encoding="UTF-8"?>
<sld:StyledLayerDescriptor xmlns="http://www.opengis.net/sld" xmlns:sld="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml" version="1.0.0">
  <sld:NamedLayer>
    <sld:Name>Default Styler</sld:Name>
    <sld:UserStyle>
      <sld:Name>Default Styler</sld:Name>
      <sld:FeatureTypeStyle>
        <sld:Name>name</sld:Name>
        <sld:Rule>
          <sld:Title/>
          <sld:MinScaleDenominator>423.0</sld:MinScaleDenominator>
          <sld:MaxScaleDenominator>4.43744032E8</sld:MaxScaleDenominator>
          <sld:PolygonSymbolizer>
            <sld:Fill>
              <sld:GraphicFill>
                <sld:Graphic>
                  <sld:Mark>
                    <sld:WellKnownName>shape://none</sld:WellKnownName>
                    <sld:Fill/>
                    <sld:Stroke>
                      <sld:CssParameter name="stroke">#ff5722</sld:CssParameter>
                    </sld:Stroke>
                  </sld:Mark>
                  <sld:Size>8</sld:Size>
                </sld:Graphic>
              </sld:GraphicFill>
              <sld:CssParameter name="fill">#ff5722</sld:CssParameter>
            </sld:Fill>
          </sld:PolygonSymbolizer>
          <sld:PolygonSymbolizer>
            <sld:Stroke>
              <sld:CssParameter name="stroke">#ff5722</sld:CssParameter>
              <sld:CssParameter name="stroke-width">0</sld:CssParameter>
            </sld:Stroke>
          </sld:PolygonSymbolizer>
          <sld:TextSymbolizer>
            <sld:Label>
              <ogc:Function name="Area">
                <ogc:PropertyName>the_geom</ogc:PropertyName>
              </ogc:Function>
            </sld:Label>
            <sld:Font>
              <sld:CssParameter name="font-family">Tahoma</sld:CssParameter>
              <sld:CssParameter name="font-size">12</sld:CssParameter>
              <sld:CssParameter name="font-style">Normal</sld:CssParameter>
              <sld:CssParameter name="font-weight">Normal</sld:CssParameter>
            </sld:Font>
            <sld:LabelPlacement>
              <sld:PointPlacement>
                <sld:AnchorPoint>
                  <sld:AnchorPointX>0.5</sld:AnchorPointX>
                  <sld:AnchorPointY>0.5</sld:AnchorPointY>
                </sld:AnchorPoint>
              </sld:PointPlacement>
            </sld:LabelPlacement>
            <sld:Halo>
              <sld:Radius>3</sld:Radius>
              <sld:Fill>
                <sld:CssParameter name="fill">#EEEEEE</sld:CssParameter>
              </sld:Fill>
            </sld:Halo>
            <sld:Fill>
              <sld:CssParameter name="fill">#000000</sld:CssParameter>
            </sld:Fill>
            <sld:VendorOption name="spaceAround">25</sld:VendorOption>
            <sld:VendorOption name="group">no</sld:VendorOption>
          </sld:TextSymbolizer>
        </sld:Rule>
      </sld:FeatureTypeStyle>
    </sld:UserStyle>
  </sld:NamedLayer>
</sld:StyledLayerDescriptor>

Solution

  • As this answer on the sister GIS site says:

    geometries are generalized, reprojected, rescaled to screen in place for performance reasons, by the time this function is evaluated it's too late. The code would have to be modified to perform these evaluations before the geometry is modified. It's possible, not immediate to do in general (if done, it would have to affect evaluation of all style properties that might be using the geometry, not just the labels), especially if the same geometry is used by other symbolizers before.

    So the only way to do this is to precalculate the areas and store them in the dataset, this will also be more efficient as it saves recalculating the areas with each map move.