@@ -541,6 +541,9 @@ class Translator(val baseURL: Option[java.net.URL]) {
541
541
Seq (polySyms, lineSyms, pointSyms, textSyms).flatten
542
542
}
543
543
544
+ type StyleSheet = Seq [Rule ]
545
+ type ZIndex = Double
546
+
544
547
/**
545
548
* Convert a list of tokens (as generated by CssParser.parse) into a GeoTools
546
549
* Style object. This works by creating individual rules for every possible
@@ -550,91 +553,111 @@ class Translator(val baseURL: Option[java.net.URL]) {
550
553
* @see org.geotools.styling.SLDTransformer if you want to serialize the
551
554
* resultant Style object to an XML file
552
555
*/
553
- def css2sld (styleSheet : Seq [Rule ]): gt.Style = {
554
- val sld = styles.createStyle
555
-
556
- val rules = stableSort(styleSheet, Specificity .order _).reverse
557
-
558
- def extractTypeName (rule : Rule ): Option [String ] =
559
- flatten(And (rule.selectors)).collect {
560
- case Typename (typename) => typename
561
- } headOption
562
-
563
- def extractScaleRanges (rule : Rule ): Seq [Pair [Option [Double ], Option [Double ]]] = {
564
- val scales =
565
- flatten(And (rule.selectors))
566
- .collect {
567
- case PseudoSelector (" scale" , _, d) => d.toDouble
568
- case Not (PseudoSelector (" scale" , _, d)) => d.toDouble
569
- }
570
- .sorted
571
- .distinct
572
-
573
- val limits = None +: (scales map (Some (_))) :+ None
574
- limits zip limits.tail
575
- }
556
+ def css2sld (s : StyleSheet ): gt.Style = {
557
+ val sorted : StyleSheet = sort(s)
558
+ val byType : Seq [(Option [String ], StyleSheet )] = splitOnType(sorted)
559
+ val resolved : Seq [(Option [String ], StyleSheet )] =
560
+ for ((t, rs) <- byType) yield (t, cascading2exclusive(rs))
561
+ val withSymbolizers : Seq [(Option [String ], Seq [(ZIndex , Rule , Seq [Symbolizer ])])] =
562
+ for ((t, rs) <- resolved) yield (t, interpret(rs))
563
+ val gtRules : Seq [(Option [String ], Seq [Seq [gt.Rule ]])] =
564
+ for ((t, rs) <- withSymbolizers) yield (t, createSLDRuleLayers(rs))
565
+ val featureTypeStyles : Seq [gt.FeatureTypeStyle ] =
566
+ gtRules.flatMap(createFeatureTypeStyles)
567
+ createStyle(featureTypeStyles)
568
+ }
569
+
570
+ def sort (s : StyleSheet ): StyleSheet =
571
+ stableSort(s, (x : Rule , y : Rule ) => Specificity .order(y, x))
572
+
573
+ def splitOnType (s : StyleSheet ): Seq [(Option [String ], StyleSheet )] = {
574
+ def isForTypename (t : Option [String ])(r : Rule ): Boolean =
575
+ t.forall(name => reduce(allOf(Typename (name) +: r.selectors)) != Exclude )
576
576
577
- def isForTypename (typename : Option [String ])(rule : Rule ): Boolean =
578
- typename map { t =>
579
- reduce(allOf(Typename (t) +: rule.selectors)) != Exclude
580
- } getOrElse true
577
+ def extractTypename (r : Rule ): Option [String ] =
578
+ flatten(And (r.selectors)).collectFirst { case Typename (t) => t }
581
579
582
- def stripTypenames (rule : Rule ): Rule =
583
- rule.copy(selectors = rule .selectors map {
580
+ def stripTypenames (r : Rule ): Rule = {
581
+ val selectors0 = r .selectors. map {
584
582
case Typename (_) => Accept
585
583
case selector => selector
586
- })
587
-
588
- val typenames = (rules map extractTypeName) distinct
589
-
590
- val styleRules =
591
- for (name <- typenames) yield (name, rules filter isForTypename(name) map stripTypenames)
592
-
593
- for ((typename, overlays) <- styleRules) {
594
- val zGroups : Seq [Seq [(Double , Rule , Seq [gt.Symbolizer ])]] =
595
- for (rule <- cascading2exclusive(overlays)) yield
596
- for ((z, syms) <- groupByZ(symbolize(rule))) yield
597
- (z, rule, syms)
598
-
599
- for ((_, group) <- flattenByZ(zGroups.flatten)) {
600
- val fts = styles.createFeatureTypeStyle
601
- typename.foreach { t => fts.featureTypeNames.add(new NameImpl (t)) }
602
- for ((rule, syms) <- group if ! syms.isEmpty) {
603
- val sldRule = styles.createRule()
604
- val ranges = extractScaleRanges(rule)
605
-
606
- for (range @ (min, max) <- ranges) {
607
- val minSelector = min.map(x => PseudoSelector (" scale" , " >" , x.toString))
608
- val maxSelector = max.map(x => PseudoSelector (" scale" , " <" , x.toString))
609
- val restricted =
610
- reduce(allOf(rule.selectors ++ minSelector ++ maxSelector))
611
-
612
- if (restricted != Exclude ) {
613
- val sldRule = styles.createRule()
614
-
615
- for (m <- min) sldRule.setMinScaleDenominator(m)
616
- for (m <- max) sldRule.setMaxScaleDenominator(m)
617
- for (title <- rule.description.title)
618
- sldRule.getDescription().setTitle(title)
619
- for (abstrakt <- rule.description.abstrakt)
620
- sldRule.getDescription().setAbstract(abstrakt)
621
-
622
- val filter = realize(restricted)
623
-
624
- for (f <- filter)
625
- sldRule.setFilter(f)
626
- for (sym <- syms)
627
- sldRule.symbolizers.add(sym)
628
-
629
- fts.rules.add(sldRule)
630
- }
631
- }
632
- }
633
- sld.featureTypeStyles.add(fts)
634
584
}
585
+
586
+ r.copy(selectors = selectors0)
635
587
}
636
588
637
- return sld
589
+ val typenames = (s map extractTypename).distinct
590
+
591
+ for (t <- typenames)
592
+ yield (t, s.filter(isForTypename(t)).map(stripTypenames))
593
+ }
594
+
595
+ def extractScaleRanges (rule : Rule ): Seq [Pair [Option [Double ], Option [Double ]]] = {
596
+ val scales =
597
+ flatten(And (rule.selectors))
598
+ .collect {
599
+ case PseudoSelector (" scale" , _, d) => d.toDouble
600
+ case Not (PseudoSelector (" scale" , _, d)) => d.toDouble
601
+ }
602
+ .sorted
603
+ .distinct
604
+
605
+ val limits = None +: (scales map (Some (_))) :+ None
606
+ limits zip limits.tail
607
+ }
608
+
609
+ def interpret (s : StyleSheet ): Seq [(ZIndex , Rule , Seq [Symbolizer ])] =
610
+ for {
611
+ r <- cascading2exclusive(s)
612
+ (z, syms) <- groupByZ(symbolize(r))
613
+ } yield (z, r, syms)
614
+
615
+ def createSLDRuleLayers (rs : Seq [(ZIndex , Rule , Seq [Symbolizer ])]): Seq [Seq [gt.Rule ]] =
616
+ for ((_, group) <- flattenByZ(rs)) yield createSLDRuleLayer(group)
617
+
618
+ def createSLDRuleLayer (group : Seq [(Rule , Seq [Symbolizer ])]): Seq [gt.Rule ] =
619
+ for {
620
+ (rule, syms) <- group if syms.nonEmpty
621
+ range @ (min, max) <- extractScaleRanges(rule)
622
+ minSelector = min.map(x => PseudoSelector (" scale" , " >" , x.toString))
623
+ maxSelector = max.map(x => PseudoSelector (" scale" , " <" , x.toString))
624
+ filter = reduce(allOf(rule.selectors ++ minSelector ++ maxSelector))
625
+ if (filter != Exclude )
626
+ } yield createSLDRule(min, max, realize(filter), rule.description.title, rule.description.abstrakt, syms)
627
+
628
+ def createSLDRule (
629
+ min : Option [Double ],
630
+ max : Option [Double ],
631
+ filter : Option [org.opengis.filter.Filter ],
632
+ title : Option [String ],
633
+ `abstract` : Option [String ],
634
+ symbolizers : Seq [gt.Symbolizer ]): gt.Rule =
635
+ {
636
+ val rule = styles.createRule()
637
+ min.foreach { rule.setMinScaleDenominator }
638
+ max.foreach { rule.setMaxScaleDenominator }
639
+ filter.foreach { rule.setFilter }
640
+ title.foreach { t => rule.getDescription().setTitle(t) }
641
+ `abstract`.foreach { a => rule.getDescription().setAbstract(a) }
642
+ symbolizers.foreach { rule.symbolizers.add }
643
+ rule
644
+ }
645
+
646
+ def createFeatureTypeStyles (spec : (Option [String ], Seq [Seq [gt.Rule ]])): Seq [gt.FeatureTypeStyle ] =
647
+ spec._2.map { createFeatureTypeStyle(spec._1, _) }
648
+
649
+ def createFeatureTypeStyle (spec : (Option [String ], Seq [gt.Rule ])): gt.FeatureTypeStyle = {
650
+ val (typename, rules) = spec
651
+ val ftStyle = styles.createFeatureTypeStyle()
652
+ typename.foreach { t => ftStyle.featureTypeNames().add(new NameImpl (t)) }
653
+ rules.foreach { ftStyle.rules.add }
654
+ ftStyle
655
+ }
656
+
657
+ def createStyle (fts : Seq [gt.FeatureTypeStyle ]): gt.Style = {
658
+ val style = styles.createStyle()
659
+ fts.foreach { style.featureTypeStyles.add }
660
+ style
638
661
}
639
662
640
663
private def flattenByZ [R , S ](zGroups : Seq [(Double , R , Seq [S ])])
0 commit comments