package dk.network42.osmfocus; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import android.graphics.Canvas; import android.graphics.RectF; import android.util.Log; public class OsmDB extends MapLayer { private static final String TAG = "OsmDB"; private long mWayId = 0; private long mNodeId = 0; private Map mNodes; private Map mWays; private Map mRels; private ArrayList mBounds; private Filter mFilter = new Filter(); float mX, mY, mYmerc; // Current view position, latitude is Mercator corrected OsmDB() { mNodes = new HashMap(); mWays = new HashMap(); mRels = new HashMap(); mBounds = new ArrayList(); } public OsmBounds getBounds() { // FIXME: Not really correct with multiple bounds return mBounds.get(0); } //void setBBox(final GeoBBox bbox) { // this.box = bbox; //} // True if we have any bounds defined. May contain zero nodes/ways public boolean isEmpty() { return (mBounds.isEmpty() || mBounds.get(0).isEmpty()); } public OsmNode getNode(final long osmId) { return mNodes.get(osmId); } public OsmWay getWay(final long osmId) { return mWays.get(osmId); } public OsmWay getRelation(final long osmId) { return mWays.get(osmId); } public OsmElement getElement(final long osmId) { OsmElement elem = mWays.get(osmId); if (elem != null) return elem; elem = mNodes.get(osmId); if (elem != null) return elem; elem = mRels.get(osmId); if (elem != null) return elem; return null; } public Map getNodes() { return mNodes; } public Map getWays() { return mWays; } public Map getRelations() { return mRels; } void insertNode(final OsmNode node) { mNodes.put(node.mOsmId, node); node.mDb = this; } void insertWay(final OsmWay way) { mWays.put(way.mOsmId, way); way.mDb = this; } void insertRelation(final OsmRelation rel) { mRels.put(rel.mOsmId, rel); rel.mDb = this; } void insertBounds(final OsmBounds box) { mBounds.add(box); if (mBounds.size()==1) { mX = (float) (getBounds().getLeft()/1e7f); mY = (float) (getBounds().getTop()/1e7f); mYmerc = (float) GeoMath.latToMercator(mY); //Log.d(TAG, "DB ref frozen to "+mX+", "+mY+"("+mYmerc+")"); } } public static OsmNode createNode(long osmId, long osmVersion, int lat, int lon) { return new OsmNode(osmId, osmVersion, lat, lon); } public OsmNode createNodeWithNewId(int lat, int lon) { return createNode(--mNodeId, 1, lat, lon); } public static OsmWay createWay(long osmId, long osmVersion) { return new OsmWay(osmId, osmVersion); } public OsmWay createWayWithNewId() { return createWay(--mWayId, 1); } public static OsmRelation createRelation(long osmId, long osmVersion) { return new OsmRelation(osmId, osmVersion); } public OsmRelation createRelationWithNewId() { return createRelation(--mWayId, 1); } public static OsmBounds createBounds(int minlon, int minlat, int maxlon, int maxlat) throws OsmException { return new OsmBounds(minlon, minlat, maxlon, maxlat); } // FIXME handle overlaps, merge newest void merge(OsmDB with) { if (with==null) return; if (mNodes.size()==0) mNodes = with.mNodes; if (mWays.size()==0) mWays = with.mWays; with.mX = mX; // Update with relative origin of dest db with.mY = mY; with.mYmerc = mYmerc; with.updateVisuals(); Iterator it; it = with.mNodes.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry) it.next(); if (!mNodes.containsKey(pair.getKey())) { insertNode((OsmNode)pair.getValue()); } } it = with.mWays.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry) it.next(); if (!mWays.containsKey(pair.getKey())) { insertWay((OsmWay)pair.getValue()); } } } void updateAndVacuum() { Iterator it = mWays.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry) it.next(); OsmWay ee = (OsmWay)pair.getValue(); mFilter.filter(ee); Iterator nit = ee.getNodes().iterator(); while (nit.hasNext()) { OsmNode nn = (OsmNode) nit.next(); nn.mIsWayNode = true; } } it = mNodes.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry) it.next(); mFilter.filter((OsmElement)pair.getValue()); } updateAndVacuumRelations(); vacuumWays(); updateVisuals(); } // Remove relation that we do not use void updateAndVacuumRelations() { Iterator it = mRels.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry) it.next(); OsmRelation rel = (OsmRelation) pair.getValue(); if (rel.hasTag("type", "multipolygon")) { rel.updateVisualDefiningElem(); } else { //Log.d(TAG, "Vacuum Rel, id="+rel.mOsmId); it.remove(); } } } // Remove e.g. ways tagged with building=yes and which are part of a multipolygon with role=outer void vacuumWays() { Iterator it = mRels.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry) it.next(); OsmRelation rel = (OsmRelation) pair.getValue(); if (rel.hasTag("type", "multipolygon") && rel.hasRole("outer")) { long ref = rel.getRoleRef("outer"); //Log.d(TAG, "Rel id="+rel.mOsmId+", outer id="+ref); OsmWay way = mWays.get(ref); if (way != null) { way.mIsMultipolyOuter = true; } } } } void updateVisuals() { Iterator it = mWays.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry) it.next(); OsmWay way = (OsmWay) pair.getValue(); way.updateVisuals(this); } it = mRels.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry) it.next(); OsmRelation rel = (OsmRelation) pair.getValue(); rel.updateVisuals(this); } } public static boolean idIsInList(long id, ArrayList list) { for (int ii = 0; ii near) { double lat_merc = GeoMath.latToMercator(lat); //Log.d(TAG, "Find elements close to ("+lon+","+lat+"(merc="+lat_merc+"))"); OsmElement e; Map.Entry pair; Iterator it = mNodes.entrySet().iterator(); while (it.hasNext()) { pair = (Map.Entry) it.next(); e = (OsmNode) pair.getValue(); if (e.getTagCnt() > 0 && !e.mFiltered && !idIsInList(e.getOsmId(), near)) { e.compareSetDistTo(lon, lat_merc); if (near.size() < max) { near.add(e); //Log.d(TAG, "Node(Id="+e.mOsmId+"): Add, near size="+near.size()+" near=["+dumpNearArray(near)+"]"); Collections.sort(near); } else if (near.get(near.size()-1).compareGet() > e.compareGet()) { near.set(near.size()-1, e); Collections.sort(near); } //Log.d(TAG, "Node(Id="+e.mOsmId+"): near size="+near.size()+" near=["+dumpNearArray(near)+"]"); } } it = mWays.entrySet().iterator(); while (it.hasNext()) { pair = (Map.Entry) it.next(); e = (OsmWay) pair.getValue(); if (e.getTagCnt() > 0 && !e.mFiltered && !idIsInList(e.getOsmId(), near)) { e.compareSetDistTo(lon, lat_merc); if (near.size() < max) { near.add(e); //Log.d(TAG, "Way(Id="+e.mOsmId+"): Add, near size="+near.size()+" near=["+dumpNearArray(near)+"]"); Collections.sort(near); } else if (near.get(near.size()-1).compareGet() > e.compareGet()) { near.set(near.size()-1, e); //Log.d(TAG, "Way(Id="+e.mOsmId+"): insert at "+(near.size()-1)+" near=["+dumpNearArray(near)+"]"); Collections.sort(near); } } } //Log.d(TAG, "Final near=["+dumpNearArray(near)+"]"); return 1; } // private static String dumpNearArray(ArrayList near) { // String st = ""; // for (int ii=0; ii near) { // String st = ""; // for (int ii=0; ii near, double lon, double latMerc, double angleOffset) { for (int ii = 0; ii(){ @Override public int compare(OsmElement e1, OsmElement e2) { return (int) e2.compareTo(e1); } }); //Log.d(TAG, "After sort:"+dumpNearArray(near)); } // Counter clock-wise public static void radianSortCCW(ArrayList near, double lon, double latMerc, double angleOffset) { for (int ii = 0; ii