Displaying Buildings
Our next step is to draw the outline of the building that we can see on the map. The Google Maps API provides a set of functions for drawing images and outlines on the map, but we need to keep track of the data we are drawing so we can remove it when it changes. Each building has a unique identifier (UUID) that we can use to check if we’ve previously drawn it. We need to keep track of the NeonBuilding object, the floor we have selected, and the current set of outlines we’ve drawn on the map, so we’ll make a class to store this data by building ID:
private ConcurrentHashMap<UUID, BuildingOverlays> buildingHashMap = new ConcurrentHashMap<>();
/**
* An object that keeps track of what is drawn to the map for each building
*/
private class BuildingOverlays {
public NeonBuilding building; //current building being displayed
public int floor; //current floor being displayed
ArrayList<Polygon> outlines; //outlines drawn to the map
public BuildingOverlays(NeonBuilding b, int floor, ArrayList<Polygon> outlines) {
this.building = b;
this.floor = floor;
this.outlines = new ArrayList<>(outlines);
}
}
On the successful download of buildings, we should iterate through them and check if our buildingHashMap contains the building ID. If it does, we can ignore it. If it doesn’t, then we should draw the building outline to the screen:
@Override
public void onComplete(List<NeonBuilding> list, DownloadResult downloadResult) {
if(downloadResult == DownloadResult.SUCCESS)
{
for (final NeonBuilding building : list) {
//check if the building has already been drawn to the screen
if (buildingHashMap.containsKey(building.getID()))
continue;
//since we are drawing for the first time, get the ground floor for display
final NeonBuildingFloor buildingFloor = building.getFloor(0);
//draw the outline of this floor to the screen
//since this is in a background thread, we draw on the UI thread
runOnUiThread(new Runnable() {
@Override
public void run() {
drawOutline(building, buildingFloor);
}
});
}
}
else
Log.i("NEONSampleApp","result failed with: "+list.toString());
}
/**
* Draws a NeonFloorOutline to the map. Converts to
* a set of Google Polygons
*/
private void drawOutline(NeonBuilding building, NeonBuildingFloor floor) {
Log.i("NEONSampleApp", "Drawing outline for building: " + building.getID() + ", floor: " + floor.getLabel());
ArrayList<Polygon> outlines = new ArrayList<>();
for (LatLongOutline outline : floor.getOutline().Outlines) {
//construct the outer hull
ArrayList<LatLng> ol = new ArrayList<>();
for (LatLong ll : outline.Hull)
ol.add(new LatLng(ll.Latitude, ll.Longitude));
//construct the inner holes
ArrayList<ArrayList<LatLng>> polygonHoles = new ArrayList<>();
for (ArrayList<LatLong> llo : outline.Holes) {
ArrayList<LatLng> hol = new ArrayList<>();
for (LatLong ll : llo)
hol.add(new LatLng(ll.Latitude, ll.Longitude));
polygonHoles.add(hol);
}
//add to map
Polygon p = mMap.addPolygon(new PolygonOptions().addAll(ol).clickable(true));
//set holes in the polygon
p.setHoles(polygonHoles);
//tag it with the building ID
p.setTag(building.getID());
//add to list
outlines.add(p);
}
//put the BuildingOverlay object in the hashmap
buildingHashMap.put(building.getID(), new BuildingOverlays(building, floor.getFloorNumber(), outlines));
}
On shutdown, the buildingHashMap should be cleared:
private void shutdown()
{
disconnectFromNeonAPI();
if (dataLooper != null) {
dataLooper.quit();
dataLooper = null;
}
mainHandler.removeCallbacks(loadBuildingsRunnable);
buildingHashMap.clear();
}