diff --git a/@here/harp-datasource-protocol/lib/DecodedTile.ts b/@here/harp-datasource-protocol/lib/DecodedTile.ts index 68696b3751..ee81fb4d21 100644 --- a/@here/harp-datasource-protocol/lib/DecodedTile.ts +++ b/@here/harp-datasource-protocol/lib/DecodedTile.ts @@ -170,6 +170,12 @@ export interface Geometry { */ featureStarts?: number[]; + /** + * Optional sorted list of feature start indices for the outline geometry. + * Equivalent to {@link featureStarts} but pointing into the edgeIndex attribute. + */ + edgeFeatureStarts?: number[]; + /** * Optional array of objects. It can be used to pass user data from the geometry to the mesh. */ diff --git a/@here/harp-mapview/lib/geometry/TileGeometryCreator.ts b/@here/harp-mapview/lib/geometry/TileGeometryCreator.ts index 45571d2730..5382035d81 100644 --- a/@here/harp-mapview/lib/geometry/TileGeometryCreator.ts +++ b/@here/harp-mapview/lib/geometry/TileGeometryCreator.ts @@ -931,6 +931,7 @@ export class TileGeometryCreator { if (renderDepthPrePass) { const depthPassMesh = createDepthPrePassMesh(object as THREE.Mesh); + this.addUserData(tile, srcGeometry, technique, depthPassMesh); // Set geometry kind for depth pass mesh so that it gets the displacement map // for elevation overlay. this.registerTileObject(tile, depthPassMesh, techniqueKind, { @@ -956,6 +957,13 @@ export class TileGeometryCreator { // Add the extruded building edges as a separate geometry. if (isBuilding) { + // When the source geometry is split in groups, we + // should create objects with an array of materials. + const hasEdgeFeatureGroups = + Expr.isExpr(technique.enabled) && + srcGeometry.edgeFeatureStarts && + srcGeometry.edgeFeatureStarts.length > 0; + const buildingTechnique = technique as ExtrudedPolygonTechnique; const edgeGeometry = new THREE.BufferGeometry(); edgeGeometry.setAttribute("position", bufferGeometry.getAttribute("position")); @@ -1002,7 +1010,12 @@ export class TileGeometryCreator { vertexColors: bufferGeometry.getAttribute("color") ? true : false }; const edgeMaterial = new EdgeMaterial(materialParams); - const edgeObj = new THREE.LineSegments(edgeGeometry, edgeMaterial); + const edgeObj = new THREE.LineSegments( + edgeGeometry, + hasEdgeFeatureGroups ? [edgeMaterial] : edgeMaterial + ); + + this.addUserData(tile, srcGeometry, technique, edgeObj); // Set the correct render order. edgeObj.renderOrder = object.renderOrder + 0.1; @@ -1042,6 +1055,11 @@ export class TileGeometryCreator { // Add the fill area edges as a separate geometry. if (isFillTechnique(technique) && attachment.info.edgeIndex) { + const hasEdgeFeatureGroups = + Expr.isExpr(technique.enabled) && + srcGeometry.edgeFeatureStarts && + srcGeometry.edgeFeatureStarts.length > 0; + const outlineGeometry = new THREE.BufferGeometry(); outlineGeometry.setAttribute( "position", @@ -1064,7 +1082,10 @@ export class TileGeometryCreator { vertexColors: bufferGeometry.getAttribute("color") ? true : false }; const outlineMaterial = new EdgeMaterial(materialParams); - const outlineObj = new THREE.LineSegments(outlineGeometry, outlineMaterial); + const outlineObj = new THREE.LineSegments( + outlineGeometry, + hasEdgeFeatureGroups ? [outlineMaterial] : outlineMaterial + ); outlineObj.renderOrder = object.renderOrder + 0.1; FadingFeature.addRenderHelper( @@ -1075,6 +1096,8 @@ export class TileGeometryCreator { false ); + this.addUserData(tile, srcGeometry, technique, outlineObj); + this.registerTileObject(tile, outlineObj, techniqueKind, { technique, pickable: false @@ -1527,9 +1550,12 @@ export class TileGeometryCreator { } else { // Set the feature data for picking with `MapView.intersectMapObjects()` except for // solid-line which uses tile-based picking. + const isOutline = + object.type === "LineSegments" && + (isExtrudedPolygonTechnique(technique) || isFillTechnique(technique)); const featureData: TileFeatureData = { geometryType: srcGeometry.type, - starts: srcGeometry.featureStarts, + starts: isOutline ? srcGeometry.edgeFeatureStarts : srcGeometry.featureStarts, objInfos: srcGeometry.objInfos }; object.userData.feature = featureData; diff --git a/@here/harp-omv-datasource/lib/OmvDecodedTileEmitter.ts b/@here/harp-omv-datasource/lib/OmvDecodedTileEmitter.ts index 7639c23289..f12786dc55 100644 --- a/@here/harp-omv-datasource/lib/OmvDecodedTileEmitter.ts +++ b/@here/harp-omv-datasource/lib/OmvDecodedTileEmitter.ts @@ -178,6 +178,11 @@ class MeshBuffers implements IMeshBuffers { */ readonly featureStarts: number[] = []; + /** + * Optional list of edge feature start indices. The indices point into the edge index attribute. + */ + readonly edgeFeatureStarts: number[] = []; + /** * An optional list of additional data that can be used as additional data for the object * picking. @@ -1344,6 +1349,7 @@ export class OmvDecodedTileEmitter implements IOmvEmitter { for (const polygon of polygons) { const startIndexCount = indices.length; + const edgeStartIndexCount = edgeIndices.length; for (let ringIndex = 0; ringIndex < polygon.length; ) { const vertices: number[] = []; @@ -1637,6 +1643,7 @@ export class OmvDecodedTileEmitter implements IOmvEmitter { if (this.m_gatherFeatureAttributes) { meshBuffers.objInfos.push(context.env.entries); meshBuffers.featureStarts.push(startIndexCount); + meshBuffers.edgeFeatureStarts.push(edgeStartIndexCount); } const count = indices.length - startIndexCount; @@ -1809,6 +1816,7 @@ export class OmvDecodedTileEmitter implements IOmvEmitter { } geometry.featureStarts = meshBuffers.featureStarts; + geometry.edgeFeatureStarts = meshBuffers.edgeFeatureStarts; geometry.objInfos = meshBuffers.objInfos; this.m_geometries.push(geometry); diff --git a/test/rendering/StylingTest.ts b/test/rendering/StylingTest.ts index 7de5fb2ada..27fda77e52 100644 --- a/test/rendering/StylingTest.ts +++ b/test/rendering/StylingTest.ts @@ -151,7 +151,8 @@ function mapViewFeaturesRenderingTest( styleSetName: "geojson", geojson: options.geoJson, decoder: new OmvTileDecoder(), - tiler: new GeoJsonTiler() + tiler: new GeoJsonTiler(), + gatherFeatureAttributes: true }); mapView.addDataSource(dataSource); @@ -177,7 +178,7 @@ function mapViewFeaturesRenderingTest( const grid = new THREE.GridHelper(gridSize, gridDivisions, 0xff0000, 0x00ff00); grid.geometry.rotateX(Math.PI / 2); - (grid as MapAnchor).geoPosition = position; + (grid as MapAnchor).anchor = position; grid.setRotationFromMatrix(box.getRotationMatrix()); mapView.mapAnchors.add(grid); } @@ -746,22 +747,42 @@ describe("MapView Styling Test", function() { } } ]; - const rectangle: Feature = { + const rectangle1: Feature = { // sample rectangular polygon type: "Feature", geometry: { type: "Polygon", coordinates: [ [ - [0.004, 0.002], - [-0.004, 0.002], + [0.001, 0.001], + [-0.004, 0.001], [-0.004, -0.002], - [0.004, -0.002] + [0.001, -0.002] + ] + ] + }, + properties: { + name: "Awesome Building", + kind: "building", + height: 200 + } + }; + const rectangle2: Feature = { + type: "Feature", + geometry: { + type: "Polygon", + coordinates: [ + [ + [0.001, 0.002], + [0.004, 0.002], + [0.004, -0.002], + [0.001, -0.002] ] ] }, properties: { - kind: "mall", + name: "Not So Awesome Building", + kind: "building", height: 200 } }; @@ -790,7 +811,8 @@ describe("MapView Styling Test", function() { type: "FeatureCollection", features: [ // tested horizontal line - rectangle, + rectangle1, + rectangle2, referenceBackground, ...extraFeatures ] @@ -828,12 +850,23 @@ describe("MapView Styling Test", function() { lineColor: "#7f7", lineWidth: 200 }, - "fiil-rgba-outline-rgba-200m": { + "fill-rgba-outline-rgba-200m": { color: "#0b97c470", lineColor: "#7f77", lineWidth: 200 + }, + "fill-outline-disabled": { + color: "#0b97c4", + lineColor: "#7f7", + lineWidth: 200, + enabled: false + }, + "fill-outline-partially-disabled": { + color: "#0b97c4", + lineColor: "#7f7", + lineWidth: 200, + enabled: ["match", ["get", "name"], "Awesome Building", true, false] } - // TODO: not supported by typings // "rect-rgba-outline-rgba-5px": { // color: "#0b97c470", @@ -849,7 +882,7 @@ describe("MapView Styling Test", function() { { geoJson: { type: "FeatureCollection", - features: [rectangle, referenceBackground] + features: [rectangle1, rectangle2, referenceBackground] }, theme: { lights, @@ -885,7 +918,7 @@ describe("MapView Styling Test", function() { { geoJson: { type: "FeatureCollection", - features: [rectangle, referenceBackground] + features: [rectangle1, referenceBackground] }, theme: { lights, @@ -987,6 +1020,13 @@ describe("MapView Styling Test", function() { lineColorMix: 0, lineColor: "#7f7", enabled: false + }, + "extruded-polygon-3d-rgba-outline-partialy-disabled": { + color: "#0b97c480", + lineWidth: 1, + lineColorMix: 0, + lineColor: "#7f7", + enabled: ["match", ["get", "name"], "Awesome Building", true, false] } }, viewOptions