Skip to content

Commit

Permalink
Performance improvements in CSS compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
dwins committed May 18, 2013
1 parent df03fec commit 75fb752
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 26 deletions.
2 changes: 1 addition & 1 deletion geocss/src/main/scala/org/geoscript/geocss/Converter.scala
Expand Up @@ -44,7 +44,7 @@ object Converter {
writer.close()
}

def main(args: Array[String]) = {
def main(args: Array[String]) {
val (options, filenames) = parse(args)

val write: (Seq[Rule], java.net.URL, OutputStream) => Unit =
Expand Down
2 changes: 1 addition & 1 deletion geocss/src/main/scala/org/geoscript/geocss/CssParser.scala
Expand Up @@ -118,7 +118,7 @@ object CssParser extends RegexParsers {
op <- "[><=]".r
num <- number
_ <- literal("]")
} yield PseudoSelector(id, op, num)
} yield PseudoSelector(id, op, num.toDouble)

val pseudoClass = (":" ~> identifier) ^^ PseudoClass

Expand Down
10 changes: 5 additions & 5 deletions geocss/src/main/scala/org/geoscript/geocss/Selector.scala
Expand Up @@ -40,9 +40,9 @@ object Selector {
case (Not(p), Not(q)) => implies(q, p)
case (p, Not(q)) => !allows(p, q)
case (PseudoSelector("scale", ">", a), PseudoSelector("scale", ">", b)) =>
b.toDouble <= a.toDouble
b <= a
case (PseudoSelector("scale", "<", a), PseudoSelector("scale", "<", b)) =>
b.toDouble >= a.toDouble
b >= a
case (DataFilter(f), DataFilter(g)) =>
try {
given(f).reduce(g) == ogc.Filter.INCLUDE
Expand All @@ -68,9 +68,9 @@ object Selector {
case (Not(p), Not(q)) => allows(q, p)
case (Not(p), q) => !implies(q, p)
case (PseudoSelector("scale", ">", a), PseudoSelector("scale", "<", b)) =>
b.toDouble > a.toDouble
b > a
case (PseudoSelector("scale", "<", a), PseudoSelector("scale", ">", b)) =>
b.toDouble < a.toDouble
b < a
case (DataFilter(f), DataFilter(g)) =>
try {
given(f).reduce(g) != ogc.Filter.EXCLUDE
Expand Down Expand Up @@ -247,7 +247,7 @@ case class Typename(typename: String) extends MetaSelector {
* property such as the scale denominator at render time. This corresponds to
* the [&64;scale &gt; 10000] syntax in CSS, for example.
*/
case class PseudoSelector(property: String, operator: String, value: String)
case class PseudoSelector(property: String, operator: String, value: Double)
extends MetaSelector {
override def toString = "@%s%s%s".format(property, operator, value)
}
Expand Down
44 changes: 36 additions & 8 deletions geocss/src/main/scala/org/geoscript/geocss/Translator.scala
Expand Up @@ -590,8 +590,8 @@ class Translator(val baseURL: Option[java.net.URL]) {
val scales =
flatten(And(rule.selectors))
.collect {
case PseudoSelector("scale", _, d) => d.toDouble
case Not(PseudoSelector("scale", _, d)) => d.toDouble
case PseudoSelector("scale", _, d) => d
case Not(PseudoSelector("scale", _, d)) => d
}
.sorted
.distinct
Expand All @@ -613,8 +613,8 @@ class Translator(val baseURL: Option[java.net.URL]) {
for {
(rule, syms) <- group if syms.nonEmpty
range @ (min, max) <- extractScaleRanges(rule)
minSelector = min.map(x => PseudoSelector("scale", ">", x.toString))
maxSelector = max.map(x => PseudoSelector("scale", "<", x.toString))
minSelector = min.map(x => PseudoSelector("scale", ">", x))
maxSelector = max.map(x => PseudoSelector("scale", "<", x))
filter = reduce(allOf(rule.selectors ++ minSelector ++ maxSelector))
if (filter != Exclude)
} yield createSLDRule(min, max, realize(filter), rule.description.title, rule.description.abstrakt, syms)
Expand Down Expand Up @@ -687,7 +687,7 @@ class Translator(val baseURL: Option[java.net.URL]) {
}
reduced match {
case And(sels) => sels
case sel => Seq(sel)
case sel => Seq(sel)
}
}
}
Expand Down Expand Up @@ -736,7 +736,9 @@ class Translator(val baseURL: Option[java.net.URL]) {
reduce[Selector](And(a.selectors ++ b.selectors)) == Exclude

val cliques = maximalCliques(xs.toSet, mutuallyExclusive)
val combinations = enumerateCombinations(cliques)
val combinations = visit(cliques).map(_.toSet).toSet
// val oldCombinations = enumerateCombinations(cliques)
// println(s"${oldCombinations.size}, ${combinations.size}")

val ExclusiveRule = EmptyRule.copy(selectors = Seq(Exclude))

Expand All @@ -751,13 +753,39 @@ class Translator(val baseURL: Option[java.net.URL]) {
for {
combo <- combinations
remainder = xs filterNot(combo contains _)
included = include(combo)
included = include(combo.toSet)
excluded = exclude(remainder)
constrained = constrain(included, excluded)
ruleset = simplifySelector(constrained)
if ruleset.isSatisfiable
if ruleset.isSatisfiable
} yield ruleset

// println(rulesets.size)
// rulesets.toSeq
Nil
rulesets.toSeq
}

import scala.annotation.tailrec

// @tailrec
def visit(cliques: Set[Set[Rule]]): Seq[List[Rule]] = {
def work[Rule](path: List[Rule], cliques: List[Set[Rule]]): Seq[List[Rule]] =
cliques match {
case Nil =>
Seq(path)
case top :: remainingCliques =>
val includingThisLevel: Seq[List[Rule]] =
top.toSeq flatMap { i =>
val culledRemaining =
remainingCliques.filterNot(_ contains i).map(_ -- top)
work(i :: path, culledRemaining) // remainingCliques filterNot (_ contains i))
}
val excludingThisLevel: Seq[List[Rule]] =
work(path, remainingCliques)

includingThisLevel ++ excludingThisLevel
}
work(Nil, cliques.toList.sortBy(- _.size))
}
}
30 changes: 19 additions & 11 deletions geocss/src/main/scala/org/geoscript/geocss/filter/package.scala
Expand Up @@ -134,15 +134,21 @@ package object filter {
}

class Value(val text: String) {
lazy val asDouble =
try {
Some(text.toDouble)
} catch {
case (_: NumberFormatException) => None
}

override def toString = text
override def equals(that: Any) =
that match {
case (that: Value) =>
try {
this.text.toDouble == that.text.toDouble
} catch {
case (_: NumberFormatException) => this.text == that.text
}
if (this.asDouble.isDefined && that.asDouble.isDefined)
this.asDouble == that.asDouble
else
this.text == that.text
case _ => false
}
}
Expand All @@ -153,12 +159,14 @@ package object filter {
apply(literal.getValue.toString)

implicit val valuesAreOrdered: Ordering[Value] =
Ordering.fromLessThan { (a: Value, b: Value) =>
try {
a.text.toDouble < b.text.toDouble
} catch {
case (_: NumberFormatException) => a.text < b.text
}
new Ordering[Value] {
val dbl = implicitly[Ordering[Double]]
val str = implicitly[Ordering[String]]
def compare(x: Value, y: Value): Int =
if (x.asDouble.isDefined && y.asDouble.isDefined)
dbl.compare(x.asDouble.get, y.asDouble.get)
else
str.compare(x.text, y.text)
}
}
case object Unconstrained extends Constraint
Expand Down

0 comments on commit 75fb752

Please sign in to comment.