# FP View Maps

FP View Maps creates a shareable, approximate view from a point selected on a building façade in Google Maps 3D.

Generated views place the camera 5 metres from the selected façade point in the viewing direction. The intentionally simplified conversion uses 111,000 metres per latitude degree and 75,000 metres per longitude degree.

## Google Cloud setup

Create a Google Maps Platform browser key, restrict it to these website referrers, and enable billing:

```text
https://kotlyarov.com/*
https://www.kotlyarov.com/*
```

Enable these APIs:

- Maps JavaScript API (the app uses the beta channel for 3D camera positioning)
- Places API (New), for location search and labelled place details
- Geocoding API, for building-address fallback
- Elevation API, optionally used to position the editor after an address search

The façade click returns absolute altitude through Google's `LatLngAltitude` position. The backend subtracts terrain elevation from that value to estimate height above ground, while saving the original absolute altitude unchanged. Google remains the primary source for address and terrain elevation. With the demo key, the backend falls back to the nearest OpenStreetMap address and Open-Meteo's Copernicus DEM terrain elevation.

Building labels are derived from structured address components—street number, street and suburb—and never from a clicked place or business name.
When reverse geocoding returns only a path or administrative area, the fallback searches nearby address-tagged OpenStreetMap building footprints and uses the closest building. The selection dialog intentionally omits floor estimates and shows the view direction as the nearest of eight compass directions.

The temporary demo key is committed in `config.demo.json`. The server supplies it to the browser through `/calculator/fpviewmaps-config`. Replace this with server-side production-key storage before installing the permanent key.

FP View Maps now requires the application server and MySQL, so direct `file://` use is intentionally unsupported. Start the Docker Compose project and open:

```bash
docker compose up -d --build db web
```

```text
http://127.0.0.1:3000/fpviewmaps/
```

The app reuses the former calculator's MySQL 8.4 service, `calculator` database, `calc` user and persistent `db_data` volume. It creates a `Views` table automatically.

## Backend flow

- A façade selection sends its raw Google 3D point and flipped heading to the server. The server immediately returns the existing five-metre-offset camera position and begins a separate token-scoped validation/details request.
- The editor immediately flies to that camera position over one second while terrain and address requests run in parallel. Once the flight ends, fixed-position look controls and the wide Select Window panel replace normal map navigation and the How To guide.
- Address lookup, terrain elevation, height above ground, compass direction, input validation and the existing five-metre camera offset are calculated on the server.
- Cancelling a selection removes its marker, restores normal map controls and flies the camera back to its pre-selection position.
- Preview direction and eye level follow drag or keyboard movement and are saved exactly as shown. Closing the View Created dialog performs the same editor restoration as cancelling a selection.
- Creating a view stores the final camera parameters in `Views` and returns a random 12-character ID.
- A shared page accepts only `?viewid=...`, retrieves its camera data, and then starts Google Maps.

## Modes

- `/fpviewmaps/` opens the desktop editor.
- `/fpviewmaps/?viewid=xxxxxxxxxxxx` loads a stored fixed-position view on desktop or mobile.
- The same URL automatically removes nonessential controls when loaded inside an iframe.

## Known Google Maps limitations

- 3D Maps in the Maps JavaScript API is currently a beta feature. Google does not cover beta features with an SLA or deprecation policy, and beta releases can introduce backward-incompatible changes.
- Google 3D returns a geographic hit point through its primary-click `gmp-click` event. A normal click attempts to select a window; drag gestures retain Google's native map navigation behaviour.
- Google does not identify the clicked surface as a building or terrain. The backend treats points at least two metres above the local terrain elevation as façades and silently ignores lower or unresolved points.
- A façade hit supplies a photogrammetry coordinate, not authoritative building data. Address and ground height are estimates and can be improved only by selecting a better point or regenerating the view.
- The camera location is held fixed by the app's own drag/swipe look controls because Google’s native 3D gestures combine rotation with camera movement.
- 3D imagery coverage and detail vary by location.

## Google documentation used

- [3D camera positioning](https://developers.google.com/maps/documentation/javascript/3d/camera-position)
- [3D map reference and location-click events](https://developers.google.com/maps/documentation/javascript/reference/3d-map)
- [3D Place Autocomplete example](https://developers.google.com/maps/documentation/javascript/examples/3d/places-autocomplete)
- [Maps JavaScript API versions](https://developers.google.com/maps/documentation/javascript/versions)
- [Google Maps Platform pricing](https://developers.google.com/maps/billing-and-pricing/pricing)
- [Nominatim reverse geocoding](https://nominatim.org/release-docs/latest/api/Reverse/)
- [Open-Meteo Elevation API](https://open-meteo.com/en/docs/elevation-api)

## Build

```bash
npm run build
```
