PageRenderTime 78ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/haxemaps/map/Layer.hx

http://haxemaps.googlecode.com/
Haxe | 522 lines | 364 code | 114 blank | 44 comment | 90 complexity | e4fedb9fb050d1c22c4b3723404e1a12 MD5 | raw file
  1. /*******************************************************************************
  2. Copyright (c) 2010, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
  3. Marek Vavrusa (marek AT vavrusa.com)
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions are met:
  7. * Redistributions of source code must retain the above copyright notice,
  8. this list of conditions and the following disclaimer.
  9. * Redistributions in binary form must reproduce the above copyright
  10. notice, this list of conditions and the following disclaimer in the
  11. documentation and/or other materials provided with the distribution.
  12. * Neither the name of the organization nor the names of its
  13. contributors may be used to endorse or promote products derived from this
  14. software without specific prior written permission.
  15. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  19. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25. POSSIBILITY OF SUCH DAMAGE.
  26. *******************************************************************************/
  27. package map;
  28. import flash.display.Sprite;
  29. import flash.events.Event;
  30. import flash.geom.Point;
  31. import flash.geom.Rectangle;
  32. import flash.utils.Timer;
  33. import flash.events.TimerEvent;
  34. import map.Utils;
  35. import map.LngLat;
  36. class Layer extends Sprite
  37. {
  38. public static var ZOOM_FINISHED:String = "zoomfinished";
  39. public var bbox(default, null):Rectangle;
  40. var zoom:Int;
  41. var animTimer:Timer;
  42. var animState:Int;
  43. var animTmp:Float;
  44. var initialized:Bool;
  45. var updateEnabled:Bool;
  46. var center:LngLat;
  47. var lastcenter:LngLat;
  48. var canvascenter:Point;
  49. var lastxy:Point;
  50. var lastcxy:Point;
  51. var scalable:Bool;
  52. public var mapservice:MapService;
  53. public function new(map_service:MapService = null, scalable:Bool = false)
  54. {
  55. super();
  56. this.scalable = scalable;
  57. this.mapservice = map_service;
  58. this.initialized = false;
  59. this.updateEnabled = false;
  60. this.bbox = new Rectangle(0,0,flash.Lib.current.stage.width, flash.Lib.current.stage.height);
  61. this.canvascenter = new Point(this.bbox.width/2.0,this.bbox.height/2.0);
  62. this.center = null;
  63. this.zoom = 0;
  64. this.lastxy = null;
  65. this.lastcxy = null;
  66. animTimer = new Timer(15, 0);
  67. animTimer.addEventListener(TimerEvent.TIMER, animStep);
  68. mouseEnabled = false;
  69. }
  70. /*==============================================================================================
  71. INITIALIZATION / FINALIZATION / MISC
  72. *==============================================================================================*/
  73. public function initialize(update:Bool=true) : Int
  74. {
  75. if (mapservice == null)
  76. return 1;
  77. if (this.initialized)
  78. finalize();
  79. this.x = this.canvascenter.x;
  80. this.y = this.canvascenter.y;
  81. synchronizeScale(true);
  82. if (Std.is(this, Layer))
  83. {
  84. this.initialized = true;
  85. if (!this.updateEnabled)
  86. {
  87. this.updateEnabled = true;
  88. updateChanged();
  89. }
  90. if (update)
  91. updateContent(true);
  92. }
  93. return 0;
  94. }
  95. public function finalize()
  96. {
  97. if (this.initialized)
  98. clear();
  99. this.initialized = false;
  100. }
  101. public function setBBox(bbox:Rectangle)
  102. {
  103. if (bbox == null)
  104. return;
  105. var actcenter:LngLat = null;
  106. if ((this.bbox != null) && (this.initialized))
  107. actcenter = this.getCenter();
  108. this.bbox = bbox;
  109. this.canvascenter = new Point(this.bbox.x + this.bbox.width/2.0, this.bbox.y + this.bbox.height/2.0);
  110. if (actcenter != null)
  111. this.setCenter(actcenter);
  112. }
  113. public function clear()
  114. {
  115. }
  116. /*==============================================================================================
  117. POSITION
  118. *==============================================================================================*/
  119. public function getOriginXY() : Point
  120. {
  121. if (this.mapservice == null)
  122. return new Point(0,0);
  123. return mapservice.lonlat2XY(center.lng, center.lat, mapservice.zoom_def + zoom);
  124. }
  125. public function getCenterXY() : Point
  126. {
  127. var pta:Point = getOriginXY();
  128. pta.offset(-x + this.canvascenter.x, - y + this.canvascenter.y);
  129. return pta;
  130. }
  131. public function getPointXY(point:LngLat) : Point
  132. {
  133. if (this.mapservice == null)
  134. return new Point(0,0);
  135. return mapservice.lonlat2XY(point.lng, point.lat, mapservice.zoom_def + zoom);
  136. }
  137. public function getCenter() : LngLat
  138. {
  139. if (this.mapservice == null)
  140. return null;
  141. if ((x == this.canvascenter.x) && (y == this.canvascenter.y))
  142. return center.clone();
  143. var z:Int = mapservice.zoom_def + zoom;
  144. var pta:Point = getCenterXY();
  145. var ptb:LonLat = mapservice.XY2lonlat(pta.x, pta.y, z);
  146. return new LngLat(ptb.x, ptb.y);
  147. }
  148. public function getXY(local:Point) : Point
  149. {
  150. var z:Int = mapservice.zoom_def + zoom;
  151. var pta:Point = mapservice.lonlat2XY(center.lng, center.lat, z);
  152. pta.offset(scaleX*local.x, scaleY*local.y);
  153. return pta;
  154. }
  155. public function getLngLat(local:Point) : LngLat
  156. {
  157. var z:Int = mapservice.zoom_def + zoom;
  158. var pta:Point = mapservice.lonlat2XY(center.lng, center.lat, z);
  159. var ptb:Point = mapservice.XY2lonlat(pta.x + scaleX*local.x, pta.y + scaleY*local.y, z);
  160. return new LngLat(ptb.x, ptb.y);
  161. }
  162. public function setCenter(point:LngLat)
  163. {
  164. if ((this.scalable) && (initialized))
  165. synchronizeCenter(point);
  166. else
  167. this.center = point.clone();
  168. centerUpdated(true);
  169. }
  170. public function moveTo(x:Float, y:Float)
  171. {
  172. if ((this.animTimer.running) || ((this.x == x) && (this.y == y)))
  173. return;
  174. this.x = x;
  175. this.y = y;
  176. if (this.updateEnabled)
  177. updateContent();
  178. }
  179. public function moveRelative(dx:Float, dy:Float)
  180. {
  181. if ((this.animTimer.running) || ((dx == 0) && (dy == 0)))
  182. return;
  183. this.x += dx;
  184. this.y += dy;
  185. if (this.updateEnabled)
  186. updateContent();
  187. }
  188. public function getOffset() : Point
  189. {
  190. return new Point(this.x - this.canvascenter.x, this.y - this.canvascenter.y);
  191. }
  192. public function getLeftTopCorner(margin:Float = 0.0) : LngLat
  193. {
  194. if (!initialized) return null;
  195. var x:Float = this.canvascenter.x - this.x - this.bbox.width/2.0 + margin;
  196. var y:Float = this.canvascenter.y - this.y - this.bbox.height/2.0 + margin;
  197. var z:Int = mapservice.zoom_def + zoom;
  198. var pta:Point = mapservice.lonlat2XY(center.lng, center.lat, z);
  199. var ptb:Point = mapservice.XY2lonlat(pta.x + scaleX*x, pta.y + scaleY*y, z);
  200. return new LngLat(ptb.x, ptb.y);
  201. }
  202. public function getRightBottomCorner(margin:Float = 0.0) : LngLat
  203. {
  204. if (!initialized) return null;
  205. var x:Float = this.canvascenter.x - this.x + this.bbox.width/2.0 + margin;
  206. var y:Float = this.canvascenter.y - this.y + this.bbox.height/2.0 + margin;
  207. var z:Int = mapservice.zoom_def + zoom;
  208. var pta:Point = mapservice.lonlat2XY(center.lng, center.lat, z);
  209. var ptb:Point = mapservice.XY2lonlat(pta.x + scaleX*x, pta.y + scaleY*y, z);
  210. return new LngLat(ptb.x, ptb.y);
  211. }
  212. /*==============================================================================================
  213. ZOOM
  214. *==============================================================================================*/
  215. public function validZoom(zoom:Int) : Bool
  216. {
  217. return ((!this.animTimer.running) && (this.mapservice != null) && (this.mapservice.validZoom(zoom)));
  218. }
  219. public function setZoom(zoom:Int)
  220. {
  221. if (!validZoom(zoom)) return;
  222. this.zoom = zoom;
  223. if (this.scalable)
  224. synchronizeScale();
  225. if (!this.initialized)
  226. return;
  227. this.center = getCenter(); //get actual center & update layer content
  228. centerUpdated(true);
  229. }
  230. public function zoomIn(animate:Bool = true)
  231. {
  232. if ((this.animTimer.running) || (!this.initialized) || (this.mapservice == null) || (!this.mapservice.validZoom(zoom+1)))
  233. return;
  234. this.lastxy = new Point(x,y);
  235. this.lastcenter = getCenter();
  236. this.lastcxy = new Point(this.canvascenter.x, this.canvascenter.y);
  237. if (!animate)
  238. {
  239. scaleX = scaleX * 2.0;
  240. scaleY = scaleY * 2.0;
  241. x = lastcxy.x + (lastxy.x - lastcxy.x) * 2.0;
  242. y = lastcxy.y + (lastxy.y - lastcxy.y) * 2.0;
  243. zoomChanged(this.updateEnabled, zoom + 1);
  244. return;
  245. }
  246. this.animState = 0x0000;
  247. if (this.updateEnabled)
  248. {
  249. this.updateEnabled = false;
  250. updateChanged();
  251. this.animState += 0x0100;
  252. }
  253. this.animTmp = scaleX;
  254. this.animTimer.start();
  255. }
  256. public function zoomOut(animate:Bool = true)
  257. {
  258. if ((this.animTimer.running) || (!this.initialized) || (this.mapservice == null) || (!this.mapservice.validZoom(zoom-1)))
  259. return;
  260. this.lastxy = new Point(x,y);
  261. this.lastcenter = getCenter();
  262. this.lastcxy = new Point(this.canvascenter.x, this.canvascenter.y);
  263. if (!animate)
  264. {
  265. scaleX = scaleX / 2.0;
  266. scaleY = scaleY / 2.0;
  267. x = lastcxy.x + (lastxy.x - lastcxy.x) / 2.0;
  268. y = lastcxy.y + (lastxy.y - lastcxy.y) / 2.0;
  269. zoomChanged(this.updateEnabled, zoom - 1);
  270. return;
  271. }
  272. this.animState = 0x1000;
  273. if (this.updateEnabled)
  274. {
  275. this.updateEnabled = false;
  276. updateChanged();
  277. this.animState += 0x0100;
  278. }
  279. this.animTmp = scaleX;
  280. this.animTimer.start();
  281. }
  282. public function update()
  283. {
  284. updateContent(true);
  285. }
  286. /*==============================================================================================
  287. PRIVATE
  288. *==============================================================================================*/
  289. function updateContent(forceUpdate:Bool=false)
  290. {
  291. }
  292. function updateChanged()
  293. {
  294. }
  295. function zoomChanged(prevEnabled:Bool, newZoom:Int)
  296. {
  297. this.zoom = newZoom;
  298. if (!scalable)
  299. {
  300. scaleX = scaleY = 1.0;
  301. center = this.lastcenter;
  302. centerUpdated(false);
  303. }
  304. else
  305. synchronizeCenter(this.lastcenter);
  306. dispatchEvent(new Event(ZOOM_FINISHED));
  307. if ((prevEnabled) && (!this.updateEnabled))
  308. {
  309. this.updateEnabled = true;
  310. updateContent(!scalable);
  311. updateChanged();
  312. }
  313. }
  314. /*==============================================================================================
  315. PRIVATE
  316. *==============================================================================================*/
  317. function synchronizeCenter(point:LngLat)
  318. {
  319. if (!this.scalable)
  320. return;
  321. var pta:Point = getOriginXY();
  322. var ptb:Point = getPointXY(point);
  323. this.x = pta.x - ptb.x + canvascenter.x;
  324. this.y = pta.y - ptb.y + canvascenter.y;
  325. }
  326. function synchronizeScale(init:Bool=false)
  327. {
  328. if (this.scalable)
  329. {
  330. if (this.zoom < 0) {
  331. scaleX = 1.0 / (1 << (-this.zoom));
  332. scaleY = 1.0 / (1 << (-this.zoom));
  333. } else {
  334. scaleX = (1 << this.zoom);
  335. scaleY = (1 << this.zoom);
  336. }
  337. }
  338. else if ((!this.scalable) && (init))
  339. {
  340. this.scaleX = 1.0;
  341. this.scaleY = 1.0;
  342. }
  343. }
  344. function centerUpdated(clearQueue:Bool)
  345. {
  346. if (!this.initialized)
  347. return;
  348. if (!this.scalable)
  349. {
  350. this.x = this.canvascenter.x;
  351. this.y = this.canvascenter.y;
  352. }
  353. if (this.updateEnabled)
  354. updateContent((clearQueue) && (!scalable));
  355. }
  356. function animStep(e:flash.events.Event)
  357. {
  358. var steps:Float = 10.0;
  359. var act = (animState >> 12) & 0x0F;
  360. var en = (animState >> 8) & 0x0F;
  361. var st = (animState & 0xFF);
  362. if (act == 0)
  363. {
  364. if (st < steps)
  365. {
  366. var scale:Float = (1.0 + (st + 1)/steps);
  367. scaleX = animTmp * scale;
  368. scaleY = scaleX;
  369. x = lastcxy.x + (lastxy.x - lastcxy.x) * scale;
  370. y = lastcxy.y + (lastxy.y - lastcxy.y) * scale;
  371. animState += 1;
  372. }
  373. else if (st == steps)
  374. {
  375. animTimer.stop();
  376. scaleX = animTmp * 2.0;
  377. scaleY = animTmp * 2.0;
  378. x = lastcxy.x + (lastxy.x - lastcxy.x) * 2.0;
  379. y = lastcxy.y + (lastxy.y - lastcxy.y) * 2.0;
  380. zoomChanged(en == 1, zoom + 1);
  381. }
  382. }
  383. else if (act == 1)
  384. {
  385. if (st < steps)
  386. {
  387. var scale:Float = (1.0 + (st + 1)/steps);
  388. scaleX = animTmp / scale;
  389. scaleY = scaleX;
  390. x = lastcxy.x + (lastxy.x - lastcxy.x) / scale;
  391. y = lastcxy.y + (lastxy.y - lastcxy.y) / scale;
  392. animState += 1;
  393. }
  394. else if (st == steps)
  395. {
  396. animTimer.stop();
  397. scaleX = animTmp / 2.0;
  398. scaleY = animTmp / 2.0;
  399. x = lastcxy.x + (lastxy.x - lastcxy.x) / 2.0;
  400. y = lastcxy.y + (lastxy.y - lastcxy.y) / 2.0;
  401. zoomChanged(en == 1, zoom - 1);
  402. }
  403. }
  404. }
  405. }