From 41ed7567f144f0be2c9bfcc0022b0e8e052eea4c Mon Sep 17 00:00:00 2001 From: Maxim Kuznetsov <116376092+MaximKYZ@users.noreply.github.com> Date: Tue, 27 Jun 2023 08:03:49 +0000 Subject: [PATCH] feat(i3s): Add an option to multiply colors by attribute (#2519) --- .../src/lib/parsers/parse-i3s-tile-content.ts | 2 +- .../src/lib/utils/customize-\321\201olors.ts" | 14 +++++++-- modules/i3s/src/types.ts | 1 + modules/i3s/test/i3s-content-loader.spec.js | 31 +++++++++++++++++-- yarn.lock | 6 ++-- 5 files changed, 46 insertions(+), 8 deletions(-) rename modules/i3s/src/lib/utils/customizeColors.ts => "modules/i3s/src/lib/utils/customize-\321\201olors.ts" (89%) diff --git a/modules/i3s/src/lib/parsers/parse-i3s-tile-content.ts b/modules/i3s/src/lib/parsers/parse-i3s-tile-content.ts index 4374c31602..7e47340142 100644 --- a/modules/i3s/src/lib/parsers/parse-i3s-tile-content.ts +++ b/modules/i3s/src/lib/parsers/parse-i3s-tile-content.ts @@ -23,7 +23,7 @@ import {getUrlWithToken} from '../utils/url-utils'; import {GL_TYPE_MAP, getConstructorForDataFormat, sizeOf, COORDINATE_SYSTEM} from './constants'; import {I3SLoaderOptions} from '../../i3s-loader'; -import {customizeColors} from '../utils/customizeColors'; +import {customizeColors} from '../utils/customize-сolors'; const scratchVector = new Vector3([0, 0, 0]); diff --git a/modules/i3s/src/lib/utils/customizeColors.ts "b/modules/i3s/src/lib/utils/customize-\321\201olors.ts" similarity index 89% rename from modules/i3s/src/lib/utils/customizeColors.ts rename to "modules/i3s/src/lib/utils/customize-\321\201olors.ts" index 27c951e6e7..0ed905266e 100644 --- a/modules/i3s/src/lib/utils/customizeColors.ts +++ "b/modules/i3s/src/lib/utils/customize-\321\201olors.ts" @@ -4,7 +4,7 @@ import type {COLOR, I3STileOptions, I3STilesetOptions} from '../../types'; import {load} from '@loaders.gl/core'; import {getAttributeValueType, I3SAttributeLoader} from '../../i3s-attribute-loader'; import {I3SLoaderOptions} from '../../i3s-loader'; -import {getUrlWithToken} from '../utils/url-utils'; +import {getUrlWithToken} from './url-utils'; /** * Modify vertex colors array to visualize 3D objects in a attribute driven way @@ -79,7 +79,17 @@ export async function customizeColors( if (!color) { continue; // eslint-disable-line no-continue } - colors.value.set(color, i * 4); + + /* eslint max-statements: ["error", 30] */ + /* eslint complexity: ["error", 12] */ + if (options.i3s.colorsByAttribute.mode === 'multiply') { + // multiplying original mesh and calculated for attribute rgba colors in range 0-255 + color.forEach((colorItem, index) => { + colors.value[i * 4 + index] = (colors.value[i * 4 + index] * colorItem) / 255; + }); + } else { + colors.value.set(color, i * 4); + } } return colors; diff --git a/modules/i3s/src/types.ts b/modules/i3s/src/types.ts index 3ed63d42b4..ef74a7ce54 100644 --- a/modules/i3s/src/types.ts +++ b/modules/i3s/src/types.ts @@ -114,6 +114,7 @@ export type I3SParseOptions = { maxValue: number; minColor: COLOR; maxColor: COLOR; + mode: string; }; /** @deprecated */ diff --git a/modules/i3s/test/i3s-content-loader.spec.js b/modules/i3s/test/i3s-content-loader.spec.js index fdc1c4e2cc..f4a4ad6de1 100644 --- a/modules/i3s/test/i3s-content-loader.spec.js +++ b/modules/i3s/test/i3s-content-loader.spec.js @@ -198,12 +198,12 @@ test('ParseI3sTileContent#should not decode the texture image if "decodeTextures t.end(); }); -// TODO: Enable this test after test data is merged in master branch -test.skip('ParseI3sTileContent#should colorize by attribute', async (t) => { +test('ParseI3sTileContent#should colorize by attribute', async (t) => { const response = await fetchFile(NEW_YORK_TILE_CONTENT); const data = await response.arrayBuffer(); const responseOptions = await fetchFile(NEW_YORK_CONTENT_LOADER_OPTIONS); const i3sLoaderOptions = await responseOptions.json(); + i3sLoaderOptions.colorsByAttribute.mode = 'replace'; const content = await parse(data, I3SContentLoader, { i3s: i3sLoaderOptions }); @@ -225,6 +225,33 @@ test.skip('ParseI3sTileContent#should colorize by attribute', async (t) => { t.end(); }); +test('ParseI3sTileContent#should colorize by attribute using mutiplying colors', async (t) => { + const response = await fetchFile(NEW_YORK_TILE_CONTENT); + const data = await response.arrayBuffer(); + const responseOptions = await fetchFile(NEW_YORK_CONTENT_LOADER_OPTIONS); + const i3sLoaderOptions = await responseOptions.json(); + i3sLoaderOptions.colorsByAttribute.mode = 'multiply'; + const content = await parse(data, I3SContentLoader, { + i3s: i3sLoaderOptions + }); + t.ok(content); + + // color array should be colorized by attribute using multiplying colors + const colorsArray = content.attributes.colors.value; + t.deepEquals(colorsArray.subarray(0, 9), [139, 139, 247, 255, 139, 139, 247, 255, 139]); + const arrayMiddle = (colorsArray.length - (colorsArray.length % 2)) / 2; + t.deepEquals( + colorsArray.subarray(arrayMiddle, arrayMiddle + 9), + [244, 255, 135, 135, 244, 255, 135, 135, 244] + ); + t.deepEquals( + colorsArray.subarray(colorsArray.length - 9), + [255, 141, 141, 248, 255, 141, 141, 248, 255] + ); + + t.end(); +}); + function getI3SOptions(tile, tileset) { return { _tileOptions: { diff --git a/yarn.lock b/yarn.lock index dba978b92a..174e8722a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4050,9 +4050,9 @@ camelcase@^5.0.0, camelcase@^5.3.1: integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== caniuse-lite@^1.0.30001449: - version "1.0.30001489" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001489.tgz" - integrity sha512-x1mgZEXK8jHIfAxm+xgdpHpk50IN3z3q3zP261/WS+uvePxW8izXuCu6AHz0lkuYTlATDehiZ/tNyYBdSQsOUQ== + version "1.0.30001505" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001505.tgz" + integrity sha512-jaAOR5zVtxHfL0NjZyflVTtXm3D3J9P15zSJ7HmQF8dSKGA6tqzQq+0ZI3xkjyQj46I4/M0K2GbMpcAFOcbr3A== caseless@~0.12.0: version "0.12.0"