NieuwlandGeo/SLDReader

Request: Symbolizer changes to improve QGIS support

richard-thomas opened this issue · 5 comments

Very good to see the addition of Mark GraphicFill Polygon Symbolizer in release 0.2.17. These give quite good support for QGIS polygon "simple fill" preset styles "horizontal" (i.e. "horline" in SLD), "FDiagonal" (i.e. "backslash" in SLD), "Cross" (i.e. "cross" in SLD). Would you consider adding support for some of the remaining "simple fill" preset styles?

QGIS simple fill polygon symbolizers

For "Vertical" ("line" in SLD) and "BDiagonal" ("slash" in SLD), adding the following additional wellknownname point symbolizer code appears to work:

case 'line':
  return new style.RegularShape({
    fill: fill,
    points: 2,
    radius: radius,
    stroke: stroke,
    rotation: rotationRadians,
  });

case 'slash':
  return new style.RegularShape({
    fill: fill,
    points: 2,
    radius: radius * Math.sqrt(2),
    angle: Math.PI / 4,
    stroke: stroke,
    rotation: rotationRadians,
  });

Although the QGIS "Diagonal X" fill (written as 'x' in SLD) sort of works, it leaves gaps, but if the sldreader 'x' was modified (similar to 'backslash') to scale up radius1 by sqrt(2) it then joins up:

case 'x':
  return new style.RegularShape({
    angle: Math.PI / 4,
    fill: fill,
    points: 4,
    radius1: radius * Math.sqrt(2),
    radius2: 0,
    stroke:
      stroke ||
      new style.Stroke({
        color: fillColor,
        width: radius / 2,
      }),
    rotation: rotationRadians,
  });

However, that highlights an issue I couldn't work out: all these "simple fill" patterns as written by QGIS have no defined StrokeWidth, but in sldreader they end up with StrokeWidth=2 which makes them all quite fat lined (and different to QGIS which uses 1 pixel). Is it possible to change the default to StrokeWidth=1? (I could not work out where this got set).

(There is also a more minor issue with pattern overlap points being slightly fainter in my tests which have stroke-opacity < 1, but I haven't looked into that in detail - and it may become more obvious if/when the StrokeWidth is reduced to 1).

For the remaining "simple fill", i.e. "Dense 1" to "Dense 7" I would think the new technique of generating a small "pattern" canvas that repeats would work, but it is less obvious how to generate the source pattern and probably would require other changes to handle the SLD name style, for example:

          <se:WellKnownName>brush://dense3</se:WellKnownName>

I've added line and slash to the wellknown symbol list. I've also modified the 'x' symbol to cover the entire square, so it can be used for hatching like in QGIS.

About the stroke width: it's equal to 1 in OpenLayers, but depending on the graphic size, it can appear to be two pixels wide if the line happens to falls between pixels. I have added several improvements to the rendering of graphic fills with marks that will probably help:

  • I'm rendering the symbols on a larger canvas and resizing it down.
  • I've turned off image smoothing on the temp canvas to keep the symbology sharp.
  • I draw the symbols slash and backslash multiple times to prevent gaps in the corners of the square pattern.

Please check if these changes improve your situation on the demo page: https://nieuwlandgeo.github.io/SLDReader/grenzen.html . Just copy-paste your own polygon SLD to test.

About brush fills: these cannot be implemented by drawing a single OpenLayers symbol in a square. I'd have to create a different code path and assemble the pattern canvas with direct pixel twiddling. I'll see if I can add this later.

I've added support for QGIS brush patterns (brush://dense1-7) as well.

I've released version 0.2.19 that contains these mark graphic fill improvements.

That looks great and a pleasant surprise to see it updated so quickly... and the "dense" brushes too - thanks :-). My initial test file looks to give a pretty close match for SLD styling in the layerswitcher (on the left) and the QGIS layer selector (on the right):

ol-sld-styler vs QGIS

Nice!

There's one thing I noticed with these patterned fills: QGIS appears to use a symbol size of 8 by default. SLDReader sticks to the default mark size of 6 pixels. If you add a Size element to the Graphic element, you can get even closer to QGIS appearance.

<se:PolygonSymbolizer>
  <se:Fill>
    <se:GraphicFill>
      <se:Graphic>
        <se:Mark>
          <se:WellKnownName>slash</se:WellKnownName>
          <se:Stroke>
            <se:SvgParameter name="stroke">#0000ff</se:SvgParameter>
          </se:Stroke>
        </se:Mark>
        <se:Size>8</se:Size> <!-- Add size element here -->
      </se:Graphic>
    </se:GraphicFill>
  </se:Fill>
</se:PolygonSymbolizer>