40 Commits

Author SHA1 Message Date
Emux
c0d5f4a0ca 0.15.0 2021-01-01 18:59:48 +02:00
Emux
2859a18d72 Deploy improvements 2021-01-01 18:44:53 +02:00
Emux
869446ad13 JobQueue.clear: change log level 2020-12-31 14:06:54 +02:00
Emux
b2fd22885e Samples: reorder theme dispose 2020-12-28 14:12:01 +02:00
Meibes
7d6c623a80 Samples MapFragment: use theme dispose function (#800) 2020-12-28 13:43:56 +02:00
Emux
6bea801bf6 Samples: use theme dispose function 2020-12-28 12:12:14 +02:00
Emux
d446a3448b Samples: add theme.dispose 2020-12-28 11:56:32 +02:00
Emux
d006ba5361 VectorTileLayer: code improvements 2020-12-25 14:53:19 +02:00
Meibes
0eb4f3752f OSMUtils.isArea: reorder 'if' based on OSM stats (#799) 2020-12-24 10:33:12 +02:00
Emux
789c280fc2 OSMUtils.isArea improvements #798 2020-12-23 17:16:08 +02:00
Meibes
a881eec9b1 OSMUtils.isArea improvements (#798) 2020-12-23 13:31:41 +02:00
Meibes
1bc1d88464 Android Samples: add Fragment example (#796) 2020-12-22 11:40:34 +02:00
Emux
1c18221f05 ReadBuffer: fix docs 2020-12-13 13:26:21 +02:00
Emux
f4162acf04 Update Android build tools 2020-12-10 12:06:10 +02:00
Emux
1138978c22 Use --release=7 for compiling the non-android libraries on Java >= 9 (#795) 2020-12-03 13:30:31 +02:00
Emux
bd43baba20 TileLayer: move tileSource in parent class (#794) 2020-11-30 17:47:14 +02:00
Meibes
2e6da74af8 Color: fix parseColor javadoc (#793) 2020-11-28 12:20:09 +02:00
Meibes
f6561d2a2e OsmTileLayer: add constructor (#792) 2020-11-28 12:18:16 +02:00
Emux
45a42bb242 Samples improvements #785 2020-11-24 14:13:56 +02:00
Emux
3043173814 Symbol scale option (#790) 2020-11-15 17:20:52 +02:00
Emux
cde5d898c7 Update Integration.md 2020-11-11 10:57:48 +02:00
Emux
58f6215c0f Samples improvements #785 2020-10-21 17:57:49 +03:00
Emux
d7d6fa57ac Parameters: increase maximum buffer size for map files (Japan) (#789) 2020-10-19 13:39:22 +03:00
Emux
57bf615ab7 Update Gradle (#788) 2020-10-13 14:11:45 +03:00
Emux
9bf3161010 Update Android Gradle plugin 2020-10-08 15:18:35 +03:00
Emux
98a977ea72 Merge pull request #786 from mapsforge/xml
Render theme xml pull parser
2020-09-25 16:58:44 +03:00
Emux
661bc08bbf Render theme xml pull parser, fix #431 2020-09-25 16:57:52 +03:00
Emux
804c8c4603 Merge pull request #785 from mapsforge/storage
Android: scoped storage example
2020-09-24 14:18:41 +03:00
Emux
e103c38e3e Android: scoped storage example 2020-09-24 14:18:20 +03:00
Emux
e3b4ff502e Merge pull request #784 from mapsforge/mapsforge
Mapsforge: map stream support
2020-09-24 14:02:48 +03:00
Emux
6116ebb348 Mapsforge: map stream support 2020-09-24 14:00:49 +03:00
Emux
5c3a728d05 Merge pull request #783 from mapsforge/content
Render theme from Android content providers
2020-09-24 13:54:14 +03:00
Emux
2070145880 Render theme from Android content providers 2020-09-24 13:52:13 +03:00
Emux
e9a670f274 Update Android samples 2020-09-17 10:46:17 +03:00
Emux
e5c87ba06e Merge pull request #782 from mapsforge/android
Update Android
2020-09-09 17:57:22 +03:00
Emux
fa992b93f5 Update Android 2020-09-09 17:47:42 +03:00
Emux
bf67074cf3 Merge pull request #781 from mapsforge/cache
Android samples: use OkHttp cache
2020-09-02 17:09:48 +03:00
Emux
074320d6d2 Android samples: use OkHttp cache 2020-09-02 17:08:39 +03:00
Emux
6616c22a32 Update changelog 2020-08-30 20:24:41 +03:00
Izumi Kawashima
1ddba0fe8f Use org.gretty instead of org.akhikhl.gretty maven repository (#780) 2020-08-30 18:09:28 +03:00
60 changed files with 2992 additions and 765 deletions

View File

@@ -4,8 +4,8 @@ jdk:
- openjdk8 - openjdk8
env: env:
global: global:
- ANDROID=29 - ANDROID=30
- ANDROID_BUILD_TOOLS=29.0.3 - ANDROID_BUILD_TOOLS=30.0.3
- GRADLE_OPTS="-Xmx2048m" - GRADLE_OPTS="-Xmx2048m"
- secure: sW674wuFZOuoX7jHQHDbX3j8NxL8JxR07cyq+CrrqJ537dU9lxWQmMBRUpOb+p/q7sQ74PUtiKJkmFgKCSJSAKY+nr6GJ8P/q6u5TUKbmUWODSn8znehX2zualfvFwpF4PILok/wUzXBQE62jn4lUua7cMdsHRMNHbLmKqBoVL0meObDDjsaJ/RCbOPuruy3FmgvXPp0+Y4zl1GsklDSyjFzg4LBzjAk9Ryvh1O4zvJBkkyfCgurLKCnOKIPy3v5fPMS9oDfO1aarAVGoZZe416pvTW4hb8cdB6kn9XWYDob4NDFX/sP5k7XIhd/NAIn9LrKFg0sLtATaKLX+BcasF1CgDR/u6+SEeQd5QaRF7Go2Nq5Ltuu4OIFONI2qhEeVDDK6Otf2WSWj9KPno2GHuumBfbg4ypWoJgmZrMXk8JeVV/OP/0jIQz3p/7yfF21X1XBEqYaVHPAMKdEYYkCSa46KfACyOt6LfnkuCHtoTOpFo7sq0omIA2HOtpIx1u3vMBUyAbQqT6cokkKB1b6gNTFwhHc+8ybfLFPljJB8cWshI+V/b06S6fekRmvTNxvDykWNsdlkENBYqc9hMfjcT4hO4K+76SWN62mimQYODvFyfTVMC7WkQ3k/XEnmqUPV5XkbaILbS1d/tA57N148FiJ5/QXtI6Y94imubYyVqU= - secure: sW674wuFZOuoX7jHQHDbX3j8NxL8JxR07cyq+CrrqJ537dU9lxWQmMBRUpOb+p/q7sQ74PUtiKJkmFgKCSJSAKY+nr6GJ8P/q6u5TUKbmUWODSn8znehX2zualfvFwpF4PILok/wUzXBQE62jn4lUua7cMdsHRMNHbLmKqBoVL0meObDDjsaJ/RCbOPuruy3FmgvXPp0+Y4zl1GsklDSyjFzg4LBzjAk9Ryvh1O4zvJBkkyfCgurLKCnOKIPy3v5fPMS9oDfO1aarAVGoZZe416pvTW4hb8cdB6kn9XWYDob4NDFX/sP5k7XIhd/NAIn9LrKFg0sLtATaKLX+BcasF1CgDR/u6+SEeQd5QaRF7Go2Nq5Ltuu4OIFONI2qhEeVDDK6Otf2WSWj9KPno2GHuumBfbg4ypWoJgmZrMXk8JeVV/OP/0jIQz3p/7yfF21X1XBEqYaVHPAMKdEYYkCSa46KfACyOt6LfnkuCHtoTOpFo7sq0omIA2HOtpIx1u3vMBUyAbQqT6cokkKB1b6gNTFwhHc+8ybfLFPljJB8cWshI+V/b06S6fekRmvTNxvDykWNsdlkENBYqc9hMfjcT4hO4K+76SWN62mimQYODvFyfTVMC7WkQ3k/XEnmqUPV5XkbaILbS1d/tA57N148FiJ5/QXtI6Y94imubYyVqU=
- secure: AdKSZKA4gMuKXI4X4dQNJqcMv5OmPIHdN8fpy55Y9yoOQPQHZE3Zwc4QDWBh20q298jyEC854tVTPTysdZ7h+2s2FhsprYv1Bt/QNzKIrLpeIMj2quuVGMbdPuk08y55gost94KwVLJv0sIDpRlB/PEQkA7Mg/UDsT9zR8E1Ms5x+ul2C8e1ag0zzNl1wVnT5jY8WCp74uA/XXCcJl/80qT1stUERazCKwbKNo007hi7rdm4HA7YGevORq8e2r67je+WIBZUAwrHT0Zjuo4ibwUii4LdwvjuN3w0Z6e9Wf4x5bBqGgnih0T31uom2yPjNx+U/c2AWI+Nxfy/SEF2U+9bjBEZ3ZhI7F1B9ofXo2mhvvsVDiUrymMBbG2V64C9kAzeUh7xIBTqIrbdtpAEBV9FlLAtF2swVTwtCgZgcVTOt3RKXCi3X3nk3cuH7PAorFa/QGfT4xxVu2011FVAt2Rm7SD0ZWztZTSTz/4Nt/egtGBOJfrCc7oLEygLzDmLqsqCwCROITVQjWLjrtqDyLteaNiSXeNIQMKun3izApbXnHmXB+FV3R3EZocboqk3v5bmPTahnG6Ghc2zknWyyxSx+O9qIfOpHUL8JMJiT82lUQUeibtCn7DCE8wVQ/gYC5i+a+KO/d3NemSzIFlZ8aoUiEPYq18dYlsDXeLXwF0= - secure: AdKSZKA4gMuKXI4X4dQNJqcMv5OmPIHdN8fpy55Y9yoOQPQHZE3Zwc4QDWBh20q298jyEC854tVTPTysdZ7h+2s2FhsprYv1Bt/QNzKIrLpeIMj2quuVGMbdPuk08y55gost94KwVLJv0sIDpRlB/PEQkA7Mg/UDsT9zR8E1Ms5x+ul2C8e1ag0zzNl1wVnT5jY8WCp74uA/XXCcJl/80qT1stUERazCKwbKNo007hi7rdm4HA7YGevORq8e2r67je+WIBZUAwrHT0Zjuo4ibwUii4LdwvjuN3w0Z6e9Wf4x5bBqGgnih0T31uom2yPjNx+U/c2AWI+Nxfy/SEF2U+9bjBEZ3ZhI7F1B9ofXo2mhvvsVDiUrymMBbG2V64C9kAzeUh7xIBTqIrbdtpAEBV9FlLAtF2swVTwtCgZgcVTOt3RKXCi3X3nk3cuH7PAorFa/QGfT4xxVu2011FVAt2Rm7SD0ZWztZTSTz/4Nt/egtGBOJfrCc7oLEygLzDmLqsqCwCROITVQjWLjrtqDyLteaNiSXeNIQMKun3izApbXnHmXB+FV3R3EZocboqk3v5bmPTahnG6Ghc2zknWyyxSx+O9qIfOpHUL8JMJiT82lUQUeibtCn7DCE8wVQ/gYC5i+a+KO/d3NemSzIFlZ8aoUiEPYq18dYlsDXeLXwF0=

View File

@@ -4,7 +4,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.0.1' classpath 'com.android.tools.build:gradle:4.0.2'
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
} }
} }
@@ -14,7 +14,7 @@ allprojects {
version = 'master-SNAPSHOT' version = 'master-SNAPSHOT'
ext.isReleaseVersion = !version.endsWith("SNAPSHOT") ext.isReleaseVersion = !version.endsWith("SNAPSHOT")
ext.androidBuildVersionTools = "29.0.3" ext.androidBuildVersionTools = "30.0.3"
ext.gdxVersion = "1.9.10" ext.gdxVersion = "1.9.10"
ext.gwtVersion = "2.8.2" ext.gwtVersion = "2.8.2"
ext.slf4jVersion = "1.7.28" ext.slf4jVersion = "1.7.28"
@@ -28,12 +28,12 @@ allprojects {
} }
} }
static def androidCompileSdk() { return 29 } static def androidCompileSdk() { return 30 }
// 14 for Support Library, 16 for sqlite-android // 14 for Support Library, 16 for sqlite-android
static def androidMinSdk() { return 16 } static def androidMinSdk() { return 16 }
static def androidTargetSdk() { return 29 } static def androidTargetSdk() { return 30 }
static def versionCode() { return 1 } static def versionCode() { return 1 }
@@ -50,5 +50,10 @@ subprojects {
sourceCompatibility = JavaVersion.VERSION_1_7 sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7 targetCompatibility = JavaVersion.VERSION_1_7
options.encoding = 'UTF-8' options.encoding = 'UTF-8'
if (JavaVersion.current().isJava9Compatible()) {
if (!project.properties.containsKey('android')) {
options.compilerArgs.addAll(['--release', '7'])
}
}
} }
} }

View File

@@ -9,6 +9,7 @@ if (project.hasProperty("android")) {
task javadoc(type: Javadoc) { task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
classpath += project.android.libraryVariants.toList().first().javaCompileProvider.get().classpath
} }
} else { } else {
task sourcesJar(type: Jar) { task sourcesJar(type: Jar) {

View File

@@ -1,5 +1,21 @@
# Changelog # Changelog
## New since 0.15.0
- Many other minor improvements and bug fixes
- [Solved issues](https://github.com/mapsforge/vtm/issues?q=is%3Aclosed+milestone%3A0.16.0)
## Version 0.15.0 (2021-01-01)
- Android: scoped storage example [#785](https://github.com/mapsforge/vtm/pull/785)
- Mapsforge: map stream support [#784](https://github.com/mapsforge/vtm/pull/784)
- Render theme from Android content providers [#783](https://github.com/mapsforge/vtm/pull/783)
- Render theme xml pull parser [#786](https://github.com/mapsforge/vtm/pull/786)
- Symbol scale option [#790](https://github.com/mapsforge/vtm/pull/790)
- `Parameters.SYMBOL_SCALING`
- Many other minor improvements and bug fixes
- [Solved issues](https://github.com/mapsforge/vtm/issues?q=is%3Aclosed+milestone%3A0.15.0)
## Version 0.14.0 (2020-08-25) ## Version 0.14.0 (2020-08-25)
- Render themes: symbol styles [#769](https://github.com/mapsforge/vtm/pull/769) - Render themes: symbol styles [#769](https://github.com/mapsforge/vtm/pull/769)
@@ -224,6 +240,8 @@
- libGDX layer gestures [#151](https://github.com/mapsforge/vtm/issues/151) - libGDX layer gestures [#151](https://github.com/mapsforge/vtm/issues/151)
- Render theme area tessellation option [#37](https://github.com/mapsforge/vtm/issues/37) - Render theme area tessellation option [#37](https://github.com/mapsforge/vtm/issues/37)
- Render theme resources optional location prefixes [#66](https://github.com/mapsforge/vtm/issues/66) - Render theme resources optional location prefixes [#66](https://github.com/mapsforge/vtm/issues/66)
- Render theme from input stream [#161](https://github.com/mapsforge/vtm/issues/161)
- Render theme from Android assets [#162](https://github.com/mapsforge/vtm/issues/162)
- Graphics API platform enhancements [#92](https://github.com/mapsforge/vtm/issues/92) - Graphics API platform enhancements [#92](https://github.com/mapsforge/vtm/issues/92)
- GeoPoint & BoundingBox improvements [#201](https://github.com/mapsforge/vtm/issues/201) [#200](https://github.com/mapsforge/vtm/issues/200) - GeoPoint & BoundingBox improvements [#201](https://github.com/mapsforge/vtm/issues/201) [#200](https://github.com/mapsforge/vtm/issues/200)
- vtm-jts module [#53](https://github.com/mapsforge/vtm/issues/53) - vtm-jts module [#53](https://github.com/mapsforge/vtm/issues/53)

View File

@@ -10,6 +10,7 @@ Current version is [![Maven Central](https://img.shields.io/maven-central/v/org.
```groovy ```groovy
implementation 'org.mapsforge:vtm:[CURRENT-VERSION]' implementation 'org.mapsforge:vtm:[CURRENT-VERSION]'
implementation 'org.mapsforge:vtm-themes:[CURRENT-VERSION]' implementation 'org.mapsforge:vtm-themes:[CURRENT-VERSION]'
implementation 'net.sf.kxml:kxml2:2.3.0'
implementation 'org.slf4j:slf4j-api:1.7.28' implementation 'org.slf4j:slf4j-api:1.7.28'
``` ```
@@ -56,7 +57,6 @@ implementation 'org.mapsforge:vtm-desktop:[CURRENT-VERSION]'
implementation 'org.mapsforge:vtm-desktop:[CURRENT-VERSION]:natives-linux' implementation 'org.mapsforge:vtm-desktop:[CURRENT-VERSION]:natives-linux'
implementation 'org.mapsforge:vtm-desktop:[CURRENT-VERSION]:natives-osx' implementation 'org.mapsforge:vtm-desktop:[CURRENT-VERSION]:natives-osx'
implementation 'org.mapsforge:vtm-desktop:[CURRENT-VERSION]:natives-windows' implementation 'org.mapsforge:vtm-desktop:[CURRENT-VERSION]:natives-windows'
implementation 'org.mapsforge:vtm-desktop-lwjgl:[CURRENT-VERSION]'
implementation 'com.badlogicgames.gdx:gdx:1.9.10' implementation 'com.badlogicgames.gdx:gdx:1.9.10'
implementation 'com.badlogicgames.gdx:gdx-platform:1.9.10:natives-desktop' implementation 'com.badlogicgames.gdx:gdx-platform:1.9.10:natives-desktop'
implementation 'com.github.blackears:svgSalamander:v1.1.1' implementation 'com.github.blackears:svgSalamander:v1.1.1'
@@ -64,6 +64,7 @@ implementation 'com.github.blackears:svgSalamander:v1.1.1'
### Desktop (LWJGL) ### Desktop (LWJGL)
```groovy ```groovy
implementation 'org.mapsforge:vtm-desktop-lwjgl:[CURRENT-VERSION]'
implementation 'com.badlogicgames.gdx:gdx-backend-lwjgl:1.9.10' implementation 'com.badlogicgames.gdx:gdx-backend-lwjgl:1.9.10'
implementation 'org.lwjgl.lwjgl:lwjgl:2.9.3' implementation 'org.lwjgl.lwjgl:lwjgl:2.9.3'
implementation 'org.lwjgl.lwjgl:lwjgl-platform:2.9.3:natives-linux' implementation 'org.lwjgl.lwjgl:lwjgl-platform:2.9.3:natives-linux'
@@ -73,6 +74,7 @@ implementation 'org.lwjgl.lwjgl:lwjgl-platform:2.9.3:natives-windows'
### Desktop (LWJGL 3) ### Desktop (LWJGL 3)
```groovy ```groovy
implementation 'org.mapsforge:vtm-desktop-lwjgl3:[CURRENT-VERSION]'
implementation 'com.badlogicgames.gdx:gdx-backend-lwjgl3:1.9.10' implementation 'com.badlogicgames.gdx:gdx-backend-lwjgl3:1.9.10'
implementation 'org.lwjgl:lwjgl:3.2.3' implementation 'org.lwjgl:lwjgl:3.2.3'
implementation 'org.lwjgl:lwjgl:3.2.3:natives-linux' implementation 'org.lwjgl:lwjgl:3.2.3:natives-linux'

View File

@@ -6,13 +6,13 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html # http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process. # Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings. # The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit # This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true # org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the # AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK # Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn # https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX # Automatically convert third-party libraries to use AndroidX

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -15,6 +15,7 @@
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:usesCleartextTraffic="true"> android:usesCleartextTraffic="true">
<activity <activity
android:name=".Samples" android:name=".Samples"
@@ -33,6 +34,9 @@
<activity <activity
android:name=".ClusterMarkerOverlayActivity" android:name=".ClusterMarkerOverlayActivity"
android:configChanges="keyboardHidden|orientation|screenSize" /> android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".FragmentActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity <activity
android:name=".GettingStarted" android:name=".GettingStarted"
android:configChanges="keyboardHidden|orientation|screenSize" /> android:configChanges="keyboardHidden|orientation|screenSize" />
@@ -60,12 +64,6 @@
<activity <activity
android:name=".MapsforgeActivity" android:name=".MapsforgeActivity"
android:configChanges="keyboardHidden|orientation|screenSize" /> android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".MapsforgeActivity$MapFilePicker"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".MapsforgeActivity$ThemeFilePicker"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity <activity
android:name=".MapsforgeS3DBActivity" android:name=".MapsforgeS3DBActivity"
android:configChanges="keyboardHidden|orientation|screenSize" /> android:configChanges="keyboardHidden|orientation|screenSize" />

View File

@@ -16,11 +16,11 @@ dependencies {
implementation project(':vtm-gdx') implementation project(':vtm-gdx')
implementation project(':vtm-gdx-poi3d') implementation project(':vtm-gdx-poi3d')
implementation 'org.mapsforge:mapsforge-poi-android:0.14.0' implementation 'org.mapsforge:mapsforge-poi-android:0.15.0'
implementation 'org.mapsforge:sqlite-android:0.14.0:natives-armeabi-v7a' implementation 'org.mapsforge:sqlite-android:0.15.0:natives-armeabi-v7a'
implementation 'org.mapsforge:sqlite-android:0.14.0:natives-arm64-v8a' implementation 'org.mapsforge:sqlite-android:0.15.0:natives-arm64-v8a'
implementation 'org.mapsforge:sqlite-android:0.14.0:natives-x86' implementation 'org.mapsforge:sqlite-android:0.15.0:natives-x86'
implementation 'org.mapsforge:sqlite-android:0.14.0:natives-x86_64' implementation 'org.mapsforge:sqlite-android:0.15.0:natives-x86_64'
} }
android { android {

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/empty_fragment_text" />
</RelativeLayout>

View File

@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@android:color/white"> android:background="@android:color/white">
<org.oscim.android.MapView <RelativeLayout
android:id="@+id/mapView" android:id="@+id/mapView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/replace_fragment"
android:showAsAction="never"
android:title="@string/replace_fragment" />
</menu>

View File

@@ -28,5 +28,7 @@
<string name="warning">Warning</string> <string name="warning">Warning</string>
<string name="startup_message_mbtiles">To run this sample activity, you need an MBTiles database installed on storage.\n\nadb push %s %s</string> <string name="startup_message_mbtiles">To run this sample activity, you need an MBTiles database installed on storage.\n\nadb push %s %s</string>
<string name="exit">Exit</string> <string name="exit">Exit</string>
<string name="replace_fragment">Replace fragment</string>
<string name="empty_fragment_text">This is a fragment to test the back stack behaviour of the map fragment.</string>
</resources> </resources>

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright 2010, 2011, 2012 mapsforge.org * Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2016-2018 devemux86 * Copyright 2016-2020 devemux86
* Copyright 2017 Longri * Copyright 2017 Longri
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
@@ -16,18 +16,11 @@
*/ */
package org.oscim.android.filepicker; package org.oscim.android.filepicker;
import org.oscim.theme.ExternalRenderTheme; import org.oscim.theme.ThemeLoader;
import org.oscim.theme.ThemeFile;
import org.oscim.theme.XmlThemeBuilder;
import org.oscim.tiling.TileSource.OpenResult; import org.oscim.tiling.TileSource.OpenResult;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import java.io.File; import java.io.File;
import javax.xml.parsers.SAXParserFactory;
/** /**
* Accepts all valid render theme XML files. * Accepts all valid render theme XML files.
*/ */
@@ -36,13 +29,8 @@ public final class ValidRenderTheme implements ValidFileFilter {
@Override @Override
public boolean accept(File file) { public boolean accept(File file) {
try { try {
ThemeFile theme = new ExternalRenderTheme(file.getAbsolutePath()); ThemeLoader.load(file.getAbsolutePath());
DefaultHandler renderThemeHandler = new XmlThemeBuilder(theme);
XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
xmlReader.setContentHandler(renderThemeHandler);
xmlReader.parse(new InputSource(theme.getRenderThemeAsStream()));
mOpenResult = OpenResult.SUCCESS; mOpenResult = OpenResult.SUCCESS;
} catch (Exception e) { } catch (Exception e) {
mOpenResult = new OpenResult(e.getMessage()); mOpenResult = new OpenResult(e.getMessage());

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright 2013 Hannes Janetzek * Copyright 2013 Hannes Janetzek
* Copyright 2016-2018 devemux86 * Copyright 2016-2020 devemux86
* *
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
* *
@@ -20,8 +20,8 @@ package org.oscim.android.test;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import okhttp3.Cache;
import org.oscim.android.cache.TileCache; import okhttp3.OkHttpClient;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.layers.TileGridLayer; import org.oscim.layers.TileGridLayer;
import org.oscim.layers.tile.vector.VectorTileLayer; import org.oscim.layers.tile.vector.VectorTileLayer;
@@ -29,11 +29,10 @@ import org.oscim.theme.VtmThemes;
import org.oscim.tiling.TileSource; import org.oscim.tiling.TileSource;
import org.oscim.tiling.source.OkHttpEngine; import org.oscim.tiling.source.OkHttpEngine;
import org.oscim.tiling.source.oscimap4.OSciMap4TileSource; import org.oscim.tiling.source.oscimap4.OSciMap4TileSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.io.File;
public class BaseMapActivity extends MapActivity { public class BaseMapActivity extends MapActivity {
static final Logger log = LoggerFactory.getLogger(BaseMapActivity.class);
static final boolean USE_CACHE = false; static final boolean USE_CACHE = false;
@@ -41,8 +40,6 @@ public class BaseMapActivity extends MapActivity {
TileSource mTileSource; TileSource mTileSource;
TileGridLayer mGridLayer; TileGridLayer mGridLayer;
private TileCache mCache;
public BaseMapActivity(int contentView) { public BaseMapActivity(int contentView) {
super(contentView); super(contentView);
} }
@@ -54,15 +51,19 @@ public class BaseMapActivity extends MapActivity {
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (USE_CACHE) {
// Cache the tiles into file system
File cacheDirectory = new File(getExternalCacheDir(), "tiles");
int cacheSize = 10 * 1024 * 1024; // 10 MB
Cache cache = new Cache(cacheDirectory, cacheSize);
builder.cache(cache);
}
mTileSource = OSciMap4TileSource.builder() mTileSource = OSciMap4TileSource.builder()
.httpFactory(new OkHttpEngine.OkHttpFactory()) .httpFactory(new OkHttpEngine.OkHttpFactory(builder))
.build(); .build();
if (USE_CACHE) {
mCache = new TileCache(this, null, "tile.db");
mCache.setCacheSize(512 * (1 << 10));
mTileSource.setCache(mCache);
}
mBaseLayer = mMap.setBaseMap(mTileSource); mBaseLayer = mMap.setBaseMap(mTileSource);
/* set initial position on first run */ /* set initial position on first run */
@@ -72,14 +73,6 @@ public class BaseMapActivity extends MapActivity {
mMap.setMapPosition(53.08, 8.83, Math.pow(2, 16)); mMap.setMapPosition(53.08, 8.83, Math.pow(2, 16));
} }
@Override
protected void onDestroy() {
super.onDestroy();
if (mCache != null)
mCache.dispose();
}
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {

View File

@@ -16,22 +16,21 @@
package org.oscim.android.test; package org.oscim.android.test;
import android.os.Bundle; import android.os.Bundle;
import org.oscim.android.cache.TileCache; import okhttp3.Cache;
import okhttp3.OkHttpClient;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection; import org.oscim.core.MercatorProjection;
import org.oscim.layers.tile.bitmap.BitmapTileLayer; import org.oscim.layers.tile.bitmap.BitmapTileLayer;
import org.oscim.renderer.MapRenderer; import org.oscim.renderer.MapRenderer;
import org.oscim.tiling.source.OkHttpEngine;
import org.oscim.tiling.source.bitmap.BitmapTileSource; import org.oscim.tiling.source.bitmap.BitmapTileSource;
import org.oscim.tiling.source.bitmap.DefaultSources; import org.oscim.tiling.source.bitmap.DefaultSources;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.Collections; import java.util.Collections;
public class BitmapTileActivity extends MapActivity { public class BitmapTileActivity extends MapActivity {
static final Logger log = LoggerFactory.getLogger(BitmapTileActivity.class);
private static final boolean USE_CACHE = false; private static final boolean USE_CACHE = false;
private final BitmapTileSource mTileSource; private final BitmapTileSource mTileSource;
@@ -43,12 +42,9 @@ public class BitmapTileActivity extends MapActivity {
public BitmapTileActivity(BitmapTileSource tileSource) { public BitmapTileActivity(BitmapTileSource tileSource) {
super(R.layout.activity_map); super(R.layout.activity_map);
tileSource.setHttpRequestHeaders(Collections.singletonMap("User-Agent", "vtm-android-example"));
mTileSource = tileSource; mTileSource = tileSource;
} }
private TileCache mCache;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -58,31 +54,24 @@ public class BitmapTileActivity extends MapActivity {
if (mTileSource == null) if (mTileSource == null)
return; return;
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (USE_CACHE) { if (USE_CACHE) {
String cacheFile = mTileSource.getUrl() // Cache the tiles into file system
.toString() File cacheDirectory = new File(getExternalCacheDir(), "tiles");
.replaceFirst("https?://", "") int cacheSize = 10 * 1024 * 1024; // 10 MB
.replaceAll("/", "-"); Cache cache = new Cache(cacheDirectory, cacheSize);
builder.cache(cache);
log.debug("use bitmap cache {}", cacheFile);
mCache = new TileCache(this, null, cacheFile);
mCache.setCacheSize(512 * (1 << 10));
mTileSource.setCache(mCache);
} }
mTileSource.setHttpEngine(new OkHttpEngine.OkHttpFactory(builder));
mTileSource.setHttpRequestHeaders(Collections.singletonMap("User-Agent", "vtm-android-example"));
mBitmapLayer = new BitmapTileLayer(mMap, mTileSource); mBitmapLayer = new BitmapTileLayer(mMap, mTileSource);
mMap.layers().add(mBitmapLayer); mMap.layers().add(mBitmapLayer);
//loooop(1); //loooop(1);
} }
@Override
protected void onDestroy() {
super.onDestroy();
if (mCache != null)
mCache.dispose();
}
// Stress testing // Stress testing
void loooop(final int i) { void loooop(final int i) {
final long time = (long) (500 + Math.random() * 1000); final long time = (long) (500 + Math.random() * 1000);

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2020 Meibes
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.android.test;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@SuppressWarnings("deprecation")
public class BlankFragment extends Fragment {
static BlankFragment newInstance() {
BlankFragment instance = new BlankFragment();
Bundle args = new Bundle();
instance.setArguments(args);
return instance;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_blank, container, false);
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2020 Meibes
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.android.test;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class FragmentActivity extends Activity {
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_fragment);
setTitle(getClass().getSimpleName());
if (savedInstanceState == null) {
Fragment mapFragment = MapFragment.newInstance();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.fragment_container, mapFragment).commit();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.fragment_menu, menu);
return true;
}
@SuppressWarnings("deprecation")
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.replace_fragment) {
Fragment blankFragment = BlankFragment.newInstance();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, blankFragment);
ft.addToBackStack(null);
ft.commit();
return true;
}
return super.onOptionsItemSelected(item);
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2018-2019 devemux86 * Copyright 2018-2020 devemux86
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software * terms of the GNU Lesser General Public License as published by the Free Software
@@ -15,6 +15,9 @@
package org.oscim.android.test; package org.oscim.android.test;
import android.app.Activity; import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import org.oscim.android.MapView; import org.oscim.android.MapView;
import org.oscim.backend.CanvasAdapter; import org.oscim.backend.CanvasAdapter;
@@ -25,23 +28,24 @@ import org.oscim.renderer.GLViewport;
import org.oscim.scalebar.DefaultMapScaleBar; import org.oscim.scalebar.DefaultMapScaleBar;
import org.oscim.scalebar.MapScaleBar; import org.oscim.scalebar.MapScaleBar;
import org.oscim.scalebar.MapScaleBarLayer; import org.oscim.scalebar.MapScaleBarLayer;
import org.oscim.theme.IRenderTheme;
import org.oscim.theme.VtmThemes; import org.oscim.theme.VtmThemes;
import org.oscim.tiling.source.mapfile.MapFileTileSource; import org.oscim.tiling.source.mapfile.MapFileTileSource;
import java.io.File; import java.io.FileInputStream;
/** /**
* A very basic Android app example. * A very basic Android app example.
* <p> * <p>
* You'll need a map with filename berlin.map from download.mapsforge.org in device storage: * You'll need a map with filename berlin.map from download.mapsforge.org in device storage.
* /sdcard/Android/data/org.oscim.android.test/files/
*/ */
public class GettingStarted extends Activity { public class GettingStarted extends Activity {
// Name of the map file in device storage // Request code for selecting a map file
private static final String MAP_FILE = "berlin.map"; private static final int SELECT_MAP_FILE = 0;
private MapView mapView; private MapView mapView;
private IRenderTheme theme;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@@ -51,10 +55,30 @@ public class GettingStarted extends Activity {
mapView = new MapView(this); mapView = new MapView(this);
setContentView(mapView); setContentView(mapView);
// Tile source // Open map
MapFileTileSource tileSource = new MapFileTileSource(); Intent intent = new Intent(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT ? Intent.ACTION_OPEN_DOCUMENT : Intent.ACTION_GET_CONTENT);
String mapPath = new File(getExternalFilesDir(null), MAP_FILE).getAbsolutePath(); intent.addCategory(Intent.CATEGORY_OPENABLE);
if (tileSource.setMapFile(mapPath)) { intent.setType("*/*");
startActivityForResult(intent, SELECT_MAP_FILE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == SELECT_MAP_FILE && resultCode == Activity.RESULT_OK) {
if (data != null) {
Uri uri = data.getData();
openMap(uri);
}
}
}
private void openMap(Uri uri) {
try {
// Tile source
MapFileTileSource tileSource = new MapFileTileSource();
FileInputStream fis = (FileInputStream) getContentResolver().openInputStream(uri);
tileSource.setMapFileInputStream(fis);
// Vector layer // Vector layer
VectorTileLayer tileLayer = mapView.map().setBaseMap(tileSource); VectorTileLayer tileLayer = mapView.map().setBaseMap(tileSource);
@@ -65,7 +89,7 @@ public class GettingStarted extends Activity {
mapView.map().layers().add(new LabelLayer(mapView.map(), tileLayer)); mapView.map().layers().add(new LabelLayer(mapView.map(), tileLayer));
// Render theme // Render theme
mapView.map().setTheme(VtmThemes.DEFAULT); theme = mapView.map().setTheme(VtmThemes.DEFAULT);
// Scale bar // Scale bar
MapScaleBar mapScaleBar = new DefaultMapScaleBar(mapView.map()); MapScaleBar mapScaleBar = new DefaultMapScaleBar(mapView.map());
@@ -76,6 +100,11 @@ public class GettingStarted extends Activity {
// Note: this map position is specific to Berlin area // Note: this map position is specific to Berlin area
mapView.map().setMapPosition(52.517037, 13.38886, 1 << 12); mapView.map().setMapPosition(52.517037, 13.38886, 1 << 12);
} catch (Exception e) {
/*
* In case of map file errors avoid crash, but developers should handle these cases!
*/
e.printStackTrace();
} }
} }
@@ -94,6 +123,7 @@ public class GettingStarted extends Activity {
@Override @Override
protected void onDestroy() { protected void onDestroy() {
mapView.onDestroy(); mapView.onDestroy();
theme.dispose();
super.onDestroy(); super.onDestroy();
} }
} }

View File

@@ -0,0 +1,125 @@
/*
* Copyright 2018-2020 devemux86
* Copyright 2020 Meibes
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.android.test;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import org.oscim.android.MapView;
import org.oscim.backend.CanvasAdapter;
import org.oscim.layers.tile.buildings.BuildingLayer;
import org.oscim.layers.tile.vector.VectorTileLayer;
import org.oscim.layers.tile.vector.labeling.LabelLayer;
import org.oscim.renderer.GLViewport;
import org.oscim.scalebar.DefaultMapScaleBar;
import org.oscim.scalebar.MapScaleBar;
import org.oscim.scalebar.MapScaleBarLayer;
import org.oscim.theme.IRenderTheme;
import org.oscim.theme.VtmThemes;
import org.oscim.tiling.source.mapfile.MapFileTileSource;
import java.io.File;
/**
* You'll need a map with filename berlin.map from download.mapsforge.org in device storage.
*/
@SuppressWarnings("deprecation")
public class MapFragment extends Fragment {
private MapView mapView;
private IRenderTheme theme;
public static MapFragment newInstance() {
MapFragment instance = new MapFragment();
Bundle args = new Bundle();
instance.setArguments(args);
return instance;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_map, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mapView = new MapView(getActivity());
RelativeLayout relativeLayout = view.findViewById(R.id.mapView);
relativeLayout.addView(mapView);
// Tile source
MapFileTileSource tileSource = new MapFileTileSource();
File file = new File(getActivity().getExternalFilesDir(null), "berlin.map");
tileSource.setMapFile(file.getAbsolutePath());
// Vector layer
VectorTileLayer tileLayer = mapView.map().setBaseMap(tileSource);
// Building layer
mapView.map().layers().add(new BuildingLayer(mapView.map(), tileLayer));
// Label layer
mapView.map().layers().add(new LabelLayer(mapView.map(), tileLayer));
// Render theme
theme = mapView.map().setTheme(VtmThemes.DEFAULT);
// Scale bar
MapScaleBar mapScaleBar = new DefaultMapScaleBar(mapView.map());
MapScaleBarLayer mapScaleBarLayer = new MapScaleBarLayer(mapView.map(), mapScaleBar);
mapScaleBarLayer.getRenderer().setPosition(GLViewport.Position.BOTTOM_LEFT);
mapScaleBarLayer.getRenderer().setOffset(5 * CanvasAdapter.getScale(), 0);
mapView.map().layers().add(mapScaleBarLayer);
// Note: this map position is specific to Berlin area
mapView.map().setMapPosition(52.517037, 13.38886, 1 << 12);
}
@Override
public void onResume() {
super.onResume();
if (mapView != null) {
mapView.onResume();
}
}
@Override
public void onPause() {
if (mapView != null) {
mapView.onPause();
}
super.onPause();
}
@Override
public void onDestroyView() {
if (mapView != null) {
mapView.onDestroy();
mapView = null;
}
if (theme != null) {
theme.dispose();
theme = null;
}
super.onDestroyView();
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2018-2019 devemux86 * Copyright 2018-2020 devemux86
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software * terms of the GNU Lesser General Public License as published by the Free Software
@@ -16,10 +16,10 @@ package org.oscim.android.test;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import okhttp3.Cache;
import okhttp3.CipherSuite; import okhttp3.CipherSuite;
import okhttp3.ConnectionSpec; import okhttp3.ConnectionSpec;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import org.oscim.android.cache.TileCache;
import org.oscim.layers.tile.bitmap.BitmapTileLayer; import org.oscim.layers.tile.bitmap.BitmapTileLayer;
import org.oscim.layers.tile.buildings.BuildingLayer; import org.oscim.layers.tile.buildings.BuildingLayer;
import org.oscim.layers.tile.vector.VectorTileLayer; import org.oscim.layers.tile.vector.VectorTileLayer;
@@ -30,6 +30,7 @@ import org.oscim.tiling.source.UrlTileSource;
import org.oscim.tiling.source.bitmap.DefaultSources; import org.oscim.tiling.source.bitmap.DefaultSources;
import org.oscim.tiling.source.mvt.MapilionMvtTileSource; import org.oscim.tiling.source.mvt.MapilionMvtTileSource;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -41,13 +42,18 @@ public class MapilionMvtActivity extends MapActivity {
private static final boolean USE_CACHE = false; private static final boolean USE_CACHE = false;
private TileCache mCache;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
OkHttpClient.Builder builder = new OkHttpClient.Builder(); OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (USE_CACHE) {
// Cache the tiles into file system
File cacheDirectory = new File(getExternalCacheDir(), "tiles");
int cacheSize = 10 * 1024 * 1024; // 10 MB
Cache cache = new Cache(cacheDirectory, cacheSize);
builder.cache(cache);
}
// https://github.com/square/okhttp/issues/4053 // https://github.com/square/okhttp/issues/4053
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
@@ -71,13 +77,6 @@ public class MapilionMvtActivity extends MapActivity {
//.locale("en") //.locale("en")
.build(); .build();
if (USE_CACHE) {
// Cache the tiles into a local SQLite database
mCache = new TileCache(this, null, "tile.db");
mCache.setCacheSize(512 * (1 << 10));
tileSource.setCache(mCache);
}
VectorTileLayer l = mMap.setBaseMap(tileSource); VectorTileLayer l = mMap.setBaseMap(tileSource);
mMap.setTheme(VtmThemes.OPENMAPTILES); mMap.setTheme(VtmThemes.OPENMAPTILES);
@@ -91,12 +90,4 @@ public class MapilionMvtActivity extends MapActivity {
mMap.layers().add(new BuildingLayer(mMap, l)); mMap.layers().add(new BuildingLayer(mMap, l));
mMap.layers().add(new LabelLayer(mMap, l)); mMap.layers().add(new LabelLayer(mMap, l));
} }
@Override
protected void onDestroy() {
super.onDestroy();
if (mCache != null)
mCache.dispose();
}
} }

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright 2014 Hannes Janetzek * Copyright 2014 Hannes Janetzek
* Copyright 2016-2018 devemux86 * Copyright 2016-2020 devemux86
* Copyright 2017 Longri * Copyright 2017 Longri
* Copyright 2018 Gustl22 * Copyright 2018 Gustl22
* *
@@ -19,15 +19,14 @@
*/ */
package org.oscim.android.test; package org.oscim.android.test;
import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import org.oscim.android.theme.ContentRenderTheme;
import org.oscim.android.filepicker.FilePicker;
import org.oscim.android.filepicker.FilterByFileExtension;
import org.oscim.android.filepicker.ValidMapFile;
import org.oscim.android.filepicker.ValidRenderTheme;
import org.oscim.backend.CanvasAdapter; import org.oscim.backend.CanvasAdapter;
import org.oscim.core.MapElement; import org.oscim.core.MapElement;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
@@ -42,23 +41,26 @@ import org.oscim.layers.tile.vector.labeling.LabelLayer;
import org.oscim.renderer.BitmapRenderer; import org.oscim.renderer.BitmapRenderer;
import org.oscim.renderer.GLViewport; import org.oscim.renderer.GLViewport;
import org.oscim.renderer.bucket.RenderBuckets; import org.oscim.renderer.bucket.RenderBuckets;
import org.oscim.scalebar.DefaultMapScaleBar; import org.oscim.scalebar.*;
import org.oscim.scalebar.ImperialUnitAdapter; import org.oscim.theme.IRenderTheme;
import org.oscim.scalebar.MapScaleBar; import org.oscim.theme.ThemeFile;
import org.oscim.scalebar.MapScaleBarLayer;
import org.oscim.scalebar.MetricUnitAdapter;
import org.oscim.theme.ExternalRenderTheme;
import org.oscim.theme.ThemeUtils;
import org.oscim.theme.VtmThemes; import org.oscim.theme.VtmThemes;
import org.oscim.theme.styles.AreaStyle; import org.oscim.theme.styles.AreaStyle;
import org.oscim.theme.styles.RenderStyle; import org.oscim.theme.styles.RenderStyle;
import org.oscim.tiling.source.mapfile.MapFileTileSource; import org.oscim.tiling.source.mapfile.MapFileTileSource;
import org.oscim.tiling.source.mapfile.MapInfo; import org.oscim.tiling.source.mapfile.MapInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileInputStream;
import java.io.IOException;
public class MapsforgeActivity extends MapActivity { public class MapsforgeActivity extends MapActivity {
private static final Logger log = LoggerFactory.getLogger(MapsforgeActivity.class);
static final int SELECT_MAP_FILE = 0; static final int SELECT_MAP_FILE = 0;
static final int SELECT_THEME_FILE = SELECT_MAP_FILE + 1; static final int SELECT_THEME_FILE = 1;
private static final Tag ISSEA_TAG = new Tag("natural", "issea"); private static final Tag ISSEA_TAG = new Tag("natural", "issea");
private static final Tag NOSEA_TAG = new Tag("natural", "nosea"); private static final Tag NOSEA_TAG = new Tag("natural", "nosea");
@@ -66,7 +68,8 @@ public class MapsforgeActivity extends MapActivity {
private TileGridLayer mGridLayer; private TileGridLayer mGridLayer;
private Menu mMenu; private Menu mMenu;
private boolean mS3db; private final boolean mS3db;
IRenderTheme mTheme;
VectorTileLayer mTileLayer; VectorTileLayer mTileLayer;
public MapsforgeActivity() { public MapsforgeActivity() {
@@ -87,22 +90,10 @@ public class MapsforgeActivity extends MapActivity {
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
startActivityForResult(new Intent(this, MapFilePicker.class), Intent intent = new Intent(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT ? Intent.ACTION_OPEN_DOCUMENT : Intent.ACTION_GET_CONTENT);
SELECT_MAP_FILE); intent.addCategory(Intent.CATEGORY_OPENABLE);
} intent.setType("*/*");
startActivityForResult(intent, SELECT_MAP_FILE);
public static class MapFilePicker extends FilePicker {
public MapFilePicker() {
setFileDisplayFilter(new FilterByFileExtension(".map"));
setFileSelectFilter(new ValidMapFile());
}
}
public static class ThemeFilePicker extends FilePicker {
public ThemeFilePicker() {
setFileDisplayFilter(new FilterByFileExtension(".xml"));
setFileSelectFilter(new ValidRenderTheme());
}
} }
@Override @Override
@@ -117,33 +108,45 @@ public class MapsforgeActivity extends MapActivity {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.theme_default: case R.id.theme_default:
mMap.setTheme(VtmThemes.DEFAULT); if (mTheme != null)
mTheme.dispose();
mTheme = mMap.setTheme(VtmThemes.DEFAULT);
item.setChecked(true); item.setChecked(true);
return true; return true;
case R.id.theme_osmarender: case R.id.theme_osmarender:
mMap.setTheme(VtmThemes.OSMARENDER); if (mTheme != null)
mTheme.dispose();
mTheme = mMap.setTheme(VtmThemes.OSMARENDER);
item.setChecked(true); item.setChecked(true);
return true; return true;
case R.id.theme_osmagray: case R.id.theme_osmagray:
mMap.setTheme(VtmThemes.OSMAGRAY); if (mTheme != null)
mTheme.dispose();
mTheme = mMap.setTheme(VtmThemes.OSMAGRAY);
item.setChecked(true); item.setChecked(true);
return true; return true;
case R.id.theme_tubes: case R.id.theme_tubes:
mMap.setTheme(VtmThemes.TRONRENDER); if (mTheme != null)
mTheme.dispose();
mTheme = mMap.setTheme(VtmThemes.TRONRENDER);
item.setChecked(true); item.setChecked(true);
return true; return true;
case R.id.theme_newtron: case R.id.theme_newtron:
mMap.setTheme(VtmThemes.NEWTRON); if (mTheme != null)
mTheme.dispose();
mTheme = mMap.setTheme(VtmThemes.NEWTRON);
item.setChecked(true); item.setChecked(true);
return true; return true;
case R.id.theme_external: case R.id.theme_external:
startActivityForResult(new Intent(this, ThemeFilePicker.class), Intent intent = new Intent(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT ? Intent.ACTION_OPEN_DOCUMENT : Intent.ACTION_GET_CONTENT);
SELECT_THEME_FILE); intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
startActivityForResult(intent, SELECT_THEME_FILE);
return true; return true;
case R.id.gridlayer: case R.id.gridlayer:
@@ -165,58 +168,64 @@ public class MapsforgeActivity extends MapActivity {
} }
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == SELECT_MAP_FILE) { if (requestCode == SELECT_MAP_FILE) {
if (resultCode != RESULT_OK || intent == null || intent.getStringExtra(FilePicker.SELECTED_FILE) == null) { if (resultCode != Activity.RESULT_OK || data == null) {
finish(); finish();
return; return;
} }
MapFileTileSource mTileSource = new MapFileTileSource(); MapFileTileSource tileSource = new MapFileTileSource();
//mTileSource.setPreferredLanguage("en"); //tileSource.setPreferredLanguage("en");
String file = intent.getStringExtra(FilePicker.SELECTED_FILE);
if (mTileSource.setMapFile(file)) {
mTileLayer = mMap.setBaseMap(mTileSource); try {
loadTheme(null); Uri uri = data.getData();
FileInputStream fis = (FileInputStream) getContentResolver().openInputStream(uri);
if (mS3db) tileSource.setMapFileInputStream(fis);
mMap.layers().add(new S3DBLayer(mMap, mTileLayer)); } catch (IOException e) {
else log.error(e.getMessage());
mMap.layers().add(new BuildingLayer(mMap, mTileLayer)); finish();
mMap.layers().add(new LabelLayer(mMap, mTileLayer));
DefaultMapScaleBar mMapScaleBar = new DefaultMapScaleBar(mMap);
mMapScaleBar.setScaleBarMode(DefaultMapScaleBar.ScaleBarMode.BOTH);
mMapScaleBar.setDistanceUnitAdapter(MetricUnitAdapter.INSTANCE);
mMapScaleBar.setSecondaryDistanceUnitAdapter(ImperialUnitAdapter.INSTANCE);
mMapScaleBar.setScaleBarPosition(MapScaleBar.ScaleBarPosition.BOTTOM_LEFT);
MapScaleBarLayer mapScaleBarLayer = new MapScaleBarLayer(mMap, mMapScaleBar);
BitmapRenderer renderer = mapScaleBarLayer.getRenderer();
renderer.setPosition(GLViewport.Position.BOTTOM_LEFT);
renderer.setOffset(5 * CanvasAdapter.getScale(), 0);
mMap.layers().add(mapScaleBarLayer);
MapInfo info = mTileSource.getMapInfo();
if (!info.boundingBox.contains(mMap.getMapPosition().getGeoPoint())) {
MapPosition pos = new MapPosition();
pos.setByBoundingBox(info.boundingBox, Tile.SIZE * 4, Tile.SIZE * 4);
mMap.setMapPosition(pos);
mPrefs.clear();
}
}
} else if (requestCode == SELECT_THEME_FILE) {
if (resultCode != RESULT_OK || intent == null || intent.getStringExtra(FilePicker.SELECTED_FILE) == null) {
return; return;
} }
String file = intent.getStringExtra(FilePicker.SELECTED_FILE); mTileLayer = mMap.setBaseMap(tileSource);
ExternalRenderTheme externalRenderTheme = new ExternalRenderTheme(file); loadTheme(null);
if (mS3db)
mMap.layers().add(new S3DBLayer(mMap, mTileLayer));
else
mMap.layers().add(new BuildingLayer(mMap, mTileLayer));
mMap.layers().add(new LabelLayer(mMap, mTileLayer));
DefaultMapScaleBar mapScaleBar = new DefaultMapScaleBar(mMap);
mapScaleBar.setScaleBarMode(DefaultMapScaleBar.ScaleBarMode.BOTH);
mapScaleBar.setDistanceUnitAdapter(MetricUnitAdapter.INSTANCE);
mapScaleBar.setSecondaryDistanceUnitAdapter(ImperialUnitAdapter.INSTANCE);
mapScaleBar.setScaleBarPosition(MapScaleBar.ScaleBarPosition.BOTTOM_LEFT);
MapScaleBarLayer mapScaleBarLayer = new MapScaleBarLayer(mMap, mapScaleBar);
BitmapRenderer renderer = mapScaleBarLayer.getRenderer();
renderer.setPosition(GLViewport.Position.BOTTOM_LEFT);
renderer.setOffset(5 * CanvasAdapter.getScale(), 0);
mMap.layers().add(mapScaleBarLayer);
MapInfo info = tileSource.getMapInfo();
if (!info.boundingBox.contains(mMap.getMapPosition().getGeoPoint())) {
MapPosition pos = new MapPosition();
pos.setByBoundingBox(info.boundingBox, Tile.SIZE * 4, Tile.SIZE * 4);
mMap.setMapPosition(pos);
mPrefs.clear();
}
} else if (requestCode == SELECT_THEME_FILE) {
if (resultCode != Activity.RESULT_OK || data == null)
return;
Uri uri = data.getData();
ThemeFile theme = new ContentRenderTheme(getContentResolver(), "", uri);
// Use tessellation with sea and land for Mapsforge themes // Use tessellation with sea and land for Mapsforge themes
if (ThemeUtils.isMapsforgeTheme(externalRenderTheme)) { if (theme.isMapsforgeTheme()) {
mTileLayer.addHook(new VectorTileLayer.TileLoaderThemeHook() { mTileLayer.addHook(new VectorTileLayer.TileLoaderThemeHook() {
@Override @Override
public boolean process(MapTile tile, RenderBuckets buckets, MapElement element, RenderStyle style, int level) { public boolean process(MapTile tile, RenderBuckets buckets, MapElement element, RenderStyle style, int level) {
@@ -233,12 +242,16 @@ public class MapsforgeActivity extends MapActivity {
}); });
} }
mMap.setTheme(externalRenderTheme); if (mTheme != null)
mTheme.dispose();
mTheme = mMap.setTheme(theme);
mMenu.findItem(R.id.theme_external).setChecked(true); mMenu.findItem(R.id.theme_external).setChecked(true);
} }
} }
protected void loadTheme(final String styleId) { protected void loadTheme(final String styleId) {
mMap.setTheme(VtmThemes.DEFAULT); if (mTheme != null)
mTheme.dispose();
mTheme = mMap.setTheme(VtmThemes.DEFAULT);
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2017 devemux86 * Copyright 2016-2020 devemux86
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software * terms of the GNU Lesser General Public License as published by the Free Software
@@ -17,7 +17,6 @@ package org.oscim.android.test;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.Toast; import android.widget.Toast;
import org.oscim.android.theme.AssetsRenderTheme; import org.oscim.android.theme.AssetsRenderTheme;
import org.oscim.theme.XmlRenderThemeMenuCallback; import org.oscim.theme.XmlRenderThemeMenuCallback;
import org.oscim.theme.XmlRenderThemeStyleLayer; import org.oscim.theme.XmlRenderThemeStyleLayer;
@@ -58,7 +57,9 @@ public class MapsforgeStyleActivity extends MapsforgeActivity {
@Override @Override
protected void loadTheme(final String styleId) { protected void loadTheme(final String styleId) {
mMap.setTheme(new AssetsRenderTheme(getAssets(), "", "vtm/stylemenu.xml", new XmlRenderThemeMenuCallback() { if (mTheme != null)
mTheme.dispose();
mTheme = mMap.setTheme(new AssetsRenderTheme(getAssets(), "", "vtm/stylemenu.xml", new XmlRenderThemeMenuCallback() {
@Override @Override
public Set<String> getCategories(XmlRenderThemeStyleMenu renderThemeStyleMenu) { public Set<String> getCategories(XmlRenderThemeStyleMenu renderThemeStyleMenu) {
// Use the selected style or the default // Use the selected style or the default

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2017-2018 devemux86 * Copyright 2017-2020 devemux86
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software * terms of the GNU Lesser General Public License as published by the Free Software
@@ -15,8 +15,8 @@
package org.oscim.android.test; package org.oscim.android.test;
import android.os.Bundle; import android.os.Bundle;
import okhttp3.Cache;
import org.oscim.android.cache.TileCache; import okhttp3.OkHttpClient;
import org.oscim.layers.tile.buildings.BuildingLayer; import org.oscim.layers.tile.buildings.BuildingLayer;
import org.oscim.layers.tile.vector.VectorTileLayer; import org.oscim.layers.tile.vector.VectorTileLayer;
import org.oscim.layers.tile.vector.labeling.LabelLayer; import org.oscim.layers.tile.vector.labeling.LabelLayer;
@@ -25,41 +25,35 @@ import org.oscim.tiling.source.OkHttpEngine;
import org.oscim.tiling.source.UrlTileSource; import org.oscim.tiling.source.UrlTileSource;
import org.oscim.tiling.source.geojson.MapzenGeojsonTileSource; import org.oscim.tiling.source.geojson.MapzenGeojsonTileSource;
import java.io.File;
public class MapzenGeojsonActivity extends MapActivity { public class MapzenGeojsonActivity extends MapActivity {
private static final boolean USE_CACHE = false; private static final boolean USE_CACHE = false;
private TileCache mCache;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (USE_CACHE) {
// Cache the tiles into file system
File cacheDirectory = new File(getExternalCacheDir(), "tiles");
int cacheSize = 10 * 1024 * 1024; // 10 MB
Cache cache = new Cache(cacheDirectory, cacheSize);
builder.cache(cache);
}
UrlTileSource tileSource = MapzenGeojsonTileSource.builder() UrlTileSource tileSource = MapzenGeojsonTileSource.builder()
.apiKey("xxxxxxx") // Put a proper API key .apiKey("xxxxxxx") // Put a proper API key
.httpFactory(new OkHttpEngine.OkHttpFactory()) .httpFactory(new OkHttpEngine.OkHttpFactory(builder))
//.locale("en") //.locale("en")
.build(); .build();
if (USE_CACHE) {
// Cache the tiles into a local SQLite database
mCache = new TileCache(this, null, "tile.db");
mCache.setCacheSize(512 * (1 << 10));
tileSource.setCache(mCache);
}
VectorTileLayer l = mMap.setBaseMap(tileSource); VectorTileLayer l = mMap.setBaseMap(tileSource);
mMap.setTheme(VtmThemes.MAPZEN); mMap.setTheme(VtmThemes.MAPZEN);
mMap.layers().add(new BuildingLayer(mMap, l)); mMap.layers().add(new BuildingLayer(mMap, l));
mMap.layers().add(new LabelLayer(mMap, l)); mMap.layers().add(new LabelLayer(mMap, l));
} }
@Override
protected void onDestroy() {
super.onDestroy();
if (mCache != null)
mCache.dispose();
}
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2018 devemux86 * Copyright 2016-2020 devemux86
* Copyright 2017 Mathieu De Brito * Copyright 2017 Mathieu De Brito
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
@@ -16,8 +16,8 @@
package org.oscim.android.test; package org.oscim.android.test;
import android.os.Bundle; import android.os.Bundle;
import okhttp3.Cache;
import org.oscim.android.cache.TileCache; import okhttp3.OkHttpClient;
import org.oscim.layers.tile.buildings.BuildingLayer; import org.oscim.layers.tile.buildings.BuildingLayer;
import org.oscim.layers.tile.vector.VectorTileLayer; import org.oscim.layers.tile.vector.VectorTileLayer;
import org.oscim.layers.tile.vector.labeling.LabelLayer; import org.oscim.layers.tile.vector.labeling.LabelLayer;
@@ -26,41 +26,35 @@ import org.oscim.tiling.source.OkHttpEngine;
import org.oscim.tiling.source.UrlTileSource; import org.oscim.tiling.source.UrlTileSource;
import org.oscim.tiling.source.mvt.MapzenMvtTileSource; import org.oscim.tiling.source.mvt.MapzenMvtTileSource;
import java.io.File;
public class MapzenMvtActivity extends MapActivity { public class MapzenMvtActivity extends MapActivity {
private static final boolean USE_CACHE = false; private static final boolean USE_CACHE = false;
private TileCache mCache;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (USE_CACHE) {
// Cache the tiles into file system
File cacheDirectory = new File(getExternalCacheDir(), "tiles");
int cacheSize = 10 * 1024 * 1024; // 10 MB
Cache cache = new Cache(cacheDirectory, cacheSize);
builder.cache(cache);
}
UrlTileSource tileSource = MapzenMvtTileSource.builder() UrlTileSource tileSource = MapzenMvtTileSource.builder()
.apiKey("xxxxxxx") // Put a proper API key .apiKey("xxxxxxx") // Put a proper API key
.httpFactory(new OkHttpEngine.OkHttpFactory()) .httpFactory(new OkHttpEngine.OkHttpFactory(builder))
//.locale("en") //.locale("en")
.build(); .build();
if (USE_CACHE) {
// Cache the tiles into a local SQLite database
mCache = new TileCache(this, null, "tile.db");
mCache.setCacheSize(512 * (1 << 10));
tileSource.setCache(mCache);
}
VectorTileLayer l = mMap.setBaseMap(tileSource); VectorTileLayer l = mMap.setBaseMap(tileSource);
mMap.setTheme(VtmThemes.MAPZEN); mMap.setTheme(VtmThemes.MAPZEN);
mMap.layers().add(new BuildingLayer(mMap, l)); mMap.layers().add(new BuildingLayer(mMap, l));
mMap.layers().add(new LabelLayer(mMap, l)); mMap.layers().add(new LabelLayer(mMap, l));
} }
@Override
protected void onDestroy() {
super.onDestroy();
if (mCache != null)
mCache.dispose();
}
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2018 devemux86 * Copyright 2018-2020 devemux86
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software * terms of the GNU Lesser General Public License as published by the Free Software
@@ -15,8 +15,8 @@
package org.oscim.android.test; package org.oscim.android.test;
import android.os.Bundle; import android.os.Bundle;
import okhttp3.Cache;
import org.oscim.android.cache.TileCache; import okhttp3.OkHttpClient;
import org.oscim.layers.tile.buildings.BuildingLayer; import org.oscim.layers.tile.buildings.BuildingLayer;
import org.oscim.layers.tile.vector.VectorTileLayer; import org.oscim.layers.tile.vector.VectorTileLayer;
import org.oscim.layers.tile.vector.labeling.LabelLayer; import org.oscim.layers.tile.vector.labeling.LabelLayer;
@@ -25,41 +25,35 @@ import org.oscim.tiling.source.OkHttpEngine;
import org.oscim.tiling.source.UrlTileSource; import org.oscim.tiling.source.UrlTileSource;
import org.oscim.tiling.source.geojson.NextzenGeojsonTileSource; import org.oscim.tiling.source.geojson.NextzenGeojsonTileSource;
import java.io.File;
public class NextzenGeojsonActivity extends MapActivity { public class NextzenGeojsonActivity extends MapActivity {
private static final boolean USE_CACHE = false; private static final boolean USE_CACHE = false;
private TileCache mCache;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (USE_CACHE) {
// Cache the tiles into file system
File cacheDirectory = new File(getExternalCacheDir(), "tiles");
int cacheSize = 10 * 1024 * 1024; // 10 MB
Cache cache = new Cache(cacheDirectory, cacheSize);
builder.cache(cache);
}
UrlTileSource tileSource = NextzenGeojsonTileSource.builder() UrlTileSource tileSource = NextzenGeojsonTileSource.builder()
.apiKey("xxxxxxx") // Put a proper API key .apiKey("xxxxxxx") // Put a proper API key
.httpFactory(new OkHttpEngine.OkHttpFactory()) .httpFactory(new OkHttpEngine.OkHttpFactory(builder))
//.locale("en") //.locale("en")
.build(); .build();
if (USE_CACHE) {
// Cache the tiles into a local SQLite database
mCache = new TileCache(this, null, "tile.db");
mCache.setCacheSize(512 * (1 << 10));
tileSource.setCache(mCache);
}
VectorTileLayer l = mMap.setBaseMap(tileSource); VectorTileLayer l = mMap.setBaseMap(tileSource);
mMap.setTheme(VtmThemes.MAPZEN); mMap.setTheme(VtmThemes.MAPZEN);
mMap.layers().add(new BuildingLayer(mMap, l)); mMap.layers().add(new BuildingLayer(mMap, l));
mMap.layers().add(new LabelLayer(mMap, l)); mMap.layers().add(new LabelLayer(mMap, l));
} }
@Override
protected void onDestroy() {
super.onDestroy();
if (mCache != null)
mCache.dispose();
}
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2018 devemux86 * Copyright 2018-2020 devemux86
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software * terms of the GNU Lesser General Public License as published by the Free Software
@@ -15,8 +15,8 @@
package org.oscim.android.test; package org.oscim.android.test;
import android.os.Bundle; import android.os.Bundle;
import okhttp3.Cache;
import org.oscim.android.cache.TileCache; import okhttp3.OkHttpClient;
import org.oscim.layers.tile.buildings.BuildingLayer; import org.oscim.layers.tile.buildings.BuildingLayer;
import org.oscim.layers.tile.vector.VectorTileLayer; import org.oscim.layers.tile.vector.VectorTileLayer;
import org.oscim.layers.tile.vector.labeling.LabelLayer; import org.oscim.layers.tile.vector.labeling.LabelLayer;
@@ -25,41 +25,35 @@ import org.oscim.tiling.source.OkHttpEngine;
import org.oscim.tiling.source.UrlTileSource; import org.oscim.tiling.source.UrlTileSource;
import org.oscim.tiling.source.mvt.NextzenMvtTileSource; import org.oscim.tiling.source.mvt.NextzenMvtTileSource;
import java.io.File;
public class NextzenMvtActivity extends MapActivity { public class NextzenMvtActivity extends MapActivity {
private static final boolean USE_CACHE = false; private static final boolean USE_CACHE = false;
private TileCache mCache;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (USE_CACHE) {
// Cache the tiles into file system
File cacheDirectory = new File(getExternalCacheDir(), "tiles");
int cacheSize = 10 * 1024 * 1024; // 10 MB
Cache cache = new Cache(cacheDirectory, cacheSize);
builder.cache(cache);
}
UrlTileSource tileSource = NextzenMvtTileSource.builder() UrlTileSource tileSource = NextzenMvtTileSource.builder()
.apiKey("xxxxxxx") // Put a proper API key .apiKey("xxxxxxx") // Put a proper API key
.httpFactory(new OkHttpEngine.OkHttpFactory()) .httpFactory(new OkHttpEngine.OkHttpFactory(builder))
//.locale("en") //.locale("en")
.build(); .build();
if (USE_CACHE) {
// Cache the tiles into a local SQLite database
mCache = new TileCache(this, null, "tile.db");
mCache.setCacheSize(512 * (1 << 10));
tileSource.setCache(mCache);
}
VectorTileLayer l = mMap.setBaseMap(tileSource); VectorTileLayer l = mMap.setBaseMap(tileSource);
mMap.setTheme(VtmThemes.MAPZEN); mMap.setTheme(VtmThemes.MAPZEN);
mMap.layers().add(new BuildingLayer(mMap, l)); mMap.layers().add(new BuildingLayer(mMap, l));
mMap.layers().add(new LabelLayer(mMap, l)); mMap.layers().add(new LabelLayer(mMap, l));
} }
@Override
protected void onDestroy() {
super.onDestroy();
if (mCache != null)
mCache.dispose();
}
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2018 devemux86 * Copyright 2016-2020 devemux86
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software * terms of the GNU Lesser General Public License as published by the Free Software
@@ -15,8 +15,8 @@
package org.oscim.android.test; package org.oscim.android.test;
import android.os.Bundle; import android.os.Bundle;
import okhttp3.Cache;
import org.oscim.android.cache.TileCache; import okhttp3.OkHttpClient;
import org.oscim.layers.tile.buildings.BuildingLayer; import org.oscim.layers.tile.buildings.BuildingLayer;
import org.oscim.layers.tile.vector.VectorTileLayer; import org.oscim.layers.tile.vector.VectorTileLayer;
import org.oscim.layers.tile.vector.labeling.LabelLayer; import org.oscim.layers.tile.vector.labeling.LabelLayer;
@@ -25,41 +25,35 @@ import org.oscim.tiling.source.OkHttpEngine;
import org.oscim.tiling.source.UrlTileSource; import org.oscim.tiling.source.UrlTileSource;
import org.oscim.tiling.source.mvt.OpenMapTilesMvtTileSource; import org.oscim.tiling.source.mvt.OpenMapTilesMvtTileSource;
import java.io.File;
public class OpenMapTilesMvtActivity extends MapActivity { public class OpenMapTilesMvtActivity extends MapActivity {
private static final boolean USE_CACHE = false; private static final boolean USE_CACHE = false;
private TileCache mCache;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (USE_CACHE) {
// Cache the tiles into file system
File cacheDirectory = new File(getExternalCacheDir(), "tiles");
int cacheSize = 10 * 1024 * 1024; // 10 MB
Cache cache = new Cache(cacheDirectory, cacheSize);
builder.cache(cache);
}
UrlTileSource tileSource = OpenMapTilesMvtTileSource.builder() UrlTileSource tileSource = OpenMapTilesMvtTileSource.builder()
.apiKey("xxxxxxx") // Put a proper API key .apiKey("xxxxxxx") // Put a proper API key
.httpFactory(new OkHttpEngine.OkHttpFactory()) .httpFactory(new OkHttpEngine.OkHttpFactory(builder))
//.locale("en") //.locale("en")
.build(); .build();
if (USE_CACHE) {
// Cache the tiles into a local SQLite database
mCache = new TileCache(this, null, "tile.db");
mCache.setCacheSize(512 * (1 << 10));
tileSource.setCache(mCache);
}
VectorTileLayer l = mMap.setBaseMap(tileSource); VectorTileLayer l = mMap.setBaseMap(tileSource);
mMap.setTheme(VtmThemes.OPENMAPTILES); mMap.setTheme(VtmThemes.OPENMAPTILES);
mMap.layers().add(new BuildingLayer(mMap, l)); mMap.layers().add(new BuildingLayer(mMap, l));
mMap.layers().add(new LabelLayer(mMap, l)); mMap.layers().add(new LabelLayer(mMap, l));
} }
@Override
protected void onDestroy() {
super.onDestroy();
if (mCache != null)
mCache.dispose();
}
} }

View File

@@ -28,7 +28,6 @@ package org.oscim.android.test;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.Gravity; import android.view.Gravity;
@@ -126,5 +125,6 @@ public class Samples extends Activity {
linearLayout.addView(createButton(GdxPoi3DActivity.class)); linearLayout.addView(createButton(GdxPoi3DActivity.class));
linearLayout.addView(createButton(OverpassActivity.class)); linearLayout.addView(createButton(OverpassActivity.class));
linearLayout.addView(createButton(ClusterMarkerOverlayActivity.class)); linearLayout.addView(createButton(ClusterMarkerOverlayActivity.class));
linearLayout.addView(createButton(FragmentActivity.class));
} }
} }

View File

@@ -0,0 +1,109 @@
/*
* Copyright 2020 devemux86
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.android.theme;
import android.content.ContentResolver;
import android.net.Uri;
import org.oscim.theme.IRenderTheme.ThemeException;
import org.oscim.theme.ThemeFile;
import org.oscim.theme.ThemeUtils;
import org.oscim.theme.XmlRenderThemeMenuCallback;
import org.oscim.utils.Utils;
import java.io.IOException;
import java.io.InputStream;
/**
* An ContentRenderTheme allows for customizing the rendering style of the map
* via an XML from the Android content providers.
*/
public class ContentRenderTheme implements ThemeFile {
private static final long serialVersionUID = 1L;
private final ContentResolver mContentResolver;
private XmlRenderThemeMenuCallback mMenuCallback;
private final String mRelativePathPrefix;
private final Uri mUri;
/**
* @param contentResolver the Android content resolver.
* @param relativePathPrefix the prefix for all relative resource paths.
* @param uri the XML render theme URI.
* @throws ThemeException if an error occurs while reading the render theme XML.
*/
public ContentRenderTheme(ContentResolver contentResolver, String relativePathPrefix, Uri uri) throws ThemeException {
this(contentResolver, relativePathPrefix, uri, null);
}
/**
* @param contentResolver the Android content resolver.
* @param relativePathPrefix the prefix for all relative resource paths.
* @param uri the XML render theme URI.
* @param menuCallback the interface callback to create a settings menu on the fly.
* @throws ThemeException if an error occurs while reading the render theme XML.
*/
public ContentRenderTheme(ContentResolver contentResolver, String relativePathPrefix, Uri uri, XmlRenderThemeMenuCallback menuCallback) throws ThemeException {
mContentResolver = contentResolver;
mRelativePathPrefix = relativePathPrefix;
mUri = uri;
mMenuCallback = menuCallback;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (!(obj instanceof ContentRenderTheme)) {
return false;
}
ContentRenderTheme other = (ContentRenderTheme) obj;
if (getRenderThemeAsStream() != other.getRenderThemeAsStream()) {
return false;
}
if (!Utils.equals(mRelativePathPrefix, other.mRelativePathPrefix)) {
return false;
}
return true;
}
@Override
public XmlRenderThemeMenuCallback getMenuCallback() {
return mMenuCallback;
}
@Override
public String getRelativePathPrefix() {
return mRelativePathPrefix;
}
@Override
public InputStream getRenderThemeAsStream() throws ThemeException {
try {
return mContentResolver.openInputStream(mUri);
} catch (IOException e) {
throw new ThemeException(e.getMessage());
}
}
@Override
public boolean isMapsforgeTheme() {
return ThemeUtils.isMapsforgeTheme(this);
}
@Override
public void setMenuCallback(XmlRenderThemeMenuCallback menuCallback) {
mMenuCallback = menuCallback;
}
}

View File

@@ -15,6 +15,7 @@
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/application_name" android:label="@string/application_name"
android:requestLegacyExternalStorage="true"
android:usesCleartextTraffic="true"> android:usesCleartextTraffic="true">
<!-- android:theme="@style/Theme.TileMap" --> <!-- android:theme="@style/Theme.TileMap" -->

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright 2010, 2011, 2012 mapsforge.org * Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2016 devemux86 * Copyright 2016-2020 devemux86
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software * terms of the GNU Lesser General Public License as published by the Free Software
@@ -15,40 +15,30 @@
*/ */
package org.oscim.app.filefilter; package org.oscim.app.filefilter;
import org.oscim.theme.ExternalRenderTheme; import org.oscim.theme.ThemeLoader;
import org.oscim.theme.ThemeFile;
import org.oscim.theme.XmlThemeBuilder;
import org.oscim.tiling.TileSource.OpenResult; import org.oscim.tiling.TileSource.OpenResult;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import java.io.File; import java.io.File;
import javax.xml.parsers.SAXParserFactory;
/** /**
* Accepts all valid render theme XML files. * Accepts all valid render theme XML files.
*/ */
public final class ValidRenderTheme implements ValidFileFilter { public final class ValidRenderTheme implements ValidFileFilter {
private OpenResult openResult; private OpenResult mOpenResult;
@Override @Override
public boolean accept(File file) { public boolean accept(File file) {
try { try {
ThemeFile theme = new ExternalRenderTheme(file.getAbsolutePath()); ThemeLoader.load(file.getAbsolutePath());
XmlThemeBuilder renderThemeHandler = new XmlThemeBuilder(theme); mOpenResult = OpenResult.SUCCESS;
XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
xmlReader.setContentHandler(renderThemeHandler);
xmlReader.parse(new InputSource(theme.getRenderThemeAsStream()));
this.openResult = OpenResult.SUCCESS;
} catch (Exception e) { } catch (Exception e) {
this.openResult = new OpenResult(e.getMessage()); mOpenResult = new OpenResult(e.getMessage());
} }
return this.openResult.isSuccess(); return mOpenResult.isSuccess();
} }
@Override @Override
public OpenResult getFileOpenResult() { public OpenResult getFileOpenResult() {
return this.openResult; return mOpenResult;
} }
} }

View File

@@ -45,7 +45,7 @@ public class ExternalRenderThemeTest extends GdxMapApp {
try { try {
IRenderTheme theme = ThemeLoader.load(name); IRenderTheme theme = ThemeLoader.load(name);
mapLayer.setRenderTheme(theme); mapLayer.setTheme(theme);
MapRenderer.setBackgroundColor(theme.getMapBackground()); MapRenderer.setBackgroundColor(theme.getMapBackground());
} catch (ThemeException e) { } catch (ThemeException e) {
e.printStackTrace(); e.printStackTrace();
@@ -80,7 +80,7 @@ public class ExternalRenderThemeTest extends GdxMapApp {
// IRenderTheme theme = // IRenderTheme theme =
// ThemeLoader.load("themes/elevate/theme.xml"); // ThemeLoader.load("themes/elevate/theme.xml");
// IRenderTheme theme = ThemeLoader.load("themes/vmap/theme.xml"); // IRenderTheme theme = ThemeLoader.load("themes/vmap/theme.xml");
l.setRenderTheme(theme); l.setTheme(theme);
MapRenderer.setBackgroundColor(theme.getMapBackground()); MapRenderer.setBackgroundColor(theme.getMapBackground());
} catch (ThemeException e) { } catch (ThemeException e) {
e.printStackTrace(); e.printStackTrace();

View File

@@ -39,7 +39,7 @@ public class ThemeTest extends GdxMapApp {
VectorTileLayer l = mMap.setBaseMap(ts); VectorTileLayer l = mMap.setBaseMap(ts);
l.setRenderTheme(new RenderTheme()); l.setTheme(new RenderTheme());
MapRenderer.setBackgroundColor(0xffcccccc); MapRenderer.setBackgroundColor(0xffcccccc);

View File

@@ -10,11 +10,11 @@ dependencies {
implementation 'com.fifesoft:rsyntaxtextarea:2.6.1' implementation 'com.fifesoft:rsyntaxtextarea:2.6.1'
implementation 'com.jtattoo:JTattoo:1.6.11' implementation 'com.jtattoo:JTattoo:1.6.11'
implementation 'org.mapsforge:mapsforge-core:0.14.0' implementation 'org.mapsforge:mapsforge-core:0.15.0'
implementation 'org.mapsforge:mapsforge-map:0.14.0' implementation 'org.mapsforge:mapsforge-map:0.15.0'
implementation 'org.mapsforge:mapsforge-map-awt:0.14.0' implementation 'org.mapsforge:mapsforge-map-awt:0.15.0'
implementation 'org.mapsforge:mapsforge-map-reader:0.14.0' implementation 'org.mapsforge:mapsforge-map-reader:0.15.0'
implementation 'org.mapsforge:mapsforge-themes:0.14.0' implementation 'org.mapsforge:mapsforge-themes:0.15.0'
implementation 'net.sf.kxml:kxml2:2.3.0' implementation 'net.sf.kxml:kxml2:2.3.0'
} }

View File

@@ -4,13 +4,13 @@ buildscript {
} }
dependencies { dependencies {
classpath 'org.wisepersist:gwt-gradle-plugin:1.0.13' classpath 'org.wisepersist:gwt-gradle-plugin:1.0.13'
classpath 'org.akhikhl.gretty:gretty:2.0.0' classpath 'org.gretty:gretty:3.0.3'
} }
} }
apply plugin: 'gwt' apply plugin: 'gwt'
apply plugin: 'war' apply plugin: 'war'
apply plugin: 'org.akhikhl.gretty' apply plugin: 'org.gretty'
sourceSets { sourceSets {
main.java.srcDirs = ['src'] main.java.srcDirs = ['src']

View File

@@ -4,13 +4,13 @@ buildscript {
} }
dependencies { dependencies {
classpath 'org.wisepersist:gwt-gradle-plugin:1.0.13' classpath 'org.wisepersist:gwt-gradle-plugin:1.0.13'
classpath 'org.akhikhl.gretty:gretty:2.0.0' classpath 'org.gretty:gretty:3.0.3'
} }
} }
apply plugin: 'gwt' apply plugin: 'gwt'
apply plugin: 'war' apply plugin: 'war'
apply plugin: 'org.akhikhl.gretty' apply plugin: 'org.gretty'
sourceSets { sourceSets {
main.java.srcDirs = ['src'] main.java.srcDirs = ['src']

View File

@@ -75,6 +75,9 @@ gwt {
//} //}
javadoc { javadoc {
if (JavaVersion.current().isJava9Compatible()) {
options.addStringOption("-release", "8")
}
options.addStringOption("sourcepath", "") options.addStringOption("sourcepath", "")
} }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,76 @@
/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/
// for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/)
package org.xmlpull.v1;
/**
* This exception is thrown to signal XML Pull Parser related faults.
*
* @author <a href="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
*/
public class XmlPullParserException extends Exception {
protected Throwable detail;
protected int row = -1;
protected int column = -1;
/* public XmlPullParserException() {
}*/
public XmlPullParserException(String s) {
super(s);
}
/*
public XmlPullParserException(String s, Throwable thrwble) {
super(s);
this.detail = thrwble;
}
public XmlPullParserException(String s, int row, int column) {
super(s);
this.row = row;
this.column = column;
}
*/
public XmlPullParserException(String msg, XmlPullParser parser, Throwable chain) {
super ((msg == null ? "" : msg+" ")
+ (parser == null ? "" : "(position:"+parser.getPositionDescription()+") ")
+ (chain == null ? "" : "caused by: "+chain));
if (parser != null) {
this.row = parser.getLineNumber();
this.column = parser.getColumnNumber();
}
this.detail = chain;
}
public Throwable getDetail() { return detail; }
// public void setDetail(Throwable cause) { this.detail = cause; }
public int getLineNumber() { return row; }
public int getColumnNumber() { return column; }
/*
public String getMessage() {
if(detail == null)
return super.getMessage();
else
return super.getMessage() + "; nested exception is: \n\t"
+ detail.getMessage();
}
*/
//NOTE: code that prints this and detail is difficult in J2ME
public void printStackTrace() {
if (detail == null) {
super.printStackTrace();
} else {
synchronized(System.err) {
System.err.println(super.getMessage() + "; nested exception is:");
detail.printStackTrace();
}
}
}
}

View File

@@ -0,0 +1,237 @@
/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/
// for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/)
package org.xmlpull.v1;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* This class is used to create implementations of XML Pull Parser defined in XMPULL V1 API.
*
* @see XmlPullParser
*
* @author <a href="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
* @author Stefan Haustein
*/
public class XmlPullParserFactory {
public static final String PROPERTY_NAME = "org.xmlpull.v1.XmlPullParserFactory";
protected ArrayList parserClasses;
protected ArrayList serializerClasses;
/** Unused, but we have to keep it because it's public API. */
protected String classNamesLocation = null;
// features are kept there
// TODO: This can't be made final because it's a public API.
protected HashMap<String, Boolean> features = new HashMap<String, Boolean>();
/**
* Protected constructor to be called by factory implementations.
*/
protected XmlPullParserFactory() {
parserClasses = new ArrayList<String>();
serializerClasses = new ArrayList<String>();
// GWT
/*try {
parserClasses.add(Class.forName("com.android.org.kxml2.io.KXmlParser"));
serializerClasses.add(Class.forName("com.android.org.kxml2.io.KXmlSerializer"));
} catch (ClassNotFoundException e) {
throw new AssertionError();
}*/
}
/**
* Set the features to be set when XML Pull Parser is created by this factory.
* <p><b>NOTE:</b> factory features are not used for XML Serializer.
*
* @param name string with URI identifying feature
* @param state if true feature will be set; if false will be ignored
*/
public void setFeature(String name, boolean state) throws XmlPullParserException {
features.put(name, state);
}
/**
* Return the current value of the feature with given name.
* <p><b>NOTE:</b> factory features are not used for XML Serializer.
*
* @param name The name of feature to be retrieved.
* @return The value of named feature.
* Unknown features are <string>always</strong> returned as false
*/
public boolean getFeature(String name) {
Boolean value = features.get(name);
return value != null ? value.booleanValue() : false;
}
/**
* Specifies that the parser produced by this factory will provide
* support for XML namespaces.
* By default the value of this is set to false.
*
* @param awareness true if the parser produced by this code
* will provide support for XML namespaces; false otherwise.
*/
public void setNamespaceAware(boolean awareness) {
features.put (XmlPullParser.FEATURE_PROCESS_NAMESPACES, awareness);
}
/**
* Indicates whether or not the factory is configured to produce
* parsers which are namespace aware
* (it simply set feature XmlPullParser.FEATURE_PROCESS_NAMESPACES to true or false).
*
* @return true if the factory is configured to produce parsers
* which are namespace aware; false otherwise.
*/
public boolean isNamespaceAware() {
return getFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES);
}
/**
* Specifies that the parser produced by this factory will be validating
* (it simply set feature XmlPullParser.FEATURE_VALIDATION to true or false).
*
* By default the value of this is set to false.
*
* @param validating - if true the parsers created by this factory must be validating.
*/
public void setValidating(boolean validating) {
features.put(XmlPullParser.FEATURE_VALIDATION, validating);
}
/**
* Indicates whether or not the factory is configured to produce parsers
* which validate the XML content during parse.
*
* @return true if the factory is configured to produce parsers
* which validate the XML content during parse; false otherwise.
*/
public boolean isValidating() {
return getFeature(XmlPullParser.FEATURE_VALIDATION);
}
/**
* Creates a new instance of a XML Pull Parser
* using the currently configured factory features.
*
* @return A new instance of a XML Pull Parser.
*/
public XmlPullParser newPullParser() throws XmlPullParserException {
final XmlPullParser pp = getParserInstance();
for (Map.Entry<String, Boolean> entry : features.entrySet()) {
// NOTE: This test is needed for compatibility reasons. We guarantee
// that we only set a feature on a parser if its value is true.
if (entry.getValue()) {
pp.setFeature(entry.getKey(), entry.getValue());
}
}
return pp;
}
private XmlPullParser getParserInstance() throws XmlPullParserException {
ArrayList<Exception> exceptions = null;
if (parserClasses != null && !parserClasses.isEmpty()) {
exceptions = new ArrayList<Exception>();
for (Object o : parserClasses) {
// GWT
/*try {
if (o != null) {
Class<?> parserClass = (Class<?>) o;
return (XmlPullParser) parserClass.newInstance();
}
} catch (InstantiationException e) {
exceptions.add(e);
} catch (IllegalAccessException e) {
exceptions.add(e);
} catch (ClassCastException e) {
exceptions.add(e);
}*/
}
}
throw newInstantiationException("Invalid parser class list", exceptions);
}
private XmlSerializer getSerializerInstance() throws XmlPullParserException {
ArrayList<Exception> exceptions = null;
if (serializerClasses != null && !serializerClasses.isEmpty()) {
exceptions = new ArrayList<Exception>();
for (Object o : serializerClasses) {
// GWT
/*try {
if (o != null) {
Class<?> serializerClass = (Class<?>) o;
return (XmlSerializer) serializerClass.newInstance();
}
} catch (InstantiationException e) {
exceptions.add(e);
} catch (IllegalAccessException e) {
exceptions.add(e);
} catch (ClassCastException e) {
exceptions.add(e);
}*/
}
}
throw newInstantiationException("Invalid serializer class list", exceptions);
}
private static XmlPullParserException newInstantiationException(String message,
ArrayList<Exception> exceptions) {
if (exceptions == null || exceptions.isEmpty()) {
return new XmlPullParserException(message);
} else {
XmlPullParserException exception = new XmlPullParserException(message);
for (Exception ex : exceptions) {
exception.addSuppressed(ex);
}
return exception;
}
}
/**
* Creates a new instance of a XML Serializer.
*
* <p><b>NOTE:</b> factory features are not used for XML Serializer.
*
* @return A new instance of a XML Serializer.
* @throws XmlPullParserException if a parser cannot be created which satisfies the
* requested configuration.
*/
public XmlSerializer newSerializer() throws XmlPullParserException {
return getSerializerInstance();
}
/**
* Creates a new instance of a PullParserFactory that can be used
* to create XML pull parsers. The factory will always return instances
* of Android's built-in {@link XmlPullParser} and {@link XmlSerializer}.
*/
public static XmlPullParserFactory newInstance () throws XmlPullParserException {
return new XmlPullParserFactory();
}
/**
* Creates a factory that always returns instances of Android's built-in
* {@link XmlPullParser} and {@link XmlSerializer} implementation. This
* <b>does not</b> support factories capable of creating arbitrary parser
* and serializer implementations. Both arguments to this method are unused.
*/
public static XmlPullParserFactory newInstance (String unused, Class unused2)
throws XmlPullParserException {
return newInstance();
}
}

View File

@@ -0,0 +1,325 @@
package org.xmlpull.v1;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
/**
* Define an interface to serialization of XML Infoset.
* This interface abstracts away if serialized XML is XML 1.0 compatible text or
* other formats of XML 1.0 serializations (such as binary XML for example with WBXML).
*
* <p><b>PLEASE NOTE:</b> This interface will be part of XmlPull 1.2 API.
* It is included as basis for discussion. It may change in any way.
*
* <p>Exceptions that may be thrown are: IOException or runtime exception
* (more runtime exceptions can be thrown but are not declared and as such
* have no semantics defined for this interface):
* <ul>
* <li><em>IllegalArgumentException</em> - for almost all methods to signal that
* argument is illegal
* <li><em>IllegalStateException</em> - to signal that call has good arguments but
* is not expected here (violation of contract) and for features/properties
* when requesting setting unimplemented feature/property
* (UnsupportedOperationException would be better but it is not in MIDP)
* </ul>
*
* <p><b>NOTE:</b> writing CDSECT, ENTITY_REF, IGNORABLE_WHITESPACE,
* PROCESSING_INSTRUCTION, COMMENT, and DOCDECL in some implementations
* may not be supported (for example when serializing to WBXML).
* In such case IllegalStateException will be thrown and it is recommended
* to use an optional feature to signal that implementation is not
* supporting this kind of output.
*/
public interface XmlSerializer {
/**
* Set feature identified by name (recommended to be URI for uniqueness).
* Some well known optional features are defined in
* <a href="http://www.xmlpull.org/v1/doc/features.html">
* http://www.xmlpull.org/v1/doc/features.html</a>.
*
* If feature is not recognized or can not be set
* then IllegalStateException MUST be thrown.
*
* @exception IllegalStateException If the feature is not supported or can not be set
*/
void setFeature(String name,
boolean state)
throws IllegalArgumentException, IllegalStateException;
/**
* Return the current value of the feature with given name.
* <p><strong>NOTE:</strong> unknown properties are <strong>always</strong> returned as null
*
* @param name The name of feature to be retrieved.
* @return The value of named feature.
* @exception IllegalArgumentException if feature string is null
*/
boolean getFeature(String name);
/**
* Set the value of a property.
* (the property name is recommended to be URI for uniqueness).
* Some well known optional properties are defined in
* <a href="http://www.xmlpull.org/v1/doc/properties.html">
* http://www.xmlpull.org/v1/doc/properties.html</a>.
*
* If property is not recognized or can not be set
* then IllegalStateException MUST be thrown.
*
* @exception IllegalStateException if the property is not supported or can not be set
*/
void setProperty(String name,
Object value)
throws IllegalArgumentException, IllegalStateException;
/**
* Look up the value of a property.
*
* The property name is any fully-qualified URI. I
* <p><strong>NOTE:</strong> unknown properties are <string>always</strong> returned as null
*
* @param name The name of property to be retrieved.
* @return The value of named property.
*/
Object getProperty(String name);
/**
* Set to use binary output stream with given encoding.
*/
void setOutput (OutputStream os, String encoding)
throws IOException, IllegalArgumentException, IllegalStateException;
/**
* Set the output to the given writer.
* <p><b>WARNING</b> no information about encoding is available!
*/
void setOutput (Writer writer)
throws IOException, IllegalArgumentException, IllegalStateException;
/**
* Write &lt;&#63;xml declaration with encoding (if encoding not null)
* and standalone flag (if standalone not null)
* This method can only be called just after setOutput.
*/
void startDocument (String encoding, Boolean standalone)
throws IOException, IllegalArgumentException, IllegalStateException;
/**
* Finish writing. All unclosed start tags will be closed and output
* will be flushed. After calling this method no more output can be
* serialized until next call to setOutput()
*/
void endDocument ()
throws IOException, IllegalArgumentException, IllegalStateException;
/**
* Binds the given prefix to the given namespace.
* This call is valid for the next element including child elements.
* The prefix and namespace MUST be always declared even if prefix
* is not used in element (startTag() or attribute()) - for XML 1.0
* it must result in declaring <code>xmlns:prefix='namespace'</code>
* (or <code>xmlns:prefix="namespace"</code> depending what character is used
* to quote attribute value).
*
* <p><b>NOTE:</b> this method MUST be called directly before startTag()
* and if anything but startTag() or setPrefix() is called next there will be exception.
* <p><b>NOTE:</b> prefixes "xml" and "xmlns" are already bound
* and can not be redefined see:
* <a href="http://www.w3.org/XML/xml-names-19990114-errata#NE05">Namespaces in XML Errata</a>.
* <p><b>NOTE:</b> to set default namespace use as prefix empty string.
*
* @param prefix must be not null (or IllegalArgumentException is thrown)
* @param namespace must be not null
*/
void setPrefix (String prefix, String namespace)
throws IOException, IllegalArgumentException, IllegalStateException;
/**
* Return namespace that corresponds to given prefix
* If there is no prefix bound to this namespace return null
* but if generatePrefix is false then return generated prefix.
*
* <p><b>NOTE:</b> if the prefix is empty string "" and default namespace is bound
* to this prefix then empty string ("") is returned.
*
* <p><b>NOTE:</b> prefixes "xml" and "xmlns" are already bound
* will have values as defined
* <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces in XML specification</a>
*/
String getPrefix (String namespace, boolean generatePrefix)
throws IllegalArgumentException;
/**
* Returns the current depth of the element.
* Outside the root element, the depth is 0. The
* depth is incremented by 1 when startTag() is called.
* The depth is decremented after the call to endTag()
* event was observed.
*
* <pre>
* &lt;!-- outside --&gt; 0
* &lt;root&gt; 1
* sometext 1
* &lt;foobar&gt; 2
* &lt;/foobar&gt; 2
* &lt;/root&gt; 1
* &lt;!-- outside --&gt; 0
* </pre>
*/
int getDepth();
/**
* Returns the namespace URI of the current element as set by startTag().
*
* <p><b>NOTE:</b> that means in particular that: <ul>
* <li>if there was startTag("", ...) then getNamespace() returns ""
* <li>if there was startTag(null, ...) then getNamespace() returns null
* </ul>
*
* @return namespace set by startTag() that is currently in scope
*/
String getNamespace ();
/**
* Returns the name of the current element as set by startTag().
* It can only be null before first call to startTag()
* or when last endTag() is called to close first startTag().
*
* @return namespace set by startTag() that is currently in scope
*/
String getName();
/**
* Writes a start tag with the given namespace and name.
* If there is no prefix defined for the given namespace,
* a prefix will be defined automatically.
* The explicit prefixes for namespaces can be established by calling setPrefix()
* immediately before this method.
* If namespace is null no namespace prefix is printed but just name.
* If namespace is empty string then serializer will make sure that
* default empty namespace is declared (in XML 1.0 xmlns='')
* or throw IllegalStateException if default namespace is already bound
* to non-empty string.
*/
XmlSerializer startTag (String namespace, String name)
throws IOException, IllegalArgumentException, IllegalStateException;
/**
* Write an attribute. Calls to attribute() MUST follow a call to
* startTag() immediately. If there is no prefix defined for the
* given namespace, a prefix will be defined automatically.
* If namespace is null or empty string
* no namespace prefix is printed but just name.
*/
XmlSerializer attribute (String namespace, String name, String value)
throws IOException, IllegalArgumentException, IllegalStateException;
/**
* Write end tag. Repetition of namespace and name is just for avoiding errors.
* <p><b>Background:</b> in kXML endTag had no arguments, and non matching tags were
* very difficult to find...
* If namespace is null no namespace prefix is printed but just name.
* If namespace is empty string then serializer will make sure that
* default empty namespace is declared (in XML 1.0 xmlns='').
*/
XmlSerializer endTag (String namespace, String name)
throws IOException, IllegalArgumentException, IllegalStateException;
// /**
// * Writes a start tag with the given namespace and name.
// * <br />If there is no prefix defined (prefix == null) for the given namespace,
// * a prefix will be defined automatically.
// * <br />If explicit prefixes is passed (prefix != null) then it will be used
// *and namespace declared if not already declared or
// * throw IllegalStateException the same prefix was already set on this
// * element (setPrefix()) and was bound to different namespace.
// * <br />If namespace is null then prefix must be null too or IllegalStateException is thrown.
// * <br />If namespace is null then no namespace prefix is printed but just name.
// * <br />If namespace is empty string then serializer will make sure that
// * default empty namespace is declared (in XML 1.0 xmlns='')
// * or throw IllegalStateException if default namespace is already bound
// * to non-empty string.
// */
// XmlSerializer startTag (String prefix, String namespace, String name)
// throws IOException, IllegalArgumentException, IllegalStateException;
//
// /**
// * Write an attribute. Calls to attribute() MUST follow a call to
// * startTag() immediately.
// * <br />If there is no prefix defined (prefix == null) for the given namespace,
// * a prefix will be defined automatically.
// * <br />If explicit prefixes is passed (prefix != null) then it will be used
// * and namespace declared if not already declared or
// * throw IllegalStateException the same prefix was already set on this
// * element (setPrefix()) and was bound to different namespace.
// * <br />If namespace is null then prefix must be null too or IllegalStateException is thrown.
// * <br />If namespace is null then no namespace prefix is printed but just name.
// * <br />If namespace is empty string then serializer will make sure that
// * default empty namespace is declared (in XML 1.0 xmlns='')
// * or throw IllegalStateException if default namespace is already bound
// * to non-empty string.
// */
// XmlSerializer attribute (String prefix, String namespace, String name, String value)
// throws IOException, IllegalArgumentException, IllegalStateException;
//
// /**
// * Write end tag. Repetition of namespace, prefix, and name is just for avoiding errors.
// * <br />If namespace or name arguments are different from corresponding startTag call
// * then IllegalArgumentException is thrown, if prefix argument is not null and is different
// * from corresponding starTag then IllegalArgumentException is thrown.
// * <br />If namespace is null then prefix must be null too or IllegalStateException is thrown.
// * <br />If namespace is null then no namespace prefix is printed but just name.
// * <br />If namespace is empty string then serializer will make sure that
// * default empty namespace is declared (in XML 1.0 xmlns='').
// * <p><b>Background:</b> in kXML endTag had no arguments, and non matching tags were
// * very difficult to find...</p>
// */
// ALEK: This is really optional as prefix in end tag MUST correspond to start tag but good for error checking
// XmlSerializer endTag (String prefix, String namespace, String name)
// throws IOException, IllegalArgumentException, IllegalStateException;
/**
* Writes text, where special XML chars are escaped automatically
*/
XmlSerializer text (String text)
throws IOException, IllegalArgumentException, IllegalStateException;
/**
* Writes text, where special XML chars are escaped automatically
*/
XmlSerializer text (char [] buf, int start, int len)
throws IOException, IllegalArgumentException, IllegalStateException;
void cdsect (String text)
throws IOException, IllegalArgumentException, IllegalStateException;
void entityRef (String text) throws IOException,
IllegalArgumentException, IllegalStateException;
void processingInstruction (String text)
throws IOException, IllegalArgumentException, IllegalStateException;
void comment (String text)
throws IOException, IllegalArgumentException, IllegalStateException;
void docdecl (String text)
throws IOException, IllegalArgumentException, IllegalStateException;
void ignorableWhitespace (String text)
throws IOException, IllegalArgumentException, IllegalStateException;
/**
* Write all pending output to the stream.
* If method startTag() or attribute() was called then start tag is closed (final &gt;)
* before flush() is called on underlying output stream.
*
* <p><b>NOTE:</b> if there is need to close start tag
* (so no more attribute() calls are allowed) but without flushing output
* call method text() with empty string (text("")).
*
*/
void flush ()
throws IOException;
}

View File

@@ -2,6 +2,7 @@ apply plugin: 'java-library'
apply plugin: 'maven' apply plugin: 'maven'
dependencies { dependencies {
api 'net.sf.kxml:kxml2:2.3.0'
api "org.slf4j:slf4j-api:$slf4jVersion" api "org.slf4j:slf4j-api:$slf4jVersion"
compileOnly 'com.google.code.findbugs:jsr305:3.0.2' compileOnly 'com.google.code.findbugs:jsr305:3.0.2'
} }

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright 2013 Hannes Janetzek * Copyright 2013 Hannes Janetzek
* Copyright 2016-2018 devemux86 * Copyright 2016-2020 devemux86
* Copyright 2017 Longri * Copyright 2017 Longri
* *
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
@@ -59,6 +59,11 @@ public abstract class CanvasAdapter {
*/ */
public static Platform platform = Platform.UNKNOWN; public static Platform platform = Platform.UNKNOWN;
/**
* The symbol scale.
*/
public static float symbolScale = 1;
/** /**
* The text scale. * The text scale.
*/ */

View File

@@ -254,8 +254,8 @@ public final class Color {
* exception. Supported formats are: * exception. Supported formats are:
* #RRGGBB * #RRGGBB
* #AARRGGBB * #AARRGGBB
* 'red', 'blue', 'green', 'black', 'white', 'gray', 'cyan', 'magenta', * rgb(r, g, b)
* 'yellow', 'lightgray', 'darkgray' * rgba(r, g, b, a)
* *
* @param colorString the color string * @param colorString the color string
* @return the int * @return the int

View File

@@ -56,7 +56,7 @@ public class JobQueue {
if (t.state(LOADING | CANCEL)) { if (t.state(LOADING | CANCEL)) {
t.setState(NONE); t.setState(NONE);
} else { } else {
log.error("Wrong tile in queue {} {}", t, t.state()); log.debug("Wrong tile in queue {} {}", t, t.state());
} }
tiles[i] = null; tiles[i] = null;
} }

View File

@@ -1,6 +1,7 @@
/* /*
* Copyright 2013 Hannes Janetzek * Copyright 2013 Hannes Janetzek
* Copyright 2016 Andrey Novikov * Copyright 2016 Andrey Novikov
* Copyright 2020 devemux86
* *
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
* *
@@ -22,16 +23,10 @@ import org.oscim.event.Event;
import org.oscim.layers.Layer; import org.oscim.layers.Layer;
import org.oscim.map.Map; import org.oscim.map.Map;
import org.oscim.map.Map.UpdateListener; import org.oscim.map.Map.UpdateListener;
import org.slf4j.Logger; import org.oscim.tiling.TileSource;
import org.slf4j.LoggerFactory;
/**
* TODO - add a TileLayer.Builder
*/
public abstract class TileLayer extends Layer implements UpdateListener { public abstract class TileLayer extends Layer implements UpdateListener {
static final Logger log = LoggerFactory.getLogger(TileLayer.class);
private int mNumLoaders = 4; private int mNumLoaders = 4;
/** /**
@@ -42,6 +37,8 @@ public abstract class TileLayer extends Layer implements UpdateListener {
protected TileLoader[] mTileLoader; protected TileLoader[] mTileLoader;
protected TileSource mTileSource;
public TileLayer(Map map, TileManager tileManager, TileRenderer renderer) { public TileLayer(Map map, TileManager tileManager, TileRenderer renderer) {
super(map); super(map);
renderer.setTileManager(tileManager); renderer.setTileManager(tileManager);
@@ -116,6 +113,8 @@ public abstract class TileLayer extends Layer implements UpdateListener {
loader.finish(); loader.finish();
loader.dispose(); loader.dispose();
} }
if (mTileSource != null)
mTileSource.close();
} }
void notifyLoaders() { void notifyLoaders() {
@@ -148,4 +147,8 @@ public abstract class TileLayer extends Layer implements UpdateListener {
public TileManager getManager() { public TileManager getManager() {
return mTileManager; return mTileManager;
} }
public TileSource getTileSource() {
return mTileSource;
}
} }

View File

@@ -1,7 +1,7 @@
/* /*
* Copyright 2013 Hannes Janetzek * Copyright 2013 Hannes Janetzek
* Copyright 2017 Andrey Novikov * Copyright 2017 Andrey Novikov
* Copyright 2017-2018 devemux86 * Copyright 2017-2020 devemux86
* Copyright 2019 Gustl22 * Copyright 2019 Gustl22
* *
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
@@ -38,8 +38,6 @@ public class BitmapTileLayer extends TileLayer {
private static final int CACHE_LIMIT = 40; private static final int CACHE_LIMIT = 40;
protected final TileSource mTileSource;
/** /**
* Bitmap alpha in range 0 to 1. * Bitmap alpha in range 0 to 1.
*/ */

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright 2013 Hannes Janetzek * Copyright 2013 Hannes Janetzek
* Copyright 2020 devemux86
* *
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
* *
@@ -34,8 +35,6 @@ public class S3DBTileLayer extends TileLayer {
private static final int MIN_ZOOM = 16; private static final int MIN_ZOOM = 16;
private static final int MAX_ZOOM = 16; private static final int MAX_ZOOM = 16;
private final TileSource mTileSource;
public S3DBTileLayer(Map map, TileSource tileSource) { public S3DBTileLayer(Map map, TileSource tileSource) {
this(map, tileSource, true, false); this(map, tileSource, true, false);
} }

View File

@@ -21,6 +21,7 @@ import org.oscim.core.Tag;
import org.oscim.core.TagSet; import org.oscim.core.TagSet;
import org.oscim.layers.tile.TileLoader; import org.oscim.layers.tile.TileLoader;
import org.oscim.map.Map; import org.oscim.map.Map;
import org.oscim.tiling.TileSource;
import org.oscim.utils.Utils; import org.oscim.utils.Utils;
public class OsmTileLayer extends VectorTileLayer { public class OsmTileLayer extends VectorTileLayer {
@@ -36,6 +37,12 @@ public class OsmTileLayer extends VectorTileLayer {
mTileManager.setZoomLevel(zoomMin, zoomMax); mTileManager.setZoomLevel(zoomMin, zoomMax);
} }
public OsmTileLayer(Map map, TileSource tileSource) {
this(map);
setTileSource(tileSource);
}
@Override @Override
protected TileLoader createLoader() { protected TileLoader createLoader() {
return new OsmTileLoader(this); return new OsmTileLoader(this);

View File

@@ -1,6 +1,7 @@
/* /*
* Copyright 2013 Hannes Janetzek * Copyright 2013 Hannes Janetzek
* Copyright 2016 Longri * Copyright 2016 Longri
* Copyright 2020 devemux86
* *
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
* *
@@ -18,11 +19,7 @@
package org.oscim.layers.tile.vector; package org.oscim.layers.tile.vector;
import org.oscim.core.MapElement; import org.oscim.core.MapElement;
import org.oscim.layers.tile.MapTile; import org.oscim.layers.tile.*;
import org.oscim.layers.tile.TileLayer;
import org.oscim.layers.tile.TileLoader;
import org.oscim.layers.tile.TileManager;
import org.oscim.layers.tile.VectorTileRenderer;
import org.oscim.map.Map; import org.oscim.map.Map;
import org.oscim.renderer.bucket.RenderBuckets; import org.oscim.renderer.bucket.RenderBuckets;
import org.oscim.theme.IRenderTheme; import org.oscim.theme.IRenderTheme;
@@ -42,7 +39,11 @@ import org.slf4j.LoggerFactory;
public class VectorTileLayer extends TileLayer { public class VectorTileLayer extends TileLayer {
static final Logger log = LoggerFactory.getLogger(VectorTileLayer.class); static final Logger log = LoggerFactory.getLogger(VectorTileLayer.class);
protected TileSource mTileSource; private final List<LList<TileLoaderProcessHook>> mLoaderProcessHooks = new List<>();
private final List<LList<TileLoaderThemeHook>> mLoaderThemeHooks = new List<>();
private IRenderTheme mTheme;
public VectorTileLayer(Map map, TileSource tileSource) { public VectorTileLayer(Map map, TileSource tileSource) {
this(map, new TileManager(map, this(map, new TileManager(map,
@@ -104,14 +105,18 @@ public class VectorTileLayer extends TileLayer {
return true; return true;
} }
public TileSource getTileSource() { /**
return mTileSource; * Set {@link IRenderTheme} used by {@link TileLoader}
*/
@Deprecated
public void setRenderTheme(IRenderTheme theme) {
setTheme(theme);
} }
/** /**
* Set {@link IRenderTheme} used by {@link TileLoader} * Set {@link IRenderTheme} used by {@link TileLoader}
*/ */
public void setRenderTheme(IRenderTheme theme) { public void setTheme(IRenderTheme theme) {
/* wait for loaders to finish all current jobs to /* wait for loaders to finish all current jobs to
* not change theme instance hold by loader instance * not change theme instance hold by loader instance
* while running */ * while running */
@@ -127,8 +132,6 @@ public class VectorTileLayer extends TileLayer {
resumeLoaders(); resumeLoaders();
} }
private IRenderTheme mTheme;
public IRenderTheme getTheme() { public IRenderTheme getTheme() {
return mTheme; return mTheme;
} }
@@ -164,12 +167,6 @@ public class VectorTileLayer extends TileLayer {
public void complete(MapTile tile, boolean success); public void complete(MapTile tile, boolean success);
} }
private List<LList<TileLoaderProcessHook>> mLoaderProcessHooks =
new List<LList<TileLoaderProcessHook>>();
private List<LList<TileLoaderThemeHook>> mLoaderThemeHooks =
new List<LList<TileLoaderThemeHook>>();
public void addHook(TileLoaderProcessHook h) { public void addHook(TileLoaderProcessHook h) {
mLoaderProcessHooks.append(new LList<TileLoaderProcessHook>(h)); mLoaderProcessHooks.append(new LList<TileLoaderProcessHook>(h));
} }
@@ -178,13 +175,6 @@ public class VectorTileLayer extends TileLayer {
mLoaderThemeHooks.append(new LList<TileLoaderThemeHook>(h)); mLoaderThemeHooks.append(new LList<TileLoaderThemeHook>(h));
} }
@Override
public void onDetach() {
super.onDetach();
if (mTileSource != null)
mTileSource.close();
}
public void callThemeHooks(MapTile tile, RenderBuckets layers, MapElement element, public void callThemeHooks(MapTile tile, RenderBuckets layers, MapElement element,
RenderStyle style, int level) { RenderStyle style, int level) {

View File

@@ -2,7 +2,7 @@
* Copyright 2013 Hannes Janetzek * Copyright 2013 Hannes Janetzek
* Copyright 2016 Andrey Novikov * Copyright 2016 Andrey Novikov
* Copyright 2016 Stephan Leuschner * Copyright 2016 Stephan Leuschner
* Copyright 2016-2019 devemux86 * Copyright 2016-2020 devemux86
* Copyright 2016 Longri * Copyright 2016 Longri
* Copyright 2018 Gustl22 * Copyright 2018 Gustl22
* *
@@ -24,11 +24,7 @@ package org.oscim.map;
import org.oscim.core.BoundingBox; import org.oscim.core.BoundingBox;
import org.oscim.core.Box; import org.oscim.core.Box;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.event.Event; import org.oscim.event.*;
import org.oscim.event.EventDispatcher;
import org.oscim.event.EventListener;
import org.oscim.event.Gesture;
import org.oscim.event.MotionEvent;
import org.oscim.layers.AbstractMapEventLayer; import org.oscim.layers.AbstractMapEventLayer;
import org.oscim.layers.Layer; import org.oscim.layers.Layer;
import org.oscim.layers.MapEventLayer; import org.oscim.layers.MapEventLayer;
@@ -189,16 +185,18 @@ public abstract class Map implements TaskQueue {
* Utility function to set theme of base vector-layer and * Utility function to set theme of base vector-layer and
* use map background color from theme. * use map background color from theme.
*/ */
public void setTheme(ThemeFile theme) { public IRenderTheme setTheme(ThemeFile theme) {
setTheme(theme, false); return setTheme(theme, false);
} }
/** /**
* Utility function to set theme of base vector-layer, optionally * Utility function to set theme of base vector-layer, optionally
* to all vector layers and use map background color from theme. * to all vector layers and use map background color from theme.
*/ */
public void setTheme(ThemeFile theme, boolean allLayers) { public IRenderTheme setTheme(ThemeFile theme, boolean allLayers) {
setTheme(ThemeLoader.load(theme), allLayers); IRenderTheme renderTheme = ThemeLoader.load(theme);
setTheme(renderTheme, allLayers);
return renderTheme;
} }
public void setTheme(IRenderTheme theme) { public void setTheme(IRenderTheme theme) {
@@ -213,7 +211,7 @@ public abstract class Map implements TaskQueue {
boolean themeSet = false; boolean themeSet = false;
for (Layer layer : mLayers) { for (Layer layer : mLayers) {
if (layer instanceof VectorTileLayer) { if (layer instanceof VectorTileLayer) {
((VectorTileLayer) layer).setRenderTheme(theme); ((VectorTileLayer) layer).setTheme(theme);
themeSet = true; themeSet = true;
if (!allLayers) if (!allLayers)
break; break;

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright 2017 Longri * Copyright 2017 Longri
* Copyright 2017-2018 devemux86 * Copyright 2017-2020 devemux86
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software * terms of the GNU Lesser General Public License as published by the Free Software
@@ -17,7 +17,6 @@ package org.oscim.theme;
import org.oscim.backend.CanvasAdapter; import org.oscim.backend.CanvasAdapter;
import org.oscim.backend.Platform; import org.oscim.backend.Platform;
import org.oscim.backend.XMLReaderAdapter;
import org.oscim.backend.canvas.Bitmap; import org.oscim.backend.canvas.Bitmap;
import org.oscim.renderer.atlas.TextureAtlas; import org.oscim.renderer.atlas.TextureAtlas;
import org.oscim.renderer.atlas.TextureRegion; import org.oscim.renderer.atlas.TextureRegion;
@@ -26,8 +25,11 @@ import org.oscim.theme.rule.Rule;
import org.oscim.theme.styles.RenderStyle; import org.oscim.theme.styles.RenderStyle;
import org.oscim.theme.styles.SymbolStyle; import org.oscim.theme.styles.SymbolStyle;
import org.oscim.theme.styles.SymbolStyle.SymbolBuilder; import org.oscim.theme.styles.SymbolStyle.SymbolBuilder;
import org.oscim.utils.IOUtils;
import org.oscim.utils.TextureAtlasUtils; import org.oscim.utils.TextureAtlasUtils;
import org.xmlpull.v1.XmlPullParser;
import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -51,20 +53,23 @@ public class XmlAtlasThemeBuilder extends XmlThemeBuilder {
* @throws ThemeException if an error occurs while parsing the render theme XML. * @throws ThemeException if an error occurs while parsing the render theme XML.
*/ */
public static IRenderTheme read(ThemeFile theme, ThemeCallback themeCallback) throws ThemeException { public static IRenderTheme read(ThemeFile theme, ThemeCallback themeCallback) throws ThemeException {
Map<Object, TextureRegion> outputMap = new HashMap<>(); InputStream inputStream = null;
List<TextureAtlas> atlasList = new ArrayList<>();
XmlAtlasThemeBuilder renderThemeHandler = new XmlAtlasThemeBuilder(theme, themeCallback, outputMap, atlasList);
try { try {
new XMLReaderAdapter().parse(renderThemeHandler, theme.getRenderThemeAsStream()); XmlPullParser pullParser = getXmlPullParserFactory().newPullParser();
Map<Object, TextureRegion> outputMap = new HashMap<>();
List<TextureAtlas> atlasList = new ArrayList<>();
XmlAtlasThemeBuilder renderThemeHandler = new XmlAtlasThemeBuilder(theme, pullParser, themeCallback, outputMap, atlasList);
inputStream = theme.getRenderThemeAsStream();
pullParser.setInput(inputStream, null);
renderThemeHandler.processRenderTheme();
TextureAtlasUtils.createTextureRegions(renderThemeHandler.bitmapMap, outputMap, atlasList,
true, CanvasAdapter.platform == Platform.IOS);
return replaceThemeSymbols(renderThemeHandler.mRenderTheme, outputMap);
} catch (Exception e) { } catch (Exception e) {
throw new ThemeException(e.getMessage()); throw new ThemeException(e.getMessage());
} finally {
IOUtils.closeQuietly(inputStream);
} }
TextureAtlasUtils.createTextureRegions(renderThemeHandler.bitmapMap, outputMap, atlasList,
true, CanvasAdapter.platform == Platform.IOS);
return replaceThemeSymbols(renderThemeHandler.mRenderTheme, outputMap);
} }
private static IRenderTheme replaceThemeSymbols(RenderTheme renderTheme, Map<Object, TextureRegion> regionMap) { private static IRenderTheme replaceThemeSymbols(RenderTheme renderTheme, Map<Object, TextureRegion> regionMap) {
@@ -98,14 +103,14 @@ public class XmlAtlasThemeBuilder extends XmlThemeBuilder {
private final Map<Object, Bitmap> bitmapMap = new HashMap<>(); private final Map<Object, Bitmap> bitmapMap = new HashMap<>();
public XmlAtlasThemeBuilder(ThemeFile theme, public XmlAtlasThemeBuilder(ThemeFile theme, XmlPullParser pullParser,
Map<Object, TextureRegion> regionMap, List<TextureAtlas> atlasList) { Map<Object, TextureRegion> regionMap, List<TextureAtlas> atlasList) {
this(theme, null, regionMap, atlasList); this(theme, pullParser, null, regionMap, atlasList);
} }
public XmlAtlasThemeBuilder(ThemeFile theme, ThemeCallback themeCallback, public XmlAtlasThemeBuilder(ThemeFile theme, XmlPullParser pullParser, ThemeCallback themeCallback,
Map<Object, TextureRegion> regionMap, List<TextureAtlas> atlasList) { Map<Object, TextureRegion> regionMap, List<TextureAtlas> atlasList) {
super(theme, themeCallback); super(theme, pullParser, themeCallback);
this.regionMap = regionMap; this.regionMap = regionMap;
this.atlasList = atlasList; this.atlasList = atlasList;
} }

View File

@@ -1,7 +1,8 @@
/* /*
* Copyright 2010, 2011, 2012 mapsforge.org * Copyright 2010, 2011, 2012, 2013 mapsforge.org
* Copyright 2013 Hannes Janetzek * Copyright 2013 Hannes Janetzek
* Copyright 2016-2019 devemux86 * Copyright 2014 Ludwig M Brinckmann
* Copyright 2016-2020 devemux86
* Copyright 2016-2017 Longri * Copyright 2016-2017 Longri
* Copyright 2016-2020 Andrey Novikov * Copyright 2016-2020 Andrey Novikov
* Copyright 2018-2019 Gustl22 * Copyright 2018-2019 Gustl22
@@ -24,7 +25,6 @@
package org.oscim.theme; package org.oscim.theme;
import org.oscim.backend.CanvasAdapter; import org.oscim.backend.CanvasAdapter;
import org.oscim.backend.XMLReaderAdapter;
import org.oscim.backend.canvas.Bitmap; import org.oscim.backend.canvas.Bitmap;
import org.oscim.backend.canvas.Canvas; import org.oscim.backend.canvas.Canvas;
import org.oscim.backend.canvas.Color; import org.oscim.backend.canvas.Color;
@@ -49,27 +49,26 @@ import org.oscim.theme.styles.LineStyle.LineBuilder;
import org.oscim.theme.styles.SymbolStyle.SymbolBuilder; import org.oscim.theme.styles.SymbolStyle.SymbolBuilder;
import org.oscim.theme.styles.TextStyle.TextBuilder; import org.oscim.theme.styles.TextStyle.TextBuilder;
import org.oscim.utils.FastMath; import org.oscim.utils.FastMath;
import org.oscim.utils.IOUtils;
import org.oscim.utils.Parameters;
import org.oscim.utils.Utils; import org.oscim.utils.Utils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes; import org.xmlpull.v1.XmlPullParser;
import org.xml.sax.SAXException; import org.xmlpull.v1.XmlPullParserException;
import org.xml.sax.SAXParseException; import org.xmlpull.v1.XmlPullParserFactory;
import org.xml.sax.helpers.DefaultHandler;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.*; import java.util.*;
import static java.lang.Boolean.parseBoolean; public class XmlThemeBuilder {
import static java.lang.Float.parseFloat;
import static java.lang.Integer.parseInt;
public class XmlThemeBuilder extends DefaultHandler {
private static final Logger log = LoggerFactory.getLogger(XmlThemeBuilder.class); private static final Logger log = LoggerFactory.getLogger(XmlThemeBuilder.class);
private static final int RENDER_THEME_VERSION_MAPSFORGE = 6; private static final int RENDER_THEME_VERSION_MAPSFORGE = 6;
private static final int RENDER_THEME_VERSION_VTM = 1; private static final int RENDER_THEME_VERSION_VTM = 1;
private static XmlPullParserFactory xmlPullParserFactory = null;
private enum Element { private enum Element {
RENDER_THEME, RENDERING_INSTRUCTION, RULE, STYLE, ATLAS, RECT, RENDERING_STYLE, TAG_TRANSFORM RENDER_THEME, RENDERING_INSTRUCTION, RULE, STYLE, ATLAS, RECT, RENDERING_STYLE, TAG_TRANSFORM
@@ -109,15 +108,30 @@ public class XmlThemeBuilder extends DefaultHandler {
* @throws ThemeException if an error occurs while parsing the render theme XML. * @throws ThemeException if an error occurs while parsing the render theme XML.
*/ */
public static IRenderTheme read(ThemeFile theme, ThemeCallback themeCallback) throws ThemeException { public static IRenderTheme read(ThemeFile theme, ThemeCallback themeCallback) throws ThemeException {
XmlThemeBuilder renderThemeHandler = new XmlThemeBuilder(theme, themeCallback); InputStream inputStream = null;
try { try {
new XMLReaderAdapter().parse(renderThemeHandler, theme.getRenderThemeAsStream()); XmlPullParser pullParser = getXmlPullParserFactory().newPullParser();
XmlThemeBuilder renderThemeHandler = new XmlThemeBuilder(theme, pullParser, themeCallback);
inputStream = theme.getRenderThemeAsStream();
pullParser.setInput(inputStream, null);
renderThemeHandler.processRenderTheme();
return renderThemeHandler.mRenderTheme;
} catch (Exception e) { } catch (Exception e) {
throw new ThemeException(e.getMessage()); throw new ThemeException(e.getMessage());
} finally {
IOUtils.closeQuietly(inputStream);
} }
}
return renderThemeHandler.mRenderTheme; public static XmlPullParserFactory getXmlPullParserFactory() throws XmlPullParserException {
if (xmlPullParserFactory == null) {
xmlPullParserFactory = XmlPullParserFactory.newInstance();
}
return xmlPullParserFactory;
}
public static void setXmlPullParserFactory(XmlPullParserFactory xmlPullParserFactory) {
XmlThemeBuilder.xmlPullParserFactory = xmlPullParserFactory;
} }
/** /**
@@ -128,19 +142,17 @@ public class XmlThemeBuilder extends DefaultHandler {
* @param value the XML attribute value. * @param value the XML attribute value.
* @param attributeIndex the XML attribute index position. * @param attributeIndex the XML attribute index position.
*/ */
private static void logUnknownAttribute(String element, String name, private static void logUnknownAttribute(String element, String name, String value, int attributeIndex) {
String value, int attributeIndex) { log.debug("unknown attribute in element {} {} : {} = {}", element, attributeIndex, name, value);
log.debug("unknown attribute in element {} () : {} = {}",
element, attributeIndex, name, value);
} }
private final ArrayList<RuleBuilder> mRulesList = new ArrayList<>(); private final ArrayList<RuleBuilder> mRulesList = new ArrayList<>();
private final Stack<Element> mElementStack = new Stack<>(); private final Stack<Element> mElementStack = new Stack<>();
private final Stack<RuleBuilder> mRuleStack = new Stack<>(); private final Stack<RuleBuilder> mRuleStack = new Stack<>();
private final HashMap<String, RenderStyle> mStyles = new HashMap<>(10); private final Map<String, RenderStyle<?>> mStyles = new HashMap<>(10);
private final HashMap<String, TextStyle.TextBuilder<?>> mTextStyles = new HashMap<>(10); private final Map<String, TextStyle.TextBuilder<?>> mTextStyles = new HashMap<>(10);
private final HashMap<String, SymbolStyle.SymbolBuilder<?>> mSymbolStyles = new HashMap<>(10); private final Map<String, SymbolStyle.SymbolBuilder<?>> mSymbolStyles = new HashMap<>(10);
private final AreaBuilder<?> mAreaBuilder = AreaStyle.builder(); private final AreaBuilder<?> mAreaBuilder = AreaStyle.builder();
private final CircleBuilder<?> mCircleBuilder = CircleStyle.builder(); private final CircleBuilder<?> mCircleBuilder = CircleStyle.builder();
@@ -157,6 +169,8 @@ public class XmlThemeBuilder extends DefaultHandler {
private float mStrokeScale = 1; private float mStrokeScale = 1;
float mTextScale = 1; float mTextScale = 1;
private final XmlPullParser mPullParser;
private String qName;
final ThemeFile mTheme; final ThemeFile mTheme;
private final ThemeCallback mThemeCallback; private final ThemeCallback mThemeCallback;
RenderTheme mRenderTheme; RenderTheme mRenderTheme;
@@ -168,21 +182,38 @@ public class XmlThemeBuilder extends DefaultHandler {
private XmlRenderThemeStyleLayer mCurrentLayer; private XmlRenderThemeStyleLayer mCurrentLayer;
private XmlRenderThemeStyleMenu mRenderThemeStyleMenu; private XmlRenderThemeStyleMenu mRenderThemeStyleMenu;
private Map<String, String> mTransformKeyMap = new HashMap<>(); private final Map<String, String> mTransformKeyMap = new HashMap<>();
private Map<Tag, Tag> mTransformTagMap = new HashMap<>(); private final Map<Tag, Tag> mTransformTagMap = new HashMap<>();
public XmlThemeBuilder(ThemeFile theme) { public XmlThemeBuilder(ThemeFile theme, XmlPullParser pullParser) {
this(theme, null); this(theme, pullParser, null);
} }
public XmlThemeBuilder(ThemeFile theme, ThemeCallback themeCallback) { public XmlThemeBuilder(ThemeFile theme, XmlPullParser pullParser, ThemeCallback themeCallback) {
mTheme = theme; mTheme = theme;
mPullParser = pullParser;
mThemeCallback = themeCallback; mThemeCallback = themeCallback;
mMapsforgeTheme = theme.isMapsforgeTheme(); mMapsforgeTheme = theme.isMapsforgeTheme();
mScale = CanvasAdapter.getScale(); mScale = CanvasAdapter.getScale();
} }
@Override public void processRenderTheme() throws XmlPullParserException, IOException {
int eventType = mPullParser.getEventType();
do {
if (eventType == XmlPullParser.START_DOCUMENT) {
// no-op
} else if (eventType == XmlPullParser.START_TAG) {
startElement();
} else if (eventType == XmlPullParser.END_TAG) {
endElement();
} else if (eventType == XmlPullParser.TEXT) {
// not implemented
}
eventType = mPullParser.next();
} while (eventType != XmlPullParser.END_DOCUMENT);
endDocument();
}
public void endDocument() { public void endDocument() {
if (mMapsforgeTheme) { if (mMapsforgeTheme) {
// Building rule for Mapsforge themes // Building rule for Mapsforge themes
@@ -209,11 +240,12 @@ public class XmlThemeBuilder extends DefaultHandler {
return new RenderTheme(mMapBackground, mTextScale, rules, mLevels, mTransformKeyMap, mTransformTagMap, mMapsforgeTheme); return new RenderTheme(mMapBackground, mTextScale, rules, mLevels, mTransformKeyMap, mTransformTagMap, mMapsforgeTheme);
} }
@Override public void endElement() {
public void endElement(String uri, String localName, String qName) { qName = mPullParser.getName();
mElementStack.pop(); mElementStack.pop();
if (ELEMENT_NAME_MATCH_MAPSFORGE.equals(localName) || ELEMENT_NAME_MATCH_VTM.equals(localName)) { if (ELEMENT_NAME_MATCH_MAPSFORGE.equals(qName) || ELEMENT_NAME_MATCH_VTM.equals(qName)) {
mRuleStack.pop(); mRuleStack.pop();
if (mRuleStack.empty()) { if (mRuleStack.empty()) {
if (isVisible(mCurrentRule)) { if (isVisible(mCurrentRule)) {
@@ -222,7 +254,7 @@ public class XmlThemeBuilder extends DefaultHandler {
} else { } else {
mCurrentRule = mRuleStack.peek(); mCurrentRule = mRuleStack.peek();
} }
} else if (ELEMENT_NAME_STYLE_MENU.equals(localName)) { } else if (ELEMENT_NAME_STYLE_MENU.equals(qName)) {
// when we are finished parsing the menu part of the file, we can get the // when we are finished parsing the menu part of the file, we can get the
// categories to render from the initiator. This allows the creating action // categories to render from the initiator. This allows the creating action
// to select which of the menu options to choose // to select which of the menu options to choose
@@ -233,118 +265,108 @@ public class XmlThemeBuilder extends DefaultHandler {
} }
} }
@Override public void startElement() throws ThemeException {
public void error(SAXParseException exception) { qName = mPullParser.getName();
log.debug(exception.getMessage());
}
@Override
public void warning(SAXParseException exception) {
log.debug(exception.getMessage());
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws ThemeException {
try { try {
if (ELEMENT_NAME_RENDER_THEME.equals(localName)) { if (ELEMENT_NAME_RENDER_THEME.equals(qName)) {
checkState(localName, Element.RENDER_THEME); checkState(qName, Element.RENDER_THEME);
createRenderTheme(localName, attributes); createRenderTheme(qName);
} else if (ELEMENT_NAME_MATCH_MAPSFORGE.equals(localName) || ELEMENT_NAME_MATCH_VTM.equals(localName)) { } else if (ELEMENT_NAME_MATCH_MAPSFORGE.equals(qName) || ELEMENT_NAME_MATCH_VTM.equals(qName)) {
checkState(localName, Element.RULE); checkState(qName, Element.RULE);
RuleBuilder rule = createRule(localName, attributes); RuleBuilder rule = createRule(qName);
if (!mRuleStack.empty() && isVisible(rule)) { if (!mRuleStack.empty() && isVisible(rule)) {
mCurrentRule.addSubRule(rule); mCurrentRule.addSubRule(rule);
} }
mCurrentRule = rule; mCurrentRule = rule;
mRuleStack.push(mCurrentRule); mRuleStack.push(mCurrentRule);
} else if ("style-text".equals(localName)) { } else if ("style-text".equals(qName)) {
checkState(localName, Element.STYLE); checkState(qName, Element.STYLE);
handleTextElement(localName, attributes, true, false); handleTextElement(qName, true, false);
} else if ("style-symbol".equals(localName)) { } else if ("style-symbol".equals(qName)) {
checkState(localName, Element.STYLE); checkState(qName, Element.STYLE);
handleSymbolElement(localName, attributes, true); handleSymbolElement(qName, true);
} else if ("style-area".equals(localName)) { } else if ("style-area".equals(qName)) {
checkState(localName, Element.STYLE); checkState(qName, Element.STYLE);
handleAreaElement(localName, attributes, true); handleAreaElement(qName, true);
} else if ("style-line".equals(localName)) { } else if ("style-line".equals(qName)) {
checkState(localName, Element.STYLE); checkState(qName, Element.STYLE);
handleLineElement(localName, attributes, true, false); handleLineElement(qName, true, false);
} else if ("outline-layer".equals(localName)) { } else if ("outline-layer".equals(qName)) {
checkState(localName, Element.RENDERING_INSTRUCTION); checkState(qName, Element.RENDERING_INSTRUCTION);
LineStyle line = createLine(null, localName, attributes, mLevels++, true, false); LineStyle line = createLine(null, qName, mLevels++, true, false);
mStyles.put(OUTLINE_STYLE + line.style, line); mStyles.put(OUTLINE_STYLE + line.style, line);
} else if ("area".equals(localName)) { } else if ("area".equals(qName)) {
checkState(localName, Element.RENDERING_INSTRUCTION); checkState(qName, Element.RENDERING_INSTRUCTION);
handleAreaElement(localName, attributes, false); handleAreaElement(qName, false);
} else if ("caption".equals(localName)) { } else if ("caption".equals(qName)) {
checkState(localName, Element.RENDERING_INSTRUCTION); checkState(qName, Element.RENDERING_INSTRUCTION);
handleTextElement(localName, attributes, false, true); handleTextElement(qName, false, true);
} else if ("circle".equals(localName)) { } else if ("circle".equals(qName)) {
checkState(localName, Element.RENDERING_INSTRUCTION); checkState(qName, Element.RENDERING_INSTRUCTION);
CircleStyle circle = createCircle(localName, attributes, mLevels++); CircleStyle circle = createCircle(qName, mLevels++);
if (isVisible(circle)) if (isVisible(circle))
mCurrentRule.addStyle(circle); mCurrentRule.addStyle(circle);
} else if ("line".equals(localName)) { } else if ("line".equals(qName)) {
checkState(localName, Element.RENDERING_INSTRUCTION); checkState(qName, Element.RENDERING_INSTRUCTION);
handleLineElement(localName, attributes, false, false); handleLineElement(qName, false, false);
} else if ("text".equals(localName) || "pathText".equals(localName)) { } else if ("text".equals(qName) || "pathText".equals(qName)) {
checkState(localName, Element.RENDERING_INSTRUCTION); checkState(qName, Element.RENDERING_INSTRUCTION);
handleTextElement(localName, attributes, false, false); handleTextElement(qName, false, false);
} else if ("symbol".equals(localName)) { } else if ("symbol".equals(qName)) {
checkState(localName, Element.RENDERING_INSTRUCTION); checkState(qName, Element.RENDERING_INSTRUCTION);
handleSymbolElement(localName, attributes, false); handleSymbolElement(qName, false);
} else if ("outline".equals(localName)) { } else if ("outline".equals(qName)) {
checkState(localName, Element.RENDERING_INSTRUCTION); checkState(qName, Element.RENDERING_INSTRUCTION);
LineStyle outline = createOutline(attributes.getValue("use"), attributes); LineStyle outline = createOutline(getStringAttribute("use"));
if (outline != null && isVisible(outline)) if (outline != null && isVisible(outline))
mCurrentRule.addStyle(outline); mCurrentRule.addStyle(outline);
} else if ("extrusion".equals(localName)) { } else if ("extrusion".equals(qName)) {
checkState(localName, Element.RENDERING_INSTRUCTION); checkState(qName, Element.RENDERING_INSTRUCTION);
ExtrusionStyle extrusion = createExtrusion(localName, attributes, mLevels++); ExtrusionStyle extrusion = createExtrusion(qName, mLevels++);
if (isVisible(extrusion)) if (isVisible(extrusion))
mCurrentRule.addStyle(extrusion); mCurrentRule.addStyle(extrusion);
} else if ("lineSymbol".equals(localName)) { } else if ("lineSymbol".equals(qName)) {
checkState(localName, Element.RENDERING_INSTRUCTION); checkState(qName, Element.RENDERING_INSTRUCTION);
handleLineElement(localName, attributes, false, true); handleLineElement(qName, false, true);
} else if ("atlas".equals(localName)) { } else if ("atlas".equals(qName)) {
checkState(localName, Element.ATLAS); checkState(qName, Element.ATLAS);
createAtlas(localName, attributes); createAtlas(qName);
} else if ("rect".equals(localName)) { } else if ("rect".equals(qName)) {
checkState(localName, Element.RECT); checkState(qName, Element.RECT);
createTextureRegion(localName, attributes); createTextureRegion(qName);
} else if ("cat".equals(localName)) { } else if ("cat".equals(qName)) {
checkState(qName, Element.RENDERING_STYLE); checkState(qName, Element.RENDERING_STYLE);
mCurrentLayer.addCategory(getStringAttribute(attributes, "id")); mCurrentLayer.addCategory(getStringAttribute("id"));
} else if ("layer".equals(localName)) { } else if ("layer".equals(qName)) {
// render theme menu layer // render theme menu layer
checkState(qName, Element.RENDERING_STYLE); checkState(qName, Element.RENDERING_STYLE);
boolean enabled = false; boolean enabled = false;
if (getStringAttribute(attributes, "enabled") != null) { if (getStringAttribute("enabled") != null) {
enabled = Boolean.valueOf(getStringAttribute(attributes, "enabled")); enabled = Boolean.parseBoolean(getStringAttribute("enabled"));
} }
boolean visible = Boolean.valueOf(getStringAttribute(attributes, "visible")); boolean visible = Boolean.parseBoolean(getStringAttribute("visible"));
mCurrentLayer = mRenderThemeStyleMenu.createLayer(getStringAttribute(attributes, "id"), visible, enabled); mCurrentLayer = mRenderThemeStyleMenu.createLayer(getStringAttribute("id"), visible, enabled);
String parent = getStringAttribute(attributes, "parent"); String parent = getStringAttribute("parent");
if (null != parent) { if (null != parent) {
XmlRenderThemeStyleLayer parentEntry = mRenderThemeStyleMenu.getLayer(parent); XmlRenderThemeStyleLayer parentEntry = mRenderThemeStyleMenu.getLayer(parent);
if (null != parentEntry) { if (null != parentEntry) {
@@ -357,40 +379,38 @@ public class XmlThemeBuilder extends DefaultHandler {
} }
} }
} else if ("name".equals(localName)) { } else if ("name".equals(qName)) {
// render theme menu name // render theme menu name
checkState(qName, Element.RENDERING_STYLE); checkState(qName, Element.RENDERING_STYLE);
mCurrentLayer.addTranslation(getStringAttribute(attributes, "lang"), getStringAttribute(attributes, "value")); mCurrentLayer.addTranslation(getStringAttribute("lang"), getStringAttribute("value"));
} else if ("overlay".equals(localName)) { } else if ("overlay".equals(qName)) {
// render theme menu overlay // render theme menu overlay
checkState(qName, Element.RENDERING_STYLE); checkState(qName, Element.RENDERING_STYLE);
XmlRenderThemeStyleLayer overlay = mRenderThemeStyleMenu.getLayer(getStringAttribute(attributes, "id")); XmlRenderThemeStyleLayer overlay = mRenderThemeStyleMenu.getLayer(getStringAttribute("id"));
if (overlay != null) { if (overlay != null) {
mCurrentLayer.addOverlay(overlay); mCurrentLayer.addOverlay(overlay);
} }
} else if ("stylemenu".equals(localName)) { } else if ("stylemenu".equals(qName)) {
checkState(qName, Element.RENDERING_STYLE); checkState(qName, Element.RENDERING_STYLE);
mRenderThemeStyleMenu = new XmlRenderThemeStyleMenu(getStringAttribute(attributes, "id"), mRenderThemeStyleMenu = new XmlRenderThemeStyleMenu(getStringAttribute("id"),
getStringAttribute(attributes, "defaultlang"), getStringAttribute(attributes, "defaultvalue")); getStringAttribute("defaultlang"), getStringAttribute("defaultvalue"));
} else if ("tag-transform".equals(localName)) { } else if ("tag-transform".equals(qName)) {
checkState(qName, Element.TAG_TRANSFORM); checkState(qName, Element.TAG_TRANSFORM);
tagTransform(localName, attributes); tagTransform(qName);
} else { } else {
log.error("unknown element: {}", localName); log.error("unknown element: {}", qName);
throw new SAXException("unknown element: " + localName); throw new XmlPullParserException("unknown element: " + qName);
} }
} catch (SAXException e) { } catch (XmlPullParserException | IOException e) {
throw new ThemeException(e.getMessage());
} catch (IOException e) {
throw new ThemeException(e.getMessage()); throw new ThemeException(e.getMessage());
} }
} }
private RuleBuilder createRule(String localName, Attributes attributes) { private RuleBuilder createRule(String qName) {
String cat = null; String cat = null;
int element = Rule.Element.ANY; int element = Rule.Element.ANY;
int closed = Closed.ANY; int closed = Closed.ANY;
@@ -400,9 +420,9 @@ public class XmlThemeBuilder extends DefaultHandler {
byte zoomMax = Byte.MAX_VALUE; byte zoomMax = Byte.MAX_VALUE;
int selector = 0; int selector = 0;
for (int i = 0; i < attributes.getLength(); i++) { for (int i = 0, n = mPullParser.getAttributeCount(); i < n; ++i) {
String name = attributes.getLocalName(i); String name = mPullParser.getAttributeName(i);
String value = attributes.getValue(i); String value = mPullParser.getAttributeValue(i);
if ("e".equals(name)) { if ("e".equals(name)) {
String val = value.toUpperCase(Locale.ENGLISH); String val = value.toUpperCase(Locale.ENGLISH);
@@ -440,7 +460,7 @@ public class XmlThemeBuilder extends DefaultHandler {
if ("when-matched".equals(value)) if ("when-matched".equals(value))
selector |= Selector.WHEN_MATCHED; selector |= Selector.WHEN_MATCHED;
} else { } else {
logUnknownAttribute(localName, name, value, i); logUnknownAttribute(qName, name, value, i);
} }
} }
@@ -474,10 +494,9 @@ public class XmlThemeBuilder extends DefaultHandler {
return texture; return texture;
} }
private void handleLineElement(String localName, Attributes attributes, boolean isStyle, boolean hasSymbol) private void handleLineElement(String qName, boolean isStyle, boolean hasSymbol) {
throws SAXException {
String use = attributes.getValue("use"); String use = getStringAttribute("use");
LineStyle style = null; LineStyle style = null;
if (use != null) { if (use != null) {
@@ -488,7 +507,7 @@ public class XmlThemeBuilder extends DefaultHandler {
} }
} }
LineStyle line = createLine(style, localName, attributes, mLevels++, false, hasSymbol); LineStyle line = createLine(style, qName, mLevels++, false, hasSymbol);
if (isStyle) { if (isStyle) {
mStyles.put(LINE_STYLE + line.style, line); mStyles.put(LINE_STYLE + line.style, line);
@@ -497,9 +516,9 @@ public class XmlThemeBuilder extends DefaultHandler {
mCurrentRule.addStyle(line); mCurrentRule.addStyle(line);
/* Note 'outline' will not be inherited, it's just a /* Note 'outline' will not be inherited, it's just a
* shortcut to add the outline RenderInstruction. */ * shortcut to add the outline RenderInstruction. */
String outlineValue = attributes.getValue("outline"); String outlineValue = getStringAttribute("outline");
if (outlineValue != null) { if (outlineValue != null) {
LineStyle outline = createOutline(outlineValue, attributes); LineStyle outline = createOutline(outlineValue);
if (outline != null) if (outline != null)
mCurrentRule.addStyle(outline); mCurrentRule.addStyle(outline);
} }
@@ -513,17 +532,16 @@ public class XmlThemeBuilder extends DefaultHandler {
* @param isOutline is outline layer * @param isOutline is outline layer
* @return a new Line with the given rendering attributes. * @return a new Line with the given rendering attributes.
*/ */
private LineStyle createLine(LineStyle line, String elementName, Attributes attributes, private LineStyle createLine(LineStyle line, String elementName, int level, boolean isOutline, boolean hasSymbol) {
int level, boolean isOutline, boolean hasSymbol) {
LineBuilder<?> b = mLineBuilder.set(line); LineBuilder<?> b = mLineBuilder.set(line);
b.isOutline(isOutline); b.isOutline(isOutline);
b.level(level); b.level(level);
b.themeCallback(mThemeCallback); b.themeCallback(mThemeCallback);
String src = null; String src = null;
for (int i = 0; i < attributes.getLength(); i++) { for (int i = 0, n = mPullParser.getAttributeCount(); i < n; ++i) {
String name = attributes.getLocalName(i); String name = mPullParser.getAttributeName(i);
String value = attributes.getValue(i); String value = mPullParser.getAttributeValue(i);
if ("id".equals(name)) if ("id".equals(name))
b.style = value; b.style = value;
@@ -544,7 +562,7 @@ public class XmlThemeBuilder extends DefaultHandler {
b.color(value); b.color(value);
else if ("width".equals(name) || "stroke-width".equals(name)) { else if ("width".equals(name) || "stroke-width".equals(name)) {
b.strokeWidth = parseFloat(value) * mScale * mStrokeScale; b.strokeWidth = Float.parseFloat(value) * mScale * mStrokeScale;
if (line == null) { if (line == null) {
if (!isOutline) if (!isOutline)
validateNonNegative("width", b.strokeWidth); validateNonNegative("width", b.strokeWidth);
@@ -558,16 +576,16 @@ public class XmlThemeBuilder extends DefaultHandler {
b.cap = Cap.valueOf(value.toUpperCase(Locale.ENGLISH)); b.cap = Cap.valueOf(value.toUpperCase(Locale.ENGLISH));
else if ("fix".equals(name)) else if ("fix".equals(name))
b.fixed = parseBoolean(value); b.fixed = Boolean.parseBoolean(value);
else if ("stipple".equals(name)) else if ("stipple".equals(name))
b.stipple = Math.round(parseInt(value) * mScale * mStrokeScale); b.stipple = Math.round(Integer.parseInt(value) * mScale * mStrokeScale);
else if ("stipple-stroke".equals(name)) else if ("stipple-stroke".equals(name))
b.stippleColor(value); b.stippleColor(value);
else if ("stipple-width".equals(name)) else if ("stipple-width".equals(name))
b.stippleWidth = parseFloat(value); b.stippleWidth = Float.parseFloat(value);
else if ("fade".equals(name)) else if ("fade".equals(name))
b.fadeScale = Integer.parseInt(value); b.fadeScale = Integer.parseInt(value);
@@ -576,7 +594,7 @@ public class XmlThemeBuilder extends DefaultHandler {
; //min = Float.parseFloat(value); ; //min = Float.parseFloat(value);
else if ("blur".equals(name)) else if ("blur".equals(name))
b.blur = parseFloat(value); b.blur = Float.parseFloat(value);
else if ("style".equals(name)) else if ("style".equals(name))
; // ignore ; // ignore
@@ -646,8 +664,10 @@ public class XmlThemeBuilder extends DefaultHandler {
b.stippleWidth = 1; b.stippleWidth = 1;
b.stippleColor = b.fillColor; b.stippleColor = b.fillColor;
} else { } else {
if (src != null) if (src != null) {
b.texture = Utils.loadTexture(mTheme.getRelativePathPrefix(), src, b.symbolWidth, b.symbolHeight, b.symbolPercent); float symbolScale = Parameters.SYMBOL_SCALING == Parameters.SymbolScaling.ALL ? CanvasAdapter.symbolScale : 1;
b.texture = Utils.loadTexture(mTheme.getRelativePathPrefix(), src, b.symbolWidth, b.symbolHeight, (int) (b.symbolPercent * symbolScale));
}
if (b.texture != null && hasSymbol) { if (b.texture != null && hasSymbol) {
// Line symbol // Line symbol
@@ -671,10 +691,9 @@ public class XmlThemeBuilder extends DefaultHandler {
return b.build(); return b.build();
} }
private void handleAreaElement(String localName, Attributes attributes, boolean isStyle) private void handleAreaElement(String qName, boolean isStyle) {
throws SAXException {
String use = attributes.getValue("use"); String use = getStringAttribute("use");
AreaStyle style = null; AreaStyle style = null;
if (use != null) { if (use != null) {
@@ -685,7 +704,7 @@ public class XmlThemeBuilder extends DefaultHandler {
} }
} }
AreaStyle area = createArea(style, localName, attributes, mLevels++); AreaStyle area = createArea(style, qName, mLevels++);
if (isStyle) { if (isStyle) {
mStyles.put(AREA_STYLE + area.style, area); mStyles.put(AREA_STYLE + area.style, area);
@@ -698,16 +717,15 @@ public class XmlThemeBuilder extends DefaultHandler {
/** /**
* @return a new Area with the given rendering attributes. * @return a new Area with the given rendering attributes.
*/ */
private AreaStyle createArea(AreaStyle area, String elementName, Attributes attributes, private AreaStyle createArea(AreaStyle area, String elementName, int level) {
int level) {
AreaBuilder<?> b = mAreaBuilder.set(area); AreaBuilder<?> b = mAreaBuilder.set(area);
b.level(level); b.level(level);
b.themeCallback(mThemeCallback); b.themeCallback(mThemeCallback);
String src = null; String src = null;
for (int i = 0; i < attributes.getLength(); i++) { for (int i = 0, n = mPullParser.getAttributeCount(); i < n; ++i) {
String name = attributes.getLocalName(i); String name = mPullParser.getAttributeName(i);
String value = attributes.getValue(i); String value = mPullParser.getAttributeValue(i);
if ("id".equals(name)) if ("id".equals(name))
b.style = value; b.style = value;
@@ -766,15 +784,15 @@ public class XmlThemeBuilder extends DefaultHandler {
return b.build(); return b.build();
} }
private LineStyle createOutline(String style, Attributes attributes) { private LineStyle createOutline(String style) {
if (style != null) { if (style != null) {
LineStyle line = (LineStyle) mStyles.get(OUTLINE_STYLE + style); LineStyle line = (LineStyle) mStyles.get(OUTLINE_STYLE + style);
if (line != null && line.outline) { if (line != null && line.outline) {
String cat = null; String cat = null;
for (int i = 0; i < attributes.getLength(); i++) { for (int i = 0, n = mPullParser.getAttributeCount(); i < n; ++i) {
String name = attributes.getLocalName(i); String name = mPullParser.getAttributeName(i);
String value = attributes.getValue(i); String value = mPullParser.getAttributeValue(i);
if ("cat".equals(name)) { if ("cat".equals(name)) {
cat = value; cat = value;
@@ -790,12 +808,12 @@ public class XmlThemeBuilder extends DefaultHandler {
return null; return null;
} }
private void createAtlas(String elementName, Attributes attributes) throws IOException { private void createAtlas(String elementName) throws IOException {
String img = null; String img = null;
for (int i = 0; i < attributes.getLength(); i++) { for (int i = 0, n = mPullParser.getAttributeCount(); i < n; ++i) {
String name = attributes.getLocalName(i); String name = mPullParser.getAttributeName(i);
String value = attributes.getValue(i); String value = mPullParser.getAttributeValue(i);
if ("img".equals(name)) { if ("img".equals(name)) {
img = value; img = value;
@@ -810,16 +828,16 @@ public class XmlThemeBuilder extends DefaultHandler {
mTextureAtlas = new TextureAtlas(bitmap); mTextureAtlas = new TextureAtlas(bitmap);
} }
private void createTextureRegion(String elementName, Attributes attributes) { private void createTextureRegion(String elementName) {
if (mTextureAtlas == null) if (mTextureAtlas == null)
return; return;
String regionName = null; String regionName = null;
Rect r = null; Rect r = null;
for (int i = 0, n = attributes.getLength(); i < n; i++) { for (int i = 0, n = mPullParser.getAttributeCount(); i < n; ++i) {
String name = attributes.getLocalName(i); String name = mPullParser.getAttributeName(i);
String value = attributes.getValue(i); String value = mPullParser.getAttributeValue(i);
if ("id".equals(name)) { if ("id".equals(name)) {
regionName = value; regionName = value;
@@ -841,12 +859,12 @@ public class XmlThemeBuilder extends DefaultHandler {
mTextureAtlas.addTextureRegion(regionName.intern(), r); mTextureAtlas.addTextureRegion(regionName.intern(), r);
} }
private void checkElement(String elementName, Element element) throws SAXException { private void checkElement(String elementName, Element element) throws XmlPullParserException {
Element parentElement; Element parentElement;
switch (element) { switch (element) {
case RENDER_THEME: case RENDER_THEME:
if (!mElementStack.empty()) { if (!mElementStack.empty()) {
throw new SAXException(UNEXPECTED_ELEMENT_STACK_NOT_EMPTY + elementName); throw new XmlPullParserException(UNEXPECTED_ELEMENT_STACK_NOT_EMPTY + elementName);
} }
return; return;
@@ -854,34 +872,34 @@ public class XmlThemeBuilder extends DefaultHandler {
parentElement = mElementStack.peek(); parentElement = mElementStack.peek();
if (parentElement != Element.RENDER_THEME if (parentElement != Element.RENDER_THEME
&& parentElement != Element.RULE) { && parentElement != Element.RULE) {
throw new SAXException(UNEXPECTED_ELEMENT_RULE_PARENT_ELEMENT_MISMATCH + elementName); throw new XmlPullParserException(UNEXPECTED_ELEMENT_RULE_PARENT_ELEMENT_MISMATCH + elementName);
} }
return; return;
case STYLE: case STYLE:
parentElement = mElementStack.peek(); parentElement = mElementStack.peek();
if (parentElement != Element.RENDER_THEME) { if (parentElement != Element.RENDER_THEME) {
throw new SAXException(UNEXPECTED_ELEMENT_STYLE_PARENT_ELEMENT_MISMATCH + elementName); throw new XmlPullParserException(UNEXPECTED_ELEMENT_STYLE_PARENT_ELEMENT_MISMATCH + elementName);
} }
return; return;
case RENDERING_INSTRUCTION: case RENDERING_INSTRUCTION:
if (mElementStack.peek() != Element.RULE) { if (mElementStack.peek() != Element.RULE) {
throw new SAXException(UNEXPECTED_ELEMENT_RENDERING_INSTRUCTION_PARENT_ELEMENT_MISMATCH + elementName); throw new XmlPullParserException(UNEXPECTED_ELEMENT_RENDERING_INSTRUCTION_PARENT_ELEMENT_MISMATCH + elementName);
} }
return; return;
case ATLAS: case ATLAS:
parentElement = mElementStack.peek(); parentElement = mElementStack.peek();
if (parentElement != Element.RENDER_THEME) { if (parentElement != Element.RENDER_THEME) {
throw new SAXException(UNEXPECTED_ELEMENT_ATLAS_PARENT_ELEMENT_MISMATCH + elementName); throw new XmlPullParserException(UNEXPECTED_ELEMENT_ATLAS_PARENT_ELEMENT_MISMATCH + elementName);
} }
return; return;
case RECT: case RECT:
parentElement = mElementStack.peek(); parentElement = mElementStack.peek();
if (parentElement != Element.ATLAS) { if (parentElement != Element.ATLAS) {
throw new SAXException(UNEXPECTED_ELEMENT_RECT_PARENT_ELEMENT_MISMATCH + elementName); throw new XmlPullParserException(UNEXPECTED_ELEMENT_RECT_PARENT_ELEMENT_MISMATCH + elementName);
} }
return; return;
@@ -891,28 +909,28 @@ public class XmlThemeBuilder extends DefaultHandler {
case TAG_TRANSFORM: case TAG_TRANSFORM:
parentElement = mElementStack.peek(); parentElement = mElementStack.peek();
if (parentElement != Element.RENDER_THEME) { if (parentElement != Element.RENDER_THEME) {
throw new SAXException(UNEXPECTED_ELEMENT_TAG_TRANSFORM_PARENT_ELEMENT_MISMATCH + elementName); throw new XmlPullParserException(UNEXPECTED_ELEMENT_TAG_TRANSFORM_PARENT_ELEMENT_MISMATCH + elementName);
} }
return; return;
} }
throw new SAXException("unknown enum value: " + element); throw new XmlPullParserException("unknown enum value: " + element);
} }
private void checkState(String elementName, Element element) throws SAXException { private void checkState(String elementName, Element element) throws XmlPullParserException {
checkElement(elementName, element); checkElement(elementName, element);
mElementStack.push(element); mElementStack.push(element);
} }
private void createRenderTheme(String elementName, Attributes attributes) { private void createRenderTheme(String elementName) {
Integer version = null; Integer version = null;
int mapBackground = Color.WHITE; int mapBackground = Color.WHITE;
float baseStrokeWidth = 1; float baseStrokeWidth = 1;
float baseTextScale = 1; float baseTextScale = 1;
for (int i = 0; i < attributes.getLength(); ++i) { for (int i = 0, n = mPullParser.getAttributeCount(); i < n; ++i) {
String name = attributes.getLocalName(i); String name = mPullParser.getAttributeName(i);
String value = attributes.getValue(i); String value = mPullParser.getAttributeValue(i);
if ("schemaLocation".equals(name)) if ("schemaLocation".equals(name))
continue; continue;
@@ -950,10 +968,9 @@ public class XmlThemeBuilder extends DefaultHandler {
mTextScale = baseTextScale; mTextScale = baseTextScale;
} }
private void handleTextElement(String localName, Attributes attributes, boolean isStyle, private void handleTextElement(String qName, boolean isStyle, boolean isCaption) {
boolean isCaption) throws SAXException {
String style = attributes.getValue("use"); String style = getStringAttribute("use");
TextBuilder<?> pt = null; TextBuilder<?> pt = null;
if (style != null) { if (style != null) {
@@ -964,7 +981,7 @@ public class XmlThemeBuilder extends DefaultHandler {
} }
} }
TextBuilder<?> b = createText(localName, attributes, isCaption, pt); TextBuilder<?> b = createText(qName, isCaption, pt);
if (isStyle) { if (isStyle) {
log.debug("put style {}", b.style); log.debug("put style {}", b.style);
mTextStyles.put(b.style, TextStyle.builder().from(b)); mTextStyles.put(b.style, TextStyle.builder().from(b));
@@ -979,8 +996,7 @@ public class XmlThemeBuilder extends DefaultHandler {
* @param caption ... * @param caption ...
* @return a new Text with the given rendering attributes. * @return a new Text with the given rendering attributes.
*/ */
private TextBuilder<?> createText(String elementName, Attributes attributes, private TextBuilder<?> createText(String elementName, boolean caption, TextBuilder<?> style) {
boolean caption, TextBuilder<?> style) {
TextBuilder<?> b; TextBuilder<?> b;
if (style == null) { if (style == null) {
b = mTextBuilder.reset(); b = mTextBuilder.reset();
@@ -995,9 +1011,9 @@ public class XmlThemeBuilder extends DefaultHandler {
b.priority = DEFAULT_PRIORITY; b.priority = DEFAULT_PRIORITY;
} }
for (int i = 0; i < attributes.getLength(); i++) { for (int i = 0, n = mPullParser.getAttributeCount(); i < n; ++i) {
String name = attributes.getLocalName(i); String name = mPullParser.getAttributeName(i);
String value = attributes.getValue(i); String value = mPullParser.getAttributeValue(i);
if ("id".equals(name)) if ("id".equals(name))
b.style = value; b.style = value;
@@ -1046,7 +1062,7 @@ public class XmlThemeBuilder extends DefaultHandler {
else if ("dy".equals(name)) else if ("dy".equals(name))
// NB: minus.. // NB: minus..
b.dy = -Float.parseFloat(value) * mScale; b.dy = -Float.parseFloat(value) * mScale * CanvasAdapter.symbolScale;
else if ("symbol".equals(name)) else if ("symbol".equals(name))
symbol = value; symbol = value;
@@ -1071,7 +1087,7 @@ public class XmlThemeBuilder extends DefaultHandler {
if (b.dy == 0) { if (b.dy == 0) {
value = "above".equals(value) ? "20" : "-20"; value = "above".equals(value) ? "20" : "-20";
// NB: minus.. // NB: minus..
b.dy = -Float.parseFloat(value) * mScale; b.dy = -Float.parseFloat(value) * mScale * CanvasAdapter.symbolScale;
} }
} else } else
@@ -1086,7 +1102,7 @@ public class XmlThemeBuilder extends DefaultHandler {
String lowValue = symbol.toLowerCase(Locale.ENGLISH); String lowValue = symbol.toLowerCase(Locale.ENGLISH);
if (lowValue.endsWith(".png") || lowValue.endsWith(".svg")) { if (lowValue.endsWith(".png") || lowValue.endsWith(".svg")) {
try { try {
b.bitmap = CanvasAdapter.getBitmapAsset(mTheme.getRelativePathPrefix(), symbol, b.symbolWidth, b.symbolHeight, b.symbolPercent); b.bitmap = CanvasAdapter.getBitmapAsset(mTheme.getRelativePathPrefix(), symbol, b.symbolWidth, b.symbolHeight, (int) (b.symbolPercent * CanvasAdapter.symbolScale));
} catch (Exception e) { } catch (Exception e) {
log.error("{}: {}", symbol, e.getMessage()); log.error("{}: {}", symbol, e.getMessage());
} }
@@ -1101,14 +1117,14 @@ public class XmlThemeBuilder extends DefaultHandler {
* @param level the drawing level of this instruction. * @param level the drawing level of this instruction.
* @return a new Circle with the given rendering attributes. * @return a new Circle with the given rendering attributes.
*/ */
private CircleStyle createCircle(String elementName, Attributes attributes, int level) { private CircleStyle createCircle(String elementName, int level) {
CircleBuilder<?> b = mCircleBuilder.reset(); CircleBuilder<?> b = mCircleBuilder.reset();
b.level(level); b.level(level);
b.themeCallback(mThemeCallback); b.themeCallback(mThemeCallback);
for (int i = 0; i < attributes.getLength(); i++) { for (int i = 0, n = mPullParser.getAttributeCount(); i < n; ++i) {
String name = attributes.getLocalName(i); String name = mPullParser.getAttributeName(i);
String value = attributes.getValue(i); String value = mPullParser.getAttributeValue(i);
if ("r".equals(name) || "radius".equals(name)) if ("r".equals(name) || "radius".equals(name))
b.radius(Float.parseFloat(value) * mScale * mStrokeScale); b.radius(Float.parseFloat(value) * mScale * mStrokeScale);
@@ -1139,10 +1155,9 @@ public class XmlThemeBuilder extends DefaultHandler {
return b.build(); return b.build();
} }
private void handleSymbolElement(String localName, Attributes attributes, boolean isStyle) private void handleSymbolElement(String qName, boolean isStyle) {
throws SAXException {
String style = attributes.getValue("use"); String style = getStringAttribute("use");
SymbolBuilder<?> ps = null; SymbolBuilder<?> ps = null;
if (style != null) { if (style != null) {
@@ -1153,7 +1168,7 @@ public class XmlThemeBuilder extends DefaultHandler {
} }
} }
SymbolBuilder<?> b = createSymbol(localName, attributes, ps); SymbolBuilder<?> b = createSymbol(qName, ps);
if (isStyle) { if (isStyle) {
log.debug("put style {}", b.style); log.debug("put style {}", b.style);
mSymbolStyles.put(b.style, SymbolStyle.builder().from(b)); mSymbolStyles.put(b.style, SymbolStyle.builder().from(b));
@@ -1167,8 +1182,7 @@ public class XmlThemeBuilder extends DefaultHandler {
/** /**
* @return a new Symbol with the given rendering attributes. * @return a new Symbol with the given rendering attributes.
*/ */
private SymbolBuilder<?> createSymbol(String elementName, Attributes attributes, private SymbolBuilder<?> createSymbol(String elementName, SymbolBuilder<?> style) {
SymbolBuilder<?> style) {
SymbolBuilder<?> b; SymbolBuilder<?> b;
if (style == null) if (style == null)
b = mSymbolBuilder.reset(); b = mSymbolBuilder.reset();
@@ -1176,9 +1190,9 @@ public class XmlThemeBuilder extends DefaultHandler {
b = mSymbolBuilder.from(style); b = mSymbolBuilder.from(style);
b.themeCallback(mThemeCallback); b.themeCallback(mThemeCallback);
for (int i = 0; i < attributes.getLength(); i++) { for (int i = 0, n = mPullParser.getAttributeCount(); i < n; ++i) {
String name = attributes.getLocalName(i); String name = mPullParser.getAttributeName(i);
String value = attributes.getValue(i); String value = mPullParser.getAttributeValue(i);
if ("id".equals(name)) if ("id".equals(name))
b.style = value; b.style = value;
@@ -1232,7 +1246,17 @@ public class XmlThemeBuilder extends DefaultHandler {
String lowSrc = b.src.toLowerCase(Locale.ENGLISH); String lowSrc = b.src.toLowerCase(Locale.ENGLISH);
if (lowSrc.endsWith(".png") || lowSrc.endsWith(".svg")) { if (lowSrc.endsWith(".png") || lowSrc.endsWith(".svg")) {
try { try {
Bitmap bitmap = CanvasAdapter.getBitmapAsset(mTheme.getRelativePathPrefix(), b.src, b.symbolWidth, b.symbolHeight, b.symbolPercent); float symbolScale = 1;
switch (Parameters.SYMBOL_SCALING) {
case ALL:
symbolScale = CanvasAdapter.symbolScale;
break;
case POI:
if (!b.repeat)
symbolScale = CanvasAdapter.symbolScale;
break;
}
Bitmap bitmap = CanvasAdapter.getBitmapAsset(mTheme.getRelativePathPrefix(), b.src, b.symbolWidth, b.symbolHeight, (int) (b.symbolPercent * symbolScale));
if (bitmap != null) if (bitmap != null)
return buildSymbol(b, b.src, bitmap); return buildSymbol(b, b.src, bitmap);
} catch (Exception e) { } catch (Exception e) {
@@ -1247,14 +1271,14 @@ public class XmlThemeBuilder extends DefaultHandler {
return b.bitmap(bitmap).build(); return b.bitmap(bitmap).build();
} }
private ExtrusionStyle createExtrusion(String elementName, Attributes attributes, int level) { private ExtrusionStyle createExtrusion(String elementName, int level) {
ExtrusionBuilder<?> b = mExtrusionBuilder.reset(); ExtrusionBuilder<?> b = mExtrusionBuilder.reset();
b.level(level); b.level(level);
b.themeCallback(mThemeCallback); b.themeCallback(mThemeCallback);
for (int i = 0; i < attributes.getLength(); ++i) { for (int i = 0, n = mPullParser.getAttributeCount(); i < n; ++i) {
String name = attributes.getLocalName(i); String name = mPullParser.getAttributeName(i);
String value = attributes.getValue(i); String value = mPullParser.getAttributeValue(i);
if ("cat".equals(name)) if ("cat".equals(name))
b.cat(value); b.cat(value);
@@ -1287,10 +1311,11 @@ public class XmlThemeBuilder extends DefaultHandler {
return b.build(); return b.build();
} }
private String getStringAttribute(Attributes attributes, String name) { private String getStringAttribute(String name) {
for (int i = 0; i < attributes.getLength(); ++i) { int n = mPullParser.getAttributeCount();
if (attributes.getLocalName(i).equals(name)) { for (int i = 0; i < n; i++) {
return attributes.getValue(i); if (mPullParser.getAttributeName(i).equals(name)) {
return mPullParser.getAttributeValue(i);
} }
} }
return null; return null;
@@ -1300,7 +1325,7 @@ public class XmlThemeBuilder extends DefaultHandler {
* A style is visible if categories is not set or the style has no category * A style is visible if categories is not set or the style has no category
* or the categories contain the style's category. * or the categories contain the style's category.
*/ */
private boolean isVisible(RenderStyle renderStyle) { private boolean isVisible(RenderStyle<?> renderStyle) {
return mCategories == null || renderStyle.cat == null || mCategories.contains(renderStyle.cat); return mCategories == null || renderStyle.cat == null || mCategories.contains(renderStyle.cat);
} }
@@ -1321,13 +1346,13 @@ public class XmlThemeBuilder extends DefaultHandler {
return dashIntervals; return dashIntervals;
} }
private void tagTransform(String localName, Attributes attributes) { private void tagTransform(String qName) {
String k, v, libK, libV; String k, v, libK, libV;
k = v = libK = libV = null; k = v = libK = libV = null;
for (int i = 0; i < attributes.getLength(); i++) { for (int i = 0, n = mPullParser.getAttributeCount(); i < n; ++i) {
String name = attributes.getLocalName(i); String name = mPullParser.getAttributeName(i);
String value = attributes.getValue(i); String value = mPullParser.getAttributeValue(i);
switch (name) { switch (name) {
case "k": case "k":
@@ -1343,12 +1368,12 @@ public class XmlThemeBuilder extends DefaultHandler {
libV = value; libV = value;
break; break;
default: default:
logUnknownAttribute(localName, name, value, i); logUnknownAttribute(qName, name, value, i);
} }
} }
if (k == null || k.isEmpty() || libK == null || libK.isEmpty()) { if (k == null || k.isEmpty() || libK == null || libK.isEmpty()) {
log.debug("empty key in element " + localName); log.debug("empty key in element " + qName);
return; return;
} }

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright 2010, 2011, 2012 mapsforge.org * Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2017-2020 devemux86
* *
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
* *
@@ -20,7 +21,8 @@ import org.oscim.tiling.source.mapfile.header.SubFileParameter;
import org.oscim.utils.LRUCache; import org.oscim.utils.LRUCache;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
@@ -44,15 +46,15 @@ class IndexCache {
* SubFileParameter.BYTES_PER_INDEX_ENTRY; * SubFileParameter.BYTES_PER_INDEX_ENTRY;
private final Map<IndexCacheEntryKey, byte[]> map; private final Map<IndexCacheEntryKey, byte[]> map;
private final RandomAccessFile randomAccessFile; private final FileChannel fileChannel;
/** /**
* @param randomAccessFile the map file from which the index should be read and cached. * @param inputChannel the map file from which the index should be read and cached.
* @param capacity the maximum number of entries in the cache. * @param capacity the maximum number of entries in the cache.
* @throws IllegalArgumentException if the capacity is negative. * @throws IllegalArgumentException if the capacity is negative.
*/ */
IndexCache(RandomAccessFile randomAccessFile, int capacity) { IndexCache(FileChannel inputChannel, int capacity) {
this.randomAccessFile = randomAccessFile; this.fileChannel = inputChannel;
this.map = Collections.synchronizedMap(new LRUCache<IndexCacheEntryKey, byte[]>(capacity)); this.map = Collections.synchronizedMap(new LRUCache<IndexCacheEntryKey, byte[]>(capacity));
} }
@@ -97,11 +99,14 @@ class IndexCache {
int remainingIndexSize = (int) (subFileParameter.indexEndAddress - indexBlockPosition); int remainingIndexSize = (int) (subFileParameter.indexEndAddress - indexBlockPosition);
int indexBlockSize = Math.min(SIZE_OF_INDEX_BLOCK, remainingIndexSize); int indexBlockSize = Math.min(SIZE_OF_INDEX_BLOCK, remainingIndexSize);
indexBlock = new byte[indexBlockSize]; indexBlock = new byte[indexBlockSize];
ByteBuffer indexBlockWrapper = ByteBuffer.wrap(indexBlock, 0, indexBlockSize);
this.randomAccessFile.seek(indexBlockPosition); synchronized (this.fileChannel) {
if (this.randomAccessFile.read(indexBlock, 0, indexBlockSize) != indexBlockSize) { this.fileChannel.position(indexBlockPosition);
LOG.warning("reading the current index block has failed"); if (this.fileChannel.read(indexBlockWrapper) != indexBlockSize) {
return -1; LOG.warning("reading the current index block has failed");
return -1;
}
} }
// put the index block in the map // put the index block in the map

View File

@@ -2,7 +2,7 @@
* Copyright 2010, 2011, 2012 mapsforge.org * Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2013, 2014 Hannes Janetzek * Copyright 2013, 2014 Hannes Janetzek
* Copyright 2014-2015 Ludwig M Brinckmann * Copyright 2014-2015 Ludwig M Brinckmann
* Copyright 2016-2019 devemux86 * Copyright 2016-2020 devemux86
* Copyright 2016 Andrey Novikov * Copyright 2016 Andrey Novikov
* Copyright 2017-2018 Gustl22 * Copyright 2017-2018 Gustl22
* Copyright 2018 Bezzu * Copyright 2018 Bezzu
@@ -38,8 +38,9 @@ import org.oscim.utils.geom.TileSeparator;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.nio.channels.FileChannel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -202,8 +203,7 @@ public class MapDatabase implements ITileDataSource {
private long mFileSize; private long mFileSize;
private boolean mDebugFile; private boolean mDebugFile;
private RandomAccessFile mInputFile; private FileChannel mInputChannel;
private ReadBuffer mReadBuffer;
private String mSignatureBlock; private String mSignatureBlock;
private String mSignaturePoi; private String mSignaturePoi;
private String mSignatureWay; private String mSignatureWay;
@@ -227,11 +227,15 @@ public class MapDatabase implements ITileDataSource {
public MapDatabase(MapFileTileSource tileSource) throws IOException { public MapDatabase(MapFileTileSource tileSource) throws IOException {
mTileSource = tileSource; mTileSource = tileSource;
try { try {
/* open the file in read only mode */ // false positive: stream gets closed when the channel is closed
mInputFile = new RandomAccessFile(tileSource.mapFile, "r"); // see e.g. http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4796385
mFileSize = mInputFile.length(); if (tileSource.mapFileInputStream != null)
mReadBuffer = new ReadBuffer(mInputFile); mInputChannel = tileSource.mapFileInputStream.getChannel();
else {
FileInputStream fis = new FileInputStream(tileSource.mapFile);
mInputChannel = fis.getChannel();
}
mFileSize = mInputChannel.size();
} catch (IOException e) { } catch (IOException e) {
log.error(e.getMessage()); log.error(e.getMessage());
/* make sure that the file is closed */ /* make sure that the file is closed */
@@ -314,12 +318,10 @@ public class MapDatabase implements ITileDataSource {
@Override @Override
public void dispose() { public void dispose() {
mReadBuffer = null; if (mInputChannel != null) {
if (mInputFile != null) {
try { try {
mInputFile.close(); mInputChannel.close();
mInputFile = null; mInputChannel = null;
} catch (IOException e) { } catch (IOException e) {
log.error(e.getMessage()); log.error(e.getMessage());
} }
@@ -351,13 +353,13 @@ public class MapDatabase implements ITileDataSource {
private void processBlock(QueryParameters queryParameters, private void processBlock(QueryParameters queryParameters,
SubFileParameter subFileParameter, ITileDataSink mapDataSink, SubFileParameter subFileParameter, ITileDataSink mapDataSink,
BoundingBox boundingBox, Selector selector, BoundingBox boundingBox, Selector selector,
MapReadResult mapReadResult) { MapReadResult mapReadResult, ReadBuffer readBuffer) {
if (!processBlockSignature()) { if (!processBlockSignature(readBuffer)) {
return; return;
} }
int[][] zoomTable = readZoomTable(subFileParameter); int[][] zoomTable = readZoomTable(subFileParameter, readBuffer);
if (zoomTable == null) { if (zoomTable == null) {
return; return;
} }
@@ -366,7 +368,7 @@ public class MapDatabase implements ITileDataSource {
int waysOnQueryZoomLevel = zoomTable[zoomTableRow][1]; int waysOnQueryZoomLevel = zoomTable[zoomTableRow][1];
/* get the relative offset to the first stored way in the block */ /* get the relative offset to the first stored way in the block */
int firstWayOffset = mReadBuffer.readUnsignedInt(); int firstWayOffset = readBuffer.readUnsignedInt();
if (firstWayOffset < 0) { if (firstWayOffset < 0) {
log.warn(INVALID_FIRST_WAY_OFFSET + firstWayOffset); log.warn(INVALID_FIRST_WAY_OFFSET + firstWayOffset);
if (mDebugFile) { if (mDebugFile) {
@@ -376,8 +378,8 @@ public class MapDatabase implements ITileDataSource {
} }
/* add the current buffer position to the relative first way offset */ /* add the current buffer position to the relative first way offset */
firstWayOffset += mReadBuffer.getBufferPosition(); firstWayOffset += readBuffer.getBufferPosition();
if (firstWayOffset > mReadBuffer.getBufferSize()) { if (firstWayOffset > readBuffer.getBufferSize()) {
log.warn(INVALID_FIRST_WAY_OFFSET + firstWayOffset); log.warn(INVALID_FIRST_WAY_OFFSET + firstWayOffset);
if (mDebugFile) { if (mDebugFile) {
log.warn(DEBUG_SIGNATURE_BLOCK + mSignatureBlock); log.warn(DEBUG_SIGNATURE_BLOCK + mSignatureBlock);
@@ -391,13 +393,13 @@ public class MapDatabase implements ITileDataSource {
if (mapReadResult != null) if (mapReadResult != null)
pois = new ArrayList<>(); pois = new ArrayList<>();
if (!processPOIs(mapDataSink, poisOnQueryZoomLevel, boundingBox, filterRequired, pois)) { if (!processPOIs(mapDataSink, poisOnQueryZoomLevel, boundingBox, filterRequired, pois, readBuffer)) {
return; return;
} }
/* finished reading POIs, check if the current buffer position is valid */ /* finished reading POIs, check if the current buffer position is valid */
if (mReadBuffer.getBufferPosition() > firstWayOffset) { if (readBuffer.getBufferPosition() > firstWayOffset) {
log.warn("invalid buffer position: " + mReadBuffer.getBufferPosition()); log.warn("invalid buffer position: " + readBuffer.getBufferPosition());
if (mDebugFile) { if (mDebugFile) {
log.warn(DEBUG_SIGNATURE_BLOCK + mSignatureBlock); log.warn(DEBUG_SIGNATURE_BLOCK + mSignatureBlock);
} }
@@ -405,13 +407,13 @@ public class MapDatabase implements ITileDataSource {
} }
/* move the pointer to the first way */ /* move the pointer to the first way */
mReadBuffer.setBufferPosition(firstWayOffset); readBuffer.setBufferPosition(firstWayOffset);
List<Way> ways = null; List<Way> ways = null;
if (mapReadResult != null && Selector.POIS != selector) if (mapReadResult != null && Selector.POIS != selector)
ways = new ArrayList<>(); ways = new ArrayList<>();
if (!processWays(queryParameters, mapDataSink, waysOnQueryZoomLevel, boundingBox, filterRequired, selector, ways)) { if (!processWays(queryParameters, mapDataSink, waysOnQueryZoomLevel, boundingBox, filterRequired, selector, ways, readBuffer)) {
return; return;
} }
@@ -576,10 +578,9 @@ public class MapDatabase implements ITileDataSource {
} }
/* seek to the current block in the map file */ /* seek to the current block in the map file */
mInputFile.seek(subFileParameter.startAddress + blockPointer);
/* read the current block into the buffer */ /* read the current block into the buffer */
if (!mReadBuffer.readFromFile(blockSize)) { ReadBuffer readBuffer = new ReadBuffer(mInputChannel);
if (!readBuffer.readFromFile(subFileParameter.startAddress + blockPointer, blockSize)) {
/* skip the current block */ /* skip the current block */
log.warn("reading current block has failed: " + blockSize); log.warn("reading current block has failed: " + blockSize);
return; return;
@@ -596,7 +597,7 @@ public class MapDatabase implements ITileDataSource {
mTileLatitude = (int) (tileLatitudeDeg * 1E6); mTileLatitude = (int) (tileLatitudeDeg * 1E6);
mTileLongitude = (int) (tileLongitudeDeg * 1E6); mTileLongitude = (int) (tileLongitudeDeg * 1E6);
processBlock(queryParams, subFileParameter, mapDataSink, boundingBox, selector, mapReadResult); processBlock(queryParams, subFileParameter, mapDataSink, boundingBox, selector, mapReadResult, readBuffer);
} }
} }
} }
@@ -607,10 +608,10 @@ public class MapDatabase implements ITileDataSource {
* @return true if the block signature could be processed successfully, * @return true if the block signature could be processed successfully,
* false otherwise. * false otherwise.
*/ */
private boolean processBlockSignature() { private boolean processBlockSignature(ReadBuffer readBuffer) {
if (mDebugFile) { if (mDebugFile) {
/* get and check the block signature */ /* get and check the block signature */
mSignatureBlock = mReadBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_BLOCK); mSignatureBlock = readBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_BLOCK);
if (!mSignatureBlock.startsWith("###TileStart")) { if (!mSignatureBlock.startsWith("###TileStart")) {
log.warn("invalid block signature: " + mSignatureBlock); log.warn("invalid block signature: " + mSignatureBlock);
return false; return false;
@@ -628,7 +629,7 @@ public class MapDatabase implements ITileDataSource {
* otherwise. * otherwise.
*/ */
private boolean processPOIs(ITileDataSink mapDataSink, int numberOfPois, BoundingBox boundingBox, private boolean processPOIs(ITileDataSink mapDataSink, int numberOfPois, BoundingBox boundingBox,
boolean filterRequired, List<PointOfInterest> pois) { boolean filterRequired, List<PointOfInterest> pois, ReadBuffer readBuffer) {
Tag[] poiTags = mTileSource.fileInfo.poiTags; Tag[] poiTags = mTileSource.fileInfo.poiTags;
MapElement e = mElem; MapElement e = mElem;
@@ -638,7 +639,7 @@ public class MapDatabase implements ITileDataSource {
if (mDebugFile) { if (mDebugFile) {
/* get and check the POI signature */ /* get and check the POI signature */
mSignaturePoi = mReadBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_POI); mSignaturePoi = readBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_POI);
if (!mSignaturePoi.startsWith("***POIStart")) { if (!mSignaturePoi.startsWith("***POIStart")) {
log.warn("invalid POI signature: " + mSignaturePoi); log.warn("invalid POI signature: " + mSignaturePoi);
log.warn(DEBUG_SIGNATURE_BLOCK + mSignatureBlock); log.warn(DEBUG_SIGNATURE_BLOCK + mSignatureBlock);
@@ -647,12 +648,12 @@ public class MapDatabase implements ITileDataSource {
} }
/* get the POI latitude offset (VBE-S) */ /* get the POI latitude offset (VBE-S) */
int latitude = mTileLatitude + mReadBuffer.readSignedInt(); int latitude = mTileLatitude + readBuffer.readSignedInt();
/* get the POI longitude offset (VBE-S) */ /* get the POI longitude offset (VBE-S) */
int longitude = mTileLongitude + mReadBuffer.readSignedInt(); int longitude = mTileLongitude + readBuffer.readSignedInt();
/* get the special byte which encodes multiple flags */ /* get the special byte which encodes multiple flags */
byte specialByte = mReadBuffer.readByte(); byte specialByte = readBuffer.readByte();
/* bit 1-4 represent the layer */ /* bit 1-4 represent the layer */
byte layer = (byte) ((specialByte & POI_LAYER_BITMASK) >>> POI_LAYER_SHIFT); byte layer = (byte) ((specialByte & POI_LAYER_BITMASK) >>> POI_LAYER_SHIFT);
@@ -661,29 +662,29 @@ public class MapDatabase implements ITileDataSource {
byte numberOfTags = (byte) (specialByte & POI_NUMBER_OF_TAGS_BITMASK); byte numberOfTags = (byte) (specialByte & POI_NUMBER_OF_TAGS_BITMASK);
if (numberOfTags != 0) { if (numberOfTags != 0) {
if (!mReadBuffer.readTags(e.tags, poiTags, numberOfTags)) if (!readBuffer.readTags(e.tags, poiTags, numberOfTags))
return false; return false;
} }
/* get the feature bitmask (1 byte) */ /* get the feature bitmask (1 byte) */
byte featureByte = mReadBuffer.readByte(); byte featureByte = readBuffer.readByte();
/* bit 1-3 enable optional features /* bit 1-3 enable optional features
* check if the POI has a name */ * check if the POI has a name */
if ((featureByte & POI_FEATURE_NAME) != 0) { if ((featureByte & POI_FEATURE_NAME) != 0) {
String str = mTileSource.extractLocalized(mReadBuffer.readUTF8EncodedString()); String str = mTileSource.extractLocalized(readBuffer.readUTF8EncodedString());
e.tags.add(new Tag(Tag.KEY_NAME, str, false)); e.tags.add(new Tag(Tag.KEY_NAME, str, false));
} }
/* check if the POI has a house number */ /* check if the POI has a house number */
if ((featureByte & POI_FEATURE_HOUSE_NUMBER) != 0) { if ((featureByte & POI_FEATURE_HOUSE_NUMBER) != 0) {
String str = mReadBuffer.readUTF8EncodedString(); String str = readBuffer.readUTF8EncodedString();
e.tags.add(new Tag(Tag.KEY_HOUSE_NUMBER, str, false)); e.tags.add(new Tag(Tag.KEY_HOUSE_NUMBER, str, false));
} }
/* check if the POI has an elevation */ /* check if the POI has an elevation */
if ((featureByte & POI_FEATURE_ELEVATION) != 0) { if ((featureByte & POI_FEATURE_ELEVATION) != 0) {
String str = Integer.toString(mReadBuffer.readSignedInt()); String str = Integer.toString(readBuffer.readSignedInt());
e.tags.add(new Tag(Tag.KEY_ELE, str, false)); e.tags.add(new Tag(Tag.KEY_ELE, str, false));
} }
mTileProjection.projectPoint(latitude, longitude, e); mTileProjection.projectPoint(latitude, longitude, e);
@@ -712,9 +713,9 @@ public class MapDatabase implements ITileDataSource {
return true; return true;
} }
private boolean processWayDataBlock(MapElement e, boolean doubleDeltaEncoding, boolean isLine, List<GeoPoint[]> wayCoordinates, int[] labelPosition) { private boolean processWayDataBlock(MapElement e, boolean doubleDeltaEncoding, boolean isLine, List<GeoPoint[]> wayCoordinates, int[] labelPosition, ReadBuffer readBuffer) {
/* get and check the number of way coordinate blocks (VBE-U) */ /* get and check the number of way coordinate blocks (VBE-U) */
int numBlocks = mReadBuffer.readUnsignedInt(); int numBlocks = readBuffer.readUnsignedInt();
if (numBlocks < 1 || numBlocks > Short.MAX_VALUE) { if (numBlocks < 1 || numBlocks > Short.MAX_VALUE) {
log.warn("invalid number of way coordinate blocks: " + numBlocks); log.warn("invalid number of way coordinate blocks: " + numBlocks);
return false; return false;
@@ -726,7 +727,7 @@ public class MapDatabase implements ITileDataSource {
/* read the way coordinate blocks */ /* read the way coordinate blocks */
for (int coordinateBlock = 0; coordinateBlock < numBlocks; ++coordinateBlock) { for (int coordinateBlock = 0; coordinateBlock < numBlocks; ++coordinateBlock) {
int numWayNodes = mReadBuffer.readUnsignedInt(); int numWayNodes = readBuffer.readUnsignedInt();
if (numWayNodes < 2 || numWayNodes > Short.MAX_VALUE) { if (numWayNodes < 2 || numWayNodes > Short.MAX_VALUE) {
log.warn("invalid number of way nodes: " + numWayNodes); log.warn("invalid number of way nodes: " + numWayNodes);
@@ -744,7 +745,7 @@ public class MapDatabase implements ITileDataSource {
// label position must be set on first coordinate block // label position must be set on first coordinate block
wayLengths[coordinateBlock] = decodeWayNodes(doubleDeltaEncoding, e, len, isLine, wayLengths[coordinateBlock] = decodeWayNodes(doubleDeltaEncoding, e, len, isLine,
coordinateBlock == 0 ? labelPosition : null, waySegment); coordinateBlock == 0 ? labelPosition : null, waySegment, readBuffer);
if (wayCoordinates != null) if (wayCoordinates != null)
wayCoordinates.add(waySegment); wayCoordinates.add(waySegment);
@@ -753,9 +754,9 @@ public class MapDatabase implements ITileDataSource {
return true; return true;
} }
private int decodeWayNodes(boolean doubleDelta, MapElement e, int length, boolean isLine, int[] labelPosition, GeoPoint[] waySegment) { private int decodeWayNodes(boolean doubleDelta, MapElement e, int length, boolean isLine, int[] labelPosition, GeoPoint[] waySegment, ReadBuffer readBuffer) {
int[] buffer = mIntBuffer; int[] buffer = mIntBuffer;
mReadBuffer.readSignedInt(buffer, length); readBuffer.readSignedInt(buffer, length);
float[] outBuffer = e.ensurePointSize(e.pointNextPos + length, true); float[] outBuffer = e.ensurePointSize(e.pointNextPos + length, true);
int outPos = e.pointNextPos; int outPos = e.pointNextPos;
@@ -848,7 +849,7 @@ public class MapDatabase implements ITileDataSource {
*/ */
private boolean processWays(QueryParameters queryParameters, ITileDataSink mapDataSink, private boolean processWays(QueryParameters queryParameters, ITileDataSink mapDataSink,
int numberOfWays, BoundingBox boundingBox, boolean filterRequired, int numberOfWays, BoundingBox boundingBox, boolean filterRequired,
Selector selector, List<Way> ways) { Selector selector, List<Way> ways, ReadBuffer readBuffer) {
Tag[] wayTags = mTileSource.fileInfo.wayTags; Tag[] wayTags = mTileSource.fileInfo.wayTags;
MapElement e = mElem; MapElement e = mElem;
@@ -860,9 +861,9 @@ public class MapDatabase implements ITileDataSource {
stringOffset = 0; stringOffset = 0;
if (mTileSource.experimental) { if (mTileSource.experimental) {
stringsSize = mReadBuffer.readUnsignedInt(); stringsSize = readBuffer.readUnsignedInt();
stringOffset = mReadBuffer.getBufferPosition(); stringOffset = readBuffer.getBufferPosition();
mReadBuffer.skipBytes(stringsSize); readBuffer.skipBytes(stringsSize);
} }
//setTileClipping(queryParameters); //setTileClipping(queryParameters);
@@ -873,7 +874,7 @@ public class MapDatabase implements ITileDataSource {
if (mDebugFile) { if (mDebugFile) {
// get and check the way signature // get and check the way signature
mSignatureWay = mReadBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_WAY); mSignatureWay = readBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_WAY);
if (!mSignatureWay.startsWith("---WayStart")) { if (!mSignatureWay.startsWith("---WayStart")) {
log.warn("invalid way signature: " + mSignatureWay); log.warn("invalid way signature: " + mSignatureWay);
log.warn(DEBUG_SIGNATURE_BLOCK + mSignatureBlock); log.warn(DEBUG_SIGNATURE_BLOCK + mSignatureBlock);
@@ -882,7 +883,7 @@ public class MapDatabase implements ITileDataSource {
} }
if (queryParameters.useTileBitmask) { if (queryParameters.useTileBitmask) {
elementCounter = mReadBuffer.skipWays(queryParameters.queryTileBitmask, elementCounter = readBuffer.skipWays(queryParameters.queryTileBitmask,
elementCounter); elementCounter);
if (elementCounter == 0) if (elementCounter == 0)
@@ -891,19 +892,19 @@ public class MapDatabase implements ITileDataSource {
if (elementCounter < 0) if (elementCounter < 0)
return false; return false;
if (mTileSource.experimental && mReadBuffer.lastTagPosition > 0) { if (mTileSource.experimental && readBuffer.lastTagPosition > 0) {
int pos = mReadBuffer.getBufferPosition(); int pos = readBuffer.getBufferPosition();
mReadBuffer.setBufferPosition(mReadBuffer.lastTagPosition); readBuffer.setBufferPosition(readBuffer.lastTagPosition);
byte numberOfTags = byte numberOfTags =
(byte) (mReadBuffer.readByte() & WAY_NUMBER_OF_TAGS_BITMASK); (byte) (readBuffer.readByte() & WAY_NUMBER_OF_TAGS_BITMASK);
if (!mReadBuffer.readTags(e.tags, wayTags, numberOfTags)) if (!readBuffer.readTags(e.tags, wayTags, numberOfTags))
return false; return false;
mReadBuffer.setBufferPosition(pos); readBuffer.setBufferPosition(pos);
} }
} else { } else {
int wayDataSize = mReadBuffer.readUnsignedInt(); int wayDataSize = readBuffer.readUnsignedInt();
if (wayDataSize < 0) { if (wayDataSize < 0) {
log.warn("invalid way data size: " + wayDataSize); log.warn("invalid way data size: " + wayDataSize);
if (mDebugFile) { if (mDebugFile) {
@@ -914,11 +915,11 @@ public class MapDatabase implements ITileDataSource {
} }
/* ignore the way tile bitmask (2 bytes) */ /* ignore the way tile bitmask (2 bytes) */
mReadBuffer.skipBytes(2); readBuffer.skipBytes(2);
} }
/* get the special byte which encodes multiple flags */ /* get the special byte which encodes multiple flags */
byte specialByte = mReadBuffer.readByte(); byte specialByte = readBuffer.readByte();
/* bit 1-4 represent the layer */ /* bit 1-4 represent the layer */
byte layer = (byte) ((specialByte & WAY_LAYER_BITMASK) >>> WAY_LAYER_SHIFT); byte layer = (byte) ((specialByte & WAY_LAYER_BITMASK) >>> WAY_LAYER_SHIFT);
@@ -926,12 +927,12 @@ public class MapDatabase implements ITileDataSource {
byte numberOfTags = (byte) (specialByte & WAY_NUMBER_OF_TAGS_BITMASK); byte numberOfTags = (byte) (specialByte & WAY_NUMBER_OF_TAGS_BITMASK);
if (numberOfTags != 0) { if (numberOfTags != 0) {
if (!mReadBuffer.readTags(e.tags, wayTags, numberOfTags)) if (!readBuffer.readTags(e.tags, wayTags, numberOfTags))
return false; return false;
} }
/* get the feature bitmask (1 byte) */ /* get the feature bitmask (1 byte) */
byte featureByte = mReadBuffer.readByte(); byte featureByte = readBuffer.readByte();
/* bit 1-6 enable optional features */ /* bit 1-6 enable optional features */
boolean featureWayDoubleDeltaEncoding = boolean featureWayDoubleDeltaEncoding =
@@ -943,42 +944,42 @@ public class MapDatabase implements ITileDataSource {
if (mTileSource.experimental) { if (mTileSource.experimental) {
if (hasName) { if (hasName) {
int textPos = mReadBuffer.readUnsignedInt(); int textPos = readBuffer.readUnsignedInt();
String str = mTileSource.extractLocalized(mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos)); String str = mTileSource.extractLocalized(readBuffer.readUTF8EncodedStringAt(stringOffset + textPos));
e.tags.add(new Tag(Tag.KEY_NAME, str, false)); e.tags.add(new Tag(Tag.KEY_NAME, str, false));
} }
if (hasHouseNr) { if (hasHouseNr) {
int textPos = mReadBuffer.readUnsignedInt(); int textPos = readBuffer.readUnsignedInt();
String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos); String str = readBuffer.readUTF8EncodedStringAt(stringOffset + textPos);
e.tags.add(new Tag(Tag.KEY_HOUSE_NUMBER, str, false)); e.tags.add(new Tag(Tag.KEY_HOUSE_NUMBER, str, false));
} }
if (hasRef) { if (hasRef) {
int textPos = mReadBuffer.readUnsignedInt(); int textPos = readBuffer.readUnsignedInt();
String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos); String str = readBuffer.readUTF8EncodedStringAt(stringOffset + textPos);
e.tags.add(new Tag(Tag.KEY_REF, str, false)); e.tags.add(new Tag(Tag.KEY_REF, str, false));
} }
} else { } else {
if (hasName) { if (hasName) {
String str = mTileSource.extractLocalized(mReadBuffer.readUTF8EncodedString()); String str = mTileSource.extractLocalized(readBuffer.readUTF8EncodedString());
e.tags.add(new Tag(Tag.KEY_NAME, str, false)); e.tags.add(new Tag(Tag.KEY_NAME, str, false));
} }
if (hasHouseNr) { if (hasHouseNr) {
String str = mReadBuffer.readUTF8EncodedString(); String str = readBuffer.readUTF8EncodedString();
e.tags.add(new Tag(Tag.KEY_HOUSE_NUMBER, str, false)); e.tags.add(new Tag(Tag.KEY_HOUSE_NUMBER, str, false));
} }
if (hasRef) { if (hasRef) {
String str = mReadBuffer.readUTF8EncodedString(); String str = readBuffer.readUTF8EncodedString();
e.tags.add(new Tag(Tag.KEY_REF, str, false)); e.tags.add(new Tag(Tag.KEY_REF, str, false));
} }
} }
int[] labelPosition = null; int[] labelPosition = null;
if ((featureByte & WAY_FEATURE_LABEL_POSITION) != 0) { if ((featureByte & WAY_FEATURE_LABEL_POSITION) != 0) {
labelPosition = readOptionalLabelPosition(); labelPosition = readOptionalLabelPosition(readBuffer);
} }
if ((featureByte & WAY_FEATURE_DATA_BLOCKS_BYTE) != 0) { if ((featureByte & WAY_FEATURE_DATA_BLOCKS_BYTE) != 0) {
wayDataBlocks = mReadBuffer.readUnsignedInt(); wayDataBlocks = readBuffer.readUnsignedInt();
if (wayDataBlocks < 1) { if (wayDataBlocks < 1) {
log.warn("invalid number of way data blocks: " + wayDataBlocks); log.warn("invalid number of way data blocks: " + wayDataBlocks);
@@ -999,7 +1000,7 @@ public class MapDatabase implements ITileDataSource {
if (ways != null) if (ways != null)
wayNodes = new ArrayList<>(); wayNodes = new ArrayList<>();
if (!processWayDataBlock(e, featureWayDoubleDeltaEncoding, linearFeature, wayNodes, labelPosition)) if (!processWayDataBlock(e, featureWayDoubleDeltaEncoding, linearFeature, wayNodes, labelPosition, readBuffer))
return false; return false;
/* drop invalid outer ring */ /* drop invalid outer ring */
@@ -1152,14 +1153,14 @@ public class MapDatabase implements ITileDataSource {
return mapReadResult; return mapReadResult;
} }
private int[] readOptionalLabelPosition() { private int[] readOptionalLabelPosition(ReadBuffer readBuffer) {
int[] labelPosition = new int[2]; int[] labelPosition = new int[2];
/* get the label position latitude offset (VBE-S) */ /* get the label position latitude offset (VBE-S) */
labelPosition[1] = mReadBuffer.readSignedInt(); labelPosition[1] = readBuffer.readSignedInt();
/* get the label position longitude offset (VBE-S) */ /* get the label position longitude offset (VBE-S) */
labelPosition[0] = mReadBuffer.readSignedInt(); labelPosition[0] = readBuffer.readSignedInt();
return labelPosition; return labelPosition;
} }
@@ -1187,7 +1188,7 @@ public class MapDatabase implements ITileDataSource {
return readMapData(upperLeft, lowerRight, Selector.POIS); return readMapData(upperLeft, lowerRight, Selector.POIS);
} }
private int[][] readZoomTable(SubFileParameter subFileParameter) { private int[][] readZoomTable(SubFileParameter subFileParameter, ReadBuffer readBuffer) {
int rows = subFileParameter.zoomLevelMax - subFileParameter.zoomLevelMin + 1; int rows = subFileParameter.zoomLevelMax - subFileParameter.zoomLevelMin + 1;
int[][] zoomTable = new int[rows][2]; int[][] zoomTable = new int[rows][2];
@@ -1195,8 +1196,8 @@ public class MapDatabase implements ITileDataSource {
int cumulatedNumberOfWays = 0; int cumulatedNumberOfWays = 0;
for (int row = 0; row < rows; row++) { for (int row = 0; row < rows; row++) {
cumulatedNumberOfPois += mReadBuffer.readUnsignedInt(); cumulatedNumberOfPois += readBuffer.readUnsignedInt();
cumulatedNumberOfWays += mReadBuffer.readUnsignedInt(); cumulatedNumberOfWays += readBuffer.readUnsignedInt();
zoomTable[row][0] = cumulatedNumberOfPois; zoomTable[row][0] = cumulatedNumberOfPois;
zoomTable[row][1] = cumulatedNumberOfWays; zoomTable[row][1] = cumulatedNumberOfWays;

View File

@@ -1,7 +1,7 @@
/* /*
* Copyright 2013 mapsforge.org * Copyright 2013 mapsforge.org
* Copyright 2013 Hannes Janetzek * Copyright 2013 Hannes Janetzek
* Copyright 2016-2018 devemux86 * Copyright 2016-2020 devemux86
* *
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
* *
@@ -25,13 +25,13 @@ import org.oscim.tiling.OverzoomTileDataSource;
import org.oscim.tiling.TileSource; import org.oscim.tiling.TileSource;
import org.oscim.tiling.source.mapfile.header.MapFileHeader; import org.oscim.tiling.source.mapfile.header.MapFileHeader;
import org.oscim.tiling.source.mapfile.header.MapFileInfo; import org.oscim.tiling.source.mapfile.header.MapFileInfo;
import org.oscim.utils.IOUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.nio.channels.FileChannel;
public class MapFileTileSource extends TileSource implements IMapFileTileSource { public class MapFileTileSource extends TileSource implements IMapFileTileSource {
private static final Logger log = LoggerFactory.getLogger(MapFileTileSource.class); private static final Logger log = LoggerFactory.getLogger(MapFileTileSource.class);
@@ -40,14 +40,14 @@ public class MapFileTileSource extends TileSource implements IMapFileTileSource
* Amount of cache blocks that the index cache should store. * Amount of cache blocks that the index cache should store.
*/ */
private static final int INDEX_CACHE_SIZE = 64; private static final int INDEX_CACHE_SIZE = 64;
private static final String READ_ONLY_MODE = "r";
MapFileHeader fileHeader; MapFileHeader fileHeader;
MapFileInfo fileInfo; MapFileInfo fileInfo;
IndexCache databaseIndexCache; IndexCache databaseIndexCache;
boolean experimental; boolean experimental;
File mapFile; File mapFile;
private RandomAccessFile mInputFile; FileInputStream mapFileInputStream;
private FileChannel inputChannel;
/** /**
* The preferred language when extracting labels from this tile source. * The preferred language when extracting labels from this tile source.
@@ -98,6 +98,10 @@ public class MapFileTileSource extends TileSource implements IMapFileTileSource
return true; return true;
} }
public void setMapFileInputStream(FileInputStream fileInputStream) {
this.mapFileInputStream = fileInputStream;
}
@Override @Override
public void setPreferredLanguage(String preferredLanguage) { public void setPreferredLanguage(String preferredLanguage) {
this.preferredLanguage = preferredLanguage; this.preferredLanguage = preferredLanguage;
@@ -105,31 +109,38 @@ public class MapFileTileSource extends TileSource implements IMapFileTileSource
@Override @Override
public OpenResult open() { public OpenResult open() {
if (!options.containsKey("file")) if (mapFileInputStream == null && !options.containsKey("file"))
return new OpenResult("no map file set"); return new OpenResult("no map file set");
try { try {
// make sure to close any previously opened file first // false positive: stream gets closed when the channel is closed
//close(); // see e.g. http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4796385
File file = null;
if (mapFileInputStream != null)
inputChannel = mapFileInputStream.getChannel();
else {
// make sure to close any previously opened file first
//close();
File file = new File(options.get("file")); file = new File(options.get("file"));
// check if the file exists and is readable // check if the file exists and is readable
if (!file.exists()) { if (!file.exists()) {
return new OpenResult("file does not exist: " + file); return new OpenResult("file does not exist: " + file);
} else if (!file.isFile()) { } else if (!file.isFile()) {
return new OpenResult("not a file: " + file); return new OpenResult("not a file: " + file);
} else if (!file.canRead()) { } else if (!file.canRead()) {
return new OpenResult("cannot read file: " + file); return new OpenResult("cannot read file: " + file);
}
FileInputStream fis = new FileInputStream(file);
inputChannel = fis.getChannel();
} }
long fileSize = inputChannel.size();
// open the file in read only mode ReadBuffer readBuffer = new ReadBuffer(inputChannel);
mInputFile = new RandomAccessFile(file, READ_ONLY_MODE);
long mFileSize = mInputFile.length();
ReadBuffer mReadBuffer = new ReadBuffer(mInputFile);
fileHeader = new MapFileHeader(); fileHeader = new MapFileHeader();
OpenResult openResult = fileHeader.readHeader(mReadBuffer, mFileSize); OpenResult openResult = fileHeader.readHeader(readBuffer, fileSize);
if (!openResult.isSuccess()) { if (!openResult.isSuccess()) {
close(); close();
@@ -137,10 +148,7 @@ public class MapFileTileSource extends TileSource implements IMapFileTileSource
} }
fileInfo = fileHeader.getMapFileInfo(); fileInfo = fileHeader.getMapFileInfo();
mapFile = file; mapFile = file;
databaseIndexCache = new IndexCache(mInputFile, INDEX_CACHE_SIZE); databaseIndexCache = new IndexCache(inputChannel, INDEX_CACHE_SIZE);
// Experimental?
//experimental = fileInfo.fileVersion == 4;
log.debug("File version: " + fileInfo.fileVersion); log.debug("File version: " + fileInfo.fileVersion);
return OpenResult.SUCCESS; return OpenResult.SUCCESS;
@@ -164,8 +172,14 @@ public class MapFileTileSource extends TileSource implements IMapFileTileSource
@Override @Override
public void close() { public void close() {
IOUtils.closeQuietly(mInputFile); if (inputChannel != null) {
mInputFile = null; try {
inputChannel.close();
inputChannel = null;
} catch (IOException e) {
log.error(e.getMessage());
}
}
fileHeader = null; fileHeader = null;
fileInfo = null; fileInfo = null;
mapFile = null; mapFile = null;

View File

@@ -1,7 +1,8 @@
/* /*
* Copyright 2010, 2011, 2012, 2013 mapsforge.org * Copyright 2010, 2011, 2012, 2013 mapsforge.org
* Copyright 2015-2016 devemux86 * Copyright 2015-2020 devemux86
* Copyright 2015-2016 lincomatic * Copyright 2015-2016 lincomatic
* Copyright 2020 Meibes
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software * terms of the GNU Lesser General Public License as published by the Free Software
@@ -19,19 +20,31 @@ package org.oscim.tiling.source.mapfile;
import org.oscim.core.MapElement; import org.oscim.core.MapElement;
import org.oscim.core.Tag; import org.oscim.core.Tag;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale; import java.util.Locale;
import java.util.Set;
public final class OSMUtils { public final class OSMUtils {
private static final Set<String> areaKeys = new HashSet<>(Arrays.asList(
"building", "natural", "landuse", "amenity", "leisure", "aeroway",
"highway", "barrier",
"railway",
"area"
));
/** /**
* Heuristic to determine from attributes if a map element is likely to be an area. * Heuristic to determine from attributes if a map element is likely to be an area.
* Precondition for this call is that the first and last node of a map element are the * Precondition for this call is that the first and last node of a map element are the
* same, so that this method should only return false if it is known that the * same, so that this method should only return false if it is known that the
* feature should not be an area even if the geometry is a polygon. * feature should not be an area even if the geometry is a polygon.
* <p/> * <p>
* Determining what is an area is neigh impossible in OSM, this method inspects tag elements * Determining what is an area is neigh impossible in OSM, this method inspects tag elements
* to give a likely answer. See http://wiki.openstreetmap.org/wiki/The_Future_of_Areas and * to give a likely answer. See http://wiki.openstreetmap.org/wiki/The_Future_of_Areas and
* http://wiki.openstreetmap.org/wiki/Way * http://wiki.openstreetmap.org/wiki/Way
* <p>
* The order in which the if-clauses are checked is determined with the help from https://taginfo.openstreetmap.org
* *
* @param mapElement the map element (which is assumed to be closed and have enough nodes to be an area) * @param mapElement the map element (which is assumed to be closed and have enough nodes to be an area)
* @return true if tags indicate this is an area, otherwise false. * @return true if tags indicate this is an area, otherwise false.
@@ -41,34 +54,35 @@ public final class OSMUtils {
for (int i = 0; i < mapElement.tags.size(); i++) { for (int i = 0; i < mapElement.tags.size(); i++) {
Tag tag = mapElement.tags.get(i); Tag tag = mapElement.tags.get(i);
String key = tag.key.toLowerCase(Locale.ENGLISH); String key = tag.key.toLowerCase(Locale.ENGLISH);
String value = tag.value.toLowerCase(Locale.ENGLISH); if (!areaKeys.contains(key)) {
if ("area".equals(key)) { continue;
// obvious result
if (("yes").equals(value) || ("y").equals(value) || ("true").equals(value)) {
return true;
}
if (("no").equals(value) || ("n").equals(value) || ("false").equals(value)) {
return false;
}
} }
// as specified by http://wiki.openstreetmap.org/wiki/Key:area if ("building".equals(key) || "natural".equals(key) || "landuse".equals(key) || "amenity".equals(key) || "leisure".equals(key) || "aeroway".equals(key)) {
if ("aeroway".equals(key) || "building".equals(key) || "landuse".equals(key) || "leisure".equals(key) || "natural".equals(key) || "amenity".equals(key)) { // as specified by http://wiki.openstreetmap.org/wiki/Key:area
return true; return true;
} } else if ("highway".equals(key) || "barrier".equals(key)) {
if ("highway".equals(key) || "barrier".equals(key)) {
// false unless something else overrides this. // false unless something else overrides this.
result = false; result = false;
} } else if ("railway".equals(key)) {
if ("railway".equals(key)) { String value = tag.value.toLowerCase(Locale.ENGLISH);
// there is more to the railway tag then just rails, this excludes the // there is more to the railway tag then just rails, this excludes the
// most common railway lines from being detected as areas if they are closed. // most common railway lines from being detected as areas if they are closed.
// Since this method is only called if the first and last node are the same // Since this method is only called if the first and last node are the same
// this should be safe // this should be safe
if ("rail".equals(value) || "tram".equals(value) || "subway".equals(value) if ("rail".equals(value) || "tram".equals(value) || "subway".equals(value)
|| "monorail".equals(value) || "narrow_gauge".equals(value) || "preserved".equals(value) || "narrow_gauge".equals(value) || "light_rail".equals(value)
|| "light_rail".equals(value) || "construction".equals(value)) { || "construction".equals(value) || "preserved".equals(value)
|| "monorail".equals(value)) {
result = false; result = false;
} }
} else if ("area".equals(key)) {
String value = tag.value.toLowerCase(Locale.ENGLISH);
if (("yes").equals(value) || ("y").equals(value) || ("true").equals(value)) {
return true;
}
if (("no").equals(value) || ("n").equals(value) || ("false").equals(value)) {
return false;
}
} }
} }
return result; return result;

View File

@@ -25,6 +25,8 @@ import org.oscim.utils.Parameters;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
@@ -39,16 +41,17 @@ public class ReadBuffer {
private byte[] mBufferData; private byte[] mBufferData;
private int mBufferPosition; private int mBufferPosition;
private final RandomAccessFile mInputFile; private ByteBuffer mBufferWrapper;
private final FileChannel mInputChannel;
private final List<Integer> mTagIds = new ArrayList<>(); private final List<Integer> mTagIds = new ArrayList<>();
ReadBuffer(RandomAccessFile inputFile) { ReadBuffer(FileChannel inputChannel) {
mInputFile = inputFile; mInputChannel = inputChannel;
} }
/** /**
* Returns one signed byte from the read buffer. * Returns one byte from the read buffer.
* *
* @return the byte value. * @return the byte value.
*/ */
@@ -91,13 +94,54 @@ public class ReadBuffer {
LOG.log(Level.SEVERE, t.getMessage(), t); LOG.log(Level.SEVERE, t.getMessage(), t);
return false; return false;
} }
mBufferWrapper = ByteBuffer.wrap(mBufferData, 0, length);
} }
mBufferPosition = 0; mBufferPosition = 0;
mBufferWrapper.clear();
// reset the buffer position and read the data into the buffer // reset the buffer position and read the data into the buffer
// bufferPosition = 0; // bufferPosition = 0;
return mInputFile.read(mBufferData, 0, length) == length; return mInputChannel.read(mBufferWrapper) == length;
}
/**
* Reads the given amount of bytes from the file into the read buffer and
* resets the internal buffer position. If
* the capacity of the read buffer is too small, a larger one is created
* automatically.
*
* @param offset the offset position, measured in bytes from the beginning of the file, at which to set the file pointer.
* @param length the amount of bytes to read from the file.
* @return true if the whole data was read successfully, false otherwise.
* @throws IOException if an error occurs while reading the file.
*/
public boolean readFromFile(long offset, int length) throws IOException {
// ensure that the read buffer is large enough
if (mBufferData == null || mBufferData.length < length) {
// ensure that the read buffer is not too large
if (length > Parameters.MAXIMUM_BUFFER_SIZE) {
LOG.warning("invalid read length: " + length);
return false;
}
try {
mBufferData = new byte[length];
} catch (Throwable t) {
LOG.log(Level.SEVERE, t.getMessage(), t);
return false;
}
mBufferWrapper = ByteBuffer.wrap(mBufferData, 0, length);
}
mBufferPosition = 0;
mBufferWrapper.clear();
// reset the buffer position and read the data into the buffer
// bufferPosition = 0;
synchronized (mInputChannel) {
mInputChannel.position(offset);
return mInputChannel.read(mBufferWrapper) == length;
}
} }
/** /**

View File

@@ -16,6 +16,8 @@ package org.oscim.utils;
public final class Parameters { public final class Parameters {
public enum SymbolScaling {ALL, POI}
/** /**
* If true the <code>Animator2</code> will be used instead of default <code>Animator</code>. * If true the <code>Animator2</code> will be used instead of default <code>Animator</code>.
*/ */
@@ -44,7 +46,7 @@ public final class Parameters {
/** /**
* Maximum buffer size for map files. * Maximum buffer size for map files.
*/ */
public static int MAXIMUM_BUFFER_SIZE = 8000000; public static int MAXIMUM_BUFFER_SIZE = 10000000;
/** /**
* Calculation of centroids for all polygons. * Calculation of centroids for all polygons.
@@ -73,6 +75,11 @@ public final class Parameters {
*/ */
public static int SIMPLIFICATION_TOLERANCE = 0; public static int SIMPLIFICATION_TOLERANCE = 0;
/**
* Symbol scaling mode.
*/
public static SymbolScaling SYMBOL_SCALING = SymbolScaling.POI;
/** /**
* Texture atlas in themes. * Texture atlas in themes.
*/ */