# Geometry

Geometric and spatial data types for location-based applications.

Geometry classes provide support for spatial and geographic data using GeoJSON-compatible structures. These types are essential for location-based applications and geospatial queries.

**Import:**
```ts
import { 
    GeometryPoint,
    GeometryLine,
    GeometryPolygon,
    GeometryMultiPoint,
    GeometryMultiLine,
    GeometryMultiPolygon,
    GeometryCollection
} from 'surrealdb';
```

**Source:** [value/geometry.ts](https://github.com/surrealdb/surrealdb.js/blob/main/packages/sdk/src/value/geometry.ts)

## Geometry types

### `GeometryPoint` {#geometrypoint}

A single point in 2D space (longitude, latitude).

#### Constructor

```ts
new GeometryPoint([longitude, latitude])
new GeometryPoint(point) // Clone existing
```

#### Properties

##### `point` {#geometrypoint-point}

The underlying point data as a `[longitude, latitude]` tuple.

**Type:** `[number, number]`

##### `coordinates` {#geometrypoint-coordinates}

GeoJSON-compatible coordinates for this point. Equivalent to `point`.

**Type:** `[number, number]`

#### Example

```ts
// Create a point (San Francisco)
const point = new GeometryPoint([-122.4194, 37.7749]);

console.log(point.point);       // [-122.4194, 37.7749]
console.log(point.coordinates); // [-122.4194, 37.7749]

// Store location
await db.create(new Table('locations')).content({
    name: 'Office',
    position: point
});
```

---

### `GeometryLine` {#geometryline}

A line defined by two or more points.

#### Constructor

```ts
new GeometryLine([point1, point2, ...points])
new GeometryLine(line) // Clone existing
```

#### Properties

##### `line` {#geometryline-line}

The underlying array of `GeometryPoint` objects that make up this line.

**Type:** `GeometryPoint[]`

##### `coordinates` {#geometryline-coordinates}

GeoJSON-compatible coordinates for this line.

**Type:** `[number, number][]`

#### Methods

##### `.close()` {#geometryline-close}

Closes the line by appending the first point to the end, if it is not already closed. Useful when constructing polygon boundaries.

```ts
const line = new GeometryLine([
    new GeometryPoint([0, 0]),
    new GeometryPoint([10, 0]),
    new GeometryPoint([10, 10])
]);

line.close();
// Line now ends with GeometryPoint([0, 0])
```

#### Example

```ts
// Create a line (path between two cities)
const line = new GeometryLine([
    new GeometryPoint([-122.4194, 37.7749]), // San Francisco
    new GeometryPoint([-118.2437, 34.0522])  // Los Angeles
]);

console.log(line.line);        // [GeometryPoint, GeometryPoint]
console.log(line.coordinates); // [[-122.4194, 37.7749], [-118.2437, 34.0522]]

// Multi-segment line
const route = new GeometryLine([
    new GeometryPoint([0, 0]),
    new GeometryPoint([1, 1]),
    new GeometryPoint([2, 1]),
    new GeometryPoint([3, 2])
]);
```

---

### `GeometryPolygon` {#geometrypolygon}

A polygon defined by one or more lines (outer boundary and optional holes).

#### Constructor

```ts
new GeometryPolygon([outerBoundary, ...holes])
new GeometryPolygon(polygon) // Clone existing
```

#### Properties

##### `polygon` {#geometrypolygon-polygon}

The underlying array of `GeometryLine` objects (outer boundary and optional holes).

**Type:** `GeometryLine[]`

##### `coordinates` {#geometrypolygon-coordinates}

GeoJSON-compatible coordinates for this polygon.

**Type:** `[number, number][][]`

#### Example

```ts
// Create a triangle
const triangle = new GeometryPolygon([
    new GeometryLine([
        new GeometryPoint([0, 0]),
        new GeometryPoint([4, 0]),
        new GeometryPoint([2, 3]),
        new GeometryPoint([0, 0]) // Close the polygon
    ])
]);

console.log(triangle.polygon); // [GeometryLine]

// Polygon with hole (donut shape)
const donut = new GeometryPolygon([
    // Outer boundary
    new GeometryLine([
        new GeometryPoint([0, 0]),
        new GeometryPoint([10, 0]),
        new GeometryPoint([10, 10]),
        new GeometryPoint([0, 10]),
        new GeometryPoint([0, 0])
    ]),
    // Inner hole
    new GeometryLine([
        new GeometryPoint([2, 2]),
        new GeometryPoint([8, 2]),
        new GeometryPoint([8, 8]),
        new GeometryPoint([2, 8]),
        new GeometryPoint([2, 2])
    ])
]);
```

---

### `GeometryMultiPoint` {#geometrymultipoint}

A collection of points.

#### Constructor

```ts
new GeometryMultiPoint([point1, point2, ...points])
new GeometryMultiPoint(multiPoint) // Clone existing
```

#### Properties

##### `points` {#geometrymultipoint-points}

The underlying array of `GeometryPoint` objects.

**Type:** `GeometryPoint[]`

##### `coordinates` {#geometrymultipoint-coordinates}

GeoJSON-compatible coordinates for this multi-point.

**Type:** `[number, number][]`

#### Example

```ts
// Multiple store locations
const stores = new GeometryMultiPoint([
    new GeometryPoint([-122.4194, 37.7749]), // SF
    new GeometryPoint([-118.2437, 34.0522]), // LA
    new GeometryPoint([-87.6298, 41.8781])   // Chicago
]);

console.log(stores.points); // [GeometryPoint, GeometryPoint, GeometryPoint]
```

---

### `GeometryMultiLine` {#geometrymultiline}

A collection of lines.

#### Constructor

```ts
new GeometryMultiLine([line1, line2, ...lines])
new GeometryMultiLine(multiLine) // Clone existing
```

#### Properties

##### `lines` {#geometrymultiline-lines}

The underlying array of `GeometryLine` objects.

**Type:** `GeometryLine[]`

##### `coordinates` {#geometrymultiline-coordinates}

GeoJSON-compatible coordinates for this multi-line.

**Type:** `[number, number][][]`

#### Example

```ts
// Multiple delivery routes
const routes = new GeometryMultiLine([
    new GeometryLine([
        new GeometryPoint([0, 0]),
        new GeometryPoint([1, 1])
    ]),
    new GeometryLine([
        new GeometryPoint([2, 2]),
        new GeometryPoint([3, 3])
    ])
]);

console.log(routes.lines); // [GeometryLine, GeometryLine]
```

---

### `GeometryMultiPolygon` {#geometrymultipolygon}

A collection of polygons.

#### Constructor

```ts
new GeometryMultiPolygon([polygon1, polygon2, ...polygons])
new GeometryMultiPolygon(multiPolygon) // Clone existing
```

#### Properties

##### `polygons` {#geometrymultipolygon-polygons}

The underlying array of `GeometryPolygon` objects.

**Type:** `GeometryPolygon[]`

##### `coordinates` {#geometrymultipolygon-coordinates}

GeoJSON-compatible coordinates for this multi-polygon.

**Type:** `[number, number][][][]`

#### Example

```ts
// Multiple service areas
const areas = new GeometryMultiPolygon([
    new GeometryPolygon([/* first area */]),
    new GeometryPolygon([/* second area */])
]);

console.log(areas.polygons); // [GeometryPolygon, GeometryPolygon]
```

---

### `GeometryCollection` {#geometrycollection}

A heterogeneous collection of geometry types.

#### Constructor

```ts
new GeometryCollection([geometry1, geometry2, ...geometries])
new GeometryCollection(collection) // Clone existing
```

#### Properties

##### `collection` {#geometrycollection-collection}

The underlying array of geometry objects in this collection.

**Type:** `Geometry[]`

##### `geometries` {#geometrycollection-geometries}

Getter that returns the array of geometry objects. Equivalent to `collection`.

**Type:** `Geometry[]`

##### `coordinates` {#geometrycollection-coordinates}

GeoJSON-compatible coordinates for this collection.

**Type:** `unknown[]`

#### Example

```ts
// Mixed geometry types
const collection = new GeometryCollection([
    new GeometryPoint([0, 0]),
    new GeometryLine([
        new GeometryPoint([1, 1]),
        new GeometryPoint([2, 2])
    ]),
    new GeometryPolygon([/* polygon data */])
]);

console.log(collection.collection);  // [GeometryPoint, GeometryLine, GeometryPolygon]
console.log(collection.geometries);  // [GeometryPoint, GeometryLine, GeometryPolygon]
```

## Common methods

All geometry types share these methods:

### `.is(type)` {#is}

Type guard that checks if a geometry matches a specific type. Each geometry subclass implements this method.

```ts
is(type: "Point"): this is GeometryPoint
is(type: "LineString"): this is GeometryLine
is(type: "Polygon"): this is GeometryPolygon
is(type: "MultiPoint"): this is GeometryMultiPoint
is(type: "MultiLineString"): this is GeometryMultiLine
is(type: "MultiPolygon"): this is GeometryMultiPolygon
is(type: "GeometryCollection"): this is GeometryCollection
```

```ts
function describeGeometry(geo: Geometry) {
    if (geo.is("Point")) {
        console.log('Point at', geo.point);
    } else if (geo.is("Polygon")) {
        console.log('Polygon with', geo.polygon.length, 'rings');
    }
}
```

### `.toJSON()` {#tojson}

Convert to GeoJSON format.

```ts
const point = new GeometryPoint([-122.4194, 37.7749]);
console.log(point.toJSON());
// { type: "Point", coordinates: [-122.4194, 37.7749] }
```

### `.toString()` {#tostring}

Convert to JSON string.

```ts
const point = new GeometryPoint([-122.4194, 37.7749]);
console.log(point.toString());
// '{"type":"Point","coordinates":[-122.4194,37.7749]}'
```

### `.clone()` {#clone}

Create a deep copy.

```ts
const original = new GeometryPoint([0, 0]);
const copy = original.clone();
```

### `.equals(other)` {#equals}

Check if two geometries are equal.

```ts
const a = new GeometryPoint([0, 0]);
const b = new GeometryPoint([0, 0]);
console.log(a.equals(b)); // true
```

## Complete examples

### Store locations

```ts
import { Surreal, GeometryPoint, Table } from 'surrealdb';

const db = new Surreal();
await db.connect('ws://localhost:8000');

// Store locations with coordinates
const locations = [
    {
        name: 'Main Office',
        address: '123 Market St, San Francisco, CA',
        position: new GeometryPoint([-122.4194, 37.7749])
    },
    {
        name: 'LA Branch',
        address: '456 Sunset Blvd, Los Angeles, CA',
        position: new GeometryPoint([-118.2437, 34.0522])
    }
];

for (const location of locations) {
    await db.create(new Table('locations')).content(location);
}
```

### Delivery routes

```ts
// Define delivery route
const route = new GeometryLine([
    new GeometryPoint([-122.4194, 37.7749]), // Start: SF
    new GeometryPoint([-122.2711, 37.8044]), // Stop 1: Oakland
    new GeometryPoint([-122.0838, 37.3861]), // Stop 2: Mountain View
    new GeometryPoint([-121.8863, 37.3382])  // End: San Jose
]);

await db.create(new Table('routes')).content({
    driver: new RecordId('drivers', 'john'),
    route: route,
    estimated_time: new Duration('2h30m'),
    created_at: DateTime.now()
});
```

### Service areas

```ts
// Define service coverage area (polygon)
const serviceArea = new GeometryPolygon([
    new GeometryLine([
        new GeometryPoint([-122.5, 37.7]),
        new GeometryPoint([-122.3, 37.7]),
        new GeometryPoint([-122.3, 37.8]),
        new GeometryPoint([-122.5, 37.8]),
        new GeometryPoint([-122.5, 37.7]) // Close the polygon
    ])
]);

await db.create(new Table('service_areas')).content({
    name: 'SF Downtown',
    area: serviceArea,
    active: true
});
```

### Geospatial queries

```ts
// Find locations near a point
const centerPoint = new GeometryPoint([-122.4194, 37.7749]);

const nearbyLocations = await db.query(`
    SELECT * FROM locations 
    WHERE geo::distance(position, $center) < 5000
    ORDER BY geo::distance(position, $center)
`, {
    center: centerPoint
}).collect();

console.log('Nearby locations:', nearbyLocations);
```

### Polygon containment

```ts
// Check if a point is within a polygon
const region = new GeometryPolygon([
    new GeometryLine([
        new GeometryPoint([0, 0]),
        new GeometryPoint([10, 0]),
        new GeometryPoint([10, 10]),
        new GeometryPoint([0, 10]),
        new GeometryPoint([0, 0])
    ])
]);

const testPoint = new GeometryPoint([5, 5]);

const result = await db.query(`
    RETURN $region CONTAINS $point
`, {
    region,
    point: testPoint
}).collect();

console.log('Point is inside:', result[0]);
```

### Multiple locations (MultiPoint)

```ts
// Store multiple branch locations
const branches = new GeometryMultiPoint([
    new GeometryPoint([-122.4194, 37.7749]), // SF
    new GeometryPoint([-118.2437, 34.0522]), // LA
    new GeometryPoint([-87.6298, 41.8781]),  // Chicago
    new GeometryPoint([-74.0060, 40.7128])   // NYC
]);

await db.create(new Table('companies')).content({
    name: 'Tech Corp',
    headquarters: new GeometryPoint([-122.4194, 37.7749]),
    all_branches: branches,
    founded: new DateTime('2020-01-01')
});
```

### Distance calculations

```ts
// Calculate distance between two points
const pointA = new GeometryPoint([-122.4194, 37.7749]); // SF
const pointB = new GeometryPoint([-118.2437, 34.0522]); // LA

const distance = await db.query(`
    RETURN geo::distance($a, $b)
`, {
    a: pointA,
    b: pointB
}).collect();

console.log('Distance in meters:', distance[0]);
```

### GeoJSON export

```ts
// Export as GeoJSON for mapping libraries
const point = new GeometryPoint([-122.4194, 37.7749]);
const geoJson = point.toJSON();

// Use with mapping libraries (Leaflet, Mapbox, etc.)
/*
{
    type: "Point",
    coordinates: [-122.4194, 37.7749]
}
*/
```

### Complex region with holes

```ts
// Define a park with a lake (hole)
const park = new GeometryPolygon([
    // Outer boundary (park border)
    new GeometryLine([
        new GeometryPoint([0, 0]),
        new GeometryPoint([100, 0]),
        new GeometryPoint([100, 100]),
        new GeometryPoint([0, 100]),
        new GeometryPoint([0, 0])
    ]),
    // Inner hole (lake)
    new GeometryLine([
        new GeometryPoint([40, 40]),
        new GeometryPoint([60, 40]),
        new GeometryPoint([60, 60]),
        new GeometryPoint([40, 60]),
        new GeometryPoint([40, 40])
    ])
]);

await db.create(new Table('parks')).content({
    name: 'Central Park',
    boundary: park,
    has_lake: true
});
```

## GeoJSON compatibility

All geometry types are compatible with GeoJSON format:

```ts
const point = new GeometryPoint([-122.4194, 37.7749]);
const geoJson = point.toJSON();

// GeoJSON structure
console.log(geoJson);
/*
{
    type: "Point",
    coordinates: [-122.4194, 37.7749]
}
*/

// Use with any GeoJSON-compatible library
```

## Best practices

### 1. Use correct coordinate order

```ts
// Good: [longitude, latitude] (GeoJSON standard)
const point = new GeometryPoint([-122.4194, 37.7749]);

// Avoid: [latitude, longitude] (Google Maps format)
const wrong = new GeometryPoint([37.7749, -122.4194]);
```

### 2. Close polygons properly

```ts
// Good: First and last points are the same
const polygon = new GeometryPolygon([
    new GeometryLine([
        new GeometryPoint([0, 0]),
        new GeometryPoint([10, 0]),
        new GeometryPoint([10, 10]),
        new GeometryPoint([0, 10]),
        new GeometryPoint([0, 0]) // Closes the polygon
    ])
]);

// The library automatically closes polygons if needed
```

### 3. Use appropriate Geometry type

```ts
// Good: Single location
const office = new GeometryPoint([-122.4194, 37.7749]);

// Good: Multiple locations
const branches = new GeometryMultiPoint([point1, point2, point3]);

// Avoid: Using MultiPoint for single location
const wrong = new GeometryMultiPoint([point1]);
```

### 4. Validate coordinates

```ts
// Good: Valid coordinates
const valid = new GeometryPoint([-122.4194, 37.7749]);

// Avoid: Invalid coordinates (out of range)
// Longitude: -180 to 180, Latitude: -90 to 90
const invalid = new GeometryPoint([200, 100]); // Will create but may cause issues
```

## Use cases

- **Location-based Services** - Store and query business locations
- **Delivery Systems** - Define delivery routes and service areas
- **Real Estate** - Property boundaries and service zones
- **Transportation** - Transit routes and coverage areas
- **Environmental** - Conservation areas, wildlife habitats
- **Urban Planning** - City zones, districts, infrastructure

## See also

- [Data types overview](/docs/reference/javascript/api/values/) - All custom data types
- [Query builders](/docs/reference/javascript/api/queries/) - Using Geometry in queries
- [SurrealQL geometry](/docs/reference/query-language/language-primitives/data-types/geometries.md) - Database geometry types
- [GeoJSON Specification](https://geojson.org/) - GeoJSON format standard
