Skip to content

Commit

Permalink
refactor(Style): Style hierachisation in Layer.Style instanciation
Browse files Browse the repository at this point in the history
  • Loading branch information
ftoromanoff committed Dec 13, 2023
1 parent 565dd63 commit 55849f6
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 311 deletions.
54 changes: 26 additions & 28 deletions src/Converter/Feature2Mesh.js
Expand Up @@ -11,6 +11,8 @@ import Style, { StyleContext } from 'Core/Style';

const coord = new Coordinates('EPSG:4326', 0, 0, 0);
const context = new StyleContext();
const defaultStyle = new Style();
let style;

const dim_ref = new THREE.Vector2();
const dim = new THREE.Vector2();
Expand Down Expand Up @@ -193,7 +195,6 @@ function featureToPoint(feature, options) {
normal.set(0, 0, 1).multiply(inverseScale);

const pointMaterialSize = [];
context.globals = { point: true };
context.setFeature(feature);

for (const geometry of feature.geometries) {
Expand All @@ -209,7 +210,7 @@ function featureToPoint(feature, options) {
}

coord.copy(context.setLocalCoordinatesFromArray(feature.vertices, v));
const style = Style.applyContext(context);
style.setContext(context);
const { base_altitude, color, radius } = style.point;
coord.z = 0;

Expand Down Expand Up @@ -253,7 +254,6 @@ function featureToLine(feature, options) {
geom.setAttribute('position', new THREE.BufferAttribute(vertices, 3));

const lineMaterialWidth = [];
context.globals = { stroke: true };
context.setFeature(feature);

const countIndices = (count - feature.geometries.length) * 2;
Expand Down Expand Up @@ -290,7 +290,7 @@ function featureToLine(feature, options) {
}

coord.copy(context.setLocalCoordinatesFromArray(feature.vertices, v));
const style = Style.applyContext(context);
style.setContext(context);
const { base_altitude, color, width } = style.stroke;
coord.z = 0;

Expand Down Expand Up @@ -323,7 +323,6 @@ function featureToPolygon(feature, options) {

const batchIds = new Uint32Array(vertices.length / 3);
const batchId = options.batchId || ((p, id) => id);
context.globals = { fill: true };
context.setFeature(feature);

inverseScale.setFromMatrixScale(context.collection.matrixWorldInverse);
Expand Down Expand Up @@ -352,7 +351,7 @@ function featureToPolygon(feature, options) {
}

coord.copy(context.setLocalCoordinatesFromArray(feature.vertices, i));
const style = Style.applyContext(context);
style.setContext(context);
const { base_altitude, color } = style.fill;
coord.z = 0;

Expand Down Expand Up @@ -412,7 +411,6 @@ function featureToExtrudedPolygon(feature, options) {

let featureId = 0;

context.globals = { fill: true };
context.setFeature(feature);
inverseScale.setFromMatrixScale(context.collection.matrixWorldInverse);
normal.set(0, 0, 1).multiply(inverseScale);
Expand All @@ -439,7 +437,7 @@ function featureToExtrudedPolygon(feature, options) {

coord.copy(context.setLocalCoordinatesFromArray(ptsIn, i));

const style = Style.applyContext(context);
style.setContext(context);
const { base_altitude, extrusion_height, color } = style.fill;
coord.z = 0;

Expand Down Expand Up @@ -529,13 +527,12 @@ function createInstancedMesh(mesh, count, ptsIn) {
* Convert a [Feature]{@link Feature} of type POINT to a Instanced meshes
*
* @param {Object} feature
* @param {Object} options - options controlling the conversion
* @returns {THREE.Mesh} mesh or GROUP of THREE.InstancedMesh
*/
function pointsToInstancedMeshes(feature, options) {
function pointsToInstancedMeshes(feature) {
const ptsIn = feature.vertices;
const count = feature.geometries.length;
const modelObject = options.layer.style.point.model.object;
const modelObject = style.point.model.object;

if (modelObject instanceof THREE.Mesh) {
return createInstancedMesh(modelObject, count, ptsIn);
Expand All @@ -552,9 +549,9 @@ function pointsToInstancedMeshes(feature, options) {

/**
* Convert a [Feature]{@link Feature} to a Mesh
*
* @param {Feature} feature - the feature to convert
* @param {Object} options - options controlling the conversion
*
* @return {THREE.Mesh} mesh or GROUP of THREE.InstancedMesh
*/
function featureToMesh(feature, options) {
Expand All @@ -565,9 +562,9 @@ function featureToMesh(feature, options) {
let mesh;
switch (feature.type) {
case FEATURE_TYPES.POINT:
if (options.layer?.style?.point?.model?.object) {
if (style.point?.model?.object) {
try {
mesh = pointsToInstancedMeshes(feature, options);
mesh = pointsToInstancedMeshes(feature);
mesh.isInstancedMesh = true;
} catch (e) {
mesh = featureToPoint(feature, options);
Expand All @@ -580,7 +577,7 @@ function featureToMesh(feature, options) {
mesh = featureToLine(feature, options);
break;
case FEATURE_TYPES.POLYGON:
if (options.layer?.style?.fill.extrusion_height) {
if (style.fill && Object.keys(style.fill).includes('extrusion_height')) {
mesh = featureToExtrudedPolygon(feature, options);
} else {
mesh = featureToPolygon(feature, options);
Expand All @@ -595,10 +592,6 @@ function featureToMesh(feature, options) {
}
mesh.feature = feature;

if (options.layer) {
mesh.layer = options.layer;
}

return mesh;
}

Expand All @@ -614,6 +607,8 @@ export default {
* @param {function} [options.batchId] - optional function to create batchId attribute.
* It is passed the feature property and the feature index. As the batchId is using an unsigned int structure on 32 bits,
* the batchId could be between 0 and 4,294,967,295.
* @param {StyleOptions} [options.style] - optional style properties. Only needed if the convert is used without instancing
* a layer beforehand.
* @return {function}
* @example <caption>Example usage of batchId with featureId.</caption>
* view.addLayer({
Expand Down Expand Up @@ -646,25 +641,28 @@ export default {

if (!options.pointMaterial) {
// Opacity and wireframe refered with layer properties
// TODO :next step is move these properties to Style
// TODO: next step is move these properties to Style
options.pointMaterial = ReferLayerProperties(new THREE.PointsMaterial(), this);
options.lineMaterial = ReferLayerProperties(new THREE.LineBasicMaterial(), this);
options.polygonMaterial = ReferLayerProperties(new THREE.MeshBasicMaterial(), this);
// options.layer.style will be used later on to define the final style.
// In the case we didn't instanciate the layer before the convert, we can directly
// pass a style using options.style.
// This is usually done in some tests and if you want to use Feature2Mesh.convert()
// as in examples/source_file_gpx_3d.html.
options.layer = this || { style: options.style };
}
context.layerStyle = options.layer.style;

// In the case we didn't instanciate the layer (this) before the convert, we can pass
// style properties (@link StyleOptions) using options.style.
// This is usually done in some tests and if you want to use Feature2Mesh.convert()
// as in examples/source_file_gpx_3d.html.
style = this?.style || (options.style ? new Style(options.style) : defaultStyle);

context.setCollection(collection);

const features = collection.features;
if (!features || features.length == 0) { return; }

const meshes = features.map(feature => featureToMesh(feature, options));
const meshes = features.map((feature) => {
const mesh = featureToMesh(feature, options);
mesh.layer = this;
return mesh;
});
const featureNode = new FeatureMesh(meshes, collection);

return featureNode;
Expand Down
68 changes: 25 additions & 43 deletions src/Converter/Feature2Texture.js
Expand Up @@ -4,7 +4,9 @@ import Extent from 'Core/Geographic/Extent';
import Coordinates from 'Core/Geographic/Coordinates';
import Style, { StyleContext } from 'Core/Style';

const defaultStyle = new Style();
const context = new StyleContext();
let style;

/**
* Draw polygon (contour, line edge and fill) based on feature vertices into canvas
Expand All @@ -15,26 +17,15 @@ const context = new StyleContext();
* @param {Object[]} indices - Contains the indices that define the geometry.
* Objects stored in this array have two properties, an `offset` and a `count`.
* The offset is related to the overall number of vertices in the Feature.
* @param {Object} style - object defining the style of the polygon.
* @param {Number} size - The size of the feature.
* @param {Number} extent - The extent.
* @param {Number} invCtxScale - The ration to scale line width and radius circle.
* @param {Boolean} canBeFilled - true if feature.type == FEATURE_TYPES.POLYGON
*/
function drawPolygon(ctx, vertices, indices = [{ offset: 0, count: 1 }], style = {}, size, extent, invCtxScale, canBeFilled) {
function drawPolygon(ctx, vertices, indices = [{ offset: 0, count: 1 }], size, extent, invCtxScale, canBeFilled) {
if (vertices.length === 0) {
return;
}
if (style.length) {
for (const s of style) {
_drawPolygon(ctx, vertices, indices, s, size, extent, invCtxScale, canBeFilled);
}
} else {
_drawPolygon(ctx, vertices, indices, style, size, extent, invCtxScale, canBeFilled);
}
}

function _drawPolygon(ctx, vertices, indices, style, size, extent, invCtxScale, canBeFilled) {
// build contour
const path = new Path2D();

Expand All @@ -48,10 +39,10 @@ function _drawPolygon(ctx, vertices, indices, style, size, extent, invCtxScale,
}
}
}
Style.prototype.applyToCanvasPolygon.call(style, ctx, path, invCtxScale, canBeFilled);
style.applyToCanvasPolygon(ctx, path, invCtxScale, canBeFilled);
}

function drawPoint(ctx, x, y, style = {}, invCtxScale) {
function drawPoint(ctx, x, y, invCtxScale) {
ctx.beginPath();
const opacity = style.point.opacity == undefined ? 1.0 : style.point.opacity;
if (opacity !== ctx.globalAlpha) {
Expand All @@ -76,34 +67,28 @@ function drawFeature(ctx, feature, extent, invCtxScale) {
const extentDim = extent.planarDimensions();
const scaleRadius = extentDim.x / ctx.canvas.width;

context.setFeature(feature);

for (const geometry of feature.geometries) {
if (Extent.intersectsExtent(geometry.extent, extent)) {
context.setGeometry(geometry);

const contextStyle = Style.applyContext(context);

if (contextStyle) {
if (
feature.type === FEATURE_TYPES.POINT && contextStyle.point
) {
// cross multiplication to know in the extent system the real size of
// the point
const px = (Math.round(contextStyle.point.radius * invCtxScale) || 3 * invCtxScale) * scaleRadius;
for (const indice of geometry.indices) {
const offset = indice.offset * feature.size;
const count = offset + indice.count * feature.size;
for (let j = offset; j < count; j += feature.size) {
coord.setFromArray(feature.vertices, j);
if (extent.isPointInside(coord, px)) {
drawPoint(ctx, feature.vertices[j], feature.vertices[j + 1], contextStyle, invCtxScale);
}
if (
feature.type === FEATURE_TYPES.POINT && style.point
) {
// cross multiplication to know in the extent system the real size of
// the point
const px = (Math.round(style.point.radius * invCtxScale) || 3 * invCtxScale) * scaleRadius;
for (const indice of geometry.indices) {
const offset = indice.offset * feature.size;
const count = offset + indice.count * feature.size;
for (let j = offset; j < count; j += feature.size) {
coord.setFromArray(feature.vertices, j);
if (extent.isPointInside(coord, px)) {
drawPoint(ctx, feature.vertices[j], feature.vertices[j + 1], invCtxScale);
}
}
} else {
drawPolygon(ctx, feature.vertices, geometry.indices, contextStyle, feature.size, extent, invCtxScale, (feature.type == FEATURE_TYPES.POLYGON));
}
} else {
drawPolygon(ctx, feature.vertices, geometry.indices, feature.size, extent, invCtxScale, (feature.type == FEATURE_TYPES.POLYGON));
}
}
}
Expand All @@ -122,9 +107,10 @@ const featureExtent = new Extent('EPSG:4326', 0, 0, 0, 0);
export default {
// backgroundColor is a THREE.Color to specify a color to fill the texture
// with, given there is no feature passed in parameter
createTextureFromFeature(collection, extent, sizeTexture, layerStyle = {}, backgroundColor) {
createTextureFromFeature(collection, extent, sizeTexture, layerStyle, backgroundColor) {
style = layerStyle || defaultStyle;
style.setContext(context);
let texture;
context.layerStyle = layerStyle;

if (collection) {
// A texture is instancied drawn canvas
Expand Down Expand Up @@ -172,15 +158,11 @@ 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,
};
context.setZoom(extent.zoom);

// Draw the canvas
for (const feature of collection.features) {
context.setFeature(feature);
drawFeature(ctx, feature, featureExtent, invCtxScale);
}

Expand Down

0 comments on commit 55849f6

Please sign in to comment.