Skip to content
Snippets Groups Projects
Commit 934f5cfa authored by Alexander Rose's avatar Alexander Rose
Browse files

wip, shape instance support

parent 179461ed
Branches
Tags
No related merge requests found
...@@ -11,13 +11,20 @@ import { Geometry } from 'mol-geo/geometry/geometry'; ...@@ -11,13 +11,20 @@ import { Geometry } from 'mol-geo/geometry/geometry';
import { Mat4 } from 'mol-math/linear-algebra'; import { Mat4 } from 'mol-math/linear-algebra';
export interface Shape<G extends Geometry = Geometry> { export interface Shape<G extends Geometry = Geometry> {
/** A uuid to identify a shape object */
readonly id: UUID readonly id: UUID
/** A name to describe the shape */
readonly name: string readonly name: string
/** The geometry of the shape, e.g. `Mesh` or `Lines` */
readonly geometry: G readonly geometry: G
/** An array of transformation matrices to describe multiple instances of the geometry */
readonly transforms: Mat4[] readonly transforms: Mat4[]
/** Number of groups in the geometry */
readonly groupCount: number readonly groupCount: number
getColor(groupId: number): Color /** Get color for a given group */
getLabel(groupId: number): string getColor(groupId: number, instanceId: number): Color
/** Get color for a given group */
getLabel(groupId: number, instanceId: number): string
} }
export namespace Shape { export namespace Shape {
...@@ -37,10 +44,11 @@ export namespace Shape { ...@@ -37,10 +44,11 @@ export namespace Shape {
readonly kind: 'group-location' readonly kind: 'group-location'
shape: Shape shape: Shape
group: number group: number
instance: number
} }
export function Location(shape?: Shape, group?: number): Location { export function Location(shape?: Shape, group?: number, instance?: number): Location {
return { kind: 'group-location', shape: shape!, group: group || 0 }; return { kind: 'group-location', shape: shape!, group: group || 0, instance: instance || 0 };
} }
export function isLocation(x: any): x is Location { export function isLocation(x: any): x is Location {
...@@ -53,10 +61,11 @@ export namespace Shape { ...@@ -53,10 +61,11 @@ export namespace Shape {
readonly groups: ReadonlyArray<{ readonly groups: ReadonlyArray<{
ids: OrderedSet<number> ids: OrderedSet<number>
}> }>
readonly instance: number
} }
export function Loci(shape: Shape, groups: ArrayLike<{ ids: OrderedSet<number> }>): Loci { export function Loci(shape: Shape, groups: ArrayLike<{ ids: OrderedSet<number> }>, instance: number): Loci {
return { kind: 'group-loci', shape, groups: groups as Loci['groups'] }; return { kind: 'group-loci', shape, groups: groups as Loci['groups'], instance };
} }
export function isLoci(x: any): x is Loci { export function isLoci(x: any): x is Loci {
...@@ -66,6 +75,7 @@ export namespace Shape { ...@@ -66,6 +75,7 @@ export namespace Shape {
export function areLociEqual(a: Loci, b: Loci) { export function areLociEqual(a: Loci, b: Loci) {
if (a.shape !== b.shape) return false if (a.shape !== b.shape) return false
if (a.groups.length !== b.groups.length) return false if (a.groups.length !== b.groups.length) return false
if (a.instance !== b.instance) return false
for (let i = 0, il = a.groups.length; i < il; ++i) { for (let i = 0, il = a.groups.length; i < il; ++i) {
const groupA = a.groups[i] const groupA = a.groups[i]
const groupB = b.groups[i] const groupB = b.groups[i]
......
...@@ -131,9 +131,9 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa ...@@ -131,9 +131,9 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa
updated, updated,
createOrUpdate, createOrUpdate,
getLoci(pickingId: PickingId) { getLoci(pickingId: PickingId) {
const { objectId, groupId } = pickingId const { objectId, groupId, instanceId } = pickingId
if (_renderObject && _renderObject.id === objectId) { if (_renderObject && _renderObject.id === objectId) {
return Shape.Loci(_shape, [{ ids: OrderedSet.ofSingleton(groupId) }]) return Shape.Loci(_shape, [{ ids: OrderedSet.ofSingleton(groupId) }], instanceId)
} }
return EmptyLoci return EmptyLoci
}, },
...@@ -141,17 +141,19 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa ...@@ -141,17 +141,19 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa
if (!_renderObject) return false if (!_renderObject) return false
const { tMarker } = _renderObject.values const { tMarker } = _renderObject.values
let changed = false let changed = false
const { groupCount, count } = locationIt
if (isEveryLoci(loci)) { if (isEveryLoci(loci)) {
if (applyMarkerAction(tMarker.ref.value.array, 0, _shape.groupCount, action)) changed = true if (applyMarkerAction(tMarker.ref.value.array, 0, count, action)) changed = true
} else if (Shape.isLoci(loci)) { } else if (Shape.isLoci(loci)) {
for (const g of loci.groups) { const { instance, groups } = loci
for (const g of groups) {
if (Interval.is(g.ids)) { if (Interval.is(g.ids)) {
const start = Interval.start(g.ids) const start = instance * groupCount + Interval.start(g.ids)
const end = Interval.end(g.ids) const end = instance * groupCount + Interval.end(g.ids)
if (applyMarkerAction(tMarker.ref.value.array, start, end, action)) changed = true if (applyMarkerAction(tMarker.ref.value.array, start, end, action)) changed = true
} else { } else {
for (let i = 0, _i = g.ids.length; i < _i; i++) { for (let i = 0, _i = g.ids.length; i < _i; i++) {
const idx = g.ids[i]; const idx = instance * groupCount + g.ids[i];
if (applyMarkerAction(tMarker.ref.value.array, idx, idx + 1, action)) changed = true if (applyMarkerAction(tMarker.ref.value.array, idx, idx + 1, action)) changed = true
} }
} }
...@@ -194,8 +196,9 @@ export namespace ShapeGroupIterator { ...@@ -194,8 +196,9 @@ export namespace ShapeGroupIterator {
export function fromShape(shape: Shape): LocationIterator { export function fromShape(shape: Shape): LocationIterator {
const instanceCount = shape.transforms.length const instanceCount = shape.transforms.length
const location = Shape.Location(shape) const location = Shape.Location(shape)
const getLocation = (groupIndex: number) => { const getLocation = (groupIndex: number, instanceIndex: number) => {
location.group = groupIndex location.group = groupIndex
location.instance = instanceIndex
return location return location
} }
return LocationIterator(shape.groupCount, instanceCount, getLocation) return LocationIterator(shape.groupCount, instanceCount, getLocation)
......
...@@ -23,10 +23,10 @@ export function getShapeGroupColorThemeParams(ctx: ThemeDataContext) { ...@@ -23,10 +23,10 @@ export function getShapeGroupColorThemeParams(ctx: ThemeDataContext) {
export function ShapeGroupColorTheme(ctx: ThemeDataContext, props: PD.Values<ShapeGroupColorThemeParams>): ColorTheme<ShapeGroupColorThemeParams> { export function ShapeGroupColorTheme(ctx: ThemeDataContext, props: PD.Values<ShapeGroupColorThemeParams>): ColorTheme<ShapeGroupColorThemeParams> {
return { return {
factory: ShapeGroupColorTheme, factory: ShapeGroupColorTheme,
granularity: 'group', granularity: 'groupInstance',
color: (location: Location): Color => { color: (location: Location): Color => {
if (Shape.isLocation(location)) { if (Shape.isLocation(location)) {
return location.shape.getColor(location.group) return location.shape.getColor(location.group, location.instance)
} }
return DefaultColor return DefaultColor
}, },
......
...@@ -36,7 +36,7 @@ export function labelFirst(loci: Loci): string { ...@@ -36,7 +36,7 @@ export function labelFirst(loci: Loci): string {
case 'group-loci': case 'group-loci':
const g = loci.groups[0] const g = loci.groups[0]
if (g) { if (g) {
return loci.shape.getLabel(OrderedSet.getAt(g.ids, 0)) return loci.shape.getLabel(OrderedSet.getAt(g.ids, 0), loci.instance)
} else { } else {
return 'Unknown' return 'Unknown'
} }
......
...@@ -8,7 +8,7 @@ import './index.html' ...@@ -8,7 +8,7 @@ import './index.html'
import { Canvas3D } from 'mol-canvas3d/canvas3d'; import { Canvas3D } from 'mol-canvas3d/canvas3d';
import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
import { Sphere } from 'mol-geo/primitive/sphere'; import { Sphere } from 'mol-geo/primitive/sphere';
import { Mat4 } from 'mol-math/linear-algebra'; import { Mat4, Vec3 } from 'mol-math/linear-algebra';
import { Shape } from 'mol-model/shape'; import { Shape } from 'mol-model/shape';
import { ShapeRepresentation } from 'mol-repr/shape/representation'; import { ShapeRepresentation } from 'mol-repr/shape/representation';
import { ColorNames } from 'mol-util/color/tables'; import { ColorNames } from 'mol-util/color/tables';
...@@ -52,13 +52,21 @@ builderState.currentGroup = 0 ...@@ -52,13 +52,21 @@ builderState.currentGroup = 0
MeshBuilder.addPrimitive(builderState, t, sphere) MeshBuilder.addPrimitive(builderState, t, sphere)
const mesh = MeshBuilder.getMesh(builderState) const mesh = MeshBuilder.getMesh(builderState)
const myData = { mesh, colors: [ColorNames.aquamarine], labels: ['FooBaz'] } const myData = {
mesh,
groupCount: 1,
colors: [ColorNames.tomato, ColorNames.springgreen],
labels: ['FooBaz0', 'FooBaz1'],
transforms: [Mat4.identity(), Mat4.fromTranslation(Mat4.zero(), Vec3.create(3, 0, 0))]
}
type MyData = typeof myData type MyData = typeof myData
function getShape(data: MyData) { function getShape(data: MyData, props: {}, shape?: Shape<Mesh>) {
return Shape.create( const { mesh, colors, labels, transforms, groupCount } = data
'test', data.mesh, return shape || Shape.create(
(groupId: number) => data.colors[groupId], 'test', mesh,
(groupId: number) => data.labels[groupId] (groupId: number, instanceId: number) => colors[instanceId * groupCount + groupId],
(groupId: number, instanceId: number) => labels[instanceId * groupCount + groupId],
transforms
) )
} }
...@@ -75,4 +83,4 @@ add() ...@@ -75,4 +83,4 @@ add()
setTimeout(async () => { setTimeout(async () => {
myData.colors[0] = ColorNames.darkmagenta myData.colors[0] = ColorNames.darkmagenta
await repr.createOrUpdate({}, myData).run() await repr.createOrUpdate({}, myData).run()
}, 2000) }, 1000)
\ No newline at end of file \ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment