Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use context for all converters (and not only Feature2Mesh) #2196

Merged
merged 2 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"FeatureBuildingOptions",
"Style",
"StyleOptions",
"StyleContext",
"Label"
],

Expand Down
44 changes: 2 additions & 42 deletions src/Converter/Feature2Mesh.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,50 +7,10 @@ import Extent from 'Core/Geographic/Extent';
import Crs from 'Core/Geographic/Crs';
import OrientationUtils from 'Utils/OrientationUtils';
import Coordinates from 'Core/Geographic/Coordinates';
import { StyleContext } from 'Core/Style';

const coord = new Coordinates('EPSG:4326', 0, 0, 0);

class FeatureContext {
#worldCoord = new Coordinates('EPSG:4326', 0, 0, 0);
#localCoordinates = new Coordinates('EPSG:4326', 0, 0, 0);
#isProjected = true;
#geometry = {};

constructor() {
this.globals = {};
}

setGeometry(g) {
this.#geometry = g;
}

setCollection(c) {
this.collection = c;
this.#localCoordinates.setCrs(c.crs);
}

setLocalCoordinatesFromArray(vertices, offset) {
this.#isProjected = false;
return this.#localCoordinates.setFromArray(vertices, offset);
}

get properties() {
return this.#geometry.properties;
}

get coordinates() {
if (!this.#isProjected) {
this.#isProjected = true;
this.#worldCoord.copy(this.#localCoordinates).applyMatrix4(this.collection.matrixWorld);
if (this.#localCoordinates.crs == 'EPSG:4978') {
return this.#worldCoord.as('EPSG:4326', this.#worldCoord);
}
}
return this.#worldCoord;
}
}

const context = new FeatureContext();
const context = new StyleContext();

const dim_ref = new THREE.Vector2();
const dim = new THREE.Vector2();
Expand Down
19 changes: 11 additions & 8 deletions src/Converter/Feature2Texture.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import * as THREE from 'three';
import { FEATURE_TYPES } from 'Core/Feature';
import Extent from 'Core/Geographic/Extent';
import Coordinates from 'Core/Geographic/Coordinates';
import Style from 'Core/Style';
import Style, { StyleContext } from 'Core/Style';

const context = new StyleContext();

/**
* Draw polygon (contour, line edge and fill) based on feature vertices into canvas
Expand Down Expand Up @@ -74,16 +76,10 @@ const coord = new Coordinates('EPSG:4326', 0, 0, 0);
function drawFeature(ctx, feature, extent, style, invCtxScale) {
const extentDim = extent.planarDimensions();
const scaleRadius = extentDim.x / ctx.canvas.width;
const globals = {
fill: true,
stroke: true,
point: true,
zoom: extent.zoom,
};

for (const geometry of feature.geometries) {
if (Extent.intersectsExtent(geometry.extent, extent)) {
const context = { globals, properties: () => geometry.properties };
context.setGeometry(geometry);
const contextStyle = (geometry.properties.style || style).applyContext(context);

if (contextStyle) {
Expand Down Expand Up @@ -172,6 +168,13 @@ export default {
// to scale line width and radius circle
const invCtxScale = Math.abs(1 / scale.x);

context.globals = {
fill: true,
stroke: true,
point: true,
zoom: extent.zoom,
};

// Draw the canvas
for (const feature of collection.features) {
drawFeature(ctx, feature, featureExtent, feature.style || style, invCtxScale);
Expand Down
63 changes: 62 additions & 1 deletion src/Core/Style.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Fetcher from 'Provider/Fetcher';
import * as mapbox from '@mapbox/mapbox-gl-style-spec';
import { Color } from 'three';
import { deltaE } from 'Renderer/Color';
import Coordinates from 'Core/Geographic/Coordinates';

import itowns_stroke_single_before from './StyleChunk/itowns_stroke_single_before.css';

Expand Down Expand Up @@ -160,6 +161,66 @@ function defineStyleProperty(style, category, name, value, defaultValue) {
style[category][name] = value;
}

/**
* @class
* @classdesc StyleContext stores metadata of one FeatureGeometry that are needed for its style computation:
* type of feature and what is needed (fill, stroke or draw a point, etc.) as well as where to get its
* properties and its coordinates (for base_altitude).
*
* @property {Object} globals Style type (fill, stroke, point, text and or icon) to consider, it also
* contains the current zoom.
* @property {Object} collection The FeatureCollection to which the FeatureGeometry is attached
* @property {Coordinates} coordinates The coordinates (in world space) of the last vertex (x, y, z) set with
* setLocalCoordinatesFromArray().
* private properties:
* @property {Coordinates} worldCoord @private Coordinates object to store coordinates in world space.
* @property {Coordinates} localCoordinates @private Coordinates object to store coordinates in local space.
* @property {boolean} worldCoordsComputed @private Have the world coordinates already been computed
* from the local coordinates?
* @property {FeatureGeometry} geometry @private The FeatureGeometry to compute the style.
*/
export class StyleContext {
#worldCoord = new Coordinates('EPSG:4326', 0, 0, 0);
#localCoordinates = new Coordinates('EPSG:4326', 0, 0, 0);
#worldCoordsComputed = true;
#geometry = {};
/**
* @constructor
*/
constructor() {
this.globals = {};
}

setGeometry(g) {
this.#geometry = g;
}

setCollection(c) {
this.collection = c;
this.#localCoordinates.setCrs(c.crs);
}

setLocalCoordinatesFromArray(vertices, offset) {
this.#worldCoordsComputed = false;
return this.#localCoordinates.setFromArray(vertices, offset);
}

get properties() {
return this.#geometry.properties;
}

get coordinates() {
if (!this.#worldCoordsComputed) {
this.#worldCoordsComputed = true;
this.#worldCoord.copy(this.#localCoordinates).applyMatrix4(this.collection.matrixWorld);
if (this.#localCoordinates.crs == 'EPSG:4978') {
return this.#worldCoord.as('EPSG:4326', this.#worldCoord);
}
}
return this.#worldCoord;
}
}

/**
* @typedef {Object} StyleOptions
* @memberof StyleOptions
Expand Down Expand Up @@ -986,7 +1047,7 @@ class Style {
if (this.text.field.expression) {
return readExpression(this.text.field, ctx);
} else {
return this.text.field.replace(/\{(.+?)\}/g, (a, b) => (ctx.properties()[b] || '')).trim();
return this.text.field.replace(/\{(.+?)\}/g, (a, b) => (ctx.properties[b] || '')).trim();
}
}
}
Expand Down
9 changes: 6 additions & 3 deletions src/Layer/LabelLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import Coordinates from 'Core/Geographic/Coordinates';
import Extent from 'Core/Geographic/Extent';
import Label from 'Core/Label';
import { FEATURE_TYPES } from 'Core/Feature';
import { readExpression } from 'Core/Style';
import { readExpression, StyleContext } from 'Core/Style';
import { ScreenGrid } from 'Renderer/Label2DRenderer';

const context = new StyleContext();

const coord = new Coordinates('EPSG:4326', 0, 0, 0);

const _extent = new Extent('EPSG:4326', 0, 0, 0, 0);
Expand Down Expand Up @@ -240,7 +242,7 @@ class LabelLayer extends GeometryLayer {
// Converting the extent now is faster for further operation
extent.as(data.crs, _extent);
coord.crs = data.crs;
const globals = {
context.globals = {
jailln marked this conversation as resolved.
Show resolved Hide resolved
icon: true,
text: true,
zoom: extent.zoom,
Expand Down Expand Up @@ -271,8 +273,9 @@ class LabelLayer extends GeometryLayer {
if (!_extent.isPointInside(coord)) { return; }

const geometryField = g.properties.style && g.properties.style.text.field;

context.setGeometry(g);
let content;
const context = { globals, properties: () => g.properties };
if (this.labelDomelement) {
content = readExpression(this.labelDomelement, context);
} else if (!geometryField && !featureField && !layerField) {
Expand Down