Android Open Source - WATisRain Map View






From Project

Back to project page WATisRain.

License

The source code is released under:

MIT License

If you think the Android project WATisRain listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.lucky.watisrain.map;
//from ww w . j  a  v  a2 s.c o m
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MenuItem;

import com.lucky.watisrain.Global;
import com.lucky.watisrain.R;
import com.lucky.watisrain.backend.MapFactory;
import com.lucky.watisrain.backend.RouteFinder;
import com.lucky.watisrain.backend.Util;
import com.lucky.watisrain.backend.data.Building;
import com.lucky.watisrain.backend.data.Map;
import com.lucky.watisrain.backend.data.Path;
import com.lucky.watisrain.backend.data.Route;
import com.lucky.watisrain.backend.data.RouteStep;
import com.lucky.watisrain.backend.data.Waypoint;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;

import uk.co.senab.photoview.PhotoView;
import uk.co.senab.photoview.PhotoViewAttacher;

/**
 * Class that draws the map. It handles reading and storing the Map object.
 */
public class MapView extends PhotoView {
  
  // Needed because PhotoView.getDisplayRect doesn't actually work
  public PhotoViewAttacher attacher;
  
  public HashMap<String, Bitmap> imgs;
  
  // Contains a TextView that displays directions
  public DirectionsView directionsView;
  
  public MenuItem clearBtn;
  
  public Map map;
  public RouteFinder routefinder;
  
  // Current route state
  String selectedBuilding1 = null;
  String selectedBuilding2 = null;
  Route route = null;

  public MapView(Context context, AttributeSet attrs) {
    super(context, attrs);

    AssetManager assetManager = context.getAssets();

    if(assetManager != null) {
      // Handle reading map file
      try {
        InputStream in = assetManager.open("locations.txt");
        map = MapFactory.readMapFromStream(in);
      } catch (IOException e) {
        Global.println(e);
      }
    } else {
      map = new Map();
    }
    
    routefinder = new RouteFinder(map);
    
    // Read bitmaps
    imgs = new HashMap<String, Bitmap>();
    imgs.put("default_location.png", BitmapFactory.decodeResource(getResources(), R.drawable.default_location));
    imgs.put("active_location.png", BitmapFactory.decodeResource(getResources(), R.drawable.active_location));
    imgs.put("stairs_up.png", BitmapFactory.decodeResource(getResources(), R.drawable.stairs_up));
    imgs.put("stairs_down.png", BitmapFactory.decodeResource(getResources(), R.drawable.stairs_down));
  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    Paint paint = new Paint();

    RectF displayRect = new RectF();

    if(attacher != null) {
      displayRect = attacher.getDisplayRect();
    }

    MapDraw mapdraw = new MapDraw(canvas, displayRect);
    
    // Draw all locations
    for(Building building : map.getBuildings()){
      
      if(!building.isSelectable()) continue;
      
      Waypoint pos = building.getMainFloor().getPostion();
      mapdraw.drawImageOnMap(imgs.get("default_location.png"),pos.getX(),pos.getY(),120);
    }
    
    // draw route
    if(route != null){
      
      List<RouteStep> all_steps = route.getRouteSteps();
      for(RouteStep step : all_steps){
        paint.setColor(Color.parseColor("#0070cf"));
        paint.setStrokeCap(Paint.Cap.ROUND);
        mapdraw.drawPathOnMap(step.getPath(), 8.0f, paint);
      }
    }
    
    // Draw active locations
    for(Building building : map.getBuildings()){
      Waypoint pos = building.getMainFloor().getPostion();
      
      if(building.getName().equals(selectedBuilding1) ||
         building.getName().equals(selectedBuilding2)){
        
        mapdraw.drawImageOnMap(imgs.get("active_location.png"),pos.getX(),pos.getY(),120);
      }
    }
    
    
    
    // The following code handles drawing stairs icons.
    if(route != null){
      
      List<RouteStep> all_steps = route.getRouteSteps();
      
      // Get list of buildings we go through
      ArrayList<String> throughBuildings = new ArrayList<String>();
      throughBuildings.add(all_steps.get(0).getStart().getBuildingName());
      for(RouteStep step : all_steps) {
        String next_build = step.getEnd().getBuildingName();
        if(!throughBuildings.contains(next_build))
          throughBuildings.add(next_build);
      }
      
      // All waypoints that we go through
      ArrayList<Waypoint> throughWaypoints = new ArrayList<Waypoint>();
      for(RouteStep step : all_steps){
        throughWaypoints.addAll(step.getWaypoints());
      }
      // Filter duplicates
      throughWaypoints = new ArrayList<Waypoint>(new LinkedHashSet<Waypoint>(throughWaypoints));
      
      for(String buildingName : throughBuildings){
        int ix = throughWaypoints.indexOf(map.getBuildingByID(buildingName).getPosition());
        
        // Generate 3 waypoints to get our vectors from
        Waypoint wp_cur = throughWaypoints.get(ix);
        Waypoint wp_before;
        if(ix==0){
          wp_before = throughWaypoints.get(1);
        }else{
          wp_before = throughWaypoints.get(ix-1);
        }
        Waypoint wp_after;
        if(ix==throughWaypoints.size()-1){
          wp_after = throughWaypoints.get(throughWaypoints.size()-2);
        }else{
          wp_after = throughWaypoints.get(ix+1);
        }
        
        // Compute opposite vector
        double[] vec_c = Util.findOppositeVector(
            wp_before.getX()-wp_cur.getX(),
            wp_before.getY()-wp_cur.getY(),
            wp_after.getX()-wp_cur.getX(),
            wp_after.getY()-wp_cur.getY());
        
        
        // Determine whether we actually draw a stairs here
        boolean stairs_down = false;
        boolean stairs_up = false;
        for(RouteStep step : all_steps){
          if(step.getStart().getBuildingName().equals(buildingName)
              && step.getPathType() == Path.TYPE_STAIR){
            if(step.getStart().getFloorNumber() > step.getEnd().getFloorNumber()){
              stairs_down = true;
            }else{
              stairs_up = true;
            }
          }
        }
        
        // Draw stair icons if needed
        if(stairs_down){
          mapdraw.drawImageOnMap(imgs.get("stairs_down.png"), (float)vec_c[0]*25+wp_cur.getX(), (float)vec_c[1]*25+wp_cur.getY(), 35);
        }
        if(stairs_up){
          mapdraw.drawImageOnMap(imgs.get("stairs_up.png"), (float)vec_c[0]*25+wp_cur.getX(), (float)vec_c[1]*25+wp_cur.getY(), 35);
        }
        
      }
    }
    
  }
  
  
  /**
   * Called when user taps at location x,y on map
   * 
   * The units are relative to the image and between 0.0 and 1.0. That is, the center
   * of the map is (0.5, 0.5)
   */
  public void handleUserTap(float x, float y){
    
    if(clearBtn != null)
      clearBtn.setVisible(true);
    
    // Convert to map units
    // On map_full, it is (x * width, y * height). Then we perform scaling.
    float map_x = (x * Global.MAP_WIDTH / Global.MAP_ADJUST_SCALING) + Global.MAP_ADJUST_X;
    float map_y = (y * Global.MAP_HEIGHT / Global.MAP_ADJUST_SCALING) + Global.MAP_ADJUST_Y;
    
    Building closestBuilding = determineBuildingFromPosition(map_x, map_y, 70);
    
    // Reset route if user clicks one of existing endpoints, or something outside
    if(closestBuilding == null ||
        closestBuilding.getName().equals(selectedBuilding1) ||
        closestBuilding.getName().equals(selectedBuilding2)){
      clearRoute();
    }
    else if(selectedBuilding1 == null){
      selectedBuilding1 = closestBuilding.getName();
      directionsView.selectDestination(selectedBuilding1);
    }else{
      selectedBuilding2 = closestBuilding.getName();
      
      updateRoute();
    }
    
  }
  
  
  /**
   * Clear any route or selected buildings, as well as text view
   */
  public void clearRoute(){
    selectedBuilding1 = null;
    selectedBuilding2 = null;
    route = null;
    directionsView.unselectDestination();
    if(clearBtn != null)
      clearBtn.setVisible(false);
    invalidate();
  }
  
  
  // Assumes selectedBuilding[1,2] are the correct ones.
  private void updateRoute(){
    
    route = routefinder.findRoute(map.getBuildingByID(selectedBuilding1),
                    map.getBuildingByID(selectedBuilding2)).getContractedRoute();
    
    directionsView.generateDirectionsFromRoute(route);
  }
  
  
  /**
   * Recalculate the route if applicable, possibly with a different global pathing
   * value. If no route is selected, do nothing.
   */
  public void recalculateRoute(){
    if(selectedBuilding1 == null || selectedBuilding2 == null) return;
    
    updateRoute();
    invalidate();
  }
  
  
  /**
   * Given a set of map coordinates (x,y), return the building closest to
   * it, or null if there is no building close by.
   * 
   * @param threshold maximum allowed distance in map-pixels
   */
  private Building determineBuildingFromPosition(float x, float y, float threshold){
    
    List<Building> buildings = map.getBuildings();
    
    Building closest = null;
    float closest_dist = Float.MAX_VALUE;
    
    for(Building building : buildings){
      
      if(!building.isSelectable()) continue;
      
      float dist = (float)building.getMainFloor().getPostion().distanceTo(new Waypoint((int)x,(int)y));
      if(dist < closest_dist){
        closest = building;
        closest_dist = dist;
      }
    }
    
    if(closest_dist > threshold)
      closest = null;
    
    return closest;
  }

}




Java Source Code List

com.lucky.watisrain.Global.java
com.lucky.watisrain.MainActivity.java
com.lucky.watisrain.backend.Main.java
com.lucky.watisrain.backend.MapFactory.java
com.lucky.watisrain.backend.RouteFinder.java
com.lucky.watisrain.backend.Util.java
com.lucky.watisrain.backend.data.Building.java
com.lucky.watisrain.backend.data.Location.java
com.lucky.watisrain.backend.data.Map.java
com.lucky.watisrain.backend.data.Path.java
com.lucky.watisrain.backend.data.RouteStep.java
com.lucky.watisrain.backend.data.Route.java
com.lucky.watisrain.backend.data.Waypoint.java
com.lucky.watisrain.map.DirectionsView.java
com.lucky.watisrain.map.MapDraw.java
com.lucky.watisrain.map.MapView.java