HaxeMaps / Manipulace s mnoha objekty (využití QuadTree)

Cílem této ukázky je nastínit způsob práce s velkým počtem objektů. Pro jednoduchost budeme pracovat se 100 000 prostých obdélníkových objektů různé velikosti. Jednotlivé objekty budeme vykreslovat pouze pokud jsou vidět (nachází se uvnitř aktuálního výřezu) a to pouze tehdy, není-li jejich výsledná velikost menší než jeden bod. Výstupem tedy bude vrstva s kontextově sensitivním obsahem.

K efektivnímu vyhledávání objektů, které se nachází uvnitř určitého boxu, budeme využívat strukturu map.QuadTree. Během inicializace vrstvy vytvoříme 100 000 náhodně rozmístěných bodů, do struktury uložíme kromě souřadnic bodu také jeho barvu a velikost. Pro zefektivnění renderování využijeme stejného přístupu (odložené vykreslování pomocí časovače), který byl využit v ukázce Propojení s WMS službami. Pro filtraci objektů využijeme metodu getFilteredData, která vrací positivní hodnotu pro objekty, které splňují danou podmínku.

1. Zdrojový kód

Struktura kódu je obdobou předchozích ukázek.

example08.hx

  1. import flash.display.Sprite;
  2. import flash.events.Event;
  3. import map.Canvas;
  4. import map.LngLat;
  5. import map.MapService;
  6. import com.Button;
  7. import com.ToolBar;
  8.  
  9. class Example08 extends Sprite {
  10.  
  11.     var canvas:Canvas;
  12.     var toolbar:ToolBar;
  13.     var layer_osm:map.TileLayer;
  14.  
  15.     static public function main()
  16.     {
  17.        flash.Lib.current.stage.scaleMode = flash.display.StageScaleMode.NO_SCALE;
  18.        var t:Example08 = new Example08();
  19.        flash.Lib.current.stage.addEventListener(Event.RESIZE, t.stageResized);
  20.        flash.Lib.current.stage.addChildAt(t,0);
  21.     }
  22.  
  23.  
  24.     function new()
  25.     {
  26.         super();
  27.    
  28.         toolbar = new ToolBar();
  29.         canvas = new Canvas();
  30.  
  31.         toolbar.move(0, 0);
  32.         canvas.move(0, 0);
  33.         canvas.setCenter(new LngLat(15.5,49.5));
  34.         layer_osm = new map.TileLayer(new OpenStreetMapService(12), 8);
  35.         canvas.addLayer(layer_osm);
  36.         canvas.addLayer(new VectorLayer(new OpenStreetMapService(12)));
  37.         canvas.setZoom(-5);
  38.         stageResized(null);
  39.  
  40.         initToolbar();
  41.  
  42.         addChild(canvas);
  43.         addChild(toolbar);
  44.  
  45.         canvas.initialize();
  46.     }
  47.  
  48.     public function stageResized(e:Event)
  49.     {
  50.         toolbar.setSize(flash.Lib.current.stage.stageWidth, 30);
  51.         canvas.setSize(flash.Lib.current.stage.stageWidth, flash.Lib.current.stage.stageHeight);
  52.     }
  53.  
  54.     function initToolbar()
  55.     {
  56.         var me = this;
  57.         toolbar.addButton(new ZoomOutButton(), "Zoom Out", function(b:CustomButton) { me.canvas.zoomOut(); });
  58.         toolbar.addButton(new ZoomInButton(), "Zoom In",  function(b:CustomButton) { me.canvas.zoomIn(); });
  59.         toolbar.addSeparator(30);
  60.  
  61.         //pan buttons
  62.         toolbar.addButton(new UpButton(), "Move up",  function(b:CustomButton) { me.pan(1); });
  63.         toolbar.addButton(new DownButton(), "Move down",  function(b:CustomButton) { me.pan(2); });
  64.         toolbar.addButton(new LeftButton(), "Move left",  function(b:CustomButton) { me.pan(4); });
  65.         toolbar.addButton(new RightButton(), "Move right",  function(b:CustomButton) { me.pan(8); });
  66.  
  67.         //layer buttons
  68.         toolbar.addSeparator(50);
  69.         var me = this;
  70.         var tbosm = new TextButton("OSM Layer");
  71.         tbosm.checked = true;
  72.         toolbar.addButton(tbosm, "Open Street Map Layer",  
  73.                           function(b:CustomButton)
  74.                           {
  75.                             tbosm.checked = !tbosm.checked;
  76.                             if (tbosm.checked)
  77.                                me.canvas.enableLayer(me.layer_osm);
  78.                             else
  79.                                me.canvas.disableLayer(me.layer_osm);
  80.                           });
  81.  
  82.     }
  83.  
  84.     function pan(direction:Int)
  85.     {
  86.        var lt:LngLat = canvas.getLeftTopCorner();
  87.        var br:LngLat = canvas.getRightBottomCorner();
  88.        var p:LngLat  = canvas.getCenter();
  89.  
  90.        if (direction & 0x3 == 1) p.lat = lt.lat; //up
  91.        if (direction & 0x3 == 2) p.lat = br.lat; //down
  92.        if (direction & 0xC == 4) p.lng = lt.lng; //left
  93.        if (direction & 0xC == 8) p.lng = br.lng; //right
  94.  
  95.        canvas.panTo(p);
  96.     }
  97.  
  98. }
  99.  
  100. import flash.net.URLLoader;
  101. import flash.net.URLRequest;
  102. import flash.utils.ByteArray;
  103. import flash.geom.Point;
  104. import map.Layer;
  105. import map.QuadTree;
  106.  
  107. import flash.utils.Timer;
  108. import flash.events.TimerEvent;
  109.  
  110. class VectorLayer extends Layer
  111. {
  112.     var data:QuadTree;
  113.     var ftimer:Timer;
  114.  
  115.     public static var COLORS = [0xB2182B, 0xD6604D, 0xF4A582, 0xFDDBC7,
  116.                                 0xE0E0E0, 0xBABABA, 0x878787, 0x4D4D4D];
  117.  
  118.     public function new(map_service:MapService = null)
  119.     {
  120.         super(map_service, false);
  121.  
  122.  
  123.         ftimer = new Timer(100, 1);
  124.         ftimer.addEventListener(TimerEvent.TIMER_COMPLETE, redraw);
  125.  
  126.         data = new QuadTree();
  127.         for (i in 0...100000)
  128.         {
  129.             var lng:Float = -30 + Math.random()*100;
  130.             var lat:Float = Math.random()*80;
  131.             var clr:Int = Math.floor(Math.random()*8);
  132.             var r:Int = 5 + (1 << Math.floor(i / 10000));
  133.             data.push(lng,lat, {color: COLORS[clr], radius: r});
  134.         }
  135.     }
  136.  
  137.     override function updateContent(forceUpdate:Bool=false)
  138.     {
  139.         if (ftimer.running)
  140.            ftimer.stop();
  141.  
  142.         if (forceUpdate)
  143.            redraw(null);
  144.         else
  145.            ftimer.start();
  146.     }
  147.  
  148.     function redraw(e:TimerEvent)
  149.     {
  150.  
  151.         var zz:Int = this.mapservice.zoom_def + this.zoom;
  152.         var scale:Float = Math.pow(2.0, this.zoom);
  153.         var l2pt = this.mapservice.lonlat2XY;
  154.         var cpt:Point = l2pt(center.lng, center.lat, zz);
  155.         var pt:Point;
  156.  
  157.         graphics.clear();
  158.         var lt:LngLat = getLeftTopCorner();
  159.         var rb:LngLat = getRightBottomCorner();
  160.  
  161.         var minsz:Float = 1.0/scale;
  162.         var data:Array<QuadData> =
  163.             data.getFilteredData(lt.lng, rb.lat, rb.lng, lt.lat,
  164.                                   function(q:QuadData):Bool {return q.data.radius > minsz;}
  165.                                  ); // test: scale*q.data.radius > 1.0
  166.           //data.getData(lt.lng, rb.lat, rb.lng, lt.lat);
  167.  
  168.         var r:Float;
  169.         for (d in data)
  170.         {
  171.             r = scale*d.data.radius;
  172.             pt = l2pt(d.x, d.y, zz);
  173.             graphics.lineStyle(r/2.0, d.data.color);
  174.             graphics.drawRect((pt.x - cpt.x), (pt.y - cpt.y), r, r);
  175.         }
  176.     }
  177. }
  178.  

2. Výsledek

Při změně výřezu dojde k a) zjištění seznamu viditelných bodů a b) jejich vykreslení.

Pro správnou funkci je vyžadován Flash player
   


Deprecated: Function ereg() is deprecated in /home2/web/homes/vasicek/private/notes/web/data/map/examples.php on line 12

Zobrazeno: 774x Naposledy: 1.4.2024 16:01:09