geos.js
Version:
an easy-to-use JavaScript wrapper over WebAssembly build of GEOS
85 lines (76 loc) • 3.33 kB
text/typescript
import { POINTER } from '../core/symbols.mjs';
import { type Geometry, GeometryRef } from '../geom/Geometry.mjs';
import { geos } from '../core/geos.mjs';
export interface MakeValidOptions {
/**
* Method used for fixing invalid geometries.
* - `linework` - builds valid geometries by first extracting all lines,
* noding that linework together, then building a value output from the
* linework
* - `structure` - is an algorithm that distinguishes between interior and
* exterior rings, building new geometry by unioning exterior rings, and
* then differencing all interior rings
* @default 'linework'
*/
method?: 'linework' | 'structure';
/**
* Only valid for the `structure` method.
* When set to `false`, geometry components that collapse to a lower
* dimensionality, for example, a one-point linestring would be dropped.
* @default false
*/
keepCollapsed?: boolean;
}
/**
* Repairs an invalid geometry, returns a repaired, valid geometry.
* Input geometries are always processed, so even valid inputs may
* have some minor alterations. The output is always a new geometry object.
*
* @param geometry - The geometry to repair
* @param options - Optional parameters to control the algorithm
* @returns A new repaired geometry
* @throws {GEOSError} on unsupported geometry types (curved)
*
* @see {@link isValid} checks whether a geometry is already valid
*
* @example #live
* const poly = fromWKT('POLYGON ((2.22 2.28, 7.67 2.06, 10.98 7.7, 9.39 5, 7.96 7.12, 6.77 5.16, 7.43 6.24, 3.7 7.22, 5.72 5.77, 4.18 10.74, 2.2 6.83, 2.22 2.28))');
* const valid1 = makeValid(poly);
* const valid2 = makeValid(poly, { method: 'structure' });
*
* @example #live polygon with hole partially outside shell
* const poly = polygon([ [ [ 0, 0 ], [ 0, 2 ], [ 2, 0 ], [ 0, 0 ] ], [ [ 0.5, 0.5 ], [ 2, 1 ], [ 2, 0.5 ], [ 0.5, 0.5 ] ] ]);
* const valid1 = makeValid(poly);
* const valid2 = makeValid(poly, { method: 'structure' });
*
* @example #live
* const lineInDisguise = polygon([ [ [ 0, 0 ], [ 1, 1 ], [ 1, 2 ], [ 1, 1 ], [ 0, 0 ] ] ]);
* const valid1 = makeValid(lineInDisguise);
* // MULTILINESTRING ((0 0, 1 1), (1 1, 1 2))
* const valid2 = makeValid(lineInDisguise, { method: 'structure', keepCollapsed: true });
* // LINESTRING (0 0, 1 1, 1 2, 1 1, 0 0)
* const valid3 = makeValid(lineInDisguise, { method: 'structure' });
* // POLYGON EMPTY
*/
export function makeValid(geometry: Geometry, options?: MakeValidOptions): Geometry {
const cache = geos.m_v;
const key = options
? [ options.method, options.keepCollapsed ].join()
: '';
let paramsPtr = cache[ key ];
if (!paramsPtr) {
const ptr = geos.GEOSMakeValidParams_create();
if (options) {
const { method, keepCollapsed } = options;
if (method != null) {
geos.GEOSMakeValidParams_setMethod(ptr, method === 'structure' ? 1 : 0);
}
if (keepCollapsed != null) {
geos.GEOSMakeValidParams_setKeepCollapsed(ptr, +keepCollapsed);
}
}
paramsPtr = cache[ key ] = ptr;
}
const geomPtr = geos.GEOSMakeValidWithParams(geometry[ POINTER ], paramsPtr);
return new GeometryRef(geomPtr) as Geometry;
}