Package org.geomajas.puregwt.client.map.layer

Source Code of org.geomajas.puregwt.client.map.layer.VectorLayerRenderer

/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2011 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the GNU Affero
* General Public License. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/

package org.geomajas.puregwt.client.map.layer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.geomajas.layer.tile.TileCode;
import org.geomajas.puregwt.client.map.MapRenderer;
import org.geomajas.puregwt.client.map.ViewPort;
import org.geomajas.puregwt.client.map.event.EventBus;
import org.geomajas.puregwt.client.map.event.LayerAddedEvent;
import org.geomajas.puregwt.client.map.event.LayerHideEvent;
import org.geomajas.puregwt.client.map.event.LayerOrderChangedEvent;
import org.geomajas.puregwt.client.map.event.LayerRemovedEvent;
import org.geomajas.puregwt.client.map.event.LayerShowEvent;
import org.geomajas.puregwt.client.map.event.LayerStyleChangedEvent;
import org.geomajas.puregwt.client.map.event.LayerVisibilityMarkedEvent;
import org.geomajas.puregwt.client.map.event.MapResizedEvent;
import org.geomajas.puregwt.client.map.event.ViewPortChangedEvent;
import org.geomajas.puregwt.client.map.event.ViewPortScaledEvent;
import org.geomajas.puregwt.client.map.event.ViewPortTranslatedEvent;
import org.geomajas.puregwt.client.map.gfx.HtmlContainer;
import org.geomajas.puregwt.client.map.gfx.VectorContainer;
import org.geomajas.puregwt.client.map.layer.TilePresenter.STATUS;
import org.geomajas.puregwt.client.spatial.Bbox;
import org.geomajas.puregwt.client.spatial.GeometryFactory;
import org.geomajas.puregwt.client.spatial.GeometryFactoryImpl;

/**
* MapRenderer implementation that renders a single vector layer.
*
* @author Pieter De Graef
*/
public class VectorLayerRenderer implements MapRenderer {

  private VectorLayer layer;

  private ViewPort viewPort;

  private EventBus eventBus;

  private HtmlContainer htmlContainer;

  private VectorContainer vectorContainer;

  private GeometryFactory factory;

  private Map<String, TilePresenter> tiles;

  private Bbox layerBounds;

  // ------------------------------------------------------------------------
  // Constructor:
  // ------------------------------------------------------------------------

  public VectorLayerRenderer(VectorLayer layer, ViewPort viewPort) {
    this.layer = layer;
    this.viewPort = viewPort;

    factory = new GeometryFactoryImpl();
    layerBounds = factory.createBbox(layer.getLayerInfo().getMaxExtent());
    tiles = new HashMap<String, TilePresenter>();
  }

  // ------------------------------------------------------------------------
  // MapResizedHandler implementation:
  // ------------------------------------------------------------------------

  public void onMapResized(MapResizedEvent event) {
    // TODO implement me...
  }

  // ------------------------------------------------------------------------
  // MapCompositionHandler implementation:
  // ------------------------------------------------------------------------

  public void onLayerAdded(LayerAddedEvent event) {
    VectorLayer layer = (VectorLayer) event.getLayer();
    vectorContainer.setVisible(layer.getLayerInfo().isVisible());
  }

  public void onLayerRemoved(LayerRemovedEvent event) {
  }

  // ------------------------------------------------------------------------
  // Public methods:
  // ------------------------------------------------------------------------

  public void render(Bbox bbox) {
    // Only fetch when inside the layer bounds:
    if (bbox.intersects(layerBounds)) {

      // Find needed tile codes:
      List<TileCode> tempCodes = calcCodesForBounds(bbox);
      for (TileCode tileCode : tempCodes) {

        TilePresenter tilePresenter = tiles.get(tileCode.toString());
        if (tilePresenter == null) {
          // New tile
          tilePresenter = addTile(tileCode);
          tilePresenter.render();
        } else if (tilePresenter.getSiblingStatus() == STATUS.EMPTY) {
          // Tile already exists, but the siblings have not yet been loaded:
          tilePresenter.renderSiblings();
        }
      }
    }
  }

  public TilePresenter addTile(TileCode tileCode) {
    TilePresenter tilePresenter = tiles.get(tileCode.toString());
    if (tilePresenter == null) {
      tilePresenter = new TilePresenter(this, tileCode.clone());
      tiles.put(tileCode.toString(), tilePresenter);
    }
    return tilePresenter;
  }

  public TilePresenter getTile(TileCode tileCode) {
    return tiles.get(tileCode.toString());
  }

  // ------------------------------------------------------------------------
  // LayerStyleChangedHandler implementation:
  // ------------------------------------------------------------------------

  public void onLayerStyleChanged(LayerStyleChangedEvent event) {
    if (event.getLayer().getId().equals(layer.getId())) {
      // TODO implement me.
    }
  }

  // ------------------------------------------------------------------------
  // LayerVisibleHandler Implementation:
  // ------------------------------------------------------------------------

  public void onShow(LayerShowEvent event) {
    if (event.getLayer().getId().equals(layer.getId())) {
      if (htmlContainer != null) {
        htmlContainer.setVisible(true);
      }
      if (vectorContainer != null) {
        vectorContainer.setVisible(true);
      }
      render(viewPort.getBounds());
    }
  }

  public void onHide(LayerHideEvent event) {
    if (event.getLayer().getId().equals(layer.getId())) {
      if (htmlContainer != null) {
        htmlContainer.setVisible(false);
      }
      if (vectorContainer != null) {
        vectorContainer.setVisible(false);
      }
    }
  }

  public void onVisibilityMarked(LayerVisibilityMarkedEvent event) {
  }

  // ------------------------------------------------------------------------
  // MapRenderer Implementation:
  // ------------------------------------------------------------------------

  public void onViewPortChanged(ViewPortChangedEvent event) {
    clear();
    render(event.getViewPort().getBounds());
  }

  public void onViewPortScaled(ViewPortScaledEvent event) {
    clear();
    render(event.getViewPort().getBounds());
  }

  public void onViewPortTranslated(ViewPortTranslatedEvent event) {
    render(event.getViewPort().getBounds());
  }

  public void onLayerOrderChanged(LayerOrderChangedEvent event) {
    // Do nothing
  }

  public void setMapExentScaleAtFetch(double scale) {
    // TODO Not implemented...
  }

  public void clear() {
    for (TilePresenter tilePresenter : tiles.values()) {
      tilePresenter.cancel();
    }
    tiles.clear();
    if (htmlContainer != null) {
      htmlContainer.clear();
    }
    if (vectorContainer != null) {
      vectorContainer.clear();
    }
  }

  public void setHtmlContainer(HtmlContainer htmlContainer) {
    this.htmlContainer = htmlContainer;
  }

  public HtmlContainer getHtmlContainer() {
    return htmlContainer;
  }

  public void setVectorContainer(VectorContainer vectorContainer) {
    this.vectorContainer = vectorContainer;
  }

  public VectorContainer getVectorContainer() {
    return vectorContainer;
  }

  // ------------------------------------------------------------------------
  // Getters and setters:
  // ------------------------------------------------------------------------

  public ViewPort getViewPort() {
    return viewPort;
  }

  public VectorLayer getLayer() {
    return layer;
  }

  public EventBus getEventBus() {
    return eventBus;
  }

  // -------------------------------------------------------------------------
  // Private functions:
  // -------------------------------------------------------------------------

  /**
   * Saves the complete array of TileCode objects for the given bounds (and the current scale).
   *
   * @param bounds
   *            view bounds
   * @return list of tiles in these bounds
   */
  private List<TileCode> calcCodesForBounds(Bbox bounds) {
    int currentTileLevel = calculateTileLevel(bounds);

    // Calculate tile width and height for tileLevel=currentTileLevel
    double div = Math.pow(2, currentTileLevel); // tile level must be correct!
    double scale = viewPort.getScale();
    double tileWidth = Math.ceil((scale * layerBounds.getWidth()) / div) / scale;
    double tileHeight = Math.ceil((scale * layerBounds.getHeight()) / div) / scale;

    // For safety (to prevent division by 0):
    List<TileCode> codes = new ArrayList<TileCode>();
    if (tileWidth == 0 || tileHeight == 0) {
      return codes;
    }

    // Calculate bounds relative to extents:
    Bbox clippedBounds = bounds.intersection(layerBounds);
    if (clippedBounds == null) {
      // TODO throw error? If this is null, then the server configuration is incorrect.
      return codes;
    }
    double relativeBoundX = Math.abs(clippedBounds.getX() - layerBounds.getX());
    double relativeBoundY = Math.abs(clippedBounds.getY() - layerBounds.getY());
    int currentMinX = (int) Math.floor(relativeBoundX / tileWidth);
    int currentMinY = (int) Math.floor(relativeBoundY / tileHeight);
    int currentMaxX = (int) Math.ceil((relativeBoundX + clippedBounds.getWidth()) / tileWidth) - 1;
    int currentMaxY = (int) Math.ceil((relativeBoundY + clippedBounds.getHeight()) / tileHeight) - 1;

    // Now fill the list with the correct codes:
    for (int x = currentMinX; x <= currentMaxX; x++) {
      for (int y = currentMinY; y <= currentMaxY; y++) {
        codes.add(new TileCode(currentTileLevel, x, y));
      }
    }
    return codes;
  }

  /**
   * Calculate the best tile level to use for a certain view-bounds.
   *
   * @param bounds
   *            view bounds
   * @return best tile level for view bounds
   */
  private int calculateTileLevel(Bbox bounds) {
    double baseX = layerBounds.getWidth();
    double baseY = layerBounds.getHeight();
    // choose the tile level so the area is between 256*256 and 512*512 pixels
    double baseArea = baseX * baseY;
    double scale = viewPort.getScale();
    double osmArea = 256 * 256 / (scale * scale);
    int tileLevel = (int) Math.floor(Math.log(baseArea / osmArea) / Math.log(4.0));
    if (tileLevel < 0) {
      tileLevel = 0;
    }
    return tileLevel;
  }
}
TOP

Related Classes of org.geomajas.puregwt.client.map.layer.VectorLayerRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.