Skip to content

Commit

Permalink
Merge pull request #96 from geo-engine/visual-point-clustering
Browse files Browse the repository at this point in the history
use clustering symbology as default
  • Loading branch information
michaelmattig authored Aug 27, 2021
2 parents 370c272 + 32c1c53 commit 82a1d81
Show file tree
Hide file tree
Showing 11 changed files with 356 additions and 60 deletions.
13 changes: 13 additions & 0 deletions projects/wave-core-new/src/lib/backend/operator.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,16 @@ export interface TemporalRasterAggregationDict extends OperatorDict {
};
};
}

export interface VisualPointClusteringParams extends OperatorParams {
minRadiusPx: number;
deltaPx: number;
radiusColumn: string;
countColumn: string;
columnAggregates: {
[columnName: string]: {
columnName: string;
aggregateType: 'meanNumber' | 'stringSample' | 'null';
};
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ import {FormGroup, FormControl, Validators} from '@angular/forms';
import {GeoEngineError, RasterResultDescriptorDict, UUID, VectorResultDescriptorDict} from '../../backend/backend.model';
import {colorToDict} from '../../colors/color';
import {RasterLayer, VectorLayer} from '../../layers/layer.model';
import {LineSymbology, PointSymbology, PolygonSymbology, RasterSymbology, VectorSymbology} from '../../layers/symbology/symbology.model';
import {
ClusteredPointSymbology,
LineSymbology,
PointSymbology,
PolygonSymbology,
RasterSymbology,
VectorSymbology,
} from '../../layers/symbology/symbology.model';
import {NotificationService} from '../../notification.service';
import {ProjectService} from '../../project/project.service';
import {isValidUuid} from '../../util/form.validators';
Expand Down Expand Up @@ -70,9 +77,9 @@ export class AddWorkflowComponent implements OnInit {
// TODO: cope with that
throw Error('we cannot add data layers here, yet');
case 'MultiPoint':
return PointSymbology.fromPointSymbologyDict({
return ClusteredPointSymbology.fromPointSymbologyDict({
type: 'point',
radius: {type: 'static', value: 10},
radius: {type: 'static', value: PointSymbology.DEFAULT_POINT_RADIUS},
stroke: {
width: {type: 'static', value: 1},
color: {type: 'static', color: [0, 0, 0, 255]},
Expand Down
13 changes: 10 additions & 3 deletions projects/wave-core-new/src/lib/datasets/dataset.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@ import {
} from '../backend/backend.model';
import {RandomColorService} from '../util/services/random-color.service';
import {RasterLayer, VectorLayer} from '../layers/layer.model';
import {LineSymbology, PointSymbology, PolygonSymbology, RasterSymbology, VectorSymbology} from '../layers/symbology/symbology.model';
import {
ClusteredPointSymbology,
LineSymbology,
PointSymbology,
PolygonSymbology,
RasterSymbology,
VectorSymbology,
} from '../layers/symbology/symbology.model';
import {VectorDataTypes} from '../operators/datatype.model';
import {colorToDict} from '../colors/color';
import {ProjectService} from '../project/project.service';
Expand Down Expand Up @@ -114,11 +121,11 @@ export class DatasetService {
case VectorDataTypes.MultiPoint:
symbology = (dataset.symbology as PointSymbology)
? (dataset.symbology as PointSymbology)
: PointSymbology.fromPointSymbologyDict({
: ClusteredPointSymbology.fromPointSymbologyDict({
type: 'point',
radius: {
type: 'static',
value: 10,
value: PointSymbology.DEFAULT_POINT_RADIUS,
},
stroke: {
width: {
Expand Down
18 changes: 12 additions & 6 deletions projects/wave-core-new/src/lib/layers/layer-metadata.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,17 @@ import {
import * as Immutable from 'immutable';
import {Measurement} from './measurement';
import {ResultType, ResultTypes} from '../operators/result-type.model';
import {SpatialReference} from '../spatial-references/spatial-reference.model';

export abstract class LayerMetadata implements HasLayerType {
abstract readonly layerType: LayerType;
readonly spatialReference: SpatialReference;

public abstract get resultType(): ResultType;

constructor(spatialReference: SpatialReference) {
this.spatialReference = spatialReference;
}
}

export class VectorLayerMetadata extends LayerMetadata {
Expand All @@ -24,8 +30,8 @@ export class VectorLayerMetadata extends LayerMetadata {
readonly dataType: VectorDataType;
readonly columns: Immutable.Map<string, VectorColumnDataType>;

constructor(dataType: VectorDataType, columns: {[index: string]: VectorColumnDataType}) {
super();
constructor(dataType: VectorDataType, spatialReference: SpatialReference, columns: {[index: string]: VectorColumnDataType}) {
super(spatialReference);

this.dataType = dataType;
this.columns = Immutable.Map(columns);
Expand All @@ -39,7 +45,7 @@ export class VectorLayerMetadata extends LayerMetadata {
columns[columnName] = VectorColumnDataTypes.fromCode(dict.columns[columnName]);
}

return new VectorLayerMetadata(dataType, columns);
return new VectorLayerMetadata(dataType, SpatialReference.fromSrsString(dict.spatialReference), columns);
}

public get resultType(): ResultType {
Expand All @@ -53,8 +59,8 @@ export class RasterLayerMetadata extends LayerMetadata {
readonly dataType: RasterDataType;
readonly measurement: Measurement;

constructor(dataType: RasterDataType, measurement: Measurement) {
super();
constructor(dataType: RasterDataType, spatialReference: SpatialReference, measurement: Measurement) {
super(spatialReference);

this.dataType = dataType;
this.measurement = measurement;
Expand All @@ -64,7 +70,7 @@ export class RasterLayerMetadata extends LayerMetadata {
const dataType = RasterDataTypes.fromCode(dict.dataType);
const measurement = Measurement.fromDict(dict.measurement);

return new RasterLayerMetadata(dataType, measurement);
return new RasterLayerMetadata(dataType, SpatialReference.fromSrsString(dict.spatialReference), measurement);
}

public get resultType(): ResultType {
Expand Down
79 changes: 77 additions & 2 deletions projects/wave-core-new/src/lib/layers/symbology/symbology.model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Color, colorToDict, RgbaTuple, rgbaColorFromDict} from '../../colors/color';
import {Color, colorToDict, RgbaTuple, rgbaColorFromDict, WHITE, BLACK} from '../../colors/color';
import {Feature as OlFeature} from 'ol';
import {
ColorParamDict,
Expand Down Expand Up @@ -89,7 +89,11 @@ export abstract class Symbology {
export abstract class VectorSymbology extends Symbology {
static fromVectorSymbologyDict(dict: VectorSymbologyDict): VectorSymbology {
if (dict.type === 'point') {
return PointSymbology.fromPointSymbologyDict(dict);
if (dict.radius.type === 'derived' && dict.radius.attribute === ClusteredPointSymbology.RADIUS_COLUMN) {
return ClusteredPointSymbology.fromPointSymbologyDict(dict);
} else {
return PointSymbology.fromPointSymbologyDict(dict);
}
} else if (dict.type === 'line') {
return LineSymbology.fromLineSymbologyDict(dict);
} else if (dict.type === 'polygon') {
Expand Down Expand Up @@ -314,6 +318,8 @@ export class TextStyler extends Styler {
}

export class PointSymbology extends VectorSymbology {
static readonly DEFAULT_POINT_RADIUS = 10;

// TODO: visiblity
radius: NumberParam;
fillColor: ColorParam;
Expand Down Expand Up @@ -390,6 +396,75 @@ export class PointSymbology extends VectorSymbology {
}
}

export class ClusteredPointSymbology extends VectorSymbology {
static readonly RADIUS_COLUMN = '___radius';
static readonly COUNT_COLUMN = '___count';
static readonly DELTA_PX = 1;

// TODO: visiblity

readonly fillColor: ColorParam;
readonly stroke: Stroke;

readonly radius = new DerivedNumber(ClusteredPointSymbology.RADIUS_COLUMN, 1, PointSymbology.DEFAULT_POINT_RADIUS);
readonly text = new TextSymbology(
ClusteredPointSymbology.COUNT_COLUMN,
new StaticColor(WHITE),
new Stroke(new StaticNumber(1), new StaticColor(BLACK)),
);

constructor(fillColor: ColorParam, stroke: Stroke) {
super();
this.fillColor = fillColor;
this.stroke = stroke;
}

static fromPointSymbologyDict(dict: PointSymbologyDict): ClusteredPointSymbology {
// we ignore anything that is stored for radius and text
return new ClusteredPointSymbology(ColorParam.fromDict(dict.fillColor), Stroke.fromDict(dict.stroke));
}

createStyler(feature: OlFeature): PointStyler {
return new PointStyler(
this.radius.getNumber(feature),
this.fillColor.getColor(feature).rgbaTuple(),
this.stroke.createStyler(feature),
(this.text.createStyler(feature) as unknown) as TextStyler,
);
}

equals(other: ClusteredPointSymbology): boolean {
return other instanceof ClusteredPointSymbology && this.fillColor.equals(other.fillColor) && this.stroke.equals(other.stroke);
}

clone(): ClusteredPointSymbology {
return new ClusteredPointSymbology(this.fillColor.clone(), this.stroke.clone());
}

toDict(): SymbologyDict {
return {
type: 'point',
radius: this.radius.toDict(),
fillColor: this.fillColor.toDict(),
stroke: this.stroke.toDict(),
text: this.text ? this.text.toDict() : undefined,
};
}

getSymbologyType(): SymbologyType {
return SymbologyType.POINT;
}

getIconStyle(): PointIconStyle {
return {
strokeWidth: this.stroke.width.getDefault(),
// strokeDashStyle: StrokeDashStyle;
strokeRGBA: this.stroke.color.getDefault(),
fillRGBA: this.fillColor.getDefault(),
};
}
}

export class LineSymbology extends VectorSymbology {
stroke: Stroke;
text?: TextSymbology;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@
</wave-dialog-help>

<mat-accordion multi="true">
<!-- For points -->
<mat-expansion-panel expanded="true" *ngIf="isPointLayer">
<mat-expansion-panel-header>
<mat-panel-title fxLayoutAlign="space-between center" fxLayoutGap="0.5rem">
<mat-icon>map</mat-icon>
<span fxFlex>Symbology Type</span>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<mat-slide-toggle [checked]="isClustered" (change)="setClusterSymbology($event.checked)"
>Visually clustered points</mat-slide-toggle
>
</ng-template>
</mat-expansion-panel>

<!-- For points and polygons -->
<mat-expansion-panel expanded="true" *ngIf="showFillColorEditor">
<mat-expansion-panel-header>
Expand Down
Loading

0 comments on commit 82a1d81

Please sign in to comment.