Skip to content

Commit 5a56d5c

Browse files
committed
wip
1 parent aa36ec8 commit 5a56d5c

File tree

10 files changed

+227
-15
lines changed

10 files changed

+227
-15
lines changed

src/layer/segmentation/index.ts

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,11 @@ import type { vec3, vec4 } from "#src/util/geom.js";
123123
import {
124124
parseArray,
125125
parseUint64,
126+
verifyArray,
126127
verifyFiniteNonNegativeFloat,
128+
verifyObject,
127129
verifyObjectAsMap,
130+
verifyObjectProperty,
128131
verifyOptionalObjectProperty,
129132
verifyString,
130133
} from "#src/util/json.js";
@@ -139,6 +142,18 @@ import { ShaderControlState } from "#src/webgl/shader_ui_controls.js";
139142

140143
const MAX_LAYER_BAR_UI_INDICATOR_COLORS = 6;
141144

145+
export interface SegmentPropertyColor {
146+
type: "tag" | "numeric";
147+
property: string;
148+
map?: Map<string, string>; // TODO is there a color type?
149+
options?: {
150+
min?: number;
151+
max?: number;
152+
minColor?: string;
153+
maxColor?: string;
154+
}
155+
}
156+
142157
export class SegmentationUserLayerGroupState
143158
extends RefCounted
144159
implements SegmentationGroupState
@@ -302,9 +317,69 @@ export class SegmentationUserLayerColorGroupState
302317
specificationChanged = new Signal();
303318
constructor(public layer: SegmentationUserLayer) {
304319
super();
320+
321+
322+
this.segmentPropertyColorsMap = this.registerDisposer(makeCachedDerivedWatchableValue(
323+
(segmentPropertyMap, segmentPropertyColors) => {
324+
console.log('update segmentPropertyColorsMap');
325+
segmentPropertyColors;
326+
const map = new Uint64Map();
327+
if (!segmentPropertyMap) {
328+
return map;
329+
}
330+
331+
const { tags: tagsProperty } = segmentPropertyMap;
332+
333+
console.log("tags", segmentPropertyMap.tags);
334+
335+
for (const propertyColor of segmentPropertyColors) {
336+
if (propertyColor.type === "tag" && tagsProperty) {
337+
const { tags, values } = tagsProperty;
338+
339+
// const colors = todo performance, cache colors as bigints
340+
341+
const bigIntColors = new Map<string, bigint>();
342+
for (const [tag, colorString] of propertyColor.map!.entries()) {
343+
const color = parseRGBColorSpecification(colorString);
344+
bigIntColors.set(tag, BigInt(packColor(color)));
345+
console.log("tag color", tag, colorString, color);
346+
}
347+
348+
for (const [index, id] of (segmentPropertyMap.segmentPropertyMap.inlineProperties?.ids || []).entries()) {
349+
if (map.has(id)) continue; // priority first color match
350+
const tagIndices = values[index];
351+
const segmentTags = new Set(
352+
tagIndices.split("").map((x) => tags[x.charCodeAt(0)]),
353+
);
354+
355+
for (const [tag, color] of bigIntColors.entries()) {
356+
if (segmentTags.has(tag)) {
357+
map.set(id, color);
358+
break;
359+
}
360+
}
361+
}
362+
} else if (propertyColor.type === "numeric") {
363+
console.log("propety:", propertyColor.property);
364+
}
365+
366+
/*
367+
"type": "numeric",
368+
"property": "Nvx",
369+
*/
370+
}
371+
console.log('map', map.size);
372+
return map;
373+
},
374+
[this.layer.displayState.originalSegmentationGroupState.segmentPropertyMap,
375+
this.segmentPropertyColors],
376+
));
377+
305378
const { specificationChanged } = this;
306379
this.segmentColorHash.changed.add(specificationChanged.dispatch);
307380
this.segmentStatedColors.changed.add(specificationChanged.dispatch);
381+
this.segmentPropertyColors.changed.add(specificationChanged.dispatch);
382+
this.segmentPropertyColorsMap.changed.add(specificationChanged.dispatch);
308383
this.tempSegmentStatedColors2d.changed.add(specificationChanged.dispatch);
309384
this.segmentDefaultColor.changed.add(specificationChanged.dispatch);
310385
this.tempSegmentDefaultColor2d.changed.add(specificationChanged.dispatch);
@@ -330,39 +405,103 @@ export class SegmentationUserLayerColorGroupState
330405
parseRGBColorSpecification(String(x)),
331406
);
332407
for (const [idStr, colorVec] of result) {
408+
console.log("stated color", idStr, colorVec);
333409
const id = parseUint64(idStr);
334410
const color = BigInt(packColor(colorVec));
335411
this.segmentStatedColors.set(id, color);
336412
}
337413
},
338414
);
415+
416+
verifyOptionalObjectProperty(
417+
specification,
418+
json_keys.SEGMENT_PROPERTY_COLORS_JSON_KEY,
419+
(value) => {
420+
const segmentPropertyColors = verifyArray(value);
421+
for (const propertyColor of segmentPropertyColors) {
422+
verifyObject(propertyColor);
423+
const type = verifyObjectProperty(
424+
propertyColor,
425+
"type",
426+
verifyString,
427+
);
428+
const property = verifyObjectProperty(
429+
propertyColor,
430+
"property",
431+
verifyString,
432+
);
433+
const map = verifyObjectProperty(
434+
propertyColor,
435+
json_keys.MAP_JSON_KEY,
436+
(x) => {
437+
verifyObject(x);
438+
const res = new Map<string, string>();
439+
for (const [tag, value] of Object.entries(x)) {
440+
const color = verifyString(value);
441+
res.set(tag, color);
442+
}
443+
return res;
444+
},
445+
);
446+
447+
if (type !== "tag") throw new Error(`unsupported type: ${type}`);
448+
449+
this.segmentPropertyColors.value.push({
450+
type,
451+
property,
452+
map,
453+
});
454+
}
455+
this.segmentPropertyColors.changed.dispatch();
456+
},
457+
);
339458
}
340459

341460
toJSON() {
342461
const x: any = {};
343462
x[json_keys.COLOR_SEED_JSON_KEY] = this.segmentColorHash.toJSON();
344463
x[json_keys.SEGMENT_DEFAULT_COLOR_JSON_KEY] =
345464
this.segmentDefaultColor.toJSON();
346-
const { segmentStatedColors } = this;
465+
const { segmentStatedColors, segmentPropertyColors: {value: segmentPropertyColors} } = this;
347466
if (segmentStatedColors.size > 0) {
348467
const j: any = (x[json_keys.SEGMENT_STATED_COLORS_JSON_KEY] = {});
349468
for (const [key, value] of segmentStatedColors) {
350469
j[key.toString()] = serializeColor(unpackRGB(Number(value)));
351470
}
352471
}
472+
if (segmentPropertyColors.length > 0) {
473+
const j: any[] = (x[json_keys.SEGMENT_PROPERTY_COLORS_JSON_KEY] = []);
474+
for (const propertyColor of segmentPropertyColors) {
475+
const p: any = {};
476+
p["type"] = propertyColor.type;
477+
p["property"] = propertyColor.property;
478+
if (propertyColor.type === "tag") {
479+
const map: any = (p[json_keys.MAP_JSON_KEY] = {});
480+
for (const [key, value] of propertyColor.map!.entries()) {
481+
map[key.toString()] = value;
482+
}
483+
} else {
484+
// TODO numeric
485+
}
486+
j.push(p);
487+
}
488+
}
353489
return x;
354490
}
355491

356492
assignFrom(other: SegmentationUserLayerColorGroupState) {
357493
this.segmentColorHash.value = other.segmentColorHash.value;
358494
this.segmentStatedColors.assignFrom(other.segmentStatedColors);
495+
this.segmentPropertyColors.value = other.segmentPropertyColors.value;
359496
this.tempSegmentStatedColors2d.assignFrom(other.tempSegmentStatedColors2d);
360497
this.segmentDefaultColor.value = other.segmentDefaultColor.value;
361498
this.highlightColor.value = other.highlightColor.value;
362499
}
363500

364501
segmentColorHash = SegmentColorHash.getDefault();
365502
segmentStatedColors = this.registerDisposer(new Uint64Map());
503+
segmentPropertyColors = new WatchableValue<SegmentPropertyColor[]>([]);
504+
segmentPropertyColorsMap: WatchableValueInterface<Uint64Map>;
366505
tempSegmentStatedColors2d = this.registerDisposer(new Uint64Map());
367506
segmentDefaultColor = new TrackableOptionalRGB();
368507
tempSegmentDefaultColor2d = new WatchableValue<vec3 | vec4 | undefined>(
@@ -494,6 +633,18 @@ class SegmentationUserLayerDisplayState implements SegmentationDisplayState {
494633
(group) => group.segmentStatedColors,
495634
),
496635
);
636+
this.segmentPropertyColors = this.layer.registerDisposer(
637+
new IndirectTrackableValue(
638+
this.segmentationColorGroupState,
639+
(group) => group.segmentPropertyColors,
640+
),
641+
);
642+
this.segmentPropertyColorsMap = this.layer.registerDisposer(
643+
new IndirectTrackableValue(
644+
this.segmentationColorGroupState,
645+
(group) => group.segmentPropertyColorsMap,
646+
),
647+
);
497648
this.tempSegmentStatedColors2d = this.layer.registerDisposer(
498649
new IndirectTrackableValue(
499650
this.segmentationColorGroupState,
@@ -576,6 +727,8 @@ class SegmentationUserLayerDisplayState implements SegmentationDisplayState {
576727
segmentColorHash: TrackableValueInterface<number>;
577728
segmentStatedColors: WatchableValueInterface<Uint64Map>;
578729
tempSegmentStatedColors2d: WatchableValueInterface<Uint64Map>;
730+
segmentPropertyColors: WatchableValueInterface<SegmentPropertyColor[]>;
731+
segmentPropertyColorsMap: WatchableValueInterface<Uint64Map>;
579732
segmentDefaultColor: WatchableValueInterface<vec3 | undefined>;
580733
tempSegmentDefaultColor2d: WatchableValueInterface<vec3 | vec4 | undefined>;
581734
highlightColor: WatchableValueInterface<vec4 | undefined>;

src/layer/segmentation/json_keys.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ export const SEGMENTS_JSON_KEY = "segments";
1212
export const EQUIVALENCES_JSON_KEY = "equivalences";
1313
export const COLOR_SEED_JSON_KEY = "colorSeed";
1414
export const SEGMENT_STATED_COLORS_JSON_KEY = "segmentColors";
15+
export const SEGMENT_PROPERTY_COLORS_JSON_KEY = "segmentPropertyColors";
16+
export const MAP_JSON_KEY = "map";
1517
export const MESH_RENDER_SCALE_JSON_KEY = "meshRenderScale";
1618
export const CROSS_SECTION_RENDER_SCALE_JSON_KEY = "crossSectionRenderScale";
1719
export const SHADER_JSON_KEY = "shader";

src/mesh/frontend.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,6 @@ export class MeshLayer extends PerspectiveViewRenderLayer<ThreeDimensionalRender
643643
segmentPropertyMap: { value: segmentPropertyMap },
644644
} = displayState.segmentationGroupState.value;
645645
if (segmentPropertyMap) {
646-
console.log('key/objectId', key, objectId);
647646
setSegmentPropertyUniforms(gl, shader, segmentPropertyMap, objectId);
648647
}
649648

@@ -956,7 +955,7 @@ export class MultiscaleMeshLayer extends PerspectiveViewRenderLayer<ThreeDimensi
956955
attachment,
957956
);
958957
if (modelMatrix === undefined) return;
959-
console.log("get shader multiscale!");
958+
// console.log("get shader multiscale!");
960959
const { shader, parameters } = this.getShader(renderContext.emitter);
961960
parameters;
962961
if (shader === null) return;
@@ -1034,7 +1033,6 @@ export class MultiscaleMeshLayer extends PerspectiveViewRenderLayer<ThreeDimensi
10341033
segmentPropertyMap: { value: segmentPropertyMap },
10351034
} = displayState.segmentationGroupState.value;
10361035
if (segmentPropertyMap) {
1037-
console.log('key/objectId', key, objectId);
10381036
setSegmentPropertyUniforms(gl, shader, segmentPropertyMap, objectId);
10391037
}
10401038

src/segmentation_display_state/frontend.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ import type { LayerChunkProgressInfo } from "#src/chunk_manager/base.js";
1818
import type { ChunkManager } from "#src/chunk_manager/frontend.js";
1919
import { ChunkRenderLayerFrontend } from "#src/chunk_manager/frontend.js";
2020
import type { LayerSelectedValues } from "#src/layer/index.js";
21-
import type { SegmentationUserLayer } from "#src/layer/segmentation/index.js";
21+
import type {
22+
SegmentationUserLayer,
23+
SegmentPropertyColor,
24+
} from "#src/layer/segmentation/index.js";
2225
import type { PickIDManager } from "#src/object_picking.js";
2326
import type { WatchableRenderLayerTransform } from "#src/render_coordinate_transform.js";
2427
import type { RenderScaleHistogram } from "#src/render_scale_statistics.js";
@@ -178,6 +181,8 @@ export interface SegmentationColorGroupState {
178181
segmentColorHash: SegmentColorHash;
179182
segmentStatedColors: Uint64Map;
180183
tempSegmentStatedColors2d: Uint64Map;
184+
segmentPropertyColors: WatchableValueInterface<SegmentPropertyColor[]>;
185+
segmentPropertyColorsMap: WatchableValueInterface<Uint64Map>;
181186
segmentDefaultColor: WatchableValueInterface<vec3 | undefined>;
182187
tempSegmentDefaultColor2d: WatchableValueInterface<vec3 | vec4 | undefined>;
183188
}
@@ -199,6 +204,7 @@ export interface SegmentationDisplayState {
199204
hideSegmentZero: WatchableValueInterface<boolean>;
200205
segmentColorHash: WatchableValueInterface<number>;
201206
segmentStatedColors: WatchableValueInterface<Uint64Map>;
207+
segmentPropertyColorsMap: WatchableValueInterface<Uint64Map>; // which of these do I need?
202208
tempSegmentStatedColors2d: WatchableValueInterface<Uint64Map>;
203209
useTempSegmentStatedColors2d: WatchableValueInterface<boolean>;
204210
segmentDefaultColor: WatchableValueInterface<vec3 | undefined>;
@@ -934,7 +940,11 @@ export function getBaseObjectColor(
934940
return color;
935941
}
936942
const colorGroupState = displayState.segmentationColorGroupState.value;
937-
const { segmentStatedColors } = colorGroupState;
943+
const {
944+
segmentStatedColors,
945+
segmentPropertyColorsMap: { value: segmentPropertyColorsMap },
946+
// segmentPropertyColors: { value: segmentPropertyColors },
947+
} = colorGroupState;
938948
let statedColor: bigint | undefined;
939949
if (
940950
segmentStatedColors.size !== 0 &&
@@ -947,6 +957,16 @@ export function getBaseObjectColor(
947957
color[2] = (Number(statedColor & 0xff0000n) >>> 16) / 255.0;
948958
return color;
949959
}
960+
let propertyColor: bigint | undefined;
961+
if (
962+
segmentPropertyColorsMap.size !== 0 &&
963+
(propertyColor = segmentPropertyColorsMap.get(objectId)) !== undefined
964+
) {
965+
color[0] = Number(propertyColor & 0x0000ffn) / 255.0;
966+
color[1] = (Number(propertyColor & 0x00ff00n) >>> 8) / 255.0;
967+
color[2] = (Number(propertyColor & 0xff0000n) >>> 16) / 255.0;
968+
return color;
969+
}
950970
const segmentDefaultColor = colorGroupState.segmentDefaultColor.value;
951971
if (segmentDefaultColor !== undefined) {
952972
color[0] = segmentDefaultColor[0];

src/segmentation_display_state/property_map.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,7 +1434,6 @@ export const setSegmentPropertyUniforms = (
14341434
numericalProperties,
14351435
} = segmentPropertyMap;
14361436
labels; // TODO, support labels
1437-
14381437
for (const [i, property] of numericalProperties.entries()) {
14391438
const value = index !== -1 ? property.values[index] : 0;
14401439
const uniformSetter = getShaderUniformValueSetter(gl, property.dataType);
@@ -1444,7 +1443,6 @@ export const setSegmentPropertyUniforms = (
14441443
value,
14451444
);
14461445
}
1447-
14481446
if (tagsProperty !== undefined) {
14491447
const { values, tags } = tagsProperty;
14501448
for (let i = 0; i < tags.length; ++i) {
@@ -1453,8 +1451,7 @@ export const setSegmentPropertyUniforms = (
14531451
const tagIndices = index !== -1 ? values[index] : "";
14541452
for (let i = 0, length = tagIndices.length; i < length; ++i) {
14551453
const tagIdx = tagIndices.charCodeAt(i);
1456-
1457-
console.log("enable tag property", tagIdx);
1454+
// console.log('enabling tagIdx', tagIdx);
14581455
gl.uniform1ui(shader.uniform(`uSegmentTagProperty${tagIdx}`), 1);
14591456
}
14601457
}

0 commit comments

Comments
 (0)