# SurveyView — tools for AI agents / herramientas para agentes

SurveyView is a read-only 3D viewer for topographic survey deliveries (terrain and design surfaces, orthophoto,
LiDAR point cloud, alignments, cuts). A project is opened from a `.svz` file:

    https://visor.jacdot.com/?svz=<URL of the .svz>

Coordinates are always **absolute in the project's CRS** (`E`, `N`, `Z` in metres; see `info().epsg`).
PK = chainage along an alignment, in metres.

## 1. Deep links (no code needed)

Add to the viewer URL, after `?svz=…`:

| Parameter | Effect |
|---|---|
| `&eje=Eje01&pk=300` | opens the cross-section of alignment `Eje01` at PK 300 (`&ancho=40`: half-width, default 30 m) |
| `&eje=Eje01` | opens the longitudinal profile of `Eje01` |
| `&corte=A` | opens the existing cut A–A' |
| `&ir=404000,4673200` | centres the view on E, N |
| `&vista=planta` | plan view (`3d` for perspective) |

## 2. JavaScript API (`window.surveyview`)

For agents that can run JavaScript in the page. Every tool takes one object and returns JSON:

```js
await surveyview.listo();                         // wait until the project is loaded
await surveyview.info();                          // CRS, surfaces, alignments (PK range), cuts, layers, extent
await surveyview.seccion({eje:'Eje01', pk:300});  // cross-section: z at the axis per surface + lines
await surveyview.llamar('cota', {E:404000, N:4673200});
surveyview.herramientas                           // the list below, with JSON Schemas
```

## 3. WebMCP

If the browser exposes `navigator.modelContext` (WebMCP), the same tools are registered there, so a browser
assistant can call them directly.

## Tools

| Tool | Input | Returns |
|---|---|---|
| `info` | — | project, `epsg`, `superficies` [{id, nombre, rol, visible}], `ejes` [{nombre, pkInicio, pkFin, longitud}], `cortes`, `capas`, `extension` |
| `cota` | `E`, `N`, `todas?` | elevation of each (visible) surface at that point |
| `seccion` | `pk`, `eje?`, `ancho?`, `mostrar?` | opens the cross-section; per surface `zEje` and `lineas` (offset from axis, z; left negative) |
| `perfil` | `eje?`, `mostrar?` | opens the profile; per surface `lineas` (PK, z) |
| `corte` | `puntos` [[E,N],…] \| `eje?`, `pk` \| `pks` [..], `ancho?` (half-width, 30 m); `mostrar?` | creates a cut along a polyline (min. 0.2 m), or perpendicular to an alignment at one or more PKs (left to right looking forward); per surface `lineas` (distance, z) |
| `abrir_corte` | `id` | opens an existing cut (A, B…) |
| `volumen` | `superficie`, `base?`, `area?` (a drawn closed measurement) \| `poligono?` [[E,N],…] | cut/fill volume: `corte_m3`, `relleno_m3`, `neto_m3`, areas. Whole surface: exact TIN-to-TIN; inside an area or polygon: fine point grid (`metodo`), with `areaSinDatos_m2` and mean depths |
| `diferencias` | `superficie`, `referencia?` (default: nearest earlier date or base terrain), `lod?` (0.05 m), `tolerancia?`, `area?` \| `poligono?`, `mostrar?` | difference map surface − reference (another date or the design): shows it (red below, blue above, grey within the level of detection) and returns mean, std, percentiles, area and volume above/below the LoD, `fueraTolerancia_pct` and a histogram |
| `borde_libre` | `cresta` (trace, distance or alignment name, or [[E,N],…]), `plano?` (drawn horizontal plane; the only one if omitted) \| `cota?`, `superficie?` (beach surface, default base terrain), `superficieCresta?` (default: highest visible), `requerido?` (required freeboard, m), `anotar?` | tailings dam freeboard along the crest (crest z − water level): min with its point, mean, max; wetted pond `area_m2` (water above the beach surface, inside the plane polygon); beach width min/mean (crest to shoreline) and a profile along the crest. LiDAR does not see the pond bottom: no water volume |
| `flujos` | `accion?` listar/ejecutar, `nombre?` | node flows saved by the user in the Monitoring workspace (chained queries and analyses): list them or run one by name; returns each node's result |
| `tiempo` | `principal?` (on screen «Hasta»/To), `comparacion?` (on screen «Desde»/From) (AAAA-MM-DD, any day, not only days with surfaces; empty to clear), `aFecha?`, `diferencia?`, `espacio?` consulta/monitoreo, `paso?` dia/semana/mes (empty = auto), `color?` propio/gris/grupo/nivel (mean elevation)/zmax/zmin/espesor (mean thickness over what was below when pasted)/volumen (declared, atributos.volumen)/difvol (measured − declared, %)/tiempo (thematic colour of the overlay surfaces), `activo?` (highlight the main date's day), `intervalo?` (highlight comparison–main) | Monitoring workspace and timeline of epochs (surface dates): sets the main and comparison dates, «state at date» (hides what is later than the main date) or paints the difference between both dates; returns the epochs with their surfaces |
| `grupos` | `accion?` listar/crear/editar/eliminar/aislar/mostrar_todo, `grupo?`, `nombre?`, `tipo?` seguimiento/material/sector, `superficies?` [..], `base?`, `diseno?` (references: the group's base and design, never members, untouched by themes, used in calculations; "" removes), `contexto?` gris/apagado | named groups of surfaces (a group may carry a `regla` — name contains / type / date range — and then updates itself) to follow (a time series of progress patches, a material, a sector); isolating one leaves the rest as grey context (or off) without changing any surface setting |
| `avance` | `superficies?` [..] (default: all dated surfaces except the base) \| `grupo?` (tracking group), `base?` (starting surface), `area?` \| `poligono?` | progress by date (e.g. weekly fill of a tailings dam): each dated surface against everything earlier at each point (latest earlier surface with data, else the base): `filas` with fill, cut, net and cumulative per date, and totals |
| `corte_relleno` | `superficie`, `base?`, `area?` \| `poligono?`, `seccion?` relleno/corte, `margen?` (20 m), `mostrar?` | where the cut and the fill are: per kind `volumen_m3`, `area_m2`, `espesorMax_m`, `puntoMax` {E, N, zona}, `centro`; with `seccion` it also draws a representative cut through the thickest point, across the long axis of that region |
| `capa` | `nombre`, `visible` | shows or hides a surface or layer (point cloud, breaklines…) |
| `ir_a` | `E`, `N` \| `zona` \| `corte` \| `medicion`; `vista?` | centres the view on a point, or frames a zone, cut or measurement |
| `zonas` | `clase?`, `texto?`, `areaMin?`, `areaMax?`, `zMin?`, `zMax?`, `E?`, `N?`, `radio?`, `max?` | terrain zones (2.5D semantics): `id`, `nombre`, `clase` (plataforma, rampa, ladera, talud, deposito or a user class), `origen` (calculada / editada / dibujada), `area_m2`, `z` {min, media, max}, `pendiente` (°), `punto` (inside the zone), `bbox`, `descripcion`, `etiquetas`, `vecinas` |
| `zona_en` | `E`, `N` | the zone at a point and the placed objects on it |
| `objetos` | `texto?` | placed objects (trucks, equipment…: OBJ models identified by `nombre`, `descripcion`, `etiquetas`) with `E`, `N`, `z`, `giro`, `escala`, `tamano`, `zona` |
| `resaltar` | `zona?` \| `objeto?` | highlights a zone or object and flies there |
| `editar_zona` | `zona`, `nombre?`, `clase?`, `descripcion?`, `etiquetas?`, `oculta?`, `confianza?` | proposes a name/class/description for a zone; it shows as an *AI proposal* (with its confidence) until the user accepts or corrects it |
| `recorte` | `zona?` \| `bbox?` [E0,N0,E1,N1] \| `E`,`N`,`radio?`; `tipo?` orto/relieve/pendiente; `px?` | plan image, north up, of that area (`imagen`), with the zone outlined in magenta; `m_por_px`, `bbox`, slope `leyenda`. Look before you label |
| `crear_zona` | `nombre`, `clase`, `poligono` [[E,N],…], `descripcion?`, `etiquetas?`, `confianza?` | marks an area of interest (canal, acceso, acopio…) as an AI proposal; if the package has no zones layer, it creates a blank one (user-painted zones) |
| `camino_agua` | `E`, `N` | where water flows from a point: `longitud_m`, `desnivel_m`, `fin` (borde / deprimida / limite), end point and zone |
| `volumen_zona` | `zona`, `referencia?` borde/cota, `z?` | approx. volume of a zone above/below a plane fitted to its border (stockpiles, pits) or a horizontal plane at `z` (cut/fill of a pad) |
| `fotos` | `E?`, `N?`, `radio?` | 360 photos and panoramas, by distance |
| `ver_foto` | `nombre`, `rumbo?`, `cerrar?` | opens a 360 photo looking at an azimuth and returns the view (`imagen`) |
| `anotar` | `E`, `N`, `texto`, `color?` | leaves a visible label for the user |
| `red` | `tipo?`, `zona?`, `E?`,`N?`,`radio?`, `longitudMin?`, `max?`, `puntos?` | linear network: `canal` lines (where water concentrates, downstream, with `areaDrenada_m2`) and `franja` lines (axes of narrow elongated flat/ramp strips: candidate access roads, ramps or berms), with length, grade (%), width and the zones they cross. `zona` returns the lines that reach it |
| `editar_linea` | `linea`, `nombre?`, `tipo?` (acceso, rampa, berma, cuneta…), `descripcion?`, `confianza?`, `restablecer?` | names/classifies a line of the network as an AI proposal, or resets it |
| `ajustar_a_via` | `puntos` [[E,N],…] (rough trace), `busqueda?` (15 m), `anchoMax?` (25 m), `umbral?` (10°), `crear?` {nombre, clase, descripcion, confianza} | snaps a rough polyline to the centre of the nearest flat strip (analysis slope), tracking it along the road so it does not jump to a parallel berm or channel; returns the corrected axis, `ancho_m`, `pendiente_pct`, `confianza`, `tramosSinVia_m`, and with `crear` the zone shaped like the strip |
| `mediciones` | `tipo?`, `zona?`, `texto?` | the user's measurements (points, distances, areas, traces, pads, planes…): `id`, `tipo`, `nombre`, coordinates, `area_m2`/`longitud_m`, the `zonas` they fall in, and `porZona` (count by zone and type) |
| `recorrido` | `eje?` \| `medicion?` (trace or distance), `perfil?` peaton/vehiculo/camion/dron \| `altura?`, `vel?` (m/s) \| `kmh?`, `pk?`; `accion?` iniciar/pausa/seguir/detener/estado | drives along an alignment or trace at ground-following height; returns the route, length, current PK and `duracion_s` |
| `captura` | — | JPEG of the current view (`imagen`, data URL) |

The analysis tools (`diferencias`, `borde_libre`, `corte_relleno`, `volumen`, `avance`) also leave their result in the viewer's **Analysis** panel (marked *agente*), with parameters, date and method, so the user can review, export (CSV) or delete it.

Lines are reduced to at most ~150 points; `null` marks a gap (no surface there). Names are matched exactly or
case-insensitively; unknown names return an error listing the valid ones.

## Zones (semantic layer)

If the package has a `semantica` layer, the terrain is split into zones by slope and shape (rules only, no ML):
`plataforma` (benches, platforms, pit floor), `rampa` (narrow, elongated gentle slopes: ramps, roads), `ladera`,
`talud` (bench faces, cuts) and `deposito` (closed depressions where water ponds). It is a starting point: users rename,
reclassify, merge or draw zones, and those edits win (`origen`). Zone areas are plan areas. Example questions:
«platforms over 1 000 m² above 4 300 m» → `zonas({clase:'plataforma', areaMin:1000, zMin:4300})`; «what is at this
point and which equipment is there» → `zona_en`; «show the crusher pad» → `zonas({texto:'chancado'})` then `resaltar`.

### Labelling zones with a vision model (recommended loop)

1. `zonas({max:50})` (or filtered) to get candidates; skip tiny ones.
2. For each: `recorte({zona, tipo:'orto'})` and, if unsure, `recorte({zona, tipo:'pendiente'})`; read its numbers
   (area, slope, z, `vecinas`).
3. `editar_zona({zona, nombre, clase, descripcion, confianza})` — be honest with `confianza`; the user reviews.
4. Linear features: `red` lists candidate channels and strips; look at them with `recorte` and name them with
   `editar_linea` (e.g. a `franja` that links two platforms at 8–10 % is likely an access road; one along a bench, a berm).
   Main roads are not always detected by geometry: trace them roughly from `recorte` images (5–10 m is fine) and pass the trace to `ajustar_a_via` with `crear` — it snaps it to the real road and measures its width. Follow water with `camino_agua`. Use `anotar` to point at anything the user should look at.

Your edits never overwrite what a person decided: a human edit removes the AI mark, and the user can *Accept* or
*Reset* each proposal.

## Notes

- The viewer never modifies the `.svz`. Tools only change what is shown; `corte` adds a cut to the viewer's
  local session.
- The official deliverables (TIF, LAS, meshes) are delivered separately: the web package is a consultation copy.

---

**Resumen en español.** Para consultar SurveyView sin clics: enlaces directos (`&eje=…&pk=…`), la API
`window.surveyview` (`info`, `cota`, `seccion`, `perfil`, `corte`, `abrir_corte`, `volumen`, `corte_relleno`, `diferencias`, `borde_libre`, `avance`, `grupos`, `tiempo`, `flujos`, `capa`, `ir_a`,
`mediciones`, `recorrido`, `zonas`, `zona_en`, `objetos`, `resaltar`, `editar_zona`, `recorte`, `crear_zona`, `camino_agua`, `volumen_zona`, `fotos`, `ver_foto`, `anotar`, `red`, `editar_linea`, `ajustar_a_via`, `captura`) o WebMCP. Coordenadas absolutas del sistema del proyecto; PK en metros.
