From 6b19631cb3f4500f5896dce6b60ec4138f2edb27 Mon Sep 17 00:00:00 2001 From: Richard Fairhurst Date: Mon, 8 Jun 2009 15:20:36 +0000 Subject: [PATCH] Draw multiple strokes, label POIs, and much much more fun. --- halcyon.mxml | 6 - halcyon.tmproj | 52 ++++- net/systemeD/halcyon/Map.as | 20 +- net/systemeD/halcyon/POI.as | 71 ++++--- net/systemeD/halcyon/WayUI.as | 180 +++++++++--------- net/systemeD/halcyon/connection/Way.as | 4 + .../halcyon/styleparser/PointStyle.as | 1 + net/systemeD/halcyon/styleparser/Rule.as | 4 +- net/systemeD/halcyon/styleparser/RuleSet.as | 31 +-- .../halcyon/styleparser/ShapeStyle.as | 18 +- net/systemeD/halcyon/styleparser/TextStyle.as | 47 ++++- 11 files changed, 275 insertions(+), 159 deletions(-) diff --git a/halcyon.mxml b/halcyon.mxml index 3b96573b..dd09029d 100755 --- a/halcyon.mxml +++ b/halcyon.mxml @@ -6,12 +6,6 @@ horizontalAlign="center" addedToStage="initApp()"> - - - - - - diff --git a/halcyon.tmproj b/halcyon.tmproj index e987b408..6905e9ff 100644 --- a/halcyon.tmproj +++ b/halcyon.tmproj @@ -1,28 +1,28 @@ - + + currentDocument + net/systemeD/halcyon/styleparser/ShapeStyle.as documents filename net/systemeD/halcyon/Map.as lastUsed - 2009-06-01T11:58:41Z + 2009-06-05T16:08:57Z filename net/systemeD/halcyon/POI.as lastUsed - 2009-06-01T12:11:15Z - selected - + 2009-06-05T15:58:51Z filename net/systemeD/halcyon/WayUI.as lastUsed - 2009-06-01T11:58:42Z + 2009-06-05T15:58:51Z expanded @@ -52,16 +52,50 @@ filename halcyon.mxml lastUsed - 2009-06-01T11:49:17Z + 2009-06-04T15:10:55Z fileHierarchyDrawerWidth 200 metaData - + + net/systemeD/halcyon/Map.as + + caret + + column + 2 + line + 78 + + firstVisibleColumn + 0 + firstVisibleLine + 56 + + net/systemeD/halcyon/styleparser/ShapeStyle.as + + caret + + column + 0 + line + 25 + + firstVisibleColumn + 0 + firstVisibleLine + 0 + + + openDocuments + + net/systemeD/halcyon/Map.as + net/systemeD/halcyon/styleparser/ShapeStyle.as + showFileHierarchyDrawer windowFrame - {{268, 182}, {710, 564}} + {{261, 43}, {836, 630}} diff --git a/net/systemeD/halcyon/Map.as b/net/systemeD/halcyon/Map.as index ed136c3f..d6a1413c 100755 --- a/net/systemeD/halcyon/Map.as +++ b/net/systemeD/halcyon/Map.as @@ -83,7 +83,7 @@ package net.systemeD.halcyon { addChild(s); // | } s=new Sprite(); addChild(s); // 11 - POIs - s=new Sprite(); addChild(s); // 12 - shields + s=new Sprite(); addChild(s); // 12 - shields and POI names connection= Connection.getConnection(); connection.addEventListener(Connection.NEW_WAY, newWayCreated); @@ -93,20 +93,23 @@ package net.systemeD.halcyon { } public function gotEnvironment(r:Object):void { - init(52.022,-1.2745); + init(53.09465,-2.56495,17); } // ------------------------------------------------------------------------------------------ // Initialise map at a given lat/lon - public function init(startlat:Number,startlon:Number):void { + public function init(startlat:Number,startlon:Number,startscale:uint):void { ruleset.load("test.yaml?d="+Math.random()); // rules.initExample(); // initialise dummy rules updateSize(); - baselon =startlon -(mapwidth /2)/MASTERSCALE; - basey =lat2latp(startlat)+(mapheight/2)/MASTERSCALE; + + scale=startscale; + scalefactor=MASTERSCALE/Math.pow(2,14-scale); + baselon =startlon -(mapwidth /2)/scalefactor; + basey =lat2latp(startlat)+(mapheight/2)/scalefactor; addDebug("Baselon "+baselon+", basey "+basey); updateCoords(0,0); download(); @@ -165,6 +168,9 @@ package net.systemeD.halcyon { // (typically from whichways, but will want to add more connections) public function download():void { + var e:MapEvent = new MapEvent("download",edge_l,edge_r,edge_t,edge_b); + this.dispatchEvent(e); + if (edge_l>=bigedge_l && edge_r<=bigedge_r && edge_b>=bigedge_b && edge_t<=bigedge_t) { return; } // we have already loaded this area, so ignore bigedge_l=edge_l; bigedge_r=edge_r; @@ -214,7 +220,7 @@ package net.systemeD.halcyon { // Redraw all items, zoom in and out public function redraw():void { - for each (var w:WayUI in ways) { w.redraw(); } + for each (var w:WayUI in ways) { w.recalculate(); w.redraw(); } for each (var p:POI in pois) { p.redraw(); } } @@ -275,7 +281,7 @@ package net.systemeD.halcyon { // Miscellaneous events public function keyUpHandler(event:KeyboardEvent):void { -addDebug("pressed "+event.keyCode); +// addDebug("pressed "+event.keyCode); if (event.keyCode==82) { this.redraw(); } // R - redraw if (event.keyCode==73) { this.zoomIn(); } // I - zoom in if (event.keyCode==79) { this.zoomOut(); } // O - zoom out diff --git a/net/systemeD/halcyon/POI.as b/net/systemeD/halcyon/POI.as index e5b99912..9deecba7 100644 --- a/net/systemeD/halcyon/POI.as +++ b/net/systemeD/halcyon/POI.as @@ -1,24 +1,29 @@ package net.systemeD.halcyon { + import flash.display.*; + import flash.events.*; + import flash.text.AntiAliasType; + import flash.text.GridFitType; + import flash.text.TextField; + import flash.text.TextFormat; import net.systemeD.halcyon.connection.Node; - + import net.systemeD.halcyon.styleparser.*; + public class POI extends Object { - - import flash.display.*; - import flash.events.*; - import flash.text.TextField; - import flash.text.TextFormat; - import net.systemeD.halcyon.styleparser.*; - + private var node:Node; public var map:Map; // reference to parent map public var icon:Bitmap; // instance in display list public var name:Sprite; // | private var iconname:String=''; // name of icon + public static const DEFAULT_TEXTFIELD_PARAMS:Object = { + embedFonts: true, + antiAliasType: AntiAliasType.ADVANCED, + gridFitType: GridFitType.NONE + }; [Embed(source="fonts/DejaVuSans.ttf", fontFamily="DejaVu", fontWeight="normal", mimeType="application/x-font-truetype")] public static var DejaVu:Class; - public var nameformat:TextFormat; public function POI(node:Node, map:Map) { this.map = map; @@ -28,24 +33,35 @@ package net.systemeD.halcyon { public function redraw():void { var tags:Object = node.getTagsCopy(); - var styles:Array=map.ruleset.getStyle(true,tags,map.scale); - var ps:PointStyle=styles[1]; - - if (ps && ps.icon && ps.icon!='') { - if (ps.icon!=iconname) { - // 'load' icon (actually just from library) - if (map.ruleset.images[ps.icon]) { - var loader:Loader = new Loader(); - loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadedIcon); - loader.loadBytes(map.ruleset.images[ps.icon]); - iconname=ps.icon; + var styles:Array=map.ruleset.getStyles(true,tags,map.scale); + var r:Boolean=false; // ** rendered + for each (var s:* in styles) { + if ((s is PointStyle) && s.icon && s.icon!="") { + r=true; + if (s.icon!=iconname) { + // 'load' icon (actually just from library) + if (map.ruleset.images[s.icon]) { + var loader:Loader = new Loader(); + loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadedIcon); + loader.loadBytes(map.ruleset.images[s.icon]); + iconname=s.icon; + } + } else { + // already loaded, so just reposition + updatePosition(); + iconname=s.icon; + } + } else if ((s is TextStyle) && s.tag && tags[s.tag]) { + // create name sprite + if (!name) { + name=new Sprite(); + var c:DisplayObject=map.getChildAt(12); + Sprite(c).addChild(name); } - } else { - // already loaded, so just reposition - updatePosition(); - iconname=ps.icon; + s.writeNameLabel(name,tags[s.tag],map.lon2coord(node.lon),map.latp2coord(node.latp)); } - } else if (iconname!='') { + } + if (!r && iconname!='') { // not rendered any more, so remove var l:DisplayObject=map.getChildAt(11); Sprite(l).removeChild(icon); @@ -61,8 +77,9 @@ package net.systemeD.halcyon { } private function updatePosition():void { - icon.x=map.lon2coord(node.lon); - icon.y=map.latp2coord(node.latp); + icon.x=map.lon2coord(node.lon)-icon.width/2; + icon.y=map.latp2coord(node.latp)-icon.height/2; } + } } diff --git a/net/systemeD/halcyon/WayUI.as b/net/systemeD/halcyon/WayUI.as index 6ceff854..15490bdf 100755 --- a/net/systemeD/halcyon/WayUI.as +++ b/net/systemeD/halcyon/WayUI.as @@ -15,12 +15,12 @@ package net.systemeD.halcyon { private var way:Way; public var pathlength:Number; // length of path - + public var patharea:Number; // area of path + public var centroid_x:Number; // centroid + public var centroid_y:Number; // | public var layer:int=0; // map layer public var map:Map; // reference to parent map - public var stroke:Sprite; // instance in display list - public var fill:Sprite; // | - public var roadname:Sprite; // | + public var sprites:Array=new Array(); // instances in display list public static const DEFAULT_TEXTFIELD_PARAMS:Object = { embedFonts: true, @@ -39,23 +39,46 @@ package net.systemeD.halcyon { } private function init():void { - var lx:Number, ly:Number; + recalculate(); + redraw(); + // updateBbox(lon, lat); + // ** various other stuff + } + + // ------------------------------------------------------------------------------------------ + // Calculate length etc. + // ** this could be made scale-independent - would speed up redraw + + public function recalculate():void { + var lx:Number, ly:Number, sc:Number; + var cx:Number=0, cy:Number=0; pathlength=0; + patharea=0; for ( var i:uint = 0; i < way.length; i++ ) { var node:Node = way.getNode(i); - var lat:Number = node.lat; - var lon:Number = node.lon; -// updateBbox(lon, lat); + var latp:Number = node.latp; + var lon:Number = node.lon; if ( !isNaN(lx) ) { - pathlength += Math.sqrt( Math.pow(lon-lx,2)+Math.pow(lat-ly,2) ); + pathlength += Math.sqrt( Math.pow(lon-lx,2)+Math.pow(latp-ly,2) ); + patharea += lx*latp-lon*ly; + sc = (lx*latp-lon*ly); + cx += (lx+lon)*sc; + cy += (ly+latp)*sc; } - lx=lon; ly=lat; + lx=lon; ly=latp; } pathlength*=map.scalefactor; - redraw(); - // ** various other stuff + patharea*=map.scalefactor/2; + if (patharea>0 && way.isArea()) { + centroid_x=map.lon2coord(cx/patharea/6); + centroid_y=map.latp2coord(cy/patharea/6); + } else if (pathlength>0) { + var c:Array=pointAt(0.5); + centroid_x=c[0]; + centroid_y=c[1]; + } } // ------------------------------------------------------------------------------------------ @@ -64,88 +87,70 @@ package net.systemeD.halcyon { public function redraw():void { var tags:Object = way.getTagsCopy(); - // ** remove previous version from any layer/sublayer + // remove all currently existing sprites + while (sprites.length>0) { + var d:Sprite=sprites.pop(); d.parent.removeChild(d); + } + + // which layer? layer=5; if ( tags['layer'] ) layer=Math.min(Math.max(tags['layer']+5,-5),5)+5; // set style - var styles:Array=map.ruleset.getStyle(false, tags, map.scale); - var sublayer:uint=0; if (styles[0] && styles[0].sublayer) { sublayer=styles[0].sublayer; } - - // find/create sprites - if (stroke) { - fill.graphics.clear(); - stroke.graphics.clear(); - roadname.graphics.clear(); - while (roadname.numChildren) { roadname.removeChildAt(0); } - } else { - fill=new Sprite(); addToLayer(fill,0); - stroke=new Sprite(); addToLayer(stroke,1,sublayer); - roadname=new Sprite(); addToLayer(roadname,2); - } - var g:Graphics=stroke.graphics; - var f:Graphics=fill.graphics; - - // ShapeStyle - // ** do line-caps/joints - var doStroke:Boolean=false, doDashed:Boolean=false; - var doFill:Boolean=false, fill_colour:uint, fill_opacity:Number; - var doCasing:Boolean=false, doDashedCasing:Boolean=false; - if (styles[0]) { - var ss:ShapeStyle=styles[0]; - if (ss.isStroked) { doStroke=true; - doDashed=(ss.stroke_dashArray.length>0); - g.lineStyle(ss.stroke_width, ss.stroke_colour, ss.stroke_opacity/100, - false,"normal", ss.stroke_linecap,ss.stroke_linejoin); } - if (ss.isCased) { doCasing=true; - doDashedCasing=(ss.casing_dashArray.length>0); - f.lineStyle(ss.casing_width, ss.casing_colour, ss.casing_opacity/100, - false,"normal", ss.stroke_linecap, ss.stroke_linejoin); } - if (ss.isFilled) { doFill=true; - fill_colour = ss.fill_colour; - fill_opacity= ss.fill_opacity/100; } - } + var styles:Array=map.ruleset.getStyles(false, tags, map.scale); + for each (var s:* in styles) { + + if (s is ShapeStyle) { + var stroke:Sprite, fill:Sprite, roadname:Sprite, f:Graphics, g:Graphics; + var doStroke:Boolean=false, doDashed:Boolean=false; + var doFill:Boolean=false, fill_colour:uint, fill_opacity:Number; + var doCasing:Boolean=false, doDashedCasing:Boolean=false; + + // Set stroke style + if (s.isStroked) { + stroke=new Sprite(); addToLayer(stroke,1,s.sublayer); g=stroke.graphics; + g.moveTo(map.lon2coord(way.getNode(0).lon), map.latp2coord(way.getNode(0).latp)); + g.lineStyle(s.stroke_width, s.stroke_colour, s.stroke_opacity/100, + false, "normal", s.stroke_linecap, s.stroke_linejoin); + } + + // Set fill and casing style + if (s.isFilled || s.isCased) { + fill=new Sprite(); addToLayer(fill,0); f=fill.graphics; + f.moveTo(map.lon2coord(way.getNode(0).lon), map.latp2coord(way.getNode(0).latp)); + if (s.isCased) { f.lineStyle(s.casing_width, s.casing_colour, s.casing_opacity/100, + false, "normal", s.stroke_linecap, s.stroke_linejoin); } + if (s.isFilled) { f.beginFill(s.fill_colour,s.fill_opacity/100); } + } - // draw line - if (doFill) - f.beginFill(fill_colour,fill_opacity); - if (doStroke) - g.moveTo(map.lon2coord(way.getNode(0).lon), map.latp2coord(way.getNode(0).latp)); - if (doFill || doCasing) - f.moveTo(map.lon2coord(way.getNode(0).lon), map.latp2coord(way.getNode(0).latp)); - - if (doDashed) - dashedLine(g,ss.stroke_dashArray); - else if (doStroke) - solidLine(g); + // Draw stroke + if (s.stroke_dashArray.length>0) { dashedLine(g,s.stroke_dashArray); } + else if (s.isStroked) { solidLine(g); } - if (doDashedCasing) { - dashedLine(f,ss.casing_dashArray); - f.lineStyle(); - } - if (doFill) { - f.beginFill(fill_colour,fill_opacity); - solidLine(f); - f.endFill(); - } else if (doCasing && !doDashedCasing) { - solidLine(f); - } - - // TextStyle - // ** do pull-out - if (styles[2] && styles[2].tag && tags[styles[2].tag]) { - var ts:TextStyle=styles[2]; - nameformat = new TextFormat(ts.font_name ? ts.font_name : "DejaVu", - ts.text_size ? ts.text_size : 8, - ts.text_colour ? ts.text_colour: 0, - ts.font_bold ? ts.font_bold : false, - ts.font_italic ? ts.font_italic: false); - var a:String=tags[ts.tag]; if (ts.font_caps) { a=a.toUpperCase(); } - writeName(roadname,a,ts.text_offset ? ts.text_offset : 0); + // Draw fill and casing + if (s.casing_dashArray.length>0) { dashedLine(f,s.casing_dashArray); f.lineStyle(); } + if (s.isFilled) { f.beginFill(s.fill_colour,s.fill_opacity/100); + solidLine(f); f.endFill(); } + else if (s.isCased && s.casing_dashArray.length==0) { solidLine(f); } + + + } else if (s is TextStyle && s.tag && tags[s.tag]) { + roadname=new Sprite(); addToLayer(roadname,2); + nameformat = s.getTextFormat(); + var a:String=tags[s.tag]; if (s.font_caps) { a=a.toUpperCase(); } + if (s.isLine) { + writeNameOnPath(roadname,a,s.text_offset ? s.text_offset : 0); + if (s.pullout_radius>0) { roadname.filters=s.getPulloutFilter(); } + } else if (centroid_x) { + s.writeNameLabel(roadname,tags[s.tag],centroid_x,centroid_y); + } + + + } else if (s is ShieldStyle) { + // ** to do + } } - // ShieldStyle - 3 - // ** to do } // ------------------------------------------------------------------------------------------ @@ -237,7 +242,7 @@ package net.systemeD.halcyon { // based on code by Tom Carden // ** needs styling - private function writeName(s:Sprite,a:String,textOffset:Number=0):void { + private function writeNameOnPath(s:Sprite,a:String,textOffset:Number=0):void { // make a dummy textfield so we can measure its width var tf:TextField = new TextField(); @@ -301,6 +306,7 @@ package net.systemeD.halcyon { var o:DisplayObject=Sprite(l).getChildAt(t); if (sublayer!=-1) { o=Sprite(o).getChildAt(sublayer); } Sprite(o).addChild(s); + sprites.push(s); } } } diff --git a/net/systemeD/halcyon/connection/Way.as b/net/systemeD/halcyon/connection/Way.as index 02a3cbf1..f26d5b64 100644 --- a/net/systemeD/halcyon/connection/Way.as +++ b/net/systemeD/halcyon/connection/Way.as @@ -33,6 +33,10 @@ package net.systemeD.halcyon.connection { return "Way("+id+"@"+version+"): "+getTagList()+ " "+nodes.map(function(item:Node,index:int, arr:Array):String {return item.id.toString();}).join(","); } + + public function isArea():Boolean { + return nodes[0]==nodes[nodes.length-1] && nodes.length>2; + } } } diff --git a/net/systemeD/halcyon/styleparser/PointStyle.as b/net/systemeD/halcyon/styleparser/PointStyle.as index 1a28a505..84d226aa 100644 --- a/net/systemeD/halcyon/styleparser/PointStyle.as +++ b/net/systemeD/halcyon/styleparser/PointStyle.as @@ -5,6 +5,7 @@ package net.systemeD.halcyon.styleparser { public var icon:String; public var width:uint; public var height:uint; + public var sublayer:uint=0; } diff --git a/net/systemeD/halcyon/styleparser/Rule.as b/net/systemeD/halcyon/styleparser/Rule.as index d9853cec..4e24f640 100644 --- a/net/systemeD/halcyon/styleparser/Rule.as +++ b/net/systemeD/halcyon/styleparser/Rule.as @@ -7,7 +7,9 @@ package net.systemeD.halcyon.styleparser { public var isAnd:Boolean = true; public var minScale:uint = 19; public var maxScale:uint = 13; - + public var hasTags:Boolean = false; + public var setTags:Object = {}; + public function test(tags:Object):Boolean { var v:Boolean; var i:uint=0; for each (var condition:Condition in conditions) { diff --git a/net/systemeD/halcyon/styleparser/RuleSet.as b/net/systemeD/halcyon/styleparser/RuleSet.as index 15541ae3..a7852a58 100644 --- a/net/systemeD/halcyon/styleparser/RuleSet.as +++ b/net/systemeD/halcyon/styleparser/RuleSet.as @@ -18,26 +18,31 @@ package net.systemeD.halcyon.styleparser { iconCallback=f; } - // returns array of ShapeStyle,PointStyle,TextStyle,ShieldStyle - public function getStyle(isPoint:Boolean,tags:Object,scale:uint):Array { - var ss:ShapeStyle; - var ps:PointStyle; - var ts:TextStyle; - var hs:ShieldStyle; + // returns array of styles + public function getStyles(isPoint:Boolean,tags:Object,scale:uint):Array { + var rt:Object=tags; var rtused:Boolean=false; // new tag object to be returned + var i:String; + var styles:Array=[]; for each (var rule:* in rules) { if ( isPoint && rule is ShapeRule) { continue; } if (!isPoint && rule is PointRule) { continue; } if (scale>rule.minScale) { continue; } if (scale0) { tf.filters=getPulloutFilter(); } + d.x=x-tf.width/2; + d.y=y+(text_offset ? text_offset : 0); + d.addChild(tf); + return tf; + } } -- 2.30.0