From f37734c53acbf9756214618b87c930b996d38bfc Mon Sep 17 00:00:00 2001 From: egeller <ëlena.geller@gmail.com@> Date: Sat, 2 Nov 2013 10:45:43 +0100 Subject: [PATCH] first commit --- .gitignore | 217 ++++++ MapTest.hxproj | 57 ++ application.xml | 27 + assets/openfl.svg | 17 + openfl-readme.txt | 68 ++ src/Main.hx | 144 ++++ src/VectorLayer.hx | 84 +++ src/com/.svn/all-wcprops | 35 + src/com/.svn/entries | 198 +++++ src/com/.svn/text-base/Button.hx.svn-base | 431 +++++++++++ src/com/.svn/text-base/Component.hx.svn-base | 74 ++ src/com/.svn/text-base/InfoBox.hx.svn-base | 86 +++ src/com/.svn/text-base/StatusBar.hx.svn-base | 94 +++ src/com/.svn/text-base/ToolBar.hx.svn-base | 153 ++++ src/com/Button.hx | 431 +++++++++++ src/com/Component.hx | 74 ++ src/com/InfoBox.hx | 86 +++ src/com/StatusBar.hx | 94 +++ src/com/ToolBar.hx | 153 ++++ src/map/.svn/all-wcprops | 59 ++ src/map/.svn/entries | 334 +++++++++ src/map/.svn/text-base/Canvas.hx.svn-base | 666 +++++++++++++++++ src/map/.svn/text-base/Layer.hx.svn-base | 522 ++++++++++++++ src/map/.svn/text-base/LngLat.hx.svn-base | 85 +++ src/map/.svn/text-base/MapService.hx.svn-base | 211 ++++++ src/map/.svn/text-base/QuadTree.hx.svn-base | 240 +++++++ src/map/.svn/text-base/Tile.hx.svn-base | 173 +++++ src/map/.svn/text-base/TileLayer.hx.svn-base | 546 ++++++++++++++ src/map/.svn/text-base/TileLoader.hx.svn-base | 547 ++++++++++++++ src/map/.svn/text-base/Utils.hx.svn-base | 74 ++ src/map/Canvas.hx | 676 ++++++++++++++++++ src/map/Layer.hx | 522 ++++++++++++++ src/map/LngLat.hx | 85 +++ src/map/MapService.hx | 215 ++++++ src/map/QuadTree.hx | 240 +++++++ src/map/Tile.hx | 174 +++++ src/map/TileLayer.hx | 546 ++++++++++++++ src/map/TileLoader.hx | 547 ++++++++++++++ src/map/Utils.hx | 74 ++ 39 files changed, 9059 insertions(+) create mode 100644 .gitignore create mode 100644 MapTest.hxproj create mode 100644 application.xml create mode 100644 assets/openfl.svg create mode 100644 openfl-readme.txt create mode 100644 src/Main.hx create mode 100644 src/VectorLayer.hx create mode 100644 src/com/.svn/all-wcprops create mode 100644 src/com/.svn/entries create mode 100644 src/com/.svn/text-base/Button.hx.svn-base create mode 100644 src/com/.svn/text-base/Component.hx.svn-base create mode 100644 src/com/.svn/text-base/InfoBox.hx.svn-base create mode 100644 src/com/.svn/text-base/StatusBar.hx.svn-base create mode 100644 src/com/.svn/text-base/ToolBar.hx.svn-base create mode 100644 src/com/Button.hx create mode 100644 src/com/Component.hx create mode 100644 src/com/InfoBox.hx create mode 100644 src/com/StatusBar.hx create mode 100644 src/com/ToolBar.hx create mode 100644 src/map/.svn/all-wcprops create mode 100644 src/map/.svn/entries create mode 100644 src/map/.svn/text-base/Canvas.hx.svn-base create mode 100644 src/map/.svn/text-base/Layer.hx.svn-base create mode 100644 src/map/.svn/text-base/LngLat.hx.svn-base create mode 100644 src/map/.svn/text-base/MapService.hx.svn-base create mode 100644 src/map/.svn/text-base/QuadTree.hx.svn-base create mode 100644 src/map/.svn/text-base/Tile.hx.svn-base create mode 100644 src/map/.svn/text-base/TileLayer.hx.svn-base create mode 100644 src/map/.svn/text-base/TileLoader.hx.svn-base create mode 100644 src/map/.svn/text-base/Utils.hx.svn-base create mode 100644 src/map/Canvas.hx create mode 100644 src/map/Layer.hx create mode 100644 src/map/LngLat.hx create mode 100644 src/map/MapService.hx create mode 100644 src/map/QuadTree.hx create mode 100644 src/map/Tile.hx create mode 100644 src/map/TileLayer.hx create mode 100644 src/map/TileLoader.hx create mode 100644 src/map/Utils.hx diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..90eada1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,217 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +obj/ + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +build/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +#packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +############# +## Windows detritus +############# + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + + +############# +## Python +############# + +*.py[co] + +# Packages +*.egg +*.egg-info +dist/ +build/ +eggs/ +parts/ +var/ +sdist/ +develop-eggs/ +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg diff --git a/MapTest.hxproj b/MapTest.hxproj new file mode 100644 index 0000000..9e9c471 --- /dev/null +++ b/MapTest.hxproj @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/application.xml b/application.xml new file mode 100644 index 0000000..178f9ea --- /dev/null +++ b/application.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/openfl.svg b/assets/openfl.svg new file mode 100644 index 0000000..506f61d --- /dev/null +++ b/assets/openfl.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + diff --git a/openfl-readme.txt b/openfl-readme.txt new file mode 100644 index 0000000..035191d --- /dev/null +++ b/openfl-readme.txt @@ -0,0 +1,68 @@ +About OpenFL + + OpenFL is the successor of NME, for Haxe 3+. + + Building a game or application with OpenFL is almost like writing for a single platform. However, + when you are ready to publish your application, you can choose between targets like iOS, webOS, + Android, Windows, Mac, Linux and Flash Player. + + Instead of using the lowest common denominator between platforms with a "universal" runtime, + OpenFL projects are compiled as SWF bytecode or C++ applications, using the Haxe language compiler + and the standard C++ compiler toolchain for each platform. + + Read more: + http://openfl.org/ + +Project configuration, libraries, classpaths + + OpenFL configuration is based on a XML file - it allows you very complex + configurations depending on the target platform. There is no GUI for it. + + DO NOT modify FlashDevelop project properties as they will automatically be synchronized with the + XML when you modify it. + +Development + + OpenFL is encouraging to develop using the Flash API (ie. flash.display.Sprite) as in ActionScript 3. + + Just code like you would code a Flash application, with the limitation that you can only use + the drawing API, bitmaps (see below) and TextFields. + + However test often all the platforms you plan to target! + + In OpenFL 3.x, SWFs and videos aren't supported yet. + +Assets + + Place all your images, sounds, fonts in /assets and access them in your code using the + global Assets class which abstracts assets management for all platforms: + + var img = new Bitmap(Assets.getBitmapData("assets/my-image.png")); + addChild(img); + + Tutorials: + https://github.com/openfl/openfl/wiki/Get-Started + +Debugging + + By default your project targets Flash so you'll be able to add breakpoints and debug your app + like any AS3 project. + HTML5 target can be debugged in the browser - some browsers, like Chrome, support "script maps" + which let you interactively debug .hx code directly instead of the generated JS. + There is however no interactive debugger yet for native targets. + +Changing target platform + + For OpenFL projects, an additional drop-down menu appears in the main toolbar where you can choose + a supported targets on Windows: flash, html5, windows, neko, android, webos, blackberry. + You can also manually enter a custom target not in the list. + + Attention, for native targets you'll need to install additional compilers & SDKs. The compiler + will tell you in the Output panel what command to execute for that. More information here: + https://github.com/openfl/openfl/wiki/Get-Started + +Tips: + - in C++ expect first compilation to be very long as it first compiles the whole OpenFL API, + - if a change is not taken in account, delete everything in /bin to start a fresh compilation, + - on mobile, Bitmap blitting is NOT performant, + - use spritesheets and Tilesheet.drawTiles for optimal rendering performance. diff --git a/src/Main.hx b/src/Main.hx new file mode 100644 index 0000000..1e715e1 --- /dev/null +++ b/src/Main.hx @@ -0,0 +1,144 @@ +package ; + +import flash.display.Sprite; +import flash.events.Event; +import flash.Lib; + +import map.Canvas; +import map.LngLat; +import map.MapService; +import com.Button; +import com.ToolBar; + +/** + * ... + * @author eg + */ + +class Main extends Sprite +{ + var inited:Bool; + var canvas:Canvas; + var toolbar:ToolBar; + var layer_osm:map.TileLayer; + + + /* ENTRY POINT */ + + function resize(e) + { + if (!inited) init(); + // else (resize or orientation change) + } + + function init() + { + if (inited) return; + inited = true; + + // (your code here) + toolbar = new ToolBar(); + canvas = new Canvas(); + + toolbar.move(0, 0); + canvas.move(0, 0); +// canvas.setCenter(new LngLat(15.5, 49.5)); + canvas.setCenter(new LngLat(7.4635729, 51.5120542 )); + layer_osm = new map.TileLayer(new OpenStreetMapService(12), 8); + canvas.addLayer(layer_osm); + canvas.addLayer(new VectorLayer(new OpenStreetMapService(12))); + canvas.setZoom(2); + stageResized(null); + + initToolbar(); + + addChild(canvas); + addChild(toolbar); + + canvas.initialize(); + // Stage: + // stage.stageWidth x stage.stageHeight @ stage.dpiScale + + // Assets: + // nme.Assets.getBitmapData("img/assetname.jpg"); + } + + /* SETUP */ + + public function new() + { + super(); + addEventListener(Event.ADDED_TO_STAGE, added); + } + + function added(e) + { + removeEventListener(Event.ADDED_TO_STAGE, added); + stage.addEventListener(Event.RESIZE, resize); + #if ios + haxe.Timer.delay(init, 100); // iOS 6 + #else + init(); + #end + } + public function stageResized(e:Event) + { + toolbar.setSize(flash.Lib.current.stage.stageWidth, 30); + canvas.setSize(flash.Lib.current.stage.stageWidth, flash.Lib.current.stage.stageHeight); + } + + function initToolbar() + { + var me = this; + toolbar.addButton(new ZoomOutButton(), "Zoom Out", function(b:CustomButton) { me.canvas.zoomOut(); }); + toolbar.addButton(new ZoomInButton(), "Zoom In", function(b:CustomButton) { me.canvas.zoomIn(); }); + toolbar.addSeparator(30); + + //pan buttons + toolbar.addButton(new UpButton(), "Move up", function(b:CustomButton) { me.pan(1); }); + toolbar.addButton(new DownButton(), "Move down", function(b:CustomButton) { me.pan(2); }); + toolbar.addButton(new LeftButton(), "Move left", function(b:CustomButton) { me.pan(4); }); + toolbar.addButton(new RightButton(), "Move right", function(b:CustomButton) { me.pan(8); }); + + //layer buttons + toolbar.addSeparator(50); + var me = this; + var tbosm = new TextButton("OSM Layer"); + tbosm.checked = true; + toolbar.addButton(tbosm, "Open Street Map Layer", + function(b:CustomButton) + { + tbosm.checked = !tbosm.checked; + if (tbosm.checked) + me.canvas.enableLayer(me.layer_osm); + else + me.canvas.disableLayer(me.layer_osm); + }); + + } + + function pan(direction:Int) + { + var lt:LngLat = canvas.getLeftTopCorner(); + var br:LngLat = canvas.getRightBottomCorner(); + var p:LngLat = canvas.getCenter(); + + if (direction & 0x3 == 1) p.lat = lt.lat; //up + if (direction & 0x3 == 2) p.lat = br.lat; //down + if (direction & 0xC == 4) p.lng = lt.lng; //left + if (direction & 0xC == 8) p.lng = br.lng; //right + + canvas.panTo(p); + } + + + public static function main() + { + // static entry point + Lib.current.stage.align = flash.display.StageAlign.TOP_LEFT; + Lib.current.stage.scaleMode = flash.display.StageScaleMode.NO_SCALE; + Lib.current.addChild(new Main()); + } +} + + diff --git a/src/VectorLayer.hx b/src/VectorLayer.hx new file mode 100644 index 0000000..cdb7610 --- /dev/null +++ b/src/VectorLayer.hx @@ -0,0 +1,84 @@ +package ; + +/** + * ... + * @author eg + */ +import flash.net.URLLoader; +import flash.net.URLRequest; +import flash.utils.ByteArray; +import flash.geom.Point; +import map.Layer; +import map.QuadTree; +import map.MapService; +import map.LngLat; + +import flash.utils.Timer; +import flash.events.TimerEvent; + +class VectorLayer extends Layer +{ + var data:QuadTree; + var ftimer:Timer; + + public static var COLORS = [0xB2182B, 0xD6604D, 0xF4A582, 0xFDDBC7, 0xE0E0E0, 0xBABABA, 0x878787, 0x4D4D4D]; + + public function new(map_service:MapService = null) + { + super(map_service, false); + + + ftimer = new Timer(100, 1); + ftimer.addEventListener(TimerEvent.TIMER_COMPLETE, redraw); + + data = new QuadTree(); + for (i in 0...100000) + { + var lng:Float = -30 + Math.random()*100; + var lat:Float = Math.random()*80; + var clr:Int = Math.floor(Math.random()*8); + var r:Int = 5 + (1 << Math.floor(i / 10000)); + data.push(lng,lat, {color: COLORS[clr], radius: r}); + } + } + + override function updateContent(forceUpdate:Bool=false) + { + if (ftimer.running) + ftimer.stop(); + + if (forceUpdate) + redraw(null); + else + ftimer.start(); + } + + function redraw(e:TimerEvent) + { + + var zz:Int = this.mapservice.zoom_def + this.zoom; + var scale:Float = Math.pow(2.0, this.zoom); + var l2pt = this.mapservice.lonlat2XY; + var cpt:Point = l2pt(center.lng, center.lat, zz); + var pt:Point; + + graphics.clear(); + var lt:LngLat = getLeftTopCorner(); + var rb:LngLat = getRightBottomCorner(); + + //var data:Array = data.getData(lt.lng, rb.lat, rb.lng, lt.lat); + + var minsz:Float = 1.0/scale; + var data:Array = data.getFilteredData(lt.lng, rb.lat, rb.lng, lt.lat, function(q:QuadData):Bool { return q.data.radius > minsz;}); //return scale*q.data.radius > 0.8;}); + + var r:Float; + for (d in data) + { + r = scale*d.data.radius; + pt = l2pt(d.x, d.y, zz); + graphics.lineStyle(r/2.0, d.data.color); + graphics.drawRect((pt.x - cpt.x), (pt.y - cpt.y), r, r); + } + } +} + diff --git a/src/com/.svn/all-wcprops b/src/com/.svn/all-wcprops new file mode 100644 index 0000000..e604341 --- /dev/null +++ b/src/com/.svn/all-wcprops @@ -0,0 +1,35 @@ +K 25 +svn:wc:ra_dav:version-url +V 34 +/svn/!svn/ver/2/trunk/haxemaps/com +END +ToolBar.hx +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/2/trunk/haxemaps/com/ToolBar.hx +END +Component.hx +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/2/trunk/haxemaps/com/Component.hx +END +InfoBox.hx +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/2/trunk/haxemaps/com/InfoBox.hx +END +StatusBar.hx +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/2/trunk/haxemaps/com/StatusBar.hx +END +Button.hx +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/2/trunk/haxemaps/com/Button.hx +END diff --git a/src/com/.svn/entries b/src/com/.svn/entries new file mode 100644 index 0000000..b6d0183 --- /dev/null +++ b/src/com/.svn/entries @@ -0,0 +1,198 @@ +10 + +dir +5 +http://haxemaps.googlecode.com/svn/trunk/haxemaps/com +http://haxemaps.googlecode.com/svn + + + +2010-03-13T13:28:15.676966Z +2 +vzdenek@seznam.cz + + + + + + + + + + + + + + +91f78bee-1f10-11df-98cf-3116c4ba2102 + +ToolBar.hx +file + + + + +2013-10-31T20:25:13.036822Z +f63f6e1f506d7050025455765d853700 +2010-03-13T13:28:15.676966Z +2 +vzdenek@seznam.cz + + + + + + + + + + + + + + + + + + + + + +4689 + +Component.hx +file + + + + +2013-10-31T20:25:13.037822Z +6b0e56f8b02c722dcd3d892d18fcafef +2010-03-13T13:28:15.676966Z +2 +vzdenek@seznam.cz + + + + + + + + + + + + + + + + + + + + + +2492 + +InfoBox.hx +file + + + + +2013-10-31T20:25:13.039822Z +f3f33a827212d17d0141fbc7560a062a +2010-03-13T13:28:15.676966Z +2 +vzdenek@seznam.cz + + + + + + + + + + + + + + + + + + + + + +2906 + +StatusBar.hx +file + + + + +2013-10-31T20:25:13.041822Z +6cff2c873e5e84bd5523cc0acf268a2a +2010-03-13T13:28:15.676966Z +2 +vzdenek@seznam.cz + + + + + + + + + + + + + + + + + + + + + +3125 + +Button.hx +file + + + + +2013-10-31T20:25:13.043822Z +a3ee19a4df6b6daab7e946198e0e89f5 +2010-03-13T13:28:15.676966Z +2 +vzdenek@seznam.cz + + + + + + + + + + + + + + + + + + + + + +12485 + diff --git a/src/com/.svn/text-base/Button.hx.svn-base b/src/com/.svn/text-base/Button.hx.svn-base new file mode 100644 index 0000000..59f3364 --- /dev/null +++ b/src/com/.svn/text-base/Button.hx.svn-base @@ -0,0 +1,431 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package com; + +import flash.display.Shape; +import flash.display.Graphics; +import flash.display.SimpleButton; +import flash.display.BitmapData; +import flash.events.MouseEvent; +import flash.filters.GlowFilter; + + +class UpButton extends CustomButton { + + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) { + var h:Float = (2*szh/5.0)/2; + + g.beginFill(color); + g.moveTo(midx-4, midy+h); + g.lineTo(midx+4, midy+h); + g.lineTo(midx, midy-h); + g.endFill(); + + if (Std.is(this, RightButton)) { + curshape.rotation = 90; + curshape.x += szh; + } + + if (Std.is(this, LeftButton)) { + curshape.rotation = 270; + curshape.y += szh; + } + + if (Std.is(this, DownButton)) { + curshape.rotation = 180; + curshape.y += szh; + curshape.x += szw; + } + + } +} + +class RightButton extends UpButton +{ +} + +class LeftButton extends UpButton +{ +} + +class DownButton extends UpButton +{ +} + +class BarButton extends CustomButton +{ + + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) + { + var h:Float = (szh/2.0)/2; + + g.lineStyle(4, color); + g.moveTo(midx, midy-h); + g.lineTo(midx, midy+h); + + } + +} + +class PauseButton extends CustomButton +{ + + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) + { + var h:Float = (szh/2.5)/2; + + g.lineStyle(2, color); + g.moveTo(midx-2, midy-h); + g.lineTo(midx-2, midy+h); + g.moveTo(midx+2, midy-h); + g.lineTo(midx+2, midy+h); + + } + +} + + + +class SaveButton extends CustomButton +{ + + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) + { + var h:Float = (szh/2.0)/2; + + g.beginFill(color); + g.moveTo(midx-h, midy-h); + g.lineTo(midx+h, midy-h); + g.lineTo(midx+h, midy+h); + g.lineTo(midx+h-h/2.0, midy+h); + g.lineTo(midx+h-h/2.0, midy+h-h/2); + g.lineTo(midx-h+h/2.0, midy+h-h/2); + g.lineTo(midx-h+h/2.0, midy+h); + g.lineTo(midx-h, midy+h); + g.drawRect(midx-h+h/2.0+1, midy+h-h/2+1, h/2, h/2-1); + g.endFill(); + } + +} + +class PrintButton extends CustomButton +{ + + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) + { + var h:Float = (szh/1.5)/2; + var oy:Float = -3; + + g.beginFill(color); + g.moveTo(midx-h, midy+oy); + g.lineTo(midx-h+h/2.0, midy+oy); + g.lineTo(midx-h+h/2.0, midy+h-h/1.5+oy); + g.lineTo(midx+h-h/2.0, midy+h-h/1.5+oy); + g.lineTo(midx+h-h/2.0, midy+oy); + g.lineTo(midx+h, midy+oy); + g.lineTo(midx+h, midy+h+oy); + g.lineTo(midx-h, midy+h+oy); + + g.drawRect(midx-h+h/2.0+1, midy-h/2.5+oy, h/2+1, h/2.5+h/1.5-1); + g.drawRect(midx-h+h/2.0, midy+h+0.5+oy, h, 2); + + g.endFill(); + } + +} + +class MaximizeButton extends CustomButton +{ + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) + { + var h:Float = (szh/3.0)/2; // 1/4 vysky zabira symbol + g.lineStyle(4, 0x888888); + g.drawRect(midx-h-1, midy-h-1,2*h+2,2*h+2); + + g.lineStyle(2, color); + g.drawRect(midx-h-1, midy-h-1,2*h+2,2*h+2); + + } +} + +class ZoomInButton extends CustomButton +{ + + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) + { + var h:Float = (szh/4.0)/2; // 1/4 vysky zabira symbol + + g.lineStyle(2, color); + g.moveTo(midx, midy); + g.lineTo(midx+h+4, midy+h+4); + + #if flash9 + g.moveTo(midx,midy); //bugfix + #end + g.beginFill(0x888888); + g.drawCircle(midx, midy, 2*h); + g.endFill(); + + if (Std.is(this, SearchButton)) + return; + + g.moveTo(midx-h, midy); + g.lineTo(midx+h, midy); + + if (!Std.is(this, ZoomOutButton)) + { + g.moveTo(midx, midy-h); + g.lineTo(midx, midy+h); + } + + } +} + +class ZoomOutButton extends ZoomInButton +{ +} + + +class SearchButton extends ZoomInButton +{ +} + +class TextButton extends CustomButton { + + var text:String; + + public function new(text:String = "", width:Int = 45, size:Int = 25, bgColor:Null = null, bgColorHover:Null = null, fgColor:Int = 0xEEEEEE) + { + this.text = text; + super(size, bgColor, bgColorHover, fgColor); + this.szw = width; + updateShapes(); + } + + + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) + { + g.clear(); + + var tf:flash.text.TextField = new flash.text.TextField(); + tf.textColor = 0xFFFFFF; + tf.background = false; + tf.border = false; + tf.autoSize = flash.text.TextFieldAutoSize.LEFT; + var fmt = new flash.text.TextFormat(); + fmt.font = "Arial"; + fmt.size = 11; + fmt.bold = true; + tf.defaultTextFormat = fmt; + tf.text = this.text; + + var bd:BitmapData = new BitmapData(Std.int(tf.width),Std.int(tf.height), true, 0x00FFFFFF); + bd.draw(tf); + + g.lineStyle(Math.NaN); + g.beginBitmapFill(bd, null, false); + g.drawRect(0, 0, bd.width, bd.height); + g.endFill(); + + if (checked) + { + g.lineStyle(2, 0xFFFFFF); + g.moveTo(0, bd.height+2); + g.lineTo(bd.width, bd.height+2); + } + } +} + +class CustomButton extends SimpleButton { + + var fgColor:Int; + var szw:Float; + var szh:Float; + var shint:Shape; + var curshape:Shape; + var canupdate:Bool; + public var hint:String; + public var checked(default, setChecked):Bool; + public var onClick:Dynamic; + public var bgColor(default, setBgColor):Null; + public var bgColorHover(default, setBgColorHover):Null; + + public function new(size:Int = 25, bgColor:Null = null, bgColorHover:Null = null, fgColor:Int = 0xEEEEEE)//0x007BC8) + { + super(); + this.canupdate = false; + downState = overState = upState = hitTestState = null; + this.bgColor = bgColor; + this.bgColorHover = bgColorHover; + this.fgColor = fgColor; + this.szw = (size == 0) ? 4 : size; + this.szh = (size == 0) ? 25 : size; + this.shint = null; + this.hint = ""; + this.canupdate = true; + updateShapes(); + + useHandCursor = true; + onClick = null; + checked = false; + + addEventListener(MouseEvent.CLICK, clicked); + addEventListener(MouseEvent.MOUSE_OVER, mouseOver); + + } + + function mouseOver(e:MouseEvent) + { + removeEventListener(MouseEvent.MOUSE_OVER, mouseOver); + addEventListener(MouseEvent.MOUSE_OUT, mouseOut); + + if (this.hint == "") return; + + var tf:flash.text.TextField = new flash.text.TextField(); + tf.autoSize = flash.text.TextFieldAutoSize.LEFT; + tf.text = hint; + + var bd:BitmapData = new BitmapData(Std.int(tf.width),Std.int(tf.height), true, 0x00FFFFFF); //w,h + bd.draw(tf); + + shint = new Shape(); + shint.graphics.lineStyle(1,0x808080); + shint.graphics.beginFill(0xFDFECB); + shint.graphics.drawRect(-2,-2, bd.width+4, bd.height+4); + shint.graphics.endFill(); + + shint.graphics.lineStyle(Math.NaN); + shint.graphics.beginBitmapFill(bd, null, false); + shint.graphics.drawRect(0, 0, bd.width, bd.height); + shint.graphics.endFill(); + + var p:flash.geom.Point = localToGlobal(new flash.geom.Point(szw/2, szh+10)); + if (p.x + shint.width > flash.Lib.current.stage.stageWidth) p.x = flash.Lib.current.stage.stageWidth - shint.width; + if (p.y + shint.height > flash.Lib.current.stage.stageHeight) p.y = flash.Lib.current.stage.stageHeight - shint.height - szh; + if (p.y < 2) p.y = 2; + shint.x = p.x; shint.y = p.y; + + flash.Lib.current.stage.addChild(shint); + } + + function mouseOut(e:MouseEvent) + { + if (shint != null) { + flash.Lib.current.stage.removeChild(shint); + shint = null; + } + + removeEventListener(MouseEvent.MOUSE_OUT, mouseOut); + addEventListener(MouseEvent.MOUSE_OVER, mouseOver); + } + + function setBgColor(val:Null) : Null + { + if (val != bgColor) { + bgColor = val; + updateShapes(); + } + return val; + } + + function setBgColorHover(val:Null) : Null + { + if (val != bgColorHover) { + bgColorHover = val; + updateShapes(); + } + return val; + } + + function setChecked(val:Bool) : Bool + { + if (val != checked) { + checked = val; + updateShapes(); + } + return val; + } + + function updateShapes() + { + if (!this.canupdate) return; + downState = getShape(bgColorHover, fgColor, true); + overState = getShape(checked ? 0xFF8000 : bgColorHover, 0xeeeeee /*fgColor*/); + overState.filters = [new GlowFilter(0xFFFFFF, 0.75, 5, 5, 2, 2, false, false)]; + upState = getShape(checked ? 0xFF8000 : bgColor, fgColor); + hitTestState = getHitTestShape(); + } + + public function setSize(w:Float, h:Float) + { + szw = w; + szh = h; + updateShapes(); + } + + function clicked(event:MouseEvent) { + if (onClick) + onClick(this); + } + + function getHitTestShape() { + var s = new Shape(); + + s.graphics.beginFill(0x000000); + s.graphics.drawRect(0, 0, szw, szh); + s.graphics.endFill(); + + return s; + } + + function getShape(bgColor:Null, fgColor:Int, ?down:Bool = false):Shape { + curshape = new Shape(); + + if (bgColor != null) + { + curshape.graphics.beginFill(bgColor); + curshape.graphics.drawRect(0, 0, szw, szh); + curshape.graphics.endFill(); + } + + var x:Float = szw/2; + var y:Float = szh/2; + + if (down) { x += 1; y += 1; } + + drawSymbol(curshape.graphics, fgColor, x, y, down); + + return curshape; + } + + function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) { + } +} diff --git a/src/com/.svn/text-base/Component.hx.svn-base b/src/com/.svn/text-base/Component.hx.svn-base new file mode 100644 index 0000000..60a6979 --- /dev/null +++ b/src/com/.svn/text-base/Component.hx.svn-base @@ -0,0 +1,74 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package com; + +import flash.display.Sprite; +import flash.geom.Rectangle; + +typedef ComponentSize = { + var width : Float; + var height : Float; +}; + + +class Component extends Sprite +{ + var _size : ComponentSize; + + public function new() + { + super(); + + this._size = {width: 100.0, height:100.0}; + } + + public function move(x:Float, y:Float) + { + this.x = x; + this.y = y; + } + + public function setSize(w:Float, h:Float) + { + this._size.width = w; + this._size.height = h; + this.onResize(w, h); + } + + public function getSize() : ComponentSize + { + return this._size; + } + + function onResize(w:Float, h:Float) + { + } +} diff --git a/src/com/.svn/text-base/InfoBox.hx.svn-base b/src/com/.svn/text-base/InfoBox.hx.svn-base new file mode 100644 index 0000000..30e7238 --- /dev/null +++ b/src/com/.svn/text-base/InfoBox.hx.svn-base @@ -0,0 +1,86 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package com; + +import com.Component; +import flash.text.TextField; + +class InfoBox extends Component +{ + var ofsy : Float; + var maxw : Float; + + public function new() + { + super(); + this.ofsy = 0; + this.maxw = 0; + } + + public function addItem(text:String) : TextField + { + var sz = getSize(); + + var fmt = new flash.text.TextFormat(); + fmt.font="Arial"; + fmt.size=12; + fmt.color = 0xFFFFFF; + + var tf = new TextField(); + tf.defaultTextFormat = fmt; + tf.x = 2; + tf.y = this.ofsy; + tf.autoSize = flash.text.TextFieldAutoSize.LEFT; + tf.multiline = false; + tf.text = text; + tf.border = false; + tf.background = false; + + addChild(tf); + + if (tf.width > this.maxw) this.maxw = tf.width; + + this.ofsy += tf.height + 1; + + update(); + + return tf; + } + + function update() + { + graphics.clear(); + graphics.beginFill(0x000000, 0.5); + graphics.drawRect(0,0, this.maxw + 4, this.ofsy); + graphics.endFill(); + } + +} diff --git a/src/com/.svn/text-base/StatusBar.hx.svn-base b/src/com/.svn/text-base/StatusBar.hx.svn-base new file mode 100644 index 0000000..a7833ee --- /dev/null +++ b/src/com/.svn/text-base/StatusBar.hx.svn-base @@ -0,0 +1,94 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package com; +import flash.text.TextField; +import flash.text.TextFormat; +import flash.utils.Timer; +import flash.events.TimerEvent; +import com.Component; + +class StatusBar extends Component +{ + var text:TextField; + var timer:Timer; + + public function new() + { + var format = new TextFormat(); + format.font = "Arial"; + format.size = 12; + + text = new TextField(); + text.defaultTextFormat = format; + text.selectable = false; + text.border = false; + text.background = false; + text.textColor = 0x444444; + text.autoSize = flash.text.TextFieldAutoSize.LEFT; + text.text = ''; + text.x = 2; + text.x = 2; + this.addChild(text); + + timer = new Timer(2000, 1); + timer.addEventListener(TimerEvent.TIMER, timeOut); + + super(); + } + + public function clear() + { + text.text = ''; + } + + public function setText(s:String) + { + text.text = s; + + if (timer.running) + timer.stop(); + timer.start(); + } + + function timeOut(e:flash.events.Event) + { + clear(); + } + + override function onResize(w:Float, h:Float) + { + graphics.clear(); + graphics.beginFill(0xE0E0E0); + graphics.drawRect(0,0,w, h); + graphics.endFill(); + } + +} diff --git a/src/com/.svn/text-base/ToolBar.hx.svn-base b/src/com/.svn/text-base/ToolBar.hx.svn-base new file mode 100644 index 0000000..0773c59 --- /dev/null +++ b/src/com/.svn/text-base/ToolBar.hx.svn-base @@ -0,0 +1,153 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package com; + +import com.Component; +import com.Button; +import flash.text.TextField; + +class ToolBar extends Component +{ + var ofsx: Float; + var spacing: Float; + var tf: TextField; + + public function new(leftmargin:Float = 10, spacing:Float = 15) + { + super(); + + this.spacing = spacing; + this.ofsx = leftmargin; + + tf = new TextField(); + tf.y = 5; + tf.autoSize = flash.text.TextFieldAutoSize.LEFT; + tf.text = ""; + + var fmt = new flash.text.TextFormat(); + fmt.font="Arial"; + fmt.size=12; + fmt.color = 0xFFFFFF; + tf.defaultTextFormat = fmt; + + addChild(tf); + + } + + public function addButton(btn:CustomButton, hint:String = "", onClick:CustomButton->Void = null, space:Int = 0) : CustomButton + { + var sz = getSize(); + + btn.x = this.ofsx; + btn.y = 2; + btn.hint = hint; + btn.onClick = onClick; + addChild(btn); + + this.ofsx += btn.width + this.spacing + space; + + return btn; + } + + public function addTextField(width:Int = 100, text:String = "", label:String = "", space:Int = 0) : TextField + { + var sz = getSize(); + + if (label != "") + { + var tf = new TextField(); + tf.y = 5; + tf.x = this.ofsx; + tf.autoSize = flash.text.TextFieldAutoSize.LEFT; + + var fmt = new flash.text.TextFormat(); + fmt.font="Arial"; + fmt.size=12; + fmt.color = 0xFFFFFF; + tf.defaultTextFormat = fmt; + tf.text = label; + + addChild(tf); + + this.ofsx += tf.width + 5; + + } + + var tf = new TextField(); + tf.x = this.ofsx; + tf.y = 5; + tf.width = width; + tf.height = sz.height - 10; + tf.autoSize = flash.text.TextFieldAutoSize.NONE; + tf.border = false; + tf.background = true; + tf.backgroundColor = 0xFFFFFF; + tf.multiline = false; + tf.type = flash.text.TextFieldType.INPUT; + tf.mouseWheelEnabled = false; + + var fmt = new flash.text.TextFormat(); + fmt.font="Arial"; + fmt.size=12; + fmt.color = 0x000000; + tf.defaultTextFormat = fmt; + tf.text = text; + + addChild(tf); + this.ofsx += width + this.spacing + space; + + return tf; + } + + public function addSeparator(size:Int = 10) + { + ofsx += size; + } + + public function setText(text:String) + { + var sz = getSize(); + + tf.text = text; + tf.x = sz.width - tf.width - 10; + } + + override function onResize(w:Float, h:Float) + { + graphics.clear(); + graphics.beginFill(0x000000, 0.5); + graphics.drawRect(0,0, w, h); + graphics.endFill(); + + tf.x = w - tf.width - 10; + } + +} diff --git a/src/com/Button.hx b/src/com/Button.hx new file mode 100644 index 0000000..3b275aa --- /dev/null +++ b/src/com/Button.hx @@ -0,0 +1,431 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package com; + +import flash.display.Shape; +import flash.display.Graphics; +import flash.display.SimpleButton; +import flash.display.BitmapData; +import flash.events.MouseEvent; +import flash.filters.GlowFilter; + + +class UpButton extends CustomButton { + + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) { + var h:Float = (2*szh/5.0)/2; + + g.beginFill(color); + g.moveTo(midx-4, midy+h); + g.lineTo(midx+4, midy+h); + g.lineTo(midx, midy-h); + g.endFill(); + + if (Std.is(this, RightButton)) { + curshape.rotation = 90; + curshape.x += szh; + } + + if (Std.is(this, LeftButton)) { + curshape.rotation = 270; + curshape.y += szh; + } + + if (Std.is(this, DownButton)) { + curshape.rotation = 180; + curshape.y += szh; + curshape.x += szw; + } + + } +} + +class RightButton extends UpButton +{ +} + +class LeftButton extends UpButton +{ +} + +class DownButton extends UpButton +{ +} + +class BarButton extends CustomButton +{ + + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) + { + var h:Float = (szh/2.0)/2; + + g.lineStyle(4, color); + g.moveTo(midx, midy-h); + g.lineTo(midx, midy+h); + + } + +} + +class PauseButton extends CustomButton +{ + + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) + { + var h:Float = (szh/2.5)/2; + + g.lineStyle(2, color); + g.moveTo(midx-2, midy-h); + g.lineTo(midx-2, midy+h); + g.moveTo(midx+2, midy-h); + g.lineTo(midx+2, midy+h); + + } + +} + + + +class SaveButton extends CustomButton +{ + + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) + { + var h:Float = (szh/2.0)/2; + + g.beginFill(color); + g.moveTo(midx-h, midy-h); + g.lineTo(midx+h, midy-h); + g.lineTo(midx+h, midy+h); + g.lineTo(midx+h-h/2.0, midy+h); + g.lineTo(midx+h-h/2.0, midy+h-h/2); + g.lineTo(midx-h+h/2.0, midy+h-h/2); + g.lineTo(midx-h+h/2.0, midy+h); + g.lineTo(midx-h, midy+h); + g.drawRect(midx-h+h/2.0+1, midy+h-h/2+1, h/2, h/2-1); + g.endFill(); + } + +} + +class PrintButton extends CustomButton +{ + + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) + { + var h:Float = (szh/1.5)/2; + var oy:Float = -3; + + g.beginFill(color); + g.moveTo(midx-h, midy+oy); + g.lineTo(midx-h+h/2.0, midy+oy); + g.lineTo(midx-h+h/2.0, midy+h-h/1.5+oy); + g.lineTo(midx+h-h/2.0, midy+h-h/1.5+oy); + g.lineTo(midx+h-h/2.0, midy+oy); + g.lineTo(midx+h, midy+oy); + g.lineTo(midx+h, midy+h+oy); + g.lineTo(midx-h, midy+h+oy); + + g.drawRect(midx-h+h/2.0+1, midy-h/2.5+oy, h/2+1, h/2.5+h/1.5-1); + g.drawRect(midx-h+h/2.0, midy+h+0.5+oy, h, 2); + + g.endFill(); + } + +} + +class MaximizeButton extends CustomButton +{ + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) + { + var h:Float = (szh/3.0)/2; // 1/4 vysky zabira symbol + g.lineStyle(4, 0x888888); + g.drawRect(midx-h-1, midy-h-1,2*h+2,2*h+2); + + g.lineStyle(2, color); + g.drawRect(midx-h-1, midy-h-1,2*h+2,2*h+2); + + } +} + +class ZoomInButton extends CustomButton +{ + + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) + { + var h:Float = (szh/4.0)/2; // 1/4 vysky zabira symbol + + g.lineStyle(2, color); + g.moveTo(midx, midy); + g.lineTo(midx+h+4, midy+h+4); + + #if flash9 + g.moveTo(midx,midy); //bugfix + #end + g.beginFill(0x888888); + g.drawCircle(midx, midy, 2*h); + g.endFill(); + + if (Std.is(this, SearchButton)) + return; + + g.moveTo(midx-h, midy); + g.lineTo(midx+h, midy); + + if (!Std.is(this, ZoomOutButton)) + { + g.moveTo(midx, midy-h); + g.lineTo(midx, midy+h); + } + + } +} + +class ZoomOutButton extends ZoomInButton +{ +} + + +class SearchButton extends ZoomInButton +{ +} + +class TextButton extends CustomButton { + + var text:String; + + public function new(text:String = "", width:Int = 45, size:Int = 25, bgColor:Null = null, bgColorHover:Null = null, fgColor:Int = 0xEEEEEE) + { + this.text = text; + super(size, bgColor, bgColorHover, fgColor); + this.szw = width; + updateShapes(); + } + + + override function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) + { + g.clear(); + + var tf:flash.text.TextField = new flash.text.TextField(); + tf.textColor = 0xFFFFFF; + tf.background = false; + tf.border = false; + tf.autoSize = flash.text.TextFieldAutoSize.LEFT; + var fmt = new flash.text.TextFormat(); + fmt.font = "Arial"; + fmt.size = 11; + fmt.bold = true; + tf.defaultTextFormat = fmt; + tf.text = this.text; + + var bd:BitmapData = new BitmapData(Std.int(tf.width),Std.int(tf.height), true, 0x00FFFFFF); + bd.draw(tf); + + g.lineStyle(Math.NaN); + g.beginBitmapFill(bd, null, false); + g.drawRect(0, 0, bd.width, bd.height); + g.endFill(); + + if (checked) + { + g.lineStyle(2, 0xFFFFFF); + g.moveTo(0, bd.height+2); + g.lineTo(bd.width, bd.height+2); + } + } +} + +class CustomButton extends SimpleButton { + + var fgColor:Int; + var szw:Float; + var szh:Float; + var shint:Shape; + var curshape:Shape; + var canupdate:Bool; + public var hint:String; + public var checked:Bool; + public var onClick:Dynamic; + public var bgColor:Null; + public var bgColorHover:Null; + + public function new(size:Int = 25, bgColor:Null = null, bgColorHover:Null = null, fgColor:Int = 0xEEEEEE)//0x007BC8) + { + super(); + this.canupdate = false; + downState = overState = upState = hitTestState = null; + this.bgColor = bgColor; + this.bgColorHover = bgColorHover; + this.fgColor = fgColor; + this.szw = (size == 0) ? 4 : size; + this.szh = (size == 0) ? 25 : size; + this.shint = null; + this.hint = ""; + this.canupdate = true; + updateShapes(); + + useHandCursor = true; + onClick = null; + checked = false; + + addEventListener(MouseEvent.CLICK, clicked); + addEventListener(MouseEvent.MOUSE_OVER, mouseOver); + + } + + function mouseOver(e:MouseEvent) + { + removeEventListener(MouseEvent.MOUSE_OVER, mouseOver); + addEventListener(MouseEvent.MOUSE_OUT, mouseOut); + + if (this.hint == "") return; + + var tf:flash.text.TextField = new flash.text.TextField(); + tf.autoSize = flash.text.TextFieldAutoSize.LEFT; + tf.text = hint; + + var bd:BitmapData = new BitmapData(Std.int(tf.width),Std.int(tf.height), true, 0x00FFFFFF); //w,h + bd.draw(tf); + + shint = new Shape(); + shint.graphics.lineStyle(1,0x808080); + shint.graphics.beginFill(0xFDFECB); + shint.graphics.drawRect(-2,-2, bd.width+4, bd.height+4); + shint.graphics.endFill(); + + shint.graphics.lineStyle(Math.NaN); + shint.graphics.beginBitmapFill(bd, null, false); + shint.graphics.drawRect(0, 0, bd.width, bd.height); + shint.graphics.endFill(); + + var p:flash.geom.Point = localToGlobal(new flash.geom.Point(szw/2, szh+10)); + if (p.x + shint.width > flash.Lib.current.stage.stageWidth) p.x = flash.Lib.current.stage.stageWidth - shint.width; + if (p.y + shint.height > flash.Lib.current.stage.stageHeight) p.y = flash.Lib.current.stage.stageHeight - shint.height - szh; + if (p.y < 2) p.y = 2; + shint.x = p.x; shint.y = p.y; + + flash.Lib.current.stage.addChild(shint); + } + + function mouseOut(e:MouseEvent) + { + if (shint != null) { + flash.Lib.current.stage.removeChild(shint); + shint = null; + } + + removeEventListener(MouseEvent.MOUSE_OUT, mouseOut); + addEventListener(MouseEvent.MOUSE_OVER, mouseOver); + } + + function set_BgColor(val:Null) : Null + { + if (val != bgColor) { + bgColor = val; + updateShapes(); + } + return val; + } + + function set_bgColorHover(val:Null) : Null + { + if (val != bgColorHover) { + bgColorHover = val; + updateShapes(); + } + return val; + } + + function set_checked(val:Bool) : Bool + { + if (val != checked) { + checked = val; + updateShapes(); + } + return val; + } + + function updateShapes() + { + if (!this.canupdate) return; + downState = getShape(bgColorHover, fgColor, true); + overState = getShape(checked ? 0xFF8000 : bgColorHover, 0xeeeeee /*fgColor*/); + overState.filters = [new GlowFilter(0xFFFFFF, 0.75, 5, 5, 2, 2, false, false)]; + upState = getShape(checked ? 0xFF8000 : bgColor, fgColor); + hitTestState = getHitTestShape(); + } + + public function setSize(w:Float, h:Float) + { + szw = w; + szh = h; + updateShapes(); + } + + function clicked(event:MouseEvent) { + if (onClick) + onClick(this); + } + + function getHitTestShape() { + var s = new Shape(); + + s.graphics.beginFill(0x000000); + s.graphics.drawRect(0, 0, szw, szh); + s.graphics.endFill(); + + return s; + } + + function getShape(bgColor:Null, fgColor:Int, ?down:Bool = false):Shape { + curshape = new Shape(); + + if (bgColor != null) + { + curshape.graphics.beginFill(bgColor); + curshape.graphics.drawRect(0, 0, szw, szh); + curshape.graphics.endFill(); + } + + var x:Float = szw/2; + var y:Float = szh/2; + + if (down) { x += 1; y += 1; } + + drawSymbol(curshape.graphics, fgColor, x, y, down); + + return curshape; + } + + function drawSymbol(g:Graphics, color:Int, midx:Float, midy:Float, down:Bool) { + } +} diff --git a/src/com/Component.hx b/src/com/Component.hx new file mode 100644 index 0000000..60a6979 --- /dev/null +++ b/src/com/Component.hx @@ -0,0 +1,74 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package com; + +import flash.display.Sprite; +import flash.geom.Rectangle; + +typedef ComponentSize = { + var width : Float; + var height : Float; +}; + + +class Component extends Sprite +{ + var _size : ComponentSize; + + public function new() + { + super(); + + this._size = {width: 100.0, height:100.0}; + } + + public function move(x:Float, y:Float) + { + this.x = x; + this.y = y; + } + + public function setSize(w:Float, h:Float) + { + this._size.width = w; + this._size.height = h; + this.onResize(w, h); + } + + public function getSize() : ComponentSize + { + return this._size; + } + + function onResize(w:Float, h:Float) + { + } +} diff --git a/src/com/InfoBox.hx b/src/com/InfoBox.hx new file mode 100644 index 0000000..30e7238 --- /dev/null +++ b/src/com/InfoBox.hx @@ -0,0 +1,86 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package com; + +import com.Component; +import flash.text.TextField; + +class InfoBox extends Component +{ + var ofsy : Float; + var maxw : Float; + + public function new() + { + super(); + this.ofsy = 0; + this.maxw = 0; + } + + public function addItem(text:String) : TextField + { + var sz = getSize(); + + var fmt = new flash.text.TextFormat(); + fmt.font="Arial"; + fmt.size=12; + fmt.color = 0xFFFFFF; + + var tf = new TextField(); + tf.defaultTextFormat = fmt; + tf.x = 2; + tf.y = this.ofsy; + tf.autoSize = flash.text.TextFieldAutoSize.LEFT; + tf.multiline = false; + tf.text = text; + tf.border = false; + tf.background = false; + + addChild(tf); + + if (tf.width > this.maxw) this.maxw = tf.width; + + this.ofsy += tf.height + 1; + + update(); + + return tf; + } + + function update() + { + graphics.clear(); + graphics.beginFill(0x000000, 0.5); + graphics.drawRect(0,0, this.maxw + 4, this.ofsy); + graphics.endFill(); + } + +} diff --git a/src/com/StatusBar.hx b/src/com/StatusBar.hx new file mode 100644 index 0000000..a7833ee --- /dev/null +++ b/src/com/StatusBar.hx @@ -0,0 +1,94 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package com; +import flash.text.TextField; +import flash.text.TextFormat; +import flash.utils.Timer; +import flash.events.TimerEvent; +import com.Component; + +class StatusBar extends Component +{ + var text:TextField; + var timer:Timer; + + public function new() + { + var format = new TextFormat(); + format.font = "Arial"; + format.size = 12; + + text = new TextField(); + text.defaultTextFormat = format; + text.selectable = false; + text.border = false; + text.background = false; + text.textColor = 0x444444; + text.autoSize = flash.text.TextFieldAutoSize.LEFT; + text.text = ''; + text.x = 2; + text.x = 2; + this.addChild(text); + + timer = new Timer(2000, 1); + timer.addEventListener(TimerEvent.TIMER, timeOut); + + super(); + } + + public function clear() + { + text.text = ''; + } + + public function setText(s:String) + { + text.text = s; + + if (timer.running) + timer.stop(); + timer.start(); + } + + function timeOut(e:flash.events.Event) + { + clear(); + } + + override function onResize(w:Float, h:Float) + { + graphics.clear(); + graphics.beginFill(0xE0E0E0); + graphics.drawRect(0,0,w, h); + graphics.endFill(); + } + +} diff --git a/src/com/ToolBar.hx b/src/com/ToolBar.hx new file mode 100644 index 0000000..3af5bf2 --- /dev/null +++ b/src/com/ToolBar.hx @@ -0,0 +1,153 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package com; + +import com.Component; +import com.Button; +import flash.text.TextField; + +class ToolBar extends Component +{ + var ofsx: Float; + var spacing: Float; + var tf: TextField; + + public function new(leftmargin:Float = 10, spacing:Float = 15) + { + super(); + + this.spacing = spacing; + this.ofsx = leftmargin; + + tf = new TextField(); + tf.y = 5; + tf.autoSize = flash.text.TextFieldAutoSize.LEFT; + tf.text = ""; + + var fmt = new flash.text.TextFormat(); + fmt.font="Arial"; + fmt.size=12; + fmt.color = 0xFFFFFF; + tf.defaultTextFormat = fmt; + + addChild(tf); + + } + + public function addButton(btn:CustomButton, hint:String = "", onClick:CustomButton->Void = null, space:Int = 0) : CustomButton + { + var sz = getSize(); + + btn.x = this.ofsx; + btn.y = 2; + btn.hint = hint; + btn.onClick = onClick; + addChild(btn); + + this.ofsx += btn.width + this.spacing + space; + + return btn; + } + + public function addTextField(width:Int = 100, text:String = "", label:String = "", space:Int = 0) : TextField + { + var sz = getSize(); + + if (label != "") + { + var tf = new TextField(); + tf.y = 5; + tf.x = this.ofsx; + tf.autoSize = flash.text.TextFieldAutoSize.LEFT; + + var fmt = new flash.text.TextFormat(); + fmt.font="Arial"; + fmt.size=12; + fmt.color = 0xFFFFFF; + tf.defaultTextFormat = fmt; + tf.text = label; + + addChild(tf); + + this.ofsx += tf.width + 5; + + } + + var tf = new TextField(); + tf.x = this.ofsx; + tf.y = 5; + tf.width = width; + tf.height = sz.height - 10; + tf.autoSize = flash.text.TextFieldAutoSize.NONE; + tf.border = false; + tf.background = true; + tf.backgroundColor = 0xFFFFFF; + tf.multiline = false; + tf.type = flash.text.TextFieldType.INPUT; + // tf.mouseWheelEnabled = false; + + var fmt = new flash.text.TextFormat(); + fmt.font="Arial"; + fmt.size=12; + fmt.color = 0x000000; + tf.defaultTextFormat = fmt; + tf.text = text; + + addChild(tf); + this.ofsx += width + this.spacing + space; + + return tf; + } + + public function addSeparator(size:Int = 10) + { + ofsx += size; + } + + public function setText(text:String) + { + var sz = getSize(); + + tf.text = text; + tf.x = sz.width - tf.width - 10; + } + + override function onResize(w:Float, h:Float) + { + graphics.clear(); + graphics.beginFill(0x000000, 0.5); + graphics.drawRect(0,0, w, h); + graphics.endFill(); + + tf.x = w - tf.width - 10; + } + +} diff --git a/src/map/.svn/all-wcprops b/src/map/.svn/all-wcprops new file mode 100644 index 0000000..c855f45 --- /dev/null +++ b/src/map/.svn/all-wcprops @@ -0,0 +1,59 @@ +K 25 +svn:wc:ra_dav:version-url +V 34 +/svn/!svn/ver/3/trunk/haxemaps/map +END +LngLat.hx +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/2/trunk/haxemaps/map/LngLat.hx +END +TileLoader.hx +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/2/trunk/haxemaps/map/TileLoader.hx +END +QuadTree.hx +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/2/trunk/haxemaps/map/QuadTree.hx +END +TileLayer.hx +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/2/trunk/haxemaps/map/TileLayer.hx +END +Canvas.hx +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/2/trunk/haxemaps/map/Canvas.hx +END +Layer.hx +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/3/trunk/haxemaps/map/Layer.hx +END +Tile.hx +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/2/trunk/haxemaps/map/Tile.hx +END +MapService.hx +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/2/trunk/haxemaps/map/MapService.hx +END +Utils.hx +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/2/trunk/haxemaps/map/Utils.hx +END diff --git a/src/map/.svn/entries b/src/map/.svn/entries new file mode 100644 index 0000000..b95de7f --- /dev/null +++ b/src/map/.svn/entries @@ -0,0 +1,334 @@ +10 + +dir +5 +http://haxemaps.googlecode.com/svn/trunk/haxemaps/map +http://haxemaps.googlecode.com/svn + + + +2010-04-03T15:29:27.879189Z +3 +vzdenek@seznam.cz + + + + + + + + + + + + + + +91f78bee-1f10-11df-98cf-3116c4ba2102 + +LngLat.hx +file + + + + +2013-10-31T20:25:12.966822Z +0d948ef67ee65767bba19957173fa83a +2010-03-13T13:28:15.676966Z +2 +vzdenek@seznam.cz + + + + + + + + + + + + + + + + + + + + + +3248 + +TileLoader.hx +file + + + + +2013-10-31T20:25:12.968822Z +b5d51e3dc095209a5e815d90c33491a0 +2010-03-13T13:28:15.676966Z +2 +vzdenek@seznam.cz + + + + + + + + + + + + + + + + + + + + + +14780 + +QuadTree.hx +file + + + + +2013-10-31T20:25:12.970822Z +27188120784e114b158fe9b5a9a13986 +2010-03-13T13:28:15.676966Z +2 +vzdenek@seznam.cz + + + + + + + + + + + + + + + + + + + + + +7971 + +TileLayer.hx +file + + + + +2013-10-31T20:25:12.978822Z +bfb7209e02852624fd4326257eaa34f3 +2010-03-13T13:28:15.676966Z +2 +vzdenek@seznam.cz + + + + + + + + + + + + + + + + + + + + + +18922 + +Canvas.hx +file + + + + +2013-10-31T20:25:12.980822Z +e9fcf8b1844d9e392f018aa574e5df45 +2010-03-13T13:28:15.676966Z +2 +vzdenek@seznam.cz + + + + + + + + + + + + + + + + + + + + + +19335 + +Layer.hx +file + + + + +2013-10-31T20:25:12.981822Z +e4fedb9fb050d1c22c4b3723404e1a12 +2010-04-03T15:29:27.879189Z +3 +vzdenek@seznam.cz + + + + + + + + + + + + + + + + + + + + + +15302 + +Tile.hx +file + + + + +2013-10-31T20:25:12.983822Z +0dbe88817f1d78c0eec00931428612b4 +2010-03-13T13:28:15.676966Z +2 +vzdenek@seznam.cz + + + + + + + + + + + + + + + + + + + + + +5331 + +MapService.hx +file + + + + +2013-10-31T20:25:12.985822Z +171ec2f13bcd6cb833321e02c4a1a6ed +2010-03-13T13:28:15.676966Z +2 +vzdenek@seznam.cz + + + + + + + + + + + + + + + + + + + + + +7362 + +Utils.hx +file + + + + +2013-10-31T20:25:12.986822Z +eb95ae08373af5cf08d9ce98a97e331b +2010-03-13T13:28:15.676966Z +2 +vzdenek@seznam.cz + + + + + + + + + + + + + + + + + + + + + +2859 + diff --git a/src/map/.svn/text-base/Canvas.hx.svn-base b/src/map/.svn/text-base/Canvas.hx.svn-base new file mode 100644 index 0000000..a0d3987 --- /dev/null +++ b/src/map/.svn/text-base/Canvas.hx.svn-base @@ -0,0 +1,666 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +import com.Component; + +import map.MapService; +import map.LngLat; +import flash.events.Event; +import flash.events.MouseEvent; +import flash.geom.Point; +import flash.geom.Rectangle; +import flash.utils.Timer; +import flash.events.TimerEvent; +import flash.display.Shape; +import flash.display.BitmapData; + +typedef ALayer = { + var layer : Layer; + var enabled : Bool; +} + +class MapEvent extends flash.events.Event +{ + public static var MAP_CLICKED:String = "mapclicked"; + public static var MAP_MOUSEMOVE:String = "mapmousemove"; + public static var MAP_MOVE:String = "mapmove"; + public static var MAP_ZOOMCHANGED:String = "mapzoom"; + public static var MAP_CHANGED:String = "mapchanged"; + + public var point:LngLat; + + public function new(event:String, point:LngLat = null) { + super(event); + this.point = point; + } +} + + +class Canvas extends Component +{ + var layers:Array; + var start:Point; + var initialized:Bool; + var zoom:Int; + var animTimer : Timer; + var animTo:LngLat; + var center:LngLat; + var thpassed:Bool; + var thtimer:Timer; + var mappoint:LngLat; + public var mousethreshold:Int; //the minimal number of pixels that have to be passed in order to start moving + public var transparent(default, setTransparent):Bool; + + public function new(interactive:Bool = true) + { + super(); + + this.initialized = false; + this.start = null; + this.zoom = 0; + this.mousethreshold = 5; + this.thpassed = false; + this.thtimer = null; + this.animTimer = new Timer(50, 0); + this.center = new LngLat(16.722079,49.577496); + this.layers = new Array(); + this.doubleClickEnabled = true; + this.transparent = false; + + contextMenu = new flash.ui.ContextMenu(); + contextMenu.hideBuiltInItems(); + var itm = new flash.ui.ContextMenuItem("HaxeMaps"); + itm.addEventListener(flash.events.ContextMenuEvent.MENU_ITEM_SELECT, + function(e) { flash.Lib.getURL(new flash.net.URLRequest("http://code.google.com/p/haxemaps/")); }); + contextMenu.customItems.push(itm); + var itm = new flash.ui.ContextMenuItem(" (C) 2010"); + itm.enabled = false; + contextMenu.customItems.push(itm); + + if (interactive) + { + addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); + addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); + addEventListener(MouseEvent.DOUBLE_CLICK, onMouseDoubleClick); + + var me = this; + var itm = new flash.ui.ContextMenuItem("HaxeMaps - zoom in"); + itm.separatorBefore = true; + itm.addEventListener(flash.events.ContextMenuEvent.MENU_ITEM_SELECT, + function(e) { me.zoomIn(); }); + contextMenu.customItems.push(itm); + var itm = new flash.ui.ContextMenuItem("HaxeMaps - Zoom out"); + itm.addEventListener(flash.events.ContextMenuEvent.MENU_ITEM_SELECT, + function(e) { me.zoomOut(); }); + contextMenu.customItems.push(itm); + + } + } + + /*============================================================================================== + LAYER MANAGEMENT + *==============================================================================================*/ + public function initialize() + { + if (initialized) + return; + + var m:MapService = null; + + //find the first defined service + for (l in layers) + if (l.layer.mapservice != null) + { + m = l.layer.mapservice; + break; + } + + //Check if there is a layer containing mapservice + if (m == null) + return; + + //initialize the layers + for (l in layers) + { + if (l.layer.mapservice == null) + l.layer.mapservice = m; + + if (l.enabled) + { + initializeLayer(l); + addChild(l.layer); + } + } + + initialized = true; + dispatchEvent(new MapEvent(MapEvent.MAP_CHANGED, null)); + } + + public function addLayer(layer:Layer, enable:Bool=true) + { + for (l in layers) + if (l.layer == layer) + return; + + var alayer:ALayer = {layer:layer, enabled:false}; + layers.push(alayer); + layer.addEventListener(Layer.ZOOM_FINISHED, zoomFinished); + + if ((initialized) && (enable)) //synchronize + { + initializeLayer(alayer); + dispatchEvent(new MapEvent(MapEvent.MAP_CHANGED, null)); + } + + alayer.enabled = enable; + } + + public function removeLayer(layer:Layer) + { + for (l in layers) + { + if (l.layer == layer) + { + removeChild(layer); + layer.removeEventListener(Layer.ZOOM_FINISHED, zoomFinished); + layer.clear(); + layers.remove(l); + return; + } + } + } + + public function enableLayer(layer:Layer) + { + var childidx = 0; + for (i in 0...layers.length) + { + + var l:ALayer = layers[i]; + if (l.layer == layer) + { + if (l.enabled) + break; + + l.enabled = true; + + if (initialized) + { + initializeLayer(l, false); + dispatchEvent(new MapEvent(MapEvent.MAP_CHANGED, null)); + } + + if (i == layers.length - 1) + addChild(l.layer); + else + addChildAt(l.layer, childidx); + return; + } + + if (l.enabled) + childidx++; + } + } + + public function disableLayer(layer:Layer) + { + for (l in layers) + if (l.layer == layer) + { + if (!l.enabled) + break; + + removeChild(l.layer); + l.layer.clear(); + l.enabled = false; + + return; + } + } + + public function updateLayer(layer:Layer) + { + for (l in layers) + if (l.layer == layer) + { + if (l.enabled) + l.layer.update(); + return; + } + + } + + public function layerEnabled(layer:Layer) + { + for (l in layers) + if (l.layer == layer) + return l.enabled; + + return false; + } + + function initializeLayer(alayer:ALayer, canAdd:Bool = true) + { + if (alayer.layer.mapservice == null) + { + for (l in layers) + if (l.layer.mapservice != null) + { + alayer.layer.mapservice = l.layer.mapservice; + break; + } + } + + if (alayer.layer.mapservice == null) + return; + + var sz = getSize(); + var center:LngLat = this.center; + + if (initialized) + { + //synchronize position + for (l in layers) + if ((l != alayer) && (l.enabled) && (l.layer.mapservice != null)) + { + center = l.layer.getCenter(); + //trace("Init new center:"+center); + break; + } + } + + alayer.layer.finalize(); + alayer.layer.setCenter(center); + alayer.layer.setBBox(new Rectangle(0,0,sz.width,sz.height)); + alayer.layer.setZoom(this.zoom); + alayer.layer.initialize(); + + if ((!alayer.enabled) && (canAdd)) + addChild(alayer.layer); + } + + /*============================================================================================== + POSITION / ZOOM + *==============================================================================================*/ + public function zoomIn() + { + for (l in layers) + if ((l.enabled) && (!l.layer.validZoom(this.zoom + 1))) + return; + + this.zoom += 1; + for (l in layers) + if (l.enabled) + l.layer.zoomIn(); + } + + public function zoomOut() + { + for (l in layers) + if ((l.enabled) && (!l.layer.validZoom(this.zoom - 1))) + return; + + this.zoom -= 1; + for (l in layers) + if (l.enabled) + l.layer.zoomOut(); + } + + public function getZoom() : Int + { + return this.zoom; + } + + public function getMinZoom() : Int + { + var z:Int = this.zoom - 1; + while (z > -16) + { + var vld:Bool = true; + + for (l in layers) + if ((l.enabled) && (!l.layer.validZoom(z))) + { + vld = false; + break; + } + + if (!vld) + break; + + z--; + } + + return z + 1; + } + + public function getMaxZoom() : Int + { + var z:Int = this.zoom + 1; + while (z > -16) + { + var vld:Bool = true; + + for (l in layers) + if ((l.enabled) && (!l.layer.validZoom(z))) + { + vld = false; + break; + } + + if (!vld) + break; + + z++; + } + + return z - 1; + } + + public function setZoom(zoom:Int) + { + for (l in layers) + if ((l.enabled) && (!l.layer.validZoom(zoom)) && (l.layer.mapservice != null)) + return; + + this.zoom = zoom; + + if (!initialized) return; + + for (l in layers) + if (l.enabled) + l.layer.setZoom(this.zoom); + } + + public function setCenter(point:LngLat) + { + if (!initialized) + { + center = point; + return; + } + + for (l in layers) + if (l.enabled) + l.layer.setCenter(point); + + + dispatchEvent(new MapEvent(MapEvent.MAP_CHANGED, null)); + } + + public function getCenter(): LngLat + { + var c:LngLat = center.clone(); + if (initialized) + for (l in layers) + if (l.enabled) + { + c = l.layer.getCenter(); + break; + } + + return c; + } + + public function getLngLat(global:Point) : LngLat + { + if (initialized) + for (l in layers) + if (l.enabled) + return l.layer.getLngLat(l.layer.globalToLocal(global)); + return null; + } + + public function getLeftTopCorner() : LngLat + { + return getLngLat(localToGlobal(new Point(0,0))); + } + + public function getRightBottomCorner() : LngLat + { + var sz = getSize(); + return getLngLat(localToGlobal(new Point(sz.width,sz.height))); + } + + public function panTo(point:LngLat) + { + if (this.animTimer.running) + { + this.animTo = point.clone(); + return; + } + + for (l in layers) + if (l.enabled) + { + this.animTo = point.clone(); + this.animTimer.addEventListener(TimerEvent.TIMER, animStep); + this.animTimer.start(); + + return; + } + } + + + public function getBitmap() : BitmapData + { + var sz = getSize(); + var bmp:BitmapData = new BitmapData(Std.int(sz.width), Std.int(sz.height), false, 0x00FFFFFF); + bmp.draw(this); + return bmp; + } + + /*============================================================================================== + PRIVATE methods + *==============================================================================================*/ + function setTransparent(val:Bool): Bool + { + this.transparent = val; + + graphics.clear(); + if (this.transparent) + return true; + + var sz = getSize(); + graphics.beginFill(0xFFFFFF); + graphics.drawRect(0,0,sz.width,sz.height); + graphics.endFill(); + + return this.transparent; + } + + override function onResize(w:Float, h:Float) + { + setTransparent(this.transparent); + scrollRect = new Rectangle(0, 0, w, h); + + //trace("Canvas resized w:"+w+" h:"+h); + for (l in layers) + l.layer.setBBox(new Rectangle(0,0,w,h)); + } + + function onMouseDown(e:MouseEvent) + { + var tl:Point = localToGlobal(new Point(0,0)); + var br:Point = localToGlobal(new Point(width, height)); + + start = new Point(e.stageX, e.stageY); + thpassed = false; + + removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); + removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); + flash.Lib.current.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); + flash.Lib.current.stage.addEventListener(MouseEvent.MOUSE_MOVE, onStageMouseMove); + } + + function onMouseUp(e:MouseEvent) + { + addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); + addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); + flash.Lib.current.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp); + flash.Lib.current.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onStageMouseMove); + + if ((!thpassed) && (thtimer == null)) + { + mappoint = getLngLat(new Point(e.stageX, e.stageY)); + thtimer = new Timer(300, 1); + thtimer.addEventListener(TimerEvent.TIMER_COMPLETE, fireMapClicked); + thtimer.start(); + } + } + + function fireMapClicked(e:TimerEvent) + { + dispatchEvent(new MapEvent(MapEvent.MAP_CLICKED, mappoint)); + + if (thtimer != null) + { + thtimer.stop(); + thtimer.removeEventListener(TimerEvent.TIMER_COMPLETE, fireMapClicked); + thtimer = null; + } + } + + function onMouseDoubleClick(e:MouseEvent) + { + if (!doubleClickEnabled) return; + + if (thtimer != null) + { + thtimer.stop(); + thtimer.removeEventListener(TimerEvent.TIMER_COMPLETE, fireMapClicked); + thtimer = null; + } + + if (e.ctrlKey) + zoomOut() + else + zoomIn(); + } + + function onMouseMove(e:MouseEvent) + { + for (l in layers) + if (l.enabled) + { + var pt = l.layer.globalToLocal(new Point(e.stageX, e.stageY)); + dispatchEvent(new MapEvent(MapEvent.MAP_MOUSEMOVE, l.layer.getLngLat(pt))); + return; + } + } + + function onStageMouseMove(e:MouseEvent) + { + var pt:Point = new Point(e.stageX, e.stageY); + + if (!thpassed) + { + if (Point.distance(pt, start) < this.mousethreshold) + return; + start = pt; + thpassed = true; + return; + } + + animStop(); + + var diff = pt.subtract(start); + var cntr:LngLat = null; + + for (l in layers) + if (l.enabled) + { + try + { + l.layer.moveRelative(diff.x, diff.y); + cntr = l.layer.getCenter(); + center = cntr; + } + catch (unknown : Dynamic) + {} + } + + if (cntr != null) + { + dispatchEvent(new MapEvent(MapEvent.MAP_MOVE, cntr)); + dispatchEvent(new MapEvent(MapEvent.MAP_CHANGED, null)); + } + start = pt; + } + + + function animStop() + { + if (animTimer.running) + { + animTimer.stop(); + animTimer.removeEventListener(TimerEvent.TIMER, animStep); + } + } + + function animStep(e:flash.events.Event) + { + for (l in layers) + if (l.enabled) + { + try { + var a:Point = l.layer.getCenterXY(); + var b:Point = l.layer.getPointXY(animTo); + var dist:Float = Point.distance(a, b); + if (dist < 1.0) + animStop(); + a = a.subtract(b); + + var k:Float = (dist < 5) ? 1.0 : ((dist < 10) ? 5.0 : 10.0); + a.x = a.x / k; + if (a.x < -64) a.x = -64; + if (a.x > 64) a.x = 64; + a.y = a.y / k; + if (a.y < -64) a.y = -64; + if (a.y > 64) a.y = 64; + + l.layer.moveRelative(a.x, a.y); + + dispatchEvent(new MapEvent(MapEvent.MAP_CHANGED, null)); + } + catch (unknown : Dynamic) + {} + } + } + + + function zoomFinished(e:Event) + { + dispatchEvent(new MapEvent(MapEvent.MAP_ZOOMCHANGED, null)); + dispatchEvent(new MapEvent(MapEvent.MAP_CHANGED, null)); + } +} diff --git a/src/map/.svn/text-base/Layer.hx.svn-base b/src/map/.svn/text-base/Layer.hx.svn-base new file mode 100644 index 0000000..21dafa6 --- /dev/null +++ b/src/map/.svn/text-base/Layer.hx.svn-base @@ -0,0 +1,522 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +import flash.display.Sprite; +import flash.events.Event; +import flash.geom.Point; +import flash.geom.Rectangle; +import flash.utils.Timer; +import flash.events.TimerEvent; +import map.Utils; +import map.LngLat; + +class Layer extends Sprite +{ + public static var ZOOM_FINISHED:String = "zoomfinished"; + + public var bbox(default, null):Rectangle; + var zoom:Int; + var animTimer:Timer; + var animState:Int; + var animTmp:Float; + var initialized:Bool; + var updateEnabled:Bool; + var center:LngLat; + var lastcenter:LngLat; + var canvascenter:Point; + var lastxy:Point; + var lastcxy:Point; + var scalable:Bool; + public var mapservice:MapService; + + public function new(map_service:MapService = null, scalable:Bool = false) + { + super(); + + this.scalable = scalable; + this.mapservice = map_service; + this.initialized = false; + this.updateEnabled = false; + this.bbox = new Rectangle(0,0,flash.Lib.current.stage.width, flash.Lib.current.stage.height); + this.canvascenter = new Point(this.bbox.width/2.0,this.bbox.height/2.0); + this.center = null; + this.zoom = 0; + this.lastxy = null; + this.lastcxy = null; + + animTimer = new Timer(15, 0); + animTimer.addEventListener(TimerEvent.TIMER, animStep); + + mouseEnabled = false; + + } + + /*============================================================================================== + INITIALIZATION / FINALIZATION / MISC + *==============================================================================================*/ + + public function initialize(update:Bool=true) : Int + { + + if (mapservice == null) + return 1; + + if (this.initialized) + finalize(); + + this.x = this.canvascenter.x; + this.y = this.canvascenter.y; + + synchronizeScale(true); + + if (Std.is(this, Layer)) + { + this.initialized = true; + if (!this.updateEnabled) + { + this.updateEnabled = true; + updateChanged(); + } + + if (update) + updateContent(true); + } + + return 0; + } + + public function finalize() + { + if (this.initialized) + clear(); + + this.initialized = false; + } + + + public function setBBox(bbox:Rectangle) + { + if (bbox == null) + return; + + var actcenter:LngLat = null; + if ((this.bbox != null) && (this.initialized)) + actcenter = this.getCenter(); + + this.bbox = bbox; + this.canvascenter = new Point(this.bbox.x + this.bbox.width/2.0, this.bbox.y + this.bbox.height/2.0); + + if (actcenter != null) + this.setCenter(actcenter); + } + + + public function clear() + { + } + + /*============================================================================================== + POSITION + *==============================================================================================*/ + + public function getOriginXY() : Point + { + if (this.mapservice == null) + return new Point(0,0); + + return mapservice.lonlat2XY(center.lng, center.lat, mapservice.zoom_def + zoom); + } + + public function getCenterXY() : Point + { + var pta:Point = getOriginXY(); + pta.offset(-x + this.canvascenter.x, - y + this.canvascenter.y); + return pta; + } + + public function getPointXY(point:LngLat) : Point + { + if (this.mapservice == null) + return new Point(0,0); + + return mapservice.lonlat2XY(point.lng, point.lat, mapservice.zoom_def + zoom); + } + + public function getCenter() : LngLat + { + if (this.mapservice == null) + return null; + + if ((x == this.canvascenter.x) && (y == this.canvascenter.y)) + return center.clone(); + + var z:Int = mapservice.zoom_def + zoom; + var pta:Point = getCenterXY(); + var ptb:LonLat = mapservice.XY2lonlat(pta.x, pta.y, z); + + return new LngLat(ptb.x, ptb.y); + } + + public function getXY(local:Point) : Point + { + var z:Int = mapservice.zoom_def + zoom; + var pta:Point = mapservice.lonlat2XY(center.lng, center.lat, z); + pta.offset(scaleX*local.x, scaleY*local.y); + return pta; + } + + public function getLngLat(local:Point) : LngLat + { + var z:Int = mapservice.zoom_def + zoom; + var pta:Point = mapservice.lonlat2XY(center.lng, center.lat, z); + var ptb:Point = mapservice.XY2lonlat(pta.x + scaleX*local.x, pta.y + scaleY*local.y, z); + return new LngLat(ptb.x, ptb.y); + } + + public function setCenter(point:LngLat) + { + if ((this.scalable) && (initialized)) + synchronizeCenter(point); + else + this.center = point.clone(); + centerUpdated(true); + } + + public function moveTo(x:Float, y:Float) + { + if ((this.animTimer.running) || ((this.x == x) && (this.y == y))) + return; + + + this.x = x; + this.y = y; + + if (this.updateEnabled) + updateContent(); + } + + public function moveRelative(dx:Float, dy:Float) + { + if ((this.animTimer.running) || ((dx == 0) && (dy == 0))) + return; + + this.x += dx; + this.y += dy; + + if (this.updateEnabled) + updateContent(); + } + + public function getOffset() : Point + { + return new Point(this.x - this.canvascenter.x, this.y - this.canvascenter.y); + } + + public function getLeftTopCorner(margin:Float = 0.0) : LngLat + { + if (!initialized) return null; + + var x:Float = this.canvascenter.x - this.x - this.bbox.width/2.0 + margin; + var y:Float = this.canvascenter.y - this.y - this.bbox.height/2.0 + margin; + + var z:Int = mapservice.zoom_def + zoom; + var pta:Point = mapservice.lonlat2XY(center.lng, center.lat, z); + var ptb:Point = mapservice.XY2lonlat(pta.x + scaleX*x, pta.y + scaleY*y, z); + + return new LngLat(ptb.x, ptb.y); + } + + public function getRightBottomCorner(margin:Float = 0.0) : LngLat + { + if (!initialized) return null; + + var x:Float = this.canvascenter.x - this.x + this.bbox.width/2.0 + margin; + var y:Float = this.canvascenter.y - this.y + this.bbox.height/2.0 + margin; + + var z:Int = mapservice.zoom_def + zoom; + var pta:Point = mapservice.lonlat2XY(center.lng, center.lat, z); + var ptb:Point = mapservice.XY2lonlat(pta.x + scaleX*x, pta.y + scaleY*y, z); + + return new LngLat(ptb.x, ptb.y); + } + + + /*============================================================================================== + ZOOM + *==============================================================================================*/ + + public function validZoom(zoom:Int) : Bool + { + return ((!this.animTimer.running) && (this.mapservice != null) && (this.mapservice.validZoom(zoom))); + } + + public function setZoom(zoom:Int) + { + if (!validZoom(zoom)) return; + + this.zoom = zoom; + if (this.scalable) + synchronizeScale(); + + if (!this.initialized) + return; + + this.center = getCenter(); //get actual center & update layer content + centerUpdated(true); + } + + public function zoomIn(animate:Bool = true) + { + if ((this.animTimer.running) || (!this.initialized) || (this.mapservice == null) || (!this.mapservice.validZoom(zoom+1))) + return; + + this.lastxy = new Point(x,y); + this.lastcenter = getCenter(); + this.lastcxy = new Point(this.canvascenter.x, this.canvascenter.y); + + if (!animate) + { + scaleX = scaleX * 2.0; + scaleY = scaleY * 2.0; + + x = lastcxy.x + (lastxy.x - lastcxy.x) * 2.0; + y = lastcxy.y + (lastxy.y - lastcxy.y) * 2.0; + + zoomChanged(this.updateEnabled, zoom + 1); + + return; + } + + + this.animState = 0x0000; + + if (this.updateEnabled) + { + this.updateEnabled = false; + updateChanged(); + this.animState += 0x0100; + } + + this.animTmp = scaleX; + this.animTimer.start(); + } + + public function zoomOut(animate:Bool = true) + { + if ((this.animTimer.running) || (!this.initialized) || (this.mapservice == null) || (!this.mapservice.validZoom(zoom-1))) + return; + + this.lastxy = new Point(x,y); + this.lastcenter = getCenter(); + this.lastcxy = new Point(this.canvascenter.x, this.canvascenter.y); + + if (!animate) + { + scaleX = scaleX / 2.0; + scaleY = scaleY / 2.0; + + x = lastcxy.x + (lastxy.x - lastcxy.x) / 2.0; + y = lastcxy.y + (lastxy.y - lastcxy.y) / 2.0; + + zoomChanged(this.updateEnabled, zoom - 1); + + return; + } + + this.animState = 0x1000; + if (this.updateEnabled) + { + this.updateEnabled = false; + updateChanged(); + this.animState += 0x0100; + } + + this.animTmp = scaleX; + this.animTimer.start(); + } + + public function update() + { + updateContent(true); + } + + /*============================================================================================== + PRIVATE + *==============================================================================================*/ + function updateContent(forceUpdate:Bool=false) + { + } + + function updateChanged() + { + } + + function zoomChanged(prevEnabled:Bool, newZoom:Int) + { + this.zoom = newZoom; + if (!scalable) + { + scaleX = scaleY = 1.0; + + center = this.lastcenter; + centerUpdated(false); + } + else + synchronizeCenter(this.lastcenter); + + dispatchEvent(new Event(ZOOM_FINISHED)); + + if ((prevEnabled) && (!this.updateEnabled)) + { + this.updateEnabled = true; + updateContent(!scalable); + updateChanged(); + } + } + + /*============================================================================================== + PRIVATE + *==============================================================================================*/ + + function synchronizeCenter(point:LngLat) + { + if (!this.scalable) + return; + + var pta:Point = getOriginXY(); + var ptb:Point = getPointXY(point); + this.x = pta.x - ptb.x + canvascenter.x; + this.y = pta.y - ptb.y + canvascenter.y; + } + + function synchronizeScale(init:Bool=false) + { + + if (this.scalable) + { + if (this.zoom < 0) { + scaleX = 1.0 / (1 << (-this.zoom)); + scaleY = 1.0 / (1 << (-this.zoom)); + } else { + scaleX = (1 << this.zoom); + scaleY = (1 << this.zoom); + } + + } + else if ((!this.scalable) && (init)) + { + this.scaleX = 1.0; + this.scaleY = 1.0; + } + + } + + function centerUpdated(clearQueue:Bool) + { + if (!this.initialized) + return; + + if (!this.scalable) + { + this.x = this.canvascenter.x; + this.y = this.canvascenter.y; + } + + if (this.updateEnabled) + updateContent((clearQueue) && (!scalable)); + } + + function animStep(e:flash.events.Event) + { + var steps:Float = 10.0; + + var act = (animState >> 12) & 0x0F; + var en = (animState >> 8) & 0x0F; + var st = (animState & 0xFF); + + if (act == 0) + { + if (st < steps) + { + var scale:Float = (1.0 + (st + 1)/steps); + + scaleX = animTmp * scale; + scaleY = scaleX; + + x = lastcxy.x + (lastxy.x - lastcxy.x) * scale; + y = lastcxy.y + (lastxy.y - lastcxy.y) * scale; + + animState += 1; + } + else if (st == steps) + { + animTimer.stop(); + + scaleX = animTmp * 2.0; + scaleY = animTmp * 2.0; + + x = lastcxy.x + (lastxy.x - lastcxy.x) * 2.0; + y = lastcxy.y + (lastxy.y - lastcxy.y) * 2.0; + + zoomChanged(en == 1, zoom + 1); + } + } + else if (act == 1) + { + if (st < steps) + { + var scale:Float = (1.0 + (st + 1)/steps); + + scaleX = animTmp / scale; + scaleY = scaleX; + + x = lastcxy.x + (lastxy.x - lastcxy.x) / scale; + y = lastcxy.y + (lastxy.y - lastcxy.y) / scale; + + animState += 1; + } + else if (st == steps) + { + animTimer.stop(); + + scaleX = animTmp / 2.0; + scaleY = animTmp / 2.0; + + x = lastcxy.x + (lastxy.x - lastcxy.x) / 2.0; + y = lastcxy.y + (lastxy.y - lastcxy.y) / 2.0; + + zoomChanged(en == 1, zoom - 1); + } + } + } + +} diff --git a/src/map/.svn/text-base/LngLat.hx.svn-base b/src/map/.svn/text-base/LngLat.hx.svn-base new file mode 100644 index 0000000..7d16363 --- /dev/null +++ b/src/map/.svn/text-base/LngLat.hx.svn-base @@ -0,0 +1,85 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +class LngLat +{ + public var lat: Float; + public var lng: Float; + + public function new(lng:Float, lat:Float) + { + this.lng = lng; + this.lat = lat; + } + + inline public function clone() + { + return new LngLat(this.lng, this.lat); + } + + public function toString():String + { + + return "[LngLat] lng:" + fmtCoordinate(this.lng) + " lat:" + fmtCoordinate(this.lat); + } + + //convert coordinate to string (format %.6f) + static public function fmtCoordinate(value:Float) : String + { + var valuef:Float = Math.floor(value); + var f:Float = value - valuef; + var s:String = Std.string(valuef) + "."; + for (i in 0...6) + { + f *= 10.0; + s += Std.string(Math.floor(f)); + f = f - Math.floor(f); + } + return s; + } + + //distance between two points in meters + static public function distance(a:LngLat, b:LngLat) : Float + { + var dlat:Float = (b.lat - a.lat) * Math.PI / 180; + var dlon:Float = (b.lng - a.lng) * Math.PI / 180; + + dlat = Math.sin(dlat/2); + dlon = Math.sin(dlon/2); + var a:Float = dlat*dlat + Math.cos(a.lat * Math.PI / 180 ) * Math.cos(b.lat * Math.PI / 180 ) * dlon*dlon; + var c:Float = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); + c = 6371000.0 * c; //avg. radius of the earth in meters + + return c; + } + +} diff --git a/src/map/.svn/text-base/MapService.hx.svn-base b/src/map/.svn/text-base/MapService.hx.svn-base new file mode 100644 index 0000000..80c555e --- /dev/null +++ b/src/map/.svn/text-base/MapService.hx.svn-base @@ -0,0 +1,211 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +import map.Utils; +import flash.geom.Point; + +interface MapService +{ + var id(default,null):String; + var zoom_min(default,null):Int; + var zoom_max(default,null):Int; + var zoom_def(default,null):Int; + var tile_size(default,null):Int; + var invert_x(default,null):Bool; + var invert_y(default,null):Bool; + + function lonlat2tile(lon:Float, lat:Float, zoom:Int) : TileID; + function tile2lonlat(t:TileID) : LonLat; + function lonlat2XY(lon:Float, lat:Float, zoom:Int) : Point; + function XY2lonlat(x:Float, y:Float, zoom:Int) : LonLat; + function validZoom(z:Int) : Bool; + function tile2url(t:TileID) : String; +} + +class BaseMapService { + + public var id(default,null):String; + public var zoom_min(default,null):Int; + public var zoom_max(default,null):Int; + public var zoom_def(default,null):Int; + public var tile_size(default,null):Int; + public var invert_x(default,null):Bool; + public var invert_y(default,null):Bool; + + var proxy:Bool; + var proxy_url:String; + + public function new(id:String, abbrev:String, zoom_min:Int, zoom_max:Int, zoom_def:Int, tile_size:Int=256) + { + setInfo(id, abbrev, zoom_min, zoom_max, zoom_def, tile_size); + } + + function setInfo(id:String, abbrev:String, zoom_min:Int, zoom_max:Int, zoom_def:Int, tile_size:Int=256) + { + this.id = id; + this.zoom_min = zoom_min; + this.zoom_max = zoom_max; + this.zoom_def = zoom_def; + this.tile_size = tile_size; + this.invert_x = false; + this.invert_y = false; + this.proxy = false; + + //check if the proxy parameter is set + var params = flash.Lib.current.loaderInfo.parameters; + if ((params != null) && (params.proxy != null) && (params.proxy != "")) + { + this.proxy_url = params.proxy; + if (this.proxy_url.charAt(proxy_url.length-1) != '/') + this.proxy_url += '/'; + this.proxy_url += abbrev + "/"; + this.id += " (Proxy)"; + this.proxy = true; + } + } + + public function validZoom(z:Int) : Bool + { + return (((zoom_def + z) >= zoom_min) && ((zoom_def + z) <= zoom_max)); + } + +} + +class OpenStreetMapService extends BaseMapService, implements MapService +{ + // Details: + // --------------------------------------------------------- + // http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames + + override public function new(default_zoom:Int = 13) + { + super("Open Street Map", "osm", 0, 18, default_zoom, 256); + } + + public inline function lonlat2tile(lon:Float, lat:Float, zoom:Int) : TileID + { + var z:Float = Math.pow(2,zoom); + var lr:Float = lat*Math.PI/180; + return {x: (Math.floor((lon+180)/360*z)), + y: (Math.floor(z*(1-Math.log(Math.tan(lr) + 1/Math.cos(lr))/Math.PI)/2)), + z: zoom}; + } + + public inline function lonlat2XY(lon:Float, lat:Float, zoom:Int) : Point + { + var z:Float = tile_size * Math.pow(2,zoom); + var lr:Float = lat*Math.PI/180; + return new Point((Math.floor(z*(lon+180)/360)), + (Math.floor(z*(1-Math.log(Math.tan(lr) + 1/Math.cos(lr))/Math.PI)/2))); + } + + public inline function tile2lonlat(t:TileID) : LonLat + { + var z = Math.pow(2,t.z); + var n = Math.PI-2*Math.PI*t.y/z; + return new LonLat(t.x/z*360-180, 180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n)))); + } + + public inline function XY2lonlat(x:Float, y:Float, zoom:Int) : LonLat + { + var z = tile_size * Math.pow(2, zoom); + var n = Math.PI-2*Math.PI*y/z; + return new LonLat(x/z*360-180, 180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n)))); + } + + public function tile2url(t:TileID) : String + { + if (!isValid(t)) return ""; + + if (!proxy) + return "http://tile.openstreetmap.org/" + (t.z) + "/" + (t.x) + "/" + (t.y) + ".png"; + + return this.proxy_url + (t.z) + "_" + (t.x) + "_" + (t.y); + } + + function isValid(t:TileID) : Bool + { + //check zoom + if ((t.z < zoom_min) || (t.z > zoom_max)) return false; + + //check bounds + var z:Float = Math.pow(2, t.z); + if ((t.x < 0) || (t.x >= z) || (t.y < 0) || (t.y >= z)) return false; + + return true; + } + +} + +class BingMapService extends OpenStreetMapService +{ + + // Details: + // --------------------------------------------------------- + // http://msdn.microsoft.com/en-us/library/bb545006.aspx + + var hybrid:Bool; + + override public function new(default_zoom:Int = 13, hybrid:Bool = false) + { + super(); + this.hybrid = hybrid; + setInfo("Bink Maps", "bnk", 1, 18, default_zoom, 256); + + } + + override public function tile2url(t:TileID) : String + { + if (!isValid(t)) return ""; + + if (!proxy) + { + var xx:Int = t.x; + var yy:Int = t.y; + var tid:String = ""; + for (i in 0...t.z) + { + var q:Int = 0; + if ((xx & 1) == 1) q += 1; + if ((yy & 1) == 1) q += 2; + tid = q + tid; + + xx = xx >> 1; + yy = yy >> 1; + } + return "http://tiles.virtualearth.net/tiles/"+(hybrid ? "h" : "r")+tid+".png?g=414&mkt=en-us&shading=hill&n=z"; + } + + return this.proxy_url + (t.z) + "_" + (t.x) + "_" + (t.y); + } + +} diff --git a/src/map/.svn/text-base/QuadTree.hx.svn-base b/src/map/.svn/text-base/QuadTree.hx.svn-base new file mode 100644 index 0000000..45a789a --- /dev/null +++ b/src/map/.svn/text-base/QuadTree.hx.svn-base @@ -0,0 +1,240 @@ +/******************************************************************************* +Copyright (c) 2010, Karel Slany (slany AT fit.vutbr.cz) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +typedef QuadData = { + public var x:Float; + public var y:Float; + public var data:Dynamic; +} + +class QuadLeaf { + public var x:Float; + public var y:Float; + public var data:Array; + public var ll:Dynamic; // < x, < y + public var lg:Dynamic; // < x, >= y + public var gl:Dynamic; // >= x, < y + public var gg:Dynamic; // >= x, >= y + + public function new(xv:Float, yv:Float, d:Dynamic, optfast:Bool) { + x = xv; + y = yv; + data = new Array(); + if (optfast) { + var qd:QuadData = {x:xv, y:yv, data:d}; + data.push(qd); + } else { + data.push(d); + } + ll = lg = gl = gg = null; + } + + public function push(d:Dynamic, optfast:Bool) { + if (optfast) { + var qd:QuadData = {x:x, y:y, data:d}; + data.push(qd); + } else { + data.push(data); + } + } + + public function remove(d:Dynamic, optfast:Bool):Bool { + if (optfast) { + for (itm in data) + if (itm.data == d) + return data.remove(itm); + } else { + return data.remove(d); + } + return false; + } + + public function getData(data:Array, optfast:Bool, filter:QuadData->Bool) { + var qd:QuadData = null;// = {x:0.0, y:0.0, data:null}; + if (optfast) { + for (qd in this.data) { + if ((filter == null) || (filter(qd))) + data.push(qd); + } + } else { + for (i in 0...this.data.length) { + qd.x = x; + qd.y = y; + qd.data = this.data[i]; + if ((filter == null) || (filter(qd))) + data.push(qd); + } + } + } +} + +class QuadTree { + + public var qroot:Dynamic; + var optfast:Bool; + + public function new() { + optfast = true; //true - optimized for maximal speed, + //false - optimized for mimimal memory footprint + qroot = null; + } + + /*============================================================================================== + PUBLIC methods + *==============================================================================================*/ + public function clear() { + qroot = null; + } + + public function isEmpty() { + return qroot == null; + } + + public function push(x:Float, y:Float, data:Dynamic) { + if (qroot != null) { + push_recursive(qroot, x, y, data); + } else { + qroot = new QuadLeaf(x, y, data, optfast); + } + } + + public function remove(x:Float, y:Float, data:Dynamic) : Bool { + // return true if found and removed + if (qroot != null) { + return remove_recursive(qroot, x, y, data); + } + return false; + } + + public function getData(minx:Float, miny:Float, maxx:Float, maxy:Float) : Array { + var data = new Array(); + if (qroot == null) return data; + get_data_recursive(qroot, data, minx, miny, maxx, maxy, null); + return data; + } + + public function getFilteredData(minx:Float, miny:Float, maxx:Float, maxy:Float, filter:QuadData->Bool) : Array { + var data = new Array(); + if (qroot == null) return data; + get_data_recursive(qroot, data, minx, miny, maxx, maxy, filter); + return data; + } + + /*============================================================================================== + PRIVATE methods + *==============================================================================================*/ + + function push_recursive(root:QuadLeaf, x:Float, y:Float, data:Dynamic) { + if ((x == root.x) && (y == root.y)) { + // allows multiple entries + root.push(data, optfast); + } else if (x < root.x) { + if (y < root.y) { + if (root.ll != null) { + push_recursive(root.ll, x, y, data); + } else { + root.ll = new QuadLeaf(x, y, data, optfast); + } + } else { + if (root.lg != null) { + push_recursive(root.lg, x, y, data); + } else { + root.lg = new QuadLeaf(x, y, data, optfast); + } + } + } else { + if (y < root.y) { + if (root.gl != null) { + push_recursive(root.gl, x, y, data); + } else { + root.gl = new QuadLeaf(x, y, data, optfast); + } + } else { + if (root.gg != null) { + push_recursive(root.gg, x, y, data); + } else { + root.gg = new QuadLeaf(x, y, data, optfast); + } + } + } + } + + function remove_recursive(root:QuadLeaf, x:Float, y:Float, data:Dynamic) : Bool { + // does not remove nodes, only removes data entries + if ((x == root.x) && (y == root.y)) { + return root.remove(data, optfast); + } else if (x < root.x) { + if (y < root.y) { + if (root.ll != null) { + return remove_recursive(root.ll, x, y, data); + } + return false; + } else { + if (root.lg != null) { + return remove_recursive(root.lg, x, y, data); + } + return false; + } + } else { + if (y < root.y) { + if (root.gl != null) { + return remove_recursive(root.gl, x, y, data); + } + return false; + } else { + if (root.gg != null) { + return remove_recursive(root.gg, x, y, data); + } + return false; + } + } + } + + function get_data_recursive(root:QuadLeaf, data:Array, minx:Float, miny:Float, maxx:Float, maxy:Float, filter:QuadData->Bool) { + if ((minx <= root.x) && (miny <= root.y) && (maxx >= root.x) && (maxy >= root.y)) { + root.getData(data, optfast, filter); + } + if ((root.ll != null) && (minx <= root.x) && (miny <= root.y)) { + get_data_recursive(root.ll, data, minx, miny, maxx, maxy, filter); + } + if ((root.lg != null) && (minx <= root.x) && (maxy >= root.y)) { + get_data_recursive(root.lg, data, minx, miny, maxx, maxy, filter); + } + if ((root.gl != null) && (maxx >= root.x) && (miny <= root.y)) { + get_data_recursive(root.gl, data, minx, miny, maxx, maxy, filter); + } + if ((root.gg != null) && (maxx >= root.x) && (maxy >= root.y)) { + get_data_recursive(root.gg, data, minx, miny, maxx, maxy, filter); + } + } + +} diff --git a/src/map/.svn/text-base/Tile.hx.svn-base b/src/map/.svn/text-base/Tile.hx.svn-base new file mode 100644 index 0000000..81958d5 --- /dev/null +++ b/src/map/.svn/text-base/Tile.hx.svn-base @@ -0,0 +1,173 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +import flash.display.Sprite; +import flash.display.Bitmap; +import flash.text.TextField; +import flash.text.TextFieldAutoSize; + +class Tile extends Sprite +{ + #if TILE_DBG + var t:TextField; + #end + + var size:Int; + var valid:Bool; + public var tx(default, settx):Int; + public var ty(default, setty):Int; + public var tidx(default, null):Int; + public var image(default, null):Bitmap; + + public var rtidx:Int; //right neighbour tidx + public var ltidx:Int; //left neighbour tidx + public var ttidx:Int; //top neighbour tidx + public var btidx:Int; //bottom neighbour tidx + + override public function new(tidx:Int, size:Int = 256, x:Int = 0, y:Int = 0) + { + super(); + + #if TILE_DBG + var s:Sprite = new Sprite(); + s.graphics.lineStyle(2, (tidx == 0) ? 0xFF0000 : 0x008000); + s.graphics.moveTo(0,0); + s.graphics.lineTo(size,size); + s.graphics.moveTo(size,0); + s.graphics.lineTo(0,size); + s.graphics.moveTo(size-1,0); + s.graphics.lineTo(size-1,size); + s.graphics.moveTo(0,size-1); + s.graphics.lineTo(size,size-1); + addChild(s); + + t = new TextField(); + t.autoSize = TextFieldAutoSize.LEFT; + t.mouseEnabled = false; + addChild(t); + #end + + this.tidx = tidx; + this.rtidx = -1; + this.ltidx = -1; + this.ttidx = -1; + this.btidx = -1; + + this.tx = x; + this.ty = y; + this.size = size; + this.image = null; + this.valid = false; + mouseEnabled = false; + + update(); + } + + /*============================================================================================== + PUBLIC methods + *==============================================================================================*/ + public function assignImage(image:Bitmap) + { + graphics.clear(); + + if (this.image != null) + { + removeChild(this.image); + this.image = null; + } + + if (image != null) + { + this.image = image; + addChildAt(this.image, 0); + } + else + { + graphics.lineStyle(2, 0xF0F0F0); + graphics.drawCircle(size/2,size/2, 10); + } + + this.valid = (this.image != null); + } + + //returns True iff the tile waits for an image + public function needImage():Bool + { + return !this.valid; + } + + //tile is being loaded + public function waitForImage() + { + } + + public function invalidate() + { + this.valid = false; + } + + /*============================================================================================== + PRIVATE methods + *==============================================================================================*/ + function update() + { + #if TILE_DBG + t.text = "("+tx+","+ty+")"; + t.x = (size - t.width)/2; + t.y = (size - t.height)/2; + #end + } + + + function settx(val:Int) : Int + { + if (val != tx) + { + tx = val; + update(); + assignImage(null); + } + return val; + } + + function setty(val:Int) : Int + { + if (val != ty) + { + ty = val; + update(); + assignImage(null); + } + return val; + } + +} diff --git a/src/map/.svn/text-base/TileLayer.hx.svn-base b/src/map/.svn/text-base/TileLayer.hx.svn-base new file mode 100644 index 0000000..fe35261 --- /dev/null +++ b/src/map/.svn/text-base/TileLayer.hx.svn-base @@ -0,0 +1,546 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +import map.Tile; +import map.TileLoader; +import map.Layer; +import map.Utils; +import flash.events.Event; +import flash.geom.Point; +import flash.display.Bitmap; + +#if TILE_EVT_DBG +import flash.external.ExternalInterface; +#end + +class TileLayer extends Layer +{ + var tiles:Array; + var tilecnt:Int; + var loader:TileLoader; + + var tofs:Int; /* kdy presunout tiles zprava doleva (kolik za obrazem musi min. byt) */ + var lx:Int; + var rx:Int; + var ty:Int; + var by:Int; + var tilesize:Int; + var basetid:TileID; + var ofsx:Float; + var ofsy:Float; + var smooth:Bool; + + public function new(map_service:MapService = null, tiles:Int = 8, smooth_zoom:Bool = true) + { + super(map_service); + + this.tilecnt = tiles; + this.tiles = new Array(); + this.tilesize = 256; + this.tofs = 1; + this.basetid = {x:0,y:0,z:0}; + this.ofsx = this.ofsy = 0; + this.tofs = 0; + this.smooth = smooth_zoom; + + while (this.tiles.length < this.tilecnt*this.tilecnt) + { + var t:Tile = new Tile(this.tiles.length, this.tilesize); + this.tiles.push(t); + addChild(t); + } + initTile(); + + this.loader = new TileLoader(); + this.loader.addEventListener(TileLoadedEvent.TILE_LOADED, tileLoaded); + } + + /*============================================================================================== + PUBLIC methods + *==============================================================================================*/ + override public function initialize(update:Bool=true) : Int + { + var res = super.initialize(false); + if (res != 0) + return res; + + loader.mapservice = mapservice; + basetid.z = mapservice.zoom_def; + tilesize = mapservice.tile_size; + + alignLayer(); + + initialized = true; + updateEnabled = true; + + if (update) + updateContent(true); + + return 0; + } + + override public function clear() + { + //clean loader queue + loader.clear(); + + //release used images + for (t in tiles) + t.assignImage(null); + } + + override public function getOffset() : Point + { + var tp = tiles.length >> 1; + return new Point(this.x - (this.canvascenter.x - (scaleX*this.tilesize)/2), this.y - (this.canvascenter.y - (scaleY*this.tilesize)/2)); + } + + /*============================================================================================== + PRIVATE methods + *==============================================================================================*/ + function initTile() + { + this.lx = -this.tofs; + this.rx = this.tilecnt-1-this.tofs; + this.ty = -this.tofs; + this.by = this.tilecnt-1-this.tofs; + + var tp = this.tilecnt >> 1; + this.lx = -tp; + this.ty = -tp; + tp = this.tilecnt - tp; + this.rx = tp-1; + this.by = tp-1; + + var i:Int = 0; + var j:Int = 0; + var idx:Int = 0; + + for (t in tiles) + { + if (i == this.tilecnt) + { + i = 0; + j++; + } + + t.tx = this.lx + i; + t.ty = this.ty + j; + + t.ltidx = (i == 0) ? idx + this.tilecnt - 1 : idx - 1; + t.rtidx = (i < this.tilecnt-1) ? idx + 1 : idx - this.tilecnt + 1; + t.ttidx = (j == 0) ? idx + ((this.tilecnt-1) * this.tilecnt) : idx - this.tilecnt; + t.btidx = (j < this.tilecnt-1) ? idx + this.tilecnt : idx; + + t.x = tilesize*t.tx + ofsx; + t.y = tilesize*t.ty + ofsy; + + i++; + idx++; + } + + } + + override function centerUpdated(clearQueue:Bool) + { + if (!this.initialized) + return; + + if (clearQueue) + { + saveImages(); + clear(); + } + + alignLayer(); + + initTile(); + emitRequests(); + } + + + + override function updateContent(forceUpdate:Bool=false) + { + var i = 0; + + //move tiles if it is needed + while (i < tiles.length / 2) + { + if (!testAndShift()) + break; + + i++; + } + + if ((i == 0) && (!forceUpdate)) + return; + + //update tile positions + for (t in tiles) + { + t.x = tilesize*t.tx + ofsx; + t.y = tilesize*t.ty + ofsy; + } + + //load required images + emitRequests(); + } + + override function updateChanged() + { + if (!this.updateEnabled) + loader.clear(); + } + + override function zoomChanged(prevEnabled:Bool, newZoom:Int) + { + var lp:Int = 0; + var tp:Int = 0; + var tilehsize:Float = tilesize / 2; + + if (this.zoom > newZoom) + { + + if (smooth) { + //smooth zoom - combines four tiles into one + + var bx:Int = (basetid.x & 1) ^ 1; + var by:Int = (basetid.y & 1) ^ 1; + + for (t in tiles) + { + if ((t.tx & 1 == bx) || (t.ty & 1 == by)) continue; + + var bd = new flash.display.BitmapData(tilesize, tilesize, false, 0xFFFFFF); + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(0.5, 0.5); + if (t.image != null) + bd.draw(t.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(0,0,tilehsize,tilehsize), false); + + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(0.5, 0.5); + scaleMatrix.translate(tilehsize,0); + var tt = tiles[t.rtidx]; + if ((tt.tx != this.lx) && (tt.image != null)) + bd.draw(tt.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(tilehsize,0,tilehsize,tilehsize), false); + + + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(0.5, 0.5); + scaleMatrix.translate(0,tilehsize); + var tt = tiles[t.btidx]; + if ((tt.ty != this.ty) && (tt.image != null)) + bd.draw(tt.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(0,tilehsize,tilehsize,tilehsize), false); + + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(0.5, 0.5); + scaleMatrix.translate(tilehsize,tilehsize); + var tt = tiles[tiles[t.btidx].rtidx]; + if ((tt.tx != this.lx) && (tt.ty != this.ty) && (tt.image != null)) + bd.draw(tt.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(tilehsize,tilehsize,tilehsize,tilehsize), false); + + loader.addTile((((mapservice.invert_x) ? -t.tx : t.tx) + basetid.x) >> 1, + (((mapservice.invert_y) ? -t.ty : t.ty) + basetid.y) >> 1, + newZoom + basetid.z, + bd, false + ); + + } + } + + //zoom out + if (basetid.x & 1 == 1) x -= tilesize/2; + if (basetid.y & 1 == 1) y -= tilesize/2; + basetid.x = basetid.x >> 1; + basetid.y = basetid.y >> 1; + + ofsx = ofsx / 2.0; + ofsy = ofsy / 2.0; + + //coeficients for the /2 transformation + // x' = x/2 == x - x/2 + // y' = y/2 == y - y/2 + lp = - Std.int(this.lx/2); + tp = - Std.int(this.ty/2); + + } + else + { + + if (smooth) + { + //smooth zoom - each tile is splited into the four tiles + var mintx:Int = Std.int((3*this.lx + this.rx + 1) / 4); + var maxtx:Int = Std.int((3*this.rx + this.lx + 3) / 4); + var minty:Int = Std.int((3*this.ty + this.by + 1) / 4); + var maxty:Int = Std.int((3*this.by + this.ty + 3) / 4); + for (t in tiles) + if ((t.image != null) && (t.tx >= mintx) && (t.tx <= maxtx) && (t.ty >= minty) && (t.ty <= maxty)) + { + var bd = new flash.display.BitmapData(tilesize, tilesize, false, 0xFFFFFF); + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(2, 2); + bd.draw(t.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(0,0,tilesize,tilesize), false); + loader.addTile((((mapservice.invert_x) ? -t.tx : t.tx) + basetid.x)*2, + (((mapservice.invert_y) ? -t.ty : t.ty) + basetid.y)*2, + newZoom + basetid.z, bd, false + ); + + + var bd = new flash.display.BitmapData(tilesize, tilesize, false, 0xFFFFFF); + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(2, 2); + scaleMatrix.translate(-tilesize,0); + bd.draw(t.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(0,0,tilesize,tilesize), false); + loader.addTile((((mapservice.invert_x) ? -t.tx : t.tx) + basetid.x)*2 + 1, + (((mapservice.invert_y) ? -t.ty : t.ty) + basetid.y)*2, + newZoom + basetid.z, bd, false + ); + + + var bd = new flash.display.BitmapData(tilesize, tilesize, false, 0xFFFFFF); + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(2, 2); + scaleMatrix.translate(0,-tilesize); + bd.draw(t.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(0,0,tilesize,tilesize), false); + loader.addTile((((mapservice.invert_x) ? -t.tx : t.tx) + basetid.x)*2, + (((mapservice.invert_y) ? -t.ty : t.ty) + basetid.y)*2 + 1, + newZoom + basetid.z, bd, false + ); + + + var bd = new flash.display.BitmapData(tilesize, tilesize, false, 0x00FF00); + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(2, 2); + scaleMatrix.translate(-tilesize,-tilesize); + bd.draw(t.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(0,0,tilesize,tilesize), false); + loader.addTile((((mapservice.invert_x) ? -t.tx : t.tx) + basetid.x)*2 + 1, + (((mapservice.invert_y) ? -t.ty : t.ty) + basetid.y)*2 + 1, + newZoom + basetid.z, bd, false + ); + + } + } + + //zoom in + basetid.x = basetid.x << 1; + basetid.y = basetid.y << 1; + + ofsx = ofsx * 2.0; + ofsy = ofsy * 2.0; + + //coeficients for the *2 transformation + // x' = x*2 == x + x + // y' = y*2 == y + y + lp = this.lx; + tp = this.ty; + + + } + + //transform tile id's + for (t in tiles) + { + t.tx += lp; + t.ty += tp; + } + + this.rx += lp; + this.by += tp; + this.lx += lp; + this.ty += tp; + + //update zoom, reset scale + this.zoom = newZoom; + + scaleX = 1; + scaleY = 1; + + clear(); + center = this.lastcenter; + centerUpdated(false); + + dispatchEvent(new Event(Layer.ZOOM_FINISHED)); + + if ((prevEnabled) && (!this.updateEnabled)) + { + this.updateEnabled = true; + updateChanged(); + } + + updateContent(true); + } + + function testAndShift() : Bool + { + var mv_left = ((this.lx+this.tofs)*tilesize*scaleX + this.x > bbox.x); + var mv_right = ((this.rx-this.tofs)*tilesize*scaleX + this.x < (bbox.x+bbox.width)); + var mv_up = ((this.ty+this.tofs)*tilesize*scaleY + this.y > bbox.y); + var mv_down = ((this.by-this.tofs)*tilesize*scaleY + this.y < (bbox.y+bbox.height)); + + if ((mv_left) && ((this.rx-1)*tilesize*scaleX + this.x < (bbox.x+bbox.width))) + mv_left = false; + if ((mv_up) && ((this.by-1)*tilesize*scaleY + this.y < (bbox.y+bbox.height))) + mv_up = false; + if ((mv_right) && ((this.lx+1)*tilesize*scaleX + this.x > bbox.x)) + mv_right = false; + if ((mv_down) && ((this.ty+1)*tilesize*scaleY + this.y > bbox.y)) + mv_down = false; + + if (mv_left && mv_right) mv_right = false; + if (mv_up && mv_down) mv_down = false; + + if (!(mv_left || mv_right || mv_up || mv_down)) return false; + + for (t in tiles) + { + if ((mv_left) && (t.tx == rx)) + t.tx = lx - 1; + if ((mv_right) && (t.tx == lx)) + t.tx = rx + 1; + if ((mv_up) && (t.ty == by)) + t.ty = ty - 1; + if ((mv_down) && (t.ty == ty)) + t.ty = by + 1; + } + var dx = (mv_left) ? -1 : ((mv_right) ? 1 : 0); + var dy = (mv_up) ? -1 : ((mv_down) ? 1 : 0); + + lx += dx; + rx += dx; + ty += dy; + by += dy; + + return true; + } + + function alignLayer() + { + + if (center == null) return; + + x = this.canvascenter.x; + y = this.canvascenter.y; + + basetid = mapservice.lonlat2tile(center.lng, center.lat, basetid.z+zoom); + var ptc = mapservice.lonlat2XY(center.lng, center.lat, basetid.z); + var ll = mapservice.tile2lonlat(basetid); + var ptt = mapservice.lonlat2XY(ll.x, ll.y, basetid.z); + basetid.z -= zoom; + ptt = ptt.subtract(ptc); + ofsx = ptt.x; + ofsy = ptt.y; + } + + + function emitRequests() + { + var prio:Int = 0; + var xx:Float; + var yy:Float; + + loader.disable(); + + try + { + loader.tidyQueue(((mapservice.invert_x) ? -lx : lx) + basetid.x, ((mapservice.invert_x) ? -rx : rx) + basetid.x, + ((mapservice.invert_y) ? -ty : ty) + basetid.y, ((mapservice.invert_y) ? -by : by) + basetid.y, + zoom + basetid.z + ); + + for (tile in tiles) + { + if (tile.needImage()) + { + + + xx = (tile.x + x - ofsx - this.canvascenter.x); + yy = (tile.y + y - ofsy - this.canvascenter.y); + prio = Std.int(Math.sqrt(xx*xx + yy*yy)); + + loader.addRequest( ((mapservice.invert_x) ? -tile.tx : tile.tx) + basetid.x, + ((mapservice.invert_y) ? -tile.ty : tile.ty) + basetid.y, + zoom + basetid.z, + tile.tidx, + prio + ); + + tile.waitForImage(); + } + } + + } catch (unknown : Dynamic) {}; + + loader.enable(); + } + + + function tileLoaded(e:TileLoadedEvent) + { + if ((e.tidx >= 0) && (e.tidx < tiles.length)) + { + + var t:Tile = tiles[e.tidx]; + if ((t != null) && + (((mapservice.invert_x) ? -t.tx : t.tx) == e.x - basetid.x) && //check x-id + (((mapservice.invert_y) ? -t.ty : t.ty) == e.y - basetid.y) && //check y-id + (e.z - basetid.z == zoom) //check z + ) + { + + #if TILE_EVT_DBG + try { + ExternalInterface.call("debugMessage", "tileLoaded "+e.data+" x:"+t.tx+" y:"+t.ty+" ("+e.x+","+e.y+","+e.z+") priority:"+e.p); + } catch (unknown : Dynamic) { }; + #end + + t.assignImage(e.data); + } + } + } + + + function saveImages() + { + for (t in tiles) + if (t.image != null) + loader.addTile(((mapservice.invert_x) ? -t.tx : t.tx) + basetid.x, + ((mapservice.invert_y) ? -t.ty : t.ty) + basetid.y, + zoom + basetid.z, + t.image.bitmapData + ); + + + } + +} diff --git a/src/map/.svn/text-base/TileLoader.hx.svn-base b/src/map/.svn/text-base/TileLoader.hx.svn-base new file mode 100644 index 0000000..fd960a9 --- /dev/null +++ b/src/map/.svn/text-base/TileLoader.hx.svn-base @@ -0,0 +1,547 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +import map.Utils; + +import flash.events.Event; +import flash.events.EventDispatcher; +import flash.events.IOErrorEvent; +import flash.display.Loader; +import flash.display.Bitmap; +import flash.display.BitmapData; +import flash.net.URLRequest; +import flash.system.LoaderContext; + +import flash.utils.Timer; +import flash.events.TimerEvent; + +#if TILE_EVT_DBG +import flash.external.ExternalInterface; +#end + +typedef TileIDT = { + var x : Int; + var y : Int; + var z : Int; + var tidx : Int; + var ttl : Int; + var priority: Int; +}; + + +class TileLoadedEvent extends flash.events.Event +{ + public static var TILE_LOADED:String = "tileLoaded"; + + public var x:Int; + public var y:Int; + public var z:Int; + public var p:Int; + public var tidx:Int; + public var data:Bitmap; + + public function new(x:Int, y:Int, z:Int, tidx:Int, p:Int, data:Bitmap) { + super(TILE_LOADED); + this.x = x; + this.y = y; + this.z = z; + this.p = p; + this.tidx = tidx; + this.data = data; + } +} + +class ImageLoader extends Loader +{ + static var TIMEOUT:Int = 5; //10 sec + + public var used:Bool; + public var ignore:Bool; + public var id:Int; + public var ttl:Int; + public var tid:TileIDT; + + + public function new(id:Int) + { + super(); + this.used = false; + this.ignore = false; + this.id = id; + this.ttl = TIMEOUT; + } + + public function loadImage(tid:TileIDT, url:String) { + var urlRequest:URLRequest = new URLRequest(url); + this.tid = tid; + try { + + #if TILE_EVT_DBG + try { + ExternalInterface.call("debugMessage", "loadImage "+id+" ("+tid.x+","+tid.y+","+tid.z+") prio:"+tid.priority); + } catch (unknown : Dynamic) { }; + #end + + this.load(urlRequest, new LoaderContext(true)); + this.used = true; + this.ttl = TIMEOUT; + + } + catch (unknown : Dynamic) + { + this.used = false; + } + } + + override public function toString() + { + return "[ImageLoader id:" + id + "]"; + } + +} + +typedef TempTile = { + var x : Int; + var y : Int; + var z : Int; + var img : BitmapData; + var ttl : Int; + var original : Bool; +}; + +class TileLoader extends EventDispatcher +{ + public static var DEFAULT_TTL:Int = 3; + public var mapservice:MapService; + var loaders:Array; + var queue:Array; + var tempqueue:Array; + var enabled:Int; + var watchdog:Timer; + + public function new(threads:Int = 8) + { + super(); + + mapservice = null; + enabled = 0; + + watchdog = new Timer(1000, 0); + watchdog.addEventListener(TimerEvent.TIMER, checkLoaders); + watchdog.stop(); + + loaders = new Array(); + queue = new Array(); + tempqueue = new Array(); + + for (i in 0...threads) + { + var l = new ImageLoader(i); + l.contentLoaderInfo.addEventListener(flash.events.Event.COMPLETE, loaderComplete); + l.contentLoaderInfo.addEventListener(flash.events.IOErrorEvent.IO_ERROR, loaderError); + loaders.push(l); + + } + } + + /*============================================================================================== + PUBLIC methods + *==============================================================================================*/ + + public function clear() + { + clearQueue(); + + for (l in loaders) + if (l.used) + { + l.ignore = true; + try { + //l.close(); //BUGGY! + //l.unload(); + } + catch (unknown : Dynamic) + { }; + } + + } + + public function enable() + { + if (enabled > 0) + enabled--; + + if (enabled == 0) + { + sortQueue(); + processQueue(); + + if (!watchdog.running) + watchdog.start(); + } + } + + public function disable() + { + if (watchdog.running) + watchdog.stop(); + + enabled++; + } + + + public function tidyQueue(minx:Int, maxx:Int, miny:Int, maxy:Int, z:Int) + { + var i:Int = 0; + while (i < queue.length) + { + var tid:TileIDT = queue[i]; + if (tid.z == z) + { + if ((tid.x < minx) || (tid.x > maxx) || (tid.y < miny) || (tid.y > maxy)) + queue.remove(tid); + else + i += 1; + } + else + queue.remove(tid); + } + } + + public function addRequest(x:Int, y:Int, z:Int, tidx:Int, priority:Int = 0) + { + if ((x < 0) || (y < 0) || (z < 0)) return; + + var q:TempTile = getTile(x, y, z); + if (q != null) + { + tempqueue.remove(q); + dispatchEvent(new TileLoadedEvent(x,y,z,tidx,priority, new Bitmap(q.img))); + if (q.original) + return; + } + + for (l in loaders) + if ((l.used) && (!l.ignore) && (l.tid.x == x) && (l.tid.y == y) && (l.tid.z == z)) + return; //request already served, return + + var exists:Bool = false; + for (tid in queue) + if ((tid.x == x) && (tid.y == y) && (tid.z == z)) + { + //request already in queue, update priority + tid.priority = priority; + exists = true; + break; + } + + if (!exists) + queue.push({x:x,y:y,z:z,tidx:tidx,priority:priority,ttl:DEFAULT_TTL}); + + if (enabled == 0) + { + sortQueue(); + processQueue(); + } + + } + + public function addTile(x:Int, y:Int, z:Int, img:BitmapData, original:Bool = true) + { + //check if the tile image is not already in queue + var tmp:TempTile = getTile(x,y,z); + if (tmp != null) + { + if (((!tmp.original) && (original)) || ((!tmp.original) && (!original))) + { + tmp.img = img; + tmp.original = original; + tmp.ttl = DEFAULT_TTL; + } + return; + } + + insertTile({x: x, y: y, z: z, img: img, ttl:DEFAULT_TTL, original:original}); + } + + override public function toString() : String + { + var used = 0; + for (l in loaders) + if (l.used) + used++; + + return "[TileLoader] threads total:" + loaders.length + ", active threads:" + used + ", enabled threads:" + enabled; + } + + /*============================================================================================== + PRIVATE methods + *==============================================================================================*/ + function clearQueue() + { + while (queue.length > 0) + queue.pop(); + } + + function checkLoaders(e:TimerEvent) + { + //watchdog timer event + + //check for broken loaders + var used = 0; + for (l in loaders) + if (l.used) + { + if (l.ttl > 0) + l.ttl--; + else if (l.ttl == 0) + loaderFailed(l); + used++; + } + + var i=0; + var q:TempTile; + //remove unused tiles in tempqueue + while (i < tempqueue.length) + { + q = tempqueue[i]; + + if (q.ttl > 0) + q.ttl--; + else if (q.ttl == 0) + { + tempqueue.remove(q); + continue; + } + + i++; + used++; + } + + if ((used == 0) && (watchdog.running)) + watchdog.stop(); + + } + + + function sortQueue() + { + queue.sort(function(x:TileIDT,y:TileIDT):Int { return x.priority - y.priority;}); + } + + + function processQueue() + { + + if ((enabled != 0) || (queue.length == 0) || (mapservice == null)) + return; + + if (queue.length == 0) + return; + + var tid:TileIDT; + for (l in loaders) + { + if (l.used) + continue; + + #if TILE_EVT_DBG + try { + ExternalInterface.call("debugMessage", "processQueue qlen:"+queue.length); + } catch (unknown : Dynamic) { }; + #end + + if (queue.length == 0) return; + + tid = queue.shift(); + + var url:String = mapservice.tile2url(tid); + if (url != "") + l.loadImage(tid, url); + + if (!watchdog.running) + watchdog.start(); + + } + + } + + function loaderComplete(e:Event) + { + + if ((e.target == null) || (e.target.loader == null)) + return; + + var loader:ImageLoader = e.target.loader; + + if (!loader.ignore) + { + try { + var x:Int = loader.tid.x; + var y:Int = loader.tid.y; + var z:Int = loader.tid.z; + var t:Int = loader.tid.tidx; + var p:Int = loader.tid.priority; + + #if TILE_EVT_DBG + try { + ExternalInterface.call("debugMessage", "tileLoaded ("+x+","+y+","+z+") priority:"+p); + } catch (unknown : Dynamic) { }; + #end + + var bitmapc:Bitmap = new Bitmap(cast(loader.content, Bitmap).bitmapData.clone()); + dispatchEvent(new TileLoadedEvent(x,y,z,t,p, bitmapc)); + + } + catch (unknown : Dynamic) + { + + //chyba, znovu do fronty, pokud jiz neni vycerpan poc. pokusu + if (loader.tid.ttl > 0) + { + queue.push({x:loader.tid.x, y:loader.tid.y, z:loader.tid.z, + tidx:loader.tid.tidx, + ttl:loader.tid.ttl - 1, + priority:loader.tid.priority + }); + if (enabled == 0) + sortQueue(); + } + + }; + } + else + { + #if TILE_EVT_DBG + try { + ExternalInterface.call("debugMessage", "tileIgnored"); + } catch (unknown : Dynamic) { }; + #end + } + + try { + loader.unload(); + } catch (unknown : Dynamic) {}; + + loader.used = false; + loader.ignore = false; + + processQueue(); + } + + function loaderFailed(l:ImageLoader) + { + l.used = false; + l.ignore = false; + + #if TILE_EVT_DBG + try { + ExternalInterface.call("debugMessage", "tileError " + l.tid.x + ","+l.tid.y+","+l.tid.z); + } catch (unknown : Dynamic) { }; + #end + + if ((l.tid.ttl > 0) && (!l.ignore)) + { + //loading failed, return request back to the queue + queue.push({x:l.tid.x,y:l.tid.y,z:l.tid.z,tidx:l.tid.tidx,ttl:l.tid.ttl - 1,priority:l.tid.priority}); + + if (enabled == 0) + sortQueue(); + } + + processQueue(); + } + + + function loaderError(e:IOErrorEvent) + { + + for (l in loaders) + if (l.contentLoaderInfo == e.target) + loaderFailed(l); + } + + function getTile(x:Int, y:Int, z:Int) : TempTile + { + //looking for a tile in the sorted array + + var min:Int = 0; + var max:Int = tempqueue.length-1; + var mid:Int; + var val:Int; var cmp:Int; + while (min <= max) { + mid = Math.floor((min + max) / 2); + + cmp = (x - tempqueue[mid].x); + if (cmp == 0) cmp = (y - tempqueue[mid].y); + if (cmp == 0) cmp = (z - tempqueue[mid].z); + + if (cmp == 0) + return tempqueue[mid] + else if (cmp > 0) + min = mid + 1; + else + max = mid - 1; + + } + + return null; + } + + function insertTile(t:TempTile) + { + //insert TempTile into the sorted array + + var min:Int = 0; + var max:Int = tempqueue.length-1; + var mid:Int; + var val:Int; var cmp:Int; + + while (min <= max) { + mid = Math.floor((min + max) / 2); + + cmp = (t.x - tempqueue[mid].x); + if (cmp == 0) cmp = (t.y - tempqueue[mid].y); + if (cmp == 0) cmp = (t.z - tempqueue[mid].z); + + if (cmp > 0) + min = mid + 1; + else + max = mid - 1; + + } + + tempqueue.insert(min, t); + } + +} + diff --git a/src/map/.svn/text-base/Utils.hx.svn-base b/src/map/.svn/text-base/Utils.hx.svn-base new file mode 100644 index 0000000..5f9b407 --- /dev/null +++ b/src/map/.svn/text-base/Utils.hx.svn-base @@ -0,0 +1,74 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +import flash.geom.Point; +import flash.filters.ColorMatrixFilter; + +class Utils +{ + public static function dec2hex(i:Int, digits:Int) + { + var c = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']; + var s:String = ''; + var val = i; + for (j in 0...digits) + { + s = c[val % 16] + s; + val = val >> 4; + } + return s; + } + + public static function desaturationFilter(sat:Float = 1.0) : ColorMatrixFilter + { + var r = 0.212671; + var g = 0.715160; + var b = 0.072169; + return new ColorMatrixFilter( + [/* R */ sat*r+1-sat, sat*g, sat*b, 0, 0, + /* G */ sat*r, sat*g+1-sat, sat*b, 0, 0, + /* B */ sat*r, sat*g, sat*b+1-sat, 0, 0, + /* A */ 0, 0, 0, 1, 0 + ] + ); + } + +} + +typedef LonLat = Point; /* for internal usage */ + +typedef TileID = { + var x : Int; + var y : Int; + var z : Int; +}; + diff --git a/src/map/Canvas.hx b/src/map/Canvas.hx new file mode 100644 index 0000000..d631463 --- /dev/null +++ b/src/map/Canvas.hx @@ -0,0 +1,676 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +import com.Component; + +import map.MapService; +import map.LngLat; +import flash.events.Event; +import flash.events.MouseEvent; +import flash.geom.Point; +import flash.geom.Rectangle; +import flash.utils.Timer; +import flash.events.TimerEvent; +import flash.display.Shape; +import flash.display.BitmapData; + + +typedef ALayer = { + var layer : Layer; + var enabled : Bool; +} + +class MapEvent extends flash.events.Event +{ + public static var MAP_CLICKED:String = "mapclicked"; + public static var MAP_MOUSEMOVE:String = "mapmousemove"; + public static var MAP_MOVE:String = "mapmove"; + public static var MAP_ZOOMCHANGED:String = "mapzoom"; + public static var MAP_CHANGED:String = "mapchanged"; + + public var point:LngLat; + + public function new(event:String, point:LngLat = null) { + super(event); + this.set_point( point ); + } + public function set_point(point : LngLat) + { + this.point = point; + } + public function get_point(t) + { + return this.point; + } + +} + + +class Canvas extends Component +{ + var layers:Array; + var start:Point; + var initialized:Bool; + var zoom:Int; + var animTimer : Timer; + var animTo:LngLat; + var center:LngLat; + var thpassed:Bool; + var thtimer:Timer; + var mappoint:LngLat; + public var mousethreshold:Int; //the minimal number of pixels that have to be passed in order to start moving + public var transparent:Bool; + + public function new(interactive:Bool = true) + { + super(); + + this.initialized = false; + this.start = null; + this.zoom = 0; + this.mousethreshold = 5; + this.thpassed = false; + this.thtimer = null; + this.animTimer = new Timer(50, 0); + this.center = new LngLat(16.722079,49.577496); + this.layers = new Array(); + this.doubleClickEnabled = true; + this.transparent = false; +/* + contextMenu = new flash.ui.ContextMenu(); + contextMenu.hideBuiltInItems(); + var itm = new flash.ui.ContextMenuItem("HaxeMaps"); + itm.addEventListener(flash.events.ContextMenuEvent.MENU_ITEM_SELECT, + function(e) { flash.Lib.getURL(new flash.net.URLRequest("http://code.google.com/p/haxemaps/")); }); + contextMenu.customItems.push(itm); + var itm = new flash.ui.ContextMenuItem(" (C) 2013"); + itm.enabled = false; + contextMenu.customItems.push(itm); +*/ + if (interactive) + { + addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); + addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); + addEventListener(MouseEvent.DOUBLE_CLICK, onMouseDoubleClick); + + var me = this; + /* var itm = new flash.ui.ContextMenuItem("HaxeMaps - zoom in"); + itm.separatorBefore = true; + itm.addEventListener(flash.events.ContextMenuEvent.MENU_ITEM_SELECT, + function(e) { me.zoomIn(); }); + contextMenu.customItems.push(itm); + var itm = new flash.ui.ContextMenuItem("HaxeMaps - Zoom out"); + itm.addEventListener(flash.events.ContextMenuEvent.MENU_ITEM_SELECT, + function(e) { me.zoomOut(); }); + contextMenu.customItems.push(itm); +*/ + } + } + + /*============================================================================================== + LAYER MANAGEMENT + *==============================================================================================*/ + public function initialize() + { + if (initialized) + return; + + var m:MapService = null; + + //find the first defined service + for (l in layers) + if (l.layer.mapservice != null) + { + m = l.layer.mapservice; + break; + } + + //Check if there is a layer containing mapservice + if (m == null) + return; + + //initialize the layers + for (l in layers) + { + if (l.layer.mapservice == null) + l.layer.mapservice = m; + + if (l.enabled) + { + initializeLayer(l); + addChild(l.layer); + } + } + + initialized = true; + dispatchEvent(new MapEvent(MapEvent.MAP_CHANGED, null)); + } + + public function addLayer(layer:Layer, enable:Bool=true) + { + for (l in layers) + if (l.layer == layer) + return; + + var alayer:ALayer = {layer:layer, enabled:false}; + layers.push(alayer); + layer.addEventListener(Layer.ZOOM_FINISHED, zoomFinished); + + if ((initialized) && (enable)) //synchronize + { + initializeLayer(alayer); + dispatchEvent(new MapEvent(MapEvent.MAP_CHANGED, null)); + } + + alayer.enabled = enable; + } + + public function removeLayer(layer:Layer) + { + for (l in layers) + { + if (l.layer == layer) + { + removeChild(layer); + layer.removeEventListener(Layer.ZOOM_FINISHED, zoomFinished); + layer.clear(); + layers.remove(l); + return; + } + } + } + + public function enableLayer(layer:Layer) + { + var childidx = 0; + for (i in 0...layers.length) + { + + var l:ALayer = layers[i]; + if (l.layer == layer) + { + if (l.enabled) + break; + + l.enabled = true; + + if (initialized) + { + initializeLayer(l, false); + dispatchEvent(new MapEvent(MapEvent.MAP_CHANGED, null)); + } + + if (i == layers.length - 1) + addChild(l.layer); + else + addChildAt(l.layer, childidx); + return; + } + + if (l.enabled) + childidx++; + } + } + + public function disableLayer(layer:Layer) + { + for (l in layers) + if (l.layer == layer) + { + if (!l.enabled) + break; + + removeChild(l.layer); + l.layer.clear(); + l.enabled = false; + + return; + } + } + + public function updateLayer(layer:Layer) + { + for (l in layers) + if (l.layer == layer) + { + if (l.enabled) + l.layer.update(); + return; + } + + } + + public function layerEnabled(layer:Layer) + { + for (l in layers) + if (l.layer == layer) + return l.enabled; + + return false; + } + + function initializeLayer(alayer:ALayer, canAdd:Bool = true) + { + if (alayer.layer.mapservice == null) + { + for (l in layers) + if (l.layer.mapservice != null) + { + alayer.layer.mapservice = l.layer.mapservice; + break; + } + } + + if (alayer.layer.mapservice == null) + return; + + var sz = getSize(); + var center:LngLat = this.center; + + if (initialized) + { + //synchronize position + for (l in layers) + if ((l != alayer) && (l.enabled) && (l.layer.mapservice != null)) + { + center = l.layer.getCenter(); + //trace("Init new center:"+center); + break; + } + } + + alayer.layer.finalize(); + alayer.layer.setCenter(center); + alayer.layer.setBBox(new Rectangle(0,0,sz.width,sz.height)); + alayer.layer.setZoom(this.zoom); + alayer.layer.initialize(); + + if ((!alayer.enabled) && (canAdd)) + addChild(alayer.layer); + } + + /*============================================================================================== + POSITION / ZOOM + *==============================================================================================*/ + public function zoomIn() + { + for (l in layers) + if ((l.enabled) && (!l.layer.validZoom(this.zoom + 1))) + return; + + this.zoom += 1; + for (l in layers) + if (l.enabled) + l.layer.zoomIn(); + } + + public function zoomOut() + { + for (l in layers) + if ((l.enabled) && (!l.layer.validZoom(this.zoom - 1))) + return; + + this.zoom -= 1; + for (l in layers) + if (l.enabled) + l.layer.zoomOut(); + } + + public function getZoom() : Int + { + return this.zoom; + } + + public function getMinZoom() : Int + { + var z:Int = this.zoom - 1; + while (z > -16) + { + var vld:Bool = true; + + for (l in layers) + if ((l.enabled) && (!l.layer.validZoom(z))) + { + vld = false; + break; + } + + if (!vld) + break; + + z--; + } + + return z + 1; + } + + public function getMaxZoom() : Int + { + var z:Int = this.zoom + 1; + while (z > -16) + { + var vld:Bool = true; + + for (l in layers) + if ((l.enabled) && (!l.layer.validZoom(z))) + { + vld = false; + break; + } + + if (!vld) + break; + + z++; + } + + return z - 1; + } + + public function setZoom(zoom:Int) + { + for (l in layers) + if ((l.enabled) && (!l.layer.validZoom(zoom)) && (l.layer.mapservice != null)) + return; + + this.zoom = zoom; + + if (!initialized) return; + + for (l in layers) + if (l.enabled) + l.layer.setZoom(this.zoom); + } + + public function setCenter(point:LngLat) + { + if (!initialized) + { + center = point; + return; + } + + for (l in layers) + if (l.enabled) + l.layer.setCenter(point); + + + dispatchEvent(new MapEvent(MapEvent.MAP_CHANGED, null)); + } + + public function getCenter(): LngLat + { + var c:LngLat = center.clone(); + if (initialized) + for (l in layers) + if (l.enabled) + { + c = l.layer.getCenter(); + break; + } + + return c; + } + + public function getLngLat(global:Point) : LngLat + { + if (initialized) + for (l in layers) + if (l.enabled) + return l.layer.getLngLat(l.layer.globalToLocal(global)); + return null; + } + + public function getLeftTopCorner() : LngLat + { + return getLngLat(localToGlobal(new Point(0,0))); + } + + public function getRightBottomCorner() : LngLat + { + var sz = getSize(); + return getLngLat(localToGlobal(new Point(sz.width,sz.height))); + } + + public function panTo(point:LngLat) + { + if (this.animTimer.running) + { + this.animTo = point.clone(); + return; + } + + for (l in layers) + if (l.enabled) + { + this.animTo = point.clone(); + this.animTimer.addEventListener(TimerEvent.TIMER, animStep); + this.animTimer.start(); + + return; + } + } + + + public function getBitmap() : BitmapData + { + var sz = getSize(); + var bmp:BitmapData = new BitmapData(Std.int(sz.width), Std.int(sz.height), false, 0x00FFFFFF); + bmp.draw(this); + return bmp; + } + + /*============================================================================================== + PRIVATE methods + *==============================================================================================*/ + function set_transparent(val:Bool): Bool + { + this.transparent = val; + + graphics.clear(); + if (this.transparent) + return true; + + var sz = getSize(); + graphics.beginFill(0xFFFFFF); + graphics.drawRect(0,0,sz.width,sz.height); + graphics.endFill(); + + return this.transparent; + } + + override function onResize(w:Float, h:Float) + { + set_transparent(this.transparent); + scrollRect = new Rectangle(0, 0, w, h); + + //trace("Canvas resized w:"+w+" h:"+h); + for (l in layers) + l.layer.setBBox(new Rectangle(0,0,w,h)); + } + + function onMouseDown(e:MouseEvent) + { + var tl:Point = localToGlobal(new Point(0,0)); + var br:Point = localToGlobal(new Point(width, height)); + + start = new Point(e.stageX, e.stageY); + thpassed = false; + + removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); + removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); + flash.Lib.current.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); + flash.Lib.current.stage.addEventListener(MouseEvent.MOUSE_MOVE, onStageMouseMove); + } + + function onMouseUp(e:MouseEvent) + { + addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); + addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); + flash.Lib.current.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp); + flash.Lib.current.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onStageMouseMove); + + if ((!thpassed) && (thtimer == null)) + { + mappoint = getLngLat(new Point(e.stageX, e.stageY)); + thtimer = new Timer(300, 1); + thtimer.addEventListener(TimerEvent.TIMER_COMPLETE, fireMapClicked); + thtimer.start(); + } + } + + function fireMapClicked(e:TimerEvent) + { + dispatchEvent(new MapEvent(MapEvent.MAP_CLICKED, mappoint)); + + if (thtimer != null) + { + thtimer.stop(); + thtimer.removeEventListener(TimerEvent.TIMER_COMPLETE, fireMapClicked); + thtimer = null; + } + } + + function onMouseDoubleClick(e:MouseEvent) + { + if (!doubleClickEnabled) return; + + if (thtimer != null) + { + thtimer.stop(); + thtimer.removeEventListener(TimerEvent.TIMER_COMPLETE, fireMapClicked); + thtimer = null; + } + + if (e.ctrlKey) + zoomOut() + else + zoomIn(); + } + + function onMouseMove(e:MouseEvent) + { + for (l in layers) + if (l.enabled) + { + var pt = l.layer.globalToLocal(new Point(e.stageX, e.stageY)); + dispatchEvent(new MapEvent(MapEvent.MAP_MOUSEMOVE, l.layer.getLngLat(pt))); + return; + } + } + + function onStageMouseMove(e:MouseEvent) + { + var pt:Point = new Point(e.stageX, e.stageY); + + if (!thpassed) + { + if (Point.distance(pt, start) < this.mousethreshold) + return; + start = pt; + thpassed = true; + return; + } + + animStop(); + + var diff = pt.subtract(start); + var cntr:LngLat = null; + + for (l in layers) + if (l.enabled) + { + try + { + l.layer.moveRelative(diff.x, diff.y); + cntr = l.layer.getCenter(); + center = cntr; + } + catch (unknown : Dynamic) + {} + } + + if (cntr != null) + { + dispatchEvent(new MapEvent(MapEvent.MAP_MOVE, cntr)); + dispatchEvent(new MapEvent(MapEvent.MAP_CHANGED, null)); + } + start = pt; + } + + + function animStop() + { + if (animTimer.running) + { + animTimer.stop(); + animTimer.removeEventListener(TimerEvent.TIMER, animStep); + } + } + + function animStep(e:flash.events.Event) + { + for (l in layers) + if (l.enabled) + { + try { + var a:Point = l.layer.getCenterXY(); + var b:Point = l.layer.getPointXY(animTo); + var dist:Float = Point.distance(a, b); + if (dist < 1.0) + animStop(); + a = a.subtract(b); + + var k:Float = (dist < 5) ? 1.0 : ((dist < 10) ? 5.0 : 10.0); + a.x = a.x / k; + if (a.x < -64) a.x = -64; + if (a.x > 64) a.x = 64; + a.y = a.y / k; + if (a.y < -64) a.y = -64; + if (a.y > 64) a.y = 64; + + l.layer.moveRelative(a.x, a.y); + + dispatchEvent(new MapEvent(MapEvent.MAP_CHANGED, null)); + } + catch (unknown : Dynamic) + {} + } + } + + + function zoomFinished(e:Event) + { + dispatchEvent(new MapEvent(MapEvent.MAP_ZOOMCHANGED, null)); + dispatchEvent(new MapEvent(MapEvent.MAP_CHANGED, null)); + } +} diff --git a/src/map/Layer.hx b/src/map/Layer.hx new file mode 100644 index 0000000..21dafa6 --- /dev/null +++ b/src/map/Layer.hx @@ -0,0 +1,522 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +import flash.display.Sprite; +import flash.events.Event; +import flash.geom.Point; +import flash.geom.Rectangle; +import flash.utils.Timer; +import flash.events.TimerEvent; +import map.Utils; +import map.LngLat; + +class Layer extends Sprite +{ + public static var ZOOM_FINISHED:String = "zoomfinished"; + + public var bbox(default, null):Rectangle; + var zoom:Int; + var animTimer:Timer; + var animState:Int; + var animTmp:Float; + var initialized:Bool; + var updateEnabled:Bool; + var center:LngLat; + var lastcenter:LngLat; + var canvascenter:Point; + var lastxy:Point; + var lastcxy:Point; + var scalable:Bool; + public var mapservice:MapService; + + public function new(map_service:MapService = null, scalable:Bool = false) + { + super(); + + this.scalable = scalable; + this.mapservice = map_service; + this.initialized = false; + this.updateEnabled = false; + this.bbox = new Rectangle(0,0,flash.Lib.current.stage.width, flash.Lib.current.stage.height); + this.canvascenter = new Point(this.bbox.width/2.0,this.bbox.height/2.0); + this.center = null; + this.zoom = 0; + this.lastxy = null; + this.lastcxy = null; + + animTimer = new Timer(15, 0); + animTimer.addEventListener(TimerEvent.TIMER, animStep); + + mouseEnabled = false; + + } + + /*============================================================================================== + INITIALIZATION / FINALIZATION / MISC + *==============================================================================================*/ + + public function initialize(update:Bool=true) : Int + { + + if (mapservice == null) + return 1; + + if (this.initialized) + finalize(); + + this.x = this.canvascenter.x; + this.y = this.canvascenter.y; + + synchronizeScale(true); + + if (Std.is(this, Layer)) + { + this.initialized = true; + if (!this.updateEnabled) + { + this.updateEnabled = true; + updateChanged(); + } + + if (update) + updateContent(true); + } + + return 0; + } + + public function finalize() + { + if (this.initialized) + clear(); + + this.initialized = false; + } + + + public function setBBox(bbox:Rectangle) + { + if (bbox == null) + return; + + var actcenter:LngLat = null; + if ((this.bbox != null) && (this.initialized)) + actcenter = this.getCenter(); + + this.bbox = bbox; + this.canvascenter = new Point(this.bbox.x + this.bbox.width/2.0, this.bbox.y + this.bbox.height/2.0); + + if (actcenter != null) + this.setCenter(actcenter); + } + + + public function clear() + { + } + + /*============================================================================================== + POSITION + *==============================================================================================*/ + + public function getOriginXY() : Point + { + if (this.mapservice == null) + return new Point(0,0); + + return mapservice.lonlat2XY(center.lng, center.lat, mapservice.zoom_def + zoom); + } + + public function getCenterXY() : Point + { + var pta:Point = getOriginXY(); + pta.offset(-x + this.canvascenter.x, - y + this.canvascenter.y); + return pta; + } + + public function getPointXY(point:LngLat) : Point + { + if (this.mapservice == null) + return new Point(0,0); + + return mapservice.lonlat2XY(point.lng, point.lat, mapservice.zoom_def + zoom); + } + + public function getCenter() : LngLat + { + if (this.mapservice == null) + return null; + + if ((x == this.canvascenter.x) && (y == this.canvascenter.y)) + return center.clone(); + + var z:Int = mapservice.zoom_def + zoom; + var pta:Point = getCenterXY(); + var ptb:LonLat = mapservice.XY2lonlat(pta.x, pta.y, z); + + return new LngLat(ptb.x, ptb.y); + } + + public function getXY(local:Point) : Point + { + var z:Int = mapservice.zoom_def + zoom; + var pta:Point = mapservice.lonlat2XY(center.lng, center.lat, z); + pta.offset(scaleX*local.x, scaleY*local.y); + return pta; + } + + public function getLngLat(local:Point) : LngLat + { + var z:Int = mapservice.zoom_def + zoom; + var pta:Point = mapservice.lonlat2XY(center.lng, center.lat, z); + var ptb:Point = mapservice.XY2lonlat(pta.x + scaleX*local.x, pta.y + scaleY*local.y, z); + return new LngLat(ptb.x, ptb.y); + } + + public function setCenter(point:LngLat) + { + if ((this.scalable) && (initialized)) + synchronizeCenter(point); + else + this.center = point.clone(); + centerUpdated(true); + } + + public function moveTo(x:Float, y:Float) + { + if ((this.animTimer.running) || ((this.x == x) && (this.y == y))) + return; + + + this.x = x; + this.y = y; + + if (this.updateEnabled) + updateContent(); + } + + public function moveRelative(dx:Float, dy:Float) + { + if ((this.animTimer.running) || ((dx == 0) && (dy == 0))) + return; + + this.x += dx; + this.y += dy; + + if (this.updateEnabled) + updateContent(); + } + + public function getOffset() : Point + { + return new Point(this.x - this.canvascenter.x, this.y - this.canvascenter.y); + } + + public function getLeftTopCorner(margin:Float = 0.0) : LngLat + { + if (!initialized) return null; + + var x:Float = this.canvascenter.x - this.x - this.bbox.width/2.0 + margin; + var y:Float = this.canvascenter.y - this.y - this.bbox.height/2.0 + margin; + + var z:Int = mapservice.zoom_def + zoom; + var pta:Point = mapservice.lonlat2XY(center.lng, center.lat, z); + var ptb:Point = mapservice.XY2lonlat(pta.x + scaleX*x, pta.y + scaleY*y, z); + + return new LngLat(ptb.x, ptb.y); + } + + public function getRightBottomCorner(margin:Float = 0.0) : LngLat + { + if (!initialized) return null; + + var x:Float = this.canvascenter.x - this.x + this.bbox.width/2.0 + margin; + var y:Float = this.canvascenter.y - this.y + this.bbox.height/2.0 + margin; + + var z:Int = mapservice.zoom_def + zoom; + var pta:Point = mapservice.lonlat2XY(center.lng, center.lat, z); + var ptb:Point = mapservice.XY2lonlat(pta.x + scaleX*x, pta.y + scaleY*y, z); + + return new LngLat(ptb.x, ptb.y); + } + + + /*============================================================================================== + ZOOM + *==============================================================================================*/ + + public function validZoom(zoom:Int) : Bool + { + return ((!this.animTimer.running) && (this.mapservice != null) && (this.mapservice.validZoom(zoom))); + } + + public function setZoom(zoom:Int) + { + if (!validZoom(zoom)) return; + + this.zoom = zoom; + if (this.scalable) + synchronizeScale(); + + if (!this.initialized) + return; + + this.center = getCenter(); //get actual center & update layer content + centerUpdated(true); + } + + public function zoomIn(animate:Bool = true) + { + if ((this.animTimer.running) || (!this.initialized) || (this.mapservice == null) || (!this.mapservice.validZoom(zoom+1))) + return; + + this.lastxy = new Point(x,y); + this.lastcenter = getCenter(); + this.lastcxy = new Point(this.canvascenter.x, this.canvascenter.y); + + if (!animate) + { + scaleX = scaleX * 2.0; + scaleY = scaleY * 2.0; + + x = lastcxy.x + (lastxy.x - lastcxy.x) * 2.0; + y = lastcxy.y + (lastxy.y - lastcxy.y) * 2.0; + + zoomChanged(this.updateEnabled, zoom + 1); + + return; + } + + + this.animState = 0x0000; + + if (this.updateEnabled) + { + this.updateEnabled = false; + updateChanged(); + this.animState += 0x0100; + } + + this.animTmp = scaleX; + this.animTimer.start(); + } + + public function zoomOut(animate:Bool = true) + { + if ((this.animTimer.running) || (!this.initialized) || (this.mapservice == null) || (!this.mapservice.validZoom(zoom-1))) + return; + + this.lastxy = new Point(x,y); + this.lastcenter = getCenter(); + this.lastcxy = new Point(this.canvascenter.x, this.canvascenter.y); + + if (!animate) + { + scaleX = scaleX / 2.0; + scaleY = scaleY / 2.0; + + x = lastcxy.x + (lastxy.x - lastcxy.x) / 2.0; + y = lastcxy.y + (lastxy.y - lastcxy.y) / 2.0; + + zoomChanged(this.updateEnabled, zoom - 1); + + return; + } + + this.animState = 0x1000; + if (this.updateEnabled) + { + this.updateEnabled = false; + updateChanged(); + this.animState += 0x0100; + } + + this.animTmp = scaleX; + this.animTimer.start(); + } + + public function update() + { + updateContent(true); + } + + /*============================================================================================== + PRIVATE + *==============================================================================================*/ + function updateContent(forceUpdate:Bool=false) + { + } + + function updateChanged() + { + } + + function zoomChanged(prevEnabled:Bool, newZoom:Int) + { + this.zoom = newZoom; + if (!scalable) + { + scaleX = scaleY = 1.0; + + center = this.lastcenter; + centerUpdated(false); + } + else + synchronizeCenter(this.lastcenter); + + dispatchEvent(new Event(ZOOM_FINISHED)); + + if ((prevEnabled) && (!this.updateEnabled)) + { + this.updateEnabled = true; + updateContent(!scalable); + updateChanged(); + } + } + + /*============================================================================================== + PRIVATE + *==============================================================================================*/ + + function synchronizeCenter(point:LngLat) + { + if (!this.scalable) + return; + + var pta:Point = getOriginXY(); + var ptb:Point = getPointXY(point); + this.x = pta.x - ptb.x + canvascenter.x; + this.y = pta.y - ptb.y + canvascenter.y; + } + + function synchronizeScale(init:Bool=false) + { + + if (this.scalable) + { + if (this.zoom < 0) { + scaleX = 1.0 / (1 << (-this.zoom)); + scaleY = 1.0 / (1 << (-this.zoom)); + } else { + scaleX = (1 << this.zoom); + scaleY = (1 << this.zoom); + } + + } + else if ((!this.scalable) && (init)) + { + this.scaleX = 1.0; + this.scaleY = 1.0; + } + + } + + function centerUpdated(clearQueue:Bool) + { + if (!this.initialized) + return; + + if (!this.scalable) + { + this.x = this.canvascenter.x; + this.y = this.canvascenter.y; + } + + if (this.updateEnabled) + updateContent((clearQueue) && (!scalable)); + } + + function animStep(e:flash.events.Event) + { + var steps:Float = 10.0; + + var act = (animState >> 12) & 0x0F; + var en = (animState >> 8) & 0x0F; + var st = (animState & 0xFF); + + if (act == 0) + { + if (st < steps) + { + var scale:Float = (1.0 + (st + 1)/steps); + + scaleX = animTmp * scale; + scaleY = scaleX; + + x = lastcxy.x + (lastxy.x - lastcxy.x) * scale; + y = lastcxy.y + (lastxy.y - lastcxy.y) * scale; + + animState += 1; + } + else if (st == steps) + { + animTimer.stop(); + + scaleX = animTmp * 2.0; + scaleY = animTmp * 2.0; + + x = lastcxy.x + (lastxy.x - lastcxy.x) * 2.0; + y = lastcxy.y + (lastxy.y - lastcxy.y) * 2.0; + + zoomChanged(en == 1, zoom + 1); + } + } + else if (act == 1) + { + if (st < steps) + { + var scale:Float = (1.0 + (st + 1)/steps); + + scaleX = animTmp / scale; + scaleY = scaleX; + + x = lastcxy.x + (lastxy.x - lastcxy.x) / scale; + y = lastcxy.y + (lastxy.y - lastcxy.y) / scale; + + animState += 1; + } + else if (st == steps) + { + animTimer.stop(); + + scaleX = animTmp / 2.0; + scaleY = animTmp / 2.0; + + x = lastcxy.x + (lastxy.x - lastcxy.x) / 2.0; + y = lastcxy.y + (lastxy.y - lastcxy.y) / 2.0; + + zoomChanged(en == 1, zoom - 1); + } + } + } + +} diff --git a/src/map/LngLat.hx b/src/map/LngLat.hx new file mode 100644 index 0000000..7d16363 --- /dev/null +++ b/src/map/LngLat.hx @@ -0,0 +1,85 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +class LngLat +{ + public var lat: Float; + public var lng: Float; + + public function new(lng:Float, lat:Float) + { + this.lng = lng; + this.lat = lat; + } + + inline public function clone() + { + return new LngLat(this.lng, this.lat); + } + + public function toString():String + { + + return "[LngLat] lng:" + fmtCoordinate(this.lng) + " lat:" + fmtCoordinate(this.lat); + } + + //convert coordinate to string (format %.6f) + static public function fmtCoordinate(value:Float) : String + { + var valuef:Float = Math.floor(value); + var f:Float = value - valuef; + var s:String = Std.string(valuef) + "."; + for (i in 0...6) + { + f *= 10.0; + s += Std.string(Math.floor(f)); + f = f - Math.floor(f); + } + return s; + } + + //distance between two points in meters + static public function distance(a:LngLat, b:LngLat) : Float + { + var dlat:Float = (b.lat - a.lat) * Math.PI / 180; + var dlon:Float = (b.lng - a.lng) * Math.PI / 180; + + dlat = Math.sin(dlat/2); + dlon = Math.sin(dlon/2); + var a:Float = dlat*dlat + Math.cos(a.lat * Math.PI / 180 ) * Math.cos(b.lat * Math.PI / 180 ) * dlon*dlon; + var c:Float = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); + c = 6371000.0 * c; //avg. radius of the earth in meters + + return c; + } + +} diff --git a/src/map/MapService.hx b/src/map/MapService.hx new file mode 100644 index 0000000..2a151bb --- /dev/null +++ b/src/map/MapService.hx @@ -0,0 +1,215 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +import map.Utils; +import flash.geom.Point; + +interface MapService +{ + var id(default,null):String; + var zoom_min(default,null):Int; + var zoom_max(default,null):Int; + var zoom_def(default,null):Int; + var tile_size(default,null):Int; + var invert_x(default,null):Bool; + var invert_y(default,null):Bool; + + function lonlat2tile(lon:Float, lat:Float, zoom:Int) : TileID; + function tile2lonlat(t:TileID) : LonLat; + function lonlat2XY(lon:Float, lat:Float, zoom:Int) : Point; + function XY2lonlat(x:Float, y:Float, zoom:Int) : LonLat; + function validZoom(z:Int) : Bool; + function tile2url(t:TileID) : String; +} + +class BaseMapService { + + public var id(default,null):String; + public var zoom_min(default,null):Int; + public var zoom_max(default,null):Int; + public var zoom_def(default,null):Int; + public var tile_size(default,null):Int; + public var invert_x(default,null):Bool; + public var invert_y(default,null):Bool; + + var proxy:Bool; + var proxy_url:String; + + public function new(id:String, abbrev:String, zoom_min:Int, zoom_max:Int, zoom_def:Int, tile_size:Int=256) + { + setInfo(id, abbrev, zoom_min, zoom_max, zoom_def, tile_size); + } + + function setInfo(id:String, abbrev:String, zoom_min:Int, zoom_max:Int, zoom_def:Int, tile_size:Int=256) + { + this.id = id; + this.zoom_min = zoom_min; + this.zoom_max = zoom_max; + this.zoom_def = zoom_def; + this.tile_size = tile_size; + this.invert_x = false; + this.invert_y = false; + this.proxy = false; + + //check if the proxy parameter is set + var params = flash.Lib.current.loaderInfo.parameters; + if ((params != null) && (params.proxy != null) && (params.proxy != "")) + { + this.proxy_url = params.proxy; + if (this.proxy_url.charAt(proxy_url.length-1) != '/') + this.proxy_url += '/'; + this.proxy_url += abbrev + "/"; + this.id += " (Proxy)"; + this.proxy = true; + } + } + + public function validZoom(z:Int) : Bool + { + return (((zoom_def + z) >= zoom_min) && ((zoom_def + z) <= zoom_max)); + } + +} + +class OpenStreetMapService extends BaseMapService implements MapService +{ + // Details: + // --------------------------------------------------------- + // http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames + + override public function new(default_zoom:Int = 13) + { + super("Open Street Map", "osm", 0, 18, default_zoom, 256); + } + + public inline function lonlat2tile(lon:Float, lat:Float, zoom:Int) : TileID + { + var z:Float = Math.pow(2,zoom); + var lr:Float = lat*Math.PI/180; + return {x: (Math.floor((lon+180)/360*z)), + y: (Math.floor(z*(1-Math.log(Math.tan(lr) + 1/Math.cos(lr))/Math.PI)/2)), + z: zoom}; + } + + public inline function lonlat2XY(lon:Float, lat:Float, zoom:Int) : Point + { + var z:Float = tile_size * Math.pow(2,zoom); + var lr:Float = lat*Math.PI/180; + return new Point((Math.floor(z*(lon+180)/360)), + (Math.floor(z*(1-Math.log(Math.tan(lr) + 1/Math.cos(lr))/Math.PI)/2))); + } + + public inline function tile2lonlat(t:TileID) : LonLat + { + var z = Math.pow(2,t.z); + var n = Math.PI-2*Math.PI*t.y/z; + return new LonLat(t.x/z*360-180, 180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n)))); + } + + public inline function XY2lonlat(x:Float, y:Float, zoom:Int) : LonLat + { + var z = tile_size * Math.pow(2, zoom); + var n = Math.PI-2*Math.PI*y/z; + return new LonLat(x/z*360-180, 180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n)))); + } + + public function tile2url(t:TileID) : String + { + if (!isValid(t)) return ""; + + if (!proxy) { + return "http://tile.openstreetmap.org/" + (t.z) + "/" + (t.x) + "/" + (t.y) + ".png"; + // return "http://otile1.mqcdn.com/tiles/1.0.0/map/" + (t.z) + "/" + (t.x) + "/" + (t.y) + ".png"; + + } + + + return this.proxy_url + (t.z) + "_" + (t.x) + "_" + (t.y); + } + + function isValid(t:TileID) : Bool + { + //check zoom + if ((t.z < zoom_min) || (t.z > zoom_max)) return false; + + //check bounds + var z:Float = Math.pow(2, t.z); + if ((t.x < 0) || (t.x >= z) || (t.y < 0) || (t.y >= z)) return false; + + return true; + } + +} + +class BingMapService extends OpenStreetMapService +{ + + // Details: + // --------------------------------------------------------- + // http://msdn.microsoft.com/en-us/library/bb545006.aspx + + var hybrid:Bool; + + override public function new(default_zoom:Int = 13, hybrid:Bool = false) + { + super(); + this.hybrid = hybrid; + setInfo("Bink Maps", "bnk", 1, 18, default_zoom, 256); + + } + + override public function tile2url(t:TileID) : String + { + if (!isValid(t)) return ""; + + if (!proxy) + { + var xx:Int = t.x; + var yy:Int = t.y; + var tid:String = ""; + for (i in 0...t.z) + { + var q:Int = 0; + if ((xx & 1) == 1) q += 1; + if ((yy & 1) == 1) q += 2; + tid = q + tid; + + xx = xx >> 1; + yy = yy >> 1; + } + return "http://tiles.virtualearth.net/tiles/"+(hybrid ? "h" : "r")+tid+".png?g=414&mkt=en-us&shading=hill&n=z"; + } + + return this.proxy_url + (t.z) + "_" + (t.x) + "_" + (t.y); + } + +} diff --git a/src/map/QuadTree.hx b/src/map/QuadTree.hx new file mode 100644 index 0000000..45a789a --- /dev/null +++ b/src/map/QuadTree.hx @@ -0,0 +1,240 @@ +/******************************************************************************* +Copyright (c) 2010, Karel Slany (slany AT fit.vutbr.cz) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +typedef QuadData = { + public var x:Float; + public var y:Float; + public var data:Dynamic; +} + +class QuadLeaf { + public var x:Float; + public var y:Float; + public var data:Array; + public var ll:Dynamic; // < x, < y + public var lg:Dynamic; // < x, >= y + public var gl:Dynamic; // >= x, < y + public var gg:Dynamic; // >= x, >= y + + public function new(xv:Float, yv:Float, d:Dynamic, optfast:Bool) { + x = xv; + y = yv; + data = new Array(); + if (optfast) { + var qd:QuadData = {x:xv, y:yv, data:d}; + data.push(qd); + } else { + data.push(d); + } + ll = lg = gl = gg = null; + } + + public function push(d:Dynamic, optfast:Bool) { + if (optfast) { + var qd:QuadData = {x:x, y:y, data:d}; + data.push(qd); + } else { + data.push(data); + } + } + + public function remove(d:Dynamic, optfast:Bool):Bool { + if (optfast) { + for (itm in data) + if (itm.data == d) + return data.remove(itm); + } else { + return data.remove(d); + } + return false; + } + + public function getData(data:Array, optfast:Bool, filter:QuadData->Bool) { + var qd:QuadData = null;// = {x:0.0, y:0.0, data:null}; + if (optfast) { + for (qd in this.data) { + if ((filter == null) || (filter(qd))) + data.push(qd); + } + } else { + for (i in 0...this.data.length) { + qd.x = x; + qd.y = y; + qd.data = this.data[i]; + if ((filter == null) || (filter(qd))) + data.push(qd); + } + } + } +} + +class QuadTree { + + public var qroot:Dynamic; + var optfast:Bool; + + public function new() { + optfast = true; //true - optimized for maximal speed, + //false - optimized for mimimal memory footprint + qroot = null; + } + + /*============================================================================================== + PUBLIC methods + *==============================================================================================*/ + public function clear() { + qroot = null; + } + + public function isEmpty() { + return qroot == null; + } + + public function push(x:Float, y:Float, data:Dynamic) { + if (qroot != null) { + push_recursive(qroot, x, y, data); + } else { + qroot = new QuadLeaf(x, y, data, optfast); + } + } + + public function remove(x:Float, y:Float, data:Dynamic) : Bool { + // return true if found and removed + if (qroot != null) { + return remove_recursive(qroot, x, y, data); + } + return false; + } + + public function getData(minx:Float, miny:Float, maxx:Float, maxy:Float) : Array { + var data = new Array(); + if (qroot == null) return data; + get_data_recursive(qroot, data, minx, miny, maxx, maxy, null); + return data; + } + + public function getFilteredData(minx:Float, miny:Float, maxx:Float, maxy:Float, filter:QuadData->Bool) : Array { + var data = new Array(); + if (qroot == null) return data; + get_data_recursive(qroot, data, minx, miny, maxx, maxy, filter); + return data; + } + + /*============================================================================================== + PRIVATE methods + *==============================================================================================*/ + + function push_recursive(root:QuadLeaf, x:Float, y:Float, data:Dynamic) { + if ((x == root.x) && (y == root.y)) { + // allows multiple entries + root.push(data, optfast); + } else if (x < root.x) { + if (y < root.y) { + if (root.ll != null) { + push_recursive(root.ll, x, y, data); + } else { + root.ll = new QuadLeaf(x, y, data, optfast); + } + } else { + if (root.lg != null) { + push_recursive(root.lg, x, y, data); + } else { + root.lg = new QuadLeaf(x, y, data, optfast); + } + } + } else { + if (y < root.y) { + if (root.gl != null) { + push_recursive(root.gl, x, y, data); + } else { + root.gl = new QuadLeaf(x, y, data, optfast); + } + } else { + if (root.gg != null) { + push_recursive(root.gg, x, y, data); + } else { + root.gg = new QuadLeaf(x, y, data, optfast); + } + } + } + } + + function remove_recursive(root:QuadLeaf, x:Float, y:Float, data:Dynamic) : Bool { + // does not remove nodes, only removes data entries + if ((x == root.x) && (y == root.y)) { + return root.remove(data, optfast); + } else if (x < root.x) { + if (y < root.y) { + if (root.ll != null) { + return remove_recursive(root.ll, x, y, data); + } + return false; + } else { + if (root.lg != null) { + return remove_recursive(root.lg, x, y, data); + } + return false; + } + } else { + if (y < root.y) { + if (root.gl != null) { + return remove_recursive(root.gl, x, y, data); + } + return false; + } else { + if (root.gg != null) { + return remove_recursive(root.gg, x, y, data); + } + return false; + } + } + } + + function get_data_recursive(root:QuadLeaf, data:Array, minx:Float, miny:Float, maxx:Float, maxy:Float, filter:QuadData->Bool) { + if ((minx <= root.x) && (miny <= root.y) && (maxx >= root.x) && (maxy >= root.y)) { + root.getData(data, optfast, filter); + } + if ((root.ll != null) && (minx <= root.x) && (miny <= root.y)) { + get_data_recursive(root.ll, data, minx, miny, maxx, maxy, filter); + } + if ((root.lg != null) && (minx <= root.x) && (maxy >= root.y)) { + get_data_recursive(root.lg, data, minx, miny, maxx, maxy, filter); + } + if ((root.gl != null) && (maxx >= root.x) && (miny <= root.y)) { + get_data_recursive(root.gl, data, minx, miny, maxx, maxy, filter); + } + if ((root.gg != null) && (maxx >= root.x) && (maxy >= root.y)) { + get_data_recursive(root.gg, data, minx, miny, maxx, maxy, filter); + } + } + +} diff --git a/src/map/Tile.hx b/src/map/Tile.hx new file mode 100644 index 0000000..79c913a --- /dev/null +++ b/src/map/Tile.hx @@ -0,0 +1,174 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +import flash.display.Sprite; +import flash.display.Bitmap; +import flash.text.TextField; +import flash.text.TextFieldAutoSize; + +class Tile extends Sprite +{ + #if TILE_DBG + var t:TextField; + #end + + var size:Int; + var valid:Bool; + public var tx(default, set_tx):Int; + public var ty(default, set_ty):Int; + public var tidx(default, null):Int; + public var image(default, null):Bitmap; + + + public var rtidx:Int; //right neighbour tidx + public var ltidx:Int; //left neighbour tidx + public var ttidx:Int; //top neighbour tidx + public var btidx:Int; //bottom neighbour tidx + + override public function new(tidx:Int, size:Int = 256, x:Int = 0, y:Int = 0) + { + super(); + + #if TILE_DBG + var s:Sprite = new Sprite(); + s.graphics.lineStyle(2, (tidx == 0) ? 0xFF0000 : 0x008000); + s.graphics.moveTo(0,0); + s.graphics.lineTo(size,size); + s.graphics.moveTo(size,0); + s.graphics.lineTo(0,size); + s.graphics.moveTo(size-1,0); + s.graphics.lineTo(size-1,size); + s.graphics.moveTo(0,size-1); + s.graphics.lineTo(size,size-1); + addChild(s); + + t = new TextField(); + t.autoSize = TextFieldAutoSize.LEFT; + t.mouseEnabled = false; + addChild(t); + #end + + this.tidx = tidx; + this.rtidx = -1; + this.ltidx = -1; + this.ttidx = -1; + this.btidx = -1; + + this.tx = x; + this.ty = y; + this.size = size; + this.image = null; + this.valid = false; + mouseEnabled = false; + + update(); + } + + /*============================================================================================== + PUBLIC methods + *==============================================================================================*/ + public function assignImage(image:Bitmap) + { + graphics.clear(); + + if (this.image != null) + { + removeChild(this.image); + this.image = null; + } + + if (image != null) + { + this.image = image; + addChildAt(this.image, 0); + } + else + { + graphics.lineStyle(2, 0xF0F0F0); + graphics.drawCircle(size/2,size/2, 10); + } + + this.valid = (this.image != null); + } + + //returns True iff the tile waits for an image + public function needImage():Bool + { + return !this.valid; + } + + //tile is being loaded + public function waitForImage() + { + } + + public function invalidate() + { + this.valid = false; + } + + /*============================================================================================== + PRIVATE methods + *==============================================================================================*/ + function update() + { + #if TILE_DBG + t.text = "("+tx+","+ty+")"; + t.x = (size - t.width)/2; + t.y = (size - t.height)/2; + #end + } + + + function set_tx(val:Int) : Int + { + if (val != tx) + { + tx = val; + update(); + assignImage(null); + } + return val; + } + + function set_ty(val:Int) : Int + { + if (val != ty) + { + ty = val; + update(); + assignImage(null); + } + return val; + } + +} diff --git a/src/map/TileLayer.hx b/src/map/TileLayer.hx new file mode 100644 index 0000000..fe35261 --- /dev/null +++ b/src/map/TileLayer.hx @@ -0,0 +1,546 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +import map.Tile; +import map.TileLoader; +import map.Layer; +import map.Utils; +import flash.events.Event; +import flash.geom.Point; +import flash.display.Bitmap; + +#if TILE_EVT_DBG +import flash.external.ExternalInterface; +#end + +class TileLayer extends Layer +{ + var tiles:Array; + var tilecnt:Int; + var loader:TileLoader; + + var tofs:Int; /* kdy presunout tiles zprava doleva (kolik za obrazem musi min. byt) */ + var lx:Int; + var rx:Int; + var ty:Int; + var by:Int; + var tilesize:Int; + var basetid:TileID; + var ofsx:Float; + var ofsy:Float; + var smooth:Bool; + + public function new(map_service:MapService = null, tiles:Int = 8, smooth_zoom:Bool = true) + { + super(map_service); + + this.tilecnt = tiles; + this.tiles = new Array(); + this.tilesize = 256; + this.tofs = 1; + this.basetid = {x:0,y:0,z:0}; + this.ofsx = this.ofsy = 0; + this.tofs = 0; + this.smooth = smooth_zoom; + + while (this.tiles.length < this.tilecnt*this.tilecnt) + { + var t:Tile = new Tile(this.tiles.length, this.tilesize); + this.tiles.push(t); + addChild(t); + } + initTile(); + + this.loader = new TileLoader(); + this.loader.addEventListener(TileLoadedEvent.TILE_LOADED, tileLoaded); + } + + /*============================================================================================== + PUBLIC methods + *==============================================================================================*/ + override public function initialize(update:Bool=true) : Int + { + var res = super.initialize(false); + if (res != 0) + return res; + + loader.mapservice = mapservice; + basetid.z = mapservice.zoom_def; + tilesize = mapservice.tile_size; + + alignLayer(); + + initialized = true; + updateEnabled = true; + + if (update) + updateContent(true); + + return 0; + } + + override public function clear() + { + //clean loader queue + loader.clear(); + + //release used images + for (t in tiles) + t.assignImage(null); + } + + override public function getOffset() : Point + { + var tp = tiles.length >> 1; + return new Point(this.x - (this.canvascenter.x - (scaleX*this.tilesize)/2), this.y - (this.canvascenter.y - (scaleY*this.tilesize)/2)); + } + + /*============================================================================================== + PRIVATE methods + *==============================================================================================*/ + function initTile() + { + this.lx = -this.tofs; + this.rx = this.tilecnt-1-this.tofs; + this.ty = -this.tofs; + this.by = this.tilecnt-1-this.tofs; + + var tp = this.tilecnt >> 1; + this.lx = -tp; + this.ty = -tp; + tp = this.tilecnt - tp; + this.rx = tp-1; + this.by = tp-1; + + var i:Int = 0; + var j:Int = 0; + var idx:Int = 0; + + for (t in tiles) + { + if (i == this.tilecnt) + { + i = 0; + j++; + } + + t.tx = this.lx + i; + t.ty = this.ty + j; + + t.ltidx = (i == 0) ? idx + this.tilecnt - 1 : idx - 1; + t.rtidx = (i < this.tilecnt-1) ? idx + 1 : idx - this.tilecnt + 1; + t.ttidx = (j == 0) ? idx + ((this.tilecnt-1) * this.tilecnt) : idx - this.tilecnt; + t.btidx = (j < this.tilecnt-1) ? idx + this.tilecnt : idx; + + t.x = tilesize*t.tx + ofsx; + t.y = tilesize*t.ty + ofsy; + + i++; + idx++; + } + + } + + override function centerUpdated(clearQueue:Bool) + { + if (!this.initialized) + return; + + if (clearQueue) + { + saveImages(); + clear(); + } + + alignLayer(); + + initTile(); + emitRequests(); + } + + + + override function updateContent(forceUpdate:Bool=false) + { + var i = 0; + + //move tiles if it is needed + while (i < tiles.length / 2) + { + if (!testAndShift()) + break; + + i++; + } + + if ((i == 0) && (!forceUpdate)) + return; + + //update tile positions + for (t in tiles) + { + t.x = tilesize*t.tx + ofsx; + t.y = tilesize*t.ty + ofsy; + } + + //load required images + emitRequests(); + } + + override function updateChanged() + { + if (!this.updateEnabled) + loader.clear(); + } + + override function zoomChanged(prevEnabled:Bool, newZoom:Int) + { + var lp:Int = 0; + var tp:Int = 0; + var tilehsize:Float = tilesize / 2; + + if (this.zoom > newZoom) + { + + if (smooth) { + //smooth zoom - combines four tiles into one + + var bx:Int = (basetid.x & 1) ^ 1; + var by:Int = (basetid.y & 1) ^ 1; + + for (t in tiles) + { + if ((t.tx & 1 == bx) || (t.ty & 1 == by)) continue; + + var bd = new flash.display.BitmapData(tilesize, tilesize, false, 0xFFFFFF); + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(0.5, 0.5); + if (t.image != null) + bd.draw(t.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(0,0,tilehsize,tilehsize), false); + + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(0.5, 0.5); + scaleMatrix.translate(tilehsize,0); + var tt = tiles[t.rtidx]; + if ((tt.tx != this.lx) && (tt.image != null)) + bd.draw(tt.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(tilehsize,0,tilehsize,tilehsize), false); + + + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(0.5, 0.5); + scaleMatrix.translate(0,tilehsize); + var tt = tiles[t.btidx]; + if ((tt.ty != this.ty) && (tt.image != null)) + bd.draw(tt.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(0,tilehsize,tilehsize,tilehsize), false); + + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(0.5, 0.5); + scaleMatrix.translate(tilehsize,tilehsize); + var tt = tiles[tiles[t.btidx].rtidx]; + if ((tt.tx != this.lx) && (tt.ty != this.ty) && (tt.image != null)) + bd.draw(tt.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(tilehsize,tilehsize,tilehsize,tilehsize), false); + + loader.addTile((((mapservice.invert_x) ? -t.tx : t.tx) + basetid.x) >> 1, + (((mapservice.invert_y) ? -t.ty : t.ty) + basetid.y) >> 1, + newZoom + basetid.z, + bd, false + ); + + } + } + + //zoom out + if (basetid.x & 1 == 1) x -= tilesize/2; + if (basetid.y & 1 == 1) y -= tilesize/2; + basetid.x = basetid.x >> 1; + basetid.y = basetid.y >> 1; + + ofsx = ofsx / 2.0; + ofsy = ofsy / 2.0; + + //coeficients for the /2 transformation + // x' = x/2 == x - x/2 + // y' = y/2 == y - y/2 + lp = - Std.int(this.lx/2); + tp = - Std.int(this.ty/2); + + } + else + { + + if (smooth) + { + //smooth zoom - each tile is splited into the four tiles + var mintx:Int = Std.int((3*this.lx + this.rx + 1) / 4); + var maxtx:Int = Std.int((3*this.rx + this.lx + 3) / 4); + var minty:Int = Std.int((3*this.ty + this.by + 1) / 4); + var maxty:Int = Std.int((3*this.by + this.ty + 3) / 4); + for (t in tiles) + if ((t.image != null) && (t.tx >= mintx) && (t.tx <= maxtx) && (t.ty >= minty) && (t.ty <= maxty)) + { + var bd = new flash.display.BitmapData(tilesize, tilesize, false, 0xFFFFFF); + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(2, 2); + bd.draw(t.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(0,0,tilesize,tilesize), false); + loader.addTile((((mapservice.invert_x) ? -t.tx : t.tx) + basetid.x)*2, + (((mapservice.invert_y) ? -t.ty : t.ty) + basetid.y)*2, + newZoom + basetid.z, bd, false + ); + + + var bd = new flash.display.BitmapData(tilesize, tilesize, false, 0xFFFFFF); + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(2, 2); + scaleMatrix.translate(-tilesize,0); + bd.draw(t.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(0,0,tilesize,tilesize), false); + loader.addTile((((mapservice.invert_x) ? -t.tx : t.tx) + basetid.x)*2 + 1, + (((mapservice.invert_y) ? -t.ty : t.ty) + basetid.y)*2, + newZoom + basetid.z, bd, false + ); + + + var bd = new flash.display.BitmapData(tilesize, tilesize, false, 0xFFFFFF); + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(2, 2); + scaleMatrix.translate(0,-tilesize); + bd.draw(t.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(0,0,tilesize,tilesize), false); + loader.addTile((((mapservice.invert_x) ? -t.tx : t.tx) + basetid.x)*2, + (((mapservice.invert_y) ? -t.ty : t.ty) + basetid.y)*2 + 1, + newZoom + basetid.z, bd, false + ); + + + var bd = new flash.display.BitmapData(tilesize, tilesize, false, 0x00FF00); + var scaleMatrix = new flash.geom.Matrix(); + scaleMatrix.scale(2, 2); + scaleMatrix.translate(-tilesize,-tilesize); + bd.draw(t.image.bitmapData, scaleMatrix, null, null, new flash.geom.Rectangle(0,0,tilesize,tilesize), false); + loader.addTile((((mapservice.invert_x) ? -t.tx : t.tx) + basetid.x)*2 + 1, + (((mapservice.invert_y) ? -t.ty : t.ty) + basetid.y)*2 + 1, + newZoom + basetid.z, bd, false + ); + + } + } + + //zoom in + basetid.x = basetid.x << 1; + basetid.y = basetid.y << 1; + + ofsx = ofsx * 2.0; + ofsy = ofsy * 2.0; + + //coeficients for the *2 transformation + // x' = x*2 == x + x + // y' = y*2 == y + y + lp = this.lx; + tp = this.ty; + + + } + + //transform tile id's + for (t in tiles) + { + t.tx += lp; + t.ty += tp; + } + + this.rx += lp; + this.by += tp; + this.lx += lp; + this.ty += tp; + + //update zoom, reset scale + this.zoom = newZoom; + + scaleX = 1; + scaleY = 1; + + clear(); + center = this.lastcenter; + centerUpdated(false); + + dispatchEvent(new Event(Layer.ZOOM_FINISHED)); + + if ((prevEnabled) && (!this.updateEnabled)) + { + this.updateEnabled = true; + updateChanged(); + } + + updateContent(true); + } + + function testAndShift() : Bool + { + var mv_left = ((this.lx+this.tofs)*tilesize*scaleX + this.x > bbox.x); + var mv_right = ((this.rx-this.tofs)*tilesize*scaleX + this.x < (bbox.x+bbox.width)); + var mv_up = ((this.ty+this.tofs)*tilesize*scaleY + this.y > bbox.y); + var mv_down = ((this.by-this.tofs)*tilesize*scaleY + this.y < (bbox.y+bbox.height)); + + if ((mv_left) && ((this.rx-1)*tilesize*scaleX + this.x < (bbox.x+bbox.width))) + mv_left = false; + if ((mv_up) && ((this.by-1)*tilesize*scaleY + this.y < (bbox.y+bbox.height))) + mv_up = false; + if ((mv_right) && ((this.lx+1)*tilesize*scaleX + this.x > bbox.x)) + mv_right = false; + if ((mv_down) && ((this.ty+1)*tilesize*scaleY + this.y > bbox.y)) + mv_down = false; + + if (mv_left && mv_right) mv_right = false; + if (mv_up && mv_down) mv_down = false; + + if (!(mv_left || mv_right || mv_up || mv_down)) return false; + + for (t in tiles) + { + if ((mv_left) && (t.tx == rx)) + t.tx = lx - 1; + if ((mv_right) && (t.tx == lx)) + t.tx = rx + 1; + if ((mv_up) && (t.ty == by)) + t.ty = ty - 1; + if ((mv_down) && (t.ty == ty)) + t.ty = by + 1; + } + var dx = (mv_left) ? -1 : ((mv_right) ? 1 : 0); + var dy = (mv_up) ? -1 : ((mv_down) ? 1 : 0); + + lx += dx; + rx += dx; + ty += dy; + by += dy; + + return true; + } + + function alignLayer() + { + + if (center == null) return; + + x = this.canvascenter.x; + y = this.canvascenter.y; + + basetid = mapservice.lonlat2tile(center.lng, center.lat, basetid.z+zoom); + var ptc = mapservice.lonlat2XY(center.lng, center.lat, basetid.z); + var ll = mapservice.tile2lonlat(basetid); + var ptt = mapservice.lonlat2XY(ll.x, ll.y, basetid.z); + basetid.z -= zoom; + ptt = ptt.subtract(ptc); + ofsx = ptt.x; + ofsy = ptt.y; + } + + + function emitRequests() + { + var prio:Int = 0; + var xx:Float; + var yy:Float; + + loader.disable(); + + try + { + loader.tidyQueue(((mapservice.invert_x) ? -lx : lx) + basetid.x, ((mapservice.invert_x) ? -rx : rx) + basetid.x, + ((mapservice.invert_y) ? -ty : ty) + basetid.y, ((mapservice.invert_y) ? -by : by) + basetid.y, + zoom + basetid.z + ); + + for (tile in tiles) + { + if (tile.needImage()) + { + + + xx = (tile.x + x - ofsx - this.canvascenter.x); + yy = (tile.y + y - ofsy - this.canvascenter.y); + prio = Std.int(Math.sqrt(xx*xx + yy*yy)); + + loader.addRequest( ((mapservice.invert_x) ? -tile.tx : tile.tx) + basetid.x, + ((mapservice.invert_y) ? -tile.ty : tile.ty) + basetid.y, + zoom + basetid.z, + tile.tidx, + prio + ); + + tile.waitForImage(); + } + } + + } catch (unknown : Dynamic) {}; + + loader.enable(); + } + + + function tileLoaded(e:TileLoadedEvent) + { + if ((e.tidx >= 0) && (e.tidx < tiles.length)) + { + + var t:Tile = tiles[e.tidx]; + if ((t != null) && + (((mapservice.invert_x) ? -t.tx : t.tx) == e.x - basetid.x) && //check x-id + (((mapservice.invert_y) ? -t.ty : t.ty) == e.y - basetid.y) && //check y-id + (e.z - basetid.z == zoom) //check z + ) + { + + #if TILE_EVT_DBG + try { + ExternalInterface.call("debugMessage", "tileLoaded "+e.data+" x:"+t.tx+" y:"+t.ty+" ("+e.x+","+e.y+","+e.z+") priority:"+e.p); + } catch (unknown : Dynamic) { }; + #end + + t.assignImage(e.data); + } + } + } + + + function saveImages() + { + for (t in tiles) + if (t.image != null) + loader.addTile(((mapservice.invert_x) ? -t.tx : t.tx) + basetid.x, + ((mapservice.invert_y) ? -t.ty : t.ty) + basetid.y, + zoom + basetid.z, + t.image.bitmapData + ); + + + } + +} diff --git a/src/map/TileLoader.hx b/src/map/TileLoader.hx new file mode 100644 index 0000000..fd960a9 --- /dev/null +++ b/src/map/TileLoader.hx @@ -0,0 +1,547 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +import map.Utils; + +import flash.events.Event; +import flash.events.EventDispatcher; +import flash.events.IOErrorEvent; +import flash.display.Loader; +import flash.display.Bitmap; +import flash.display.BitmapData; +import flash.net.URLRequest; +import flash.system.LoaderContext; + +import flash.utils.Timer; +import flash.events.TimerEvent; + +#if TILE_EVT_DBG +import flash.external.ExternalInterface; +#end + +typedef TileIDT = { + var x : Int; + var y : Int; + var z : Int; + var tidx : Int; + var ttl : Int; + var priority: Int; +}; + + +class TileLoadedEvent extends flash.events.Event +{ + public static var TILE_LOADED:String = "tileLoaded"; + + public var x:Int; + public var y:Int; + public var z:Int; + public var p:Int; + public var tidx:Int; + public var data:Bitmap; + + public function new(x:Int, y:Int, z:Int, tidx:Int, p:Int, data:Bitmap) { + super(TILE_LOADED); + this.x = x; + this.y = y; + this.z = z; + this.p = p; + this.tidx = tidx; + this.data = data; + } +} + +class ImageLoader extends Loader +{ + static var TIMEOUT:Int = 5; //10 sec + + public var used:Bool; + public var ignore:Bool; + public var id:Int; + public var ttl:Int; + public var tid:TileIDT; + + + public function new(id:Int) + { + super(); + this.used = false; + this.ignore = false; + this.id = id; + this.ttl = TIMEOUT; + } + + public function loadImage(tid:TileIDT, url:String) { + var urlRequest:URLRequest = new URLRequest(url); + this.tid = tid; + try { + + #if TILE_EVT_DBG + try { + ExternalInterface.call("debugMessage", "loadImage "+id+" ("+tid.x+","+tid.y+","+tid.z+") prio:"+tid.priority); + } catch (unknown : Dynamic) { }; + #end + + this.load(urlRequest, new LoaderContext(true)); + this.used = true; + this.ttl = TIMEOUT; + + } + catch (unknown : Dynamic) + { + this.used = false; + } + } + + override public function toString() + { + return "[ImageLoader id:" + id + "]"; + } + +} + +typedef TempTile = { + var x : Int; + var y : Int; + var z : Int; + var img : BitmapData; + var ttl : Int; + var original : Bool; +}; + +class TileLoader extends EventDispatcher +{ + public static var DEFAULT_TTL:Int = 3; + public var mapservice:MapService; + var loaders:Array; + var queue:Array; + var tempqueue:Array; + var enabled:Int; + var watchdog:Timer; + + public function new(threads:Int = 8) + { + super(); + + mapservice = null; + enabled = 0; + + watchdog = new Timer(1000, 0); + watchdog.addEventListener(TimerEvent.TIMER, checkLoaders); + watchdog.stop(); + + loaders = new Array(); + queue = new Array(); + tempqueue = new Array(); + + for (i in 0...threads) + { + var l = new ImageLoader(i); + l.contentLoaderInfo.addEventListener(flash.events.Event.COMPLETE, loaderComplete); + l.contentLoaderInfo.addEventListener(flash.events.IOErrorEvent.IO_ERROR, loaderError); + loaders.push(l); + + } + } + + /*============================================================================================== + PUBLIC methods + *==============================================================================================*/ + + public function clear() + { + clearQueue(); + + for (l in loaders) + if (l.used) + { + l.ignore = true; + try { + //l.close(); //BUGGY! + //l.unload(); + } + catch (unknown : Dynamic) + { }; + } + + } + + public function enable() + { + if (enabled > 0) + enabled--; + + if (enabled == 0) + { + sortQueue(); + processQueue(); + + if (!watchdog.running) + watchdog.start(); + } + } + + public function disable() + { + if (watchdog.running) + watchdog.stop(); + + enabled++; + } + + + public function tidyQueue(minx:Int, maxx:Int, miny:Int, maxy:Int, z:Int) + { + var i:Int = 0; + while (i < queue.length) + { + var tid:TileIDT = queue[i]; + if (tid.z == z) + { + if ((tid.x < minx) || (tid.x > maxx) || (tid.y < miny) || (tid.y > maxy)) + queue.remove(tid); + else + i += 1; + } + else + queue.remove(tid); + } + } + + public function addRequest(x:Int, y:Int, z:Int, tidx:Int, priority:Int = 0) + { + if ((x < 0) || (y < 0) || (z < 0)) return; + + var q:TempTile = getTile(x, y, z); + if (q != null) + { + tempqueue.remove(q); + dispatchEvent(new TileLoadedEvent(x,y,z,tidx,priority, new Bitmap(q.img))); + if (q.original) + return; + } + + for (l in loaders) + if ((l.used) && (!l.ignore) && (l.tid.x == x) && (l.tid.y == y) && (l.tid.z == z)) + return; //request already served, return + + var exists:Bool = false; + for (tid in queue) + if ((tid.x == x) && (tid.y == y) && (tid.z == z)) + { + //request already in queue, update priority + tid.priority = priority; + exists = true; + break; + } + + if (!exists) + queue.push({x:x,y:y,z:z,tidx:tidx,priority:priority,ttl:DEFAULT_TTL}); + + if (enabled == 0) + { + sortQueue(); + processQueue(); + } + + } + + public function addTile(x:Int, y:Int, z:Int, img:BitmapData, original:Bool = true) + { + //check if the tile image is not already in queue + var tmp:TempTile = getTile(x,y,z); + if (tmp != null) + { + if (((!tmp.original) && (original)) || ((!tmp.original) && (!original))) + { + tmp.img = img; + tmp.original = original; + tmp.ttl = DEFAULT_TTL; + } + return; + } + + insertTile({x: x, y: y, z: z, img: img, ttl:DEFAULT_TTL, original:original}); + } + + override public function toString() : String + { + var used = 0; + for (l in loaders) + if (l.used) + used++; + + return "[TileLoader] threads total:" + loaders.length + ", active threads:" + used + ", enabled threads:" + enabled; + } + + /*============================================================================================== + PRIVATE methods + *==============================================================================================*/ + function clearQueue() + { + while (queue.length > 0) + queue.pop(); + } + + function checkLoaders(e:TimerEvent) + { + //watchdog timer event + + //check for broken loaders + var used = 0; + for (l in loaders) + if (l.used) + { + if (l.ttl > 0) + l.ttl--; + else if (l.ttl == 0) + loaderFailed(l); + used++; + } + + var i=0; + var q:TempTile; + //remove unused tiles in tempqueue + while (i < tempqueue.length) + { + q = tempqueue[i]; + + if (q.ttl > 0) + q.ttl--; + else if (q.ttl == 0) + { + tempqueue.remove(q); + continue; + } + + i++; + used++; + } + + if ((used == 0) && (watchdog.running)) + watchdog.stop(); + + } + + + function sortQueue() + { + queue.sort(function(x:TileIDT,y:TileIDT):Int { return x.priority - y.priority;}); + } + + + function processQueue() + { + + if ((enabled != 0) || (queue.length == 0) || (mapservice == null)) + return; + + if (queue.length == 0) + return; + + var tid:TileIDT; + for (l in loaders) + { + if (l.used) + continue; + + #if TILE_EVT_DBG + try { + ExternalInterface.call("debugMessage", "processQueue qlen:"+queue.length); + } catch (unknown : Dynamic) { }; + #end + + if (queue.length == 0) return; + + tid = queue.shift(); + + var url:String = mapservice.tile2url(tid); + if (url != "") + l.loadImage(tid, url); + + if (!watchdog.running) + watchdog.start(); + + } + + } + + function loaderComplete(e:Event) + { + + if ((e.target == null) || (e.target.loader == null)) + return; + + var loader:ImageLoader = e.target.loader; + + if (!loader.ignore) + { + try { + var x:Int = loader.tid.x; + var y:Int = loader.tid.y; + var z:Int = loader.tid.z; + var t:Int = loader.tid.tidx; + var p:Int = loader.tid.priority; + + #if TILE_EVT_DBG + try { + ExternalInterface.call("debugMessage", "tileLoaded ("+x+","+y+","+z+") priority:"+p); + } catch (unknown : Dynamic) { }; + #end + + var bitmapc:Bitmap = new Bitmap(cast(loader.content, Bitmap).bitmapData.clone()); + dispatchEvent(new TileLoadedEvent(x,y,z,t,p, bitmapc)); + + } + catch (unknown : Dynamic) + { + + //chyba, znovu do fronty, pokud jiz neni vycerpan poc. pokusu + if (loader.tid.ttl > 0) + { + queue.push({x:loader.tid.x, y:loader.tid.y, z:loader.tid.z, + tidx:loader.tid.tidx, + ttl:loader.tid.ttl - 1, + priority:loader.tid.priority + }); + if (enabled == 0) + sortQueue(); + } + + }; + } + else + { + #if TILE_EVT_DBG + try { + ExternalInterface.call("debugMessage", "tileIgnored"); + } catch (unknown : Dynamic) { }; + #end + } + + try { + loader.unload(); + } catch (unknown : Dynamic) {}; + + loader.used = false; + loader.ignore = false; + + processQueue(); + } + + function loaderFailed(l:ImageLoader) + { + l.used = false; + l.ignore = false; + + #if TILE_EVT_DBG + try { + ExternalInterface.call("debugMessage", "tileError " + l.tid.x + ","+l.tid.y+","+l.tid.z); + } catch (unknown : Dynamic) { }; + #end + + if ((l.tid.ttl > 0) && (!l.ignore)) + { + //loading failed, return request back to the queue + queue.push({x:l.tid.x,y:l.tid.y,z:l.tid.z,tidx:l.tid.tidx,ttl:l.tid.ttl - 1,priority:l.tid.priority}); + + if (enabled == 0) + sortQueue(); + } + + processQueue(); + } + + + function loaderError(e:IOErrorEvent) + { + + for (l in loaders) + if (l.contentLoaderInfo == e.target) + loaderFailed(l); + } + + function getTile(x:Int, y:Int, z:Int) : TempTile + { + //looking for a tile in the sorted array + + var min:Int = 0; + var max:Int = tempqueue.length-1; + var mid:Int; + var val:Int; var cmp:Int; + while (min <= max) { + mid = Math.floor((min + max) / 2); + + cmp = (x - tempqueue[mid].x); + if (cmp == 0) cmp = (y - tempqueue[mid].y); + if (cmp == 0) cmp = (z - tempqueue[mid].z); + + if (cmp == 0) + return tempqueue[mid] + else if (cmp > 0) + min = mid + 1; + else + max = mid - 1; + + } + + return null; + } + + function insertTile(t:TempTile) + { + //insert TempTile into the sorted array + + var min:Int = 0; + var max:Int = tempqueue.length-1; + var mid:Int; + var val:Int; var cmp:Int; + + while (min <= max) { + mid = Math.floor((min + max) / 2); + + cmp = (t.x - tempqueue[mid].x); + if (cmp == 0) cmp = (t.y - tempqueue[mid].y); + if (cmp == 0) cmp = (t.z - tempqueue[mid].z); + + if (cmp > 0) + min = mid + 1; + else + max = mid - 1; + + } + + tempqueue.insert(min, t); + } + +} + diff --git a/src/map/Utils.hx b/src/map/Utils.hx new file mode 100644 index 0000000..5f9b407 --- /dev/null +++ b/src/map/Utils.hx @@ -0,0 +1,74 @@ +/******************************************************************************* +Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + Marek Vavrusa (marek AT vavrusa.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organization nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +package map; + +import flash.geom.Point; +import flash.filters.ColorMatrixFilter; + +class Utils +{ + public static function dec2hex(i:Int, digits:Int) + { + var c = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']; + var s:String = ''; + var val = i; + for (j in 0...digits) + { + s = c[val % 16] + s; + val = val >> 4; + } + return s; + } + + public static function desaturationFilter(sat:Float = 1.0) : ColorMatrixFilter + { + var r = 0.212671; + var g = 0.715160; + var b = 0.072169; + return new ColorMatrixFilter( + [/* R */ sat*r+1-sat, sat*g, sat*b, 0, 0, + /* G */ sat*r, sat*g+1-sat, sat*b, 0, 0, + /* B */ sat*r, sat*g, sat*b+1-sat, 0, 0, + /* A */ 0, 0, 0, 1, 0 + ] + ); + } + +} + +typedef LonLat = Point; /* for internal usage */ + +typedef TileID = { + var x : Int; + var y : Int; + var z : Int; +}; +