Implement base map layer. Fix some bugs

This commit is contained in:
Victor Shcherb 2011-06-19 19:06:35 +02:00
parent 3ee0d8dcd7
commit 802c52c860
61 changed files with 712 additions and 263 deletions

View file

@ -13,6 +13,9 @@ public class ToDoConstants {
// Map Refactoring // Map Refactoring
// Remove notification from OsmAndMapTileView (?) // Remove notification from OsmAndMapTileView (?)
// Yandex Traffic make downloadable // Yandex Traffic make downloadable
// Index version
// 1. POI inside obf
// 2. Multiple attributes for one point (amenity=circle, type=...)
// === Refactoring issues === // === Refactoring issues ===

View file

@ -28,14 +28,14 @@ public class Boundary {
int intersections = 0; int intersections = 0;
for(Way w : outerWays){ for(Way w : outerWays){
for(int i=0; i<w.getNodes().size() - 1; i++){ for(int i=0; i<w.getNodes().size() - 1; i++){
if(ray_intersect(w.getNodes().get(i), w.getNodes().get(i+1), latitude, longitude)){ if(MapAlgorithms.ray_intersect(w.getNodes().get(i), w.getNodes().get(i+1), latitude, longitude)){
intersections ++; intersections ++;
} }
} }
} }
for(Way w : innerWays){ for(Way w : innerWays){
for(int i=0; i<w.getNodes().size() - 1; i++){ for(int i=0; i<w.getNodes().size() - 1; i++){
if(ray_intersect(w.getNodes().get(i), w.getNodes().get(i+1), latitude, longitude)){ if(MapAlgorithms.ray_intersect(w.getNodes().get(i), w.getNodes().get(i+1), latitude, longitude)){
intersections ++; intersections ++;
} }
} }
@ -44,39 +44,6 @@ public class Boundary {
return intersections % 2 == 1; return intersections % 2 == 1;
} }
// Try to intersect with ray from left to right
private boolean ray_intersect(Node node, Node node2, double latitude, double longitude) {
// a node below
Node a = node.getLatitude() < node2.getLatitude() ? node : node2;
// b node above
Node b = a == node2 ? node : node2;
if(latitude == a.getLatitude() || latitude == b.getLatitude()){
latitude += 0.00000001d;
}
if(latitude < a.getLatitude() || latitude > b.getLatitude()){
return false;
} else {
if(longitude > Math.max(a.getLongitude(), b.getLongitude())) {
return true;
} else if(longitude < Math.min(a.getLongitude(), b.getLongitude())){
return false;
} else {
if(a.getLongitude() == b.getLongitude()) {
// the node on the boundary !!!
return true;
}
// that tested on all cases (left/right)
double mR = (b.getLatitude() - a.getLatitude()) / (b.getLongitude() - a.getLongitude());
double mB = (latitude - a.getLatitude()) / (longitude - a.getLongitude());
if(mB <= mR){
return true;
} else {
return false;
}
}
}
}
public LatLon getCenterPoint(){ public LatLon getCenterPoint(){
List<Node> points = new ArrayList<Node>(); List<Node> points = new ArrayList<Node>();
for(Way w : outerWays){ for(Way w : outerWays){

View file

@ -1,8 +1,10 @@
package net.osmand.data; package net.osmand.data;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import net.osmand.osm.LatLon;
import net.osmand.osm.MapUtils; import net.osmand.osm.MapUtils;
import net.osmand.osm.Node; import net.osmand.osm.Node;
import net.osmand.osm.Way; import net.osmand.osm.Way;
@ -61,6 +63,9 @@ public class MapAlgorithms {
} }
private static double orthogonalDistance(int zoom, Node nodeLineStart, Node nodeLineEnd, Node node) { private static double orthogonalDistance(int zoom, Node nodeLineStart, Node nodeLineEnd, Node node) {
if(zoom > 31){
zoom = 31;
}
double x1 = MapUtils.getTileNumberX(zoom, nodeLineStart.getLongitude()); double x1 = MapUtils.getTileNumberX(zoom, nodeLineStart.getLongitude());
double y1 = MapUtils.getTileNumberY(zoom, nodeLineStart.getLatitude()); double y1 = MapUtils.getTileNumberY(zoom, nodeLineStart.getLatitude());
double x2 = MapUtils.getTileNumberX(zoom, nodeLineEnd.getLongitude()); double x2 = MapUtils.getTileNumberX(zoom, nodeLineEnd.getLongitude());
@ -73,4 +78,138 @@ public class MapAlgorithms {
double D = y2 - y1; double D = y2 - y1;
return Math.abs(A * D - C * B) / Math.sqrt(C * C + D * D); return Math.abs(A * D - C * B) / Math.sqrt(C * C + D * D);
} }
public static boolean isClockwiseWay(Way w){
return isClockwiseWay(Collections.singletonList(w));
}
public static boolean isClockwiseWay(List<Way> ways){
if(ways.isEmpty()){
return true;
}
LatLon latLon = ways.get(0).getLatLon();
double lat = latLon.getLatitude();
double lon = 180;
double firstLon = -360;
boolean firstDirectionUp = false;
double previousLon = -360;
double clockwiseSum = 0;
Node prev = null;
boolean firstWay = true;
for(Way w : ways){
List<Node> ns = w.getNodes();
int startInd = 0;
if(firstWay && ns.size() > 0){
prev = ns.get(0);
startInd = 1;
firstWay = false;
}
for(int i = startInd; i < ns.size();i++) {
Node next = ns.get(i);
double rlon = ray_intersect_lon(prev, next, lat, lon);
if(rlon != - 360d){
boolean skipSameSide = (prev.getLatitude() <= lat) == (next.getLatitude() <= lat);
if(skipSameSide){
continue;
}
boolean directionUp = prev.getLatitude() <= lat;
if(firstLon == - 360){
firstDirectionUp = directionUp;
firstLon = rlon;
} else {
boolean clockwise = (!directionUp) == (previousLon < rlon);
if(clockwise){
clockwiseSum += Math.abs(previousLon - rlon);
} else {
clockwiseSum -= Math.abs(previousLon - rlon);
}
}
previousLon = rlon;
}
prev = next;
}
}
if(firstLon != -360){
boolean clockwise = (!firstDirectionUp) == (previousLon < firstLon);
if(clockwise){
clockwiseSum += Math.abs(previousLon - firstLon);
} else {
clockwiseSum -= Math.abs(previousLon - firstLon);
}
}
return clockwiseSum >= 0;
}
public static double ray_intersect_lon(Node node, Node node2, double latitude, double longitude) {
// a node below
Node a = node.getLatitude() < node2.getLatitude() ? node : node2;
// b node above
Node b = a == node2 ? node : node2;
if (latitude == a.getLatitude() || latitude == b.getLatitude()) {
latitude += 0.00000001d;
}
if (latitude < a.getLatitude() || latitude > b.getLatitude()) {
return -360d;
} else {
if (longitude < Math.min(a.getLongitude(), b.getLongitude())) {
return -360d;
} else {
if (a.getLongitude() == b.getLongitude() && longitude == a.getLongitude()) {
// the node on the boundary !!!
return longitude;
}
// that tested on all cases (left/right)
double lon = b.getLongitude()+
(b.getLatitude() - latitude) * (b.getLongitude() - a.getLongitude()) / (b.getLatitude() - a.getLatitude());
if (lon <= longitude) {
return lon;
} else {
return -360d;
}
}
}
}
// Try to intersect with ray from left to right
public static boolean ray_intersect(Node node, Node node2, double latitude, double longitude) {
// a node below
Node a = node.getLatitude() < node2.getLatitude() ? node : node2;
// b node above
Node b = a == node2 ? node : node2;
if(latitude == a.getLatitude() || latitude == b.getLatitude()){
latitude += 0.00000001d;
}
if(latitude < a.getLatitude() || latitude > b.getLatitude()){
return false;
} else {
if(longitude > Math.max(a.getLongitude(), b.getLongitude())) {
return true;
} else if(longitude < Math.min(a.getLongitude(), b.getLongitude())){
return false;
} else {
if(a.getLongitude() == b.getLongitude()) {
// the node on the boundary !!!
return true;
}
// that tested on all cases (left/right)
double mR = (b.getLatitude() - a.getLatitude()) / (b.getLongitude() - a.getLongitude());
double mB = (latitude - a.getLatitude()) / (longitude - a.getLongitude());
if(mB <= mR){
return true;
} else {
return false;
}
}
}
}
} }

View file

@ -10,11 +10,13 @@ import java.io.RandomAccessFile;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Arrays;
import net.osmand.Algoritms; import net.osmand.Algoritms;
import net.osmand.IProgress; import net.osmand.IProgress;
import net.osmand.binary.BinaryMapIndexWriter; import net.osmand.binary.BinaryMapIndexWriter;
import net.osmand.data.IndexConstants; import net.osmand.data.IndexConstants;
import net.osmand.data.preparation.MapZooms.MapZoomPair;
import net.osmand.data.preparation.OsmDbAccessor.OsmDbVisitor; import net.osmand.data.preparation.OsmDbAccessor.OsmDbVisitor;
import net.osmand.impl.ConsoleProgressImplementation; import net.osmand.impl.ConsoleProgressImplementation;
import net.osmand.osm.Entity; import net.osmand.osm.Entity;
@ -63,11 +65,14 @@ public class IndexCreator {
private boolean normalizeStreets = true; // true by default private boolean normalizeStreets = true; // true by default
private boolean saveAddressWays = true; // true by default private boolean saveAddressWays = true; // true by default
private int zoomWaySmothness = 0;
private String regionName; private String regionName;
private String poiFileName = null; private String poiFileName = null;
private String mapFileName = null; private String mapFileName = null;
private Long lastModifiedDate = null; private Long lastModifiedDate = null;
private IndexTransportCreator indexTransportCreator; private IndexTransportCreator indexTransportCreator;
@ -116,6 +121,10 @@ public class IndexCreator {
public void setNormalizeStreets(boolean normalizeStreets) { public void setNormalizeStreets(boolean normalizeStreets) {
this.normalizeStreets = normalizeStreets; this.normalizeStreets = normalizeStreets;
} }
public void setZoomWaySmothness(int zoomWaySmothness) {
this.zoomWaySmothness = zoomWaySmothness;
}
public String getRegionName() { public String getRegionName() {
if (regionName == null) { if (regionName == null) {
@ -351,7 +360,7 @@ public class IndexCreator {
this.accessor = new OsmDbAccessor(); this.accessor = new OsmDbAccessor();
indexMapCreator.initSettings(mapZooms, renderingTypes); indexMapCreator.initSettings(mapZooms, renderingTypes, zoomWaySmothness);
// init address // init address
String[] normalizeDefaultSuffixes = null; String[] normalizeDefaultSuffixes = null;
@ -587,9 +596,9 @@ public class IndexCreator {
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
IndexCreator creator = new IndexCreator(new File("/home/victor/projects/OsmAnd/data/osm-gen/")); //$NON-NLS-1$ IndexCreator creator = new IndexCreator(new File("/home/victor/projects/OsmAnd/data/osm-gen/")); //$NON-NLS-1$
creator.setIndexMap(true); creator.setIndexMap(true);
creator.setIndexAddress(true); // creator.setIndexAddress(true);
creator.setIndexPOI(true); // creator.setIndexPOI(true);
creator.setIndexTransport(true); // creator.setIndexTransport(true);
// for NL // for NL
// creator.setCityAdminLevel("10"); // creator.setCityAdminLevel("10");
@ -597,11 +606,24 @@ public class IndexCreator {
creator.deleteDatabaseIndexes = true; creator.deleteDatabaseIndexes = true;
creator.deleteOsmDB = true; creator.deleteOsmDB = true;
creator.generateIndexes(new File("/home/victor/projects/OsmAnd/download/410/map.osm"), // creator.generateIndexes(new File("/home/victor/projects/OsmAnd/download/410/map.osm"),
new ConsoleProgressImplementation(1), null, MapZooms.getDefault(), null); // new ConsoleProgressImplementation(1), null, MapZooms.getDefault(), null);
// creator.generateIndexes(new File("/home/victor/projects/OsmAnd/data/osm-maps/minsk_around.osm"), // creator.generateIndexes(new File("/home/victor/projects/OsmAnd/data/osm-maps/minsk_around.osm"),
// new ConsoleProgressImplementation(1), null, MapZooms.getDefault(), null); // new ConsoleProgressImplementation(1), null, MapZooms.getDefault(), null);
MapZooms mapZooms = new MapZooms();
MapZoomPair pair1 = new MapZooms.MapZoomPair(1, 3);
MapZoomPair pair2 = new MapZooms.MapZoomPair(4, 5);
MapZoomPair pair3 = new MapZooms.MapZoomPair(6, 7);
mapZooms.setLevels(Arrays.asList(pair1, pair2, pair3));
creator.setZoomWaySmothness(2);
creator.generateIndexes(new File(
"/home/victor/projects/OsmAnd/download/basemap/10m_coastline_out.osm"
// "/home/victor/projects/OsmAnd/download/basemap/10-admin-0-countries.osm"
// "/home/victor/projects/OsmAnd/download/basemap/10m_populated_places.osm"
),
new ConsoleProgressImplementation(1), null, mapZooms, null);
// creator.setNodesDBFile(new File("e:/Information/OSM maps/osmand/minsk.tmp.odb")); // creator.setNodesDBFile(new File("e:/Information/OSM maps/osmand/minsk.tmp.odb"));

View file

@ -12,7 +12,6 @@ import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
@ -67,6 +66,8 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
private int lowLevelWays = -1; private int lowLevelWays = -1;
private RTree[] mapTree = null; private RTree[] mapTree = null;
private Connection mapConnection; private Connection mapConnection;
private int zoomWaySmothness = 0;
public IndexVectorMapCreator() { public IndexVectorMapCreator() {
@ -354,10 +355,9 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
boolean point = (type & 3) == MapRenderingTypes.POINT_TYPE; boolean point = (type & 3) == MapRenderingTypes.POINT_TYPE;
RTree rtree = null; RTree rtree = null;
int zoom;
long id = (baseId << 3) | ((level & 3) << 1); long id = (baseId << 3) | ((level & 3) << 1);
rtree = mapTree[level]; rtree = mapTree[level];
zoom = mapZooms.getLevel(level).getMaxZoom() - 1;
boolean skip = false; boolean skip = false;
String eName = renderingTypes.getEntityName(e); String eName = renderingTypes.getEntityName(e);
@ -368,11 +368,13 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
if (e.getTag(OSMTagKey.HIGHWAY) != null) { if (e.getTag(OSMTagKey.HIGHWAY) != null) {
highwayAttributes = MapRenderingTypes.getHighwayAttributes(e); highwayAttributes = MapRenderingTypes.getHighwayAttributes(e);
} }
if (e instanceof Way) { if (e instanceof Way) {
id |= 1; id |= 1;
// simplify route // simplify route
if (level > 0) { int zoomToSimplify = mapZooms.getLevel(level).getMaxZoom() - 1;
e = simplifyWay((Way) e, id, hasMulti, zoom, eName, type, level); if (zoomToSimplify < 15) {
e = simplifyWay((Way) e, id, hasMulti, zoomToSimplify, eName, type, level);
skip = e == null; skip = e == null;
} }
@ -443,12 +445,13 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
boolean cycle = originalE.getNodeIds().get(0).longValue() == originalE.getNodeIds().get(nodes.size() - 1).longValue(); boolean cycle = originalE.getNodeIds().get(0).longValue() == originalE.getNodeIds().get(nodes.size() - 1).longValue();
long longType = encodeTypesToOneLong(type); long longType = encodeTypesToOneLong(type);
boolean skip = checkForSmallAreas(nodes, zoom, 3, 3); if (cycle) {
if (skip && cycle/* || !hasMulti)*/) { if(checkForSmallAreas(nodes, zoom + Math.min(zoomWaySmothness / 2, 3), 1, 4)){
return null; return null;
}
} }
MapAlgorithms.simplifyDouglasPeucker(nodes, zoom + 8, 3, way); MapAlgorithms.simplifyDouglasPeucker(nodes, zoom + 8 + zoomWaySmothness, 3, way);
if (way.getNodes().size() < 2) { if (way.getNodes().size() < 2) {
return null; return null;
} }
@ -575,12 +578,12 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
boolean cycle = startNode == endNode; boolean cycle = startNode == endNode;
boolean hasMulti = multiPolygonsWays[level].containsKey(id >> 3); boolean hasMulti = multiPolygonsWays[level].containsKey(id >> 3);
if(cycle || !hasMulti){ if(cycle || !hasMulti){
skip = checkForSmallAreas(wNodes, zoom - 1, 1, 4); skip = checkForSmallAreas(wNodes, zoom - 1 + Math.min(zoomWaySmothness / 2, 3), 1, 4);
} }
if (!skip) { if (!skip) {
Way newWs = new Way(id); Way newWs = new Way(id);
MapAlgorithms.simplifyDouglasPeucker(wNodes, zoom - 1 + 8, 3, newWs); MapAlgorithms.simplifyDouglasPeucker(wNodes, zoom - 1 + 8 + zoomWaySmothness, 3, newWs);
int type = decodeTypesFromOneLong(ltype); int type = decodeTypesFromOneLong(ltype);
insertBinaryMapRenderObjectIndex(mapTree[level], newWs, name, insertBinaryMapRenderObjectIndex(mapTree[level], newWs, name,
@ -617,8 +620,9 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void initSettings(MapZooms mapZooms, MapRenderingTypes renderingTypes) { public void initSettings(MapZooms mapZooms, MapRenderingTypes renderingTypes, int zoomWaySmothness) {
this.mapZooms = mapZooms; this.mapZooms = mapZooms;
this.zoomWaySmothness = zoomWaySmothness;
this.renderingTypes = renderingTypes; this.renderingTypes = renderingTypes;
// init map // init map
multiPolygonsWays = new Map[mapZooms.size()]; multiPolygonsWays = new Map[mapZooms.size()];
@ -633,9 +637,10 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
if (e instanceof Way || e instanceof Node) { if (e instanceof Way || e instanceof Node) {
// manipulate what kind of way to load // manipulate what kind of way to load
ctx.loadEntityData(e, false); ctx.loadEntityData(e, false);
boolean inverse = "-1".equals(e.getTag(OSMTagKey.ONEWAY)); //$NON-NLS-1$ boolean oneway = "-1".equals(e.getTag(OSMTagKey.ONEWAY)); //$NON-NLS-1$
for (int i = 0; i < mapZooms.size(); i++) { for (int i = 0; i < mapZooms.size(); i++) {
writeBinaryEntityToMapDatabase(e, e.getId(), i == 0 ? inverse : false, i); boolean inverse = i == 0 ? oneway : false;
writeBinaryEntityToMapDatabase(e, e.getId(), inverse, i);
} }
} }
} }
@ -922,4 +927,12 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
closeAllPreparedStatements(); closeAllPreparedStatements();
} }
public void setZoomWaySmothness(int zoomWaySmothness) {
this.zoomWaySmothness = zoomWaySmothness;
}
public int getZoomWaySmothness() {
return zoomWaySmothness;
}
} }

View file

@ -1,11 +1,14 @@
package net.osmand.data.preparation; package net.osmand.data.preparation;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
public class MapZooms { public class MapZooms {
public static class MapZoomPair { public static class MapZoomPair {
public static int MAX_ALLOWED_ZOOM = 22;
private int minZoom; private int minZoom;
private int maxZoom; private int maxZoom;
@ -22,6 +25,10 @@ public class MapZooms {
return maxZoom; return maxZoom;
} }
@Override
public String toString() {
return "MapZoomPair : " + minZoom + " - "+ maxZoom;
}
} }
private List<MapZoomPair> levels = new ArrayList<MapZoomPair>(); private List<MapZoomPair> levels = new ArrayList<MapZoomPair>();
@ -33,6 +40,13 @@ public class MapZooms {
public void setLevels(List<MapZoomPair> levels) { public void setLevels(List<MapZoomPair> levels) {
this.levels = levels; this.levels = levels;
Collections.sort(levels, new Comparator<MapZoomPair>() {
@Override
public int compare(MapZoomPair o1, MapZoomPair o2) {
return -new Integer(o1.getMaxZoom()).compareTo(o2.getMaxZoom());
}
});
} }
/** /**
* @param zooms - could be 5-8;7-10;13-15;15 * @param zooms - could be 5-8;7-10;13-15;15
@ -51,7 +65,7 @@ public class MapZooms {
list.add(0, new MapZoomPair(Integer.parseInt(s.substring(0, i)), Integer.parseInt(s.substring(i + 1)))); list.add(0, new MapZoomPair(Integer.parseInt(s.substring(0, i)), Integer.parseInt(s.substring(i + 1))));
} }
} }
list.add(0, new MapZoomPair(zeroLevel, 22)); list.add(0, new MapZoomPair(zeroLevel, MapZoomPair.MAX_ALLOWED_ZOOM));
if(list.size() < 1 || list.size() > 4){ if(list.size() < 1 || list.size() > 4){
throw new IllegalArgumentException("Map zooms should have at least 1 level and less than 4 levels"); throw new IllegalArgumentException("Map zooms should have at least 1 level and less than 4 levels");
} }

View file

@ -137,17 +137,18 @@ public class MapRenderingTypes {
// val could be null means others for that tag // val could be null means others for that tag
private Integer nullRule; private Integer nullRule;
private Map<String, Integer> rules = new LinkedHashMap<String, Integer>(); private Map<String, Integer> rules = new LinkedHashMap<String, Integer>();
private String nameNullTag; private Map<String, String> nameNullTag = new LinkedHashMap<String, String>();
public MapRulType(String tag, String nameNullTag){ public MapRulType(String tag, String nameNullTag){
this.tag = tag; this.tag = tag;
this.nameNullTag.put(null, nameNullTag);
} }
public String getTag() { public String getTag() {
return tag; return tag;
} }
public String getNameNullTag() { public Map<String, String> getNameNullTag() {
return nameNullTag; return nameNullTag;
} }
@ -563,8 +564,10 @@ public class MapRenderingTypes {
for (String tag : tagKeySet) { for (String tag : tagKeySet) {
if (types.containsKey(tag)) { if (types.containsKey(tag)) {
MapRulType rType = types.get(tag); MapRulType rType = types.get(tag);
if (rType.getNameNullTag() != null) { String val = i == 1 ? null : e.getTag(tag);
name = e.getTag(rType.getNameNullTag()); String nameNullTag = rType.getNameNullTag().get(val);
if (nameNullTag != null) {
name = e.getTag(nameNullTag);
if (name != null) { if (name != null) {
break; break;
} }
@ -765,10 +768,13 @@ public class MapRenderingTypes {
if(st == INIT_RULE_TYPES){ if(st == INIT_RULE_TYPES){
MapRulType rtype = types.get(tag); MapRulType rtype = types.get(tag);
if(rtype == null){ if(rtype == null){
rtype = new MapRulType(tag, nameNullTag); rtype = new MapRulType(tag, null);
types.put(tag, rtype); types.put(tag, rtype);
} }
rtype.registerType(minZoom, val, pointRule, polylineRule, polygonRule, type, subtype); rtype.registerType(minZoom, val, pointRule, polylineRule, polygonRule, type, subtype);
if(nameNullTag != null){
rtype.getNameNullTag().put(val, nameNullTag);
}
} else if(st == INIT_AMENITY_MAP){ } else if(st == INIT_AMENITY_MAP){
if(pointRule == POINT_TYPE || polygonRule == POLYGON_WITH_CENTER_TYPE || polygonRule == POLYGON_TYPE){ if(pointRule == POINT_TYPE || polygonRule == POLYGON_WITH_CENTER_TYPE || polygonRule == POLYGON_TYPE){
registerAmenity(tag, val, type, subtype); registerAmenity(tag, val, type, subtype);

View file

@ -37,7 +37,11 @@ public class Way extends Entity {
if(nodeIds == null){ if(nodeIds == null){
return null; return null;
} }
return nodeIds.remove(i); Long toReturn = nodeIds.remove(i);
if(nodes != null && nodes.size() > i){
nodes.remove(i);
}
return toReturn;
} }
public List<Long> getNodeIds(){ public List<Long> getNodeIds(){

View file

@ -409,7 +409,7 @@
<type id="17" name="natural"> <type id="17" name="natural">
<subtype id="5" polygon="true" tag="natural" value="coastline" minzoom="5" /> <subtype id="5" polygon="true" tag="natural" value="coastline" minzoom="1" />
<subtype id="1" point="true" polygon="true" tag="natural" value="bay" minzoom="15" /> <subtype id="1" point="true" polygon="true" tag="natural" value="bay" minzoom="15" />
<subtype id="2" point="true" polygon="true" tag="natural" value="beach" minzoom="12" /> <subtype id="2" point="true" polygon="true" tag="natural" value="beach" minzoom="12" />
<subtype id="3" point="true" polygon_center="true" tag="natural" value="cave_entrance" minzoom="13" /> <subtype id="3" point="true" polygon_center="true" tag="natural" value="cave_entrance" minzoom="13" />
@ -540,14 +540,16 @@
</type> </type>
<type id="25" name="administrative"> <type id="25" name="administrative">
<subtype id="41" point="true" tag="place" value="continent" minzoom="5" /> <subtype id="41" point="true" tag="place" value="continent" minzoom="5" />
<subtype id="42" point="true" tag="place" value="country" minzoom="5" /> <subtype id="42" point="true" tag="place" value="country" minzoom="5" />
<subtype id="43" point="true" tag="place" value="state" minzoom="5" /> <subtype id="43" point="true" tag="place" value="state" minzoom="5" />
<subtype id="44" point="true" tag="place" value="region" minzoom="5" /> <subtype id="44" point="true" tag="place" value="region" minzoom="5" />
<subtype id="45" point="true" tag="place" value="county" minzoom="5" /> <subtype id="45" point="true" tag="place" value="county" minzoom="5" />
<subtype id="6" point="true" polygon_center="true" tag="place" value="city" minzoom="6" /> <subtype id="6" point="true" polygon_center="true" tag="place" value="city" minzoom="4" />
<subtype id="7" point="true" polygon_center="true" tag="place" value="town" minzoom="7" /> <subtype id="7" point="true" polygon_center="true" tag="place" value="town" minzoom="6" />
<subtype id="8" point="true" polygon_center="true" tag="place" value="village" minzoom="10" /> <subtype id="8" point="true" polygon_center="true" tag="place" value="village" minzoom="10" />
<subtype id="9" point="true" polygon_center="true" tag="place" value="hamlet" minzoom="10" /> <subtype id="9" point="true" polygon_center="true" tag="place" value="hamlet" minzoom="10" />
<subtype id="10" point="true" polygon_center="true" tag="place" value="suburb" minzoom="10" /> <subtype id="10" point="true" polygon_center="true" tag="place" value="suburb" minzoom="10" />
@ -570,8 +572,10 @@
<subtype id="19" polyline="true" tag="boundary" value="national_park" minzoom="7" /> <subtype id="19" polyline="true" tag="boundary" value="national_park" minzoom="7" />
<subtype id="20" polyline="true" tag="boundary" value="protected_area" minzoom="7" /> <subtype id="20" polyline="true" tag="boundary" value="protected_area" minzoom="7" />
<subtype id="33" point="true" tag="addr:housenumber" minzoom="15" /> <subtype id="33" point="true" tag="addr:housenumber" minzoom="15" />
</type> </type>
<type id="27" name="sport"> <type id="27" name="sport">
<subtype id="1" point="true" tag="sport" value="9pin" minzoom="15" /> <subtype id="1" point="true" tag="sport" value="9pin" minzoom="15" />
@ -623,4 +627,11 @@
<subtype id="47" point="true" tag="sport" value="volleyball" minzoom="15" /> <subtype id="47" point="true" tag="sport" value="volleyball" minzoom="15" />
<subtype id="50" point="true" tag="sport" minzoom="15" /> <subtype id="50" point="true" tag="sport" minzoom="15" />
</type> </type>
<!-- Processing base map at the end to not override tag/values for decoding -->
<type id="25" name="administrative">
<!-- same as town/city -->
<subtype id="6" point="true" tag="MEGACITY" value="1" minzoom="4" nameNullTag="NAME"/>
<subtype id="7" point="true" tag="MEGACITY" value="0" minzoom="6" nameNullTag="NAME"/>
</type>
</osmand_types> </osmand_types>

View file

@ -0,0 +1,244 @@
package net.osmand.osm.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.xml.stream.XMLStreamException;
import net.osmand.data.MapAlgorithms;
import net.osmand.impl.ConsoleProgressImplementation;
import net.osmand.osm.Entity;
import net.osmand.osm.LatLon;
import net.osmand.osm.MapUtils;
import net.osmand.osm.Node;
import net.osmand.osm.Way;
import net.osmand.osm.Entity.EntityId;
import net.osmand.osm.Entity.EntityType;
import net.osmand.osm.OSMSettings.OSMTagKey;
import net.osmand.osm.io.OsmBaseStorage;
import net.osmand.osm.io.OsmStorageWriter;
import org.xml.sax.SAXException;
public class FixLinkedCoastline {
public static void main(String[] args) throws IOException, SAXException, XMLStreamException {
String fileToRead = args != null && args.length > 0 ? args[0] : null;
if(fileToRead == null) {
fileToRead = "/home/victor/projects/OsmAnd/download/basemap/10m_coastline.osm";
}
File read = new File(fileToRead);
File write ;
String fileToWrite = args != null && args.length > 1 ? args[1] : null;
if(fileToWrite != null){
write = new File(fileToWrite);
} else {
String fileName = read.getName();
int i = fileName.lastIndexOf('.');
fileName = fileName.substring(0, i) + "_out"+ fileName.substring(i);
write = new File(read.getParentFile(), fileName);
}
write.createNewFile();
process(read, write);
}
private static void process(File read, File write) throws IOException, SAXException, XMLStreamException {
OsmBaseStorage storage = new OsmBaseStorage();
storage.parseOSM(new FileInputStream(read), new ConsoleProgressImplementation());
Map<EntityId, Entity> entities = new HashMap<EntityId, Entity>( storage.getRegisteredEntities());
List<EntityId> toWrite = new ArrayList<EntityId>();
for(EntityId e : entities.keySet()){
if(e.getType() == EntityType.WAY){
Entity oldWay = storage.getRegisteredEntities().remove(e);
List<Way> result = processWay((Way) oldWay);
alignAndAddtoStorage(storage, toWrite, result);
}
}
System.out.println("ERROR Ways : ");
int errors = 0;
for(List<Way> w : endWays.values()){
Way way = w.get(0);
Way lway = w.get(w.size() - 1);
LatLon first = way.getNodes().get(0).getLatLon();
LatLon last = lway.getNodes().get(lway.getNodes().size() - 1).getLatLon();
double dist = MapUtils.getDistance(first, last);
if(dist < 500 && w.size() >= 3){
alignAndAddtoStorage(storage, toWrite, w);
} else {
errors++;
String val = "First " + first+ "Last " + last + " id " + way.getId() + " dist " + MapUtils.getDistance(first, last) + " m";
System.out.println("Ways in chain - " + w.size() + " - " + val);
}
}
System.out.println("Fixed errors : " + ERRORS +", errors not fixed : " + errors );
OsmStorageWriter writer = new OsmStorageWriter();
writer.saveStorage(new FileOutputStream(write), storage, toWrite, true);
}
private static void alignAndAddtoStorage(OsmBaseStorage storage, List<EntityId> toWrite, List<Way> result) {
// align start/end node and add to strage
for (int i = 0; i < result.size(); i++) {
Node nextStart;
if (i < result.size() - 1) {
nextStart = result.get(i + 1).getNodes().get(0);
} else {
nextStart = result.get(0).getNodes().get(0);
}
Way w = result.get(i);
int sz = w.getNodes().size();
w.removeNodeByIndex(sz - 1);
w.addNode(nextStart);
if("land_coastline".equals(w.getTag(OSMTagKey.NATURAL))) {
w.putTag(OSMTagKey.NATURAL.getValue(), "coastline");
}
EntityId eId = EntityId.valueOf(w);
storage.getRegisteredEntities().put(eId, w);
toWrite.add(eId);
}
}
private static long calcCoordinate(net.osmand.osm.Node node){
LatLon l = node.getLatLon();
double lon =l.getLongitude();
if(180 - Math.abs(l.getLongitude()) < 0.0001){
if(l.getLongitude() < 0){
lon = -179.9999;
} else {
lon = 180;
}
}
return ((long)MapUtils.getTileNumberY(21, l.getLatitude()) << 32l) + ((long)MapUtils.getTileNumberX(21, lon));
}
private static Map<Long, List<Way>> startWays = new LinkedHashMap<Long, List<Way>>();
private static Map<Long, List<Way>> endWays = new LinkedHashMap<Long, List<Way>>();
private static Map<Way, LatLon> duplicatedSimpleIslands = new LinkedHashMap<Way, LatLon>();
private static int ERRORS = 0;
private static Way revertWay(Way way){
ArrayList<net.osmand.osm.Node> revNodes = new ArrayList<net.osmand.osm.Node>(way.getNodes());
Collections.reverse(revNodes);
Way ws = new Way(way.getId());
for(String key : way.getTagKeySet()){
ws.putTag(key, way.getTag(key));
}
for(net.osmand.osm.Node n : revNodes){
ws.addNode(n);
}
return ws;
}
private static boolean pointContains(long start, long end){
return startWays.containsKey(start) || endWays.containsKey(end) || startWays.containsKey(end) || endWays.containsKey(start);
}
private static long lastPoint(Way w){
return calcCoordinate(w.getNodes().get(w.getNodes().size() - 1));
}
private static long lastPoint(List<Way> w){
return lastPoint(w.get(w.size() - 1));
}
private static long firstPoint(List<Way> w){
return firstPoint(w.get(0));
}
private static long firstPoint(Way way) {
return calcCoordinate(way.getNodes().get(0));
}
private static List<Way> processWay(Way way) {
// F Lat 8.27039215702537 Lon 73.0661727222713L Lat 8.27039215702537 Lon 73.0661727222713 id -1211228
long start = firstPoint(way);
long end = lastPoint(way);
LatLon first = way.getNodes().get(0).getLatLon();
LatLon last = way.getNodes().get(way.getNodes().size() - 1).getLatLon();
String val = "F " + first + "L " + last + " id " + way.getId();
List<Way> cycle = null;
if (start == end || MapUtils.getDistance(first, last) < 20) {
LatLon c = way.getLatLon();
cycle = Collections.singletonList(way);
for(Way w : duplicatedSimpleIslands.keySet()){
LatLon center = duplicatedSimpleIslands.get(w);
if(MapUtils.getDistance(center, c) < 4000){
//System.out.println("DUPLICATED " + first);
return Collections.emptyList();
}
}
duplicatedSimpleIslands.put(way, c);
} else {
List<Way> list = new ArrayList<Way>();
list.add(way);
// System.out.println(val);
while (pointContains(start, end)) {
if (startWays.containsKey(start) || endWays.containsKey(end)) {
ERRORS++;
Collections.reverse(list);
for (int i = 0; i < list.size(); i++) {
list.set(i, revertWay(list.get(i)));
}
long t = start;
start = end;
end = t;
}
if (endWays.containsKey(start)) {
List<Way> tlist = endWays.remove(start);
startWays.remove(firstPoint(tlist));
tlist.addAll(list);
list = tlist;
} else if (startWays.containsKey(end)) {
List<Way> tlist = startWays.remove(end);
endWays.remove(lastPoint(tlist));
list.addAll(tlist);
}
start = firstPoint(list);
end = lastPoint(list);
if (start == end) {
cycle = list;
break;
}
}
if (cycle == null) {
startWays.put(start, list);
endWays.put(end, list);
}
}
if (cycle != null) {
boolean clockwiseWay = MapAlgorithms.isClockwiseWay(cycle);
if (clockwiseWay) {
List<Way> ways = new ArrayList<Way>();
ERRORS ++;
for (int i = cycle.size() - 1; i >= 0; i--) {
// System.out.println("Cycle error " + way.getId());
ways.add(revertWay(cycle.get(i)));
}
return ways;
}
return cycle;
}
return Collections.emptyList();
}
}

View file

@ -310,12 +310,13 @@
<filter minzoom="4" maxzoom="7" textSize="9" textColor="#9d6c9d" textHaloRadius="1" textWrapWidth="20" tag="place" value="region" /> <filter minzoom="4" maxzoom="7" textSize="9" textColor="#9d6c9d" textHaloRadius="1" textWrapWidth="20" tag="place" value="region" />
<filter minzoom="8" textSize="11" textColor="#9d6c9d" textHaloRadius="1" textWrapWidth="20" tag="place" value="region" /> <filter minzoom="8" textSize="11" textColor="#9d6c9d" textHaloRadius="1" textWrapWidth="20" tag="place" value="region" />
<filter minzoom="6" maxzoom="8" textSize="8" textHaloRadius="1" textWrapWidth="20" tag="place" value="city" /> <filter minzoom="4" maxzoom="6" textSize="10" textHaloRadius="1" textWrapWidth="20" tag="place" value="city" />
<filter minzoom="9" maxzoom="10" textSize="11" textHaloRadius="1" textWrapWidth="20" tag="place" value="city" /> <filter minzoom="7" maxzoom="8" textSize="11" textHaloRadius="1" textWrapWidth="20" tag="place" value="city" />
<filter minzoom="9" maxzoom="10" textSize="12" textHaloRadius="1" textWrapWidth="20" tag="place" value="city" />
<filter minzoom="11" textSize="14" textHaloRadius="1" textWrapWidth="20" tag="place" value="city" /> <filter minzoom="11" textSize="14" textHaloRadius="1" textWrapWidth="20" tag="place" value="city" />
<filter minzoom="9" maxzoom="10" textSize="8" textHaloRadius="1" textWrapWidth="20" tag="place" value="town" /> <filter minzoom="6" maxzoom="10" textSize="10" textHaloRadius="1" textWrapWidth="20" tag="place" value="town" />
<filter minzoom="11" maxzoom="13" textSize="11" textHaloRadius="1" textWrapWidth="20" tag="place" value="town" /> <filter minzoom="11" maxzoom="13" textSize="12" textHaloRadius="1" textWrapWidth="20" tag="place" value="town" />
<filter minzoom="14" textSize="13" textColor="#777777" textHaloRadius="1" textWrapWidth="20" tag="place" value="town" /> <filter minzoom="14" textSize="14" textColor="#777777" textHaloRadius="1" textWrapWidth="20" tag="place" value="town" />
<filter minzoom="12" maxzoom="14" textSize="9" textHaloRadius="1" tag="place" value="village" /> <filter minzoom="12" maxzoom="14" textSize="9" textHaloRadius="1" tag="place" value="village" />
<filter minzoom="15" textSize="12" textColor="#777777" textHaloRadius="1" tag="place" value="village" /> <filter minzoom="15" textSize="12" textColor="#777777" textHaloRadius="1" tag="place" value="village" />
@ -447,6 +448,9 @@
<filter minzoom="16" icon="viewpoint" tag="tourism" value="viewpoint" /> <filter minzoom="16" icon="viewpoint" tag="tourism" value="viewpoint" />
<filter minzoom="16" icon="geocache_found" tag="geocache" value="found" /> <filter minzoom="16" icon="geocache_found" tag="geocache" value="found" />
<filter minzoom="16" icon="geocache_not_found" tag="geocache" /> <filter minzoom="16" icon="geocache_not_found" tag="geocache" />
<filter minzoom="4" maxzoom="12" icon="city" value="city" />
<filter minzoom="6" maxzoom="14" icon="city" value="town" />
</point> </point>
<!-- PRIORITY Input to filter : tag, value, zoom [minzoom, maxzoom] --> <!-- PRIORITY Input to filter : tag, value, zoom [minzoom, maxzoom] -->
@ -498,7 +502,7 @@
<filter minzoom="14" color="#30666600" color_2="#60666600" strokeWidth_2="1" tag="natural" value="field" /> <filter minzoom="14" color="#30666600" color_2="#60666600" strokeWidth_2="1" tag="natural" value="field" />
<filter color="#b5d0d0"> <filter color="#b5d0d0">
<filter minzoom="6" tag="natural" value="coastline" /> <filter minzoom="1" tag="natural" value="coastline" />
<filter minzoom="7" tag="natural" value="water" /> <filter minzoom="7" tag="natural" value="water" />
<filter minzoom="7" tag="natural" value="lake" /> <filter minzoom="7" tag="natural" value="lake" />
</filter> </filter>

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

View file

@ -53,7 +53,7 @@
<string name="tip_day_night_mode">Day/Night Mode</string> <string name="tip_day_night_mode">Day/Night Mode</string>
<string name="tip_day_night_mode_t">\tThe map appearance can for some vector maps be changed between day (brighter) and night (darker). <string name="tip_day_night_mode_t">\tThe map appearance can for some vector maps be changed between day (brighter) and night (darker).
\n\tNight colors are safer for night driving. \n\tNight colors are safer for night driving.
\n\tYou can set a policy for day/night switching in \'Main Menu\' -> \'Settings\' -> \'Maps\' ->\'Day/night mode\'. \n\tYou can set a policy for day/night switching in \'Main Menu\' -> \'Settings\' -> \'Map appearance\' ->\'Day/night mode\'.
\n\tChoices are: \n\tChoices are:
\n\t\'Sunrise/Sunset\' - automatic mode, controlled by position of the sun (default) \n\t\'Sunrise/Sunset\' - automatic mode, controlled by position of the sun (default)
\n\t\'Day\' - always use day mode \n\t\'Day\' - always use day mode

View file

@ -500,7 +500,7 @@ public class OsmandSettings {
public final OsmandPreference<Integer> MAX_LEVEL_TO_DOWNLOAD_TILE = new IntPreference("max_level_download_tile", 18, false, true); public final OsmandPreference<Integer> MAX_LEVEL_TO_DOWNLOAD_TILE = new IntPreference("max_level_download_tile", 18, false, true);
// this value string is synchronized with settings_pref.xml preference name // this value string is synchronized with settings_pref.xml preference name
public final OsmandPreference<Integer> LEVEL_TO_SWITCH_VECTOR_RASTER = new IntPreference("level_to_switch_vector_raster", 5, false, true); public final OsmandPreference<Integer> LEVEL_TO_SWITCH_VECTOR_RASTER = new IntPreference("level_to_switch_vector_raster", 1, false, true);
// this value string is synchronized with settings_pref.xml preference name // this value string is synchronized with settings_pref.xml preference name
public final OsmandPreference<Boolean> MAP_VIEW_3D = new BooleanPreference("map_view_3d", false, false); public final OsmandPreference<Boolean> MAP_VIEW_3D = new BooleanPreference("map_view_3d", false, false);

View file

@ -164,9 +164,11 @@ public class MainMenuActivity extends Activity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
boolean exit = false;
if(getIntent() != null){ if(getIntent() != null){
Intent intent = getIntent(); Intent intent = getIntent();
if(intent.getExtras() != null && intent.getExtras().containsKey(APP_EXIT_KEY)){ if(intent.getExtras() != null && intent.getExtras().containsKey(APP_EXIT_KEY)){
exit = true;
finish(); finish();
} }
} }
@ -222,10 +224,11 @@ public class MainMenuActivity extends Activity {
activity.startActivity(search); activity.startActivity(search);
} }
}); });
if(exit){
return;
}
((OsmandApplication)getApplication()).checkApplicationIsBeingInitialized(this); ((OsmandApplication)getApplication()).checkApplicationIsBeingInitialized(this);
SharedPreferences pref = getPreferences(MODE_WORLD_WRITEABLE); SharedPreferences pref = getPreferences(MODE_WORLD_WRITEABLE);
boolean firstTime = false; boolean firstTime = false;
if(!pref.contains(FIRST_TIME_APP_RUN)){ if(!pref.contains(FIRST_TIME_APP_RUN)){

View file

@ -231,7 +231,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
} }
registerListPreference(osmandSettings.MAX_LEVEL_TO_DOWNLOAD_TILE, screen, entries, intValues); registerListPreference(osmandSettings.MAX_LEVEL_TO_DOWNLOAD_TILE, screen, entries, intValues);
startZoom = 3; startZoom = 1;
endZoom = 18; endZoom = 18;
entries = new String[endZoom - startZoom + 1]; entries = new String[endZoom - startZoom + 1];
intValues = new Integer[endZoom - startZoom + 1]; intValues = new Integer[endZoom - startZoom + 1];

View file

@ -93,24 +93,24 @@ public class MapVectorLayer extends BaseMapLayer {
tileLayer.drawTileMap(canvas, tilesRect); tileLayer.drawTileMap(canvas, tilesRect);
resourceManager.getRenderer().interruptLoadingMap(); resourceManager.getRenderer().interruptLoadingMap();
} else { } else {
if (!view.isZooming()){ if (!view.isZooming()) {
pixRect.set(0, 0, view.getWidth(), view.getHeight()); pixRect.set(0, 0, view.getWidth(), view.getHeight());
updateRotatedTileBox(); updateRotatedTileBox();
if(resourceManager.updateRenderedMapNeeded(rotatedTileBox)){ if (resourceManager.updateRenderedMapNeeded(rotatedTileBox)) {
// pixRect.set(-view.getWidth(), -view.getHeight() / 2, 2 * view.getWidth(), 3 * view.getHeight() / 2); // pixRect.set(-view.getWidth(), -view.getHeight() / 2, 2 * view.getWidth(), 3 * view.getHeight() / 2);
pixRect.set(-view.getWidth()/3, -view.getHeight() / 4, 4 * view.getWidth() /3, 5 * view.getHeight() / 4); pixRect.set(-view.getWidth() / 3, -view.getHeight() / 4, 4 * view.getWidth() / 3, 5 * view.getHeight() / 4);
updateRotatedTileBox(); updateRotatedTileBox();
resourceManager.updateRendererMap(rotatedTileBox); resourceManager.updateRendererMap(rotatedTileBox);
// does it slow down Map refreshing ? // does it slow down Map refreshing ?
// Arguments : 1. Map request to read data slows whole process // 2. It works in operating memory // Arguments : 1. Map request to read data slows whole process // 2. It works in operating memory
if(!warningToSwitchMapShown){ if (!warningToSwitchMapShown) {
if(!resourceManager.getRenderer().containsLatLonMapData(view.getLatitude(), view.getLongitude(), view.getZoom())){ if (!resourceManager.getRenderer().containsLatLonMapData(view.getLatitude(), view.getLongitude(), view.getZoom())) {
Toast.makeText(view.getContext(), R.string.switch_to_raster_map_to_see, Toast.LENGTH_LONG).show(); Toast.makeText(view.getContext(), R.string.switch_to_raster_map_to_see, Toast.LENGTH_LONG).show();
warningToSwitchMapShown = true; warningToSwitchMapShown = true;
} }
} }
} }
} }
MapRenderRepositories renderer = resourceManager.getRenderer(); MapRenderRepositories renderer = resourceManager.getRenderer();

View file

@ -685,8 +685,8 @@ public class OsmandRenderer {
rc.main.updatePaint(paint); rc.main.updatePaint(paint);
canvas.drawPath(path, paint); canvas.drawPath(path, paint);
// for test purpose // for test purpose
// rc.second.strokeWidth = 1.5f; // rc.second.strokeWidth = 1.5f;
// rc.second.color = Color.BLACK; // rc.second.color = Color.BLACK;
if (rc.second.strokeWidth != 0) { if (rc.second.strokeWidth != 0) {
rc.second.updatePaint(paint); rc.second.updatePaint(paint);

View file

@ -1,9 +1,11 @@
package net.osmand.plus.render; package net.osmand.plus.render;
import java.lang.reflect.Field;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.R.drawable;
public class RenderingIcons { public class RenderingIcons {
@ -16,183 +18,19 @@ public class RenderingIcons {
return icons; return icons;
} }
private static void initIcons() { public static void initIcons() {
icons.put("aerodrome", R.drawable.h_aerodrome); //$NON-NLS-1$
icons.put("airport", R.drawable.h_airport); //$NON-NLS-1$
icons.put("alpine_hut", R.drawable.h_alpine_hut); //$NON-NLS-1$
icons.put("amenity_court", R.drawable.h_amenity_court); //$NON-NLS-1$
icons.put("arts_centre", R.drawable.g_amenity_arts_centre); //$NON-NLS-1$
icons.put("atm", R.drawable.h_atm); //$NON-NLS-1$
icons.put("bank", R.drawable.h_bank); //$NON-NLS-1$
icons.put("bar", R.drawable.h_bar); //$NON-NLS-1$
icons.put("beach", R.drawable.h_beach); //$NON-NLS-1$
icons.put("bench", R.drawable.g_amenity_bench); //$NON-NLS-1$
icons.put("biergarten", R.drawable.h_biergarten); //$NON-NLS-1$
icons.put("bicycle_rental", R.drawable.h_bicycle_rental); //$NON-NLS-1$
icons.put("bollard", R.drawable.h_bollard); //$NON-NLS-1$
icons.put("books", R.drawable.g_shop_books); //$NON-NLS-1$
icons.put("bus_station", R.drawable.h_bus_station); //$NON-NLS-1$
icons.put("bus_stop_small", R.drawable.h_bus_stop_small); //$NON-NLS-1$
icons.put("bus_stop", R.drawable.h_bus_stop); //$NON-NLS-1$
icons.put("cable_car", R.drawable.h_cable_car); //$NON-NLS-1$
icons.put("cafe", R.drawable.h_cafe); //$NON-NLS-1$
icons.put("camp_site", R.drawable.h_camp_site); //$NON-NLS-1$
icons.put("car_sharing", R.drawable.h_car_sharing); //$NON-NLS-1$
icons.put("caravan_park", R.drawable.h_caravan_park); //$NON-NLS-1$
icons.put("casino", R.drawable.g_tourist_casino); //$NON-NLS-1$
icons.put("castle", R.drawable.g_historic_castle); //$NON-NLS-1$
icons.put("cave_entrance", R.drawable.h_cave_entrance); //$NON-NLS-1$
icons.put("chair_lift", R.drawable.h_chair_lift); //$NON-NLS-1$
icons.put("chalet", R.drawable.h_chalet); //$NON-NLS-1$
icons.put("cinema", R.drawable.h_cinema); //$NON-NLS-1$
icons.put("cliff", R.drawable.h_cliff); //$NON-NLS-1$
icons.put("cliff2", R.drawable.h_cliff2); //$NON-NLS-1$
icons.put("computer", R.drawable.g_shop_computer); //$NON-NLS-1$
icons.put("confectionery", R.drawable.g_shop_confectionery); //$NON-NLS-1$
icons.put("courthouse", R.drawable.g_amenity_courthouse); //$NON-NLS-1$
icons.put("danger", R.drawable.h_danger); //$NON-NLS-1$
icons.put("department_store", R.drawable.h_department_store); //$NON-NLS-1$
icons.put("do_it_yourself", R.drawable.g_shop_diy); //$NON-NLS-1$
icons.put("drinking_water", R.drawable.h_drinking_water); //$NON-NLS-1$
icons.put("embassy", R.drawable.h_embassy); //$NON-NLS-1$
icons.put("emergency_phone", R.drawable.h_emergency_phone); //$NON-NLS-1$
icons.put("entrance", R.drawable.g_barrier_entrance); //$NON-NLS-1$
icons.put("exchange", R.drawable.g_money_exchange); //$NON-NLS-1$
icons.put("fast_food", R.drawable.h_fast_food); //$NON-NLS-1$
icons.put("fire_station", R.drawable.h_fire_station); //$NON-NLS-1$
icons.put("forest", R.drawable.h_forest); //$NON-NLS-1$
icons.put("fuel", R.drawable.h_fuel); //$NON-NLS-1$
icons.put("gate2", R.drawable.h_gate2); //$NON-NLS-1$
icons.put("geocache_found", R.drawable.h_geocache_found); //$NON-NLS-1$
icons.put("geocache_not_found", R.drawable.h_geocache_not_found); //$NON-NLS-1$
icons.put("guest_house", R.drawable.h_guest_house); //$NON-NLS-1$
icons.put("glacier", R.drawable.h_glacier); //$NON-NLS-1$
icons.put("grave_yard", R.drawable.h_grave_yard); //$NON-NLS-1$
icons.put("guest_house", R.drawable.h_guest_house); //$NON-NLS-1$
icons.put("florist", R.drawable.h_florist); //$NON-NLS-1$
icons.put("fountain", R.drawable.g_amenity_fountain); //$NON-NLS-1$
icons.put("garden_centre", R.drawable.g_shop_garden_centre); //$NON-NLS-1$
icons.put("halt", R.drawable.h_halt); //$NON-NLS-1$
icons.put("helipad", R.drawable.h_helipad); //$NON-NLS-1$
icons.put("hospital", R.drawable.h_hospital); //$NON-NLS-1$
icons.put("hostel", R.drawable.h_hostel); //$NON-NLS-1$
icons.put("hotel", R.drawable.h_hotel); //$NON-NLS-1$
icons.put("ice_cream", R.drawable.g_food_ice_cream); //$NON-NLS-1$
icons.put("information", R.drawable.h_information); //$NON-NLS-1$
icons.put("jewelry", R.drawable.g_shop_jewelry); //$NON-NLS-1$
icons.put("kiosk", R.drawable.g_shop_kiosk); //$NON-NLS-1$
icons.put("level_crossing", R.drawable.h_level_crossing); //$NON-NLS-1$
icons.put("level_crossing2", R.drawable.h_level_crossing2); //$NON-NLS-1$
icons.put("library", R.drawable.h_library); //$NON-NLS-1$
icons.put("liftgate", R.drawable.h_liftgate); //$NON-NLS-1$
icons.put("lighthouse", R.drawable.h_lighthouse); //$NON-NLS-1$
icons.put("lock_gate", R.drawable.h_lock_gate); //$NON-NLS-1$
icons.put("marketplace", R.drawable.g_amenity_marketplace); //$NON-NLS-1$
icons.put("marsh", R.drawable.h_marsh); //$NON-NLS-1$
icons.put("mast", R.drawable.h_mast); //$NON-NLS-1$
icons.put("memorial", R.drawable.h_memorial); //$NON-NLS-1$
icons.put("motel", R.drawable.h_motel); //$NON-NLS-1$
icons.put("mini_roundabout", R.drawable.h_mini_roundabout); //$NON-NLS-1$
icons.put("mud", R.drawable.h_mud); //$NON-NLS-1$
icons.put("museum", R.drawable.h_museum); //$NON-NLS-1$
icons.put("music", R.drawable.g_shop_music); //$NON-NLS-1$
icons.put("nr", R.drawable.h_nr); //$NON-NLS-1$
icons.put("optician", R.drawable.g_health_optician); //$NON-NLS-1$
icons.put("orchard", R.drawable.h_orchard); //$NON-NLS-1$
icons.put("parking", R.drawable.h_parking); //$NON-NLS-1$
icons.put("peak", R.drawable.h_peak); //$NON-NLS-1$
icons.put("shop_pet", R.drawable.g_shop_pet); //$NON-NLS-1$
icons.put("pharmacy", R.drawable.h_pharmacy); //$NON-NLS-1$
icons.put("picnic_site", R.drawable.h_picnic_site); //$NON-NLS-1$
icons.put("place_of_worship", R.drawable.h_place_of_worship); //$NON-NLS-1$
icons.put("playground", R.drawable.h_playground); //$NON-NLS-1$
icons.put("police", R.drawable.h_police); //$NON-NLS-1$
icons.put("postbox", R.drawable.h_postbox); //$NON-NLS-1$
icons.put("postoffice", R.drawable.h_postoffice); //$NON-NLS-1$
icons.put("power_tower", R.drawable.h_power_tower); //$NON-NLS-1$
icons.put("power_wind", R.drawable.h_power_wind); //$NON-NLS-1$
icons.put("prison", R.drawable.h_prison); //$NON-NLS-1$
icons.put("pub", R.drawable.h_pub); //$NON-NLS-1$
icons.put("quarry2", R.drawable.h_quarry2); //$NON-NLS-1$
icons.put("recycling", R.drawable.h_recycling); //$NON-NLS-1$
icons.put("restaurant", R.drawable.h_restaurant); //$NON-NLS-1$
icons.put("school", R.drawable.h_school); //$NON-NLS-1$
icons.put("scrub", R.drawable.h_scrub); //$NON-NLS-1$
icons.put("shelter", R.drawable.h_shelter); //$NON-NLS-1$
icons.put("shop_bakery", R.drawable.h_shop_bakery); //$NON-NLS-1$
icons.put("shop_butcher", R.drawable.h_shop_butcher); //$NON-NLS-1$
icons.put("shop_clothes", R.drawable.h_shop_clothes); //$NON-NLS-1$
icons.put("shop_convenience", R.drawable.h_shop_convenience); //$NON-NLS-1$
icons.put("shop_diy", R.drawable.h_shop_diy); //$NON-NLS-1$
icons.put("shop_bicycle", R.drawable.h_shop_bicycle); //$NON-NLS-1$
icons.put("shop_car", R.drawable.h_shop_car); //$NON-NLS-1$
icons.put("shop_car_repair", R.drawable.h_shop_car_repair); //$NON-NLS-1$
icons.put("shop_hairdresser", R.drawable.h_shop_hairdresser); //$NON-NLS-1$
icons.put("shop_supermarket", R.drawable.h_shop_supermarket); //$NON-NLS-1$
icons.put("slipway", R.drawable.h_slipway); //$NON-NLS-1$
icons.put("sports_centre", R.drawable.g_leisure_sports_centre); //$NON-NLS-1$
icons.put("spring", R.drawable.h_spring); //$NON-NLS-1$
icons.put("station_small", R.drawable.h_station_small); //$NON-NLS-1$
icons.put("station", R.drawable.h_station); //$NON-NLS-1$
icons.put("subway_entrance", R.drawable.h_subway_entrance); //$NON-NLS-1$
icons.put("taxi", R.drawable.g_transport_taxi); //$NON-NLS-1$
icons.put("telephone", R.drawable.h_telephone); //$NON-NLS-1$
icons.put("theatre", R.drawable.h_theatre); //$NON-NLS-1$
icons.put("toilets", R.drawable.h_toilets); //$NON-NLS-1$
icons.put("toys", R.drawable.g_shop_toys); //$NON-NLS-1$
icons.put("traffic_light", R.drawable.h_traffic_light); //$NON-NLS-1$
icons.put("highway_ford", R.drawable.h_highway_ford); //$NON-NLS-1$
icons.put("tree", R.drawable.h_tree); //$NON-NLS-1$
icons.put("tree2", R.drawable.h_tree2); //$NON-NLS-1$
icons.put("university", R.drawable.g_amenity_university); //$NON-NLS-1$
icons.put("vending_machine", R.drawable.g_amenity_vending_machine); //$NON-NLS-1$
icons.put("viewpoint", R.drawable.h_viewpoint); //$NON-NLS-1$
icons.put("vineyard", R.drawable.h_vineyard); //$NON-NLS-1$
icons.put("volcano", R.drawable.h_volcano); //$NON-NLS-1$
icons.put("water_tower", R.drawable.h_water_tower); //$NON-NLS-1$
icons.put("windmill", R.drawable.h_windmill); //$NON-NLS-1$
icons.put("zoo", R.drawable.h_zoo); //$NON-NLS-1$
icons.put("mot_shield1", R.drawable.mot_shield1); //$NON-NLS-1$
icons.put("mot_shield2", R.drawable.mot_shield2); //$NON-NLS-1$
icons.put("mot_shield3", R.drawable.mot_shield3); //$NON-NLS-1$
icons.put("mot_shield4", R.drawable.mot_shield4); //$NON-NLS-1$
icons.put("mot_shield5", R.drawable.mot_shield5); //$NON-NLS-1$
icons.put("mot_shield6", R.drawable.mot_shield6); //$NON-NLS-1$
icons.put("mot_shield7", R.drawable.mot_shield7); //$NON-NLS-1$
icons.put("mot_shield8", R.drawable.mot_shield8); //$NON-NLS-1$
icons.put("pri_shield1", R.drawable.pri_shield1); //$NON-NLS-1$
icons.put("pri_shield2", R.drawable.pri_shield2); //$NON-NLS-1$
icons.put("pri_shield3", R.drawable.pri_shield3); //$NON-NLS-1$
icons.put("pri_shield4", R.drawable.pri_shield4); //$NON-NLS-1$
icons.put("pri_shield5", R.drawable.pri_shield5); //$NON-NLS-1$
icons.put("pri_shield6", R.drawable.pri_shield6); //$NON-NLS-1$
icons.put("pri_shield7", R.drawable.pri_shield7); //$NON-NLS-1$
icons.put("pri_shield8", R.drawable.pri_shield8); //$NON-NLS-1$
icons.put("sec_shield1", R.drawable.sec_shield1); //$NON-NLS-1$
icons.put("sec_shield2", R.drawable.sec_shield2); //$NON-NLS-1$
icons.put("sec_shield3", R.drawable.sec_shield3); //$NON-NLS-1$
icons.put("sec_shield4", R.drawable.sec_shield4); //$NON-NLS-1$
icons.put("sec_shield5", R.drawable.sec_shield5); //$NON-NLS-1$
icons.put("sec_shield6", R.drawable.sec_shield6); //$NON-NLS-1$
icons.put("sec_shield7", R.drawable.sec_shield7); //$NON-NLS-1$
icons.put("sec_shield8", R.drawable.sec_shield8); //$NON-NLS-1$
icons.put("ter_shield1", R.drawable.ter_shield1); //$NON-NLS-1$
icons.put("ter_shield2", R.drawable.ter_shield2); //$NON-NLS-1$
icons.put("ter_shield3", R.drawable.ter_shield3); //$NON-NLS-1$
icons.put("ter_shield4", R.drawable.ter_shield4); //$NON-NLS-1$
icons.put("ter_shield5", R.drawable.ter_shield5); //$NON-NLS-1$
icons.put("ter_shield6", R.drawable.ter_shield6); //$NON-NLS-1$
icons.put("ter_shield7", R.drawable.ter_shield7); //$NON-NLS-1$
icons.put("ter_shield8", R.drawable.ter_shield8); //$NON-NLS-1$
icons.put("tru_shield1", R.drawable.tru_shield1); //$NON-NLS-1$
icons.put("tru_shield2", R.drawable.tru_shield2); //$NON-NLS-1$
icons.put("tru_shield3", R.drawable.tru_shield3); //$NON-NLS-1$
icons.put("tru_shield4", R.drawable.tru_shield4); //$NON-NLS-1$
icons.put("tru_shield5", R.drawable.tru_shield5); //$NON-NLS-1$
icons.put("tru_shield6", R.drawable.tru_shield6); //$NON-NLS-1$
icons.put("tru_shield7", R.drawable.tru_shield7); //$NON-NLS-1$
icons.put("tru_shield8", R.drawable.tru_shield8); //$NON-NLS-1$
}
Class<? extends drawable> cl = R.drawable.class;
for (Field f : cl.getDeclaredFields()) {
if (f.getName().startsWith("h_") || f.getName().startsWith("g_")) {
try {
icons.put(f.getName().substring(2), f.getInt(null));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
} }

14
config/basemap/README Normal file
View file

@ -0,0 +1,14 @@
1. Find and install perl Geo-ShapeFile-2.52
cd Geo-ShapeFile-2.52/
sudo perl Makefile.PL
make
make test
2. Locate and run shp2osm.pl.
Example (replacing tags): perl ./shp2osm.pl 10m-coastline/10m_coastline.shp | sed 's/FeatureCla/natural/g;s/Coastline/coastline/g' > 10m_coastline.osm
3. Fix manually all 180 degrees breaks (simply divide islands into 2 islands and add connect line on 180 degree) and make Antarctica cycled.
4. Run net.osmand.osm.util.FixLinkedCoastline from DataExtractionosm.jar with arg0=filename.
5. !Fix manually Caspey Sea !
6. ! Check 2 ShriLanka islands (2 coastlines on one place)
6. ! Check North America for bug!
7. Run Index Creator.

167
config/basemap/shp2osm.pl Executable file
View file

@ -0,0 +1,167 @@
# Copyright (c) 2006 Gabriel Ebner <ge@gabrielebner.at>
# updated in 2008 by Tobias Wendorff <tobias.wendorff@uni-dortmund.de>
# HTML-Entities based on ideas of Hermann Schwärzler
# Gauß-Krüger implementation based on gauss.pl by Andreas Achtzehn
# version 1.3 (17. September 2008)
use Geo::ShapeFile;
use HTML::Entities qw(encode_entities_numeric);
use Math::Trig;
if(@ARGV == 0) {
print "usage:\n";
print "with transformation from GK to WGS84: 'shp2osm.pl shapefile GK'\n";
print "without transformation: 'shp2osm.pl shapefile'";
exit;
}
print <<'END';
<?xml version='1.0'?>
<osm version='0.5' generator='shp2osm.pl'>
END
#BEGIN { our %default_tags = ( natural => 'water', source => 'SWDB' ); }
BEGIN { our %default_tags = ( ); }
my $file = @ARGV[0];
$file =~ s/\.shp$//;
my $shpf = Geo::ShapeFile->new($file);
proc_shpf($shpf);
{
BEGIN { our $i = -1; }
sub tags_out {
my ($tags) = @_;
my %tags = $tags ? %$tags : ();
#$tags{'created_by'} ||= 'shp2osm.pl';
delete $tags{'_deleted'} unless $tags{'_deleted'};
while ( my ( $k, $v ) = each %tags ) {
my $key = encode_entities_numeric($k);
my $val = encode_entities_numeric($v);
print ' <tag k="'. $key .'" v="'. $val ."\"/>\n" if $val;
}
}
sub node_out {
my ( $lon, $lat, $tags ) = @_;
my $id = $i--;
if(@ARGV[1] eq 'GK') {
my ($wgs84lon, $wgs84lat) = gk2geo($lon, $lat);
print " <node id='$id' visible='true' lat='$wgs84lat' lon='$wgs84lon' />\n";
} else {
print " <node id='$id' visible='true' lat='$lat' lon='$lon' />\n";
}
$id;
}
sub seg_out {
my $id = $i+1;
$id;
}
sub way_out {
my ( $segs, $tags ) = @_;
my $id = $i--;
print " <way id='$id' visible='true'>\n";
print " <nd ref='$_' />\n" for @$segs;
tags_out $tags;
print " </way>\n";
$id;
}
}
print <<'END';
</osm>
END
sub polyline_out {
my ( $pts, $tags, $connect_last_seg ) = @_;
my ( $first_node, $last_node, @segs );
for my $pt (@$pts) {
my $node = node_out @$pt;
push @segs, seg_out $last_node, $node;
$last_node = $node;
$first_node ||= $last_node;
}
push @segs, seg_out $last_node, $first_node
if $first_node && $connect_last_seg;
way_out \@segs, $tags;
}
sub proc_obj {
my ( $shp, $dbf, $type ) = @_;
my $tags = { %default_tags, %$dbf };
my $is_polygon = $type % 10 == 5;
for ( 1 .. $shp->num_parts ) {
polyline_out [ map( [ $_->X(), $_->Y() ], $shp->get_part($_) ) ], $tags,
$is_polygon;
}
}
sub proc_shpf {
my ($shpf) = @_;
my $type = $shpf->shape_type;
for ( 1 .. $shpf->shapes() ) {
my $shp = $shpf->get_shp_record($_);
my %dbf = $shpf->get_dbf_record($_);
proc_obj $shp, \%dbf, $type;
}
}
sub gk2geo {
my $sr = $_[0];
my $sx = $_[1];
my $bm = int($sr/1000000);
my $y = $sr-($bm*1000000+500000);
my $si = $sx/111120.6196;
my $px = $si+0.143885358*sin(2*$si*0.017453292)+0.00021079*sin(4*$si*0.017453292)+0.000000423*sin(6*$si*0.017453292);
my $t = (sin($px*0.017453292))/(cos($px*0.017453292));
my $v = sqrt(1+0.006719219*cos($px*0.017453292)*cos($px*0.017453292));
my $ys = ($y*$v)/6398786.85;
my $lat = $px-$ys*$ys*57.29577*$t*$v*$v*(0.5-$ys*$ys*(4.97-3*$t*$t)/24);
my $dl = $ys*57.29577/cos($px*0.017453292) * (1-$ys*$ys/6*($v*$v+2*$t*$t-$ys*$ys*(0.6+1.1*$t*$t)*(0.6+1.1*$t*$t)));
my $lon = $bm*3+$dl;
my $potsd_a = 6377397.155;
my $wgs84_a = 6378137.0;
my $potsd_f = 1/299.152812838;
my $wgs84_f = 1/298.257223563;
my $potsd_es = 2*$potsd_f - $potsd_f*$potsd_f;
my $potsd_dx = 606.0;
my $potsd_dy = 23.0;
my $potsd_dz = 413.0;
my $pi = 3.141592654;
my $latr = $lat/180*$pi;
my $lonr = $lon/180*$pi;
my $sa = sin($latr);
my $ca = cos($latr);
my $so = sin($lonr);
my $co = cos($lonr);
my $bda = 1-$potsd_f;
my $delta_a = $wgs84_a - $potsd_a;
my $delta_f = $wgs84_f - $potsd_f;
my $rn = $potsd_a / sqrt(1-$potsd_es*sin($latr)*sin($latr));
my $rm = $potsd_a * ((1-$potsd_es)/sqrt(1-$potsd_es*sin($latr)*sin($latr)*1-$potsd_es*sin($latr)*sin($latr)*1-$potsd_es*sin($latr)*sin($latr)));
my $ta = (-$potsd_dx*$sa*$co - $potsd_dy*$sa*$so)+$potsd_dz*$ca;
my $tb = $delta_a*(($rn*$potsd_es*$sa*$ca)/$potsd_a);
my $tc = $delta_f*($rm/$bda+$rn*$bda)*$sa*$ca;
my $dlat = ($ta+$tb+$tc)/$rm;
my $dlon = (-$potsd_dx*$so + $potsd_dy*$co)/($rn*$ca);
my $wgs84lat = ($latr + $dlat)*180/$pi;
my $wgs84lon = ($lonr + $dlon)*180/$pi;
return( $wgs84lon, $wgs84lat);
}