Map/Style documentation

27 views
Skip to first unread message

jericks

unread,
Oct 9, 2010, 7:57:12 PM10/9/10
to GeoScript
Hi all!

I finally got the documentation monkey off my back. I just commited
map/style documentation to the learning and examples sections of the
web site. I only did Groovy examples. As always I am open to
feedback.

Jared

Justin Deoliveira

unread,
Oct 12, 2010, 8:48:28 AM10/12/10
to geos...@googlegroups.com
Nice work Jared!

I think the content is great. I do perhaps think that some it is more suitable to api or reference docs. I see the learning section as sort of a story like introduction to key concepts. And examples I would like to see more "use case" oriented. A format i kind of like is the geoserver sld cookbook [1]

That said this is really great. I think it needs a bit of tweaking but not much. I will try to pair up the docs for python soon and hopefully then will have some more concrete feedback for you. Hopefully the rest of us slackers can catch up soon :)


--
You received this message because you are subscribed to the GeoScript mailing list.
To post to this group, send email to geos...@googlegroups.com
To unsubscribe from this group, send email to geoscript+...@googlegroups.com
Visit this group at http://groups.google.com/group/geoscript or see http://geoscript.org



--
Justin Deoliveira
Enterprise support for open source geospatial.

Tim Schaub

unread,
Oct 12, 2010, 3:15:49 PM10/12/10
to geos...@googlegroups.com
Nice work Jared.

I just tossed in the JavaScript map examples in the learning section.

http://github.com/tschaub/geoscript.org/commit/dda1e708394d3ace92783c0ecc185e7b481b2fe8

I agree with Justin that we should better define the purpose of the
narrative docs (as compared to API docs). Perhaps we can come up with a
nice outline. The purpose of examples & learning pages are a bit cloudy
in my mind right now.

I also wonder if we should discuss a bit more the Map API. I think we
came to a good place with Style (and Rule & symbolizers are pretty easy).

Perhaps we don't need better alignment, but in the JS implementation, a
map is a simple collection of layers. As with the other GeoScript
collections (workspace, layer, schema), it's got add and (soon) remove
methods.

The map render method takes (among other things) width, height, and
projection. Perhaps it's pedantic, but size feels more like a rendering
option to me (rather than a map property). Projection and bounds are
derived from the first layer added if not provided to render.

Anyway, if we don't want perfect alignment on the API, then I think the
example narrative shouldn't be specific with regard to property and
method names (these can be in the API docs). If the examples are goal
oriented, then the narrative can set up the goal and the code can
demonstrate the syntax.

I'll put more code into the examples as time allows, but wanted to hear
a bit more discussion first.

Tim

Jared Erickson

unread,
Oct 12, 2010, 11:10:57 PM10/12/10
to geos...@googlegroups.com
Thanks Justin and Tim,

Justin, I agree that the SLD cookbook is awesome.  I used it a lot while working on these modules.  I have 3 scripts in my examples directory that implement the cookbook examples in GeoScript.  This proved very useful when fleshing out the api.


Tim,  the Groovy GeoScript Map class is pretty simple.  It has properties for width, height, imageType, backgroundColor, fixAspectRatio, and layers.   Overall I find myself liking Groovy as a language but my biggest frustration so far is a lack of named parameters.  Code like this:

def map = new Map(width: 600, height: 400, fixAspectRatio: true)

is actually handled by Groovy creating a constructor that takes a HashMap of parameters and then applying them to properties (getters and setters are automatically generated).  The render method should have good defaults (width =  400, imageType=png, ect...) and I couldn't figure out a good way to do this in Groovy without named parameters and default values(I have Python/Scala envy here), so I moved all parameters out of render (except the OutputStream or File).  This ends up being pretty close to the GeoTools DefaultMapContext.


I followed your lead and picked up the Projection from the Bounds or the first Layer.  I am looking forward to the discussion.  We are very close and I would love to see further alignment.  The Mapnik Python API is another good place to look.

Also, I added color brewer support to the Style module (getPaletteNames(String type) and getPaletteColors(name, count))along with createGraduatedStyle() and createUniqueValuesStyle() methods for thematic mapping.

Thanks again,
Jared

David Winslow

unread,
Oct 15, 2010, 6:39:23 AM10/15/10
to geos...@googlegroups.com
On Wed, Oct 13, 2010 at 5:10 AM, Jared Erickson <jared.e...@gmail.com> wrote:
The render method should have good defaults (width =  400, imageType=png, ect...) and I couldn't figure out a good way to do this in Groovy without named parameters and default values(I have Python/Scala envy here), so I moved all parameters out of render (except the OutputStream or File).

A common pattern for default parameters in JavaScript (where named parameters are also emulated by a hash with string keys) is to create a map with default values and overwrite it with whichever parameters are provided:

(Scala since I don't know how maps look in Groovy):

class Map {
  private val defaults = immutable.Map("width" -> "300", "height" -> 300)

  def render(providedParams: collection.Map[String, String]) = {
     val params = defaults ++ providedParams
     ... do stuff with params here 
    } 
 }

Maybe this can serve as an inspiration for the Groovy version.

--
David Winslow

David Winslow

unread,
Oct 15, 2010, 9:47:58 AM10/15/10
to geos...@googlegroups.com
Hey guys, I've been looking over the style API docs, and I have a small suggestion.

Right now a Style is a container of Rules which are containers of Symbolizers.  I think it would be more convenient and "scripty" to make Symbolizers themselves styles which can be composed with other styles if you want multiple styles, or annotated with restrictions if desired.  Also, I think it would be a big win to drop the "stroke" prefix from LineSymbolizer properties (and "fill" from PolygonSymbolizer, etc.)  For example, calls like 
new LineSymbolizer(strokeColor:"red", strokeWidth:3)
would go to 
new LineSymbolizer(color:"red", width:"3")

Here's what a Scala style API implementing both ideas might look like (based on the Groovy examples from the site sources, in order):

var styles = collection.mutable.Buffer[Style]()
styles +=
  Stroke(color="#000000", width=3)
styles +=  
  Stroke(color="#333333", width=5, linecap="round", z=0) and
  Stroke(color="#6699FF", width=3, linecap="round", z=1)
styles +=
  Stroke(color="#000000", width=3) when ("type='local-road'")
styles +=
  Stroke(color="#000000", width=3) when (ScaleBetween(1.8e9, 3.6e9))

Here "and" is a Style method which composes two styles, and "when" is a Style method which adds a constraint.  ("when" might be overloaded to accept Strings (interpreted as CQL) and ScaleBetween's or something, specifics are up for debate).

--
David Winslow

Tim Schaub

unread,
Oct 15, 2010, 4:24:22 PM10/15/10
to geos...@googlegroups.com
On 10/15/10 7:47 AM, David Winslow wrote:
> Hey guys, I've been looking over the style API docs, and I have a small
> suggestion.
>
> Right now a Style is a container of Rules which are containers of
> Symbolizers. I think it would be more convenient and "scripty" to make
> Symbolizers themselves styles which can be composed with other styles if
> you want multiple styles, or annotated with restrictions if desired.

What is the layer property called in this case? I assume styles.

> Also, I think it would be a big win to drop the "stroke" prefix from
> LineSymbolizer properties (and "fill" from PolygonSymbolizer, etc.) For
> example, calls like
>
> new LineSymbolizer(strokeColor:"red", strokeWidth:3)
>
> would go to
>
> new LineSymbolizer(color:"red", width:"3")
>

For clarification, you are proposing "color" mean "strokeColor" for
LineSymbolizer and "fillColor" for PolygonSymbolizer? Then we still
have "strokeColor" for PolygonSymbolizer. And both "strokeColor" and
"fillColor" for PointSymbolizer.

I'm somewhat partial to the consistency we currently have (but for me,
scripting is not about typing fewer characters).

>
> Here's what a Scala style API implementing both ideas might look like
> (based on the Groovy examples from the site sources, in order):
>
> var styles = collection.mutable.Buffer[Style]()
>
> styles +=
>
> Stroke(color="#000000", width=3)
>
> styles +=
>
> Stroke(color="#333333", width=5, linecap="round", z=0) and
>
> Stroke(color="#6699FF", width=3, linecap="round", z=1)
>
> styles +=
>
> Stroke(color="#000000", width=3) when ("type='local-road'")
>
> styles +=
>
> Stroke(color="#000000", width=3) when (ScaleBetween(1.8e9, 3.6e9))
>

This is what I currently write (ommitting cap for brevity):

layer.style = [{
symbolizers: [{strokeColor: "#000000", strokeWidth: 3}]
}, {
symbolizers: [
{strokeColor: "#333333", strokeWidth: 5, zIndex: 0},
{strokeColor: "#6699FF", strokeWidth: 3, zIndex: 1}
]
}, {
symbolizers: [{strokeColor: "#000000", strokeWidth: 3}],
filter: "type='local-road'"
}, {
symbolizers: [{strokeColor: "#000000", strokeWidth: 3}],
minScaleDenominator: 1.8e9,
maxScaleDenominator: 3.6e9
}];

With your proposal, I think this is what I'd write:

layer.style = [

new Stroke({color: "#000000", width: 3}),

new Stroke({color: "#333333", width: 5, zIndex: 0})
.and({color: "#6699FF", width: 3, zIndex: 1}),

new Stroke({color: "#000000", width: 3})
.where("type='local-road'"),

new Stroke({color: "#000000", width: 3})
.range({min: 1.8e9, max: 3.6e9})

];

I like it. This does bring up some questions for me though.

var foo =
new Stroke({color: "fuchsia", width: 10, zIndex: 0})
.and({color: "navy", width: 5, zIndex: 1});

assert(foo instanceof Stroke);
assert(foo.color === "no idea");

Tim

David Winslow

unread,
Oct 15, 2010, 6:56:40 PM10/15/10
to geoscript
On Fri, Oct 15, 2010 at 10:24 PM, Tim Schaub <tim.s...@gmail.com> wrote:
On 10/15/10 7:47 AM, David Winslow wrote:
Hey guys, I've been looking over the style API docs, and I have a small
suggestion.

Right now a Style is a container of Rules which are containers of
Symbolizers.  I think it would be more convenient and "scripty" to make
Symbolizers themselves styles which can be composed with other styles if
you want multiple styles, or annotated with restrictions if desired.

What is the layer property called in this case?  I assume styles.

Either "style" or "styles" would be appropriate; "style" would be slightly better as a bunch of styles joined together with "and"s would join together to form a single composite style.

 Also, I think it would be a big win to drop the "stroke" prefix from
LineSymbolizer properties (and "fill" from PolygonSymbolizer, etc.)  For
example, calls like

   new LineSymbolizer(strokeColor:"red", strokeWidth:3)

would go to

   new LineSymbolizer(color:"red", width:"3")


For clarification, you are proposing "color" mean "strokeColor" for LineSymbolizer and "fillColor" for PolygonSymbolizer?  Then we still have "strokeColor" for PolygonSymbolizer.  And both "strokeColor" and "fillColor" for PointSymbolizer.
 
I don't see a PolygonSymbolizer with "stroke" and "fill" as somehow more useful than a Fill combined with a Stroke.  Eliminating stroke parameters from PolygonSymbolizers was, I suppose, implicit in my original proposal (I have done this in the GeoServer CSS extension without any apparent repercussions, but I am quite ready to admit that that code has very few users.)

Is 

Fill(color:blue) and Stroke(color: red)

better than 

Fill(fillcolor: blue, strokecolor:red)

??
This looks right to me, assuming that layer.style has a setter which automatically composes styles.  Otherwise, I'd expect a org.geoscript.style.compose() call in there somewhere.
  
I like it.  This does bring up some questions for me though.

   var foo =
       new Stroke({color: "fuchsia", width: 10, zIndex: 0})
           .and({color: "navy", width: 5, zIndex: 1});

   assert(foo instanceof Stroke);

I would expect this assertion to fail, as the result of a .and operation would be a CompositeStyle or something instead of a Stroke.

   assert(foo.color === "no idea");

Similarly, CompositeStyles don't have a color of their own; instead, they contain styles which might contain colors (or might themselves be composites of other styles.)

Tim Schaub

unread,
Oct 15, 2010, 7:41:17 PM10/15/10
to geos...@googlegroups.com

I consistently read Stroke as LineSymbolizer somehow in your previous
email. Seeing that you are indeed talking about creating separate
stroke and fill constructors, I agree the name "color" makes sense.

>
> With your proposal, I think this is what I'd write:
>
> layer.style = [
>
> new Stroke({color: "#000000", width: 3}),
>
> new Stroke({color: "#333333", width: 5, zIndex: 0})
> .and({color: "#6699FF", width: 3, zIndex: 1}),
>
> new Stroke({color: "#000000", width: 3})
> .where("type='local-road'"),
>
> new Stroke({color: "#000000", width: 3})
> .range({min: 1.8e9, max: 3.6e9})
>
> ];
>
>

Indeed what I was thinking I was typing above was LineSymbolizer (or
some shorthand for it) instead of Stroke.

> This looks right to me, assuming that layer.style has a setter which
> automatically composes styles. Otherwise, I'd expect a
> org.geoscript.style.compose() call in there somewhere.
>
> I like it. This does bring up some questions for me though.
>
> var foo =
> new Stroke({color: "fuchsia", width: 10, zIndex: 0})
> .and({color: "navy", width: 5, zIndex: 1});
>
> assert(foo instanceof Stroke);
>
>
> I would expect this assertion to fail, as the result of a

> *.and* operation would be a CompositeStyle or something instead of a Stroke.


>
> assert(foo.color === "no idea");
>
>
> Similarly, CompositeStyles don't have a color of their own; instead,

> they /contain/ styles which /might/ contain colors (or might themselves


> be composites of other styles.)
>

Ok, CompositeStyle is new. It would probably help to list the
constructors you are suggesting.

(I like the way this is going.)

Tim

>
> Tim
>
>
> Here "and" is a Style method which composes two styles, and
> "when" is a
> Style method which adds a constraint. ("when" might be
> overloaded to
> accept Strings (interpreted as CQL) and ScaleBetween's or something,
> specifics are up for debate).
>
> --
> David Winslow
> OpenGeo - http://opengeo.org/
>
> On Fri, Oct 15, 2010 at 12:39 PM, David Winslow
> <cdwi...@gmail.com <mailto:cdwi...@gmail.com>

> <mailto:cdwi...@gmail.com <mailto:cdwi...@gmail.com>>> wrote:
>
> On Wed, Oct 13, 2010 at 5:10 AM, Jared Erickson
> <jared.e...@gmail.com <mailto:jared.e...@gmail.com>

> <mailto:jared.e...@gmail.com

> <mailto:geos...@googlegroups.com>


> To unsubscribe from this group, send email to
> geoscript+...@googlegroups.com

> <mailto:geoscript%2Bunsu...@googlegroups.com>


> Visit this group at http://groups.google.com/group/geoscript or see
> http://geoscript.org
>
>
> --
> You received this message because you are subscribed to the
> GeoScript mailing list.
> To post to this group, send email to geos...@googlegroups.com

> <mailto:geos...@googlegroups.com>


> To unsubscribe from this group, send email to
> geoscript+...@googlegroups.com

> <mailto:geoscript%2Bunsu...@googlegroups.com>

David Winslow

unread,
Oct 16, 2010, 2:32:03 AM10/16/10
to geos...@googlegroups.com
So far:

Stuff I included in my code samples without discussing:
  • LineSymbolizer's are dumb, Stroke's are where it's at.
  • PolygonSymbolizer's are dumb, Fill's are where it's at.  Fill's only do Fill stuff, no stroking.  Use composites (see below) if you want to fill and outline stuff.
Stuff I have (at least tried to) explain so far:
  • Strokes and Fills are complete styles on their own, suitable for attaching to a layer and mapmaking.
  • Every style has an "and" method which takes another style (simple or composite) and composes the two styles, SLD-painter's-model-wise.  This produces a new style whose type is an implementation detail.
  • Every style has a "when" or "where" or "range" method which takes constraints on data or scale and produces a new style which does the same thing, but only when those constraints are met.
Corollary: 
  • This code might work (composites themselves have when's and and's): 
    • ((Stroke("blue") when ("type='river'")) and (Stroke("orange",z=-1) when ("contamination='nuclear'")) when (ScaleAbove(1.8e7))

I will (hopefully this weekend) write some code and get things working, then present a summary on this list.

-d

David Winslow

unread,
Oct 16, 2010, 4:55:21 PM10/16/10
to geos...@googlegroups.com
Ok, I spent a good chunk of today laying out the groundwork and then getting sucked into fleshing out a lot of the details, so here's a mostly functional (aside from titles and abstracts) implementation of the Style API I had in mind.  (I mean functional in the sense that it works, but it is also 100% immutable for what that's worth.)

Top level interfaces:
  • Style - Styles can be attached to Layers and passed to a Viewport to draw spatial data on maps.
    • where(Filter): Style - Produce a new Style which restricts its drawing to a subset of features based on their attributes.  Only features which are accepted by the Filter will be drawn.  There is an implicit conversion from String to Filter which interprets the String as an ECQL expression.
    • aboveScale(Double): Style - Produce a new Style which only draws features when the Map's scale denominator is above the provided value.
    • belowScale(Double): Style - Produce a new Style which only draws features when the Map's scale denominator is below the provided value.
    • and(Style): Style - Create a new Style whose effect is approximately the same as rendering this Style, followed by the Style passed as an argument.  The difference lies in the handling of zIndex properties (see SimpleStyle below).  zIndex is only respected within an And'ed style.
    • underlying: org.geotools.styling.Style - A GeoTools Style instance corresponding to this Style.
  • Paint - A Paint provides the actual pixels to use when actualizing a Stroke or Fill.  End-users will likely be more interested in the concrete implementations Color, Symbol, and Graphic.  There is an implicit conversion from String to Filter which interprets the String as a CSS/SVG color name, or else as a hexadecimal RGB color specification.
  • SimpleStyle - A Style which is "flat;" forming the leaves in the tree produced by and'ing Styles together.  This (abstract) class is mostly an implementation detail, end-users will likely be more interested in the concrete implementations Stroke, Fill, Label, Symbol, and Graphic.
    • filter: Option[Filter] - If there are attribute constraints on this Style, this property will be a Some[Filter] containing those constraints.  Otherwise, it is None.
    • minScale: Option[Double] - If there is a minimum scale denominator constraint on this Style, this property will be a Some[Double] containing the minimum allowable scale value. Otherwise, it is None.
    • maxScale: Option[Double] - If there is a maximum scale denominator constraint on this Style, this property will be a Some[Double] containing the maximum allowable scale value.  Otherwise, it is None.
    • symbolizers: Seq[org.geotools.styling.Symbolizer] - This property produces a collection of the GeoTools symbolizers which this Style contributes to the rendering.
    • zIndex: Double - This property is used to sort styles before rendering; higher values are rendered later using the painter's model ("on top" of Styles with lower-valued z-indices).
    • (also inherits all Style methods)
  • CompositeStyle - A Style which combines other Styles such that they can be treated as a single Style.  If SimpleStyles are leaves in a tree, CompositeStyles are the internal nodes.  This class is mostly an implementation detail, end-users are encouraged to use Style#and instead of instantiating CompositeStyles directly.
    • flatten: Seq[SimpleStyle] - A Seq containing all the SimpleStyles in this CompositeStyle in the order they were added.
    • (also inherits all Style methods)
  • Fill(fill: Paint, opacity: Expression, zIndex: Double) - A Style which fills in polygons.  (Multi)LineStrings will be coerced into Polygons by adding a segment between the first and last vertices, and then filled in.  Point geometries are not drawn.
  • Stroke(stroke: Paint, width: Expression, opacity: Expression, linecap: Expression, linejoin: Expression, dashoffset: Expression, dasharray: Seq[Float], zIndex: Double, mode: Stroke.Mode) - A Style which strokes lines and polygon edges.  Point geometries are not drawn.
  • Label(text: Expression, geometry: Expression) - A Style which annotates the map with text, possibly derived from a property of the data.  (Note: zIndex has no effect on Label's; the text is always rendered on top of any other map elements.)
  • Symbol(shape: Expression, fill: Fill, stroke: Stroke, size: Expression, rotation: Expression, opacity: Expression, zIndex: Double) - A Symbol can be used as Paint in Fill's or Stroke's, or as a Style which draws the described Symbol as a point marker.  For Line and Polygon geometries a marker will be placed at an appropriate but unspecified point within the geometry.
    • (inherits all Style methods, plus all Paint methods, plus provides a copy() method)
  • Graphic(url: String, size: Expression, rotation: Expression, zIndex: Double) - A Graphic can be used as Paint in Fill's or Stroke's, or as a Style which draws an image from a file or http URL as a point marker.  The URL may contain embedded CQL expressions.  For Line and Polygon geometries a marker will be placed at an appropriate but unspecified point within the geometry.
    • (inherits all Style methods, plus all Paint methods, plus provides a copy() method)
There is a sample script rendering the states shapefile we all know and love in the examples subproject:

I also took care to commit frequently once I had the groundwork laid, so reviewing the commit history may be informative.

-d

Tim Schaub

unread,
Oct 16, 2010, 5:40:51 PM10/16/10
to geos...@googlegroups.com
Nice!

I look forward to finding time to implement this and see how it feels.

I'm tempted to use Brush instead of Paint. And I think below you mean
that Fill and Stroke are constructed with "color" (instead of "fill"
and "stroke"). And the implicit conversion is from String to Paint
(or Brush). Not meaning to nitpick, but these were things that
confused me on first read, so I'm just clarifying.

Tim Schaub

unread,
Oct 16, 2010, 5:46:44 PM10/16/10
to geos...@googlegroups.com
One question that ditching LineSymbolizer and PolygonSymbolizer brings
up - given a layer with multiple geometry types, you can no longer
stroke the lines and the polygons differently, right?

David Winslow

unread,
Oct 16, 2010, 7:10:10 PM10/16/10
to geos...@googlegroups.com
I named the paint properties for Fill and Stroke, fill and stroke respectively.  This is because

Fill(color=Graphic("pattern.png"))

sounds a bit awkward to me.

I don't feel strongly about Brush vs. Paint.  I suppose Brush has been popularized by Photoshop and its ilk, so we can go with that.

The note about implicit conversions from String to Filter should have said String to Paint.  Guess it's time to move those docs over to version control.  (I may have been thinking about how Color should really be constructed with an Expression...)

As for multiple geometry types - is that how things are handled now?  I was under the impression that a LineSymbolizer and a PolygonSymbolizer with no Fill's were 100% equivalent (ie, in your style with a LineSymbolizer and a PolygonSymbolizer, lines and polygons would both get filled once and stroked twice).  On the other hand, there is a CQL function for identifying the type of a geometry, so you could do something like:

(Stroke("blue") when "geometryType(the_geom) = 'Polygon'") and 
(Stroke("red") when "geometryType(the_geom) = 'Line'")

I will try to put together a translation of the SLD Cookbook soon, so we can see how things look in a wider variety of scenarios.

-d

Tim Schaub

unread,
Oct 17, 2010, 1:25:03 PM10/17/10
to geos...@googlegroups.com
On Sat, Oct 16, 2010 at 5:10 PM, David Winslow <cdwi...@gmail.com> wrote:
> I named the paint properties for Fill and Stroke, fill and stroke
> respectively.  This is because
>>
>> Fill(color=Graphic("pattern.png"))

Yeah, I hit send too soon. Makes sense.

>
> sounds a bit awkward to me.
> I don't feel strongly about Brush vs. Paint.  I suppose Brush has been
> popularized by Photoshop and its ilk, so we can go with that.
> The note about implicit conversions from String to Filter should have said
> String to Paint.  Guess it's time to move those docs over to version
> control.  (I may have been thinking about how Color should really be
> constructed with an Expression...)
> As for multiple geometry types - is that how things are handled now?  I was
> under the impression that a LineSymbolizer and a PolygonSymbolizer with no
> Fill's were 100% equivalent (ie, in your style with a LineSymbolizer and a
> PolygonSymbolizer, lines and polygons would both get filled once and stroked
> twice).  On the other hand, there is a CQL function for identifying the type
> of a geometry, so you could do something like:

I see that GeoTools is pretty liberal in how it applies a
PolygonSymbolizer. The spec reads that it "is used draw a polygon (or
other area-type geometries)." This would lead me to believe that you
could use a PolygonSymbolizer and LineSymbolizer to stroke geometries
differently depending on their type.

In any case, I'd be tempted to add a property to Stroke that specified
whether it applied to polygons, lines, or both (default). The CQL
below is clever, but it makes round-tripping SLD a bit more awkward
(not to mention writing CQL to capture the different geometry type
names - in GML at least - that all represent polygons).

Thanks for the responses.

David Winslow

unread,
Oct 24, 2010, 10:57:55 PM10/24/10
to geos...@googlegroups.com
On Sun, Oct 17, 2010 at 1:25 PM, Tim Schaub <tim.s...@gmail.com> wrote:
On Sat, Oct 16, 2010 at 5:10 PM, David Winslow <cdwi...@gmail.com> wrote:
> I named the paint properties for Fill and Stroke, fill and stroke
> respectively.  This is because
>>
>> Fill(color=Graphic("pattern.png"))

Yeah, I hit send too soon.  Makes sense.

>
> sounds a bit awkward to me.
> I don't feel strongly about Brush vs. Paint.  I suppose Brush has been
> popularized by Photoshop and its ilk, so we can go with that.
> The note about implicit conversions from String to Filter should have said
> String to Paint.  Guess it's time to move those docs over to version
> control.  (I may have been thinking about how Color should really be
> constructed with an Expression...)
> As for multiple geometry types - is that how things are handled now?  I was
> under the impression that a LineSymbolizer and a PolygonSymbolizer with no
> Fill's were 100% equivalent (ie, in your style with a LineSymbolizer and a
> PolygonSymbolizer, lines and polygons would both get filled once and stroked
> twice).  On the other hand, there is a CQL function for identifying the type
> of a geometry, so you could do something like:

I see that GeoTools is pretty liberal in how it applies a
PolygonSymbolizer.  The spec reads that it "is used draw a polygon (or
other area-type geometries)."  This would lead me to believe that you
could use a PolygonSymbolizer and LineSymbolizer to stroke geometries
differently depending on their type.
 
I guess you're referring to section 11.2 of the SLD 1.0 spec here.  If you keep reading (bottom of p38 and on through the next page) you'll see that the spec outlines rules for converting points, lines, and even raster data to polygons for use with PolygonSymbolizers, using "should" throughout, which I suppose means a compliant implementation *could* restrict PolygonSymbolizers to only render polygon geometries, but I wouldn't call GeoTools's behavior "liberal."

In any case, I'd be tempted to add a property to Stroke that specified
whether it applied to polygons, lines, or both (default).  The CQL
below is clever, but it makes round-tripping SLD a bit more awkward
(not to mention writing CQL to capture the different geometry type
names - in GML at least - that all represent polygons).

How is CQL more awkward to round-trip than whatever property you're thinking of?  I'm not sure where you're going with it, but afaict there's no way to encode it in SLD at all, which would make round-tripping pretty difficult.  Personally, I'd be willing to just drop the issue; we would not be providing any less functionality than SLD itself.

However, to keep going with the CQL idea, we could make the CQL version less painful by providing filter function extensions which include "isPolygon", "isLine", "isPoint" tests (maybe just as complicated as the "pure" CQL version would be, but at least they would not need to be repeated for each style.)  Another simpler implementation than explicitly checking geometry types would be to test whether length or area is zero.

--
David Winslow
Reply all
Reply to author
Forward
0 new messages