Skip to content

Commit

Permalink
Merge pull request #123 from chrisvpeters/AUS-3960-A
Browse files Browse the repository at this point in the history
AUS-3960
  • Loading branch information
jia020 committed Dec 12, 2023
2 parents 08b2baa + 80b0755 commit 28e9e9e
Show file tree
Hide file tree
Showing 6 changed files with 309 additions and 1 deletion.
2 changes: 2 additions & 0 deletions projects/portal-core-ui/src/lib/portal-core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { CsWMSService } from './service/wms/cs-wms.service';
import { CsWFSService } from './service/wfs/cs-wfs.service';
import { CsIrisService } from './service/kml/cs-iris.service';
import { CsKMLService } from './service/kml/cs-kml.service';
import { CsVMFService } from './service/vmf/cs-vmf.service';
import { KMLDocService } from './service/kml/kml.service';
import { DownloadIrisService } from './service/kml/download-iris.service';
import { GMLParserService } from './utility/gmlparser.service';
Expand Down Expand Up @@ -50,6 +51,7 @@ import { PolygonsEditorService } from '@auscope/angular-cesium';
CsWMSService,
CsIrisService,
CsKMLService,
CsVMFService,
KMLDocService,
CsMapObject,
CsWFSService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { CsWMSService } from '../wms/cs-wms.service';
import { ResourceType } from '../../utility/constants.service';
import { CsIrisService } from '../kml/cs-iris.service';
import { CsKMLService } from '../kml/cs-kml.service';
import { CsVMFService } from '../vmf/cs-vmf.service';
import { MapsManagerService, RectangleEditorObservable, EventRegistrationInput, CesiumEvent, EventResult } from '@auscope/angular-cesium';
import { Entity, ProviderViewModel, buildModuleUrl, OpenStreetMapImageryProvider, BingMapsStyle, BingMapsImageryProvider,
ArcGisMapServerImageryProvider, TileMapServiceImageryProvider, Cartesian2, WebMercatorProjection, SplitDirection } from 'cesium';
Expand Down Expand Up @@ -40,6 +41,7 @@ export class CsMapService {
private csMapObject: CsMapObject, private manageStateService: ManageStateService,
private csCSWService: CsCSWService, private csIrisService: CsIrisService,
private csKMLService: CsKMLService, private mapsManagerService: MapsManagerService,
private csVMFService: CsVMFService,
@Inject('env') private env, @Inject('conf') private conf) {
this.csMapObject.registerClickHandler(this.mapClickHandler.bind(this));
this.addLayerSubject = new Subject<LayerModel>();
Expand Down Expand Up @@ -194,7 +196,7 @@ export class CsMapService {
* @returns a list of supported OnlineResource types as strings
*/
public getSupportedOnlineResourceTypes(): ResourceType[] {
return [ResourceType.WMS, ResourceType.IRIS, ResourceType.KML, ResourceType.KMZ];
return [ResourceType.WMS, ResourceType.IRIS, ResourceType.KML, ResourceType.KMZ, ResourceType.VMF];
}

/**
Expand Down Expand Up @@ -240,6 +242,10 @@ export class CsMapService {
// Add an IRIS layer
this.csIrisService.addLayer(layer, param);
this.cacheLayerModelList(layer);
} else if (UtilitiesService.layerContainsResourceType(layer, ResourceType.VMF)) {
// Add a WMS layer to map
this.csVMFService.addLayer(layer, param);
this.cacheLayerModelList(layer);
} else if (UtilitiesService.layerContainsResourceType(layer, ResourceType.KMZ)) {
// Add a WMS layer to map
this.csKMLService.addLayer(layer, param);
Expand Down Expand Up @@ -318,6 +324,8 @@ export class CsMapService {
this.csCSWService.rmLayer(layer);
} else if (UtilitiesService.layerContainsResourceType(layer, ResourceType.IRIS)) {
this.csIrisService.rmLayer(layer);
} else if (UtilitiesService.layerContainsResourceType(layer, ResourceType.VMF)) {
this.csVMFService.rmLayer(layer);
} else if (UtilitiesService.layerContainsResourceType(layer, ResourceType.KML)) {
this.csKMLService.rmLayer(layer);
} else if (UtilitiesService.layerContainsResourceType(layer, ResourceType.KMZ)) {
Expand Down
252 changes: 252 additions & 0 deletions projects/portal-core-ui/src/lib/service/vmf/cs-vmf.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@

import { throwError as observableThrowError, Observable } from 'rxjs';
import { Inject, Injectable } from '@angular/core';
import { HttpClient, HttpParams, HttpHeaders, HttpResponse } from '@angular/common/http';
import { catchError, map } from 'rxjs/operators';

import { OnlineResourceModel } from '../../model/data/onlineresource.model';
import { LayerModel } from '../../model/data/layer.model';
import { LayerHandlerService } from '../cswrecords/layer-handler.service';
import { MapsManagerService } from '@auscope/angular-cesium';
import { ResourceType } from '../../utility/constants.service';
import { RenderStatusService } from '../cesium-map/renderstatus/render-status.service';
import { VMFDocService } from './vmf.service';
import { UtilitiesService } from '../../utility/utilities.service';

// NB: Cannot use "import { XXX, YYY, ZZZ, Color } from 'cesium';" - it prevents initialising ContextLimits.js properly
// which causes a 'DeveloperError' when trying to draw the VMF
declare var Cesium;

/**
* Use Cesium to add layer to map. This service class adds VMF layer to the map
*/
@Injectable()
export class CsVMFService {

// List of VMF layers that have been cancelled
private cancelledLayers: Array<string> = [];
// Number of VMF resources added for a given layer
private numberOfResourcesAdded: Map<string, number> = new Map<string, number>();

constructor(private layerHandlerService: LayerHandlerService,
private http: HttpClient,
private renderStatusService: RenderStatusService,
private mapsManagerService: MapsManagerService,
private vmfService: VMFDocService,
@Inject('env') private env) {
}

/**
* Downloads geojson that is cropped to polygon
*
* @param vmfResource VMF resource to be fetched
* @returns VMF geojson text
*/
private getVMFFeature(url: string, polygon: string): Observable<any> {
/*
const body =
{
"maps": "territories",
"polygon_geojson": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[[111.64, -17.61], [132.45, -8.23], [146.26, -10.53], [159.37, -24.57], [147.95, -45.25], [110.29, -34.29]]
]
}
}
]
}
};
*/
const body=
{
"maps": "territories",
"polygon_geojson": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [JSON.parse(polygon)]
}
}
]
}
};
return this.http.post(url, body, {
headers: new HttpHeaders().set('Content-Type', 'application/json'),
responseType: 'text'
}).pipe(map(response => {
return response;
}), catchError((error: HttpResponse<any>) => {
return observableThrowError(error);
}),);

}

/**
* Add the VMF layer
* @param layer the VMF layer to add to the map
* @param param parameters for the VMF layer
*/
public addLayer(layer: LayerModel, param?: any): void {
// Remove from cancelled layer list (if present)
this.cancelledLayers = this.cancelledLayers.filter(l => l !== layer.id);

let vmfOnlineResources: OnlineResourceModel[];

if (UtilitiesService.layerContainsResourceType(layer, ResourceType.VMF)) {
vmfOnlineResources = this.layerHandlerService.getOnlineResources(layer, ResourceType.VMF);
}
const me = this;

// Get CesiumJS viewer
const viewer = this.getViewer();
const options = {
camera: viewer.scene.camera,
canvas: viewer.scene.canvas,
};

for (const onlineResource of vmfOnlineResources) {
// Tell UI that we're about to add a resource to map
this.renderStatusService.addResource(layer, onlineResource);

// Create data source
const source = new Cesium.GeoJsonDataSource(options);
// Add an event to tell us when loading is finished
source.loadingEvent.addEventListener((evt, isLoading: boolean) => {
if (!isLoading) {
// Tell UI that we have completed updating the map
me.renderStatusService.updateComplete(layer, onlineResource);
}
});

if (!this.numberOfResourcesAdded.get(layer.id)) {
this.numberOfResourcesAdded.set(layer.id, 0);
}

if (UtilitiesService.layerContainsResourceType(layer, ResourceType.VMF)) {
// add VMF to map

//const proxyUrl = this.env.portalBaseUrl + "getViaProxy.do?usewhitelist=false&url=" + onlineResource.url;
//const proxyUrl = "https://portal.auscope.org.au/" + "getViaProxy.do?usewhitelist=false&url=" + onlineResource.url;
const proxyUrl = onlineResource.url;
const polygon = layer["geojson"]["polygon"];
var polygonStr = "[";
var delim = ",";
var i = 0;
for (const coord of polygon) {
const lon = coord[0];
const lat = coord[1];
if (i == (polygon.length-1)) { delim = ""; }
polygonStr = polygonStr + "["+lon+","+lat+"]"+delim;
i = i + 1;
}
polygonStr = polygonStr + "]";
this.getVMFFeature(proxyUrl,polygonStr).subscribe(geojsonTxt => {
// make a geojson features collection
let fcTxt = '{"type": "FeatureCollection","features":' + geojsonTxt + '}';
let geojson = JSON.parse(fcTxt);

source.load(geojson).then(dataSource => {
if (this.cancelledLayers.indexOf(layer.id) === -1) {
viewer.dataSources.add(dataSource).then(dataSrc => {

//Get the array of entities
const entities = dataSource.entities.values;

for (let i = 0; i < entities.length; i++) {
//For each entity (polygon), get the colour property and make the polygon that colour
const entity = entities[i];
const properties = entity.properties;
const color = properties.color;
let value = color._value;
// remake the color as a hex string (RGB) with opactiy first
value = "0x40" + value.substring(5,7)+value.substring(3,5)+value.substring(1,3);
var cesiumColor = Cesium.Color.fromRgba(value);
//Set the polygon material to our color.
entity.polygon.material = cesiumColor;
//Remove the outlines.
entity.polygon.outline = false;
//Extrude the polygon
entity.polygon.extrudedHeight = 1.0;
}

layer.csLayers.push(dataSrc);
this.incrementLayersAdded(layer, vmfOnlineResources.length);
}, (err) => {
console.error('Unable to add viewer.dataSources VMF: ', err);
});
}
}, (err) => {
console.error('Unable to load source.load VMF: ', err);
});
}, (err) => {
alert('Unable to load VMF: ' + err.message);
console.error('Unable to load VMF: ', err);
// Tell UI that we have completed updating the map & there was an error
this.renderStatusService.updateComplete(layer, onlineResource, true);
this.incrementLayersAdded(layer, vmfOnlineResources.length);
});

}

}
}

/**
* Increment the number of layers added for a given LayerModel, and clear the layer from the
* cancelled layer list if all layers have been added
* @param layer the LayerModel
* @param totalLayers total number of layers for LayerModel
*/
private incrementLayersAdded(layer: LayerModel, totalLayers: number) {
this.numberOfResourcesAdded.set(layer.id, this.numberOfResourcesAdded.get(layer.id) + 1);
if (this.numberOfResourcesAdded.get(layer.id) === totalLayers) {
this.cancelledLayers = this.cancelledLayers.filter(l => l !== layer.id);
}
}

/**
* Request cancellation of layer if it's still being added
* @param layerId ID of layer
*/
public cancelLayerAdded(layerId: string) {
if (this.cancelledLayers.indexOf(layerId) === -1) {
this.cancelledLayers.push(layerId);
}
}

/**
* Removes VMF layer from the map
* @method rmLayer
* @param layer the VMF layer to remove from the map.
*/
public rmLayer(layer: LayerModel): void {
// Request cancellation of layer if it's still being added
this.cancelLayerAdded(layer.id);

const viewer = this.getViewer();
for (const dataSrc of layer.csLayers) {
viewer.dataSources.remove(dataSrc);
}
layer.csLayers = [];
this.renderStatusService.resetLayer(layer.id);
}

/**
* Fetches Cesium 'Viewer'
*/
private getViewer() {
return this.mapsManagerService.getMap().getCesiumViewer();
}

}
44 changes: 44 additions & 0 deletions projects/portal-core-ui/src/lib/service/vmf/vmf.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Injectable, Inject } from '@angular/core';

/**
* This service class contains functions used for manipulating VMF documents
*/
@Injectable({
providedIn: 'root'
})
export class VMFDocService {

constructor(@Inject('env') private env) { }

/**
* Clean VMF text by removing illegal chars and
* forcing proxying of icon images to avoid CORS errors
*
* @param vmfTxt VMF text to be cleaned
* @returns clean VMF string
*/
public cleanVMF(vmfTxt: string): string {
// Removes non-standard chars that can cause errors
vmfTxt = vmfTxt.replace(/\016/g, '');
vmfTxt = vmfTxt.replace(/\002/g, '');
// Inserts local paddle image to avoid CORS errors
// Cesium does not load proxied images for some as yet unknown reason
vmfTxt = vmfTxt.replace(/<Icon>\s*<href>.*<\/href>/g,
'<Icon>\n<href>extension/images/white-paddle.png</href>');
return vmfTxt;
}

/**
* Clean VMF text by removing illegal chars
* future: when cesium support proxying of images
*
* @param vmfTxt VMF text to be cleaned
* @returns clean VMF string
*/
public cleanKMZ(vmfTxt: string): string {
// Removes non-standard chars that can cause errors
vmfTxt = vmfTxt.replace(/\016/g, '');
vmfTxt = vmfTxt.replace(/\002/g, '');
return vmfTxt;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export enum ResourceType {
OTHERS = 'OTHERS',
SOS = "SOS",
UNSUPPORTED = 'Unsupported',
VMF = "VMF",
WMS = "WMS",
WFS = "WFS",
WCS = "WCS",
Expand Down
1 change: 1 addition & 0 deletions projects/portal-core-ui/src/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export { QueryWMSService } from './lib/service/wms/query-wms.service';
export { CsWWWService } from './lib/service/www/cs-www.service';
export { CsIrisService } from './lib/service/kml/cs-iris.service';
export { CsKMLService } from './lib/service/kml/cs-kml.service';
export { CsVMFService } from './lib/service/vmf/cs-vmf.service';
export { DownloadIrisService } from './lib/service/kml/download-iris.service';
export { KMLDocService } from './lib/service/kml/kml.service';

Expand Down

0 comments on commit 28e9e9e

Please sign in to comment.