Skip to content

Commit f67ec75

Browse files
committed
rush numeric
1 parent 5a56d5c commit f67ec75

File tree

1 file changed

+140
-73
lines changed

1 file changed

+140
-73
lines changed

src/layer/segmentation/index.ts

Lines changed: 140 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,13 @@ import {
119119
} from "#src/util/color.js";
120120
import type { Borrowed, Owned } from "#src/util/disposable.js";
121121
import { RefCounted } from "#src/util/disposable.js";
122-
import type { vec3, vec4 } from "#src/util/geom.js";
122+
import { vec3, vec4 } from "#src/util/geom.js";
123123
import {
124124
parseArray,
125125
parseUint64,
126126
verifyArray,
127127
verifyFiniteNonNegativeFloat,
128+
verifyFloat,
128129
verifyObject,
129130
verifyObjectAsMap,
130131
verifyObjectProperty,
@@ -147,11 +148,11 @@ export interface SegmentPropertyColor {
147148
property: string;
148149
map?: Map<string, string>; // TODO is there a color type?
149150
options?: {
150-
min?: number;
151-
max?: number;
152-
minColor?: string;
153-
maxColor?: string;
154-
}
151+
min: number;
152+
max: number;
153+
minColor: string;
154+
maxColor: string;
155+
};
155156
}
156157

157158
export class SegmentationUserLayerGroupState
@@ -318,62 +319,91 @@ export class SegmentationUserLayerColorGroupState
318319
constructor(public layer: SegmentationUserLayer) {
319320
super();
320321

322+
this.segmentPropertyColorsMap = this.registerDisposer(
323+
makeCachedDerivedWatchableValue(
324+
(segmentPropertyMap, segmentPropertyColors) => {
325+
console.log("update segmentPropertyColorsMap");
326+
segmentPropertyColors;
327+
const map = new Uint64Map();
328+
if (!segmentPropertyMap) {
329+
return map;
330+
}
321331

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+
const { tags: tagsProperty } = segmentPropertyMap;
332333

333-
console.log("tags", segmentPropertyMap.tags);
334+
console.log("tags", segmentPropertyMap.tags);
334335

335-
for (const propertyColor of segmentPropertyColors) {
336-
if (propertyColor.type === "tag" && tagsProperty) {
337-
const { tags, values } = tagsProperty;
336+
for (const propertyColor of segmentPropertyColors) {
337+
if (propertyColor.type === "tag" && tagsProperty) {
338+
const { tags, values } = tagsProperty;
338339

339-
// const colors = todo performance, cache colors as bigints
340+
// const colors = todo performance, cache colors as bigints
340341

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-
}
342+
const bigIntColors = new Map<string, bigint>();
343+
for (const [tag, colorString] of propertyColor.map!.entries()) {
344+
const color = parseRGBColorSpecification(colorString);
345+
bigIntColors.set(tag, BigInt(packColor(color)));
346+
console.log("tag color", tag, colorString, color);
347+
}
347348

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-
}
349+
for (const [index, id] of (
350+
segmentPropertyMap.segmentPropertyMap.inlineProperties?.ids ||
351+
[]
352+
).entries()) {
353+
if (map.has(id)) continue; // priority first color match
354+
const tagIndices = values[index];
355+
const segmentTags = new Set(
356+
tagIndices.split("").map((x) => tags[x.charCodeAt(0)]),
357+
);
358+
359+
for (const [tag, color] of bigIntColors.entries()) {
360+
if (segmentTags.has(tag)) {
361+
map.set(id, color);
362+
break;
360363
}
361364
}
362-
} else if (propertyColor.type === "numeric") {
363-
console.log("propety:", propertyColor.property);
364365
}
366+
} else if (propertyColor.type === "numeric") {
367+
368+
const options = propertyColor.options!;
365369

366-
/*
367-
"type": "numeric",
368-
"property": "Nvx",
369-
*/
370+
371+
const {numericalProperties} = segmentPropertyMap;
372+
373+
const numericalProperty = numericalProperties.find(x => x.id === propertyColor.property);
374+
375+
const {min, max} = options;
376+
377+
const minColor = parseRGBColorSpecification(options.minColor);
378+
const maxColor = parseRGBColorSpecification(options.maxColor);
379+
380+
if (numericalProperty) {
381+
const {values} = numericalProperty;
382+
for (const [index, id] of (
383+
segmentPropertyMap.segmentPropertyMap.inlineProperties?.ids ||
384+
[]
385+
).entries()) {
386+
const value = values[index];
387+
if (Number.isNaN(value)) continue;
388+
const valueClamped = Math.min(Math.max(value, min), max);
389+
const valueNormalized = (valueClamped - min) / (max - min);
390+
const color = vec3.create();
391+
vec3.lerp(color, minColor, maxColor, valueNormalized);
392+
map.set(id, BigInt(packColor(color)));
393+
}
394+
}
370395
}
371-
console.log('map', map.size);
372-
return map;
373-
},
374-
[this.layer.displayState.originalSegmentationGroupState.segmentPropertyMap,
375-
this.segmentPropertyColors],
376-
));
396+
}
397+
console.log("map", map.size);
398+
return map;
399+
},
400+
[
401+
this.layer.displayState.originalSegmentationGroupState
402+
.segmentPropertyMap,
403+
this.segmentPropertyColors,
404+
],
405+
),
406+
);
377407

378408
const { specificationChanged } = this;
379409
this.segmentColorHash.changed.add(specificationChanged.dispatch);
@@ -430,27 +460,60 @@ export class SegmentationUserLayerColorGroupState
430460
"property",
431461
verifyString,
432462
);
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-
});
463+
if (type === "tag") {
464+
const map = verifyObjectProperty(
465+
propertyColor,
466+
json_keys.MAP_JSON_KEY,
467+
(x) => {
468+
verifyObject(x);
469+
const res = new Map<string, string>();
470+
for (const [tag, value] of Object.entries(x)) {
471+
const color = verifyString(value);
472+
res.set(tag, color);
473+
}
474+
return res;
475+
},
476+
);
477+
this.segmentPropertyColors.value.push({
478+
type,
479+
property,
480+
map,
481+
});
482+
continue;
483+
} else if (type === "numeric") {
484+
const options = verifyObjectProperty(
485+
propertyColor,
486+
"options",
487+
(x) => {
488+
verifyObject(x);
489+
const min = verifyObjectProperty(x, "min", verifyFloat);
490+
const max = verifyObjectProperty(x, "max", verifyFloat);
491+
const minColor = verifyObjectProperty(
492+
x,
493+
"minColor",
494+
verifyString,
495+
);
496+
const maxColor = verifyObjectProperty(
497+
x,
498+
"maxColor",
499+
verifyString,
500+
);
501+
return {
502+
min,
503+
max,
504+
minColor,
505+
maxColor,
506+
};
507+
},
508+
);
509+
this.segmentPropertyColors.value.push({
510+
type,
511+
property,
512+
options,
513+
});
514+
} else {
515+
throw new Error(`unsupported type: ${type}`);
516+
}
454517
}
455518
this.segmentPropertyColors.changed.dispatch();
456519
},
@@ -462,7 +525,10 @@ export class SegmentationUserLayerColorGroupState
462525
x[json_keys.COLOR_SEED_JSON_KEY] = this.segmentColorHash.toJSON();
463526
x[json_keys.SEGMENT_DEFAULT_COLOR_JSON_KEY] =
464527
this.segmentDefaultColor.toJSON();
465-
const { segmentStatedColors, segmentPropertyColors: {value: segmentPropertyColors} } = this;
528+
const {
529+
segmentStatedColors,
530+
segmentPropertyColors: { value: segmentPropertyColors },
531+
} = this;
466532
if (segmentStatedColors.size > 0) {
467533
const j: any = (x[json_keys.SEGMENT_STATED_COLORS_JSON_KEY] = {});
468534
for (const [key, value] of segmentStatedColors) {
@@ -482,6 +548,7 @@ export class SegmentationUserLayerColorGroupState
482548
}
483549
} else {
484550
// TODO numeric
551+
p["options"] = propertyColor.options;
485552
}
486553
j.push(p);
487554
}

0 commit comments

Comments
 (0)