Package de.fhpotsdam.unfolding.marker

Source Code of de.fhpotsdam.unfolding.marker.AbstractShapeMarker

package de.fhpotsdam.unfolding.marker;

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

import processing.core.PGraphics;
import processing.core.PVector;
import de.fhpotsdam.unfolding.UnfoldingMap;
import de.fhpotsdam.unfolding.geo.Location;
import de.fhpotsdam.unfolding.utils.GeoUtils;
import de.fhpotsdam.unfolding.utils.MapPosition;
import de.fhpotsdam.unfolding.utils.ScreenPosition;

/**
* Abstract marker representing multiple locations and can be implemented as lines, polygons, or other shapes.
*
* Handles multiple locations, and implements the main marker methods for handling those properly.
*/
public abstract class AbstractShapeMarker extends AbstractMarker {

  /** All locations defining this shape. */
  protected List<Location> locations;

  /**
   * Creates an empty shape marker with no locations. Locations can be added dynamically after creation.
   */
  public AbstractShapeMarker() {
    this(new ArrayList<Location>(), null);
  }

  /**
   * Creates a shape marker for the given locations.
   *
   * @param locations
   *            The list of locations.
   */
  public AbstractShapeMarker(List<Location> locations) {
    this(locations, null);
  }

  /**
   * Creates a shape marker for the given locations.
   *
   * @param locations
   *            The list of locations.
   * @param properties
   *            Some data properties for this marker.
   */
  public AbstractShapeMarker(List<Location> locations, HashMap<String, Object> properties) {
    this.locations = locations;
    setProperties(properties);
  }

  // Methods handling locations -------------------------

  /**
   * Sets the list of locations.
   *
   * @param locations
   *            A list of Locations.
   */
  public void setLocations(List<Location> locations) {
    this.locations = locations;
  }

  /**
   * Gets all locations.
   *
   * @return A list of Locations.
   */
  public List<Location> getLocations() {
    return locations;
  }

  /**
   * Adds all locations to the list of locations.
   *
   * @param locations
   *            One or multiple Location.
   */
  public void addLocations(Location... locations) {
    for (Location loc : locations) {
      this.locations.add(loc);
    }
  }

  /**
   * Adds all locations to the list of locations.
   *
   * @param locations
   *            A list of Locations.
   */
  public void addLocations(List<Location> locations) {
    this.locations.addAll(locations);
  }

  /**
   * Adds a Location to the list of locations.
   *
   * @param lat
   *            The latitude value.
   * @param lon
   *            The longitude value.
   */
  public void addLocation(float lat, float lon) {
    locations.add(new Location(lat, lon));
  }

  /**
   * Gets the location at the specified index.
   *
   * @param index
   *            The index of the location.
   * @return A Location.
   */
  public Location getLocation(int index) {
    return locations.get(index);
  }

  /**
   * Deletes a Location from the list of locations.
   *
   * @param location
   *            The Location to remove.
   */
  public void removeLocation(Location location) {
    locations.remove(location);
  }

  /**
   * Deletes a Location from the list of locations.
   *
   * @param index
   *            The index of the Location to remove.
   */
  public void removeLocation(int index) {
    locations.remove(index);
  }

  /**
   * Adds the given location to the list of locations.
   *
   * NB: Does not set this as the only location! This implementation is just prevent mistakes by using this method as
   * more general Marker method.
   *
   * @param location
   *            The location to add.
   */
  @Override
  public void setLocation(Location location) {
    addLocations(location);
  }

  /**
   * Gets the geometric center location of this marker.
   */
  @Override
  public Location getLocation() {
    return getCentroid();
  }
 
  /**
   * Returns the geometric center of this shape.
   *
   * @return The centroid location.
   */
  public Location getCentroid() {
    return GeoUtils.getCentroid(locations);
  }

  @Override
  public void draw(UnfoldingMap map) {
    PGraphics pg = map.mapDisplay.getOuterPG();

    List<MapPosition> mapPositions = new ArrayList<MapPosition>();

    for (Location loc : getLocations()) {
      float[] xy = map.mapDisplay.getObjectFromLocation(loc);
      mapPositions.add(new MapPosition(xy));
    }

    draw(pg, mapPositions, properties, map);
  }

  protected void draw(PGraphics pg, List<MapPosition> mapPositions, HashMap<String, Object> properties,
      UnfoldingMap map) {
    draw(pg, mapPositions);
  }

  /**
   * Draws these markers in outer object coordinate system.
   *
   * e.g. for labels oriented to the map
   *
   * @param pg
   *            The PGraphics to draw on
   * @param objectPositions
   *            The positions in outer object coordinates.
   */
  public abstract void draw(PGraphics pg, List<MapPosition> objectPositions);

  @Override
  public void draw(PGraphics pg, float x, float y) {

  }

  @Override
  public boolean isInside(UnfoldingMap map, float checkX, float checkY) {
    List<ScreenPosition> positions = new ArrayList<ScreenPosition>();
    for (Location location : locations) {
      ScreenPosition pos = map.getScreenPosition(location);
      positions.add(pos);
    }
    return isInside(checkX, checkY, positions);
  }

  /**
   * Checks whether the position is within the border of the vectors. Uses a polygon containment algorithm.
   *
   * This method is used for both ScreenPosition as well as Location checks.
   *
   * @param checkX
   *            The x position to check if inside.
   * @param checkY
   *            The y position to check if inside.
   * @param vectors
   *            The vectors of the polygon
   * @return True if inside, false otherwise.
   */
  protected boolean isInside(float checkX, float checkY,
      List<? extends PVector> vectors) {
    boolean inside = false;
    for (int i = 0, j = vectors.size() - 1; i < vectors.size(); j = i++) {
      PVector pi = vectors.get(i);
      PVector pj = vectors.get(j);
      if ((((pi.y <= checkY) && (checkY < pj.y)) || ((pj.y <= checkY) && (checkY < pi.y)))
          && (checkX < (pj.x - pi.x) * (checkY - pi.y) / (pj.y - pi.y) + pi.x)) {
        inside = !inside;
      }
    }
    return inside;
  }

  /**
   * Checks whether given position is inside this marker, according to the shape defined by the marker's locations.
   *
   * Note: This is only in AbstractShapeMarker and not in AbstractMarker (nor Marker) as only shape markers have an
   * area to test whether a point is inside. All others (Point and Lines) have no area, and thus an inside check
   * always have to return false. (The screen-pos inside tests check whether a point is inside the visual
   * representation, which has an area.)
   *
   * @param longitude
   *            The longitude.
   * @param latitude
   *            The latitude.
   * @return True if inside, false otherwise.
   */
  public boolean isInsideByLocation(float latitude, float longitude) {
    return isInside(latitude, longitude, locations);
  }

  public boolean isInsideByLocation(Location location) {
    return isInside(location.getLat(), location.getLon(), locations);
  }
 
  @Override
  protected boolean isInside(float checkX, float checkY, float x, float y) {
    // TODO Simply return false?
    throw new RuntimeException("Check for a single positon is not implemented for polygons.");
  }

}
TOP

Related Classes of de.fhpotsdam.unfolding.marker.AbstractShapeMarker

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.