diff --git a/BatteryLifeLog/.classpath b/BatteryLifeLog/.classpath
new file mode 100644
index 0000000000..6e9239ff0d
--- /dev/null
+++ b/BatteryLifeLog/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/BatteryLifeLog/.project b/BatteryLifeLog/.project
new file mode 100644
index 0000000000..e28b3c592d
--- /dev/null
+++ b/BatteryLifeLog/.project
@@ -0,0 +1,33 @@
+
+
+ BatteryLifeLog
+
+
+
+
+
+ com.android.ide.eclipse.adt.ResourceManagerBuilder
+
+
+
+
+ com.android.ide.eclipse.adt.PreCompilerBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.android.ide.eclipse.adt.ApkBuilder
+
+
+
+
+
+ com.android.ide.eclipse.adt.AndroidNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/BatteryLifeLog/AndroidManifest.xml b/BatteryLifeLog/AndroidManifest.xml
new file mode 100644
index 0000000000..c2bb805fb5
--- /dev/null
+++ b/BatteryLifeLog/AndroidManifest.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BatteryLifeLog/default.properties b/BatteryLifeLog/default.properties
new file mode 100644
index 0000000000..a1ef8e9ff4
--- /dev/null
+++ b/BatteryLifeLog/default.properties
@@ -0,0 +1,13 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Indicates whether an apk should be generated for each density.
+split.density=false
+# Project target.
+target=android-3
diff --git a/BatteryLifeLog/gen/com/anvisics/battery/R.java b/BatteryLifeLog/gen/com/anvisics/battery/R.java
new file mode 100644
index 0000000000..b9b27c67fe
--- /dev/null
+++ b/BatteryLifeLog/gen/com/anvisics/battery/R.java
@@ -0,0 +1,42 @@
+/* AUTO-GENERATED FILE. DO NOT MODIFY.
+ *
+ * This class was automatically generated by the
+ * aapt tool from the resource data it found. It
+ * should not be modified by hand.
+ */
+
+package com.anvisics.battery;
+
+public final class R {
+ public static final class attr {
+ }
+ public static final class color {
+ public static final int background=0x7f050000;
+ }
+ public static final class drawable {
+ public static final int icon=0x7f020000;
+ }
+ public static final class id {
+ public static final int Button01=0x7f070001;
+ public static final int Button02=0x7f070002;
+ public static final int Clear=0x7f070005;
+ public static final int Exit=0x7f070004;
+ public static final int Export=0x7f070006;
+ public static final int GridView01=0x7f070003;
+ public static final int LinearLayout01=0x7f070000;
+ }
+ public static final class layout {
+ public static final int main=0x7f030000;
+ public static final int mytext=0x7f030001;
+ }
+ public static final class menu {
+ public static final int main_menu=0x7f060000;
+ }
+ public static final class string {
+ public static final int app_name=0x7f040001;
+ public static final int batter_name_service=0x7f040004;
+ public static final int hello=0x7f040000;
+ public static final int start_service=0x7f040002;
+ public static final int stop_service=0x7f040003;
+ }
+}
diff --git a/BatteryLifeLog/res/drawable/icon.png b/BatteryLifeLog/res/drawable/icon.png
new file mode 100644
index 0000000000..a07c69fa5a
Binary files /dev/null and b/BatteryLifeLog/res/drawable/icon.png differ
diff --git a/BatteryLifeLog/res/layout/main.xml b/BatteryLifeLog/res/layout/main.xml
new file mode 100644
index 0000000000..3155ab9952
--- /dev/null
+++ b/BatteryLifeLog/res/layout/main.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BatteryLifeLog/res/layout/mytext.xml b/BatteryLifeLog/res/layout/mytext.xml
new file mode 100644
index 0000000000..5ff9c5ede0
--- /dev/null
+++ b/BatteryLifeLog/res/layout/mytext.xml
@@ -0,0 +1,6 @@
+
+
+
diff --git a/BatteryLifeLog/res/menu/main_menu.xml b/BatteryLifeLog/res/menu/main_menu.xml
new file mode 100644
index 0000000000..991369eb0b
--- /dev/null
+++ b/BatteryLifeLog/res/menu/main_menu.xml
@@ -0,0 +1,8 @@
+
+
diff --git a/BatteryLifeLog/res/values/strings.xml b/BatteryLifeLog/res/values/strings.xml
new file mode 100644
index 0000000000..968c9b1137
--- /dev/null
+++ b/BatteryLifeLog/res/values/strings.xml
@@ -0,0 +1,9 @@
+
+
+ Hello World, BatteryViewActivity!
+ BatteryLifeLog
+Запустить сервис
+Остановить сервис
+#FFFFFF
+Batter Log service
+
diff --git a/BatteryLifeLog/src/com/anvisics/battery/BatteryLogService.java b/BatteryLifeLog/src/com/anvisics/battery/BatteryLogService.java
new file mode 100644
index 0000000000..f3a18b077b
--- /dev/null
+++ b/BatteryLifeLog/src/com/anvisics/battery/BatteryLogService.java
@@ -0,0 +1,158 @@
+package com.anvisics.battery;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.Binder;
+import android.os.IBinder;
+import android.text.format.DateFormat;
+
+public class BatteryLogService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return binder;
+ }
+
+
+ private BatteryLogBinder binder = new BatteryLogBinder();
+ private BatteryStatusReceiver batteryStatusReceiver;
+
+
+ public static class BatteryLogEntry {
+ private int batteryLevel;
+ private int batteryVoltage;
+ private long time;
+ private int plugged;
+ private int status;
+
+
+ public BatteryLogEntry(){
+ time = System.currentTimeMillis();
+ }
+
+ public int getPlugged() {
+ return plugged;
+ }
+ public void setPlugged(int plugged) {
+ this.plugged = plugged;
+ }
+ public int getStatus() {
+ return status;
+ }
+ public void setStatus(int status) {
+ this.status = status;
+ }
+ public int getBatteryLevel() {
+ return batteryLevel;
+ }
+ public void setBatteryLevel(int batteryLevel) {
+ this.batteryLevel = batteryLevel;
+ }
+ public int getBatteryVoltage() {
+ return batteryVoltage;
+ }
+ public void setBatteryVoltage(int batteryVoltage) {
+ this.batteryVoltage = batteryVoltage;
+ }
+ public long getTime() {
+ return time;
+ }
+
+ public boolean sameMeasurements(BatteryLogEntry e ){
+ return batteryLevel == e.batteryLevel &&
+ batteryVoltage == e.batteryVoltage &&
+ status == e.status &&
+ plugged == e.plugged;
+ }
+
+ public String getMessage(){
+ String statusS = "";
+ switch(status){
+ case BatteryManager.BATTERY_STATUS_CHARGING : statusS = "CHARGING";
+ case BatteryManager.BATTERY_STATUS_DISCHARGING: statusS = "DISCHARGING";
+ case BatteryManager.BATTERY_STATUS_FULL: statusS = "FULL";
+ case BatteryManager.BATTERY_STATUS_NOT_CHARGING: statusS = "NOT_CHARGING";
+ }
+ String pluggedS = "";
+ switch(plugged){
+ case BatteryManager.BATTERY_PLUGGED_AC: pluggedS = "PLUGGED_AC";
+ case BatteryManager.BATTERY_PLUGGED_USB: pluggedS = "PLUGGED_USB";
+ }
+ CharSequence timeS = DateFormat.format("MM/dd/yy k:mm",this.time);
+ return MessageFormat.format("{0} : battery ({1}), voltage ({2}), plugged ({3}), status ({4})",
+ timeS, batteryLevel, batteryVoltage, pluggedS, statusS);
+ }
+
+ @Override
+ public String toString() {
+ return getMessage();
+ }
+
+ }
+
+ public static class BatteryLogBinder extends Binder {
+
+ private List entries = new ArrayList();
+
+
+ public boolean addEntry(BatteryLogEntry e){
+ if(entries.isEmpty()){
+ entries.add(e);
+ return true;
+ }
+ BatteryLogEntry last = entries.get(entries.size() - 1);
+ if(!last.sameMeasurements(e) || e.getTime() - last.getTime() > 60000){
+ entries.add(e);
+ return true;
+ }
+ return false;
+ }
+
+
+ public void clearEntries(){
+ entries.clear();
+ }
+ public List getEntries() {
+ return entries;
+ }
+ }
+
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ batteryStatusReceiver = new BatteryStatusReceiver(this);
+ registerReceiver(batteryStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+
+ receiveMessage(100, 0, 0, 1);
+ }
+
+ public void receiveMessage(int voltage, int level, int plugged, int status){
+ BatteryLogEntry entry = new BatteryLogEntry();
+ entry.setBatteryVoltage(voltage);
+ entry.setBatteryLevel(level);
+ entry.setPlugged(plugged);
+ entry.setStatus(status);
+ binder.addEntry(entry);
+ }
+
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(batteryStatusReceiver);
+ }
+
+}
diff --git a/BatteryLifeLog/src/com/anvisics/battery/BatteryStatusReceiver.java b/BatteryLifeLog/src/com/anvisics/battery/BatteryStatusReceiver.java
new file mode 100644
index 0000000000..3015d5d96c
--- /dev/null
+++ b/BatteryLifeLog/src/com/anvisics/battery/BatteryStatusReceiver.java
@@ -0,0 +1,22 @@
+package com.anvisics.battery;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class BatteryStatusReceiver extends BroadcastReceiver {
+
+ private final BatteryLogService service;
+
+ public BatteryStatusReceiver(BatteryLogService service){
+ this.service = service;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ service.receiveMessage(intent.getIntExtra("voltage", -1), intent.getIntExtra("level", -1),
+ intent.getIntExtra("plugged", -1), intent.getIntExtra("status", -1));
+
+ }
+
+}
diff --git a/BatteryLifeLog/src/com/anvisics/battery/BatteryViewActivity.java b/BatteryLifeLog/src/com/anvisics/battery/BatteryViewActivity.java
new file mode 100644
index 0000000000..7dee2d865f
--- /dev/null
+++ b/BatteryLifeLog/src/com/anvisics/battery/BatteryViewActivity.java
@@ -0,0 +1,177 @@
+package com.anvisics.battery;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.List;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.GridView;
+
+import com.anvisics.battery.BatteryLogService.BatteryLogBinder;
+import com.anvisics.battery.BatteryLogService.BatteryLogEntry;
+
+public class BatteryViewActivity extends Activity {
+ private Button startServiceButton;
+ private Button stopServiceButton;
+ private GridView gridView;
+
+
+ private final Intent serviceIntent = new Intent("com.anvisics.BatteryLogService");
+
+ ServiceConnection serviceConnection = null;
+ private ArrayAdapter gridViewAdapter;
+ private BatteryLogBinder binder = null;
+
+ private class MyServiceConnection implements ServiceConnection {
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if(service instanceof BatteryLogBinder){
+ gridViewAdapter.clear();
+ binder = (BatteryLogBinder) service;
+ List entries = ((BatteryLogBinder) service).getEntries();
+ for(int i = entries.size() - 1; i>=0; i--){
+ gridViewAdapter.add(entries.get(i));
+ }
+ }
+ }
+
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ gridViewAdapter.clear();
+ binder = null;
+ }
+
+ };
+
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+
+
+ startServiceButton = (Button)findViewById(R.id.Button01);
+ stopServiceButton = (Button)findViewById(R.id.Button02);
+
+
+
+ gridView = (GridView) findViewById(R.id.GridView01);
+
+ gridView.setNumColumns(1);
+ gridView.setVerticalSpacing(3);
+ gridViewAdapter = new ArrayAdapter(getWindow().getContext(), R.layout.mytext);
+ gridView.setAdapter(gridViewAdapter);
+
+
+ startServiceButton.setOnClickListener(new OnClickListener(){
+ @Override
+ public void onClick(View v) {
+ ComponentName name = getWindow().getContext().startService(serviceIntent);
+ if(name != null){
+ stopServiceButton.setEnabled(true);
+ startServiceButton.setEnabled(false);
+ }
+ }
+ });
+
+ stopServiceButton.setOnClickListener(new OnClickListener(){
+ @Override
+ public void onClick(View v) {
+ boolean stopService = getWindow().getContext().stopService(serviceIntent);
+ if(stopService){
+ stopServiceButton.setEnabled(false);
+ startServiceButton.setEnabled(true);
+ }
+ }
+ });
+
+ ComponentName componentName = getWindow().getContext().startService(serviceIntent);
+ startServiceButton.setEnabled(componentName == null);
+ stopServiceButton.setEnabled(componentName != null);
+ serviceConnection = new MyServiceConnection();
+
+
+ getWindow().getContext().bindService(serviceIntent, serviceConnection, 0);
+
+ }
+
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.main_menu, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if(item.getItemId() == R.id.Clear){
+ if(binder != null){
+ binder.clearEntries();
+ gridViewAdapter.clear();
+ }
+ return true;
+ } else if (item.getItemId() == R.id.Export) {
+ if (binder == null) {
+ return true;
+ }
+ File directory = Environment.getExternalStorageDirectory();
+ if (directory.canWrite()) {
+ File f = new File(directory, "BatteryLog.txt");
+ int i = 1;
+ while (f.exists()) {
+ f = new File(directory, "BatteryLog" + (++i) + ".txt");
+ }
+
+ try {
+ BufferedWriter writer = new BufferedWriter(
+ new FileWriter(f));
+ List entries = binder.getEntries();
+ for (i = entries.size() - 1; i >= 0; i--) {
+ writer.write(entries.get(i).toString());
+ }
+ writer.close();
+ binder.clearEntries();
+ gridViewAdapter.clear();
+ } catch (IOException e) {
+ Log.e("batteryLog", "Can't export file", e);
+ }
+ }
+ } else if(item.getItemId() == R.id.Exit){
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+
+
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if(serviceConnection != null){
+ getWindow().getContext().unbindService(serviceConnection);
+ serviceConnection = null;
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/DataExtractionOSM/.classpath b/DataExtractionOSM/.classpath
new file mode 100644
index 0000000000..ca43d9b9db
--- /dev/null
+++ b/DataExtractionOSM/.classpath
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/DataExtractionOSM/.project b/DataExtractionOSM/.project
new file mode 100644
index 0000000000..b5b0d31f6a
--- /dev/null
+++ b/DataExtractionOSM/.project
@@ -0,0 +1,17 @@
+
+
+ DataExtractionOSM
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/DataExtractionOSM/lib/bzip2-20090327.jar b/DataExtractionOSM/lib/bzip2-20090327.jar
new file mode 100644
index 0000000000..7721279538
Binary files /dev/null and b/DataExtractionOSM/lib/bzip2-20090327.jar differ
diff --git a/DataExtractionOSM/lib/commons-logging-1.1.1.jar b/DataExtractionOSM/lib/commons-logging-1.1.1.jar
new file mode 100644
index 0000000000..1deef144cb
Binary files /dev/null and b/DataExtractionOSM/lib/commons-logging-1.1.1.jar differ
diff --git a/DataExtractionOSM/lib/jpf.jar b/DataExtractionOSM/lib/jpf.jar
new file mode 100644
index 0000000000..6d46124c5c
Binary files /dev/null and b/DataExtractionOSM/lib/jpf.jar differ
diff --git a/DataExtractionOSM/lib/osmosis-0.32.jar b/DataExtractionOSM/lib/osmosis-0.32.jar
new file mode 100644
index 0000000000..d4d05d1b72
Binary files /dev/null and b/DataExtractionOSM/lib/osmosis-0.32.jar differ
diff --git a/DataExtractionOSM/src/com/anvisics/Constants.java b/DataExtractionOSM/src/com/anvisics/Constants.java
new file mode 100644
index 0000000000..c908ba7be0
--- /dev/null
+++ b/DataExtractionOSM/src/com/anvisics/Constants.java
@@ -0,0 +1,10 @@
+package com.anvisics;
+
+public interface Constants {
+
+ // TODO externalize proper way
+ public String pathToTestDataDir = "E:\\Information\\gps\\OpenMap\\";
+
+ public String ADDR_HOUSE_NUMBER = "addr:housenumber";
+ public String ADDR_STREET = "addr:street";
+}
diff --git a/DataExtractionOSM/src/com/anvisics/DataExtraction.java b/DataExtractionOSM/src/com/anvisics/DataExtraction.java
new file mode 100644
index 0000000000..ead4249b6b
--- /dev/null
+++ b/DataExtractionOSM/src/com/anvisics/DataExtraction.java
@@ -0,0 +1,528 @@
+package com.anvisics;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTextField;
+import javax.swing.JTree;
+import javax.swing.UIManager;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.event.UndoableEditEvent;
+import javax.swing.event.UndoableEditListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.stream.XMLStreamException;
+
+import org.apache.tools.bzip2.CBZip2InputStream;
+import org.openstreetmap.osmosis.core.container.v0_6.EntityContainer;
+import org.openstreetmap.osmosis.core.container.v0_6.NodeContainer;
+import org.openstreetmap.osmosis.core.domain.v0_6.Entity;
+import org.openstreetmap.osmosis.core.domain.v0_6.Node;
+import org.openstreetmap.osmosis.core.domain.v0_6.Tag;
+import org.openstreetmap.osmosis.core.domain.v0_6.Way;
+import org.openstreetmap.osmosis.core.task.v0_6.Sink;
+import org.openstreetmap.osmosis.core.xml.v0_6.impl.OsmHandler;
+import org.xml.sax.SAXException;
+
+import com.anvisics.MapPanel.IMapLocationListener;
+import com.anvisics.NodeUtil.LatLon;
+import com.anvisics.data.City;
+import com.anvisics.data.Region;
+import com.anvisics.data.Street;
+import com.anvisics.data.City.CityType;
+
+
+// TO implement
+// 1. Full structured search for town/street/building.
+
+/**
+ * http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing#Is_inside.2Foutside
+ * http://wiki.openstreetmap.org/wiki/Relations/Proposed/Postal_Addresses
+ * http://wiki.openstreetmap.org/wiki/Proposed_features/House_numbers/Karlsruhe_Schema#Tags (node, way)
+ *
+ * 1. node - place : country, state, region, county, city, town, village, hamlet, suburb
+ * That node means label for place ! It is widely used in OSM.
+ *
+ * 2. way - highway : primary, secondary, service.
+ * That node means label for street if it is in city (primary, secondary, residential, tertiary, living_street),
+ * beware sometimes that roads could outside city. Usage : often
+ *
+ * outside city : trunk, motorway, motorway_link...
+ * special tags : lanes - 3, maxspeed - 90, bridge
+ *
+ * 3. relation - type = address. address:type : country, a1, a2, a3, a4, a5, a6, ... hno.
+ * member:node role=label :
+ * member:relation role=border :
+ * member:node role=a1,a2... :
+ *
+ * 4. node, way - addr:housenumber(+), addr:street(+), addr:country(+/-), addr:city(-)
+ * building=yes
+ *
+ * 5. relation - boundary=administrative, admin_level : 1, 2, ....
+ *
+ * 6. node, way - addr:postcode =?
+ * relation - type=postal_code (members way, node), postal_code=?
+ *
+ * 7. node, way - amenity=?
+ *
+ */
+public class DataExtraction implements IMapLocationListener {
+
+ public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException, XMLStreamException {
+ new DataExtraction().testReadingOsmFile();
+ }
+
+
+ private static boolean parseMinsk = true;
+ private static boolean parseOSM = true;
+
+ ///////////////////////////////////////////
+ // 1. Reading data - preparing data for UI
+ public void testReadingOsmFile() throws ParserConfigurationException, SAXException, IOException, XMLStreamException {
+
+ InputStream stream ;
+ if(parseMinsk){
+ stream = new FileInputStream(Constants.pathToTestDataDir+"minsk_old.osm");
+ } else {
+// stream = new FileInputStream(Constants.pathToTestDataDir+"belarus_2010_04_01.osm.bz2");
+// stream = new FileInputStream(Constants.pathToTestDataDir+"minsk_old.osm");
+ stream = new FileInputStream(Constants.pathToTestDataDir+"minsk_2010_04_26.osm.bz2");
+ if (stream.read() != 66 || stream.read() != 90)
+ throw new RuntimeException(
+ "The source stream must start with the characters BZ if it is to be read as a BZip2 stream.");
+ else
+ stream = new CBZip2InputStream(stream);
+ }
+
+
+ System.out.println("USED Memory " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())/1e6);
+ long st = System.currentTimeMillis();
+
+
+ // preloaded data
+ final List places = new ArrayList();
+ final Map nodes = new HashMap();
+ final List buildings = new ArrayList();
+ final List amenities = new ArrayList();
+
+
+ // highways count
+ final Map mapWays = new LinkedHashMap();
+
+ if (parseOSM) {
+ SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
+ parser.parse(stream, new OsmHandler(new Sink() {
+ @Override
+ public void process(EntityContainer entityContainer) {
+ if (entityContainer instanceof NodeContainer) {
+ NodeContainer rc = (NodeContainer) entityContainer;
+ if (NodeUtil.getTag(rc.getEntity(), "place") != null) {
+ places.add(rc.getEntity());
+ if (places.size() % 500 == 0) {
+ System.out.println();
+ }
+ System.out.print("-");
+ }
+ nodes.put(rc.getEntity().getId(), new LatLon(rc.getEntity().getLatitude(),
+ rc.getEntity().getLongitude()));
+ if (NodeUtil.getTag(entityContainer.getEntity(), "amenity") != null) {
+ amenities.add((Node) entityContainer.getEntity());
+ } else if (NodeUtil.getTag(entityContainer.getEntity(), "shop") != null) {
+ Entity n = entityContainer.getEntity();
+ n.getTags().add(new Tag("amenity", "shop"));
+ amenities.add((Node) n);
+ }
+
+
+ } else {
+ if (NodeUtil.tag(entityContainer.getEntity(), "building", "yes")) {
+ Entity e = entityContainer.getEntity();
+ if (NodeUtil.getTag(e, Constants.ADDR_HOUSE_NUMBER) != null
+ && NodeUtil.getTag(e, Constants.ADDR_STREET) != null) {
+ buildings.add(e);
+ }
+ }
+ if (NodeUtil.getTag(entityContainer.getEntity(), "highway") != null) {
+ String h = NodeUtil.getTag(entityContainer.getEntity(), "highway");
+ if(!mapWays.containsKey(h)){
+ mapWays.put(h, 0);
+ }
+ mapWays.put(h, mapWays.get(h) + 1);
+
+ }
+ }
+ }
+
+ @Override
+ public void complete() {
+ }
+
+ @Override
+ public void release() {
+ }
+ }, false));
+ }
+
+ System.out.println("\n"+mapWays);
+ System.out.println(System.currentTimeMillis() - st);
+
+ // 1. found towns !
+ Region country = new Region(null);
+ for (Node s : places) {
+ String place = NodeUtil.getTag(s, "place");
+ if(place == null){
+ continue;
+ }
+ if("country".equals(place)){
+ country.setEntity(s);
+ } else {
+ City registerCity = country.registerCity(s);
+ if(registerCity == null){
+ System.out.println(place + " - " + NodeUtil.getTag(s, "name"));
+ }
+ }
+ }
+
+ // 2. found buildings (index addresses)
+ for(Entity b : buildings){
+ LatLon center ;
+ if(b instanceof Node){
+ center = NodeUtil.getLatLon((Node) b);
+ } else {
+ center = NodeUtil.getWeightCenter((Way) b, nodes);
+ }
+ // TODO first of all tag could be checked NodeUtil.getTag(e, "addr:city")
+ City city = country.getClosestCity(center);
+ if(city != null){
+ city.registerBuilding(center, b);
+ }
+ }
+
+ for(Node node : amenities){
+ country.registerAmenity(node);
+ }
+
+
+ runUI(country);
+
+ System.out.println();
+ System.out.println("USED Memory " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1e6);
+ System.out.println("TIME : " + (System.currentTimeMillis() - st));
+ }
+
+
+ ///////////////////////////////////////////
+ // 2. Showing UI
+
+ protected City selectedCity;
+
+ private MapPanel mapPanel = new MapPanel(new File(Constants.pathToTestDataDir+"MinskTiles"));
+
+ private DefaultMutableTreeNode amenitiesTree;
+ private JTree treePlaces;
+
+ public void runUI(final Region r){
+ JFrame frame = new JFrame("Tree of choose");
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ DefaultMutableTreeNode root = new DataExtractionTreeNode(r.getName(), r);
+ amenitiesTree = new DataExtractionTreeNode("Amenities", r);
+ amenitiesTree.add(new DataExtractionTreeNode("closest", r));
+ root.add(amenitiesTree);
+ for(CityType t : CityType.values()){
+ DefaultMutableTreeNode cityTree = new DataExtractionTreeNode(t.toString(), t);
+ root.add(cityTree);
+ for(City ct : r.getCitiesByType(t)){
+ DefaultMutableTreeNode cityNodeTree = new DataExtractionTreeNode(ct.getName(), ct);
+ cityTree.add(cityNodeTree);
+
+ for(Street str : ct.getStreets()){
+ DefaultMutableTreeNode strTree = new DataExtractionTreeNode(str.getName(), str);
+ cityNodeTree.add(strTree);
+ for(Entity e : str.getBuildings()){
+ DefaultMutableTreeNode building = new DataExtractionTreeNode(NodeUtil.getTag(e, Constants.ADDR_HOUSE_NUMBER), e);
+ strTree.add(building);
+
+ }
+ }
+ }
+ }
+
+
+
+ frame.addWindowListener(new ExitListener());
+ Container content = frame.getContentPane();
+ frame.setFocusable(true);
+
+
+ treePlaces = new JTree(root);
+ final JList jList = new JList();
+ jList.setCellRenderer(new DefaultListCellRenderer(){
+ private static final long serialVersionUID = 4661949460526837891L;
+
+ @Override
+ public Component getListCellRendererComponent(JList list,
+ Object value, int index, boolean isSelected,
+ boolean cellHasFocus) {
+ super.getListCellRendererComponent(list, value, index, isSelected,
+ cellHasFocus);
+ if(value instanceof City){
+ setText(((City)value).getName());
+ }
+ return this;
+ }
+ });
+
+ JSplitPane panelForTreeAndImage = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(treePlaces), mapPanel);
+ panelForTreeAndImage.setResizeWeight(0.2);
+ mapPanel.setFocusable(true);
+ mapPanel.addMapLocationListener(this);
+
+
+
+ JSplitPane pane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, new JScrollPane(jList), panelForTreeAndImage);
+ pane.setResizeWeight(0.2);
+ content.add(pane, BorderLayout.CENTER);
+
+ final JLabel label = new JLabel();
+ content.add(label, BorderLayout.SOUTH);
+
+ JPanel panel = new JPanel(new BorderLayout());
+ final JTextField textField = new JTextField();
+ final JButton button = new JButton();
+ button.setText("Set town");
+ panel.add(textField, BorderLayout.CENTER);
+ panel.add(button, BorderLayout.EAST);
+
+ content.add(panel, BorderLayout.NORTH);
+
+
+ updateListCities(r, textField.getText(), jList);
+ textField.getDocument().addUndoableEditListener(new UndoableEditListener(){
+ @Override
+ public void undoableEditHappened(UndoableEditEvent e) {
+ updateListCities(r, textField.getText(), jList);
+ }
+ });
+
+ button.addActionListener(new ActionListener(){
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ selectedCity = (City)jList.getSelectedValue();
+ }
+ });
+
+ jList.addListSelectionListener(new ListSelectionListener(){
+ @Override
+ public void valueChanged(ListSelectionEvent e) {
+ if(jList.getSelectedValue() != null){
+ Node node = ((City)jList.getSelectedValue()).getNode();
+ String text = "Lat : " + node.getLatitude() + " Lon " + node.getLongitude();
+ if(selectedCity != null){
+ text += " distance " + NodeUtil.getDistance(selectedCity.getNode(), node);
+ }
+ label.setText(text);
+ mapPanel.setLatLon(node.getLatitude(), node.getLongitude());
+ } else {
+ String text = selectedCity == null ? "" : selectedCity.getName();
+ label.setText(text);
+ }
+
+ }
+
+ });
+
+ treePlaces.addTreeSelectionListener(new TreeSelectionListener(){
+ @Override
+ public void valueChanged(TreeSelectionEvent e) {
+ if (e.getPath() != null) {
+ if (e.getPath().getLastPathComponent() instanceof DefaultMutableTreeNode) {
+ Object o = ((DefaultMutableTreeNode) e.getPath().getLastPathComponent()).getUserObject();
+
+ if (o instanceof City) {
+ City c = (City) o;
+ mapPanel.setLatLon(c.getNode().getLatitude(), c.getNode().getLongitude());
+ mapPanel.requestFocus();
+ }
+
+ if (o instanceof Entity) {
+ Entity c = (Entity) o;
+ if (c instanceof Node) {
+ mapPanel.setLatLon(((Node) c).getLatitude(), ((Node) c).getLongitude());
+// mapPanel.requestFocus();
+ } else {
+ DefaultMutableTreeNode n = (DefaultMutableTreeNode) e.getPath().getPathComponent(
+ e.getPath().getPathCount() - 2);
+ if (n.getUserObject() instanceof Street) {
+ Street str = (Street) n.getUserObject();
+ LatLon l = str.getLocationBuilding(c);
+ mapPanel.setLatLon(l.getLatitude(), l.getLongitude());
+ mapPanel.requestFocus();
+ }
+ }
+ }
+ }
+ }
+
+ }
+ });
+
+
+ frame.setSize(1024, 768);
+ frame.setVisible(true);
+ }
+
+ @Override
+ public void locationChanged(final double newLatitude, final double newLongitude){
+ Region reg = (Region) amenitiesTree.getUserObject();
+ List closestAmenities = reg.getClosestAmenities(newLatitude, newLongitude);
+ Collections.sort(closestAmenities, new Comparator(){
+ @Override
+ public int compare(Node o1, Node o2) {
+ return Double.compare(NodeUtil.getDistance(o1, newLatitude, newLongitude),
+ NodeUtil.getDistance(o2, newLatitude, newLongitude));
+ }
+
+ });
+
+ Map> filter = new TreeMap>();
+ for(Node n : closestAmenities){
+ String type = NodeUtil.getTag(n, "amenity");
+ if(!filter.containsKey(type)){
+ filter.put(type, new ArrayList());
+ }
+ filter.get(type).add(n);
+ }
+ for(int i=1; i< amenitiesTree.getChildCount(); ){
+ if(!filter.containsKey(((DefaultMutableTreeNode)amenitiesTree.getChildAt(i)).getUserObject())){
+ amenitiesTree.remove(i);
+ } else {
+ i++;
+ }
+ }
+
+ ((DefaultMutableTreeNode)amenitiesTree.getChildAt(0)).removeAllChildren();
+
+
+ for(int i=0; i<15 && i < closestAmenities.size(); i++){
+ Node n = closestAmenities.get(i);
+ String type = NodeUtil.getTag(n, "amenity");
+ String name = NodeUtil.getTag(n, "name");
+ int dist = (int) (NodeUtil.getDistance(n, newLatitude, newLongitude));
+ String str = type +" "+(name == null ? n.getId() : name) +" [" +dist+" m ]";
+ ((DefaultMutableTreeNode)amenitiesTree.getChildAt(0)).add(
+ new DataExtractionTreeNode(str, n));
+ }
+
+ for(String s : filter.keySet()){
+ DefaultMutableTreeNode p = null;
+ for(int i=0; i< amenitiesTree.getChildCount(); i++){
+ if(s.equals(((DefaultMutableTreeNode)amenitiesTree.getChildAt(i)).getUserObject())){
+ p = ((DefaultMutableTreeNode)amenitiesTree.getChildAt(i));
+ break;
+ }
+ }
+ if (p == null) {
+ p = new DefaultMutableTreeNode(s);
+ }
+// Map consists = new LinkedHashMap();
+// for(Node n : filter.get(s)){
+// consists.put(n, null);
+// }
+// for(int i=0; i city = r.getSuggestedCities(text, 100);
+ City[] names = new City[city.size()];
+ int i=0;
+ for(City c : city){
+ names[i++] = c;
+ }
+ jList.setListData(names);
+ }
+
+
+ public static class DataExtractionTreeNode extends DefaultMutableTreeNode {
+ private static final long serialVersionUID = 1L;
+ private String name;
+
+ public DataExtractionTreeNode(String name, Object userObject){
+ super(userObject);
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ }
+ public static class ExitListener extends WindowAdapter {
+ public void windowClosing(WindowEvent event) {
+ System.exit(0);
+ }
+ }
+
+}
diff --git a/DataExtractionOSM/src/com/anvisics/MapPanel.java b/DataExtractionOSM/src/com/anvisics/MapPanel.java
new file mode 100644
index 0000000000..bc76679b03
--- /dev/null
+++ b/DataExtractionOSM/src/com/anvisics/MapPanel.java
@@ -0,0 +1,335 @@
+package com.anvisics;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.imageio.ImageIO;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.UIManager;
+
+import com.anvisics.DataExtraction.ExitListener;
+
+public class MapPanel extends JPanel {
+
+ private static final long serialVersionUID = 1L;
+
+ public interface IMapLocationListener {
+ void locationChanged(double newLatitude, double newLongitude);
+ }
+
+ public static void main(String[] args) throws IOException {
+ JFrame frame = new JFrame("Tree of choose");
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+
+ frame.addWindowListener(new ExitListener());
+ Container content = frame.getContentPane();
+
+// MapPanel panel = new MapPanel(new ZipFile(Constants.pathToTestDataDir + "MinskTiles.zipp"));
+ MapPanel panel = new MapPanel(new File(Constants.pathToTestDataDir + "MinskTiles"));
+
+ content.add(panel, BorderLayout.CENTER);
+
+ frame.setSize(512, 512);
+ frame.setVisible(true);
+
+ }
+
+ private final int tileSize = 256;
+ private BufferedImage[][] images;
+ private int xStartingImage = 0;
+ private int yStartingImage = 0;
+
+ private final File fileWithTiles;
+ private int zoom = 15;
+
+ // degree measurements (-180, 180)
+ //
+ private double longitude = 27.56;
+ //
+ // degree measurements (90, -90)
+ private double latitude = 53.9;
+
+ private List listeners = new ArrayList();
+
+ private String map = "Mapnik";
+
+ public MapPanel(File fileWithTiles) {
+ this.fileWithTiles = fileWithTiles;
+ initUI();
+ }
+
+
+ public double getXTile(){
+ return NodeUtil.getTileNumberX(zoom, longitude);
+ }
+
+ public double getYTile(){
+ return NodeUtil.getTileNumberY(zoom, latitude);
+ }
+
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ System.out.println("draw");
+ if (images != null) {
+ for (int i = 0; i < images.length; i++) {
+ for (int j = 0; j < images[i].length; j++) {
+ if(images[i][j] == null){
+ if((i+j + (int)getXTile() + (int)getYTile()) % 2 == 0){
+ g.setColor(Color.gray);
+ } else {
+ g.setColor(Color.white);
+ }
+ g.fillRect(i * tileSize+xStartingImage, j * tileSize + yStartingImage, tileSize, tileSize);
+ } else {
+ g.drawImage(images[i][j], i * tileSize+xStartingImage, j * tileSize + yStartingImage, this);
+ }
+ }
+ }
+ }
+ g.setColor(Color.black);
+
+ g.fillOval(getWidth()/2 - 2, getHeight()/2 -2, 4, 4);
+ g.drawOval(getWidth()/2 - 2, getHeight()/2 -2, 4, 4);
+ g.drawOval(getWidth()/2 - 5, getHeight()/2 -5, 10, 10);
+ }
+
+ public String getFile(int x, int y){
+ return map +"/"+zoom+"/"+(x) +"/"+y+".png";
+ }
+
+ Map cache = new HashMap();
+ public BufferedImage getImageFor(int x, int y) throws IOException{
+ String file = getFile(x, y);
+ if(!cache.containsKey(file)){
+// ZipEntry en = fileWithTiles.getEntry(file);
+ File en = new File(fileWithTiles, file);
+ if(cache.size() > 1000){
+ ArrayList list = new ArrayList(cache.keySet());
+ for(int i=0; i= 8){
+ dragTo(e.getPoint());
+ startDragging = e.getPoint();
+ }
+ }
+ }
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ if(e.getButton() == MouseEvent.BUTTON3){
+ if(startDragging == null){
+ startDragging = e.getPoint();
+ }
+ }
+ }
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ if(e.getButton() == MouseEvent.BUTTON3){
+ if(startDragging != null){
+ dragTo(e.getPoint());
+ fireMapLocationListeners();
+ startDragging = null;
+ }
+ }
+ super.mouseReleased(e);
+ }
+
+ }
+
+}
diff --git a/DataExtractionOSM/src/com/anvisics/NodeUtil.java b/DataExtractionOSM/src/com/anvisics/NodeUtil.java
new file mode 100644
index 0000000000..8bd78a6f5a
--- /dev/null
+++ b/DataExtractionOSM/src/com/anvisics/NodeUtil.java
@@ -0,0 +1,213 @@
+package com.anvisics;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.openstreetmap.osmosis.core.domain.v0_6.Entity;
+import org.openstreetmap.osmosis.core.domain.v0_6.Node;
+import org.openstreetmap.osmosis.core.domain.v0_6.Tag;
+import org.openstreetmap.osmosis.core.domain.v0_6.Way;
+import org.openstreetmap.osmosis.core.domain.v0_6.WayNode;
+
+public class NodeUtil {
+
+ public static class LatLon {
+ private final double longitude;
+ private final double latitude;
+
+ public LatLon(double latitude, double longitude){
+ this.latitude = latitude;
+ this.longitude = longitude;
+ }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long temp;
+ temp = Double.doubleToLongBits(latitude);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(longitude);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ LatLon other = (LatLon) obj;
+ if (Double.doubleToLongBits(latitude) != Double
+ .doubleToLongBits(other.latitude))
+ return false;
+ if (Double.doubleToLongBits(longitude) != Double
+ .doubleToLongBits(other.longitude))
+ return false;
+ return true;
+ }
+ @Override
+ public String toString() {
+ return "Lat " + latitude +" Lon "+ longitude;
+ }
+
+ public double getLatitude() {
+ return latitude;
+ }
+
+ public double getLongitude() {
+ return longitude;
+ }
+
+ }
+
+
+ public static String getTag(Entity e, String name){
+ for(Tag t : e.getTags()){
+ if(name.equals(t.getKey())){
+ return t.getValue();
+ }
+ }
+ return null;
+ }
+
+ public static double getDistance(Node e1, Node e2){
+ return getDistance(e1.getLatitude(), e1.getLongitude(), e2.getLatitude(), e2.getLongitude());
+ }
+
+ public static double getDistance(Node e1, double latitude, double longitude){
+ return getDistance(e1.getLatitude(), e1.getLongitude(), latitude, longitude);
+ }
+
+ public static double getDistance(Node e1, LatLon point){
+ return getDistance(e1.getLatitude(), e1.getLongitude(), point.getLatitude(), point.getLongitude());
+ }
+
+ /**
+ * Gets distance in meters
+ */
+ public static double getDistance(double lat1, double lon1, double lat2, double lon2){
+ double R = 6371; // km
+ double dLat = Math.toRadians(lat2-lat1);
+ double dLon = Math.toRadians(lon2-lon1);
+ double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
+ Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
+ Math.sin(dLon/2) * Math.sin(dLon/2);
+ double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
+ return R * c * 1000;
+ }
+
+ public static LatLon getWeightCenter(Collection nodes){
+ if(nodes.isEmpty()){
+ return null;
+ }
+ double longitude = 0;
+ double latitude = 0;
+ for(LatLon n : nodes){
+ longitude += n.getLongitude();
+ latitude += n.getLatitude();
+ }
+ return new LatLon(latitude/nodes.size(), longitude/nodes.size());
+ }
+
+ public static LatLon getWeightCenterForNodes(Collection nodes){
+ if(nodes.isEmpty()){
+ return null;
+ }
+ double longitude = 0;
+ double latitude = 0;
+ for(Node n : nodes){
+ longitude += n.getLongitude();
+ latitude += n.getLatitude();
+ }
+ return new LatLon(latitude/nodes.size(), longitude/nodes.size());
+ }
+
+ public static LatLon getLatLon(Node n){
+ return new LatLon(n.getLatitude(), n.getLongitude());
+ }
+
+ public static LatLon getWeightCenter(Way way, Map nodes){
+ List wayNodes = way.getWayNodes();
+ ArrayList arrayList = new ArrayList(wayNodes.size());
+ for(WayNode n : wayNodes){
+ if(nodes.containsKey(n.getNodeId())){
+ arrayList.add(nodes.get(n.getNodeId()));
+ }
+ }
+ return getWeightCenter(arrayList);
+ }
+
+ public static LatLon getWeightCenterForNodes(Way way, Map nodes){
+ List wayNodes = way.getWayNodes();
+ ArrayList arrayList = new ArrayList(wayNodes.size());
+ for(WayNode n : wayNodes){
+ if(nodes.containsKey(n.getNodeId())){
+ arrayList.add(nodes.get(n.getNodeId()));
+ }
+ }
+ return getWeightCenterForNodes(arrayList);
+ }
+
+
+
+ /**
+ * Gets distance in meters
+ */
+ public static double getDistance(LatLon l1, LatLon l2){
+ return getDistance(l1, l2);
+ }
+
+
+ /**
+ *
+ * Theses methods operate with degrees (evaluating tiles & vice versa)
+ * degree longitude measurements (-180, 180) [27.56 Minsk]
+ // degree latitude measurements (90, -90) [53.9]
+ */
+
+ // TODO check boundaries
+ public static double getTileNumberX(int zoom, double longitude){
+ int n = 1 << zoom;
+ return (longitude + 180d)/360d * n;
+ }
+
+ public static double getTileNumberY(int zoom, double latitude){
+ int n = 1 << zoom;
+ double eval = Math.log( Math.tan(Math.toRadians(latitude)) + 1/Math.cos(Math.toRadians(latitude)) );
+ return (1 - eval / Math.PI) / 2 * n;
+ }
+
+ public static double getLongitudeFromTile(int zoom, double x) {
+ return x / (1 << zoom) * 360.0 - 180.0;
+ }
+
+
+ public static double getLatitudeFromTile(int zoom, double y){
+ return Math.atan(Math.sinh(Math.PI * (1 - 2 * y / (1 << zoom)))) * 180d / Math.PI;
+ }
+
+ public static boolean isEmpty(String s){
+ return s == null || s.length() == 0;
+ }
+
+
+
+
+ public static boolean objectEquals(Object a, Object b){
+ if(a == null){
+ return b == null;
+ } else {
+ return a.equals(b);
+ }
+ }
+
+ public static boolean tag(Entity e, String name, String value){
+ String tag = getTag(e, name);
+ return value.equals(tag);
+ }
+}
diff --git a/DataExtractionOSM/src/com/anvisics/data/City.java b/DataExtractionOSM/src/com/anvisics/data/City.java
new file mode 100644
index 0000000000..ba9a21c9ad
--- /dev/null
+++ b/DataExtractionOSM/src/com/anvisics/data/City.java
@@ -0,0 +1,78 @@
+package com.anvisics.data;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.openstreetmap.osmosis.core.domain.v0_6.Entity;
+import org.openstreetmap.osmosis.core.domain.v0_6.Node;
+
+import com.anvisics.NodeUtil;
+import com.anvisics.NodeUtil.LatLon;
+
+public class City {
+
+ public enum CityType {
+ CITY(10000), TOWN(5000), VILLAGE(1000), HAMLET(300), SUBURB(300);
+
+ private double radius;
+ private CityType(double radius){
+ this.radius = radius;
+ }
+
+ public double getRadius() {
+ return radius;
+ }
+ }
+
+ private final Node el;
+ private CityType type = null;
+ private Map streets = new TreeMap();
+
+ public City(Node el){
+ this.el = el;
+ String place = NodeUtil.getTag(el, "place");
+ for(CityType t : CityType.values()){
+ if(t.name().equalsIgnoreCase(place)){
+ type = t;
+ break;
+ }
+ }
+ }
+
+ public Street registerBuilding(LatLon point, Entity e){
+ String number = NodeUtil.getTag(e, "addr:housenumber");
+ String street = NodeUtil.getTag(e, "addr:street");
+ if( street != null && number != null){
+ if(!streets.containsKey(street)){
+ streets.put(street, new Street(street));
+ }
+ streets.get(street).registerBuilding(point, e);
+ return streets.get(street);
+ }
+ return null;
+ }
+
+
+ public String getName(){
+ return NodeUtil.getTag(el, "name");
+ }
+
+ public CityType getType(){
+ return type;
+ }
+
+ public Node getNode(){
+ return el;
+ }
+
+ public Collection getStreets(){
+ return streets.values();
+ }
+
+ @Override
+ public String toString() {
+ return "City [" +type+"] " + getName();
+ }
+
+}
diff --git a/DataExtractionOSM/src/com/anvisics/data/DataTileManager.java b/DataExtractionOSM/src/com/anvisics/data/DataTileManager.java
new file mode 100644
index 0000000000..35d1111979
--- /dev/null
+++ b/DataExtractionOSM/src/com/anvisics/data/DataTileManager.java
@@ -0,0 +1,134 @@
+package com.anvisics.data;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.anvisics.NodeUtil;
+
+/**
+ *
+ * @param - object to store in that manager
+ */
+public class DataTileManager {
+
+ private int zoom = 15;
+
+ /**
+ * map for objects stores as 'xTile_yTile' -> List
+ */
+ private Map> objects = new HashMap>();
+
+ public int getZoom() {
+ return zoom;
+ }
+
+ public void setZoom(int zoom) {
+ // TODO !!! it is required to reindex all stored objects
+ if(!objects.isEmpty()){
+ throw new UnsupportedOperationException();
+ }
+ this.zoom = zoom;
+ }
+
+ private void putObjects(int tx, int ty, List r){
+ if(objects.containsKey(evTile(tx, ty))){
+ r.addAll(objects.get(evTile(tx, ty)));
+ }
+ }
+
+ /**
+ * @depth of the neighbor tile to visit
+ * returns not exactly sorted list,
+ * however the first objects are from closer tile than last
+ */
+ public List getClosestObjects(double latitude, double longitude, int depth){
+ int tileX = (int) NodeUtil.getTileNumberX(zoom, longitude);
+ int tileY = (int) NodeUtil.getTileNumberY(zoom, latitude);
+ List result = new ArrayList();
+
+
+ putObjects(tileX, tileY, result);
+
+ // that's very difficult way visiting node :
+ // similar to visit like spiral
+ // however the simplest way could visit by matrix & after that sort tiles by distance (that's less efficient)
+
+ // go through circle
+ for (int i = 1; i <= depth; i++) {
+
+ // goes
+ for (int j = 0; j <= i; j++) {
+ // left & right
+ int dx = j == 0 ? 0 : -1;
+ for (; dx < 1 || (j < i && dx == 1); dx += 2) {
+ // north
+ putObjects(tileX + dx * j, tileY + i, result);
+ // east
+ putObjects(tileX + i, tileY - dx * j, result);
+ // south
+ putObjects(tileX - dx * j, tileY - i, result);
+ // west
+ putObjects(tileX - i, tileY + dx * j, result);
+ }
+ }
+ }
+ return result;
+ }
+
+ private String evTile(int tileX, int tileY){
+ return tileX +"_"+tileY;
+ }
+
+
+ public String evaluateTile(double latitude, double longitude){
+ int tileX = (int) NodeUtil.getTileNumberX(zoom, longitude);
+ int tileY = (int) NodeUtil.getTileNumberY(zoom, latitude);
+ return evTile(tileX, tileY);
+ }
+
+ public String registerObject(double latitude, double longitude, T object){
+ String tile = evaluateTile(latitude, longitude);
+ if(!objects.containsKey(tile)){
+ objects.put(tile, new ArrayList());
+ }
+ objects.get(tile).add(object);
+ return tile;
+ }
+
+
+
+ // testing way to search
+ public static void print(int x, int y){
+ System.out.println(x + (y-1)*5);
+ }
+
+ public static void main(String[] args) {
+ int tileX = 3;
+ int tileY = 3;
+ int depth = 3;
+ for(int i=1; i<=depth; i++){
+
+ // goes
+ for(int j=0; j<=i; j++){
+ // left & right
+ int dx = j==0 ? 0 : -1;
+ for(; dx < 1 || (j < i && dx == 1); dx +=2){
+ // north
+ print(tileX + dx * j, tileY + i);
+ // east
+ print(tileX + i, tileY - dx *j);
+ // south
+ print(tileX - dx * j, tileY - i);
+ // west
+ print(tileX - i, tileY + dx *j);
+ }
+ }
+ }
+ }
+
+
+
+
+}
diff --git a/DataExtractionOSM/src/com/anvisics/data/Region.java b/DataExtractionOSM/src/com/anvisics/data/Region.java
new file mode 100644
index 0000000000..d9f91901d7
--- /dev/null
+++ b/DataExtractionOSM/src/com/anvisics/data/Region.java
@@ -0,0 +1,109 @@
+package com.anvisics.data;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.openstreetmap.osmosis.core.domain.v0_6.Entity;
+import org.openstreetmap.osmosis.core.domain.v0_6.Node;
+
+import com.anvisics.NodeUtil;
+import com.anvisics.NodeUtil.LatLon;
+import com.anvisics.data.City.CityType;
+
+public class Region {
+ private Entity entity;
+
+ private DataTileManager amenities = new DataTileManager();
+
+ private Map> cities = new HashMap>();
+ {
+ for(CityType type : CityType.values()){
+ cities.put(type, new ArrayList());
+ }
+ }
+
+
+ public Region(Entity entity){
+ this.entity = entity;
+ }
+
+
+ public void setEntity(Entity e){
+ this.entity = e;
+ }
+
+ public String getName(){
+ return entity == null ? "" : NodeUtil.getTag(entity, "name");
+ }
+
+ public Collection getCitiesByType(CityType type){
+ return cities.get(type);
+ }
+
+ public Collection getCitiesByName(String name){
+ return getCityByName(name, true, Integer.MAX_VALUE);
+ }
+
+ public Collection getSuggestedCities(String name, int number){
+ return getCityByName(name, false, number);
+ }
+
+ protected Collection getCityByName(String name, boolean exactMatch, int number){
+ List l = new ArrayList();
+ for(CityType type : CityType.values()){
+ for(City c : cities.get(type)){
+ if( (exactMatch && c.getName().equalsIgnoreCase(name)) ||
+ (!exactMatch && c.getName().toLowerCase().startsWith(name.toLowerCase())
+ )){
+ l.add(c);
+ if(l.size() >= number){
+ break;
+ }
+ }
+ }
+ }
+ return l;
+ }
+
+ public City getClosestCity(LatLon point){
+ City closest = null;
+ double relDist = Double.POSITIVE_INFINITY;
+ for(CityType t : CityType.values()){
+ for(City c : cities.get(t)){
+ double rel = NodeUtil.getDistance(c.getNode(), point) / t.getRadius();
+ if(rel < 1) {
+ return c; // we are in that city
+ }
+ if(rel < relDist){
+ closest = c;
+ relDist = rel;
+ }
+ }
+ }
+ return closest;
+ }
+
+ public List getClosestAmenities(double latitude, double longitude){
+ return amenities.getClosestObjects(latitude, longitude, 2);
+ }
+
+ public void registerAmenity(Node n){
+ amenities.registerObject(n.getLatitude(), n.getLongitude(), n);
+ }
+
+ public City registerCity(Node c){
+ City city = new City(c);
+ if(city.getType() != null && !NodeUtil.isEmpty(city.getName())){
+ cities.get(city.getType()).add(city);
+ return city;
+ }
+ return null;
+ }
+
+
+
+
+}
diff --git a/DataExtractionOSM/src/com/anvisics/data/Street.java b/DataExtractionOSM/src/com/anvisics/data/Street.java
new file mode 100644
index 0000000000..5f959c53b6
--- /dev/null
+++ b/DataExtractionOSM/src/com/anvisics/data/Street.java
@@ -0,0 +1,36 @@
+package com.anvisics.data;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.openstreetmap.osmosis.core.domain.v0_6.Entity;
+
+import com.anvisics.NodeUtil.LatLon;
+
+public class Street {
+
+ private final String name;
+ private Map buildings = new HashMap();
+
+ public Street(String name){
+ this.name = name;
+ }
+
+ public void registerBuilding(LatLon point, Entity e){
+ buildings.put(e, point);
+ }
+
+ public Set getBuildings() {
+ return buildings.keySet();
+ }
+
+ public LatLon getLocationBuilding(Entity e){
+ return buildings.get(e);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+}