Skip to content

Commit 0322564

Browse files
kediarovgithub-actions[bot]
authored andcommitted
Globe CustomLayer Example and API (#4843)
https://mapbox.atlassian.net/browse/MAPSAND-2177 Android platform version of mapbox/mapbox-sdk#3860 https://github.com/user-attachments/assets/43a4018c-890a-4690-8619-f5e88082ec4b cc @mapbox/maps-android GitOrigin-RevId: df3eb33f8cfc6fd91c9350f95813deecf0aacf18
1 parent 7f34433 commit 0322564

File tree

13 files changed

+989
-0
lines changed

13 files changed

+989
-0
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,18 @@
875875
android:name="android.support.PARENT_ACTIVITY"
876876
android:value=".ExampleOverviewActivity" />
877877
</activity>
878+
<activity
879+
android:name=".examples.customlayer.globe.GlobeCustomLayerActivity"
880+
android:description="@string/description_globe_custom_layer"
881+
android:exported="true"
882+
android:label="@string/activity_globe_custom_layer">
883+
<meta-data
884+
android:name="@string/category"
885+
android:value="@string/category_custom_layer" />
886+
<meta-data
887+
android:name="android.support.PARENT_ACTIVITY"
888+
android:value=".ExampleOverviewActivity" />
889+
</activity>
878890
<activity
879891
android:name=".examples.TransparentBackgroundActivity"
880892
android:description="@string/description_transparent_bg"
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.mapbox.maps.testapp.examples.customlayer.globe
2+
3+
import com.mapbox.geojson.Point
4+
import com.mapbox.maps.Projection
5+
import com.mapbox.maps.Vec3
6+
7+
/**
8+
* Creates data and vertices for a cube in ECEF coordinates
9+
* */
10+
class Cube(
11+
val location: Point,
12+
val sizeMeters: Float,
13+
val altitudeMeters: Float,
14+
colors: IntArray,
15+
mesh: CubeMesh,
16+
) {
17+
18+
private val _ecefVertices = ArrayList<Vec3>(mesh.vertices.size)
19+
val ecefVertices: List<Vec3> get() = _ecefVertices
20+
21+
// NxN grid, of quads.
22+
private val _colorVertices = ArrayList<Int>(mesh.verticesPerCubeSide * colors.size)
23+
val colorVertices: List<Int> get() = _colorVertices
24+
25+
init {
26+
// normalized to [0, 1]
27+
val positionMercator = Projection.latLngToMercatorXY(location)
28+
val metersToMercator = metersToMercator(location.latitude())
29+
for (vertex in mesh.vertices) {
30+
val x = positionMercator.x + vertex.x * sizeMeters * metersToMercator
31+
val y = positionMercator.y + vertex.y * sizeMeters * metersToMercator
32+
val altitude = vertex.z * sizeMeters + altitudeMeters
33+
34+
val vertexEcef = toEcef(
35+
latitude = latFromMercatorY(y),
36+
longitude = lngFromMercatorX(x),
37+
altitude,
38+
)
39+
40+
_ecefVertices.add(vertexEcef)
41+
}
42+
43+
// Create vertex buffer for cube side colors
44+
for (color in colors) {
45+
repeat(mesh.verticesPerCubeSide) {
46+
_colorVertices.add(color)
47+
}
48+
}
49+
}
50+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.mapbox.maps.testapp.examples.customlayer.globe
2+
3+
import com.mapbox.maps.Vec3
4+
import kotlin.math.max
5+
6+
/**
7+
* Create a static cube mesh to be rendered with a transformation matrix.
8+
* It defines vertices in OpenGL local space [-1.0; 1.0]
9+
* */
10+
class CubeMesh(
11+
tessellation: Int = 1,
12+
) {
13+
14+
val tessellation = max(tessellation, 1)
15+
val verticesPerCubeSide = tessellation * tessellation * 6
16+
val vertices = ArrayList<Vec3>(sides.size * this.tessellation * this.tessellation)
17+
18+
init {
19+
val step = 1.0 / this.tessellation
20+
for (side in sides) {
21+
// Create vertices for the side
22+
repeat(this.tessellation) { y ->
23+
repeat(this.tessellation) { x ->
24+
val topLeft =
25+
side.topLeft + side.right * step * x.toDouble() + side.down * step * y.toDouble()
26+
val v00 = topLeft
27+
val v10 = topLeft + side.right * step
28+
val v11 = topLeft + side.right * step + side.down * step
29+
val v01 = topLeft + side.down * step
30+
31+
vertices.add(v00)
32+
vertices.add(v10)
33+
vertices.add(v11)
34+
35+
vertices.add(v11)
36+
vertices.add(v01)
37+
vertices.add(v00)
38+
}
39+
}
40+
}
41+
}
42+
43+
companion object {
44+
45+
private val sides = arrayOf(
46+
Side(Vec3(-0.5, 0.5, 0.5), Vec3(1.0, 0.0, 0.0), Vec3(0.0, -1.0, 0.0)),
47+
Side(Vec3(0.5, 0.5, 0.5), Vec3(0.0, 0.0, -1.0), Vec3(0.0, -1.0, 0.0)),
48+
Side(Vec3(0.5, 0.5, -0.5), Vec3(-1.0, 0.0, 0.0), Vec3(0.0, -1.0, 0.0)),
49+
Side(Vec3(-0.5, 0.5, -0.5), Vec3(0.0, 0.0, 1.0), Vec3(0.0, -1.0, 0.0)),
50+
Side(Vec3(-0.5, 0.5, -0.5), Vec3(1.0, 0.0, 0.0), Vec3(0.0, 0.0, 1.0)),
51+
Side(Vec3(-0.5, -0.5, 0.5), Vec3(1.0, 0.0, 0.0), Vec3(0.0, 0.0, -1.0)),
52+
)
53+
54+
private data class Side(val topLeft: Vec3, val right: Vec3, val down: Vec3)
55+
}
56+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.mapbox.maps.testapp.examples.customlayer.globe
2+
3+
import android.os.Bundle
4+
import androidx.appcompat.app.AppCompatActivity
5+
import com.mapbox.geojson.Point
6+
import com.mapbox.maps.CameraOptions
7+
import com.mapbox.maps.Style
8+
import com.mapbox.maps.extension.style.layers.CustomLayer
9+
import com.mapbox.maps.extension.style.layers.addLayer
10+
import com.mapbox.maps.extension.style.layers.customLayer
11+
import com.mapbox.maps.extension.style.layers.properties.generated.ProjectionName
12+
import com.mapbox.maps.extension.style.projection.generated.projection
13+
import com.mapbox.maps.extension.style.style
14+
import com.mapbox.maps.testapp.R
15+
import com.mapbox.maps.testapp.databinding.ActivityGlobeCustomLayerBinding
16+
17+
/**
18+
* Test activity showcasing the Custom Layer API in globe projection.
19+
* */
20+
class GlobeCustomLayerActivity : AppCompatActivity() {
21+
22+
private var _binding: ActivityGlobeCustomLayerBinding? = null
23+
private val binding get() = _binding!!
24+
private val mapboxMap get() = binding.mapView.mapboxMap
25+
private var _host: GlobeCustomLayerHost? = null
26+
private val host: GlobeCustomLayerHost get() = _host!!
27+
28+
override fun onCreate(savedInstanceState: Bundle?) {
29+
super.onCreate(savedInstanceState)
30+
_binding = ActivityGlobeCustomLayerBinding.inflate(layoutInflater)
31+
setContentView(binding.root)
32+
val repaint = Runnable(mapboxMap::triggerRepaint)
33+
_host = GlobeCustomLayerHost {
34+
binding.mapView.post(repaint)
35+
}
36+
mapboxMap.loadStyle(
37+
style(Style.STANDARD) {
38+
+customLayer(
39+
layerId = CUSTOM_LAYER_ID,
40+
host = host
41+
)
42+
+projection(ProjectionName.GLOBE)
43+
}
44+
) {
45+
mapboxMap.setCamera(CAMERA)
46+
binding.fabSwapVisibility.setOnClickListener {
47+
swapCustomLayer()
48+
}
49+
}
50+
}
51+
52+
override fun onDestroy() {
53+
super.onDestroy()
54+
_binding = null
55+
_host = null
56+
}
57+
58+
private fun addCustomLayer(style: Style) {
59+
style.addLayer(
60+
CustomLayer(CUSTOM_LAYER_ID, host),
61+
)
62+
binding.fabSwapVisibility.setImageResource(R.drawable.ic_layers_clear)
63+
}
64+
65+
private fun swapCustomLayer() {
66+
val style = mapboxMap.style ?: return
67+
if (style.styleLayerExists(CUSTOM_LAYER_ID)) {
68+
style.removeStyleLayer(CUSTOM_LAYER_ID)
69+
binding.fabSwapVisibility.setImageResource(R.drawable.ic_layers)
70+
} else {
71+
addCustomLayer(style)
72+
}
73+
}
74+
75+
companion object {
76+
private const val CUSTOM_LAYER_ID = "customId"
77+
private val CAMERA =
78+
CameraOptions.Builder().center(Point.fromLngLat(20.0, 58.0)).pitch(0.0).zoom(1.0).build()
79+
}
80+
}

0 commit comments

Comments
 (0)