add basic implementation for normalizing street

git-svn-id: https://osmand.googlecode.com/svn/trunk@67 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
Victor Shcherb 2010-05-18 13:36:42 +00:00
parent 31a56b670a
commit 79c03f09b4
14 changed files with 293 additions and 56 deletions

View file

@ -38,6 +38,18 @@ public class Algoritms {
}
}
public static int extractFirstIntegerNumber(String s) {
int i = 0;
for (int k = 0; k < s.length(); k++) {
if (Character.isDigit(s.charAt(k))) {
i = i * 10 + (s.charAt(k) - '0');
} else {
break;
}
}
return i;
}
public static void streamCopy(InputStream in, OutputStream out) throws IOException{
byte[] b = new byte[BUFFER_SIZE];

View file

@ -23,5 +23,6 @@ public interface IProgress {
public boolean isIndeterminate();
public boolean isInterrupted();
}

View file

@ -36,7 +36,7 @@ public class ToDoConstants {
// 10. Specify auto-rotating map (compass).
// 11. Print out additional info speed, altitude, number of satellites
// 12. Show point where are you going (the arrow not the point)
// 13. Save point as favourite
// 13. Save point as favourit
// 14. Show zoom level directly on map
// -------------------
@ -48,7 +48,6 @@ public class ToDoConstants {
/// SWING version :
// TODO :
// 1. Add preferences dialog (use internet, )
// 2. implement bundle downloading tiles ()
// 3. download tiles without using dir tiles
// 4. Config file log & see log from file
// 6. Predefine before file loading what should be extracted from osm (building, poi or roads)

View file

@ -86,23 +86,16 @@ public class Amenity extends MapObject<Node> {
}
private final Node node;
private String subType;
private AmenityType type;
public Amenity(Node node){
this.node = node;
this.entity = node;
this.type = getType(node);
this.subType = getSubType(node);
}
public Amenity(){
this.node = null;
}
@Override
public Node getEntity() {
return node;
}
protected String getSubType(Node node){
@ -148,6 +141,7 @@ public class Amenity extends MapObject<Node> {
}
public static boolean isAmenity(Entity n){
// TODO allow ways to be amenity!
if(!(n instanceof Node)){
return false;
}
@ -165,9 +159,8 @@ public class Amenity extends MapObject<Node> {
public String getSimpleFormat(){
String name = getName();
return Algoritms.capitalizeFirstLetterAndLowercase(getType().toString()) +
" : " + getSubType() + " " +(name == null ? node.getId() : name);
" : " + getSubType() + " " +getName();
}
public String getStringWithoutType(){

View file

@ -12,7 +12,8 @@ import com.osmand.osm.OSMSettings.OSMTagKey;
public class City extends MapObject<Node> {
public enum CityType {
CITY(10000), TOWN(5000), VILLAGE(1000), HAMLET(300), SUBURB(300);
// that's tricky way to play with that numbers (to avoid including suburbs in city & vice verse)
CITY(10000), TOWN(5000), VILLAGE(1300), HAMLET(1000), SUBURB(300);
private double radius;
@ -42,6 +43,7 @@ public class City extends MapObject<Node> {
}
private CityType type = null;
// Be attentive ! Working with street names ignoring case
private Map<String, Street> streets = new TreeMap<String, Street>();
public City(Node el){
@ -53,16 +55,30 @@ public class City extends MapObject<Node> {
this.type = type;
}
public Street registerStreet(String street){
if(!streets.containsKey(street)){
streets.put(street, new Street(street));
if(!streets.containsKey(street.toLowerCase())){
streets.put(street.toLowerCase(), new Street(this, street));
}
return streets.get(street);
return streets.get(street.toLowerCase());
}
public Street unregisterStreet(String name){
return streets.remove(name.toLowerCase());
}
public Street registerStreet(Street street){
if(!Algoritms.isEmpty(street.getName())){
return streets.put(street.getName(), street);
String name = street.getName().toLowerCase();
if(!Algoritms.isEmpty(name)){
if(!streets.containsKey(name)){
return streets.put(name, street);
} else {
// try to merge streets
Street prev = streets.get(name);
prev.getWayNodes().addAll(street.getWayNodes());
prev.getBuildings().addAll(street.getBuildings());
return prev;
}
}
return null;
}
@ -72,12 +88,11 @@ public class City extends MapObject<Node> {
String street = e.getTag(OSMTagKey.ADDR_STREET);
if( street != null && number != null){
registerStreet(street).registerBuilding(e);
return streets.get(street);
return streets.get(street.toLowerCase());
}
return null;
}
public CityType getType(){
return type;
}
@ -86,6 +101,10 @@ public class City extends MapObject<Node> {
return streets.values();
}
public Street getStreet(String name){
return streets.get(name.toLowerCase());
}
@Override
public String toString() {
return "City [" +type+"] " + getName();

View file

@ -120,8 +120,10 @@ public class Region extends MapObject<Entity> {
public void registerAmenity(Amenity a){
LatLon location = a.getLocation();
if(location != null){
amenities.registerObject(location.getLatitude(), location.getLongitude(), a);
}
}
public void registerCity(City city){
if(city.getType() != null && !Algoritms.isEmpty(city.getName()) && city.getLocation() != null){

View file

@ -2,24 +2,31 @@ package com.osmand.data;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.osmand.Algoritms;
import com.osmand.osm.Entity;
import com.osmand.osm.LatLon;
import com.osmand.osm.MapUtils;
import com.osmand.osm.Node;
import com.osmand.osm.Way;
import com.osmand.osm.OSMSettings.OSMTagKey;
public class Street extends MapObject<Entity> {
private List<Building> buildings = new ArrayList<Building>();
private List<Node> wayNodes = new ArrayList<Node>();
private List<Way> wayNodes = new ArrayList<Way>();
private final City city;
public Street(String name){
public Street(City city, String name){
this.city = city;
this.name = name;
}
public Street(){}
public Street(City city) {
this.city = city;
}
public void registerBuilding(Entity e){
Building building = new Building(e);
@ -47,9 +54,14 @@ public class Street extends MapObject<Entity> {
entity = wayNodes.get(0);
return;
}
LatLon c = MapUtils.getWeightCenterForNodes(wayNodes);
List<Node> nodes = new ArrayList<Node>();
for(Way w : wayNodes){
nodes.addAll(w.getNodes());
}
LatLon c = MapUtils.getWeightCenterForNodes(nodes);
double dist = Double.POSITIVE_INFINITY;
for(Node n : wayNodes){
for(Node n : nodes){
if (n != null) {
double nd = MapUtils.getDistance(n, c);
if (nd < dist) {
@ -60,14 +72,34 @@ public class Street extends MapObject<Entity> {
}
}
@Override
public void setName(String name) {
if(name.equals(getName())){
return;
}
Street unregisterStreet = city.unregisterStreet(getName());
assert unregisterStreet == this;
super.setName(name);
city.registerStreet(this);
}
public List<Node> getWayNodes() {
public List<Way> getWayNodes() {
return wayNodes;
}
public void doDataPreparation() {
calculateCenter();
Collections.sort(buildings);
Collections.sort(buildings, new Comparator<Building>(){
@Override
public int compare(Building o1, Building o2) {
int i1 = Algoritms.extractFirstIntegerNumber(o1.getName());
int i2 = Algoritms.extractFirstIntegerNumber(o2.getName());
return i1 - i2;
}
});
}
}

View file

@ -35,8 +35,8 @@ import com.osmand.osm.OSMSettings;
import com.osmand.osm.Way;
import com.osmand.osm.OSMSettings.OSMTagKey;
import com.osmand.osm.io.IOsmStorageFilter;
import com.osmand.osm.io.OsmStorageWriter;
import com.osmand.osm.io.OsmBaseStorage;
import com.osmand.osm.io.OsmStorageWriter;
// TO implement
@ -210,6 +210,9 @@ public class DataExtraction {
// 5. reading buildings
readingBuildings(progress, buildings, country);
// 6. normalizing streets
normalizingStreets(progress, country);
country.doDataPreparation();
return country;
}
@ -262,9 +265,7 @@ public class DataExtraction {
if (city != null) {
Street str = city.registerStreet(street);
for (Node n : w.getNodes()) {
str.getWayNodes().add(n);
}
str.getWayNodes().add(w);
}
waysManager.registerObject(center.getLatitude(), center.getLongitude(), w);
}
@ -291,5 +292,87 @@ public class DataExtraction {
country.registerCity(s);
}
}
String[] SUFFIXES = new String[] {"просп.", "пер.", "пр.","заул.", "проспект", "переул.", "бул.", "бульвар"};
String[] DEFAUTL_SUFFIXES = new String[] {"улица", "ул."};
private int checkSuffix(String name, String suffix){
int i = -1;
boolean searchAgain = false;
do {
i = name.indexOf(suffix, i);
searchAgain = false;
if (i > 0) {
if (Character.isLetterOrDigit(name.charAt(i -1))) {
i ++;
searchAgain = true;
}
}
} while (searchAgain);
return i;
}
private String cutSuffix(String name, int ind, int suffixLength){
String newName = name.substring(0, ind);
if (name.length() > ind + suffixLength + 1) {
newName += name.substring(ind + suffixLength + 1);
}
return newName.trim();
}
private String putSuffixToEnd(String name, int ind, int suffixLength) {
if (name.length() <= ind + suffixLength) {
return name;
}
String newName;
if(ind > 0){
newName = name.substring(0, ind);
newName += name.substring(ind + suffixLength);
newName += name.substring(ind - 1, ind + suffixLength );
} else {
newName = name.substring(suffixLength + 1) + name.charAt(suffixLength) + name.substring(0, suffixLength);
}
return newName.trim();
}
public void normalizingStreets(IProgress progress, Region region){
progress.startTask("Normalizing name streets...", -1);
for(CityType t : CityType.values()){
for(City c : region.getCitiesByType(t)){
ArrayList<Street> list = new ArrayList<Street>(c.getStreets());
for (Street s : list) {
String name = s.getName();
String newName = name.trim();
boolean processed = newName.length() != name.length();
for (String ch : DEFAUTL_SUFFIXES) {
int ind = checkSuffix(newName, ch);
if (ind != -1) {
newName = cutSuffix(newName, ind, ch.length());
processed = true;
break;
}
}
if (!processed) {
for (String ch : SUFFIXES) {
int ind = checkSuffix(newName, ch);
if (ind != -1) {
newName = putSuffixToEnd(newName, ind, ch.length());
processed = true;
break;
}
}
}
if (processed) {
if(c.getStreet(name) != s){
System.out.println(name);
}
s.setName(newName);
}
}
}
}
}
}

View file

@ -69,4 +69,9 @@ public class ConsoleProgressImplementation implements IProgress {
this.lastPercentPrint = 0;
}
@Override
public boolean isInterrupted() {
return false;
}
}

View file

@ -83,7 +83,7 @@ public class OsmIndexStorage extends OsmBaseStorage {
currentParsedCity = c;
} else if(ELEM_STREET.equals(name)){
assert currentParsedCity != null;
Street street = new Street();
Street street = new Street(currentParsedCity);
parseMapObject(street, attributes);
currentParsedCity.registerStreet(street);
currentParsedStreet = street;

View file

@ -18,6 +18,9 @@ import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
@ -54,8 +57,11 @@ import com.osmand.data.preparation.MapTileDownloader.IMapDownloaderCallback;
import com.osmand.map.ITileSource;
import com.osmand.map.TileSourceManager;
import com.osmand.map.TileSourceManager.TileSourceTemplate;
import com.osmand.osm.Entity;
import com.osmand.osm.LatLon;
import com.osmand.osm.MapUtils;
import com.osmand.osm.Node;
import com.osmand.osm.Way;
public class MapPanel extends JPanel implements IMapDownloaderCallback {
@ -130,7 +136,7 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
// special points to draw
private DataTileManager<LatLon> points;
private DataTileManager<? extends Entity> points;
// zoom level
private int zoom = 1;
@ -152,6 +158,7 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
private int xStartingImage = 0;
private int yStartingImage = 0;
private List<Point> pointsToDraw = new ArrayList<Point>();
private List<Line2D> linesToDraw = new ArrayList<Line2D>();
private MapTileDownloader downloader = MapTileDownloader.getInstance();
Map<String, Image> cache = new HashMap<String, Image>();
@ -235,6 +242,30 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
g.fillOval(p.x, p.y, 3, 3);
}
g.setColor(Color.orange);
// draw user points
int[] xPoints = new int[4];
int[] yPoints = new int[4];
for (Line2D p : linesToDraw) {
AffineTransform transform = new AffineTransform();
transform.translate(p.getX1(), p.getY1());
// transform.scale(p.getX2() - p.getX1(), p.getY2() - p.getY1());
transform.rotate(p.getX2() - p.getX1(), p.getY2() - p.getY1());
xPoints[1] = xPoints[0] = 0;
xPoints[2] = xPoints[3] = (int) Math.sqrt((p.getX2() - p.getX1())*(p.getX2() - p.getX1()) +
(p.getY2() - p.getY1())*(p.getY2() - p.getY1())) +1;
yPoints[3] = yPoints[0] = 0;
yPoints[2] = yPoints[1] = 2;
for(int i=0; i< 4; i++){
Point2D po = transform.transform(new Point(xPoints[i], yPoints[i]), null);
xPoints[i] = (int) po.getX();
yPoints[i] = (int) po.getY();
}
g.drawPolygon(xPoints, yPoints, 4);
g.fillPolygon(xPoints, yPoints, 4);
}
if(selectionArea.isVisible()){
g.setColor(new Color(0, 0, 230, 50));
Rectangle r = selectionArea.getSelectedArea();
@ -374,14 +405,36 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
double longDown = MapUtils.getLongitudeFromTile(zoom, xTileRight);
double latUp = MapUtils.getLatitudeFromTile(zoom, yTileUp);
double longUp = MapUtils.getLongitudeFromTile(zoom, xTileLeft);
List<LatLon> objects = points.getObjects(latUp, longUp, latDown, longDown);
List<? extends Entity> objects = points.getObjects(latUp, longUp, latDown, longDown);
pointsToDraw.clear();
for (LatLon n : objects) {
linesToDraw.clear();
for (Entity e : objects) {
if(e instanceof Way){
List<Node> nodes = ((Way)e).getNodes();
if (nodes.size() > 1) {
int prevPixX = 0;
int prevPixY = 0;
for (int i = 0; i < nodes.size(); i++) {
Node n = nodes.get(i);
int pixX = MapUtils.getPixelShiftX(zoom, n.getLongitude(), this.longitude, tileSize) + getWidth() / 2;
int pixY = MapUtils.getPixelShiftY(zoom, n.getLatitude(), this.latitude, tileSize) + getHeight() / 2;
if (i > 0) {
linesToDraw.add(new Line2D.Float(pixX, pixY, prevPixX, prevPixY));
}
prevPixX = pixX;
prevPixY = pixY;
}
}
} else if(e instanceof Node){
Node n = (Node) e;
int pixX = MapUtils.getPixelShiftX(zoom, n.getLongitude(), this.longitude, tileSize) + getWidth() / 2;
int pixY = MapUtils.getPixelShiftY(zoom, n.getLatitude(), this.latitude, tileSize) + getHeight() / 2;
if (pixX >= 0 && pixY >= 0) {
pointsToDraw.add(new Point(pixX, pixY));
}
} else {
}
}
}
@ -504,11 +557,11 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
super.processKeyEvent(e);
}
public DataTileManager<LatLon> getPoints() {
public DataTileManager<? extends Entity> getPoints() {
return points;
}
public void setPoints(DataTileManager<LatLon> points) {
public void setPoints(DataTileManager<? extends Entity> points) {
this.points = points;
prepareImage();
}

View file

@ -68,6 +68,7 @@ import com.osmand.IMapLocationListener;
import com.osmand.data.Amenity;
import com.osmand.data.Building;
import com.osmand.data.City;
import com.osmand.data.DataTileManager;
import com.osmand.data.MapObject;
import com.osmand.data.Region;
import com.osmand.data.Street;
@ -79,6 +80,7 @@ import com.osmand.osm.Entity;
import com.osmand.osm.LatLon;
import com.osmand.osm.MapUtils;
import com.osmand.osm.Node;
import com.osmand.osm.Way;
import com.osmand.osm.io.IOsmStorageFilter;
import com.osmand.osm.io.OsmStorageWriter;
import com.osmand.osm.io.OsmBoundsFilter;
@ -109,11 +111,13 @@ public class OsmExtractionUI implements IMapLocationListener {
private JButton generateDataButton;
private JCheckBox buildPoiIndex;
private JCheckBox buildAddressIndex;
private JCheckBox normalizingStreets;
private TreeModelListener treeModelListener;
private JCheckBox zipIndexFiles;
public OsmExtractionUI(final Region r){
this.region = r;
createUI();
@ -127,6 +131,7 @@ public class OsmExtractionUI implements IMapLocationListener {
}
this.region = region;
DefaultMutableTreeNode root = new DataExtractionTreeNode(name, region);
if (region != null) {
amenitiesTree = new DataExtractionTreeNode("Closest amenities", region);
amenitiesTree.add(new DataExtractionTreeNode("First 15", region));
for (AmenityType type : AmenityType.values()) {
@ -134,7 +139,6 @@ public class OsmExtractionUI implements IMapLocationListener {
}
root.add(amenitiesTree);
if (region != null) {
for (CityType t : CityType.values()) {
DefaultMutableTreeNode cityTree = new DataExtractionTreeNode(Algoritms.capitalizeFirstLetterAndLowercase(t.toString()), t);
root.add(cityTree);
@ -169,7 +173,9 @@ public class OsmExtractionUI implements IMapLocationListener {
DefaultTreeModel newModel = new DefaultTreeModel(root, false);
newModel.addTreeModelListener(treeModelListener);
treePlaces.setModel(newModel);
updateButtonsBar();
locationChanged(mapPanel.getLatitude(), mapPanel.getLongitude(), this);
}
@ -237,6 +243,15 @@ public class OsmExtractionUI implements IMapLocationListener {
MapObject<Entity> c = (MapObject<Entity>) o;
LatLon location = c.getLocation();
if(location != null){
if(o instanceof Street){
DataTileManager<Way> ways = new DataTileManager<Way>();
for(Way w : ((Street)o).getWayNodes()){
LatLon l = w.getLatLon();
ways.registerObject(l.getLatitude(), l.getLongitude(), w);
}
mapPanel.setPoints(ways);
mapPanel.requestFocus();
}
mapPanel.setLatLon(location.getLatitude(), location.getLongitude());
mapPanel.requestFocus();
}
@ -283,9 +298,10 @@ public class OsmExtractionUI implements IMapLocationListener {
protected void updateButtonsBar() {
generateDataButton.setEnabled(region != null);
buildAddressIndex.setEnabled(generateDataButton.isEnabled() && region.getCitiesCount(null) > 0);
buildPoiIndex.setEnabled(generateDataButton.isEnabled() && !region.getAmenityManager().isEmpty());
zipIndexFiles.setEnabled(generateDataButton.isEnabled());
normalizingStreets.setVisible(region == null);
buildAddressIndex.setEnabled(region == null || region.getCitiesCount(null) > 0);
buildPoiIndex.setEnabled(region == null || !region.getAmenityManager().isEmpty());
zipIndexFiles.setVisible(region != null);
}
public void createButtonsBar(Container content){
@ -297,9 +313,7 @@ public class OsmExtractionUI implements IMapLocationListener {
generateDataButton.setToolTipText("Data with selected preferences will be generated in working directory." +
" The index files will be named as region in tree. All existing data will be overwritten.");
panel.add(generateDataButton);
generateDataButton.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
generateData();
@ -316,6 +330,11 @@ public class OsmExtractionUI implements IMapLocationListener {
panel.add(buildAddressIndex);
buildAddressIndex.setSelected(true);
normalizingStreets = new JCheckBox();
normalizingStreets.setText("Normalizing streets");
panel.add(normalizingStreets);
normalizingStreets.setSelected(true);
zipIndexFiles = new JCheckBox();
zipIndexFiles.setText("Zip index files");
panel.add(zipIndexFiles);
@ -438,6 +457,8 @@ public class OsmExtractionUI implements IMapLocationListener {
menu.add(loadFile);
JMenuItem loadSpecifiedAreaFile = new JMenuItem("Load osm file for specifed area...");
menu.add(loadSpecifiedAreaFile);
JMenuItem closeCurrentFile = new JMenuItem("Close current file");
menu.add(closeCurrentFile);
menu.addSeparator();
JMenuItem saveOsmFile = new JMenuItem("Save data to osm file...");
menu.add(saveOsmFile);
@ -455,6 +476,15 @@ public class OsmExtractionUI implements IMapLocationListener {
frame.setVisible(false);
}
});
closeCurrentFile.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
setRegion(null, "Region");
frame.setTitle("OsmAnd Map Creator");
}
});
specifyWorkingDir.addActionListener(new ActionListener(){
@Override

View file

@ -39,6 +39,10 @@ public class ProgressDialog extends JDialog implements IProgress {
initDialog();
}
public boolean isInterrupted(){
return !isVisible();
}
public Object run() throws InvocationTargetException, InterruptedException {
result = null;
new WorkerThread().start();

View file

@ -81,6 +81,10 @@ public class ProgressDialogImplementation implements IProgress {
work = -1;
progress = 0;
}
@Override
public boolean isInterrupted() {
return false;
}