diff --git a/python/examples/shapes.py b/python/examples/shapes.py index 7c08a53f7..24260a7a5 100644 --- a/python/examples/shapes.py +++ b/python/examples/shapes.py @@ -33,6 +33,92 @@ frames=alphaml, properties=chemiscope.extract_properties(alphaml, only=["alpha", "alpha-vec"]), shapes={ + "cube_smooth": dict( + kind="custom", + parameters={ + "global": { + "vertices": [ + [0, 0, 0], + [1, 0, 0], + [0, 1, 0], + [1, 1, 0], + [0, 0, 1], + [1, 0, 1], + [0, 1, 1], + [1, 1, 1], + ], + "simplices": [ + [0, 2, 1], + [1, 2, 3], + [4, 6, 5], + [5, 6, 7], + [0, 1, 4], + [0, 4, 2], + [1, 3, 5], + [2, 6, 3], + [1, 5, 4], + [2, 4, 6], + [3, 7, 5], + [3, 6, 7], + ], + }, + "structure": [ + {"position": [0, 4, 0], "color": 0xFF0000}, + {"position": [3, 2, 1], "color": 0x00FF00}, + ], + }, + ), + "cube": dict( + kind="custom", + parameters={ + "global": { + "vertices": [ + [0, 0, 0], + [0, 1, 0], + [1, 1, 0], + [1, 0, 0], + [0, 0, 0], + [0, 0, 1], + [0, 1, 1], + [0, 1, 0], + [0, 1, 0], + [0, 1, 1], + [1, 1, 1], + [1, 1, 0], + [1, 1, 0], + [1, 1, 1], + [1, 0, 1], + [1, 0, 0], + [1, 0, 0], + [1, 0, 1], + [0, 0, 1], + [0, 0, 0], + [0, 0, 1], + [1, 0, 1], + [1, 1, 1], + [0, 1, 1], + ], + "simplices": [ + [0, 1, 2], + [2, 3, 0], + [4, 5, 6], + [6, 7, 4], + [8, 9, 10], + [10, 11, 8], + [12, 13, 14], + [14, 15, 12], + [16, 17, 18], + [18, 19, 16], + [20, 21, 22], + [22, 23, 20], + ], + }, + "structure": [ + {"position": [0, 4, 0], "color": 0xFF0000}, + {"position": [3, 2, 1], "color": 0x00FF00}, + ], + }, + ), "structure_shape": dict( kind="sphere", parameters={ @@ -64,7 +150,7 @@ { "spaceFilling": False, "atomLabels": False, - "shape": "structure_shape", + "shape": "cube", "axes": "off", "keepOrientation": False, "playbackDelay": 700, diff --git a/python/tests/shapes.py b/python/tests/shapes.py index 48909f037..fecd307f0 100644 --- a/python/tests/shapes.py +++ b/python/tests/shapes.py @@ -42,7 +42,7 @@ def test_custom_shapes(self): numbers=[1, 1, 1], positions=[[0, 0, 0], [1, 1, 1], [2, 2, 5]] ) - #TODO re-enable after having fixed custom shapes + # TODO re-enable after having fixed custom shapes """ "cubes": [ [ @@ -59,21 +59,25 @@ def test_custom_shapes(self): }, ], ],""" - shapes = { + shapes = { "spheres_structure": { - "kind" : "sphere", - "parameters" : { - "global" : {"radius": 0.1}, - "structure" : [ {"position" : [1, 2, 3]} ], - } + "kind": "sphere", + "parameters": { + "global": {"radius": 0.1}, + "structure": [{"position": [1, 2, 3]}], + }, + }, + "ellipsoids_atoms": { + "kind": "ellipsoid", + "parameters": { + "global": {"semiaxes": [0.3, 0.2, 0.1]}, + "atom": [ + {}, + {"semiaxes": [0.1, 0.2, 0.3]}, + {"orientation": [0.2, 0.3, 0.4, 1]}, + ], + }, }, - "ellipsoids_atoms" : { - "kind" : "ellipsoid", - "parameters" : { - "global" : {"semiaxes": [0.3, 0.2, 0.1]}, - "atom" : [ {}, {"semiaxes": [0.1, 0.2, 0.3]}, {"orientation": [0.2,0.3,0.4,1]}], - } - } } data = chemiscope.create_input(frames=[frame], shapes=shapes) diff --git a/src/structure/shapes.ts b/src/structure/shapes.ts index a66c78976..34852f955 100644 --- a/src/structure/shapes.ts +++ b/src/structure/shapes.ts @@ -60,15 +60,17 @@ export interface EllipsoidParameters extends BaseShapeParameters // Interface for polytope data, where // orientation is stored in the (w, x, y, z) convention // and simplices refers to the indices of the facets -export interface CustomShapeData { - kind: 'custom'; +export interface CustomShapeData extends BaseShapeData { vertices: [number, number, number][]; simplices: [number, number, number][]; - orientation?: [number, number, number, number]; } -export type ShapeData = SphereData | EllipsoidData; // | CustomShapeData; -export type ShapeParameters = SphereParameters | EllipsoidParameters; +export interface CustomShapeParameters extends BaseShapeParameters { + kind: 'custom'; +} + +export type ShapeData = SphereData | EllipsoidData | CustomShapeData; +export type ShapeParameters = SphereParameters | EllipsoidParameters | CustomShapeParameters; function addXYZ(a: XYZ, b: XYZ): XYZ { return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z }; @@ -335,12 +337,16 @@ export class Ellipsoid extends Shape { vertices.push(newVertex); // the normal to the ellipsoid surface is best computed in the original - // coordinate system, and then rotated in place - const newNormal: XYZ = rotateAndPlace({ - x: v.x / Math.pow(this.semiaxes[0], 2.0), - y: v.y / Math.pow(this.semiaxes[1], 2.0), - z: v.z / Math.pow(this.semiaxes[2], 2.0), - }, this.orientation, {x:0, y:0, z:0}); + // coordinate system, and then rotated in place + const newNormal: XYZ = rotateAndPlace( + { + x: v.x / Math.pow(this.semiaxes[0], 2.0), + y: v.y / Math.pow(this.semiaxes[1], 2.0), + z: v.z / Math.pow(this.semiaxes[2], 2.0), + }, + this.orientation, + { x: 0, y: 0, z: 0 } + ); normals.push(newNormal); } @@ -357,8 +363,10 @@ export class CustomShape extends Shape { public vertices: XYZ[]; public simplices: [number, number, number][]; - constructor(position: [number, number, number] = [0, 0, 0], data: CustomShapeData) { - super({}); //position, data.orientation); + constructor(data: Partial) { + super(data); + assert(data.vertices); + assert(data.simplices); this.vertices = []; for (const v of data.vertices) { diff --git a/src/structure/viewer.ts b/src/structure/viewer.ts index 82091fe95..64cdbbf5e 100644 --- a/src/structure/viewer.ts +++ b/src/structure/viewer.ts @@ -990,6 +990,12 @@ export class MoleculeViewer { this._viewer.addCustom( shape.outputTo3Dmol(shape_data.color || 0xffffff) ); + } else { + assert(current_shape.kind === 'custom'); + const shape = new CustomShape(shape_data); + this._viewer.addCustom( + shape.outputTo3Dmol(shape_data.color || 0xffffff) + ); } /* if (current_shape[i].kind === 'ellipsoid') { @@ -1026,6 +1032,13 @@ export class MoleculeViewer { this._viewer.addCustom( shape.outputTo3Dmol(shape_data.color || 0xffffff) ); + } else { + assert(current_shape.kind === 'custom'); + console.log(shape_data); + const shape = new CustomShape(shape_data); + this._viewer.addCustom( + shape.outputTo3Dmol(shape_data.color || 0xffffff) + ); } } }