Skip to content

Commit ebdf74f

Browse files
committed
Merge branch 'raster-styling' into scala-2.10
Conflicts: geocss/src/main/scala/org/geoscript/geocss/Translator.scala
2 parents 1a59f22 + 9ff23dc commit ebdf74f

File tree

1 file changed

+138
-15
lines changed

1 file changed

+138
-15
lines changed

geocss/src/main/scala/org/geoscript/geocss/Translator.scala

Lines changed: 138 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import org.geotools.styling.{
1111
LineSymbolizer,
1212
PointSymbolizer,
1313
PolygonSymbolizer,
14+
RasterSymbolizer,
1415
Symbolizer,
1516
TextSymbolizer,
1617
TextSymbolizer2,
@@ -179,12 +180,9 @@ class Translator(val baseURL: Option[java.net.URL]) {
179180
case _ => None
180181
}
181182

182-
def getZIndex(xs: Seq[Value]): Option[Double] =
183-
keyword(xs) flatMap { text =>
184-
try Some(text.toDouble)
185-
catch {
186-
case (_: NumberFormatException) => None
187-
}
183+
def getLiteralDouble(xs: Seq[Value]): Option[Double] =
184+
Some(xs) collect {
185+
case Seq(Literal(Double(z))) => z
188186
}
189187

190188
def scale(s: String): Float = {
@@ -230,10 +228,90 @@ class Translator(val baseURL: Option[java.net.URL]) {
230228
}).toArray
231229
}
232230

233-
// implicit def stringToFilter(literal: String): org.opengis.filter.Filter = {
234-
// val cql = literal.substring(1, literal.length - 1)
235-
// org.geotools.filter.text.ecql.ECQL.toFilter(cql)
236-
// }
231+
def channelSelection(xs: Seq[Value]): gt.ChannelSelection = {
232+
object Channel {
233+
def unapply(v: Value): Option[gt.SelectedChannelType] =
234+
v match {
235+
case Literal("auto") => None
236+
case Literal(text) =>
237+
Some(styles.createSelectedChannelType(
238+
text, null: gt.ContrastEnhancement))
239+
case _ => None
240+
}
241+
}
242+
243+
val channels =
244+
Some(xs) collect {
245+
case Seq(Channel(grey)) => Array(grey)
246+
case Seq(Channel(r), Channel(g), Channel(b)) => Array(r, g, b)
247+
}
248+
249+
channels.map(styles.createChannelSelection).orNull // TODO: return Option[ChannelSelection] instead.
250+
}
251+
252+
object Double {
253+
def unapply(s: String): Option[Double] =
254+
try
255+
Some(s.toDouble)
256+
catch {
257+
case (_: NumberFormatException) => None
258+
}
259+
}
260+
261+
def colorMap(rampType: Option[Int])(xs: Seq[Value]): Option[gt.ColorMap] = {
262+
def getColorMapEntry(c: OGCExpression, v: Double, o: Double) = {
263+
val e = styles.createColorMapEntry
264+
e.setColor(c)
265+
e.setQuantity(filters.literal(v))
266+
e.setOpacity(filters.literal(o))
267+
e
268+
}
269+
def getColorMap(entries: Seq[gt.ColorMapEntry]) = {
270+
val m = styles.createColorMap
271+
rampType.foreach(m.setType)
272+
entries.foreach(m.addColorMapEntry)
273+
m
274+
}
275+
def tryEntry(v: Value): Option[gt.ColorMapEntry] =
276+
Some(v) collect {
277+
case Function("color-map-entry", Seq(Color(c), Literal(Double(v)))) =>
278+
getColorMapEntry(c, v, 1)
279+
case Function("color-map-entry", Seq(Color(c), Literal(Double(v)), Literal(Double(o)))) =>
280+
getColorMapEntry(c, v, o)
281+
}
282+
283+
def sequence[A](as: Seq[Option[A]]): Option[Seq[A]] =
284+
(as foldRight (Some(Nil): Option[Seq[A]])) {
285+
(aOpt, accum) => for (a <- aOpt; res <- accum) yield a +: res
286+
}
287+
288+
sequence(xs map tryEntry).map(getColorMap)
289+
}
290+
291+
def getOverlapBehavior(xs: Seq[Value]): Option[org.opengis.style.OverlapBehavior] = {
292+
import scala.util.control.Exception.catching
293+
xs.headOption flatMap {
294+
case Literal(name) =>
295+
catching(classOf[IllegalArgumentException]).opt {
296+
org.opengis.style.OverlapBehavior.valueOf(name)
297+
}
298+
case _ => None
299+
}
300+
}
301+
302+
def getContrastMethod(xs: Seq[Value]): Option[org.opengis.style.ContrastMethod] =
303+
xs.headOption collect {
304+
case Literal("none") => org.opengis.style.ContrastMethod.NONE
305+
case Literal("normalize") => org.opengis.style.ContrastMethod.NORMALIZE
306+
case Literal("histogram") => org.opengis.style.ContrastMethod.HISTOGRAM
307+
}
308+
309+
def getColorMapType(xs: Seq[Value]): Option[Int] =
310+
xs.headOption collect {
311+
case Literal("ramp") => org.geotools.styling.ColorMap.TYPE_RAMP
312+
case Literal("intervals") => org.geotools.styling.ColorMap.TYPE_INTERVALS
313+
case Literal("values") => org.geotools.styling.ColorMap.TYPE_VALUES
314+
}
237315

238316
def valToExpression(v: Value): Option[OGCExpression] =
239317
v match {
@@ -349,7 +427,7 @@ class Translator(val baseURL: Option[java.net.URL]) {
349427
val geom =
350428
props.get("stroke-geometry") orElse props.get("geometry") flatMap expression
351429
val zIndex: Double =
352-
props.get("stroke-z-index") orElse props.get("z-index") flatMap getZIndex getOrElse(0d)
430+
props.get("stroke-z-index") orElse props.get("z-index") flatMap getLiteralDouble getOrElse(0d)
353431

354432
val graphic = buildGraphic("stroke", props, markProps)
355433

@@ -388,7 +466,7 @@ class Translator(val baseURL: Option[java.net.URL]) {
388466
val geom =
389467
props.get("fill-geometry") orElse props.get("geometry") flatMap expression
390468
val zIndex: Double =
391-
props.get("fill-z-index") orElse props.get("z-index") flatMap getZIndex getOrElse(0d)
469+
props.get("fill-z-index") orElse props.get("z-index") flatMap getLiteralDouble getOrElse(0d)
392470

393471
val graphic = buildGraphic("fill", props, markProps)
394472

@@ -413,7 +491,7 @@ class Translator(val baseURL: Option[java.net.URL]) {
413491
val geom = (props.get("mark-geometry") orElse props.get("geometry"))
414492
.flatMap(expression)
415493
val zIndex: Double =
416-
props.get("mark-z-index") orElse props.get("z-index") flatMap getZIndex getOrElse(0d)
494+
props.get("mark-z-index") orElse props.get("z-index") flatMap getLiteralDouble getOrElse(0d)
417495

418496
val graphic = buildGraphic("mark", props, markProps)
419497

@@ -437,7 +515,7 @@ class Translator(val baseURL: Option[java.net.URL]) {
437515
val geom = (props.get("label-geometry") orElse props.get("geometry"))
438516
.flatMap(expression)
439517
val zIndex: Double =
440-
props.get("label-z-index") orElse props.get("z-index") flatMap(getZIndex) getOrElse 0d
518+
props.get("label-z-index") orElse props.get("z-index") flatMap(getLiteralDouble) getOrElse 0d
441519

442520
val font = fontFamily.getOrElse(Nil).flatMap(valToExpression).map { familyName => {
443521
val fontStyle =
@@ -531,7 +609,52 @@ class Translator(val baseURL: Option[java.net.URL]) {
531609
(zIndex, sym)
532610
}
533611

534-
Seq(polySyms, lineSyms, pointSyms, textSyms).flatten
612+
val rasterSyms: Seq[(Double, RasterSymbolizer)] =
613+
(expand(properties, "raster-channels").toStream zip
614+
(Stream.from(1) map { orderedMarkRules("outline", _) })
615+
).map { case (props, outlineProps) =>
616+
val geom =
617+
(props get "raster-geometry")
618+
.orElse(props get "geometry")
619+
.flatMap(expression)
620+
val opacity =
621+
(props get "raster-opacity") flatMap expression
622+
val channels =
623+
(props get "raster-channels") map channelSelection
624+
val overlap = (props get "raster-overlap-behavior") flatMap getOverlapBehavior
625+
val colorMapType = (props get "raster-color-map-type") flatMap getColorMapType
626+
val colorMapEntries =
627+
(props get "raster-color-map") flatMap colorMap(colorMapType)
628+
val contrastMethod =
629+
(props get "raster-contrast-enhancement") flatMap getContrastMethod
630+
val gamma =
631+
(props get "raster-gamma") flatMap getLiteralDouble
632+
val relief = (null: org.geotools.styling.ShadedRelief)
633+
val outline = (null: Symbolizer)
634+
val zIndex: Double =
635+
(props get "raster-z-index")
636+
.orElse(props get "z-index")
637+
.flatMap(getLiteralDouble)
638+
.getOrElse(0d)
639+
640+
val contrastEnhancement = styles.createContrastEnhancement()
641+
contrastMethod.foreach(contrastEnhancement.setMethod)
642+
gamma.foreach(g => contrastEnhancement.setGammaValue(filters.literal(g)))
643+
644+
val sym = styles.createRasterSymbolizer(
645+
null, // This should be the geometry property, but it only accepts a string so we use setGeometry() after creation to pass an expression.
646+
opacity.orNull,
647+
channels.orNull,
648+
overlap.map(filters.literal).orNull,
649+
colorMapEntries.orNull,
650+
contrastEnhancement,
651+
relief,
652+
outline)
653+
sym.setGeometry(geom.orNull)
654+
(zIndex, sym)
655+
}
656+
657+
Seq(polySyms, lineSyms, pointSyms, textSyms, rasterSyms).flatten
535658
}
536659

537660
type StyleSheet = Seq[Rule]

0 commit comments

Comments
 (0)