horizontalAlign="center"
addedToStage="initApp()">
-<!-- <halcyon:CountryComboBox /> -->
-
-<!-- <halcyon:Map width="400" height="200" id="theMap" /> -->
-<!-- applicationComplete -->
-<!-- rawChildren -->
-
<mx:HDividedBox width="100%" height="100%">
<mx:VBox height="100%">
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
+ <key>currentDocument</key>
+ <string>net/systemeD/halcyon/styleparser/ShapeStyle.as</string>
<key>documents</key>
<array>
<dict>
<key>filename</key>
<string>net/systemeD/halcyon/Map.as</string>
<key>lastUsed</key>
- <date>2009-06-01T11:58:41Z</date>
+ <date>2009-06-05T16:08:57Z</date>
</dict>
<dict>
<key>filename</key>
<string>net/systemeD/halcyon/POI.as</string>
<key>lastUsed</key>
- <date>2009-06-01T12:11:15Z</date>
- <key>selected</key>
- <true/>
+ <date>2009-06-05T15:58:51Z</date>
</dict>
<dict>
<key>filename</key>
<string>net/systemeD/halcyon/WayUI.as</string>
<key>lastUsed</key>
- <date>2009-06-01T11:58:42Z</date>
+ <date>2009-06-05T15:58:51Z</date>
</dict>
<dict>
<key>expanded</key>
<key>filename</key>
<string>halcyon.mxml</string>
<key>lastUsed</key>
- <date>2009-06-01T11:49:17Z</date>
+ <date>2009-06-04T15:10:55Z</date>
</dict>
</array>
<key>fileHierarchyDrawerWidth</key>
<integer>200</integer>
<key>metaData</key>
- <dict/>
+ <dict>
+ <key>net/systemeD/halcyon/Map.as</key>
+ <dict>
+ <key>caret</key>
+ <dict>
+ <key>column</key>
+ <integer>2</integer>
+ <key>line</key>
+ <integer>78</integer>
+ </dict>
+ <key>firstVisibleColumn</key>
+ <integer>0</integer>
+ <key>firstVisibleLine</key>
+ <integer>56</integer>
+ </dict>
+ <key>net/systemeD/halcyon/styleparser/ShapeStyle.as</key>
+ <dict>
+ <key>caret</key>
+ <dict>
+ <key>column</key>
+ <integer>0</integer>
+ <key>line</key>
+ <integer>25</integer>
+ </dict>
+ <key>firstVisibleColumn</key>
+ <integer>0</integer>
+ <key>firstVisibleLine</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <key>openDocuments</key>
+ <array>
+ <string>net/systemeD/halcyon/Map.as</string>
+ <string>net/systemeD/halcyon/styleparser/ShapeStyle.as</string>
+ </array>
<key>showFileHierarchyDrawer</key>
<true/>
<key>windowFrame</key>
- <string>{{268, 182}, {710, 564}}</string>
+ <string>{{261, 43}, {836, 630}}</string>
</dict>
</plist>
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);
}
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();
// (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;
// 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(); }
}
// 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
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;
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);
}
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;
}
+
}
}
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,
}
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];
+ }
}
// ------------------------------------------------------------------------------------------
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
}
// ------------------------------------------------------------------------------------------
// 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();
var o:DisplayObject=Sprite(l).getChildAt(t);
if (sublayer!=-1) { o=Sprite(o).getChildAt(sublayer); }
Sprite(o).addChild(s);
+ sprites.push(s);
}
}
}
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;
+ }
}
}
public var icon:String;
public var width:uint;
public var height:uint;
+ public var sublayer:uint=0;
}
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) {
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 (scale<rule.maxScale) { continue; }
- if (rule.test(tags)) {
- if (rule is ShapeRule && rule.shapeStyle) { ss=rule.shapeStyle; }
- if (rule is PointRule && rule.pointStyle) { ps=rule.pointStyle; }
- if ( rule.textStyle ) { ts=rule.textStyle; }
- if (rule is ShapeRule && rule.shieldStyle) { hs=rule.shieldStyle; }
- if (rule.breaker) { break; }
+ if (rule.test(rt)) {
+ if (rule is ShapeRule && rule.shapeStyle) { styles.push(rule.shapeStyle); }
+ if (rule is PointRule && rule.pointStyle) { styles.push(rule.pointStyle); }
+ if ( rule.textStyle ) { styles.push(rule.textStyle); }
+ if (rule is ShapeRule && rule.shieldStyle) { styles.push(rule.shieldStyle); }
+ if (rule.breaker) { break; }
+ if (rule.hasTags) {
+ // deep copy tag object so we're not modifying in situ
+ if (!rtused) { for (i in tags) { rt[i]=tags[i]; }; rtused=true; }
+ // and apply new tags
+ for (i in rule.setTags) { rt[i]=rule.setTags[i]; }
+ }
}
}
- return new Array(ss,ps,ts,hs);
+ return styles;
}
// Save and load rulesets
package net.systemeD.halcyon.styleparser {
+ import flash.utils.ByteArray;
+
public class ShapeStyle {
public var isStroked:Boolean=true;
- public var stroke_colour:uint=0x777777;
- public var stroke_width:Number=1;
- public var stroke_opacity:uint=100;
+ public var stroke_width:Number;
+ public var stroke_colour:Number;
+ public var stroke_opacity:Number;
public var stroke_dashArray:Array=[];
public var stroke_linecap:String="none";
public var stroke_linejoin:String="round";
public var sublayer:uint=0;
public var isFilled:Boolean=false;
- public var fill_colour:uint=0xFFFFFF;
- public var fill_opacity:Number=100;
+ public var fill_colour:Number;
+ public var fill_opacity:Number;
public var fill_pattern:String;
public var isCased:Boolean=false;
- public var casing_width:Number=1;
- public var casing_colour:uint=0;
- public var casing_opacity:Number=100;
+ public var casing_width:Number;
+ public var casing_colour:Number;
+ public var casing_opacity:Number;
public var casing_dashArray:Array=[];
}
package net.systemeD.halcyon.styleparser {
+ import flash.display.*;
+ import flash.text.TextField;
+ import flash.text.TextFormat;
+ import flash.filters.BitmapFilter;
+ import flash.filters.GlowFilter;
+
public class TextStyle {
public var font_name:String;
public var text_size:uint;
public var text_colour:uint;
public var text_offset:Number; // Y offset - i.e. within or outside casing?
+ public var text_width:Number; // maximum width of label
public var tag:String;
public var pullout_colour:uint;
- public var pullout_radius:uint;
+ public var pullout_radius:uint=0;
public var isLine:Boolean;
+ public var sublayer:uint=0;
+
+ public function getTextFormat():TextFormat {
+ return new TextFormat(font_name ? font_name : "DejaVu",
+ text_size ? text_size : 8,
+ text_colour ? text_colour: 0,
+ font_bold ? font_bold : false,
+ font_italic ? font_italic: false);
+ }
+
+ public function getPulloutFilter():Array {
+ var filter:BitmapFilter=new GlowFilter(pullout_colour ? pullout_colour : 0xFFFFFF,1,
+ pullout_radius ? pullout_radius: 2,
+ pullout_radius ? pullout_radius: 2,255);
+ return [filter];
+ }
+
+ public function writeNameLabel(d:DisplayObjectContainer,a:String,x:Number,y:Number):TextField {
+ var tf:TextField = new TextField();
+ var n:TextFormat = getTextFormat();
+ n.align = "center";
+ tf.embedFonts = true;
+ tf.defaultTextFormat = n;
+ tf.text = a;
+ if (text_width) {
+ tf.width=text_width;
+ tf.wordWrap=true;
+ tf.height=tf.textHeight+4;
+ } else {
+ tf.width = tf.textWidth+4;
+ tf.height = tf.textHeight+4;
+ }
+ if (pullout_radius>0) { tf.filters=getPulloutFilter(); }
+ d.x=x-tf.width/2;
+ d.y=y+(text_offset ? text_offset : 0);
+ d.addChild(tf);
+ return tf;
+ }
}