Skip to content

feat(projection): introduce rudimentary Projection3D utility and 2D overlay samples - #72

Open
dkhawk wants to merge 4 commits into
chore/spotless-formatting-compose-and-demofrom
feat/projection3d-and-surface-click
Open

dkhawk wants to merge 4 commits into
chore/spotless-formatting-compose-and-demofrom
feat/projection3d-and-surface-click

Conversation

@dkhawk

@dkhawk dkhawk commented Sep 22, 2026 •

Copy link
Copy Markdown
Collaborator

🥞 Stacked PR (2 of 2)

Resolves #21


Summary

Introduces a rudimentary 3D perspective projection utility (Projection3D) and interactive sample activities across Jetpack Compose, Kotlin Views, and Java Views demonstrating how to project 3D spatial coordinates (LatLngAltitude) into 2D viewport screen pixels (PointF / Offset / Point) to anchor custom 2D UI overlays over 3D world geometry.

Also notes that full 3D surface and building click detection requested in #21 is already natively supported in the SDK via GoogleMap3D.setMap3DClickListener.

All Android Lint review feedback (hardcoded preview strings, text size >= 11sp, and localized string resources) has been addressed, and complete 3-way language parity is maintained.


Key Changes

1. Mathematical Projection Engine (Projection3D.kt)

Added in both Maps3DSamples/ApiDemos/common and maps3d-compose:

  • Local East-North-Up (ENU) Frame: Converts camera focal center and target LatLngAltitude into local tangent coordinates.
  • Camera Vantage & View Matrix: Resolves camera eye coordinates and orthonormal basis vectors $(\mathbf{r}, \mathbf{u}, \mathbf{f})$ from spherical parameters (range, heading, tilt, roll).
  • Perspective Frustum & Projection: Transforms world space -> camera space -> Normalized Device Coordinates (NDC $[-1, 1]$) based on the vertical Field of View (default $45^\circ$) and viewport aspect ratio.
  • Java Interoperability: @JvmOverloads constructor for seamless Java invocation.
  • Core Methods:
    • toScreenCoordinate(point): Returns a ScreenCoordinate with (x, y) pixels, line-of-sight depth (meters), and view frustum visibility state (isVisible).
    • toScreenLocation(point) / toScreenLocationF(point) / toScreenOffset(point): Returns integer Point, floating PointF, or Compose Offset (or null if behind camera plane).
    • fromScreenLocation(screenX, screenY, targetAltitude): Raycasts from the camera eye through screen pixel $(x, y)$ to intersect an idealized reference ground plane at targetAltitude.

2. Math Unit Tests (Projection3DTest.kt)

Added in Maps3DSamples/ApiDemos/common/src/test:

  • cameraCenter_projectsToExactScreenCenter: Validates camera center projects exactly to viewport center (width / 2, height / 2).
  • pointBehindCamera_isMarkedNotVisible: Verifies points behind the camera eye are culled (isVisible = false, negative depth).
  • cardinalDirections_projectToCorrectScreenQuadrants: Tests cardinal direction offsets project to expected quadrants.
  • fromScreenLocation_centerPixel_recoversCameraCenter: Verifies inverse unprojection recovery.
  • roundTrip_projectAndUnproject_matchesOriginalGroundCoordinates: Verifies round-trip coordinate accuracy.

3. Jetpack Compose Sample (Projection3DActivity.kt)

Added to maps3d-compose-demo:

  • Observes live camera movements via onCameraChanged.
  • Uses BoxWithConstraints to feed dynamic maxWidth and maxHeight into Projection3D.
  • Anchors an animated 2D Glassmorphic HUD overlay card and target crosshair reticle above 3D landmarks (Transamerica Pyramid, Coit Tower, Ferry Building).
  • Smoothly tracks the landmark in real time as the user pans, tilts, zooms, or rotates the 3D map.
  • Automatically hides the overlay when the landmark is culled or behind the camera.
  • Supports surface interaction via onMapClick to re-project tapped coordinates.

4. Kotlin Views Sample (Projection3DActivity.kt)

Added to Maps3DSamples/ApiDemos/kotlin-app:

  • Extends SampleBaseActivity and inflates control_panel_projection_3d.xml.
  • Pins a native Android 2D CardView over 3D world geometry by dynamically updating translationX and translationY on camera change ticks.
  • Features landmark preset selection with camera transitions via flyCameraTo.
  • Displays a bottom telemetry card with real-time screen coordinate readouts, depth, and frustum culling status.

5. Java Views Sample (Projection3DActivity.java)

Added to Maps3DSamples/ApiDemos/java-app:

  • 100% 3-way language parity implementation extending SampleBaseActivity.
  • Uses googleMap3D.setCameraChangedListener and setMap3DClickListener.
  • Anchors 2D overlay and updates telemetry and frustum culling readouts in real time.
  • Registered in MainActivity.java and manifest; updated MainActivityTest to 23 samples.

Verification

  • Unit Tests: ./gradlew :Maps3DSamples:ApiDemos:common:testDebugUnitTest --tests "com.example.maps3d.common.Projection3DTest" -> 5/5 passed
  • Spotless: ./gradlew :maps3d-compose:spotlessCheck :maps3d-compose-demo:spotlessCheck -> BUILD SUCCESSFUL
  • Lint: ./gradlew :Maps3DSamples:ApiDemos:java-app:lintDebug :Maps3DSamples:ApiDemos:kotlin-app:lintDebug -> BUILD SUCCESSFUL (0 errors)
  • Compilation: ./gradlew :Maps3DSamples:ApiDemos:java-app:compileDebugJavaWithJavac :Maps3DSamples:ApiDemos:kotlin-app:compileDebugKotlin :Maps3DSamples:ApiDemos:common:compileDebugKotlin -> BUILD SUCCESSFUL

@dkhawk
dkhawk requested a review from LoyalAbbas September 22, 2026 17:11
@dkhawk
dkhawk marked this pull request as ready for review September 22, 2026 17:11
@dkhawk
dkhawk added this pull request to stack #73 September 22, 2026 17:12
@dkhawk
dkhawk force-pushed the feat/projection3d-and-surface-click branch from 1404b45 to df139cb Compare September 23, 2026 18:38

@LoyalAbbas LoyalAbbas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

# 🧩 Feature Request: Add Projection3D API (toScreenLocation(), fromScreenLocation()) and full map click listener support in Maps 3D SDK

2 participants