Skip to content

Commit 80f06a8

Browse files
committed
editing of dataset spatial grid
1 parent 3caa9e2 commit 80f06a8

File tree

3 files changed

+241
-32
lines changed

3 files changed

+241
-32
lines changed

projects/common/src/lib/util/conversions.ts

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@ import OlFormatGeoJson from 'ol/format/GeoJSON';
44
import OlGeometry from 'ol/geom/Geometry';
55
import {Extent as OlExtent} from 'ol/extent';
66
import {Observable, ReplaySubject} from 'rxjs';
7-
import {BoundingBox2D as BBoxDict, GdalDatasetParameters, ResponseError, SpatialPartition2D} from '@geoengine/openapi-client';
7+
import {
8+
BoundingBox2D as BBoxDict,
9+
GdalDatasetParameters,
10+
GeoTransform,
11+
ResponseError,
12+
SpatialGridDefinition,
13+
SpatialPartition2D,
14+
} from '@geoengine/openapi-client';
815
import {Time} from '../time/time.model';
916

1017
/**
@@ -148,26 +155,55 @@ export function isDefined<T>(arg: T | null | undefined): arg is T {
148155
export function extractSpatialPartition(gdalParams: GdalDatasetParameters): SpatialPartition2D {
149156
const geoTransform = gdalParams.geoTransform;
150157

151-
let minX, minY, maxX, maxY;
158+
const x1 = geoTransform.originCoordinate.x;
159+
const x2 = x1 + geoTransform.xPixelSize * gdalParams.width;
160+
const y1 = geoTransform.originCoordinate.y;
161+
const y2 = y1 + geoTransform.yPixelSize * gdalParams.height;
152162

153-
if (geoTransform.xPixelSize >= 0) {
154-
minX = geoTransform.originCoordinate.x;
155-
maxX = minX + geoTransform.xPixelSize * gdalParams.width;
156-
} else {
157-
maxX = geoTransform.originCoordinate.x;
158-
minX = maxX + geoTransform.xPixelSize * gdalParams.width;
159-
}
163+
const minX = Math.min(x1, x2);
164+
const maxX = Math.max(x1, x2);
165+
const minY = Math.min(y1, y2);
166+
const maxY = Math.max(y1, y2);
160167

161-
if (geoTransform.yPixelSize >= 0) {
162-
minY = geoTransform.originCoordinate.y;
163-
maxY = minY + geoTransform.yPixelSize * gdalParams.height;
164-
} else {
165-
maxY = geoTransform.originCoordinate.y;
166-
minY = maxY + geoTransform.yPixelSize * gdalParams.height;
167-
}
168+
return {
169+
lowerRightCoordinate: {x: maxX, y: minY},
170+
upperLeftCoordinate: {x: minX, y: maxY},
171+
};
172+
}
173+
174+
export function spatialPartitionFromSpatialGridDefinition(grid: SpatialGridDefinition): SpatialPartition2D {
175+
const geoTransform = grid.geoTransform;
176+
const bounds = grid.gridBounds;
177+
178+
const minX = geoTransform.originCoordinate.x - geoTransform.xPixelSize * bounds.topLeftIdx.xIdx;
179+
const maxX = geoTransform.originCoordinate.x + geoTransform.xPixelSize * bounds.bottomRightIdx.xIdx;
180+
181+
const minY = geoTransform.originCoordinate.y + geoTransform.yPixelSize * bounds.bottomRightIdx.yIdx;
182+
const maxY = geoTransform.originCoordinate.y - geoTransform.yPixelSize * bounds.topLeftIdx.yIdx;
168183

169184
return {
170185
lowerRightCoordinate: {x: maxX, y: minY},
171186
upperLeftCoordinate: {x: minX, y: maxY},
172187
};
173188
}
189+
190+
export function spatialGridDefinitionFromSpatialPartitionAndGeoTransform(
191+
spatialPartition: SpatialPartition2D,
192+
geoTransform: GeoTransform,
193+
): SpatialGridDefinition {
194+
const {originCoordinate, xPixelSize, yPixelSize} = geoTransform;
195+
196+
const topLeftXIdx = Math.round((spatialPartition.upperLeftCoordinate.x - originCoordinate.x) / xPixelSize);
197+
const topLeftYIdx = Math.round((spatialPartition.upperLeftCoordinate.y - originCoordinate.y) / yPixelSize);
198+
199+
const bottomRightXIdx = Math.round((spatialPartition.lowerRightCoordinate.x - originCoordinate.x) / xPixelSize);
200+
const bottomRightYIdx = Math.round((spatialPartition.lowerRightCoordinate.y - originCoordinate.y) / yPixelSize);
201+
202+
return {
203+
geoTransform,
204+
gridBounds: {
205+
topLeftIdx: {xIdx: topLeftXIdx, yIdx: topLeftYIdx},
206+
bottomRightIdx: {xIdx: bottomRightXIdx, yIdx: bottomRightYIdx},
207+
},
208+
};
209+
}

projects/manager/src/app/datasets/loading-info/gdal-multiband/gdal-multiband.component.html

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,54 @@
3333
<input matInput type="text" formControlName="spatialReference" />
3434
</mat-form-field>
3535

36+
<div formGroupName="spatialGrid">
37+
<div class="flex-container" formGroupName="geoTransform">
38+
<mat-form-field>
39+
<mat-label>Origin X</mat-label>
40+
<input matInput type="number" formControlName="originX" />
41+
</mat-form-field>
42+
<mat-form-field>
43+
<mat-label>Origin Y</mat-label>
44+
<input matInput type="number" formControlName="originY" />
45+
</mat-form-field>
46+
<mat-form-field>
47+
<mat-label>Pixel Size X</mat-label>
48+
<input matInput type="number" formControlName="xPixelSize" />
49+
</mat-form-field>
50+
<mat-form-field>
51+
<mat-label>Pixel Size Y</mat-label>
52+
<input matInput type="number" formControlName="yPixelSize" />
53+
</mat-form-field>
54+
</div>
55+
56+
<div class="flex-container" formGroupName="gridBounds">
57+
<mat-form-field>
58+
<mat-label>Min X Coordinate</mat-label>
59+
<input matInput type="number" formControlName="minX" />
60+
</mat-form-field>
61+
<mat-form-field>
62+
<mat-label>Min Y Coordinate</mat-label>
63+
<input matInput type="number" formControlName="minY" />
64+
</mat-form-field>
65+
<mat-form-field>
66+
<mat-label>Max X Coordinate</mat-label>
67+
<input matInput type="number" formControlName="maxX" />
68+
</mat-form-field>
69+
<mat-form-field>
70+
<mat-label>Max Y Coordinate</mat-label>
71+
<input matInput type="number" formControlName="maxY" />
72+
</mat-form-field>
73+
</div>
74+
</div>
75+
<mat-divider></mat-divider>
76+
3677
<geoengine-manager-rasterbands
37-
[rasterbands]="metaData().resultDescriptor.bands"
78+
[rasterbands]="form.controls.rasterResultDescriptor.controls.bands.value"
3879
(rasterbandsChange)="form.controls.rasterResultDescriptor.controls.bands.setValue($event); form.markAsDirty()"
3980
></geoengine-manager-rasterbands>
4081

4182
<div class="actions">
42-
<button mat-raised-button color="primary" [disabled]="form.pristine || form.invalid" (click)="saveLoadingInfo()">Apply</button>
83+
<button mat-raised-button color="primary" [disabled]="form.pristine || form.invalid" (click)="saveMetadata()">Apply</button>
4384
</div>
4485
</div>
4586

projects/manager/src/app/datasets/loading-info/gdal-multiband/gdal-multiband.component.ts

Lines changed: 146 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ import {
3737
extractSpatialPartition,
3838
ConfirmationComponent,
3939
geoengineValidators,
40+
spatialPartitionFromSpatialGridDefinition,
41+
spatialGridDefinitionFromSpatialPartitionAndGeoTransform,
42+
Coordinate2D,
4043
} from '@geoengine/common';
4144
import moment from 'moment';
4245
import {
@@ -50,6 +53,8 @@ import {
5053
RasterBandDescriptor,
5154
RasterDataType,
5255
RasterResultDescriptor,
56+
SpatialPartition2D,
57+
GeoTransform as GeoTransformDict,
5358
} from '@geoengine/openapi-client';
5459
import {MatSnackBar} from '@angular/material/snack-bar';
5560
import {MatFormField, MatLabel, MatInput, MatError} from '@angular/material/input';
@@ -88,6 +93,26 @@ export interface RasterResultDescriptorForm {
8893
bands: FormControl<Array<RasterBandDescriptor>>;
8994
dataType: FormControl<RasterDataType>;
9095
spatialReference: FormControl<string>;
96+
spatialGrid: FormGroup<SpatialGridDescriptorForm>;
97+
}
98+
99+
export interface SpatialGridDescriptorForm {
100+
geoTransform: FormGroup<GeoTransformForm>;
101+
gridBounds: FormGroup<GridBoundingBox2DForm>;
102+
}
103+
104+
export interface GeoTransformForm {
105+
originX: FormControl<number>;
106+
originY: FormControl<number>;
107+
xPixelSize: FormControl<number>;
108+
yPixelSize: FormControl<number>;
109+
}
110+
111+
export interface GridBoundingBox2DForm {
112+
minX: FormControl<number>;
113+
minY: FormControl<number>;
114+
maxX: FormControl<number>;
115+
maxY: FormControl<number>;
91116
}
92117

93118
enum EditMode {
@@ -252,13 +277,13 @@ export class GdalMultiBandComponent implements OnChanges {
252277
async ngOnChanges(changes: SimpleChanges): Promise<void> {
253278
const metaData = this.metaData();
254279
if (changes.metaData && metaData) {
255-
this.setUpFormFromMetaData(metaData);
280+
this.setUpFormFromResultDescriptor(metaData.resultDescriptor);
256281
}
257282

258283
this.setUpSource();
259284
}
260285

261-
async saveLoadingInfo(): Promise<void> {
286+
async saveMetadata(): Promise<void> {
262287
if (this.form.invalid) {
263288
return;
264289
}
@@ -270,6 +295,7 @@ export class GdalMultiBandComponent implements OnChanges {
270295
this.snackBar.open('Dataset loading information successfully updated.', 'Close', {
271296
duration: this.config.DEFAULTS.SNACKBAR_DURATION,
272297
});
298+
this.form.markAsPristine();
273299
} catch (error) {
274300
const errorMessage = await errorToText(error, 'Updating dataset loading information failed.');
275301
this.snackBar.open(errorMessage, 'Close', {panelClass: ['error-snackbar']});
@@ -462,11 +488,36 @@ export class GdalMultiBandComponent implements OnChanges {
462488
getMetaData(): MetaDataDefinition {
463489
const resultDescriptorControl = this.form.controls.rasterResultDescriptor.controls;
464490

491+
const geoTransformControl = resultDescriptorControl.spatialGrid.controls.geoTransform.controls;
492+
const geoTransform: GeoTransformDict = {
493+
originCoordinate: {
494+
x: geoTransformControl.originX.value,
495+
y: geoTransformControl.originY.value,
496+
},
497+
xPixelSize: geoTransformControl.xPixelSize.value,
498+
yPixelSize: geoTransformControl.yPixelSize.value,
499+
};
500+
501+
const spatialGridControl = resultDescriptorControl.spatialGrid.controls.gridBounds.controls;
502+
const spatialPartition: SpatialPartition2D = {
503+
upperLeftCoordinate: {
504+
x: spatialGridControl.minX.value,
505+
y: spatialGridControl.maxY.value,
506+
},
507+
lowerRightCoordinate: {
508+
x: spatialGridControl.maxX.value,
509+
y: spatialGridControl.minY.value,
510+
},
511+
};
512+
465513
const resultDescriptor: RasterResultDescriptor = {
466514
bands: resultDescriptorControl.bands.value,
467515
spatialReference: resultDescriptorControl.spatialReference.value,
468516
dataType: resultDescriptorControl.dataType.value,
469-
spatialGrid: this.metaData().resultDescriptor.spatialGrid, // TODO: allow editing
517+
spatialGrid: {
518+
descriptor: 'source',
519+
spatialGrid: spatialGridDefinitionFromSpatialPartitionAndGeoTransform(spatialPartition, geoTransform),
520+
},
470521
time: {
471522
bounds: null,
472523
dimension: {
@@ -506,7 +557,8 @@ export class GdalMultiBandComponent implements OnChanges {
506557
return;
507558
}
508559

509-
this.setResultDescriptor(resultDescriptor);
560+
this.setUpFormFromResultDescriptor(resultDescriptor);
561+
this.changeDetectorRef.markForCheck();
510562
} catch (error) {
511563
const errorMessage = await errorToText(error, 'Metadata suggestion failed.');
512564
this.snackBar.open(errorMessage, 'Close', {panelClass: ['error-snackbar']});
@@ -553,12 +605,6 @@ export class GdalMultiBandComponent implements OnChanges {
553605
}
554606
}
555607

556-
setResultDescriptor(resultDescriptor: RasterResultDescriptor): void {
557-
this.form.controls.rasterResultDescriptor.controls.bands.setValue(resultDescriptor.bands);
558-
this.form.controls.rasterResultDescriptor.controls.dataType.setValue(resultDescriptor.dataType);
559-
this.form.controls.rasterResultDescriptor.controls.spatialReference.setValue(resultDescriptor.spatialReference);
560-
}
561-
562608
protected calculateInitialNumberOfElements(): number {
563609
const element = this.viewport().elementRef.nativeElement;
564610
const numberOfElements = Math.ceil(element.clientHeight / this.itemSizePx);
@@ -590,21 +636,61 @@ export class GdalMultiBandComponent implements OnChanges {
590636
return [gdalMetaDataList.resultDescriptor, gdalParams];
591637
}
592638

593-
private setUpFormFromMetaData(metaData: GdalMultiBand): void {
639+
private setUpFormFromResultDescriptor(resultDescriptor: RasterResultDescriptor): void {
640+
const spatialPartition = spatialPartitionFromSpatialGridDefinition(resultDescriptor.spatialGrid.spatialGrid);
641+
594642
this.form = new FormGroup<GdalMultiBandForm>({
595643
rasterResultDescriptor: new FormGroup<RasterResultDescriptorForm>({
596-
bands: new FormControl(metaData.resultDescriptor.bands, {
644+
bands: new FormControl(resultDescriptor.bands, {
597645
nonNullable: true,
598646
validators: [Validators.required],
599647
}),
600-
dataType: new FormControl(metaData.resultDescriptor.dataType, {
648+
dataType: new FormControl(resultDescriptor.dataType, {
601649
nonNullable: true,
602650
validators: [Validators.required],
603651
}),
604-
spatialReference: new FormControl(metaData.resultDescriptor.spatialReference, {
652+
spatialReference: new FormControl(resultDescriptor.spatialReference, {
605653
nonNullable: true,
606654
validators: [Validators.required],
607655
}),
656+
spatialGrid: new FormGroup<SpatialGridDescriptorForm>({
657+
geoTransform: new FormGroup<GeoTransformForm>({
658+
originX: new FormControl(resultDescriptor.spatialGrid.spatialGrid.geoTransform.originCoordinate.x, {
659+
nonNullable: true,
660+
validators: [Validators.required],
661+
}),
662+
originY: new FormControl(resultDescriptor.spatialGrid.spatialGrid.geoTransform.originCoordinate.y, {
663+
nonNullable: true,
664+
validators: [Validators.required],
665+
}),
666+
xPixelSize: new FormControl(resultDescriptor.spatialGrid.spatialGrid.geoTransform.xPixelSize, {
667+
nonNullable: true,
668+
validators: [Validators.required],
669+
}),
670+
yPixelSize: new FormControl(resultDescriptor.spatialGrid.spatialGrid.geoTransform.yPixelSize, {
671+
nonNullable: true,
672+
validators: [Validators.required],
673+
}),
674+
}),
675+
gridBounds: new FormGroup<GridBoundingBox2DForm>({
676+
minX: new FormControl(spatialPartition.upperLeftCoordinate.x, {
677+
nonNullable: true,
678+
validators: [Validators.required],
679+
}),
680+
minY: new FormControl(spatialPartition.lowerRightCoordinate.y, {
681+
nonNullable: true,
682+
validators: [Validators.required],
683+
}),
684+
maxX: new FormControl(spatialPartition.lowerRightCoordinate.x, {
685+
nonNullable: true,
686+
validators: [Validators.required],
687+
}),
688+
maxY: new FormControl(spatialPartition.upperLeftCoordinate.y, {
689+
nonNullable: true,
690+
validators: [Validators.required],
691+
}),
692+
}),
693+
}),
608694
}),
609695
});
610696

@@ -634,6 +720,44 @@ export class GdalMultiBandComponent implements OnChanges {
634720
nonNullable: true,
635721
validators: [Validators.required],
636722
}),
723+
spatialGrid: new FormGroup<SpatialGridDescriptorForm>({
724+
geoTransform: new FormGroup<GeoTransformForm>({
725+
originX: new FormControl(0, {
726+
nonNullable: true,
727+
validators: [Validators.required],
728+
}),
729+
originY: new FormControl(0, {
730+
nonNullable: true,
731+
validators: [Validators.required],
732+
}),
733+
xPixelSize: new FormControl(1, {
734+
nonNullable: true,
735+
validators: [Validators.required],
736+
}),
737+
yPixelSize: new FormControl(-1, {
738+
nonNullable: true,
739+
validators: [Validators.required],
740+
}),
741+
}),
742+
gridBounds: new FormGroup<GridBoundingBox2DForm>({
743+
minX: new FormControl(0, {
744+
nonNullable: true,
745+
validators: [Validators.required],
746+
}),
747+
minY: new FormControl(0, {
748+
nonNullable: true,
749+
validators: [Validators.required],
750+
}),
751+
maxX: new FormControl(1, {
752+
nonNullable: true,
753+
validators: [Validators.required],
754+
}),
755+
maxY: new FormControl(1, {
756+
nonNullable: true,
757+
validators: [Validators.required],
758+
}),
759+
}),
760+
}),
637761
}),
638762
});
639763

@@ -803,3 +927,11 @@ class TileDataSource extends DataSource<DatasetTile> {
803927
});
804928
}
805929
}
930+
function spatialGridFromSpatialPartition(
931+
value: Partial<{
932+
geoTransform: Partial<{originX: number; originY: number; xPixelSize: number; yPixelSize: number}>;
933+
gridBounds: Partial<{minX: number; minY: number; maxX: number; maxY: number}>;
934+
}>,
935+
): import('@geoengine/openapi-client').SpatialGridDescriptor {
936+
throw new Error('Function not implemented.');
937+
}

0 commit comments

Comments
 (0)