@regionerne/gis-komponent 0.0.84 → 0.0.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -61,8 +61,8 @@ import Feature$1 from 'ol/Feature';
|
|
|
61
61
|
import { never, always } from 'ol/events/condition';
|
|
62
62
|
import { buffer, lineIntersect, lineSplit, featureCollection, difference, booleanIntersects, union, point, booleanPointInPolygon, area, flatten, feature, booleanWithin, intersect, bboxPolygon } from '@turf/turf';
|
|
63
63
|
import GeoJSON$1 from 'ol/format/GeoJSON';
|
|
64
|
+
import { containsXY, extend, createEmpty, buffer as buffer$1 } from 'ol/extent';
|
|
64
65
|
import { Feature } from 'ol';
|
|
65
|
-
import { extend, createEmpty, buffer as buffer$1 } from 'ol/extent';
|
|
66
66
|
import { easeOut } from 'ol/easing';
|
|
67
67
|
import Select from 'ol/interaction/Select';
|
|
68
68
|
import html2canvas from 'html2canvas-pro';
|
|
@@ -1591,9 +1591,9 @@ class GeometrySplitService {
|
|
|
1591
1591
|
// Move back to 25832
|
|
1592
1592
|
bufferedLine.geometry.coordinates = bufferedLine.geometry.coordinates.map(a => a.map(c => proj4('EPSG:4326', 'EPSG:25832', c)));
|
|
1593
1593
|
const overlappingFeatures = vectorSource.getFeatures().filter(f => !this._featureHelper.isLocked(f) && f.getGeometry()?.intersectsExtent(lineFeature.getGeometry()?.getExtent()));
|
|
1594
|
+
const lineFeatureObject = this.geoJsonFormat.writeFeatureObject(lineFeature, { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:25832' });
|
|
1594
1595
|
overlappingFeatures.filter(f => f.getGeometry()?.getType() === 'LineString').forEach(feature => {
|
|
1595
1596
|
const linestringFeatureObject = this.geoJsonFormat.writeFeatureObject(feature, { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:25832' });
|
|
1596
|
-
const lineFeatureObject = this.geoJsonFormat.writeFeatureObject(lineFeature, { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:25832' });
|
|
1597
1597
|
if (lineIntersect(lineFeatureObject, linestringFeatureObject)) {
|
|
1598
1598
|
const lines = lineSplit(linestringFeatureObject, lineFeatureObject);
|
|
1599
1599
|
const newFeatures = lines.features.map(lineSplitFeature => {
|
|
@@ -1607,8 +1607,19 @@ class GeometrySplitService {
|
|
|
1607
1607
|
vectorSource.removeFeature(feature);
|
|
1608
1608
|
}
|
|
1609
1609
|
});
|
|
1610
|
-
// Handle polygons
|
|
1611
|
-
|
|
1610
|
+
// Handle polygons - if the split line starts or ends inside of a polygon, that polygon is NOT split!
|
|
1611
|
+
// That split leaves weird lines in the poly and it's handled by excluding those polys alltogether.
|
|
1612
|
+
const splitLineCoordinates = lineFeature.getGeometry().getCoordinates();
|
|
1613
|
+
const coordLength = splitLineCoordinates.length;
|
|
1614
|
+
const lineFirstPoint = splitLineCoordinates[0];
|
|
1615
|
+
const lineLastPoint = splitLineCoordinates[coordLength - 1];
|
|
1616
|
+
overlappingFeatures.filter(f => f.getGeometry()?.getType() === 'Polygon')
|
|
1617
|
+
.filter(feature => {
|
|
1618
|
+
const containsStartingPoint = this.isPointStrictlyInside(feature.getGeometry(), lineFirstPoint);
|
|
1619
|
+
const containsEndPoint = this.isPointStrictlyInside(feature.getGeometry(), lineLastPoint);
|
|
1620
|
+
return !containsStartingPoint && !containsEndPoint;
|
|
1621
|
+
})
|
|
1622
|
+
.forEach((feature) => {
|
|
1612
1623
|
const overlappingFeatureGeoJson = this.geoJsonFormat.writeFeatureObject(feature);
|
|
1613
1624
|
const features = featureCollection([overlappingFeatureGeoJson, bufferedLine]);
|
|
1614
1625
|
const clipped = difference(features);
|
|
@@ -1627,6 +1638,15 @@ class GeometrySplitService {
|
|
|
1627
1638
|
}
|
|
1628
1639
|
});
|
|
1629
1640
|
}
|
|
1641
|
+
isPointStrictlyInside(geom, coord) {
|
|
1642
|
+
if (!geom.intersectsCoordinate(coord))
|
|
1643
|
+
return false;
|
|
1644
|
+
const extent = geom.getExtent();
|
|
1645
|
+
// Hvis punktet ligger udenfor extents → false
|
|
1646
|
+
if (!containsXY(extent, coord[0], coord[1]))
|
|
1647
|
+
return false;
|
|
1648
|
+
return true; // inde og ikke kun på kanten
|
|
1649
|
+
}
|
|
1630
1650
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: GeometrySplitService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1631
1651
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: GeometrySplitService, providedIn: 'root' });
|
|
1632
1652
|
}
|
|
@@ -2950,6 +2970,7 @@ class ToolboxComponent {
|
|
|
2950
2970
|
_originalMapHeight = 0;
|
|
2951
2971
|
pointClickKey;
|
|
2952
2972
|
_geometrySearchService = inject(GeometrySearchService);
|
|
2973
|
+
// private _geomClipService = inject(GeometryClipService);
|
|
2953
2974
|
drawInteraction;
|
|
2954
2975
|
get showDocumentSearch() {
|
|
2955
2976
|
return this.settings?.showDocumentSearch !== false;
|
|
@@ -3485,31 +3506,45 @@ class ToolboxComponent {
|
|
|
3485
3506
|
});
|
|
3486
3507
|
this._interactionHelper.setAsTemp(clipHoleDraw);
|
|
3487
3508
|
clipHoleDraw.on('drawend', evt => {
|
|
3488
|
-
const
|
|
3489
|
-
const
|
|
3509
|
+
const featuresInExtent = this._drawLayerService.source.getFeatures().filter(f => !this._featureHelper.isLocked(f) && f.getGeometry()?.intersectsExtent(evt.feature.getGeometry().getExtent()));
|
|
3510
|
+
const formatterOptions = { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:25832' };
|
|
3511
|
+
const geoJsonFormat = new GeoJSON$1(formatterOptions);
|
|
3490
3512
|
const holeGeoJson = geoJsonFormat.writeFeatureObject(evt.feature);
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
+
// Turf is not always able to handle difference if two polygons are completely on top of each other at the edge
|
|
3514
|
+
// That can happen when Snap is active. To handle that, I do a tiny huffer around the hole
|
|
3515
|
+
const bufferedHole = buffer(holeGeoJson, 0.01, { units: 'meters' });
|
|
3516
|
+
const wktFormat = new WKT();
|
|
3517
|
+
// This is a lot of code to handle that Turf is not very precise for larger areas, so I have to handle that. Because the clip will sometimes leave a small snippet
|
|
3518
|
+
// that needs to be removed. Tha mostly happens on large areas and with snap enabled for the draw interaction.
|
|
3519
|
+
const overlappingItems$ = featuresInExtent
|
|
3520
|
+
.map(featureInExtent => ({ feature: featureInExtent, overlappingFeatureGeoJson: geoJsonFormat.writeFeatureObject(featureInExtent) })) // Here, I just build the items I need later
|
|
3521
|
+
.map(item => ({ ...item, threshold: area(item.overlappingFeatureGeoJson) / 10000, clipped: difference(featureCollection([item.overlappingFeatureGeoJson, bufferedHole])) }))
|
|
3522
|
+
.filter(item => !!item.clipped) // Filter out the items that aren't clipped. They are in the same extent, but don't actually overlap, so I leave those out
|
|
3523
|
+
.map(item => ({ ...item, allPolys: flatten(item.clipped) })) // The clipped item can be an array of item, so I make sure to flatten it.
|
|
3524
|
+
.map(item => ({ ...item, allPolysAsWkt: item.allPolys.features.map(poly => wktFormat.writeGeometry(geoJsonFormat.readGeometry(poly.geometry))) }))
|
|
3525
|
+
.map(item => item.allPolysAsWkt.map(wkt => this._geometryService.validate(wkt).pipe(map(result => // Now, I need to validate all the clipped items
|
|
3526
|
+
result.correctedGeometries ? { ...item, validWKTS: result.correctedGeometries } : { ...item, validWKTS: [wkt] } // If there were corrections, I return the corrected items. If not, just the original
|
|
3527
|
+
))))
|
|
3528
|
+
.flatMap(r => r);
|
|
3529
|
+
combineLatest(overlappingItems$).subscribe({
|
|
3530
|
+
next: validatedItems => {
|
|
3531
|
+
const featuresToAdd = validatedItems
|
|
3532
|
+
.map(item => item.validWKTS
|
|
3533
|
+
.filter(wkt => {
|
|
3534
|
+
const feature = wktFormat.readFeature(wkt);
|
|
3535
|
+
return area(geoJsonFormat.writeFeatureObject(feature)) > item.threshold; // Map all the returned, validated wkts back to features and calc the area of them and remove the very small ones
|
|
3536
|
+
}).map(wkt => {
|
|
3537
|
+
const newFeature = item.feature.clone();
|
|
3538
|
+
this._featureHelper.setId(newFeature);
|
|
3539
|
+
const g = wktFormat.readGeometry(wkt);
|
|
3540
|
+
newFeature.setGeometry(g);
|
|
3541
|
+
return newFeature;
|
|
3542
|
+
})).flatMap(f => f);
|
|
3543
|
+
const featuresToRemove = validatedItems.map(item => item.feature);
|
|
3544
|
+
this._drawLayerService.source.removeFeatures(featuresToRemove);
|
|
3545
|
+
this._undoRedo.disable();
|
|
3546
|
+
this._drawLayerService.source.addFeatures(featuresToAdd);
|
|
3547
|
+
this._undoRedo.enable();
|
|
3513
3548
|
}
|
|
3514
3549
|
});
|
|
3515
3550
|
});
|