| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- import {HttpClient} from '@angular/common/http';
- import {Injectable} from '@angular/core';
- import {NgbCalendar, NgbDateStruct} from '@ng-bootstrap/ng-bootstrap';
- import {Subject} from 'rxjs';
- import {catchError} from 'rxjs/operators';
- import {
- HsCompositionsParserService,
- HsConfig,
- HsEventBusService,
- HsLanguageService,
- HsMapService,
- HsToastService,
- } from 'hslayers-ng';
- import {FcFieldService} from './field.service';
- import {FcZonesService} from './zones.service';
- import {imageWmsTLayer, imageWmsTSource} from './image-wms-t-layer';
- /**
- * Set of precalculated indices
- */
- const INDICES_PRE_FLIGHT = ['EVI', 'NDVI', 'RVI4S1'] as const;
- /**
- * Set of indices which are calculated on the fly
- */
- const INDICES_ON_THE_FLY = ['NDWI', 'NDTI', 'NDRE'] as const;
- export type IndexPreFlight = typeof INDICES_PRE_FLIGHT[number];
- export type IndexOnTheFly = typeof INDICES_ON_THE_FLY[number];
- export type Index = IndexPreFlight | IndexOnTheFly;
- @Injectable({providedIn: 'root'})
- export class FcCalculatorService {
- AVAILABLE_PRODUCTS = [...INDICES_PRE_FLIGHT, ...INDICES_ON_THE_FLY].sort();
- BLUR_MIN_VALUE = 1 as const;
- BLUR_MAX_VALUE = 5 as const;
- MIN_LPIS_VISIBLE_ZOOM = 15 as const;
- SERVICE_BASE_URL = 'https://fieldcalc.lesprojekt.cz/' as const;
- availableDates: Array<string>;
- blurValue = 1;
- dateRangeSelects: Subject<{date: string}> = new Subject();
- dateCalendarSelects: Subject<{date: string}> = new Subject();
- lpisLoading = false;
- quantileCount = 4;
- selectedDate: string;
- selectedDateCalendar: NgbDateStruct;
- viewChanges: Subject<any> = new Subject();
- lastError = '';
- //selectedProduct;
- private _datesLoading: boolean;
- private _zonesLoading: boolean;
- constructor(
- private fieldService: FcFieldService,
- private hsCompositionsParserService: HsCompositionsParserService,
- private hsConfig: HsConfig,
- private hsEventBus: HsEventBusService,
- private hsLanguageService: HsLanguageService,
- private hsMapService: HsMapService,
- private hsToastService: HsToastService,
- private httpClient: HttpClient,
- private zonesService: FcZonesService,
- private calendar: NgbCalendar
- ) {
- this.dateRangeSelects.subscribe(({date}) => {
- this.selectedDate = date;
- });
- /**
- * When new field is selected, clear all other params
- */
- this.fieldService.fieldSelects.subscribe(() => {
- this.availableDates = undefined;
- this.selectedDate = undefined;
- });
- this.hsEventBus.olMapLoads.subscribe((map) => {
- map.map.getView().on('change:resolution', (evt) => {
- this.viewChanges.next(evt.target);
- });
- });
- }
- noDates(): boolean {
- return this.availableDates === undefined;
- }
- /**
- * Call 'get_dates' API method
- */
- async getDates({product}: {product: Index}) {
- this.availableDates = undefined;
- this.selectedDateCalendar = null;
- this._datesLoading = true;
- try {
- const data = await this.httpClient
- .get<{dates: string[]}>(
- (this.proxyEnabled() ? this.hsConfig.apps.default.proxyPrefix : '') +
- this.SERVICE_BASE_URL +
- 'get_dates?' +
- 'product=' +
- product +
- '¢roid=' +
- JSON.stringify(this.fieldService.getSelectedFieldCentroid())
- )
- .toPromise();
- this._datesLoading = false;
- console.log('data received!', data);
- this.availableDates = data.dates;
- /* Any previously selected date must be cleaned up
- * so it won't get sent to the API as a wrong param
- */
- this.selectedDate = undefined;
- } catch (err) {
- this._datesLoading = false;
- this.hsToastService.createToastPopupMessage(
- this.hsLanguageService.getTranslationIgnoreNonExisting(
- 'CALCULATOR',
- 'errorLoading'
- ),
- this.hsLanguageService.getTranslationIgnoreNonExisting(
- 'CALCULATOR',
- 'errorLoadingDates'
- ),
- {
- toastStyleClasses: 'bg-warning text-dark',
- }
- );
- console.error('Somethin fucked up!');
- console.log(err);
- }
- }
- get datesLoading() {
- return this._datesLoading;
- }
- get zonesLoading() {
- return this._zonesLoading;
- }
- /**
- * Call 'get_zones' or 'get_zones_exp' API method
- */
- async getZones({product}: {product: Index}) {
- this.lastError = '';
- this._zonesLoading = true;
- const endpoint = INDICES_PRE_FLIGHT.includes(product as IndexPreFlight)
- ? 'get_zones'
- : 'get_zones_exp';
- try {
- const data = await this.httpClient
- .post(
- (this.proxyEnabled() ? this.hsConfig.apps.default.proxyPrefix : '') +
- this.SERVICE_BASE_URL +
- endpoint,
- {
- product,
- number_of_quantiles: this.quantileCount,
- blur: this.blurValue,
- date: this.selectedDate,
- format: 'geojson',
- geojson: this.fieldService.getSelectedFieldGeoJSON(),
- },
- {
- headers: {
- 'Content-Type': 'application/json',
- 'Accept': 'application/json',
- },
- }
- )
- .toPromise();
- console.log('data received!', data);
- // in case of unreliable data the return value is {"error": "data is not reliable."}
- // TODO: show this error message to user
- if (data['error']) {
- throw new Error(data['error']);
- }
- this._zonesLoading = false;
- await this.zonesService.updateZones(data, {
- quantileCount: this.quantileCount,
- });
- } catch (err) {
- const errLoadingZones =
- this.hsLanguageService.getTranslationIgnoreNonExisting(
- 'CALCULATOR',
- 'errorLoadingZones'
- );
- this._zonesLoading = false;
- this.hsToastService.createToastPopupMessage(
- this.hsLanguageService.getTranslationIgnoreNonExisting(
- 'CALCULATOR',
- 'errorLoading'
- ),
- errLoadingZones,
- {
- toastStyleClasses: 'bg-warning text-dark',
- }
- );
- this.lastError = errLoadingZones;
- console.error('Somethin fucked up!');
- console.log(err);
- }
- }
- /**
- * Updates WMS-t layer with the source image
- * @param date - ISO date
- */
- updateImageBackground(date: string) {
- const isoTime = date.split('T')[0].replace(/-/g, '');
- imageWmsTSource.updateParams({time: isoTime});
- imageWmsTLayer.setVisible(true);
- }
- /**
- * Adds all layers from a provided composition to the map, optionally into a provided folder
- * @param compositionLink - URL of the composition record
- * @param path - Folder name
- */
- addLayersFromComposition(compositionLink: string, {path}) {
- const composition = []; //TODO: get composition object from compositionLink URL
- if (path) {
- for (const layer of composition) {
- //TODO: add path
- }
- }
- }
- private proxyEnabled(): boolean {
- return (
- this.hsConfig.apps.default.useProxy === undefined ||
- this.hsConfig.apps.default.useProxy
- );
- }
- }
|