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

Rework style #2006

Merged
merged 11 commits into from
Dec 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
2 changes: 1 addition & 1 deletion examples/css/example.css
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ h3 {

.tooltip {
display: none;
background-image: linear-gradient(rgba(80, 80, 80,0.95), rgba(60, 60, 60,0.95));
background-image: linear-gradient(rgba(167, 164, 164, 0.95), rgba(60, 60, 60,0.95));
box-shadow: -1px 2px 5px 1px rgba(0, 0, 0, 0.5);
margin-top: 20px;
margin-left: 20px;
Expand Down
36 changes: 16 additions & 20 deletions examples/js/plugins/FeatureToolTip.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,42 +64,38 @@ const FeatureToolTip = (function _() {
}
}

function getGeometryProperties(geometry) {
return function properties() { return geometry.properties; };
}

function fillToolTip(features, layer, options) {
let content = '';
let feature;
let geometry;
let style;
const style = layer.style;
let fill;
let stroke;
let symb = '';
let prop;

const context = style.context;

for (let p = 0; p < features.length; p++) {
feature = features[p];
geometry = feature.geometry;
style = (geometry.properties && geometry.properties.style) || feature.style || layer.style;
const context = { globals: {}, properties: getGeometryProperties(geometry) };
style = style.applyContext(context);

context.setFeature(feature);
context.setGeometry(geometry);

if (feature.type === itowns.FEATURE_TYPES.POLYGON) {
symb = '&#9724';
if (style) {
fill = style.fill && style.fill.color;
stroke = style.stroke && ('1.25px ' + style.stroke.color);
}
fill = style.fill && style.fill.color;
stroke = style.stroke && ('1.25px ' + style.stroke.color);
} else if (feature.type === itowns.FEATURE_TYPES.LINE) {
symb = '&#9473';
fill = style && style.stroke && style.stroke.color;
fill = style.stroke && style.stroke.color;
stroke = '0px';
} else if (feature.type === itowns.FEATURE_TYPES.POINT) {
symb = '&#9679';
if (style && style.point) { // Style and style.point can be undefined if no style options were passed
fill = style.point.color;
stroke = '1.25px ' + style.point.line;
if (style.point || style.icon) { // Style and style.point can be undefined if no style options were passed
fill = (style.point && style.point.color) || (style.icon && style.icon.color);
stroke = '1.25px ' + ((style.point && style.point.line) || 'black');
}
}

Expand All @@ -109,10 +105,10 @@ const FeatureToolTip = (function _() {
content += '</span>';

if (geometry.properties) {
content += (geometry.properties.description || geometry.properties.name || geometry.properties.nom || layer.name || '');
content += (geometry.properties.description || geometry.properties.name || geometry.properties.nom || geometry.properties.title || layer.name || '');
}

if (feature.type === itowns.FEATURE_TYPES.POINT) {
if (feature.type === itowns.FEATURE_TYPES.POINT && options.writeLatLong) {
content += '<br/><span class="coord">long ' + feature.coordinates[0].toFixed(4) + '</span>';
content += '<br/><span class="coord">lat ' + feature.coordinates[1].toFixed(4) + '</span>';
}
Expand Down Expand Up @@ -231,8 +227,8 @@ const FeatureToolTip = (function _() {
}

const opts = options || { filterAllProperties: true };
opts.filterProperties = opts.filterProperties == undefined ? [] : opts.filterProperties;
opts.filterProperties.concat(['name', 'nom', 'style', 'description']);
opts.filterProperties = opts.filterProperties === undefined ? [] : opts.filterProperties;
opts.writeLatLong = opts.writeLatLong || false;

layers.push({ layer: layer, options: opts });
layersId.push(layer.id);
Expand Down
20 changes: 10 additions & 10 deletions examples/source_file_gpx_3d.html
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@

var waypointGeometry = new itowns.THREE.BoxGeometry(1, 1, 80);
var waypointMaterial = new itowns.THREE.MeshBasicMaterial({ color: 0xffffff });
const style = {
stroke: {
color: 'red',
width: 2,
},
point: {
color: 'white',
}
};
// Listen for globe full initialisation event
view.addEventListener(itowns.GLOBE_VIEW_EVENTS.GLOBE_INITIALIZED, function () {
console.info('Globe initialized');
Expand All @@ -72,18 +81,9 @@
out: {
crs: view.referenceCrs,
structure: '3d',
style: new itowns.Style({
stroke: {
color: 'red',
width: 2,
},
point: {
color: 'white',
}
}),
}
}))
.then(itowns.Feature2Mesh.convert())
.then(itowns.Feature2Mesh.convert({style}))
.then(function (mesh) {
if (mesh) {
mesh.updateMatrixWorld();
Expand Down
81 changes: 53 additions & 28 deletions src/Converter/Feature2Mesh.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ 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';
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 @@ -191,7 +193,9 @@ function featureToPoint(feature, options) {
const vertices = new Float32Array(ptsIn);
inverseScale.setFromMatrixScale(context.collection.matrixWorldInverse);
normal.set(0, 0, 1).multiply(inverseScale);
context.globals = { point: true };

const pointMaterialSize = [];
context.setFeature(feature);

for (const geometry of feature.geometries) {
const start = geometry.indices[0].offset;
Expand All @@ -206,10 +210,14 @@ function featureToPoint(feature, options) {
}

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

if (!pointMaterialSize.includes(radius)) {
pointMaterialSize.push(radius);
}

// populate vertices
base.copy(normal).multiplyScalar(base_altitude).add(coord).toArray(vertices, v);
toColor(color).multiplyScalar(255).toArray(colors, v);
Expand All @@ -223,7 +231,11 @@ function featureToPoint(feature, options) {
geom.setAttribute('color', new THREE.BufferAttribute(colors, 3, true));
geom.setAttribute('batchId', new THREE.BufferAttribute(batchIds, 1));

options.pointMaterial.size = feature.style.point.radius;
options.pointMaterial.size = pointMaterialSize[0];
if (pointMaterialSize.length > 1) {
// TODO CREATE material for each feature
console.warn('Too many differents point.radius, only the first one will be used');
}

return new THREE.Points(geom, options.pointMaterial);
}
Expand All @@ -241,9 +253,8 @@ function featureToLine(feature, options) {
const geom = new THREE.BufferGeometry();
geom.setAttribute('position', new THREE.BufferAttribute(vertices, 3));

// TODO CREATE material for each feature
options.lineMaterial.linewidth = feature.style.stroke.width;
context.globals = { stroke: true };
const lineMaterialWidth = [];
context.setFeature(feature);

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

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

if (!lineMaterialWidth.includes(width)) {
lineMaterialWidth.push(width);
}

// populate geometry buffers
base.copy(normal).multiplyScalar(base_altitude).add(coord).toArray(vertices, v);
toColor(color).multiplyScalar(255).toArray(colors, v);
batchIds[j] = id;
}

featureId++;
}
options.lineMaterial.linewidth = lineMaterialWidth[0];
if (lineMaterialWidth.length > 1) {
// TODO CREATE material for each feature
console.warn('Too many differents stroke.width, only the first one will be used');
}
geom.setAttribute('color', new THREE.BufferAttribute(colors, 3, true));
geom.setAttribute('batchId', new THREE.BufferAttribute(batchIds, 1));
geom.setIndex(new THREE.BufferAttribute(indices, 1));
Expand All @@ -304,7 +323,7 @@ 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);
normal.set(0, 0, 1).multiply(inverseScale);
Expand Down Expand Up @@ -332,7 +351,7 @@ function featureToPolygon(feature, options) {
}

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

Expand Down Expand Up @@ -392,7 +411,7 @@ 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);
coord.setCrs(context.collection.crs);
Expand All @@ -418,7 +437,7 @@ function featureToExtrudedPolygon(feature, options) {

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

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

Expand Down Expand Up @@ -513,7 +532,7 @@ function createInstancedMesh(mesh, count, ptsIn) {
function pointsToInstancedMeshes(feature) {
const ptsIn = feature.vertices;
const count = feature.geometries.length;
const modelObject = feature.style.point.model.object;
const modelObject = style.point.model.object;

if (modelObject instanceof THREE.Mesh) {
return createInstancedMesh(modelObject, count, ptsIn);
Expand All @@ -524,15 +543,15 @@ function pointsToInstancedMeshes(feature) {
meshes.forEach(mesh => group.add(createInstancedMesh(mesh, count, ptsIn)));
return group;
} else {
throw new Error('The format of the model object provided in the feature style (feature.style.point.model.object) is not supported. Only THREE.Mesh or THREE.Object3D are supported.');
throw new Error('The format of the model object provided in the style (layer.style.point.model.object) is not supported. Only THREE.Mesh or THREE.Object3D are supported.');
}
}

/**
* 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 @@ -543,7 +562,7 @@ function featureToMesh(feature, options) {
let mesh;
switch (feature.type) {
case FEATURE_TYPES.POINT:
if (feature.style.point?.model?.object) {
if (style.point?.model?.object) {
try {
mesh = pointsToInstancedMeshes(feature);
mesh.isInstancedMesh = true;
Expand All @@ -558,7 +577,7 @@ function featureToMesh(feature, options) {
mesh = featureToLine(feature, options);
break;
case FEATURE_TYPES.POLYGON:
if (feature.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 @@ -573,10 +592,6 @@ function featureToMesh(feature, options) {
}
mesh.feature = feature;

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

return mesh;
}

Expand All @@ -592,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 @@ -624,20 +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 = this;
}

// 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;
jailln marked this conversation as resolved.
Show resolved Hide resolved
return mesh;
});
const featureNode = new FeatureMesh(meshes, collection);

return featureNode;
Expand Down
Loading