From 3b5f0a635b3419f1539e3505bd671fc78aace6dc Mon Sep 17 00:00:00 2001 From: Richard Fairhurst Date: Sun, 12 Jun 2011 14:42:04 +0100 Subject: [PATCH 1/1] New RuleChain object to replace previous nested array within StyleChooser --- net/systemeD/halcyon/styleparser/RuleChain.as | 65 +++++++++++++++++ net/systemeD/halcyon/styleparser/RuleSet.as | 18 ++--- .../halcyon/styleparser/StyleChooser.as | 70 ++++++------------- 3 files changed, 95 insertions(+), 58 deletions(-) create mode 100644 net/systemeD/halcyon/styleparser/RuleChain.as diff --git a/net/systemeD/halcyon/styleparser/RuleChain.as b/net/systemeD/halcyon/styleparser/RuleChain.as new file mode 100644 index 00000000..cd6c5b43 --- /dev/null +++ b/net/systemeD/halcyon/styleparser/RuleChain.as @@ -0,0 +1,65 @@ +package net.systemeD.halcyon.styleparser { + + import net.systemeD.halcyon.connection.*; + + /** A descendant list of MapCSS selectors (Rules). + + For example, + relation[type=route] way[highway=primary] + ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ + first Rule second Rule + |------------|---------| + | + one RuleChain + + */ + + public class RuleChain { + public var rules:Array=[]; // should eventually become a Vector of Rules + public var subpart:String=''; // subpart name, as in way[highway=primary]::centreline + + // Test a ruleChain + // - run a set of tests in the chain + // works backwards from at position "pos" in array, or -1 for the last + // separate tags object is required in case they've been dynamically retagged + // - if they fail, return false + // - if they succeed, and it's the last in the chain, return happily + // - if they succeed, and there's more in the chain, rerun this for each parent until success + + public function test(pos:int, obj:Entity, tags:Object, zoom:uint):Boolean { + if (pos==-1) { pos=rules.length-1; } + + var r:Rule=rules[pos]; + if (!r.test(obj, tags, zoom)) { return false; } + if (pos==0) { return true; } + + var o:Array=obj.parentObjects; + for each (var p:Entity in o) { + if (test(pos-1, p, p.getTagsHash(), zoom)) { return true; } + } + return false; + } + + public function get length():int { + return rules.length; + } + + // --------------------------------------------------------------------------------------------- + // Methods to add properties (used by parsers such as MapCSS) + + public function addRule(e:String=''):void { + rules.push(new Rule(e)); + } + + public function addConditionToLast(c:Condition):void { + rules[rules.length-1].conditions.push(c); + } + + public function addZoomToLast(z1:uint,z2:uint):void { + rules[rules.length-1].minZoom=z1; + rules[rules.length-1].maxZoom=z2; + } + + + } +} diff --git a/net/systemeD/halcyon/styleparser/RuleSet.as b/net/systemeD/halcyon/styleparser/RuleSet.as index 33c20b9c..0bf9923a 100644 --- a/net/systemeD/halcyon/styleparser/RuleSet.as +++ b/net/systemeD/halcyon/styleparser/RuleSet.as @@ -43,6 +43,7 @@ package net.systemeD.halcyon.styleparser { private static const CONDITION:RegExp =/^ \[(.+?)\] \s* /sx; private static const OBJECT:RegExp =/^ (\w+) \s* /sx; private static const DECLARATION:RegExp =/^ \{(.+?)\} \s* /sx; + private static const SUBPART:RegExp =/^ ::(\S+) \s* /sx; private static const UNKNOWN:RegExp =/^ (\S+) \s* /sx; private static const ZOOM_MINMAX:RegExp =/^ (\d+)\-(\d+) $/sx; @@ -366,7 +367,7 @@ package net.systemeD.halcyon.styleparser { if (previous==oDECLARATION) { saveChooser(sc); sc=new StyleChooser(); } css=css.replace(CLASS,''); - sc.addCondition(new Condition('set',o[1])); + sc.currentChain.addConditionToLast(new Condition('set',o[1])); previous=oCONDITION; // Not class - !.motorway, !.builtup, !:hover @@ -374,30 +375,31 @@ package net.systemeD.halcyon.styleparser { if (previous==oDECLARATION) { saveChooser(sc); sc=new StyleChooser(); } css=css.replace(NOT_CLASS,''); - sc.addCondition(new Condition('unset',o[1])); + sc.currentChain.addConditionToLast(new Condition('unset',o[1])); previous=oCONDITION; // Zoom } else if ((o=ZOOM.exec(css))) { - if (previous!=oOBJECT && previous!=oCONDITION) { sc.newObject(); } + if (previous!=oOBJECT && previous!=oCONDITION) { sc.currentChain.addRule(); } css=css.replace(ZOOM,''); var z:Array=parseZoom(o[1]); - sc.addZoom(z[0],z[1]); + sc.currentChain.addZoomToLast(z[0],z[1]); + sc.zoomSpecific=true; previous=oZOOM; // Grouping - just a comma } else if ((o=GROUP.exec(css))) { css=css.replace(GROUP,''); - sc.newGroup(); + sc.newRuleChain(); previous=oGROUP; // Condition - [highway=primary] } else if ((o=CONDITION.exec(css))) { if (previous==oDECLARATION) { saveChooser(sc); sc=new StyleChooser(); } - if (previous!=oOBJECT && previous!=oZOOM && previous!=oCONDITION) { sc.newObject(); } + if (previous!=oOBJECT && previous!=oZOOM && previous!=oCONDITION) { sc.currentChain.addRule(); } css=css.replace(CONDITION,''); - sc.addCondition(parseCondition(o[1]) as Condition); + sc.currentChain.addConditionToLast(parseCondition(o[1]) as Condition); previous=oCONDITION; // Object - way, node, relation @@ -405,7 +407,7 @@ package net.systemeD.halcyon.styleparser { if (previous==oDECLARATION) { saveChooser(sc); sc=new StyleChooser(); } css=css.replace(OBJECT,''); - sc.newObject(o[1]); + sc.currentChain.addRule(o[1]); previous=oOBJECT; // Declaration - {...} diff --git a/net/systemeD/halcyon/styleparser/StyleChooser.as b/net/systemeD/halcyon/styleparser/StyleChooser.as index 05b71b88..1a3f86fa 100644 --- a/net/systemeD/halcyon/styleparser/StyleChooser.as +++ b/net/systemeD/halcyon/styleparser/StyleChooser.as @@ -10,25 +10,35 @@ package net.systemeD.halcyon.styleparser { Its ruleChains property is an array of all the selectors, which would traditionally be comma-separated. For example: h1, h2, h3 em - is three ruleChains. + is three RuleChains. - Each ruleChain is itself an array of nested selectors. So the above + Each RuleChain is itself an array of nested selectors. So the above example would roughly be encoded as: [[h1],[h2],[h3,em]] ^^ ^^ ^^ ^^ each of these is a Rule - + ^^^^ ^^^^ ^^^^^^^ each of these is a RuleChain + The styles property is an array of all the style objects to be drawn if any of the ruleChains evaluate to true. */ - public var ruleChains:Array=[[]]; // array of array of Rules + public var ruleChains:Array; // array of RuleChains (each one an array of Rules) public var styles:Array=[]; // array of ShapeStyle/ShieldStyle/TextStyle/PointStyle public var zoomSpecific:Boolean=false; // are any of the rules zoom-specific? - private var rcpos:uint=0; + private var rcpos:uint; private var stylepos:uint=0; + public function StyleChooser():void { + ruleChains=[new RuleChain()]; + rcpos=0; + } + + public function get currentChain():RuleChain { + return ruleChains[rcpos]; + } + // Update the current StyleList from this StyleChooser public function updateStyles(obj:Entity, tags:Object, sl:StyleList, imageWidths:Object, zoom:uint):void { @@ -37,8 +47,8 @@ package net.systemeD.halcyon.styleparser { // Are any of the ruleChains fulfilled? var w:Number; var fulfilled:Boolean=false; - for each (var c:Array in ruleChains) { - if (testChain(c,-1,obj,tags,zoom)) { + for each (var c:RuleChain in ruleChains) { + if (c.test(-1,obj,tags,zoom)) { fulfilled=true; break; } } @@ -86,58 +96,18 @@ package net.systemeD.halcyon.styleparser { } } } - - - // Test a ruleChain - // - run a set of tests in the chain - // works backwards from at position "pos" in array, or -1 for the last - // separate tags object is required in case they've been dynamically retagged - // - if they fail, return false - // - if they succeed, and it's the last in the chain, return happily - // - if they succeed, and there's more in the chain, rerun this for each parent until success - - private function testChain(chain:Array,pos:int,obj:Entity,tags:Object,zoom:uint):Boolean { - if (pos==-1) { pos=chain.length-1; } - - var r:Rule=chain[pos]; - if (!r.test(obj, tags, zoom)) { return false; } - if (pos==0) { return true; } - - var o:Array=obj.parentObjects; - for each (var p:Entity in o) { - if (testChain(chain, pos-1, p, p.getTagsHash(), zoom )) { return true; } - } - return false; - } // --------------------------------------------------------------------------------------------- // Methods to add properties (used by parsers such as MapCSS) - // newGroup <- starts a new ruleChain in this.ruleChains - public function newGroup():void { + // newRuleChain <- starts a new ruleChain in this.ruleChains + public function newRuleChain():void { if (ruleChains[rcpos].length>0) { - ruleChains[++rcpos]=[]; + ruleChains[++rcpos]=new RuleChain(); } } - // newObject <- adds into the current ruleChain (starting a new Rule) - public function newObject(e:String=''):void { - ruleChains[rcpos].push(new Rule(e)); - } - - // addZoom <- adds into the current ruleChain (existing Rule) - public function addZoom(z1:uint,z2:uint):void { - ruleChains[rcpos][ruleChains[rcpos].length-1].minZoom=z1; - ruleChains[rcpos][ruleChains[rcpos].length-1].maxZoom=z2; - zoomSpecific=true; - } - - // addCondition <- adds into the current ruleChain (existing Rule) - public function addCondition(c:Condition):void { - ruleChains[rcpos][ruleChains[rcpos].length-1].conditions.push(c); - } - // addStyles <- adds to this.styles public function addStyles(a:Array):void { styles=styles.concat(a); -- 2.36.1