Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
7933025
feat: add buffer parameter to intersect, nearest-neighbour and within…
NtnHgr Sep 7, 2026
84fc444
feat (buffer): unused vars fixed
NtnHgr Sep 7, 2026
7431b3f
feat (buffer): format:check carried out
NtnHgr Sep 7, 2026
8fbd9a0
fix(buffer): returnBufferGeometry, unit: meters
NtnHgr Sep 8, 2026
f6162d1
fix(buffer): format:check
NtnHgr Sep 8, 2026
5b3f91b
docs: buffer parameters documented
NtnHgr Sep 10, 2026
432f57e
fix(buffer) getBufferQuadSegs as util-module
NtnHgr Sep 16, 2026
fe015ba
fix(buffer) sprecification of returnBufferGeometry depends on buffer
NtnHgr Sep 16, 2026
cb8846c
fix(buffer): calculation of getBufferQuadSegs
NtnHgr Sep 17, 2026
3f8b6d1
fix(buffer): added upper bound for buffer distance
NtnHgr Sep 21, 2026
ac518d6
fix(buffer): resolved comments
NtnHgr Sep 21, 2026
1c0991c
fix(buffer): make returnBufferGeometry schema compatible with the val…
sebeweiss Sep 21, 2026
81d5ef9
test(buffer): add e2e tests
NtnHgr Sep 22, 2026
ee94c2d
fix(buffer): adjust test for maximum quadSegs to maximum buffer distance
NtnHgr Sep 22, 2026
6c1966b
fix(buffer): deleted unused variable
NtnHgr Sep 22, 2026
6337c7b
fix(buffer): set upper bound for buffer distance to 20000
NtnHgr Sep 22, 2026
e400ad6
fix(buffer): adjust e2e-test (within) for upper bound of buffer distance
NtnHgr Sep 22, 2026
5c19fc4
adjust documentation for upper bound of buffer distance
NtnHgr Sep 22, 2026
6a460cf
fix(buffer): returnBufferGeometry, unit: meters
NtnHgr Sep 8, 2026
18e8043
fix(buffer): format:check
NtnHgr Sep 8, 2026
8e7751f
docs: buffer parameters documented
NtnHgr Sep 10, 2026
108f41c
fix(buffer) getBufferQuadSegs as util-module
NtnHgr Sep 16, 2026
252754b
Merge main into buffer
NtnHgr Sep 22, 2026
381dfa3
docs (buffer): update changelog
NtnHgr Sep 23, 2026
7775156
fix(buffer): preserve geometry identifiers on buffer features
NtnHgr Oct 5, 2026
e40ccc4
fix(buffer): remove tsconfig.build.tsbuildinfo
NtnHgr Oct 5, 2026
1f0415b
docs(buffer): correct wording and rename getBufferGeometry to returnB…
NtnHgr Oct 5, 2026
d19b79d
docs(buffer): delete comments
NtnHgr Oct 5, 2026
1e837ed
feat(buffer): remove buffer from nearestNeighbour
NtnHgr Oct 7, 2026
0f09fc2
test(buffer): adjust e2e-tests to removal of buffer from nearestNeigh…
NtnHgr Oct 7, 2026
73714cf
docs(buffer): adjust docs to removal of buffer from nearestNeighbour
NtnHgr Oct 7, 2026
f15645f
docs(buffer): adjust docs to removal of buffer from nearestNeighbour
NtnHgr Oct 7, 2026
e2e28cf
Merge branch 'buffer' of https://github.com/geobakery/GeospatialAnaly…
NtnHgr Oct 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,6 @@ lerna-debug.log*
.env.docker.dev
.env.prod
swagger-description.md
bom.json
sbom.cyclonedx.json
tsconfig.build.tsbuildinfo
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The format follows [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/

- `GEOSPATIAL_ANALYZER_CORS_ORIGINS` environment variable to configure allowed CORS origins as a comma-separated list. CORS remains disabled when the variable is unset.
- `sn_flurstueck_f`/`flurstueck_f` now provide `gemarkungsschluessel` and `gemarkungsname`.
- `intersect` and `within` now provide optional `buffer` (distance in meters; value range: 0 - 20 000). Using a polygonal approximation, its deviation from the exact circular arc is at most 10cm. The optional specification of `returnBufferGeometry` (boolean) returns its coordinates.

### Changed

Expand Down
23 changes: 19 additions & 4 deletions documentation/intersect.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ In this document we will describe important and good-to-know facts about the int
## Functionality

Returns all features that are touched by the transferred geometries.
An optional buffer around each input geometry is also supported.
Using the buffer parameter, its distance can be entered in meters (between 0 and 20 000m).

## Examples

Expand Down Expand Up @@ -37,7 +39,9 @@ Post-call http://localhost:3000/v2/intersect with JSON body:
"topics": ["kreis_f"],
"returnGeometry": false,
"outputFormat": "geojson",
"outSRS": 4326
"outSRS": 4326,
"buffer": 100,
"returnBufferGeometry": false
}
```

Expand All @@ -60,7 +64,9 @@ Post-call http://localhost:3000/v2/intersect with JSON body:
"topics": ["kreis_f", "land_f"],
"returnGeometry": false,
"outputFormat": "geojson",
"outSRS": 4326
"outSRS": 4326,
"buffer": 100,
"returnBufferGeometry": false
}
```

Expand All @@ -86,7 +92,9 @@ Post-call http://localhost:3000/v2/intersect with JSON body:
"topics": ["kreis_f"],
"returnGeometry": false,
"outputFormat": "geojson",
"outSRS": 4326
"outSRS": 4326,
"buffer": 100,
"returnBufferGeometry": false
}
```

Expand All @@ -111,7 +119,9 @@ Post-call http://localhost:3000/v2/intersect with JSON body:
"topics": ["kreis_f"],
"returnGeometry": false,
"outputFormat": "esrijson",
"outSRS": 25833
"outSRS": 25833,
"buffer": 100,
"returnBufferGeometry": false
}
```

Expand All @@ -122,3 +132,8 @@ Post-call http://localhost:3000/v2/intersect with JSON body:
- MultiLineString
- MultiPoint
- GeometryCollection

- Accuracy of buffer is limited (10cm)
- polygonal approximation using quadSegs (count of segments per quarter circle)
- count depends on buffer distance (so max. error from "real" buffer is 10cm)
- max. 256 quadSegs
20 changes: 13 additions & 7 deletions documentation/neighbour.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ Post-call http://localhost:3000/v2/nearestNeighbour with JSON body:
"topics": ["kreis_f"],
"returnGeometry": false,
"outputFormat": "geojson",
"outSRS": 4326
"outSRS": 4326,
"buffer": 100,
"returnBufferGeometry": false
}
```

Expand All @@ -60,7 +62,9 @@ Post-call http://localhost:3000/v2/nearestNeighbour with JSON body:
"topics": ["kreis_f", "land_f"],
"returnGeometry": false,
"outputFormat": "geojson",
"outSRS": 4326
"outSRS": 4326,
"buffer": 100,
"returnBufferGeometry": false
}
```

Expand All @@ -86,7 +90,9 @@ Post-call http://localhost:3000/v2/nearestNeighbour with JSON body:
"topics": ["kreis_f"],
"returnGeometry": false,
"outputFormat": "geojson",
"outSRS": 4326
"outSRS": 4326,
"buffer": 100,
"returnBufferGeometry": false
}
```

Expand All @@ -111,14 +117,14 @@ Post-call http://localhost:3000/v2/nearestNeighbour with JSON body:
"topics": ["kreis_f"],
"returnGeometry": false,
"outputFormat": "geojson",
"outSRS": 4326
"outSRS": 4326,
"buffer": 100,
"returnBufferGeometry": false
}
```

## Known Limitations - Work in progres

- Currently, unsupported user parameter
- buffer
- Complete parameter validation
- API token authentication

Expand All @@ -128,4 +134,4 @@ Post-call http://localhost:3000/v2/nearestNeighbour with JSON body:
- MultiPolygon
- MultiLineString
- MultiPoint
- GeometryCollection
- GeometryCollection
23 changes: 19 additions & 4 deletions documentation/within.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ In this document we will describe important and good-to-know facts about the wit
## Functionality

Returns all features, where the transferred geometries are completely contained.
An optional buffer around each input geometry is also supported.
Using the buffer parameter, its distance can be entered in meters (between 0 and 20 000m).

## Examples

Expand Down Expand Up @@ -37,7 +39,9 @@ Post-call http://localhost:3000/v2/within with JSON body:
"topics": ["kreis_f"],
"returnGeometry": false,
"outputFormat": "geojson",
"outSRS": 4326
"outSRS": 4326,
"buffer": 100,
"returnBufferGeometry": false
}
```

Expand All @@ -60,7 +64,9 @@ Post-call http://localhost:3000/v2/within with JSON body:
"topics": ["kreis_f", "land_f"],
"returnGeometry": false,
"outputFormat": "geojson",
"outSRS": 4326
"outSRS": 4326,
"buffer": 100,
"returnBufferGeometry": false
}
```

Expand All @@ -86,7 +92,9 @@ Post-call http://localhost:3000/v2/within with JSON body:
"topics": ["kreis_f"],
"returnGeometry": false,
"outputFormat": "geojson",
"outSRS": 4326
"outSRS": 4326,
"buffer": 100,
"returnBufferGeometry": false
}
```

Expand All @@ -111,7 +119,9 @@ Post-call http://localhost:3000/v2/within with JSON body:
"topics": ["kreis_f"],
"returnGeometry": false,
"outputFormat": "geojson",
"outSRS": 4326
"outSRS": 4326,
"buffer": 100,
"returnBufferGeometry": false
}
```

Expand All @@ -122,3 +132,8 @@ Post-call http://localhost:3000/v2/within with JSON body:
- MultiLineString
- MultiPoint
- GeometryCollection

- Accuracy of buffer is limited (10cm)
- polygonal approximation using quadSegs (count of segments per quarter circle)
- count depends on buffer distance (so max. error from "real" buffer is 10cm)
- max. 256 quadSegs
38 changes: 38 additions & 0 deletions src/general/adapter/postgres.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ export class PostgresService extends DbAdapterService {
return `ST_TRANSFORM(${featureWkt.value}::text, ${toCrs})`;
}

override bufferFeature(
feature: SqlParameter,
distance: SqlParameter,
srid: number,
quadSegs: number,
): string {
return `ST_Transform(
ST_Buffer(
ST_Transform(${feature.value}, 4326)::geography,
${distance.value}, 'quad_segs=${quadSegs}')::geometry,
${srid})`;
}

override getJsonStructure(returnGeometry: boolean): string {
const recordValue = returnGeometry
? `ST_AsGeoJSON(
Expand All @@ -57,6 +70,31 @@ export class PostgresService extends DbAdapterService {
`;
}

override getBufferJsonStructure(
bufferGeometry: string,
bufferDistance: string,
bufferSourceId: string,
): string {
return `
json_build_object(
'type', 'FeatureCollection',
'features', json_build_array(
json_build_object(
'type', 'Feature',
'geometry',
ST_AsGeoJSON(${bufferGeometry})::json,
'properties',
json_build_object(
'__buffer', true,
'__bufferDistance', ${bufferDistance},
'__bufferSourceId', ${bufferSourceId}
)
)
)
)
`;
}

override getJsonRecordAlias(): string {
return 'custom_from_select';
}
Expand Down
22 changes: 22 additions & 0 deletions src/general/buffer.util.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { getBufferQuadSegs } from './buffer.util';

describe('getBufferQuadSegs', () => {
it('returns the minimum (8) for buffer distance <= 0', () => {
expect(getBufferQuadSegs(0)).toBe(8);
expect(getBufferQuadSegs(-5)).toBe(8);
});

it('returns more segments for larger buffer distances (finer approximation needed)', () => {
const small = getBufferQuadSegs(1);
const large = getBufferQuadSegs(10000);
expect(large).toBeGreaterThan(small);
});

it('never exceeds the maximum of 256', () => {
expect(getBufferQuadSegs(20000)).toBeLessThanOrEqual(256);
});

it('never falls below the minimum of 8', () => {
expect(getBufferQuadSegs(0.001)).toBeGreaterThanOrEqual(8);
});
});
19 changes: 19 additions & 0 deletions src/general/buffer.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export function getBufferQuadSegs(bufferDistance: number): number {
const maxError = 0.1;
const minQuadSegs = 8;
const maxQuadSegs = 256;

if (bufferDistance <= 0) {
return minQuadSegs;
}

if (maxError >= 2 * bufferDistance) {
return minQuadSegs;
}

const quadSegs = Math.ceil(
Math.PI / (4 * Math.acos(1 - maxError / bufferDistance)),
);

return Math.min(maxQuadSegs, Math.max(minQuadSegs, quadSegs));
}
13 changes: 13 additions & 0 deletions src/general/db-adapter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@ export abstract class DbAdapterService {

abstract getValueAtFeature(point: SqlParameter, raster: SqlParameter): string;

abstract bufferFeature(
feature: SqlParameter,
distance: SqlParameter,
srid: number,
quadSegs: number,
): string;

abstract getBufferJsonStructure(
bufferGeometry: string,
bufferDistance: string,
bufferSourceId: string,
): string;

abstract transformFeature(featureWkt: SqlParameter, toCrs: number): string;

abstract getJsonStructure(returnGeometry: boolean): string;
Expand Down
43 changes: 41 additions & 2 deletions src/general/dto/parameter.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,22 @@ export const SCHEMA_VALID_OUT_SRS: Readonly<SchemaObject> = {
],
};

export const SCHEMA_VALID_RETURN_BUFFER_GEOMETRY: Readonly<SchemaObject> = {
Comment thread
NtnHgr marked this conversation as resolved.
anyOf: [
{
properties: {
returnBufferGeometry: { enum: [false] },
},
},
{
required: ['buffer'],
properties: {
buffer: { not: { enum: [0] } },
},
},
],
};

@ApiExtraModels(EsriJsonDto, GeoJSONFeatureDto, GeoJSONFeatureCollectionDto)
export class ParameterDto implements GeospatialRequest {
@ApiProperty({
Expand Down Expand Up @@ -125,7 +141,30 @@ export class ParameterDto implements GeospatialRequest {
outSRS: number;
}

export class IntersectParameterDto extends ParameterDto {}
export const MAX_BUFFER_DISTANCE = 20000;

export class BufferParameterDto extends ParameterDto {
@ApiProperty({
required: false,
type: Number,
example: 100,
description: 'Buffer distance around each input geometry in meters',
minimum: 0,
maximum: MAX_BUFFER_DISTANCE,
})
buffer?: number;

@ApiProperty({
required: false,
default: false,
description:
'Return the calculated buffer geometry of the input geometry in the response',
example: false,
})
returnBufferGeometry?: boolean;
}

export class IntersectParameterDto extends BufferParameterDto {}
export class NearestNeighbourParameterDto extends ParameterDto {
@ApiProperty({ example: 3 })
count: number;
Expand All @@ -140,4 +179,4 @@ export class ValuesAtPointParameterDto extends ParameterDto {
})
topics: string[];
}
export class WithinParameterDto extends ParameterDto {}
export class WithinParameterDto extends BufferParameterDto {}
1 change: 1 addition & 0 deletions src/general/general.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const DB_RASTER_DATA_NAME = 'rast';
export const DB_TOPIC_NAME = 'topic';

export const QUERY_FEATURE_INDEX = 'feature_wkt_';
export const QUERY_BUFFER_INDEX = 'buffer_';

/**
* Choosing an appropriate status code is surprisingly unclear:
Expand Down
Loading
Loading