Repo created
This commit is contained in:
parent
d6b5d53060
commit
d90a1dc8df
2145 changed files with 210227 additions and 2 deletions
1
maps-utils/.gitignore
vendored
Normal file
1
maps-utils/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
10
maps-utils/README.md
Normal file
10
maps-utils/README.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Maps utils
|
||||
|
||||
Fork of [Maps SDK for Android Utility Library](https://github.com/googlemaps/android-maps-utils).
|
||||
Includes code up to the [2025-08-06 commit](https://github.com/googlemaps/android-maps-utils/commit/014c64e7d06c98864092b58f701b20e301ef8d30).
|
||||
|
||||
Differences with original library:
|
||||
- Only supports a small subset of features we need for Breezy Weather
|
||||
- Add an utility to decode [polylines](https://developers.google.com/maps/documentation/utilities/polylinealgorithm?hl=en) (no longer used by Breezy Weather, but still there just in case)
|
||||
- No dependency on proprietary Google Play Services
|
||||
- Rewritten in Kotlin
|
||||
18
maps-utils/build.gradle.kts
Normal file
18
maps-utils/build.gradle.kts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
plugins {
|
||||
id("breezy.library")
|
||||
kotlin("android")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.google.maps.android"
|
||||
|
||||
defaultConfig {
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation(libs.bundles.test)
|
||||
testRuntimeOnly(libs.junit.platform)
|
||||
}
|
||||
0
maps-utils/consumer-rules.pro
Normal file
0
maps-utils/consumer-rules.pro
Normal file
21
maps-utils/proguard-rules.pro
vendored
Normal file
21
maps-utils/proguard-rules.pro
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android
|
||||
|
||||
import com.google.maps.android.model.LatLng
|
||||
|
||||
/**
|
||||
* Ported from https://github.com/googlemaps/js-polyline-codec/blob/main/src/index.ts
|
||||
* by Breezy Weather
|
||||
*/
|
||||
object EncodedPolylineUtil {
|
||||
|
||||
fun decode(encodedPath: String): List<LatLng> {
|
||||
val factor = 1E5
|
||||
|
||||
val coordinatesList = mutableListOf<LatLng>()
|
||||
var index = 0
|
||||
var lat = 0
|
||||
var lng = 0
|
||||
|
||||
// This code has been profiled and optimized, so don't modify it without
|
||||
// measuring its performance.
|
||||
while (index < encodedPath.length) {
|
||||
// Fully unrolling the following loops speeds things up about 5%.
|
||||
var result = 1
|
||||
var shift = 0
|
||||
var b: Int
|
||||
do {
|
||||
// Invariant: "result" is current partial result plus (1 << shift).
|
||||
// The following line effectively clears this bit by decrementing "b".
|
||||
b = encodedPath[index++].code - 63 - 1
|
||||
result += b shl shift
|
||||
shift += 5
|
||||
} while (b >= 0x1f) // See note above.
|
||||
lat += if (result and 1 != 0) (result shr 1).inv() else result shr 1
|
||||
|
||||
result = 1
|
||||
shift = 0
|
||||
do {
|
||||
b = encodedPath[index++].code - 63 - 1
|
||||
result += b shl shift
|
||||
shift += 5
|
||||
} while (b >= 0x1f)
|
||||
lng += if (result and 1 != 0) (result shr 1).inv() else result shr 1
|
||||
|
||||
coordinatesList.add(
|
||||
LatLng(
|
||||
lat.toDouble() / factor,
|
||||
lng.toDouble() / factor
|
||||
)
|
||||
)
|
||||
}
|
||||
return coordinatesList
|
||||
}
|
||||
}
|
||||
89
maps-utils/src/main/java/com/google/maps/android/MathUtil.kt
Normal file
89
maps-utils/src/main/java/com/google/maps/android/MathUtil.kt
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android
|
||||
|
||||
import kotlin.math.asin
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.ln
|
||||
import kotlin.math.sin
|
||||
import kotlin.math.sqrt
|
||||
import kotlin.math.tan
|
||||
|
||||
/**
|
||||
* Utility functions that are used my both PolyUtil and SphericalUtil.
|
||||
*/
|
||||
internal object MathUtil {
|
||||
|
||||
/**
|
||||
* The earth's radius, in meters.
|
||||
* Mean radius as defined by IUGG.
|
||||
*/
|
||||
const val EARTH_RADIUS = 6371009.0
|
||||
|
||||
/**
|
||||
* Wraps the given value into the inclusive-exclusive interval between min and max.
|
||||
*
|
||||
* @param n The value to wrap.
|
||||
* @param min The minimum.
|
||||
* @param max The maximum.
|
||||
*/
|
||||
fun wrap(n: Double, min: Double, max: Double): Double {
|
||||
return if (n >= min && n < max) n else mod(n - min, max - min) + min
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the non-negative remainder of x / m.
|
||||
*
|
||||
* @param x The operand.
|
||||
* @param m The modulus.
|
||||
*/
|
||||
fun mod(x: Double, m: Double): Double {
|
||||
return (x % m + m) % m
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns mercator Y corresponding to latitude.
|
||||
* See https://en.wikipedia.org/wiki/Mercator_projection .
|
||||
*/
|
||||
fun mercator(lat: Double): Double {
|
||||
return ln(tan(lat * 0.5 + Math.PI / 4))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns haversine(angle-in-radians).
|
||||
* hav(x) == (1 - cos(x)) / 2 == sin(x / 2)^2.
|
||||
*/
|
||||
fun hav(x: Double): Double {
|
||||
val sinHalf: Double = sin(x * 0.5)
|
||||
return sinHalf * sinHalf
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes inverse haversine. Has good numerical stability around 0.
|
||||
* arcHav(x) == acos(1 - 2 * x) == 2 * asin(sqrt(x)).
|
||||
* The argument must be in [0, 1], and the result is positive.
|
||||
*/
|
||||
fun arcHav(x: Double): Double {
|
||||
return 2 * asin(sqrt(x))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns hav() of distance from (lat1, lng1) to (lat2, lng2) on the unit sphere.
|
||||
*/
|
||||
fun havDistance(lat1: Double, lat2: Double, dLng: Double): Double {
|
||||
return hav(lat1 - lat2) + hav(dLng) * cos(lat1) * cos(lat2)
|
||||
}
|
||||
}
|
||||
143
maps-utils/src/main/java/com/google/maps/android/PolyUtil.kt
Normal file
143
maps-utils/src/main/java/com/google/maps/android/PolyUtil.kt
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright 2008, 2013 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android
|
||||
|
||||
import com.google.maps.android.MathUtil.wrap
|
||||
import com.google.maps.android.model.LatLng
|
||||
import kotlin.math.sin
|
||||
import kotlin.math.tan
|
||||
|
||||
object PolyUtil {
|
||||
/**
|
||||
* Returns tan(latitude-at-lng3) on the great circle (lat1, lng1) to (lat2, lng2). lng1==0.
|
||||
* See http://williams.best.vwh.net/avform.htm .
|
||||
*/
|
||||
private fun tanLatGC(lat1: Double, lat2: Double, lng2: Double, lng3: Double): Double {
|
||||
return (tan(lat1) * sin(lng2 - lng3) + tan(lat2) * sin(lng3)) / sin(lng2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns mercator(latitude-at-lng3) on the Rhumb line (lat1, lng1) to (lat2, lng2). lng1==0.
|
||||
*/
|
||||
private fun mercatorLatRhumb(lat1: Double, lat2: Double, lng2: Double, lng3: Double): Double {
|
||||
return (MathUtil.mercator(lat1) * (lng2 - lng3) + MathUtil.mercator(lat2) * lng3) / lng2
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes whether the vertical segment (lat3, lng3) to South Pole intersects the segment
|
||||
* (lat1, lng1) to (lat2, lng2).
|
||||
* Longitudes are offset by -lng1; the implicit lng1 becomes 0.
|
||||
*/
|
||||
private fun intersects(
|
||||
lat1: Double,
|
||||
lat2: Double,
|
||||
lng2: Double,
|
||||
lat3: Double,
|
||||
lng3: Double,
|
||||
geodesic: Boolean,
|
||||
): Boolean {
|
||||
// Both ends on the same side of lng3.
|
||||
if (lng3 >= 0 && lng3 >= lng2 || lng3 < 0 && lng3 < lng2) {
|
||||
return false
|
||||
}
|
||||
// Point is South Pole.
|
||||
if (lat3 <= -Math.PI / 2) {
|
||||
return false
|
||||
}
|
||||
// Any segment end is a pole.
|
||||
if (lat1 <= -Math.PI / 2 || lat2 <= -Math.PI / 2 || lat1 >= Math.PI / 2 || lat2 >= Math.PI / 2) {
|
||||
return false
|
||||
}
|
||||
if (lng2 <= -Math.PI) {
|
||||
return false
|
||||
}
|
||||
val linearLat = (lat1 * (lng2 - lng3) + lat2 * lng3) / lng2
|
||||
// Northern hemisphere and point under lat-lng line.
|
||||
if (lat1 >= 0 && lat2 >= 0 && lat3 < linearLat) {
|
||||
return false
|
||||
}
|
||||
// Southern hemisphere and point above lat-lng line.
|
||||
if (lat1 <= 0 && lat2 <= 0 && lat3 >= linearLat) {
|
||||
return true
|
||||
}
|
||||
// North Pole.
|
||||
if (lat3 >= Math.PI / 2) {
|
||||
return true
|
||||
}
|
||||
// Compare lat3 with latitude on the GC/Rhumb segment corresponding to lng3.
|
||||
// Compare through a strictly-increasing function (tan() or mercator()) as convenient.
|
||||
return if (geodesic) {
|
||||
tan(lat3) >= tanLatGC(lat1, lat2, lng2, lng3)
|
||||
} else {
|
||||
MathUtil.mercator(lat3) >= mercatorLatRhumb(lat1, lat2, lng2, lng3)
|
||||
}
|
||||
}
|
||||
|
||||
fun containsLocation(point: LatLng, polygon: List<LatLng>, geodesic: Boolean): Boolean {
|
||||
return containsLocation(point.latitude, point.longitude, polygon, geodesic)
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes whether the given point lies inside the specified polygon.
|
||||
* The polygon is always considered closed, regardless of whether the last point equals
|
||||
* the first or not.
|
||||
* Inside is defined as not containing the South Pole -- the South Pole is always outside.
|
||||
* The polygon is formed of great circle segments if geodesic is true, and of rhumb
|
||||
* (loxodromic) segments otherwise.
|
||||
*/
|
||||
fun containsLocation(
|
||||
latitude: Double,
|
||||
longitude: Double,
|
||||
polygon: List<LatLng>,
|
||||
geodesic: Boolean,
|
||||
): Boolean {
|
||||
val size = polygon.size
|
||||
if (size == 0) {
|
||||
return false
|
||||
}
|
||||
val lat3 = Math.toRadians(latitude)
|
||||
val lng3 = Math.toRadians(longitude)
|
||||
val prev = polygon[size - 1]
|
||||
var lat1 = Math.toRadians(prev.latitude)
|
||||
var lng1 = Math.toRadians(prev.longitude)
|
||||
var nIntersect = 0
|
||||
for (point2 in polygon) {
|
||||
val dLng3 = wrap(lng3 - lng1, -Math.PI, Math.PI)
|
||||
// Special case: point equal to vertex is inside.
|
||||
if (lat3 == lat1 && dLng3 == 0.0) {
|
||||
return true
|
||||
}
|
||||
val lat2 = Math.toRadians(point2.latitude)
|
||||
val lng2 = Math.toRadians(point2.longitude)
|
||||
// Offset longitudes by -lng1.
|
||||
if (
|
||||
intersects(
|
||||
lat1,
|
||||
lat2,
|
||||
wrap(lng2 - lng1, -Math.PI, Math.PI),
|
||||
lat3,
|
||||
dLng3,
|
||||
geodesic
|
||||
)
|
||||
) {
|
||||
++nIntersect
|
||||
}
|
||||
lat1 = lat2
|
||||
lng1 = lng2
|
||||
}
|
||||
return nIntersect and 1 != 0
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android
|
||||
|
||||
import com.google.maps.android.MathUtil.EARTH_RADIUS
|
||||
import com.google.maps.android.MathUtil.arcHav
|
||||
import com.google.maps.android.MathUtil.havDistance
|
||||
import com.google.maps.android.model.LatLng
|
||||
|
||||
object SphericalUtil {
|
||||
/**
|
||||
* Returns distance on the unit sphere; the arguments are in radians.
|
||||
*/
|
||||
private fun distanceRadians(lat1: Double, lng1: Double, lat2: Double, lng2: Double): Double {
|
||||
return arcHav(havDistance(lat1, lat2, lng1 - lng2))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the angle between two LatLngs, in radians. This is the same as the distance
|
||||
* on the unit sphere.
|
||||
*/
|
||||
fun computeAngleBetween(from: LatLng, to: LatLng): Double {
|
||||
return distanceRadians(
|
||||
Math.toRadians(from.latitude),
|
||||
Math.toRadians(from.longitude),
|
||||
Math.toRadians(to.latitude),
|
||||
Math.toRadians(to.longitude)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the distance between two LatLngs, in meters.
|
||||
*/
|
||||
fun computeDistanceBetween(from: LatLng, to: LatLng): Double {
|
||||
return computeAngleBetween(from, to) * EARTH_RADIUS
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data
|
||||
|
||||
import com.google.maps.android.data.geojson.GeoJsonPolygon
|
||||
import com.google.maps.android.model.LatLng
|
||||
|
||||
/**
|
||||
* An interface containing the common properties of
|
||||
* [GeoJsonPolygon] and
|
||||
* [KmlPolygon][com.google.maps.android.data.kml.KmlPolygon]
|
||||
*
|
||||
* @param <T> the type of Polygon - GeoJsonPolygon or KmlPolygon
|
||||
</T> */
|
||||
interface DataPolygon<T> : Geometry<Any?> {
|
||||
/**
|
||||
* Gets an array of outer boundary coordinates
|
||||
*
|
||||
* @return array of outer boundary coordinates
|
||||
*/
|
||||
val outerBoundaryCoordinates: List<LatLng?>?
|
||||
|
||||
/**
|
||||
* Gets an array of arrays of inner boundary coordinates
|
||||
*
|
||||
* @return array of arrays of inner boundary coordinates
|
||||
*/
|
||||
val innerBoundaryCoordinates: List<List<LatLng?>?>
|
||||
}
|
||||
131
maps-utils/src/main/java/com/google/maps/android/data/Feature.kt
Normal file
131
maps-utils/src/main/java/com/google/maps/android/data/Feature.kt
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data
|
||||
|
||||
import com.google.maps.android.data.geojson.GeoJsonFeature
|
||||
|
||||
/**
|
||||
* An abstraction that shares the common properties of
|
||||
* [KmlPlacemark][com.google.maps.android.data.kml.KmlPlacemark] and
|
||||
* [GeoJsonFeature]
|
||||
* @param featureGeometry type of geometry to assign to the feature
|
||||
* @param id common identifier of the feature
|
||||
* @param properties map containing properties related to the feature
|
||||
*/
|
||||
open class Feature(
|
||||
/**
|
||||
* Sets the stored Geometry and redraws it on the layer if it has already been added
|
||||
*
|
||||
* @param geometry Geometry to set
|
||||
*/
|
||||
/**
|
||||
* Sets the stored Geometry and redraws it on the layer if it has already been added
|
||||
*
|
||||
* @param geometry Geometry to set
|
||||
*/
|
||||
var geometry: Geometry<*>?,
|
||||
/**
|
||||
* Gets the id of the feature
|
||||
*
|
||||
* @return id
|
||||
*/
|
||||
id: String?,
|
||||
properties: MutableMap<String, String?>?,
|
||||
) {
|
||||
var mId: String? = id
|
||||
protected set
|
||||
private var mProperties: MutableMap<String, String?> = properties ?: mutableMapOf()
|
||||
/**
|
||||
* Gets the geometry object
|
||||
*
|
||||
* @return geometry object
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns all the stored property keys
|
||||
*
|
||||
* @return iterable of property keys
|
||||
*/
|
||||
val propertyKeys: Iterable<String>
|
||||
get() = mProperties.keys
|
||||
|
||||
/**
|
||||
* Gets the property entry set
|
||||
*
|
||||
* @return property entry set
|
||||
*/
|
||||
val properties: Iterable<*>
|
||||
get() = mProperties.entries
|
||||
|
||||
/**
|
||||
* Gets the value for a stored property
|
||||
*
|
||||
* @param property key of the property
|
||||
* @return value of the property if its key exists, otherwise null
|
||||
*/
|
||||
fun getProperty(property: String): String? {
|
||||
return mProperties[property]
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given property key exists
|
||||
*
|
||||
* @param property key of the property to check
|
||||
* @return true if property key exists, false otherwise
|
||||
*/
|
||||
fun hasProperty(property: String): Boolean {
|
||||
return mProperties.containsKey(property)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the placemark has properties
|
||||
*
|
||||
* @return true if there are properties in the properties map, false otherwise
|
||||
*/
|
||||
fun hasProperties(): Boolean {
|
||||
return mProperties.isNotEmpty()
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the geometry is assigned
|
||||
*
|
||||
* @return true if feature contains geometry object, otherwise null
|
||||
*/
|
||||
fun hasGeometry(): Boolean {
|
||||
return geometry != null
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new property key and value
|
||||
*
|
||||
* @param property key of the property to store
|
||||
* @param propertyValue value of the property to store
|
||||
* @return previous value with the same key, otherwise null if the key didn't exist
|
||||
*/
|
||||
protected open fun setProperty(property: String, propertyValue: String?): String? {
|
||||
return mProperties.put(property, propertyValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a given property
|
||||
*
|
||||
* @param property key of the property to remove
|
||||
* @return value of the removed property or null if there was no corresponding key
|
||||
*/
|
||||
protected open fun removeProperty(property: String): String? {
|
||||
return mProperties.remove(property)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data
|
||||
|
||||
/**
|
||||
* An abstraction that represents a Geometry object
|
||||
*
|
||||
* @param <T> the type of Geometry object
|
||||
</T> */
|
||||
interface Geometry<T> {
|
||||
/**
|
||||
* Gets the type of geometry
|
||||
*
|
||||
* @return type of geometry
|
||||
*/
|
||||
val geometryType: String
|
||||
|
||||
/**
|
||||
* Gets the stored KML Geometry object
|
||||
*
|
||||
* @return geometry object
|
||||
*/
|
||||
val geometryObject: T
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2023 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data
|
||||
|
||||
import com.google.maps.android.data.geojson.GeoJsonLineString
|
||||
import com.google.maps.android.model.LatLng
|
||||
|
||||
/**
|
||||
* An abstraction that shares the common properties of
|
||||
* [KmlLineString] and
|
||||
* [GeoJsonLineString]
|
||||
* @param coordinates array of coordinates
|
||||
*/
|
||||
open class LineString(
|
||||
coordinates: List<LatLng>,
|
||||
) : Geometry<List<LatLng>> {
|
||||
|
||||
override val geometryType: String = GEOMETRY_TYPE
|
||||
|
||||
/**
|
||||
* Gets the coordinates of the LineString
|
||||
*
|
||||
* @return coordinates of the LineString
|
||||
*/
|
||||
override val geometryObject: List<LatLng> = coordinates
|
||||
|
||||
override fun toString(): String {
|
||||
return """${GEOMETRY_TYPE}{ coordinates=$geometryObject}"""
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val GEOMETRY_TYPE = "LineString"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2023 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data
|
||||
|
||||
import com.google.maps.android.data.geojson.GeoJsonMultiLineString
|
||||
import com.google.maps.android.data.geojson.GeoJsonMultiPoint
|
||||
import com.google.maps.android.data.geojson.GeoJsonMultiPolygon
|
||||
|
||||
/**
|
||||
* An abstraction that shares the common properties of
|
||||
* [KmlMultiGeometry] and [GeoJsonMultiLineString], [GeoJsonMultiPoint] and [GeoJsonMultiPolygon]
|
||||
* @param geometries contains list of Polygons, Linestrings or Points
|
||||
*/
|
||||
open class MultiGeometry(
|
||||
geometries: List<Geometry<*>>,
|
||||
) : Geometry<Any> {
|
||||
/**
|
||||
* Gets the type of geometry
|
||||
*
|
||||
* @return type of geometry
|
||||
*/
|
||||
/**
|
||||
* Set the type of geometry
|
||||
*
|
||||
* @param type String describing type of geometry
|
||||
*/
|
||||
override var geometryType = "MultiGeometry"
|
||||
private val mGeometries: List<Geometry<*>> = geometries
|
||||
|
||||
/**
|
||||
* Gets the stored geometry object
|
||||
*
|
||||
* @return geometry object
|
||||
*/
|
||||
override val geometryObject: Any
|
||||
get() = mGeometries
|
||||
|
||||
override fun toString(): String {
|
||||
var typeString = "Geometries="
|
||||
if (geometryType == "MultiPoint") {
|
||||
typeString = "LineStrings="
|
||||
}
|
||||
if (geometryType == "MultiLineString") {
|
||||
typeString = "points="
|
||||
}
|
||||
if (geometryType == "MultiPolygon") {
|
||||
typeString = "Polygons="
|
||||
}
|
||||
return """$geometryType{ $typeString$geometryObject}"""
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2023 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data
|
||||
|
||||
import com.google.maps.android.data.geojson.GeoJsonPoint
|
||||
import com.google.maps.android.model.LatLng
|
||||
|
||||
/**
|
||||
* An abstraction that shares the common properties of
|
||||
* [KmlPoint] and
|
||||
* [GeoJsonPoint]
|
||||
*/
|
||||
open class Point(
|
||||
coordinates: LatLng,
|
||||
) : Geometry<Any> {
|
||||
private val mCoordinates: LatLng
|
||||
|
||||
/**
|
||||
* Creates a new Point object
|
||||
*
|
||||
* @param coordinates coordinates of Point to store
|
||||
*/
|
||||
init {
|
||||
mCoordinates = coordinates
|
||||
}
|
||||
|
||||
override val geometryObject: Any
|
||||
/**
|
||||
* Gets the coordinates of the Point
|
||||
*
|
||||
* @return coordinates of the Point
|
||||
*/
|
||||
get() = mCoordinates
|
||||
|
||||
override fun toString(): String {
|
||||
return """$geometryType{ coordinates=$mCoordinates}"""
|
||||
}
|
||||
|
||||
override val geometryType = "Point"
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2023 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data.geojson
|
||||
|
||||
import com.google.maps.android.data.Feature
|
||||
import com.google.maps.android.data.Geometry
|
||||
import com.google.maps.android.model.LatLngBounds
|
||||
|
||||
/**
|
||||
* A GeoJsonFeature has a geometry, bounding box, id and set of properties. Styles are also stored
|
||||
* in this class.
|
||||
*/
|
||||
class GeoJsonFeature(
|
||||
geometry: Geometry<*>?,
|
||||
id: String?,
|
||||
properties: HashMap<String, String?>?,
|
||||
boundingBox: LatLngBounds?,
|
||||
) : Feature(geometry, id, properties) {
|
||||
private val mBoundingBox: LatLngBounds?
|
||||
|
||||
/**
|
||||
* Creates a new GeoJsonFeature object
|
||||
*
|
||||
* @param geometry type of geometry to assign to the feature
|
||||
* @param id common identifier of the feature
|
||||
* @param properties hashmap of containing properties related to the feature
|
||||
* @param boundingBox bounding box of the feature
|
||||
*/
|
||||
init {
|
||||
mId = id
|
||||
mBoundingBox = boundingBox
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new property key and value
|
||||
*
|
||||
* @param property key of the property to store
|
||||
* @param propertyValue value of the property to store
|
||||
* @return previous value with the same key, otherwise null if the key didn't exist
|
||||
*/
|
||||
public override fun setProperty(property: String, propertyValue: String?): String? {
|
||||
return super.setProperty(property, propertyValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a given property
|
||||
*
|
||||
* @param property key of the property to remove
|
||||
* @return value of the removed property or null if there was no corresponding key
|
||||
*/
|
||||
public override fun removeProperty(property: String): String? {
|
||||
return super.removeProperty(property)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return """Feature{ bounding box=$mBoundingBox, geometry=$geometry, id=$mId, properties=$properties}"""
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2020 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data.geojson
|
||||
|
||||
import com.google.maps.android.data.Geometry
|
||||
import com.google.maps.android.data.MultiGeometry
|
||||
|
||||
/**
|
||||
* A GeoJsonGeometryCollection geometry contains a number of GeoJson Geometry objects.
|
||||
*/
|
||||
class GeoJsonGeometryCollection(
|
||||
geometries: List<Geometry<*>>,
|
||||
) : MultiGeometry(geometries) {
|
||||
/**
|
||||
* Creates a new GeoJsonGeometryCollection object
|
||||
*
|
||||
* @param geometries array of Geometry objects to add to the GeoJsonGeometryCollection
|
||||
*/
|
||||
init {
|
||||
geometryType = "GeometryCollection"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of geometry. The type of geometry conforms to the GeoJSON 'type'
|
||||
* specification.
|
||||
*
|
||||
* @return type of geometry
|
||||
*/
|
||||
val type: String
|
||||
get() = geometryType
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2020 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data.geojson
|
||||
|
||||
import com.google.maps.android.data.LineString
|
||||
import com.google.maps.android.model.LatLng
|
||||
|
||||
/**
|
||||
* A GeoJsonLineString geometry represents a number of connected [ ]s.
|
||||
* @param coordinates array of coordinates
|
||||
*/
|
||||
class GeoJsonLineString(
|
||||
coordinates: List<LatLng>,
|
||||
) : LineString(coordinates) {
|
||||
/**
|
||||
* Gets the type of geometry. The type of geometry conforms to the GeoJSON 'type'
|
||||
* specification.
|
||||
*
|
||||
* @return type of geometry
|
||||
*/
|
||||
val type: String
|
||||
get() = geometryType
|
||||
|
||||
/**
|
||||
* Gets the coordinates of the GeoJsonLineString
|
||||
*
|
||||
* @return list of coordinates of the GeoJsonLineString
|
||||
*/
|
||||
val coordinates: List<LatLng>
|
||||
get() = geometryObject
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2020 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data.geojson
|
||||
|
||||
import com.google.maps.android.data.MultiGeometry
|
||||
|
||||
/**
|
||||
* A GeoJsonMultiLineString geometry contains a number of [GeoJsonLineString]s.
|
||||
*/
|
||||
class GeoJsonMultiLineString(
|
||||
geoJsonLineStrings: List<GeoJsonLineString>,
|
||||
) : MultiGeometry(geoJsonLineStrings) {
|
||||
/**
|
||||
* Creates a new GeoJsonMultiLineString object
|
||||
*
|
||||
* @param geoJsonLineStrings list of GeoJsonLineStrings to store
|
||||
*/
|
||||
init {
|
||||
geometryType = "MultiLineString"
|
||||
}
|
||||
|
||||
val type: String
|
||||
/**
|
||||
* Gets the type of geometry. The type of geometry conforms to the GeoJSON 'type'
|
||||
* specification.
|
||||
*
|
||||
* @return type of geometry
|
||||
*/
|
||||
get() = geometryType
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2020 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data.geojson
|
||||
|
||||
import com.google.maps.android.data.MultiGeometry
|
||||
|
||||
/**
|
||||
* A GeoJsonMultiPoint geometry contains a number of [GeoJsonPoint]s.
|
||||
*/
|
||||
class GeoJsonMultiPoint(
|
||||
geoJsonPoints: List<GeoJsonPoint>,
|
||||
) : MultiGeometry(geoJsonPoints) {
|
||||
/**
|
||||
* Creates a GeoJsonMultiPoint object
|
||||
*
|
||||
* @param geoJsonPoints list of GeoJsonPoints to store
|
||||
*/
|
||||
init {
|
||||
geometryType = "MultiPoint"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of geometry. The type of geometry conforms to the GeoJSON 'type'
|
||||
* specification.
|
||||
*
|
||||
* @return type of geometry
|
||||
*/
|
||||
val type: String
|
||||
get() = geometryType
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2020 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data.geojson
|
||||
|
||||
import com.google.maps.android.data.MultiGeometry
|
||||
|
||||
/**
|
||||
* A GeoJsonMultiPolygon geometry contains a number of [GeoJsonPolygon]s.
|
||||
*
|
||||
* @param geoJsonPolygons list of GeoJsonPolygons to store
|
||||
*/
|
||||
class GeoJsonMultiPolygon(
|
||||
geoJsonPolygons: List<GeoJsonPolygon>,
|
||||
) : MultiGeometry(geoJsonPolygons) {
|
||||
/**
|
||||
* Creates a new GeoJsonMultiPolygon
|
||||
*/
|
||||
init {
|
||||
geometryType = "MultiPolygon"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of geometry. The type of geometry conforms to the GeoJSON 'type'
|
||||
* specification.
|
||||
*
|
||||
* @return type of geometry
|
||||
*/
|
||||
val type: String
|
||||
get() = geometryType
|
||||
|
||||
/**
|
||||
* Gets a list of GeoJsonPolygons
|
||||
*
|
||||
* @return list of GeoJsonPolygons
|
||||
*/
|
||||
val polygons: List<GeoJsonPolygon>
|
||||
get() {
|
||||
// convert list of Geometry types to list of GeoJsonPolygon types
|
||||
val geometryList = geometryObject
|
||||
val geoJsonPolygon = mutableListOf<GeoJsonPolygon>()
|
||||
for (geometry in geometryList as List<GeoJsonPolygon>) {
|
||||
geoJsonPolygon.add(geometry)
|
||||
}
|
||||
return geoJsonPolygon
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,491 @@
|
|||
/*
|
||||
* Copyright 2020 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data.geojson
|
||||
|
||||
import android.util.Log
|
||||
import com.google.maps.android.data.Geometry
|
||||
import com.google.maps.android.model.LatLng
|
||||
import com.google.maps.android.model.LatLngBounds
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
|
||||
/**
|
||||
* Parses a JSONObject and places data into their appropriate GeoJsonFeature objects. Returns an
|
||||
* array of
|
||||
* GeoJsonFeature objects parsed from the GeoJSON file.
|
||||
*/
|
||||
class GeoJsonParser(
|
||||
private val mGeoJsonFile: JSONObject,
|
||||
) {
|
||||
/**
|
||||
* Gets the array of GeoJsonFeature objects
|
||||
*
|
||||
* @return array of GeoJsonFeatures
|
||||
*/
|
||||
val features = mutableListOf<GeoJsonFeature>()
|
||||
private var mBoundingBox: LatLngBounds? = null
|
||||
|
||||
/**
|
||||
* Internal helper class to store latLng and altitude in a single object.
|
||||
* This allows to parse [lon,lat,altitude] tuples in GeoJson files more efficiently.
|
||||
* Note that altitudes are generally optional so they can be null.
|
||||
*/
|
||||
private class LatLngAlt(val latLng: LatLng, val altitude: Double?)
|
||||
|
||||
/**
|
||||
* Creates a new GeoJsonParser
|
||||
*
|
||||
* @param geoJsonFile GeoJSON file to parse
|
||||
*/
|
||||
init {
|
||||
parseGeoJson()
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the GeoJSON file by type and adds the generated GeoJsonFeature objects to the
|
||||
* mFeatures array. Supported GeoJSON types include feature, feature collection and geometry.
|
||||
*/
|
||||
private fun parseGeoJson() {
|
||||
try {
|
||||
val feature: GeoJsonFeature?
|
||||
val type = mGeoJsonFile.getString("type")
|
||||
if (type == FEATURE) {
|
||||
feature = parseFeature(mGeoJsonFile)
|
||||
if (feature != null) {
|
||||
features.add(feature)
|
||||
}
|
||||
} else if (type == FEATURE_COLLECTION) {
|
||||
features.addAll(parseFeatureCollection(mGeoJsonFile))
|
||||
} else if (isGeometry(type)) {
|
||||
feature = parseGeometryToFeature(mGeoJsonFile)
|
||||
if (feature != null) {
|
||||
// Don't add null features
|
||||
features.add(feature)
|
||||
}
|
||||
} else {
|
||||
Log.w(LOG_TAG, "GeoJSON file could not be parsed.")
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
Log.w(LOG_TAG, "GeoJSON file could not be parsed.")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the array of GeoJSON features in a given GeoJSON feature collection. Also parses the
|
||||
* bounding box member of the feature collection if it exists.
|
||||
*
|
||||
* @param geoJsonFeatureCollection feature collection to parse
|
||||
* @return array of GeoJsonFeature objects
|
||||
*/
|
||||
private fun parseFeatureCollection(geoJsonFeatureCollection: JSONObject): List<GeoJsonFeature> {
|
||||
val geoJsonFeatures: JSONArray
|
||||
val features = mutableListOf<GeoJsonFeature>()
|
||||
try {
|
||||
geoJsonFeatures = geoJsonFeatureCollection.getJSONArray(FEATURE_COLLECTION_ARRAY)
|
||||
if (geoJsonFeatureCollection.has(BOUNDING_BOX)) {
|
||||
mBoundingBox = parseBoundingBox(
|
||||
geoJsonFeatureCollection.getJSONArray(BOUNDING_BOX)
|
||||
)
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
Log.w(LOG_TAG, "Feature Collection could not be created.")
|
||||
return features
|
||||
}
|
||||
for (i in 0 until geoJsonFeatures.length()) {
|
||||
try {
|
||||
val feature = geoJsonFeatures.getJSONObject(i)
|
||||
if (feature.getString("type") == FEATURE) {
|
||||
val parsedFeature = parseFeature(feature)
|
||||
if (parsedFeature != null) {
|
||||
// Don't add null features
|
||||
features.add(parsedFeature)
|
||||
} else {
|
||||
Log.w(
|
||||
LOG_TAG,
|
||||
"Index of Feature in Feature Collection that could not be created: $i"
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
Log.w(
|
||||
LOG_TAG,
|
||||
"Index of Feature in Feature Collection that could not be created: $i"
|
||||
)
|
||||
}
|
||||
}
|
||||
return features
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val LOG_TAG = "GeoJsonParser"
|
||||
|
||||
// Feature object type
|
||||
private const val FEATURE = "Feature"
|
||||
|
||||
// Feature object geometry member
|
||||
private const val FEATURE_GEOMETRY = "geometry"
|
||||
|
||||
// Feature object id member
|
||||
private const val FEATURE_ID = "id"
|
||||
|
||||
// FeatureCollection type
|
||||
private const val FEATURE_COLLECTION = "FeatureCollection"
|
||||
|
||||
// FeatureCollection features array member
|
||||
private const val FEATURE_COLLECTION_ARRAY = "features"
|
||||
|
||||
// Geometry coordinates member
|
||||
private const val GEOMETRY_COORDINATES_ARRAY = "coordinates"
|
||||
|
||||
// GeometryCollection type
|
||||
private const val GEOMETRY_COLLECTION = "GeometryCollection"
|
||||
|
||||
// GeometryCollection geometries array member
|
||||
private const val GEOMETRY_COLLECTION_ARRAY = "geometries"
|
||||
|
||||
// Coordinates for bbox
|
||||
private const val BOUNDING_BOX = "bbox"
|
||||
private const val PROPERTIES = "properties"
|
||||
private const val POINT = "Point"
|
||||
private const val MULTIPOINT = "MultiPoint"
|
||||
private const val LINESTRING = "LineString"
|
||||
private const val MULTILINESTRING = "MultiLineString"
|
||||
private const val POLYGON = "Polygon"
|
||||
private const val MULTIPOLYGON = "MultiPolygon"
|
||||
private fun isGeometry(type: String): Boolean {
|
||||
return type.matches(
|
||||
(
|
||||
POINT +
|
||||
"|" +
|
||||
MULTIPOINT +
|
||||
"|" +
|
||||
LINESTRING +
|
||||
"|" +
|
||||
MULTILINESTRING +
|
||||
"|" +
|
||||
POLYGON +
|
||||
"|" +
|
||||
MULTIPOLYGON +
|
||||
"|" +
|
||||
GEOMETRY_COLLECTION
|
||||
).toRegex()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a single GeoJSON feature which contains a geometry and properties member both of
|
||||
* which can be null. Also parses the bounding box and id members of the feature if they exist.
|
||||
*
|
||||
* @param geoJsonFeature feature to parse
|
||||
* @return GeoJsonFeature object
|
||||
*/
|
||||
private fun parseFeature(geoJsonFeature: JSONObject): GeoJsonFeature? {
|
||||
var id: String? = null
|
||||
var boundingBox: LatLngBounds? = null
|
||||
var geometry: Geometry<*>? = null
|
||||
var properties = HashMap<String, String?>()
|
||||
try {
|
||||
if (geoJsonFeature.has(FEATURE_ID)) {
|
||||
id = geoJsonFeature.getString(FEATURE_ID)
|
||||
}
|
||||
if (geoJsonFeature.has(BOUNDING_BOX)) {
|
||||
boundingBox = parseBoundingBox(geoJsonFeature.getJSONArray(BOUNDING_BOX))
|
||||
}
|
||||
if (geoJsonFeature.has(FEATURE_GEOMETRY) && !geoJsonFeature.isNull(FEATURE_GEOMETRY)) {
|
||||
geometry = parseGeometry(geoJsonFeature.getJSONObject(FEATURE_GEOMETRY))
|
||||
}
|
||||
if (geoJsonFeature.has(PROPERTIES) && !geoJsonFeature.isNull(PROPERTIES)) {
|
||||
properties = parseProperties(geoJsonFeature.getJSONObject("properties"))
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
Log.w(LOG_TAG, "Feature could not be successfully parsed $geoJsonFeature")
|
||||
return null
|
||||
}
|
||||
return GeoJsonFeature(geometry, id, properties, boundingBox)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a bounding box given as a JSONArray of 4 elements in the order of lowest values for
|
||||
* all axes followed by highest values. Axes order of a bounding box follows the axes order of
|
||||
* geometries.
|
||||
*
|
||||
* @param coordinates array of 4 coordinates
|
||||
* @return LatLngBounds containing the coordinates of the bounding box
|
||||
* @throws JSONException if the bounding box could not be parsed
|
||||
*/
|
||||
@Throws(JSONException::class)
|
||||
private fun parseBoundingBox(coordinates: JSONArray): LatLngBounds {
|
||||
// Lowest values for all axes
|
||||
val southWestCorner = LatLng(coordinates.getDouble(1), coordinates.getDouble(0))
|
||||
// Highest value for all axes
|
||||
val northEastCorner = LatLng(coordinates.getDouble(3), coordinates.getDouble(2))
|
||||
return LatLngBounds(southWestCorner, northEastCorner)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a single GeoJSON geometry object containing a coordinates array or a geometries array
|
||||
* if it has type GeometryCollection. FeatureCollections, styles, bounding boxes, and properties
|
||||
* are not processed by this method. If you want to parse GeoJSON including FeatureCollections,
|
||||
* styles, bounding boxes, and properties into an array of [GeoJsonFeature]s then
|
||||
* instantiate [GeoJsonParser] and call [GeoJsonParser.getFeatures].
|
||||
*
|
||||
* @param geoJsonGeometry geometry object to parse
|
||||
* @return Geometry object
|
||||
*/
|
||||
fun parseGeometry(geoJsonGeometry: JSONObject): Geometry<*>? {
|
||||
return try {
|
||||
val geometryType = geoJsonGeometry.getString("type")
|
||||
val geometryArray: JSONArray
|
||||
geometryArray = if (geometryType == GEOMETRY_COLLECTION) {
|
||||
// GeometryCollection
|
||||
geoJsonGeometry.getJSONArray(GEOMETRY_COLLECTION_ARRAY)
|
||||
} else if (isGeometry(geometryType)) {
|
||||
geoJsonGeometry.getJSONArray(GEOMETRY_COORDINATES_ARRAY)
|
||||
} else {
|
||||
// No geometries or coordinates array
|
||||
return null
|
||||
}
|
||||
createGeometry(geometryType, geometryArray)
|
||||
} catch (e: JSONException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Geometry object into a GeoJsonFeature object. A geometry object has no ID,
|
||||
* properties or bounding box so it is set to null.
|
||||
*
|
||||
* @param geoJsonGeometry Geometry object to convert into a Feature object
|
||||
* @return new Feature object
|
||||
*/
|
||||
private fun parseGeometryToFeature(geoJsonGeometry: JSONObject): GeoJsonFeature? {
|
||||
val geometry = parseGeometry(geoJsonGeometry)
|
||||
if (geometry != null) {
|
||||
return GeoJsonFeature(geometry, null, HashMap(), null)
|
||||
}
|
||||
Log.w(LOG_TAG, "Geometry could not be parsed")
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the properties of a GeoJSON feature into a hashmap
|
||||
*
|
||||
* @param properties GeoJSON properties member
|
||||
* @return hashmap containing property values
|
||||
* @throws JSONException if the properties could not be parsed
|
||||
*/
|
||||
@Throws(JSONException::class)
|
||||
private fun parseProperties(properties: JSONObject): HashMap<String, String?> {
|
||||
val propertiesMap = HashMap<String, String?>()
|
||||
val propertyKeys: Iterator<*> = properties.keys()
|
||||
while (propertyKeys.hasNext()) {
|
||||
val key = propertyKeys.next() as String
|
||||
propertiesMap[key] = if (properties.isNull(key)) null else properties.getString(key)
|
||||
}
|
||||
return propertiesMap
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Geometry object from the given type of geometry and its coordinates or
|
||||
* geometries array
|
||||
*
|
||||
* @param geometryType type of geometry
|
||||
* @param geometryArray coordinates or geometries of the geometry
|
||||
* @return Geometry object
|
||||
* @throws JSONException if the coordinates or geometries could be parsed
|
||||
*/
|
||||
@Throws(JSONException::class)
|
||||
private fun createGeometry(geometryType: String, geometryArray: JSONArray): Geometry<*>? {
|
||||
when (geometryType) {
|
||||
POINT -> return createPoint(geometryArray)
|
||||
MULTIPOINT -> return createMultiPoint(geometryArray)
|
||||
LINESTRING -> return createLineString(geometryArray)
|
||||
MULTILINESTRING -> return createMultiLineString(geometryArray)
|
||||
POLYGON -> return createPolygon(geometryArray)
|
||||
MULTIPOLYGON -> return createMultiPolygon(geometryArray)
|
||||
GEOMETRY_COLLECTION -> return createGeometryCollection(geometryArray)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GeoJsonPoint object
|
||||
*
|
||||
* @param coordinates array containing the coordinates for the GeoJsonPoint
|
||||
* @return GeoJsonPoint object
|
||||
* @throws JSONException if coordinates cannot be parsed
|
||||
*/
|
||||
@Throws(JSONException::class)
|
||||
private fun createPoint(coordinates: JSONArray): GeoJsonPoint {
|
||||
val latLngAlt = parseCoordinate(coordinates)
|
||||
return GeoJsonPoint(latLngAlt.latLng)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GeoJsonMultiPoint object containing an array of GeoJsonPoint objects
|
||||
*
|
||||
* @param coordinates array containing the coordinates for the GeoJsonMultiPoint
|
||||
* @return GeoJsonMultiPoint object
|
||||
* @throws JSONException if coordinates cannot be parsed
|
||||
*/
|
||||
@Throws(JSONException::class)
|
||||
private fun createMultiPoint(coordinates: JSONArray): GeoJsonMultiPoint {
|
||||
val geoJsonPoints = mutableListOf<GeoJsonPoint>()
|
||||
for (i in 0 until coordinates.length()) {
|
||||
geoJsonPoints.add(createPoint(coordinates.getJSONArray(i)))
|
||||
}
|
||||
return GeoJsonMultiPoint(geoJsonPoints)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GeoJsonLineString object
|
||||
*
|
||||
* @param coordinates array containing the coordinates for the GeoJsonLineString
|
||||
* @return GeoJsonLineString object
|
||||
* @throws JSONException if coordinates cannot be parsed
|
||||
*/
|
||||
@Throws(JSONException::class)
|
||||
private fun createLineString(coordinates: JSONArray): GeoJsonLineString {
|
||||
val latLngAlts = parseCoordinatesArray(coordinates)
|
||||
val latLngs = mutableListOf<LatLng>()
|
||||
for (latLngAlt in latLngAlts) {
|
||||
latLngs.add(latLngAlt.latLng)
|
||||
}
|
||||
return GeoJsonLineString(latLngs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GeoJsonMultiLineString object containing an array of GeoJsonLineString objects
|
||||
*
|
||||
* @param coordinates array containing the coordinates for the GeoJsonMultiLineString
|
||||
* @return GeoJsonMultiLineString object
|
||||
* @throws JSONException if coordinates cannot be parsed
|
||||
*/
|
||||
@Throws(JSONException::class)
|
||||
private fun createMultiLineString(coordinates: JSONArray): GeoJsonMultiLineString {
|
||||
val geoJsonLineStrings = mutableListOf<GeoJsonLineString>()
|
||||
for (i in 0 until coordinates.length()) {
|
||||
geoJsonLineStrings.add(createLineString(coordinates.getJSONArray(i)))
|
||||
}
|
||||
return GeoJsonMultiLineString(geoJsonLineStrings)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GeoJsonPolygon object
|
||||
*
|
||||
* @param coordinates array containing the coordinates for the GeoJsonPolygon
|
||||
* @return GeoJsonPolygon object
|
||||
* @throws JSONException if coordinates cannot be parsed
|
||||
*/
|
||||
@Throws(JSONException::class)
|
||||
private fun createPolygon(coordinates: JSONArray): GeoJsonPolygon {
|
||||
return GeoJsonPolygon(parseCoordinatesArrays(coordinates))
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GeoJsonMultiPolygon object containing an array of GeoJsonPolygon objects
|
||||
*
|
||||
* @param coordinates array containing the coordinates for the GeoJsonMultiPolygon
|
||||
* @return GeoJsonPolygon object
|
||||
* @throws JSONException if coordinates cannot be parsed
|
||||
*/
|
||||
@Throws(JSONException::class)
|
||||
private fun createMultiPolygon(coordinates: JSONArray): GeoJsonMultiPolygon {
|
||||
val geoJsonPolygons = mutableListOf<GeoJsonPolygon>()
|
||||
for (i in 0 until coordinates.length()) {
|
||||
geoJsonPolygons.add(createPolygon(coordinates.getJSONArray(i)))
|
||||
}
|
||||
return GeoJsonMultiPolygon(geoJsonPolygons)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GeoJsonGeometryCollection object containing an array of Geometry
|
||||
* objects
|
||||
*
|
||||
* @param geometries array containing the geometries for the GeoJsonGeometryCollection
|
||||
* @return GeoJsonGeometryCollection object
|
||||
* @throws JSONException if geometries cannot be parsed
|
||||
*/
|
||||
@Throws(JSONException::class)
|
||||
private fun createGeometryCollection(geometries: JSONArray): GeoJsonGeometryCollection {
|
||||
val geometryCollectionElements = mutableListOf<Geometry<*>>()
|
||||
for (i in 0 until geometries.length()) {
|
||||
val geometryElement = geometries.getJSONObject(i)
|
||||
val geometry = parseGeometry(geometryElement)
|
||||
if (geometry != null) {
|
||||
// Do not add geometries that could not be parsed
|
||||
geometryCollectionElements.add(geometry)
|
||||
}
|
||||
}
|
||||
return GeoJsonGeometryCollection(geometryCollectionElements)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an array containing a coordinate into a LatLngAlt object
|
||||
*
|
||||
* @param coordinates array containing the GeoJSON coordinate
|
||||
* @return LatLngAlt object
|
||||
* @throws JSONException if coordinate cannot be parsed
|
||||
*/
|
||||
@Throws(JSONException::class)
|
||||
private fun parseCoordinate(coordinates: JSONArray): LatLngAlt {
|
||||
// GeoJSON stores coordinates as Lng, Lat so we need to reverse
|
||||
val latLng = LatLng(coordinates.getDouble(1), coordinates.getDouble(0))
|
||||
val altitude = if (coordinates.length() < 3) null else coordinates.getDouble(2)
|
||||
return LatLngAlt(latLng, altitude)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an array containing coordinates into a List of LatLng objects
|
||||
*
|
||||
* @param coordinates array containing the GeoJSON coordinates
|
||||
* @return List of LatLng objects
|
||||
* @throws JSONException if coordinates cannot be parsed
|
||||
*/
|
||||
@Throws(JSONException::class)
|
||||
private fun parseCoordinatesArray(coordinates: JSONArray): List<LatLngAlt> {
|
||||
val coordinatesArray = mutableListOf<LatLngAlt>()
|
||||
for (i in 0 until coordinates.length()) {
|
||||
coordinatesArray.add(parseCoordinate(coordinates.getJSONArray(i)))
|
||||
}
|
||||
return coordinatesArray
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an array of arrays containing coordinates into a List of a List of LatLng
|
||||
* objects
|
||||
*
|
||||
* @param coordinates array of an array containing the GeoJSON coordinates
|
||||
* @return List of a List of LatLng objects
|
||||
* @throws JSONException if coordinates cannot be parsed
|
||||
*/
|
||||
@Throws(JSONException::class)
|
||||
private fun parseCoordinatesArrays(coordinates: JSONArray): List<List<LatLng>> {
|
||||
val coordinatesArray = mutableListOf<MutableList<LatLng>>()
|
||||
for (i in 0 until coordinates.length()) {
|
||||
val latLngAlts = parseCoordinatesArray(coordinates.getJSONArray(i))
|
||||
// this method is called for polygons, which do not have altitude values
|
||||
val latLngs = mutableListOf<LatLng>()
|
||||
for (latLngAlt in latLngAlts) {
|
||||
latLngs.add(latLngAlt.latLng)
|
||||
}
|
||||
coordinatesArray.add(latLngs)
|
||||
}
|
||||
return coordinatesArray
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2020 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data.geojson
|
||||
|
||||
import com.google.maps.android.data.Point
|
||||
import com.google.maps.android.model.LatLng
|
||||
|
||||
/**
|
||||
* A GeoJsonPoint geometry contains a single [LatLng].
|
||||
* @param coordinates coordinates of the KmlPoint
|
||||
*/
|
||||
class GeoJsonPoint(
|
||||
val coordinates: LatLng,
|
||||
) : Point(coordinates) {
|
||||
/**
|
||||
* Gets the type of geometry. The type of geometry conforms to the GeoJSON 'type'
|
||||
* specification.
|
||||
*
|
||||
* @return type of geometry
|
||||
*/
|
||||
val type: String
|
||||
get() = geometryType
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright 2023 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data.geojson
|
||||
|
||||
import com.google.maps.android.data.DataPolygon
|
||||
import com.google.maps.android.model.LatLng
|
||||
|
||||
/**
|
||||
* A GeoJsonPolygon geometry contains an array of arrays of [LatLng]s.
|
||||
* The first array is the polygon exterior boundary. Subsequent arrays are holes.
|
||||
*/
|
||||
class GeoJsonPolygon(
|
||||
/**
|
||||
* list of a list of coordinates of the GeoJsonPolygons
|
||||
*/
|
||||
val coordinates: List<List<LatLng>>,
|
||||
) : DataPolygon<Any?> {
|
||||
|
||||
/**
|
||||
* Gets the stored geometry object
|
||||
*
|
||||
* @return geometry object
|
||||
*/
|
||||
override val geometryObject: Any
|
||||
get() = coordinates
|
||||
|
||||
/**
|
||||
* Gets the type of geometry
|
||||
*
|
||||
* @return type of geometry
|
||||
*/
|
||||
override val geometryType: String
|
||||
get() = TYPE
|
||||
|
||||
/**
|
||||
* Gets an array of outer boundary coordinates
|
||||
*
|
||||
* @return array of outer boundary coordinates
|
||||
*/
|
||||
override val outerBoundaryCoordinates: List<LatLng?>
|
||||
get() = // First array of coordinates are the outline
|
||||
coordinates[POLYGON_OUTER_COORDINATE_INDEX] as MutableList<LatLng>
|
||||
|
||||
/**
|
||||
* Gets an array of arrays of inner boundary coordinates
|
||||
*
|
||||
* @return array of arrays of inner boundary coordinates
|
||||
*/
|
||||
override val innerBoundaryCoordinates: List<List<LatLng?>?>
|
||||
get() {
|
||||
// Following arrays are holes
|
||||
val innerBoundary = mutableListOf<MutableList<LatLng>>()
|
||||
for (i in POLYGON_INNER_COORDINATE_INDEX until coordinates.size) {
|
||||
innerBoundary.add(coordinates[i] as MutableList<LatLng>)
|
||||
}
|
||||
return innerBoundary
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return """$TYPE{ coordinates=$coordinates}"""
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TYPE = "Polygon"
|
||||
|
||||
private const val POLYGON_OUTER_COORDINATE_INDEX = 0
|
||||
private const val POLYGON_INNER_COORDINATE_INDEX = 1
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2020 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.maps.android.data.geojson
|
||||
|
||||
/**
|
||||
* Class used to apply styles for the
|
||||
* [GeoJsonFeature] objects
|
||||
*/
|
||||
internal interface GeoJsonStyle {
|
||||
/**
|
||||
* Gets the type of geometries this style can be applied to
|
||||
*
|
||||
* @return type of geometries this style can be applied to
|
||||
*/
|
||||
val geometryType: Array<String?>
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
package com.google.maps.android.model
|
||||
|
||||
import com.google.maps.android.SphericalUtil
|
||||
import java.text.ParseException
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class LatLng(
|
||||
latitude: Double,
|
||||
longitude: Double,
|
||||
) {
|
||||
val latitude: Double
|
||||
val longitude: Double
|
||||
|
||||
init {
|
||||
this.latitude = max(-90.0, min(90.0, latitude))
|
||||
this.longitude = max(-180.0, min(180.0, longitude))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key of the nearest location from a predefined map of locations
|
||||
*
|
||||
* @param locationMap map of locations { key (unique identifier) => LatLng }
|
||||
* @param limit furthest allowed match in meters, null if no limit
|
||||
*/
|
||||
fun getNearestLocation(
|
||||
locationMap: Map<String, LatLng>?,
|
||||
limit: Double? = null,
|
||||
): String? {
|
||||
var distance: Double
|
||||
var nearestDistance = Double.POSITIVE_INFINITY
|
||||
var nearestLocation: String? = null
|
||||
locationMap?.keys?.forEach { key ->
|
||||
locationMap[key]?.let {
|
||||
distance = SphericalUtil.computeDistanceBetween(this, locationMap[key]!!)
|
||||
if (distance < nearestDistance) {
|
||||
if (limit == null || distance <= limit) {
|
||||
nearestDistance = distance
|
||||
nearestLocation = key
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nearestLocation
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return if (other is LatLng) {
|
||||
latitude == other.latitude && longitude == other.longitude
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = latitude.hashCode()
|
||||
result = 31 * result + longitude.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "$latitude,$longitude"
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Throws(ParseException::class)
|
||||
fun parse(value: String): LatLng {
|
||||
val coordArr = value.split(",")
|
||||
|
||||
if (coordArr.size != 2) {
|
||||
throw ParseException("Failed parsing '$value' as LatLng", 0)
|
||||
}
|
||||
|
||||
val lon = coordArr[0].trim().toDoubleOrNull()
|
||||
val lat = coordArr[1].trim().toDoubleOrNull()
|
||||
|
||||
if (lon == null || lat == null || (lon == 0.0 && lat == 0.0)) {
|
||||
throw ParseException("Failed parsing '$value' as LatLng", 0)
|
||||
}
|
||||
return LatLng(lon, lat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.google.maps.android.model
|
||||
|
||||
data class LatLngBounds(
|
||||
val southwest: LatLng,
|
||||
val northeast: LatLng,
|
||||
) {
|
||||
|
||||
fun contains(point: LatLng): Boolean {
|
||||
if (southwest.latitude <= point.latitude) {
|
||||
if (point.latitude <= northeast.latitude) {
|
||||
return if (southwest.longitude <= northeast.longitude) {
|
||||
point.longitude in southwest.longitude..northeast.longitude
|
||||
} else if (southwest.longitude <= point.longitude || point.longitude <= northeast.longitude) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun parse(
|
||||
west: Double,
|
||||
south: Double,
|
||||
east: Double,
|
||||
north: Double,
|
||||
): LatLngBounds {
|
||||
return LatLngBounds(
|
||||
southwest = LatLng(south, west),
|
||||
northeast = LatLng(north, east)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* This file is part of Breezy Weather.
|
||||
*
|
||||
* Breezy Weather 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, version 3 of the License.
|
||||
*
|
||||
* Breezy Weather 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 Breezy Weather. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.google.maps.android
|
||||
|
||||
import com.google.maps.android.model.LatLng
|
||||
import io.kotest.matchers.shouldBe
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class EncodedPolylineUtilTest {
|
||||
|
||||
@Test
|
||||
fun decode() = runTest {
|
||||
val encoded = "_p~iF~ps|U_ulLnnqC_mqNvxq`@"
|
||||
val decodedLatLng = EncodedPolylineUtil.decode(encoded)
|
||||
|
||||
decodedLatLng.size shouldBe 3
|
||||
decodedLatLng[0] shouldBe LatLng(38.5, -120.2)
|
||||
decodedLatLng[1] shouldBe LatLng(40.7, -120.95)
|
||||
decodedLatLng[2] shouldBe LatLng(43.252, -126.453)
|
||||
/*
|
||||
decodedLatLng[0].latitude shouldBe 38.5
|
||||
decodedLatLng[0].longitude shouldBe -120.2
|
||||
decodedLatLng[1].latitude shouldBe 40.7
|
||||
decodedLatLng[1].longitude shouldBe -120.95
|
||||
decodedLatLng[2].latitude shouldBe 43.252
|
||||
decodedLatLng[2].longitude shouldBe -126.453
|
||||
*/
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue